[
  {
    "path": ".clang-format",
    "content": "---\nLanguage:        Cpp\nAccessModifierOffset: -4\nAlignAfterOpenBracket: Align\nAlignConsecutiveAssignments: false\nAlignConsecutiveDeclarations: false\nAlignEscapedNewlines: true\nAlignOperands:   true\nAlignTrailingComments: true\nAllowAllParametersOfDeclarationOnNextLine: true\nAllowShortBlocksOnASingleLine: true\nAllowShortCaseLabelsOnASingleLine: true\nAllowShortFunctionsOnASingleLine: Inline\nAllowShortIfStatementsOnASingleLine: false\nAllowShortLoopsOnASingleLine: false\nAlwaysBreakAfterDefinitionReturnType: None\nAlwaysBreakAfterReturnType: None\nAlwaysBreakBeforeMultilineStrings: false\nAlwaysBreakTemplateDeclarations: Yes\nBinPackArguments: false\nBinPackParameters: false\nBraceWrapping:   \n  AfterCaseLabel:  false\n  AfterClass:      false\n  AfterControlStatement: false\n  AfterEnum:       false\n  AfterFunction:   false\n  AfterNamespace:  false\n  AfterObjCDeclaration: false\n  AfterStruct:     false\n  AfterUnion:      false\n  AfterExternBlock: false\n  BeforeCatch:     true\n  BeforeElse:      true\n  IndentBraces:    false\n  SplitEmptyFunction: true\n  SplitEmptyRecord: true\n  SplitEmptyNamespace: true\nBreakBeforeBinaryOperators: All\nBreakBeforeBraces: Custom\nBreakBeforeInheritanceComma: false\nBreakInheritanceList: BeforeColon\nBreakBeforeTernaryOperators: true\nBreakConstructorInitializersBeforeComma: false\nBreakConstructorInitializers: BeforeComma\nBreakAfterJavaFieldAnnotations: false\nBreakStringLiterals: true\nColumnLimit:     180\nCommentPragmas:  '^ IWYU pragma:'\nCompactNamespaces: false\nConstructorInitializerAllOnOneLineOrOnePerLine: false\nConstructorInitializerIndentWidth: 4\nContinuationIndentWidth: 4\nCpp11BracedListStyle: true\nDerivePointerAlignment: false\nDisableFormat:   false\nExperimentalAutoDetectBinPacking: false\nFixNamespaceComments: true\nForEachMacros:   \n  - forever\n  - foreach\n  - Q_FOREACH\n  - BOOST_FOREACH\nIncludeBlocks:   Preserve\nIncludeCategories: \n  - Regex:           '^<Q.*'\n    Priority:        200\n  - Regex:           '^(<|\"(gtest|gmock|isl|json)/)'\n    Priority:        3\n  - Regex:           '.*'\n    Priority:        1\nIncludeIsMainRegex: '(Test)?$'\nIndentCaseLabels: true\nIndentPPDirectives: None\nIndentWidth:     4\nIndentWrappedFunctionNames: false\nJavaScriptQuotes: Leave\nJavaScriptWrapImports: true\nKeepEmptyLinesAtTheStartOfBlocks: false\nMacroBlockBegin: \"^wxBEGIN_EVENT_TABLE$\"\nMacroBlockEnd: \"^wxEND_EVENT_TABLE$\"\nMaxEmptyLinesToKeep: 2\nNamespaceIndentation: None\nObjCBinPackProtocolList: Auto\nObjCBlockIndentWidth: 4\nObjCSpaceAfterProperty: false\nObjCSpaceBeforeProtocolList: true\nPenaltyBreakAssignment: 150\nPenaltyBreakBeforeFirstCallParameter: 300\nPenaltyBreakComment: 500\nPenaltyBreakFirstLessLess: 400\nPenaltyBreakString: 600\nPenaltyBreakTemplateDeclaration: 10\nPenaltyExcessCharacter: 50\nPenaltyReturnTypeOnItsOwnLine: 300\nPointerAlignment: Left\nReflowComments:  false\nSortIncludes:    true\nSortUsingDeclarations: true\nSpaceAfterCStyleCast: false\nSpaceAfterTemplateKeyword: false\nSpaceBeforeAssignmentOperators: true\nSpaceBeforeCpp11BracedList: false\nSpaceBeforeCtorInitializerColon: true\nSpaceBeforeInheritanceColon: true\nSpaceBeforeParens: ControlStatements\nSpaceBeforeRangeBasedForLoopColon: true\nSpaceInEmptyParentheses: false\nSpacesBeforeTrailingComments: 1\nSpacesInAngles:  false\nSpacesInContainerLiterals: false\nSpacesInCStyleCastParentheses: false\nSpacesInParentheses: false\nSpacesInSquareBrackets: false\nStandard:        c++17\nTabWidth:        4\nUseTab:          Always\n...\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a bug report\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Description**\nA clear and concise description of what the bug and the expected behavior is.\n\n**How to reproduce**\n1. Click on '....'\n2. Go to '...'\n3. See error\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea\ntitle: ''\nlabels: request\nassignees: ''\n\n---\n\n**What is it that you want to do that isn't currently possible?**\n...\n\n**Request the feature**\n...\n"
  },
  {
    "path": ".gitignore",
    "content": "*.obj\n*.tlog\n*.exe\n*.aps\n*.res\n*.pch\n*.log\n*.ipch\n*.pdb\n*.suo\n*.sdf\n*.opensdf\n*.user\n*.db\n*.opendb\n*.dds\n*.iobj\n*.ipdb\n*.db-wal\n*.db-shm\n*.ilk\n*.vs\n\n/build"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"lib/nifly\"]\n\tpath = lib/nifly\n\turl = https://github.com/ousnius/nifly\n"
  },
  {
    "path": "BS_OS.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio 15\nVisualStudioVersion = 15.0.27130.2026\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"BodySlide\", \"BodySlide.vcxproj\", \"{F7E444AD-893D-4E93-8897-AF050C1C6A48}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"OutfitStudio\", \"OutfitStudio.vcxproj\", \"{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Debug|x64.Build.0 = Debug|x64\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|Win32.Build.0 = Release|Win32\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|x64.ActiveCfg = Release|x64\n\t\t{F7E444AD-893D-4E93-8897-AF050C1C6A48}.Release|x64.Build.0 = Release|x64\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Debug|x64.Build.0 = Debug|x64\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Release|Win32.Build.0 = Release|Win32\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Release|x64.ActiveCfg = Release|x64\n\t\t{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1DF09C69-2C4A-4B92-864E-7FFC99ACC9FE}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "BodySlide.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <longPathAware xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">true</longPathAware>\n    </windowsSettings>\n  </application>\n</assembly>\n"
  },
  {
    "path": "BodySlide.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup Label=\"ProjectConfigurations\">\r\n    <ProjectConfiguration Include=\"Debug|Win32\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Debug|x64\">\r\n      <Configuration>Debug</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|Win32\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>Win32</Platform>\r\n    </ProjectConfiguration>\r\n    <ProjectConfiguration Include=\"Release|x64\">\r\n      <Configuration>Release</Configuration>\r\n      <Platform>x64</Platform>\r\n    </ProjectConfiguration>\r\n  </ItemGroup>\r\n  <PropertyGroup Label=\"Globals\">\r\n    <ProjectGuid>{F7E444AD-893D-4E93-8897-AF050C1C6A48}</ProjectGuid>\r\n    <RootNamespace>BodySlide</RootNamespace>\r\n    <Keyword>Win32Proj</Keyword>\r\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <PlatformToolset>v145</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CLRSupport>false</CLRSupport>\r\n    <UseOfMfc>false</UseOfMfc>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <PlatformToolset>v145</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n    <WholeProgramOptimization>true</WholeProgramOptimization>\r\n    <CLRSupport>false</CLRSupport>\r\n    <UseOfMfc>false</UseOfMfc>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <PlatformToolset>v145</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\r\n    <ConfigurationType>Application</ConfigurationType>\r\n    <PlatformToolset>v145</PlatformToolset>\r\n    <CharacterSet>Unicode</CharacterSet>\r\n  </PropertyGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\r\n  <ImportGroup Label=\"ExtensionSettings\">\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\r\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\r\n  </ImportGroup>\r\n  <PropertyGroup Label=\"UserMacros\" />\r\n  <PropertyGroup>\r\n    <_ProjectFileVersion>11.0.61030.0</_ProjectFileVersion>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\r\n    <TargetName>$(ProjectName) Debug</TargetName>\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <TargetName>$(ProjectName) $(Platform) Debug</TargetName>\r\n    <LinkIncremental>true</LinkIncremental>\r\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\r\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\r\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\r\n    <LinkIncremental>false</LinkIncremental>\r\n  </PropertyGroup>\r\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <LinkIncremental>false</LinkIncremental>\r\n    <TargetName>$(ProjectName) $(Platform)</TargetName>\r\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\r\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\r\n  </PropertyGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\r\n    <ClCompile>\r\n      <Optimization>Disabled</Optimization>\r\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <MinimalRebuild>false</MinimalRebuild>\r\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\r\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>glu32.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <AdditionalLibraryDirectories>..\\wxWidgets\\lib\\vc_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>\r\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\r\n    </Link>\r\n    <Manifest>\r\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\r\n      <AdditionalManifestFiles>BodySlide.manifest</AdditionalManifestFiles>\r\n    </Manifest>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\r\n    <ClCompile>\r\n      <Optimization>Disabled</Optimization>\r\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <MinimalRebuild>false</MinimalRebuild>\r\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\r\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>glu32.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <AdditionalLibraryDirectories>..\\wxWidgets\\lib\\vc_x64_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>\r\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\r\n    </Link>\r\n    <Manifest>\r\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\r\n      <AdditionalManifestFiles>BodySlide.manifest</AdditionalManifestFiles>\r\n    </Manifest>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\r\n    <ClCompile>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <FunctionLevelLinking>\r\n      </FunctionLevelLinking>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\r\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>glu32.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <AdditionalLibraryDirectories>..\\wxWidgets\\lib\\vc_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <IgnoreSpecificDefaultLibraries>\r\n      </IgnoreSpecificDefaultLibraries>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <PreventDllBinding>\r\n      </PreventDllBinding>\r\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\r\n      <AdditionalOptions>/pdbaltpath:%_PDB% %(AdditionalOptions)</AdditionalOptions>\r\n    </Link>\r\n    <Manifest>\r\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\r\n      <AdditionalManifestFiles>BodySlide.manifest</AdditionalManifestFiles>\r\n    </Manifest>\r\n  </ItemDefinitionGroup>\r\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\r\n    <ClCompile>\r\n      <Optimization>MaxSpeed</Optimization>\r\n      <IntrinsicFunctions>true</IntrinsicFunctions>\r\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2</AdditionalIncludeDirectories>\r\n      <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r\n      <FunctionLevelLinking>\r\n      </FunctionLevelLinking>\r\n      <WarningLevel>Level4</WarningLevel>\r\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\r\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\r\n      <LanguageStandard>stdcpp17</LanguageStandard>\r\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\r\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\r\n    </ClCompile>\r\n    <Link>\r\n      <AdditionalDependencies>glu32.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r\n      <AdditionalLibraryDirectories>..\\wxWidgets\\lib\\vc_x64_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r\n      <IgnoreSpecificDefaultLibraries>\r\n      </IgnoreSpecificDefaultLibraries>\r\n      <GenerateDebugInformation>true</GenerateDebugInformation>\r\n      <SubSystem>Windows</SubSystem>\r\n      <OptimizeReferences>true</OptimizeReferences>\r\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r\n      <PreventDllBinding>\r\n      </PreventDllBinding>\r\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\r\n      <AdditionalOptions>/pdbaltpath:%_PDB% %(AdditionalOptions)</AdditionalOptions>\r\n    </Link>\r\n    <Manifest>\r\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\r\n      <AdditionalManifestFiles>BodySlide.manifest</AdditionalManifestFiles>\r\n    </Manifest>\r\n  </ItemDefinitionGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"BodySlide.ico\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"BodySlide.rc\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"lang\\BodySlide.pot\" />\r\n    <None Include=\"lib\\gli\\core\\bc.inl\" />\r\n    <None Include=\"lib\\gli\\core\\clear.inl\" />\r\n    <None Include=\"lib\\gli\\core\\comparison.inl\" />\r\n    <None Include=\"lib\\gli\\core\\convert.inl\" />\r\n    <None Include=\"lib\\gli\\core\\copy.inl\" />\r\n    <None Include=\"lib\\gli\\core\\duplicate.inl\" />\r\n    <None Include=\"lib\\gli\\core\\dx.inl\" />\r\n    <None Include=\"lib\\gli\\core\\file.inl\" />\r\n    <None Include=\"lib\\gli\\core\\filter.inl\" />\r\n    <None Include=\"lib\\gli\\core\\flip.inl\" />\r\n    <None Include=\"lib\\gli\\core\\format.inl\" />\r\n    <None Include=\"lib\\gli\\core\\generate_mipmaps.inl\" />\r\n    <None Include=\"lib\\gli\\core\\gl.inl\" />\r\n    <None Include=\"lib\\gli\\core\\image.inl\" />\r\n    <None Include=\"lib\\gli\\core\\levels.inl\" />\r\n    <None Include=\"lib\\gli\\core\\load.inl\" />\r\n    <None Include=\"lib\\gli\\core\\load_dds.inl\" />\r\n    <None Include=\"lib\\gli\\core\\load_kmg.inl\" />\r\n    <None Include=\"lib\\gli\\core\\load_ktx.inl\" />\r\n    <None Include=\"lib\\gli\\core\\make_texture.inl\" />\r\n    <None Include=\"lib\\gli\\core\\reduce.inl\" />\r\n    <None Include=\"lib\\gli\\core\\s3tc.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler1d.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler1d_array.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler2d.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler2d_array.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler3d.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler_cube.inl\" />\r\n    <None Include=\"lib\\gli\\core\\sampler_cube_array.inl\" />\r\n    <None Include=\"lib\\gli\\core\\save.inl\" />\r\n    <None Include=\"lib\\gli\\core\\save_dds.inl\" />\r\n    <None Include=\"lib\\gli\\core\\save_kmg.inl\" />\r\n    <None Include=\"lib\\gli\\core\\save_ktx.inl\" />\r\n    <None Include=\"lib\\gli\\core\\storage.inl\" />\r\n    <None Include=\"lib\\gli\\core\\storage_linear.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture1d.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture1d_array.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture2d.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture2d_array.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture3d.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture_cube.inl\" />\r\n    <None Include=\"lib\\gli\\core\\texture_cube_array.inl\" />\r\n    <None Include=\"lib\\gli\\core\\transform.inl\" />\r\n    <None Include=\"lib\\gli\\core\\view.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_common.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_common_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_half.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x2.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x3.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x4.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x2.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x3.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x4.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x2.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x3.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec1.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec2.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec3.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_common.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_projection.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_relational.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_transform.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_relational.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_transform.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_common.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_constants.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_relational.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_ulp.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\vector_common.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\vector_relational.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\ext\\vector_ulp.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\bitfield.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\color_space.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\constants.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\epsilon.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\integer.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_access.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_transform.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\noise.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\packing.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion_simd.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\random.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\reciprocal.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\round.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\type_precision.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\type_ptr.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtc\\ulp.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\associated_min_max.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\bit.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\closest_point.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\color_encoding.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\common.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\compatibility.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\component_wise.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\easing.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\euler_angles.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\extend.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\extended_min_max.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\exterior_product.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_exponential.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_square_root.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\float_notmalize.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\functions.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\gradient_paint.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\hash.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\integer.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\intersect.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\io.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\log_base.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_operation.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_query.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\mixed_product.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\norm.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\normal.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\normalize_dot.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\number_precision.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\optimum_pow.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\orthonormalize.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\perpendicular.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\projection.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\quaternion.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\raw_data.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_vector.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\scalar_relational.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\spline.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\std_based_type.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\string_cast.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\texture.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\transform.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\transform2.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\type_aligned.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\type_trait.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_angle.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_query.inl\" />\r\n    <None Include=\"lib\\gli\\glm\\gtx\\wrap.inl\" />\r\n    <None Include=\"res\\xrc\\About.xrc\" />\r\n    <None Include=\"res\\xrc\\BatchBuild.xrc\" />\r\n    <None Include=\"res\\xrc\\BodySlide.xrc\" />\r\n    <None Include=\"res\\xrc\\GroupManager.xrc\" />\r\n    <None Include=\"res\\xrc\\NormalsGenDlg.xrc\" />\r\n    <None Include=\"res\\xrc\\SavePreset.xrc\" />\r\n    <None Include=\"res\\xrc\\Settings.xrc\" />\r\n    <None Include=\"res\\xrc\\Setup.xrc\" />\r\n    <None Include=\"res\\xrc\\Slider.xrc\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"lib\\DDS.h\" />\r\n    <ClInclude Include=\"lib\\FSEngine\\FSBSA.h\" />\r\n    <ClInclude Include=\"lib\\FSEngine\\FSEngine.h\" />\r\n    <ClInclude Include=\"lib\\FSEngine\\FSManager.h\" />\r\n    <ClInclude Include=\"lib\\gli\\clear.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\comparison.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\convert.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\copy.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\bc.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\clear.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\convert_func.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\coord.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\file.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\filter.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\filter_compute.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\flip.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\mipmaps_compute.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\s3tc.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\storage.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\storage_linear.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\core\\workaround.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\duplicate.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\dx.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\format.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\generate_mipmaps.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\gl.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\gli.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_vector_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\qualifier.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\setup.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_float.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_half.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_quat.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_features.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_fixes.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_noise.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle_func.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_vectorize.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\exponential.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_projection.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_transform.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_transform.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_constants.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_float_sized.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_int_sized.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_uint_sized.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_ulp.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_ulp.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\fwd.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\geometric.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\glm.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\bitfield.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\color_space.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\constants.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\epsilon.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\integer.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_access.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_integer.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_transform.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\noise.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\packing.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\quaternion.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\random.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\reciprocal.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\round.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_aligned.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_ptr.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\ulp.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\vec1.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\associated_min_max.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\bit.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\closest_point.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_encoding.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\common.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\compatibility.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\component_wise.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\easing.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\euler_angles.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extend.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extended_min_max.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\exterior_product.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_exponential.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_square_root.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\functions.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\gradient_paint.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\hash.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\integer.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\intersect.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\io.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\log_base.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_operation.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_query.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\mixed_product.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\norm.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normal.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normalize_dot.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\number_precision.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\optimum_pow.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\orthonormalize.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\perpendicular.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\projection.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\quaternion.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\range.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\raw_data.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_vector.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_multiplication.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\spline.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\std_based_type.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\string_cast.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\texture.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_aligned.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_trait.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_angle.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_query.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vec_swizzle.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\wrap.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\integer.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\matrix.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\packing.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\common.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\exponential.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\geometric.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\integer.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\matrix.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\packing.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\platform.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\trigonometric.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\vector_relational.h\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\trigonometric.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\vec2.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\vec3.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\vec4.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\glm\\vector_relational.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\image.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\levels.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\load.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\load_dds.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\load_kmg.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\load_ktx.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\make_texture.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\reduce.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler1d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler1d_array.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler2d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler2d_array.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler3d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler_cube.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\sampler_cube_array.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\save.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\save_dds.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\save_kmg.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\save_ktx.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\target.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture1d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture1d_array.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture2d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture2d_array.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture3d.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture_cube.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\texture_cube_array.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\transform.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\type.hpp\" />\r\n    <ClInclude Include=\"lib\\gli\\view.hpp\" />\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4.h\" />\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4file.h\" />\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame.h\" />\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame_static.h\" />\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4hc.h\" />\r\n    <ClInclude Include=\"lib\\LZ4F\\xxhash.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\image_DXT.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\image_helper.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\pkm_helper.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\pvr_helper.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\SOIL2.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS_c.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext_c.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm_c.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr_c.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_c.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_write.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stb_image.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\stb_image_write.h\" />\r\n    <ClInclude Include=\"lib\\SOIL2\\wfETC.h\" />\r\n    <ClInclude Include=\"lib\\TinyXML-2\\tinyxml2.h\" />\r\n    <ClInclude Include=\"resource.h\" />\r\n    <ClInclude Include=\"src\\components\\Anim.h\" />\r\n    <ClInclude Include=\"src\\components\\Automorph.h\" />\r\n    <ClInclude Include=\"src\\components\\BuildSelection.h\" />\r\n    <ClInclude Include=\"src\\components\\ClippingFixer.h\" />\r\n    <ClInclude Include=\"src\\components\\DiffData.h\" />\r\n    <ClInclude Include=\"src\\components\\Mesh.h\" />\r\n    <ClInclude Include=\"src\\components\\NormalGenLayers.h\" />\r\n    <ClInclude Include=\"src\\components\\SliderCategories.h\" />\r\n    <ClInclude Include=\"src\\components\\SliderData.h\" />\r\n    <ClInclude Include=\"src\\components\\SliderGroup.h\" />\r\n    <ClInclude Include=\"src\\components\\SliderManager.h\" />\r\n    <ClInclude Include=\"src\\components\\SliderPresets.h\" />\r\n    <ClInclude Include=\"src\\components\\SliderSet.h\" />\r\n    <ClInclude Include=\"src\\components\\UndoState.h\" />\r\n    <ClInclude Include=\"src\\files\\MaterialFile.h\" />\r\n    <ClInclude Include=\"src\\files\\ObjFile.h\" />\r\n    <ClInclude Include=\"src\\files\\ResourceLoader.h\" />\r\n    <ClInclude Include=\"src\\files\\TriFile.h\" />\r\n    <ClInclude Include=\"src\\files\\wxDDSImage.h\" />\r\n    <ClInclude Include=\"src\\program\\BodySlideApp.h\" />\r\n    <ClInclude Include=\"src\\program\\GroupManager.h\" />\r\n    <ClInclude Include=\"src\\program\\NormalsGenDialog.h\" />\r\n    <ClInclude Include=\"src\\program\\PresetSaveDialog.h\" />\r\n    <ClInclude Include=\"src\\program\\PreviewWindow.h\" />\r\n    <ClInclude Include=\"src\\render\\GLExtensions.h\" />\r\n    <ClInclude Include=\"src\\render\\GLMaterial.h\" />\r\n    <ClInclude Include=\"src\\render\\GLOffscreenBuffer.h\" />\r\n    <ClInclude Include=\"src\\render\\GLShader.h\" />\r\n    <ClInclude Include=\"src\\render\\GLSurface.h\" />\r\n    <ClInclude Include=\"src\\ui\\PreviewPanel.h\" />\r\n    <ClInclude Include=\"src\\ui\\wxNormalsGenDlg.h\" />\r\n    <ClInclude Include=\"src\\ui\\wxStateButton.h\" />\r\n    <ClInclude Include=\"src\\utils\\AABBTree.h\" />\r\n    <ClInclude Include=\"src\\utils\\ConfigurationManager.h\" />\r\n    <ClInclude Include=\"src\\utils\\Log.h\" />\r\n    <ClInclude Include=\"src\\utils\\PlatformUtil.h\" />\r\n    <ClInclude Include=\"src\\utils\\StringStuff.h\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"lib\\FSEngine\\FSBSA.cpp\" />\r\n    <ClCompile Include=\"lib\\FSEngine\\FSEngine.cpp\" />\r\n    <ClCompile Include=\"lib\\FSEngine\\FSManager.cpp\" />\r\n    <ClCompile Include=\"lib\\gli\\core\\dummy.cpp\" />\r\n    <ClCompile Include=\"lib\\gli\\glm\\detail\\glm.cpp\" />\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4.c\" />\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4file.c\" />\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4frame.c\" />\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4hc.c\" />\r\n    <ClCompile Include=\"lib\\LZ4F\\xxhash.c\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Animation.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\BasicTypes.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\bhk.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\ExtraData.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Factory.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Geometry.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\NifFile.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\NifUtil.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Nodes.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Object3d.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Objects.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Particles.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Shaders.cpp\" />\r\n    <ClCompile Include=\"lib\\nifly\\src\\Skin.cpp\" />\r\n    <ClCompile Include=\"lib\\SOIL2\\image_DXT.c\" />\r\n    <ClCompile Include=\"lib\\SOIL2\\image_helper.c\" />\r\n    <ClCompile Include=\"lib\\SOIL2\\SOIL2.c\" />\r\n    <ClCompile Include=\"lib\\SOIL2\\wfETC.c\" />\r\n    <ClCompile Include=\"lib\\TinyXML-2\\tinyxml2.cpp\" />\r\n    <ClCompile Include=\"src\\components\\Anim.cpp\" />\r\n    <ClCompile Include=\"src\\components\\Automorph.cpp\" />\r\n    <ClCompile Include=\"src\\components\\BuildSelection.cpp\" />\r\n    <ClCompile Include=\"src\\components\\ClippingFixer.cpp\" />\r\n    <ClCompile Include=\"src\\components\\DiffData.cpp\" />\r\n    <ClCompile Include=\"src\\components\\Mesh.cpp\" />\r\n    <ClCompile Include=\"src\\components\\NormalGenLayers.cpp\" />\r\n    <ClCompile Include=\"src\\components\\SliderCategories.cpp\" />\r\n    <ClCompile Include=\"src\\components\\SliderData.cpp\" />\r\n    <ClCompile Include=\"src\\components\\SliderGroup.cpp\" />\r\n    <ClCompile Include=\"src\\components\\SliderManager.cpp\" />\r\n    <ClCompile Include=\"src\\components\\SliderPresets.cpp\" />\r\n    <ClCompile Include=\"src\\components\\SliderSet.cpp\" />\r\n    <ClCompile Include=\"src\\files\\MaterialFile.cpp\" />\r\n    <ClCompile Include=\"src\\files\\ObjFile.cpp\" />\r\n    <ClCompile Include=\"src\\files\\ResourceLoader.cpp\" />\r\n    <ClCompile Include=\"src\\files\\TriFile.cpp\" />\r\n    <ClCompile Include=\"src\\files\\wxDDSImage.cpp\" />\r\n    <ClCompile Include=\"src\\program\\BodySlideApp.cpp\" />\r\n    <ClCompile Include=\"src\\program\\GroupManager.cpp\" />\r\n    <ClCompile Include=\"src\\program\\NormalsGenDialog.cpp\" />\r\n    <ClCompile Include=\"src\\program\\PresetSaveDialog.cpp\" />\r\n    <ClCompile Include=\"src\\program\\PreviewWindow.cpp\" />\r\n    <ClCompile Include=\"src\\render\\GLExtensions.cpp\" />\r\n    <ClCompile Include=\"src\\render\\GLMaterial.cpp\" />\r\n    <ClCompile Include=\"src\\render\\GLOffscreenBuffer.cpp\" />\r\n    <ClCompile Include=\"src\\render\\GLShader.cpp\" />\r\n    <ClCompile Include=\"src\\render\\GLSurface.cpp\" />\r\n    <ClCompile Include=\"src\\ui\\PreviewPanel.cpp\" />\r\n    <ClCompile Include=\"src\\ui\\wxNormalsGenDlg.cpp\" />\r\n    <ClCompile Include=\"src\\ui\\wxStateButton.cpp\" />\r\n    <ClCompile Include=\"src\\utils\\AABBTree.cpp\" />\r\n    <ClCompile Include=\"src\\utils\\ConfigurationManager.cpp\" />\r\n    <ClCompile Include=\"src\\utils\\Log.cpp\" />\r\n    <ClCompile Include=\"src\\utils\\PlatformUtil.cpp\" />\r\n    <ClCompile Include=\"src\\utils\\StringStuff.cpp\" />\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Xml Include=\"Config.xml\" />\r\n  </ItemGroup>\r\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\r\n  <ImportGroup Label=\"ExtensionTargets\">\r\n  </ImportGroup>\r\n</Project>"
  },
  {
    "path": "BodySlide.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\r\n  <ItemGroup>\r\n    <Filter Include=\"Resources\">\r\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\">\r\n      <UniqueIdentifier>{6d6b425f-03aa-4210-b6af-ac49bf12352d}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\FSEngine\">\r\n      <UniqueIdentifier>{6f3ea695-40d7-4be2-a951-168ba3339081}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\">\r\n      <UniqueIdentifier>{e366b310-4d8d-4f5e-b43d-0aa7f0edeef1}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\TinyXML-2\">\r\n      <UniqueIdentifier>{fd5a7d0f-084f-4202-b4d6-67732f2c2302}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\core\">\r\n      <UniqueIdentifier>{5857b5e3-d66f-4467-ab4d-f70856237a1a}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\glm\">\r\n      <UniqueIdentifier>{cf289f86-ccae-4cd8-81db-71adb8328b06}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\glm\\detail\">\r\n      <UniqueIdentifier>{9222d26f-5381-4e83-b3d9-bbef711a1f09}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\glm\\gtc\">\r\n      <UniqueIdentifier>{18fc42a9-9067-4638-bb32-7a671746137a}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\glm\\gtx\">\r\n      <UniqueIdentifier>{5359067a-dabf-4cb9-a13d-bb37b483c638}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Components\">\r\n      <UniqueIdentifier>{8e852d2f-5f87-416d-be07-c75179e8f57e}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Files\">\r\n      <UniqueIdentifier>{782be5c1-aa6f-4e54-acb4-c89dc11d2fcb}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Program\">\r\n      <UniqueIdentifier>{82ef2505-7b08-4871-b498-b758d860f25c}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Rendering\">\r\n      <UniqueIdentifier>{def5c486-38d5-46f3-87b8-5d17825c309e}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"UI\">\r\n      <UniqueIdentifier>{0e8c63ba-3164-40f0-a35e-7feb262c883b}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Utilities\">\r\n      <UniqueIdentifier>{575c3247-33ba-4a9b-8af4-649cb8b54d10}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\LZ4F\">\r\n      <UniqueIdentifier>{1dd6227a-2c07-441b-a703-df5e11788296}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\SOIL2\">\r\n      <UniqueIdentifier>{746df173-aa97-45f5-9200-676a6b050846}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\glm\\ext\">\r\n      <UniqueIdentifier>{7208f4f1-7c43-4c83-b503-8677eceb8c70}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\gli\\glm\\simd\">\r\n      <UniqueIdentifier>{e8f5c7ec-6703-40f1-8df0-82794ab63125}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\nifly\">\r\n      <UniqueIdentifier>{04ceb037-1b27-4876-8d21-d93a532d5246}</UniqueIdentifier>\r\n    </Filter>\r\n    <Filter Include=\"Libraries\\nifly\\src\">\r\n      <UniqueIdentifier>{a4a64824-9052-40c3-9138-04fab014641c}</UniqueIdentifier>\r\n    </Filter>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Image Include=\"BodySlide.ico\">\r\n      <Filter>Resources</Filter>\r\n    </Image>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ResourceCompile Include=\"BodySlide.rc\">\r\n      <Filter>Resources</Filter>\r\n    </ResourceCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <None Include=\"res\\xrc\\BodySlide.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\GroupManager.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\SavePreset.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\Settings.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\Slider.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\About.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\BatchBuild.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\Setup.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"lang\\BodySlide.pot\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"res\\xrc\\NormalsGenDlg.xrc\">\r\n      <Filter>Resources</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\copy.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\duplicate.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\dx.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\file.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\filter.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\flip.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\format.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\generate_mipmaps.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\gl.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\image.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\levels.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\load.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\load_dds.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\load_kmg.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\load_ktx.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\make_texture.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\reduce.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\s3tc.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler_cube.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler_cube_array.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler1d.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler1d_array.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler2d.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler2d_array.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\sampler3d.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\save.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\save_dds.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\save_kmg.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\save_ktx.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\storage.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\storage_linear.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture_cube.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture_cube_array.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture1d.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture1d_array.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture2d.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture2d_array.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\texture3d.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\transform.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\view.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\bc.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\clear.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\comparison.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\core\\convert.inl\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_common.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_common_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_half.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x2.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x3.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x4.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x2.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x3.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x4.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x2.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x3.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec1.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec2.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec3.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\constants.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\epsilon.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\integer.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_access.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_transform.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\noise.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\packing.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\random.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\reciprocal.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\round.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\type_precision.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\type_ptr.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\ulp.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\bitfield.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtc\\color_space.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\color_encoding.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\common.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\compatibility.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\component_wise.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\easing.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\euler_angles.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\extend.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\extended_min_max.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\exterior_product.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_exponential.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_square_root.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\float_notmalize.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\functions.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\gradient_paint.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\hash.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\integer.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\intersect.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\io.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\log_base.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_operation.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_query.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\mixed_product.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\norm.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\normal.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\normalize_dot.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\number_precision.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\optimum_pow.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\orthonormalize.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\perpendicular.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\projection.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\quaternion.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\raw_data.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_vector.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\scalar_relational.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\spline.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\std_based_type.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\string_cast.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\texture.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\transform.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\transform2.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\type_aligned.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\type_trait.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_angle.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_query.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\wrap.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\associated_min_max.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\bit.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\gtx\\closest_point.inl\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_common.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_projection.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_relational.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_transform.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common_simd.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_relational.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_transform.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_common.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_constants.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_relational.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_ulp.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\vector_common.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\vector_relational.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\vector_ulp.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.inl\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </None>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClInclude Include=\"resource.h\">\r\n      <Filter>Resources</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\TinyXML-2\\tinyxml2.h\">\r\n      <Filter>Libraries\\TinyXML-2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\FSEngine\\FSEngine.h\">\r\n      <Filter>Libraries\\FSEngine</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\FSEngine\\FSManager.h\">\r\n      <Filter>Libraries\\FSEngine</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\FSEngine\\FSBSA.h\">\r\n      <Filter>Libraries\\FSEngine</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\DiffData.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\Mesh.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\SliderCategories.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\SliderData.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\SliderGroup.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\SliderManager.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\SliderPresets.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\SliderSet.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\Automorph.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\files\\ObjFile.h\">\r\n      <Filter>Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\files\\ResourceLoader.h\">\r\n      <Filter>Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\files\\TriFile.h\">\r\n      <Filter>Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\files\\MaterialFile.h\">\r\n      <Filter>Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\program\\PresetSaveDialog.h\">\r\n      <Filter>Program</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\program\\PreviewWindow.h\">\r\n      <Filter>Program</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\program\\BodySlideApp.h\">\r\n      <Filter>Program</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\program\\GroupManager.h\">\r\n      <Filter>Program</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\render\\GLShader.h\">\r\n      <Filter>Rendering</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\render\\GLSurface.h\">\r\n      <Filter>Rendering</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\ui\\wxStateButton.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\utils\\ConfigurationManager.h\">\r\n      <Filter>Utilities</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\utils\\Log.h\">\r\n      <Filter>Utilities</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\utils\\AABBTree.h\">\r\n      <Filter>Utilities</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\DDS.h\">\r\n      <Filter>Libraries</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\Anim.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\render\\GLExtensions.h\">\r\n      <Filter>Rendering</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame.h\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\LZ4F\\xxhash.h\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\render\\GLMaterial.h\">\r\n      <Filter>Rendering</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\render\\GLOffscreenBuffer.h\">\r\n      <Filter>Rendering</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\program\\NormalsGenDialog.h\">\r\n      <Filter>Program</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\ui\\PreviewPanel.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\ui\\wxNormalsGenDlg.h\">\r\n      <Filter>UI</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\NormalGenLayers.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\utils\\PlatformUtil.h\">\r\n      <Filter>Utilities</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\utils\\StringStuff.h\">\r\n      <Filter>Utilities</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\files\\wxDDSImage.h\">\r\n      <Filter>Files</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\generate_mipmaps.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\gl.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\gli.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\image.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\levels.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\load.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\load_dds.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\load_kmg.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\load_ktx.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\make_texture.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\reduce.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler_cube.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler_cube_array.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler1d.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler1d_array.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler2d.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler2d_array.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\sampler3d.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\save.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\save_dds.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\save_kmg.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\save_ktx.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\target.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture_cube.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture_cube_array.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture1d.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture1d_array.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture2d.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture2d_array.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\texture3d.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\transform.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\type.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\view.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\clear.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\comparison.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\convert.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\copy.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\duplicate.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\dx.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\format.hpp\">\r\n      <Filter>Libraries\\gli</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\convert_func.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\coord.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\file.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\filter.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\filter_compute.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\flip.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\mipmaps_compute.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\s3tc.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\storage.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\storage_linear.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\workaround.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\bc.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\core\\clear.hpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\matrix.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\packing.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\trigonometric.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\vec2.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\vec3.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\vec4.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\vector_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\common.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\exponential.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\fwd.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\geometric.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\glm.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\integer.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle_func.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_vectorize.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_common.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_vector_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\qualifier.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\setup.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_float.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_half.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_quat.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_features.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_fixes.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_noise.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\constants.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\epsilon.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\integer.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_access.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_integer.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_transform.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\noise.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\packing.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\quaternion.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\random.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\reciprocal.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\round.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_aligned.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_ptr.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\ulp.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\vec1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\bitfield.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\color_space.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\common.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\compatibility.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\component_wise.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\easing.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\euler_angles.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extend.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extended_min_max.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\exterior_product.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_exponential.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_square_root.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\functions.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\gradient_paint.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\hash.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\integer.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\intersect.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\io.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\log_base.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_operation.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_query.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\mixed_product.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\norm.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normal.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normalize_dot.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\number_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\optimum_pow.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\orthonormalize.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\perpendicular.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\projection.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\quaternion.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\range.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\raw_data.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_vector.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_multiplication.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\spline.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\std_based_type.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\string_cast.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\texture.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_aligned.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_trait.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vec_swizzle.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_angle.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_query.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\wrap.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\associated_min_max.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\bit.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\closest_point.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_encoding.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_projection.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_transform.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_common.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_transform.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_common.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_constants.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_float_sized.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_int_sized.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_uint_sized.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_ulp.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_common.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_relational.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4_precision.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_ulp.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_common.hpp\">\r\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\matrix.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\packing.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\platform.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\trigonometric.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\vector_relational.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\common.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\exponential.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\geometric.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\integer.h\">\r\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4hc.h\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4.h\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame_static.h\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\BuildSelection.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\ClippingFixer.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"src\\components\\UndoState.h\">\r\n      <Filter>Components</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\pvr_helper.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\SOIL2.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stb_image.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stb_image_write.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS_c.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext_c.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm_c.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr_c.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_c.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_write.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\wfETC.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\image_DXT.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\image_helper.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\SOIL2\\pkm_helper.h\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClInclude>\r\n    <ClInclude Include=\"lib\\LZ4F\\lz4file.h\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClInclude>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <ClCompile Include=\"lib\\TinyXML-2\\tinyxml2.cpp\">\r\n      <Filter>Libraries\\TinyXML-2</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\FSEngine\\FSEngine.cpp\">\r\n      <Filter>Libraries\\FSEngine</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\FSEngine\\FSManager.cpp\">\r\n      <Filter>Libraries\\FSEngine</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\FSEngine\\FSBSA.cpp\">\r\n      <Filter>Libraries\\FSEngine</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\Mesh.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\SliderCategories.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\SliderData.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\SliderGroup.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\SliderManager.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\SliderPresets.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\SliderSet.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\Automorph.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\DiffData.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\files\\ObjFile.cpp\">\r\n      <Filter>Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\files\\ResourceLoader.cpp\">\r\n      <Filter>Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\files\\TriFile.cpp\">\r\n      <Filter>Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\files\\MaterialFile.cpp\">\r\n      <Filter>Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\program\\PresetSaveDialog.cpp\">\r\n      <Filter>Program</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\program\\PreviewWindow.cpp\">\r\n      <Filter>Program</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\program\\BodySlideApp.cpp\">\r\n      <Filter>Program</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\program\\GroupManager.cpp\">\r\n      <Filter>Program</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\render\\GLSurface.cpp\">\r\n      <Filter>Rendering</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\render\\GLShader.cpp\">\r\n      <Filter>Rendering</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\ui\\wxStateButton.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\utils\\ConfigurationManager.cpp\">\r\n      <Filter>Utilities</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\utils\\Log.cpp\">\r\n      <Filter>Utilities</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\utils\\AABBTree.cpp\">\r\n      <Filter>Utilities</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\Anim.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\render\\GLExtensions.cpp\">\r\n      <Filter>Rendering</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\LZ4F\\xxhash.c\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4frame.c\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\render\\GLMaterial.cpp\">\r\n      <Filter>Rendering</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\render\\GLOffscreenBuffer.cpp\">\r\n      <Filter>Rendering</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\program\\NormalsGenDialog.cpp\">\r\n      <Filter>Program</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\ui\\PreviewPanel.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\ui\\wxNormalsGenDlg.cpp\">\r\n      <Filter>UI</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\NormalGenLayers.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\utils\\PlatformUtil.cpp\">\r\n      <Filter>Utilities</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\utils\\StringStuff.cpp\">\r\n      <Filter>Utilities</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\files\\wxDDSImage.cpp\">\r\n      <Filter>Files</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\gli\\core\\dummy.cpp\">\r\n      <Filter>Libraries\\gli\\core</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\gli\\glm\\detail\\glm.cpp\">\r\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4.c\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4hc.c\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\BuildSelection.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"src\\components\\ClippingFixer.cpp\">\r\n      <Filter>Components</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Animation.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\BasicTypes.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\bhk.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\ExtraData.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Factory.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Geometry.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\NifFile.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Nodes.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Object3d.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Objects.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Particles.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Shaders.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\Skin.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\SOIL2\\SOIL2.c\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\SOIL2\\wfETC.c\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\SOIL2\\image_DXT.c\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\SOIL2\\image_helper.c\">\r\n      <Filter>Libraries\\SOIL2</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\LZ4F\\lz4file.c\">\r\n      <Filter>Libraries\\LZ4F</Filter>\r\n    </ClCompile>\r\n    <ClCompile Include=\"lib\\nifly\\src\\NifUtil.cpp\">\r\n      <Filter>Libraries\\nifly\\src</Filter>\r\n    </ClCompile>\r\n  </ItemGroup>\r\n  <ItemGroup>\r\n    <Xml Include=\"Config.xml\">\r\n      <Filter>Resources</Filter>\r\n    </Xml>\r\n  </ItemGroup>\r\n</Project>"
  },
  {
    "path": "BodySlide.xml",
    "content": "<BodySlideConfig>\n    <SelectedOutfit></SelectedOutfit>\n    <SelectedPreset></SelectedPreset>\n    <LastGroupFilter></LastGroupFilter>\n    <LastOutfitFilter></LastOutfitFilter>\n    <BuildMorphs>false</BuildMorphs>\n</BodySlideConfig>\n"
  },
  {
    "path": "BuildSelection.xml",
    "content": "﻿<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<BuildSelection>\n</BuildSelection>\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.11)\n\nproject(BSOS)\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED True)\n\nfind_package(wxWidgets REQUIRED gl core base net xrc adv qa html propgrid)\nfind_package(OpenGL REQUIRED)\nfind_package(GLEW REQUIRED)\nset(fbxsdk_dir ../fbxsdk)\nfind_library(fbxsdk fbxsdk PATHS ${fbxsdk_dir}/lib/gcc/x64/release)\n\nset(commonsources\n\tlib/FSEngine/FSBSA.cpp\n\tlib/FSEngine/FSEngine.cpp\n\tlib/FSEngine/FSManager.cpp\n\tlib/gli/glm/detail/glm.cpp\n\tlib/LZ4F/lz4.c\n\tlib/LZ4F/lz4frame.c\n\tlib/LZ4F/lz4hc.c\n\tlib/LZ4F/xxhash.c\n\tlib/nifly/src/Animation.cpp\n\tlib/nifly/src/BasicTypes.cpp\n\tlib/nifly/src/bhk.cpp\n\tlib/nifly/src/ExtraData.cpp\n\tlib/nifly/src/Factory.cpp\n\tlib/nifly/src/Geometry.cpp\n\tlib/nifly/src/NifFile.cpp\n\tlib/nifly/src/NifUtil.cpp\n\tlib/nifly/src/Nodes.cpp\n\tlib/nifly/src/Object3d.cpp\n\tlib/nifly/src/Objects.cpp\n\tlib/nifly/src/Particles.cpp\n\tlib/nifly/src/Shaders.cpp\n\tlib/nifly/src/Skin.cpp\n\tlib/SOIL2/wfETC.c\n\tlib/SOIL2/image_DXT.c\n\tlib/SOIL2/image_helper.c\n\tlib/SOIL2/SOIL2.c\n\tlib/TinyXML-2/tinyxml2.cpp\n\tsrc/components/Anim.cpp\n\tsrc/components/Automorph.cpp\n\tsrc/components/ClippingFixer.cpp\n\tsrc/components/DiffData.cpp\n\tsrc/components/Mesh.cpp\n\tsrc/components/NormalGenLayers.cpp\n\tsrc/components/SliderCategories.cpp\n\tsrc/components/SliderData.cpp\n\tsrc/components/SliderGroup.cpp\n\tsrc/components/SliderManager.cpp\n\tsrc/components/SliderPresets.cpp\n\tsrc/components/SliderSet.cpp\n\tsrc/files/MaskFile.cpp\n\tsrc/files/MaterialFile.cpp\n\tsrc/files/ResourceLoader.cpp\n\tsrc/files/TriFile.cpp\n\tsrc/program/GroupManager.cpp\n\tsrc/program/PresetSaveDialog.cpp\n\tsrc/render/GLExtensions.cpp\n\tsrc/render/GLMaterial.cpp\n\tsrc/render/GLOffscreenBuffer.cpp\n\tsrc/render/GLShader.cpp\n\tsrc/render/GLSurface.cpp\n\tsrc/render/GLCanvas.cpp\n\tsrc/render/GLDialog.cpp\n\tsrc/ui/wxStateButton.cpp\n\tsrc/ui/wxSliderPanel.cpp\n\tsrc/utils/AABBTree.cpp\n\tsrc/utils/ConfigurationManager.cpp\n\tsrc/utils/Log.cpp\n\tsrc/utils/PlatformUtil.cpp\n\tsrc/utils/StringStuff.cpp\n\t)\nset(OSsources\n\t${commonsources}\n\tsrc/components/PoseData.cpp\n\tsrc/components/PoseDataYaml.cpp\n\tsrc/components/PoseDataJson.cpp\n\tsrc/components/PoseDataHkx.cpp\n\tsrc/components/RefTemplates.cpp\n\tsrc/components/Automation.cpp\n\tsrc/components/TweakBrush.cpp\n\tsrc/components/UndoHistory.cpp\n\tsrc/components/WeightNorm.cpp\n\tsrc/files/FBXWrangler.cpp\n\tsrc/files/HkxFile.cpp\n\tsrc/files/ObjFile.cpp\n\tsrc/files/SFMorphFile.cpp\n\tsrc/ui/wxBrushSettingsPopup.cpp\n\tsrc/ui/WeightCopyDialog.cpp\n\tsrc/program/EditUV.cpp\n\tsrc/program/FBXImportDialog.cpp\n\tsrc/program/ObjImportDialog.cpp\n\tsrc/program/OutfitProject.cpp\n\tsrc/program/OutfitStudio.cpp\n\tsrc/program/ShapeProperties.cpp\n\tsrc/program/ConvertBodyReferenceDialog.cpp\n\tsrc/program/AutomationDialog.cpp\n\tsrc/program/SliderDataImportDialog.cpp\n\t)\nset(BSsources\n\t${commonsources}\n\tsrc/files/wxDDSImage.cpp\n\tsrc/program/BodySlideApp.cpp\n\tsrc/program/NormalsGenDialog.cpp\n\tsrc/program/PreviewWindow.cpp\n\tsrc/ui/PreviewPanel.cpp\n\tsrc/ui/wxNormalsGenDlg.cpp\n\tsrc/components/BuildSelection.cpp\n\t)\n\nadd_executable(OutfitStudio ${OSsources})\nadd_executable(BodySlide ${BSsources})\n\ntarget_compile_definitions(OutfitStudio PRIVATE USE_FBXSDK)\n\ninclude(${wxWidgets_USE_FILE})\ntarget_include_directories(OutfitStudio SYSTEM PRIVATE\n\t${fbxsdk_dir}/include\n\t/usr/include/wine/windows\n\t)\ntarget_include_directories(BodySlide SYSTEM PRIVATE\n\t/usr/include/wine/windows\n\t)\ntarget_include_directories(OutfitStudio PUBLIC\n\tlib/gli\n\tlib/nifly/include\n\tlib/nifly/external\n\tlib/TinyXML-2\n\tlib/fkYAML/include\n\tlib/nlohmannjson/include\n\t)\ntarget_include_directories(BodySlide PUBLIC\n\tlib/gli\n\tlib/nifly/include\n\tlib/nifly/external\n\tlib/TinyXML-2\n\t)\n\ntarget_link_libraries(OutfitStudio\n\t${wxWidgets_LIBRARIES}\n\t${OPENGL_LIBRARIES}\n\t${GLEW_LIBRARIES}\n\t${fbxsdk}\n\txml2)\n\ntarget_link_libraries(BodySlide\n\t${wxWidgets_LIBRARIES}\n\t${OPENGL_LIBRARIES}\n\t${GLEW_LIBRARIES}\n\txml2)\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "Request new features or report bugs by opening an issue on GitHub or commenting on the NexusMods mod pages.\n\nTo submit a patch, please open a pull request on GitHub. If you are thinking of making a large contribution, open an issue for it before starting work.\n\nPlease note the license of the project before committing your work.\n\nTo make it easier to review and accept your pull request, please follow these\nguidelines:\n\n1. Make a new branch on your fork and use that to open a pull request of your changes.\n2. No trailing whitespaces.\n3. Save your indentation as spaces. Tab size is 4 spaces.\n4. Use the following format for curly brackets to be consistent with the rest:\n```cpp\nif (true) {\n  doThing(1);\n  doThing(2);\n}\n```\n"
  },
  {
    "path": "Config.xml",
    "content": "<Config>\r\n    <!-- 0 = FO3, 1 = FONV, 2 = SKYRIM, 3 = FO4, 4 = SKYRIMSE, 5 = FO4VR, 6 = SKYRIMVR, 7 = FO76, 8 = OB, 9 = SF -->\r\n    <TargetGame>-1</TargetGame>\r\n    <WarnMissingGamePath>true</WarnMissingGamePath>\r\n    <BSATextureScan>true</BSATextureScan>\r\n    <!-- Archives black list -->\r\n    <GameDataFiles>\r\n        <Fallout3>Anchorage - Sounds.bsa; BrokenSteel - Sounds.bsa; Fallout - MenuVoices.bsa; Fallout - Meshes.bsa; Fallout - Misc.bsa; Fallout - Sounds.bsa; Fallout - Voices.bsa; PointLookout - Sounds.bsa; ThePitt - Sounds.bsa; Zeta - Sounds.bsa</Fallout3>\r\n        <FalloutNewVegas>DeadMoney - Sounds.bsa; Fallout - Meshes.bsa; Fallout - Misc.bsa; Fallout - Sound.bsa; Fallout - Voices1.bsa; GunRunnersArsenal - Sounds.bsa; HonestHearts - Sounds.bsa; LonesomeRoad - Sounds.bsa; OldWorldBlues - Sounds.bsa</FalloutNewVegas>\r\n        <Skyrim>Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices.bsa; Skyrim - VoicesExtra.bsa</Skyrim>\r\n        <Fallout4>Fallout4 - Animations.ba2; Fallout4 - Interface.ba2; Fallout4 - Meshes.ba2; Fallout4 - MeshesExtra.ba2; Fallout4 - Misc.ba2; Fallout4 - Nvflex.ba2; Fallout4 - Shaders.ba2; Fallout4 - Sounds.ba2; Fallout4 - Startup.ba2; Fallout4 - Voices_en.ba2; DLCCoast - Voices_en.ba2; DLCNukaWorld - Voices_en.ba2; DLCRobot - Voices_en.ba2; DLCworkshop03 - Voices_en.ba2; Fallout4 - Voices_de.ba2; DLCCoast - Voices_de.ba2; DLCNukaWorld - Voices_de.ba2; DLCRobot - Voices_de.ba2; DLCworkshop03 - Voices_de.ba2; DLCUltraHighResolution - Textures01.ba2; DLCUltraHighResolution - Textures02.ba2; DLCUltraHighResolution - Textures03.ba2; DLCUltraHighResolution - Textures04.ba2; DLCUltraHighResolution - Textures05.ba2; DLCUltraHighResolution - Textures06.ba2; DLCUltraHighResolution - Textures07.ba2; DLCUltraHighResolution - Textures08.ba2; DLCUltraHighResolution - Textures09.ba2; DLCUltraHighResolution - Textures10.ba2; DLCUltraHighResolution - Textures11.ba2; DLCUltraHighResolution - Textures12.ba2; DLCUltraHighResolution - Textures13.ba2; DLCUltraHighResolution - Textures14.ba2; DLCUltraHighResolution - Textures15.ba2</Fallout4>\r\n        <SkyrimSpecialEdition>Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes0.bsa; Skyrim - Meshes1.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices_en0.bsa; Skyrim - Voices_de0.bsa</SkyrimSpecialEdition>\r\n        <Fallout4VR>Fallout4 - Animations.ba2; Fallout4 - Interface.ba2; Fallout4 - Meshes.ba2; Fallout4 - MeshesExtra.ba2; Fallout4 - Misc.ba2; Fallout4 - Misc - Beta.ba2; Fallout4 - Misc - Debug.ba2; Fallout4 - Shaders.ba2; Fallout4 - Sounds.ba2; Fallout4 - Startup.ba2; Fallout4 - Voices.ba2; Fallout4 - Voices_en.ba2; Fallout4 - Voices_de.ba2; Fallout4_VR - Shaders.ba2</Fallout4VR>\r\n        <SkyrimVR>Skyrim - Animations.bsa; Skyrim - Interface.bsa; Skyrim - Meshes0.bsa; Skyrim - Meshes1.bsa; Skyrim - Misc.bsa; Skyrim - Shaders.bsa; Skyrim - Sounds.bsa; Skyrim - Voices_en0.bsa; Skyrim - Voices_de0.bsa; Skyrim_VR - Main.bsa</SkyrimVR>\r\n        <Fallout76></Fallout76>\r\n\t\t<Oblivion>Oblivion - Misc.bsa; Oblivion - Sounds.bsa; Oblivion - Voices1.bsa; Oblivion - Voices2.bsa; DLCShiveringIsles - Sounds.bsa; DLCShiveringIsles - Voices.bsa</Oblivion>\r\n\t\t<Starfield>Starfield - Animations.ba2; Starfield - DensityMaps.ba2; Starfield - FaceAnimation01.ba2; Starfield - FaceAnimation02.ba2; Starfield - FaceAnimation03.ba2; Starfield - FaceAnimation04.ba2; Starfield - FaceAnimationPatch.ba2; Starfield - GeneratedTextures.ba2; Starfield - Interface.ba2; Starfield - LODMeshes.ba2; Starfield - LODMeshesPatch.ba2; Starfield - LODTextures01.ba2; Starfield - LODTextures02.ba2; Starfield - Localization.ba2; Starfield - Misc.ba2; Starfield - Particles.ba2; Starfield - PlanetData.ba2; Starfield - Shaders.ba2; Starfield - Terrain01.ba2; Starfield - Terrain02.ba2; Starfield - Terrain03.ba2; Starfield - Terrain04.ba2; Starfield - TerrainPatch.ba2; Starfield - Voices01.ba2; Starfield - Voices02.ba2; Starfield - VoicesPatch.ba2; Starfield - WwiseSounds01.ba2; Starfield - WwiseSounds02.ba2; Starfield - WwiseSounds03.ba2; Starfield - WwiseSounds04.ba2; Starfield - WwiseSounds05.ba2; Starfield - WwiseSoundsPatch.ba2; BlueprintShips-Starfield - Localization.ba2; Constellation - Localization.ba2; OldMars - Localization.ba2; SFBGS003 - Voices_de.ba2; SFBGS003 - Voices_en.ba2; SFBGS003 - Voices_es.ba2; SFBGS003 - Voices_fr.ba2; SFBGS003 - Voices_ja.ba2; SFBGS004 - Voices_de.ba2; SFBGS004 - Voices_en.ba2; SFBGS004 - Voices_es.ba2; SFBGS004 - Voices_fr.ba2; SFBGS004 - Voices_ja.ba2</Starfield></GameDataFiles>\r\n    <GameDataPaths>\r\n        <Fallout3></Fallout3>\r\n        <FalloutNewVegas></FalloutNewVegas>\r\n        <Skyrim></Skyrim>\r\n        <Fallout4></Fallout4>\r\n        <SkyrimSpecialEdition></SkyrimSpecialEdition>\r\n        <Fallout4VR></Fallout4VR>\r\n        <SkyrimVR></SkyrimVR>\r\n        <Fallout76></Fallout76>\r\n        <Oblivion></Oblivion>\r\n        <Starfield></Starfield></GameDataPaths>\r\n    <GameDataPath></GameDataPath>\r\n    <OutputDataPath></OutputDataPath>\r\n    <ProjectPath></ProjectPath>\r\n    <GameRegKey></GameRegKey>\r\n    <GameRegVal></GameRegVal>\r\n    <LogLevel>3</LogLevel>\r\n    <Language>-1</Language>\r\n    <!-- Default groups are the groups virtually assigned to outfits that are not currently members of any groups.\r\n\tThis information is used by BodySlide for choosing what presets to display for outfits.\r\n\tIf the attribute \"includeInBuild\" is true, batch building the specified groups will also build unassigned outfits. -->\r\n    <DefaultGroups includeInBuild=\"true\"></DefaultGroups>\r\n    <!-- Group aliases provide a way for presets saved under older group names to still apply when a group has been renamed -->\r\n    <GroupAliases></GroupAliases>\r\n    <Input>\r\n        <!-- Sets the minimum and maximum slider values for the UI. There might be clipping outside of the 0-100 range! -->\r\n        <SliderMinimum>0</SliderMinimum>\r\n        <SliderMaximum>100</SliderMaximum>\r\n        <!-- Set the left mouse button to pan the view when dragged on the canvas in Outfit Studio -->\r\n        <LeftMousePan>false</LeftMousePan></Input>\r\n    <!--Light Settings-->\r\n    <Lights>\r\n        <Ambient>20</Ambient>\r\n        <Frontal>20</Frontal>\r\n        <Directional0 x=\"-100\" y=\"10\" z=\"100\">60</Directional0>\r\n        <Directional1 x=\"100\" y=\"10\" z=\"100\">60</Directional1>\r\n        <Directional2 x=\"0\" y=\"20\" z=\"-100\">85</Directional2></Lights>\r\n    <!--Rendering Settings-->\r\n    <Rendering>\r\n        <ColorBackground r=\"160\" g=\"160\" b=\"160\"></ColorBackground></Rendering>\r\n    <!-- Animation data. The default skeleton reference is used by Outfit Studio to determine the positions and skinning transforms for all vertices of an outfit -->\r\n    <Anim>\r\n        <DefaultSkeletonReference></DefaultSkeletonReference>\r\n        <SkeletonRootName></SkeletonRootName></Anim>\r\n</Config>\r\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "OutfitStudio.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n  <application xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <windowsSettings>\n      <longPathAware xmlns=\"http://schemas.microsoft.com/SMI/2016/WindowsSettings\">true</longPathAware>\n    </windowsSettings>\n  </application>\n</assembly>\n"
  },
  {
    "path": "OutfitStudio.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{C2F0A3CF-6D9F-4935-8BDF-77EEF7F1C771}</ProjectGuid>\n    <RootNamespace>Outfit Studio</RootNamespace>\n    <Keyword>Win32Proj</Keyword>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v145</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CLRSupport>false</CLRSupport>\n    <UseOfMfc>false</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v145</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CLRSupport>false</CLRSupport>\n    <UseOfMfc>false</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v145</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <PlatformToolset>v145</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>11.0.61030.0</_ProjectFileVersion>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\n    <TargetName>$(ProjectName) Debug</TargetName>\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <TargetName>$(ProjectName) $(Platform) Debug</TargetName>\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <TargetName>$(ProjectName) $(Platform)</TargetName>\n    <OutDir>$(SolutionDir)build\\$(Configuration)\\$(Platform)\\</OutDir>\n    <IntDir>$(SolutionDir)build\\tmp_$(ProjectName)\\$(Configuration)\\$(Platform)\\</IntDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2;lib\\fkYAML\\include;lib\\nlohmannjson\\include</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level4</WarningLevel>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>glu32.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>..\\wxWidgets\\lib\\vc_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\n      <IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\n      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n      <AdditionalManifestFiles>OutfitStudio.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <Optimization>Disabled</Optimization>\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;..\\FBX SDK\\2020.3.7\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2;lib\\fkYAML\\include;lib\\nlohmannjson\\include</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;USE_FBXSDK;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <MinimalRebuild>false</MinimalRebuild>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n      <WarningLevel>Level4</WarningLevel>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>glu32.lib;opengl32.lib;libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>..\\FBX SDK\\2020.3.7\\lib\\x64\\debug;..\\wxWidgets\\lib\\vc_x64_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\n      <IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\n      <AdditionalOptions>/ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n      <AdditionalManifestFiles>OutfitStudio.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2;lib\\fkYAML\\include;lib\\nlohmannjson\\include</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>\n      </FunctionLevelLinking>\n      <WarningLevel>Level4</WarningLevel>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>glu32.lib;opengl32.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>..\\wxWidgets\\lib\\vc_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\n      <IgnoreSpecificDefaultLibraries>\n      </IgnoreSpecificDefaultLibraries>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <PreventDllBinding>\n      </PreventDllBinding>\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\n      <AdditionalOptions>/pdbaltpath:%_PDB% /ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n      <AdditionalManifestFiles>OutfitStudio.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <Optimization>MaxSpeed</Optimization>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <AdditionalIncludeDirectories>..\\wxWidgets\\include\\msvc;..\\wxWidgets\\include;..\\FBX SDK\\2020.3.7\\include;lib\\gli;lib\\nifly\\include;lib\\nifly\\external;lib\\TinyXML-2;lib\\fkYAML\\include;lib\\nlohmannjson\\include</AdditionalIncludeDirectories>\n      <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;WIN32_LEAN_AND_MEAN;NOMINMAX;USE_FBXSDK;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n      <FunctionLevelLinking>\n      </FunctionLevelLinking>\n      <WarningLevel>Level4</WarningLevel>\n      <MultiProcessorCompilation>true</MultiProcessorCompilation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <AdditionalOptions>/bigobj /wd26812 %(AdditionalOptions)</AdditionalOptions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <TreatAngleIncludeAsExternal>true</TreatAngleIncludeAsExternal>\n      <ExternalWarningLevel>Level1</ExternalWarningLevel>\n    </ClCompile>\n    <Link>\n      <AdditionalDependencies>glu32.lib;opengl32.lib;libfbxsdk-mt.lib;libxml2-mt.lib;zlib-mt.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <AdditionalLibraryDirectories>..\\FBX SDK\\2020.3.7\\lib\\x64\\release;..\\wxWidgets\\lib\\vc_x64_lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\n      <IgnoreSpecificDefaultLibraries>\n      </IgnoreSpecificDefaultLibraries>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <SubSystem>Windows</SubSystem>\n      <OptimizeReferences>true</OptimizeReferences>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <PreventDllBinding>\n      </PreventDllBinding>\n      <UACExecutionLevel>AsInvoker</UACExecutionLevel>\n      <AdditionalOptions>/pdbaltpath:%_PDB% /ignore:4099 %(AdditionalOptions)</AdditionalOptions>\n    </Link>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n      <AdditionalManifestFiles>OutfitStudio.manifest</AdditionalManifestFiles>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <Image Include=\"OutfitStudio.ico\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"OutfitStudio.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"lang\\BodySlide.pot\" />\n    <None Include=\"lib\\gli\\core\\bc.inl\" />\n    <None Include=\"lib\\gli\\core\\clear.inl\" />\n    <None Include=\"lib\\gli\\core\\comparison.inl\" />\n    <None Include=\"lib\\gli\\core\\convert.inl\" />\n    <None Include=\"lib\\gli\\core\\copy.inl\" />\n    <None Include=\"lib\\gli\\core\\duplicate.inl\" />\n    <None Include=\"lib\\gli\\core\\dx.inl\" />\n    <None Include=\"lib\\gli\\core\\file.inl\" />\n    <None Include=\"lib\\gli\\core\\filter.inl\" />\n    <None Include=\"lib\\gli\\core\\flip.inl\" />\n    <None Include=\"lib\\gli\\core\\format.inl\" />\n    <None Include=\"lib\\gli\\core\\generate_mipmaps.inl\" />\n    <None Include=\"lib\\gli\\core\\gl.inl\" />\n    <None Include=\"lib\\gli\\core\\image.inl\" />\n    <None Include=\"lib\\gli\\core\\levels.inl\" />\n    <None Include=\"lib\\gli\\core\\load.inl\" />\n    <None Include=\"lib\\gli\\core\\load_dds.inl\" />\n    <None Include=\"lib\\gli\\core\\load_kmg.inl\" />\n    <None Include=\"lib\\gli\\core\\load_ktx.inl\" />\n    <None Include=\"lib\\gli\\core\\make_texture.inl\" />\n    <None Include=\"lib\\gli\\core\\reduce.inl\" />\n    <None Include=\"lib\\gli\\core\\s3tc.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler1d.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler1d_array.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler2d.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler2d_array.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler3d.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler_cube.inl\" />\n    <None Include=\"lib\\gli\\core\\sampler_cube_array.inl\" />\n    <None Include=\"lib\\gli\\core\\save.inl\" />\n    <None Include=\"lib\\gli\\core\\save_dds.inl\" />\n    <None Include=\"lib\\gli\\core\\save_kmg.inl\" />\n    <None Include=\"lib\\gli\\core\\save_ktx.inl\" />\n    <None Include=\"lib\\gli\\core\\storage_linear.inl\" />\n    <None Include=\"lib\\gli\\core\\texture.inl\" />\n    <None Include=\"lib\\gli\\core\\texture1d.inl\" />\n    <None Include=\"lib\\gli\\core\\texture1d_array.inl\" />\n    <None Include=\"lib\\gli\\core\\texture2d.inl\" />\n    <None Include=\"lib\\gli\\core\\texture2d_array.inl\" />\n    <None Include=\"lib\\gli\\core\\texture3d.inl\" />\n    <None Include=\"lib\\gli\\core\\texture_cube.inl\" />\n    <None Include=\"lib\\gli\\core\\texture_cube_array.inl\" />\n    <None Include=\"lib\\gli\\core\\transform.inl\" />\n    <None Include=\"lib\\gli\\core\\view.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_common.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_common_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_half.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x2.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x3.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x4.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x2.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x3.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x4.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x2.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x3.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec1.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec2.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec3.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4.inl\" />\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_common.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_projection.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_relational.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_transform.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_relational.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_transform.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_common.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_constants.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_integer.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_packing.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_relational.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_ulp.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\vector_common.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\vector_integer.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\vector_packing.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\vector_relational.inl\" />\n    <None Include=\"lib\\gli\\glm\\ext\\vector_ulp.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\bitfield.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\color_space.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\constants.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\epsilon.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\integer.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_access.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_transform.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\noise.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\packing.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion_simd.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\random.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\reciprocal.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\round.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\type_precision.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\type_ptr.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtc\\ulp.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\associated_min_max.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\bit.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\closest_point.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\color_encoding.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\common.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\compatibility.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\component_wise.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\easing.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\euler_angles.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\extend.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\extended_min_max.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\exterior_product.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_exponential.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_square_root.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\float_notmalize.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\functions.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\gradient_paint.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\hash.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\integer.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\intersect.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\io.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\log_base.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_operation.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_query.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\mixed_product.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\norm.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\normal.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\normalize_dot.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\number_precision.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\optimum_pow.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\orthonormalize.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\perpendicular.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\projection.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\quaternion.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\raw_data.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_vector.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\scalar_relational.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\spline.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\std_based_type.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\string_cast.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\texture.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\transform.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\transform2.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\type_aligned.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\type_trait.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_angle.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_query.inl\" />\n    <None Include=\"lib\\gli\\glm\\gtx\\wrap.inl\" />\n    <None Include=\"res\\xrc\\About.xrc\" />\n    <None Include=\"res\\xrc\\Actions.xrc\" />\n    <None Include=\"res\\xrc\\ConvertBodyReference.xrc\" />\n    <None Include=\"res\\xrc\\Automation.xrc\" />\n    <None Include=\"res\\xrc\\EditUV.xrc\" />\n    <None Include=\"res\\xrc\\ImportDialog.xrc\" />\n    <None Include=\"res\\xrc\\OutfitStudio.xrc\" />\n    <None Include=\"res\\xrc\\Project.xrc\" />\n    <None Include=\"res\\xrc\\SavePreset.xrc\" />\n    <None Include=\"res\\xrc\\Settings.xrc\" />\n    <None Include=\"res\\xrc\\Setup.xrc\" />\n    <None Include=\"res\\xrc\\ShapeProperties.xrc\" />\n    <None Include=\"res\\xrc\\Skeleton.xrc\" />\n    <None Include=\"res\\xrc\\Slider.xrc\" />\n    <None Include=\"res\\xrc\\WeightCopy.xrc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"lib\\DDS.h\" />\n    <ClInclude Include=\"lib\\fkYAML\\include\\fkYAML\\fkyaml_fwd.hpp\" />\n    <ClInclude Include=\"lib\\fkYAML\\include\\fkYAML\\node.hpp\" />\n    <ClInclude Include=\"lib\\FSEngine\\FSBSA.h\" />\n    <ClInclude Include=\"lib\\FSEngine\\FSEngine.h\" />\n    <ClInclude Include=\"lib\\FSEngine\\FSManager.h\" />\n    <ClInclude Include=\"lib\\gli\\clear.hpp\" />\n    <ClInclude Include=\"lib\\gli\\comparison.hpp\" />\n    <ClInclude Include=\"lib\\gli\\convert.hpp\" />\n    <ClInclude Include=\"lib\\gli\\copy.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\bc.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\clear.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\convert_func.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\coord.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\file.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\filter.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\filter_compute.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\flip.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\mipmaps_compute.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\s3tc.hpp\" />\n    <ClInclude Include=\"lib\\gli\\core\\storage_linear.hpp\" />\n    <ClInclude Include=\"lib\\gli\\duplicate.hpp\" />\n    <ClInclude Include=\"lib\\gli\\dx.hpp\" />\n    <ClInclude Include=\"lib\\gli\\format.hpp\" />\n    <ClInclude Include=\"lib\\gli\\generate_mipmaps.hpp\" />\n    <ClInclude Include=\"lib\\gli\\gl.hpp\" />\n    <ClInclude Include=\"lib\\gli\\gli.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_vector_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\qualifier.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\setup.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_float.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_half.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_quat.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_features.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_fixes.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_noise.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle_func.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_vectorize.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\exponential.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_projection.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_transform.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_transform.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_constants.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_integer.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_int_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_packing.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_uint_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_ulp.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_integer.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_packing.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4_sized.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_ulp.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\fwd.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\geometric.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\glm.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\bitfield.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\color_space.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\constants.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\epsilon.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\integer.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_access.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_integer.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_transform.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\noise.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\packing.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\quaternion.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\random.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\reciprocal.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\round.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_aligned.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_ptr.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\ulp.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\vec1.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\associated_min_max.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\bit.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\closest_point.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_encoding.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\common.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\compatibility.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\component_wise.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\easing.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\euler_angles.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extend.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extended_min_max.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\exterior_product.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_exponential.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_square_root.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\functions.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\gradient_paint.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\hash.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\integer.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\intersect.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\io.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\log_base.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_operation.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_query.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\mixed_product.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\norm.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normal.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normalize_dot.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\number_precision.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\optimum_pow.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\orthonormalize.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\perpendicular.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\projection.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\quaternion.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\range.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\raw_data.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_vector.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_multiplication.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\spline.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\std_based_type.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\string_cast.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\texture.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_aligned.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_trait.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_angle.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_query.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vec_swizzle.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\wrap.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\integer.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\matrix.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\packing.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\common.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\exponential.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\geometric.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\integer.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\matrix.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\neon.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\packing.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\platform.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\trigonometric.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\vector_relational.h\" />\n    <ClInclude Include=\"lib\\gli\\glm\\trigonometric.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\vec2.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\vec3.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\vec4.hpp\" />\n    <ClInclude Include=\"lib\\gli\\glm\\vector_relational.hpp\" />\n    <ClInclude Include=\"lib\\gli\\image.hpp\" />\n    <ClInclude Include=\"lib\\gli\\levels.hpp\" />\n    <ClInclude Include=\"lib\\gli\\load.hpp\" />\n    <ClInclude Include=\"lib\\gli\\load_dds.hpp\" />\n    <ClInclude Include=\"lib\\gli\\load_kmg.hpp\" />\n    <ClInclude Include=\"lib\\gli\\load_ktx.hpp\" />\n    <ClInclude Include=\"lib\\gli\\make_texture.hpp\" />\n    <ClInclude Include=\"lib\\gli\\reduce.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler1d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler1d_array.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler2d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler2d_array.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler3d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler_cube.hpp\" />\n    <ClInclude Include=\"lib\\gli\\sampler_cube_array.hpp\" />\n    <ClInclude Include=\"lib\\gli\\save.hpp\" />\n    <ClInclude Include=\"lib\\gli\\save_dds.hpp\" />\n    <ClInclude Include=\"lib\\gli\\save_kmg.hpp\" />\n    <ClInclude Include=\"lib\\gli\\save_ktx.hpp\" />\n    <ClInclude Include=\"lib\\gli\\target.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture1d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture1d_array.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture2d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture2d_array.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture3d.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture_cube.hpp\" />\n    <ClInclude Include=\"lib\\gli\\texture_cube_array.hpp\" />\n    <ClInclude Include=\"lib\\gli\\transform.hpp\" />\n    <ClInclude Include=\"lib\\gli\\type.hpp\" />\n    <ClInclude Include=\"lib\\gli\\view.hpp\" />\n    <ClInclude Include=\"lib\\LZ4F\\lz4.h\" />\n    <ClInclude Include=\"lib\\LZ4F\\lz4file.h\" />\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame.h\" />\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame_static.h\" />\n    <ClInclude Include=\"lib\\LZ4F\\lz4hc.h\" />\n    <ClInclude Include=\"lib\\LZ4F\\xxhash.h\" />\n    <ClInclude Include=\"lib\\nlohmannjson\\include\\nlohmann\\json.hpp\" />\n    <ClInclude Include=\"lib\\nlohmannjson\\include\\nlohmann\\json_fwd.hpp\" />\n    <ClInclude Include=\"lib\\SOIL2\\image_DXT.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\image_helper.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\pkm_helper.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\pvr_helper.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\SOIL2.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS_c.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext_c.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm_c.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr_c.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_c.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_write.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stb_image.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\stb_image_write.h\" />\n    <ClInclude Include=\"lib\\SOIL2\\wfETC.h\" />\n    <ClInclude Include=\"lib\\TinyXML-2\\tinyxml2.h\" />\n    <ClInclude Include=\"resource.h\" />\n    <ClInclude Include=\"src\\components\\Anim.h\" />\n    <ClInclude Include=\"src\\components\\Automorph.h\" />\n    <ClInclude Include=\"src\\components\\ClippingFixer.h\" />\n    <ClInclude Include=\"src\\components\\DiffData.h\" />\n    <ClInclude Include=\"src\\components\\Mesh.h\" />\n    <ClInclude Include=\"src\\components\\NormalGenLayers.h\" />\n    <ClInclude Include=\"src\\components\\PoseData.h\" />\n    <ClInclude Include=\"src\\components\\RefTemplates.h\" />\n    <ClInclude Include=\"src\\components\\SliderCategories.h\" />\n    <ClInclude Include=\"src\\components\\SliderData.h\" />\n    <ClInclude Include=\"src\\components\\SliderGroup.h\" />\n    <ClInclude Include=\"src\\components\\SliderManager.h\" />\n    <ClInclude Include=\"src\\components\\SliderPresets.h\" />\n    <ClInclude Include=\"src\\components\\SliderSet.h\" />\n    <ClInclude Include=\"src\\components\\TweakBrush.h\" />\n    <ClInclude Include=\"src\\components\\UndoState.h\" />\n    <ClInclude Include=\"src\\components\\UndoHistory.h\" />\n    <ClInclude Include=\"src\\components\\WeightNorm.h\" />\n    <ClInclude Include=\"src\\files\\FBXWrangler.h\" />\n    <ClInclude Include=\"src\\files\\MaterialFile.h\" />\n    <ClInclude Include=\"src\\files\\ObjFile.h\" />\n    <ClInclude Include=\"src\\files\\ResourceLoader.h\" />\n    <ClInclude Include=\"src\\files\\SFMorphFile.h\" />\n    <ClInclude Include=\"src\\files\\TriFile.h\" />\n    <ClInclude Include=\"src\\files\\MaskFile.h\" />\n    <ClInclude Include=\"src\\files\\HkxFile.h\" />\n    <ClInclude Include=\"src\\program\\ConvertBodyReferenceDialog.h\" />\n    <ClInclude Include=\"src\\program\\AutomationDialog.h\" />\n    <ClInclude Include=\"src\\components\\Automation.h\" />\n    <ClInclude Include=\"src\\program\\EditUV.h\" />\n    <ClInclude Include=\"src\\program\\FBXImportDialog.h\" />\n    <ClInclude Include=\"src\\program\\GroupManager.h\" />\n    <ClInclude Include=\"src\\program\\ObjImportDialog.h\" />\n    <ClInclude Include=\"src\\program\\OutfitProject.h\" />\n    <ClInclude Include=\"src\\program\\OutfitStudio.h\" />\n    <ClInclude Include=\"src\\program\\PresetSaveDialog.h\" />\n    <ClInclude Include=\"src\\program\\ShapeProperties.h\" />\n    <ClInclude Include=\"src\\program\\SliderDataImportDialog.h\" />\n    <ClInclude Include=\"src\\render\\GLCanvas.h\" />\n    <ClInclude Include=\"src\\render\\GLDialog.h\" />\n    <ClInclude Include=\"src\\render\\GLExtensions.h\" />\n    <ClInclude Include=\"src\\render\\GLMaterial.h\" />\n    <ClInclude Include=\"src\\render\\GLOffscreenBuffer.h\" />\n    <ClInclude Include=\"src\\render\\GLShader.h\" />\n    <ClInclude Include=\"src\\render\\GLSurface.h\" />\n    <ClInclude Include=\"src\\ui\\wxBrushSettingsPopup.h\" />\n    <ClInclude Include=\"src\\ui\\WeightCopyDialog.h\" />\n    <ClInclude Include=\"src\\ui\\wxSliderPanel.h\" />\n    <ClInclude Include=\"src\\ui\\wxStateButton.h\" />\n    <ClInclude Include=\"src\\utils\\AABBTree.h\" />\n    <ClInclude Include=\"src\\utils\\ConfigurationManager.h\" />\n    <ClInclude Include=\"src\\utils\\ConfigDialogUtil.h\" />\n    <ClInclude Include=\"src\\utils\\Log.h\" />\n    <ClInclude Include=\"src\\utils\\PlatformUtil.h\" />\n    <ClInclude Include=\"src\\utils\\StringStuff.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"lib\\FSEngine\\FSBSA.cpp\" />\n    <ClCompile Include=\"lib\\FSEngine\\FSEngine.cpp\" />\n    <ClCompile Include=\"lib\\FSEngine\\FSManager.cpp\" />\n    <ClCompile Include=\"lib\\gli\\core\\dummy.cpp\" />\n    <ClCompile Include=\"lib\\gli\\glm\\detail\\glm.cpp\" />\n    <ClCompile Include=\"lib\\LZ4F\\lz4.c\" />\n    <ClCompile Include=\"lib\\LZ4F\\lz4file.c\" />\n    <ClCompile Include=\"lib\\LZ4F\\lz4frame.c\" />\n    <ClCompile Include=\"lib\\LZ4F\\lz4hc.c\" />\n    <ClCompile Include=\"lib\\LZ4F\\xxhash.c\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Animation.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\BasicTypes.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\bhk.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\ExtraData.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Factory.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Geometry.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\NifFile.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\NifUtil.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Nodes.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Object3d.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Objects.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Particles.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Shaders.cpp\" />\n    <ClCompile Include=\"lib\\nifly\\src\\Skin.cpp\" />\n    <ClCompile Include=\"lib\\SOIL2\\image_DXT.c\" />\n    <ClCompile Include=\"lib\\SOIL2\\image_helper.c\" />\n    <ClCompile Include=\"lib\\SOIL2\\SOIL2.c\" />\n    <ClCompile Include=\"lib\\SOIL2\\wfETC.c\" />\n    <ClCompile Include=\"lib\\TinyXML-2\\tinyxml2.cpp\" />\n    <ClCompile Include=\"src\\components\\Anim.cpp\" />\n    <ClCompile Include=\"src\\components\\Automorph.cpp\" />\n    <ClCompile Include=\"src\\components\\ClippingFixer.cpp\" />\n    <ClCompile Include=\"src\\components\\DiffData.cpp\" />\n    <ClCompile Include=\"src\\components\\Mesh.cpp\" />\n    <ClCompile Include=\"src\\components\\NormalGenLayers.cpp\" />\n    <ClCompile Include=\"src\\components\\PoseData.cpp\" />\n    <ClCompile Include=\"src\\components\\PoseDataYaml.cpp\" />\n    <ClCompile Include=\"src\\components\\PoseDataJson.cpp\" />\n    <ClCompile Include=\"src\\components\\PoseDataHkx.cpp\" />\n    <ClCompile Include=\"src\\components\\RefTemplates.cpp\" />\n    <ClCompile Include=\"src\\components\\SliderCategories.cpp\" />\n    <ClCompile Include=\"src\\components\\SliderData.cpp\" />\n    <ClCompile Include=\"src\\components\\SliderGroup.cpp\" />\n    <ClCompile Include=\"src\\components\\SliderManager.cpp\" />\n    <ClCompile Include=\"src\\components\\SliderPresets.cpp\" />\n    <ClCompile Include=\"src\\components\\SliderSet.cpp\" />\n    <ClCompile Include=\"src\\components\\TweakBrush.cpp\" />\n    <ClCompile Include=\"src\\components\\UndoHistory.cpp\" />\n    <ClCompile Include=\"src\\components\\WeightNorm.cpp\" />\n    <ClCompile Include=\"src\\files\\FBXWrangler.cpp\" />\n    <ClCompile Include=\"src\\files\\MaterialFile.cpp\" />\n    <ClCompile Include=\"src\\files\\ObjFile.cpp\" />\n    <ClCompile Include=\"src\\files\\ResourceLoader.cpp\" />\n    <ClCompile Include=\"src\\files\\SFMorphFile.cpp\" />\n    <ClCompile Include=\"src\\files\\TriFile.cpp\" />\n    <ClCompile Include=\"src\\files\\MaskFile.cpp\" />\n    <ClCompile Include=\"src\\files\\HkxFile.cpp\" />\n    <ClCompile Include=\"src\\program\\ConvertBodyReferenceDialog.cpp\" />\n    <ClCompile Include=\"src\\program\\AutomationDialog.cpp\" />\n    <ClCompile Include=\"src\\components\\Automation.cpp\" />\n    <ClCompile Include=\"src\\program\\EditUV.cpp\" />\n    <ClCompile Include=\"src\\program\\FBXImportDialog.cpp\" />\n    <ClCompile Include=\"src\\program\\GroupManager.cpp\" />\n    <ClCompile Include=\"src\\program\\ObjImportDialog.cpp\" />\n    <ClCompile Include=\"src\\program\\OutfitProject.cpp\" />\n    <ClCompile Include=\"src\\program\\OutfitStudio.cpp\" />\n    <ClCompile Include=\"src\\program\\PresetSaveDialog.cpp\" />\n    <ClCompile Include=\"src\\program\\ShapeProperties.cpp\" />\n    <ClCompile Include=\"src\\program\\SliderDataImportDialog.cpp\" />\n    <ClCompile Include=\"src\\render\\GLCanvas.cpp\" />\n    <ClCompile Include=\"src\\render\\GLDialog.cpp\" />\n    <ClCompile Include=\"src\\render\\GLExtensions.cpp\" />\n    <ClCompile Include=\"src\\render\\GLMaterial.cpp\" />\n    <ClCompile Include=\"src\\render\\GLOffscreenBuffer.cpp\" />\n    <ClCompile Include=\"src\\render\\GLShader.cpp\" />\n    <ClCompile Include=\"src\\render\\GLSurface.cpp\" />\n    <ClCompile Include=\"src\\ui\\wxBrushSettingsPopup.cpp\" />\n    <ClCompile Include=\"src\\ui\\WeightCopyDialog.cpp\" />\n    <ClCompile Include=\"src\\ui\\wxSliderPanel.cpp\" />\n    <ClCompile Include=\"src\\ui\\wxStateButton.cpp\" />\n    <ClCompile Include=\"src\\utils\\AABBTree.cpp\" />\n    <ClCompile Include=\"src\\utils\\ConfigurationManager.cpp\" />\n    <ClCompile Include=\"src\\utils\\Log.cpp\" />\n    <ClCompile Include=\"src\\utils\\PlatformUtil.cpp\" />\n    <ClCompile Include=\"src\\utils\\StringStuff.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"Config.xml\" />\n    <Xml Include=\"res\\xrc\\SliderDataImport.xrc\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "OutfitStudio.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Resources\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\n    </Filter>\n    <Filter Include=\"Libraries\">\n      <UniqueIdentifier>{6d6b425f-03aa-4210-b6af-ac49bf12352d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\FSEngine\">\n      <UniqueIdentifier>{6f3ea695-40d7-4be2-a951-168ba3339081}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\">\n      <UniqueIdentifier>{e366b310-4d8d-4f5e-b43d-0aa7f0edeef1}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\TinyXML-2\">\n      <UniqueIdentifier>{fd5a7d0f-084f-4202-b4d6-67732f2c2302}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\core\">\n      <UniqueIdentifier>{5857b5e3-d66f-4467-ab4d-f70856237a1a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\glm\">\n      <UniqueIdentifier>{cf289f86-ccae-4cd8-81db-71adb8328b06}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\glm\\detail\">\n      <UniqueIdentifier>{9222d26f-5381-4e83-b3d9-bbef711a1f09}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\glm\\gtc\">\n      <UniqueIdentifier>{18fc42a9-9067-4638-bb32-7a671746137a}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\glm\\gtx\">\n      <UniqueIdentifier>{5359067a-dabf-4cb9-a13d-bb37b483c638}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Components\">\n      <UniqueIdentifier>{8e852d2f-5f87-416d-be07-c75179e8f57e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Files\">\n      <UniqueIdentifier>{782be5c1-aa6f-4e54-acb4-c89dc11d2fcb}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Program\">\n      <UniqueIdentifier>{82ef2505-7b08-4871-b498-b758d860f25c}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Rendering\">\n      <UniqueIdentifier>{def5c486-38d5-46f3-87b8-5d17825c309e}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"UI\">\n      <UniqueIdentifier>{0e8c63ba-3164-40f0-a35e-7feb262c883b}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Utilities\">\n      <UniqueIdentifier>{575c3247-33ba-4a9b-8af4-649cb8b54d10}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\LZ4F\">\n      <UniqueIdentifier>{1dd6227a-2c07-441b-a703-df5e11788296}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\SOIL2\">\n      <UniqueIdentifier>{746df173-aa97-45f5-9200-676a6b050846}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\glm\\ext\">\n      <UniqueIdentifier>{29047cf6-171b-41a4-9dd3-9725559f19dd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\gli\\glm\\simd\">\n      <UniqueIdentifier>{c651ea53-1ed3-4f8d-8e11-0aa04e6b9ad6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\nifly\">\n      <UniqueIdentifier>{1e51341d-129d-409d-90b0-f83a0c40f24d}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\nifly\\src\">\n      <UniqueIdentifier>{d95f2d14-c32c-42eb-8742-c174b699d5fe}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\fkYAML\">\n      <UniqueIdentifier>{3f339eee-e545-4d1d-a050-a3d2fbb686cd}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Libraries\\nlohmannjson\">\n      <UniqueIdentifier>{dccfbf1e-b15e-4cf8-a112-7c543d854aa8}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"OutfitStudio.ico\">\n      <Filter>Resources</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"OutfitStudio.rc\">\n      <Filter>Resources</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"res\\xrc\\OutfitStudio.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Project.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\SavePreset.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Settings.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\ShapeProperties.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Skeleton.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Slider.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\About.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Actions.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Setup.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\WeightCopy.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"lang\\BodySlide.pot\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\copy.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\duplicate.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\dx.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\file.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\filter.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\flip.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\format.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\generate_mipmaps.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\gl.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\image.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\levels.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\load.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\load_dds.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\load_kmg.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\load_ktx.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\make_texture.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\reduce.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\s3tc.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler_cube.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler_cube_array.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler1d.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler1d_array.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler2d.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler2d_array.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\sampler3d.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\save.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\save_dds.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\save_kmg.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\save_ktx.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\storage_linear.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture_cube.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture_cube_array.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture1d.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture1d_array.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture2d.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture2d_array.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\texture3d.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\transform.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\view.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\bc.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\clear.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\comparison.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\core\\convert.inl\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_common.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_common_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_exponential_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_geometric_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_integer_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_matrix_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_packing_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_trigonometric_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\func_vector_relational_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_half.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x2.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x3.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat2x4.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x2.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x3.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat3x4.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x2.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x3.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_mat4x4_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_quat_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec1.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec2.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec3.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\detail\\type_vec4_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\epsilon.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\integer.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_access.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\matrix_transform.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\noise.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\packing.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\quaternion_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\random.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\reciprocal.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\round.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\type_precision.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\type_ptr.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\ulp.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\bitfield.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\color_space.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtc\\constants.inl\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\common.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\compatibility.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\component_wise.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\easing.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\euler_angles.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\extend.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\extended_min_max.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\exterior_product.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_exponential.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_square_root.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\float_notmalize.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\functions.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\gradient_paint.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\hash.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\integer.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\intersect.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\io.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\log_base.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_operation.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_query.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\mixed_product.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\norm.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\normal.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\normalize_dot.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\number_precision.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\optimum_pow.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\orthonormalize.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\perpendicular.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\projection.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\quaternion.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\raw_data.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\rotate_vector.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\scalar_relational.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\spline.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\std_based_type.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\string_cast.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\texture.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\transform.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\transform2.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\type_aligned.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\type_trait.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_angle.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\vector_query.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\wrap.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\associated_min_max.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\bit.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\closest_point.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\color_encoding.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.inl\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </None>\n    <None Include=\"res\\xrc\\ConvertBodyReference.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\Automation.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_common.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_projection.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_relational.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\matrix_transform.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_common_simd.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_relational.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_transform.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_common.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_constants.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_integer.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_packing.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_relational.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\scalar_ulp.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\vector_common.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\vector_integer.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\vector_packing.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\vector_relational.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"lib\\gli\\glm\\ext\\vector_ulp.inl\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </None>\n    <None Include=\"res\\xrc\\EditUV.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n    <None Include=\"res\\xrc\\ImportDialog.xrc\">\n      <Filter>Resources</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"resource.h\">\n      <Filter>Resources</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\TinyXML-2\\tinyxml2.h\">\n      <Filter>Libraries\\TinyXML-2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\FSEngine\\FSEngine.h\">\n      <Filter>Libraries\\FSEngine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\FSEngine\\FSManager.h\">\n      <Filter>Libraries\\FSEngine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\FSEngine\\FSBSA.h\">\n      <Filter>Libraries\\FSEngine</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\DiffData.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\Mesh.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\SliderCategories.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\SliderData.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\SliderGroup.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\SliderManager.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\SliderPresets.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\SliderSet.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\TweakBrush.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\UndoState.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\UndoHistory.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\WeightNorm.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\Automorph.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\ClippingFixer.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\ObjFile.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\ResourceLoader.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\TriFile.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\MaskFile.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\HkxFile.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\FBXWrangler.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\MaterialFile.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\OutfitStudio.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\PresetSaveDialog.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\ShapeProperties.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\OutfitProject.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLShader.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLSurface.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\ui\\wxStateButton.h\">\n      <Filter>UI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\utils\\ConfigurationManager.h\">\n      <Filter>Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\utils\\Log.h\">\n      <Filter>Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\utils\\AABBTree.h\">\n      <Filter>Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\DDS.h\">\n      <Filter>Libraries</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\Anim.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\FBXImportDialog.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLExtensions.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\LZ4F\\xxhash.h\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLMaterial.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLOffscreenBuffer.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\NormalGenLayers.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\utils\\PlatformUtil.h\">\n      <Filter>Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\utils\\StringStuff.h\">\n      <Filter>Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\coord.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\file.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\filter.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\filter_compute.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\flip.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\mipmaps_compute.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\s3tc.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\storage_linear.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\bc.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\clear.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\core\\convert_func.hpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\target.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture_cube.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture_cube_array.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture1d.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture1d_array.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture2d.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture2d_array.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\texture3d.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\transform.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\type.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\view.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\clear.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\comparison.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\convert.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\copy.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\duplicate.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\dx.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\format.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\generate_mipmaps.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\gl.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\gli.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\image.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\levels.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\load.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\load_dds.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\load_kmg.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\load_ktx.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\make_texture.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\reduce.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler_cube.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler_cube_array.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler1d.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler1d_array.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler2d.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler2d_array.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\sampler3d.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\save.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\save_dds.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\save_kmg.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\save_ktx.hpp\">\n      <Filter>Libraries\\gli</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x4.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\matrix.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\packing.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\trigonometric.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\vec2.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\vec3.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\vec4.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\vector_relational.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\common.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\exponential.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\fwd.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\geometric.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\glm.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\integer.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x2.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x3.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat2x4.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x2.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x3.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat3x4.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x2.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\mat4x3.hpp\">\n      <Filter>Libraries\\gli\\glm</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_noise.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_swizzle_func.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_vectorize.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_common.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\compute_vector_relational.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\qualifier.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\setup.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_float.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_half.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat2x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat3x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_mat4x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_quat.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec1.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec2.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec3.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\type_vec4.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_features.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\detail\\_fixes.hpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\platform.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\trigonometric.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\vector_relational.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\common.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\exponential.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\geometric.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\integer.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\matrix.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\packing.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\epsilon.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\integer.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_access.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_integer.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_inverse.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\matrix_transform.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\noise.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\packing.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\quaternion.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\random.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\reciprocal.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\round.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_aligned.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\type_ptr.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\ulp.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\vec1.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\bitfield.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\color_space.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtc\\constants.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtc</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\common.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\compatibility.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\component_wise.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\dual_quaternion.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\easing.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\euler_angles.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extend.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\extended_min_max.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\exterior_product.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_exponential.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_square_root.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\fast_trigonometry.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\functions.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\gradient_paint.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\handed_coordinate_space.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\hash.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\integer.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\intersect.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\io.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\log_base.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_cross_product.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_decompose.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_factorisation.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_interpolation.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_major_storage.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_operation.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_query.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\matrix_transform_2d.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\mixed_product.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\norm.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normal.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\normalize_dot.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\number_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\optimum_pow.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\orthonormalize.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\perpendicular.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\polar_coordinates.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\projection.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\quaternion.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\range.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\raw_data.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_normalized_axis.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\rotate_vector.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_multiplication.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\scalar_relational.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\spline.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\std_based_type.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\string_cast.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\texture.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\transform2.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_aligned.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\type_trait.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vec_swizzle.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_angle.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\vector_query.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\wrap.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\associated_min_max.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\bit.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\closest_point.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_encoding.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\gtx\\color_space_YCoCg.hpp\">\n      <Filter>Libraries\\gli\\glm\\gtx</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\LZ4F\\lz4.h\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame_static.h\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\LZ4F\\lz4hc.h\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\LZ4F\\lz4frame.h\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\GroupManager.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\EditUV.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\RefTemplates.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\PoseData.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\ui\\wxBrushSettingsPopup.h\">\n      <Filter>UI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\ui\\WeightCopyDialog.h\">\n      <Filter>UI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\ui\\wxSliderPanel.h\">\n      <Filter>UI</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\ConvertBodyReferenceDialog.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\AutomationDialog.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\components\\Automation.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\utils\\ConfigDialogUtil.h\">\n      <Filter>Utilities</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\SliderDataImportDialog.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_clip_space.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_common.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double2x4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double3x4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_double4x4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float2x4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float3x4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_float4x4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int2x4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int3x4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_int4x4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_projection.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_relational.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_transform.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint2x4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint3x4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\matrix_uint4x4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_common.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_double_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_exponential.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_float_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_geometric.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_relational.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_transform.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\quaternion_trigonometric.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_common.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_constants.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_int_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_integer.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_packing.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_relational.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_uint_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\scalar_ulp.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool1_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_bool4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_common.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double1_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_double4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float1_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float2_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float3_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_float4_precision.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int1_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_int4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_integer.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_packing.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_relational.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint1_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint2_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint3_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_uint4_sized.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\ext\\vector_ulp.hpp\">\n      <Filter>Libraries\\gli\\glm\\ext</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\gli\\glm\\simd\\neon.h\">\n      <Filter>Libraries\\gli\\glm\\simd</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLCanvas.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\render\\GLDialog.h\">\n      <Filter>Rendering</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\program\\ObjImportDialog.h\">\n      <Filter>Program</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stb_image.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stb_image_write.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_DDS_c.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_ext_c.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pkm_c.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_pvr_c.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_c.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\stbi_qoi_write.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\wfETC.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\image_DXT.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\image_helper.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\pkm_helper.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\pvr_helper.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\SOIL2\\SOIL2.h\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\LZ4F\\lz4file.h\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClInclude>\n    <ClInclude Include=\"src\\files\\SFMorphFile.h\">\n      <Filter>Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\fkYAML\\include\\fkYAML\\fkyaml_fwd.hpp\">\n      <Filter>Libraries\\fkYAML</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\fkYAML\\include\\fkYAML\\node.hpp\">\n      <Filter>Libraries\\fkYAML</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\nlohmannjson\\include\\nlohmann\\json.hpp\">\n      <Filter>Libraries\\nlohmannjson</Filter>\n    </ClInclude>\n    <ClInclude Include=\"lib\\nlohmannjson\\include\\nlohmann\\json_fwd.hpp\">\n      <Filter>Libraries\\nlohmannjson</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"lib\\TinyXML-2\\tinyxml2.cpp\">\n      <Filter>Libraries\\TinyXML-2</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\FSEngine\\FSEngine.cpp\">\n      <Filter>Libraries\\FSEngine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\FSEngine\\FSManager.cpp\">\n      <Filter>Libraries\\FSEngine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\FSEngine\\FSBSA.cpp\">\n      <Filter>Libraries\\FSEngine</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\Mesh.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\SliderCategories.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\SliderData.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\SliderGroup.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\SliderManager.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\SliderPresets.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\SliderSet.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\TweakBrush.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\UndoHistory.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\WeightNorm.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\Automorph.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\ClippingFixer.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\DiffData.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\ObjFile.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\ResourceLoader.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\TriFile.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\MaskFile.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\HkxFile.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\FBXWrangler.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\MaterialFile.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\OutfitStudio.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\PresetSaveDialog.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\ShapeProperties.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\OutfitProject.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLSurface.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLShader.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\ui\\wxStateButton.cpp\">\n      <Filter>UI</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\utils\\ConfigurationManager.cpp\">\n      <Filter>Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\utils\\Log.cpp\">\n      <Filter>Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\utils\\AABBTree.cpp\">\n      <Filter>Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\Anim.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\FBXImportDialog.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLExtensions.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\LZ4F\\xxhash.c\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\LZ4F\\lz4frame.c\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLMaterial.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLOffscreenBuffer.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\NormalGenLayers.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\utils\\PlatformUtil.cpp\">\n      <Filter>Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\utils\\StringStuff.cpp\">\n      <Filter>Utilities</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\gli\\core\\dummy.cpp\">\n      <Filter>Libraries\\gli\\core</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\gli\\glm\\detail\\glm.cpp\">\n      <Filter>Libraries\\gli\\glm\\detail</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\LZ4F\\lz4hc.c\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\LZ4F\\lz4.c\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\GroupManager.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\EditUV.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\RefTemplates.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Animation.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\BasicTypes.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\bhk.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\ExtraData.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Factory.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Geometry.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\NifFile.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Nodes.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Object3d.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Objects.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Particles.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Shaders.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\Skin.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\PoseData.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\PoseDataYaml.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\PoseDataJson.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\PoseDataHkx.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\ui\\wxBrushSettingsPopup.cpp\">\n      <Filter>UI</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\ui\\WeightCopyDialog.cpp\">\n      <Filter>UI</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\ui\\wxSliderPanel.cpp\">\n      <Filter>UI</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\ConvertBodyReferenceDialog.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\AutomationDialog.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\components\\Automation.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\SliderDataImportDialog.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLDialog.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\render\\GLCanvas.cpp\">\n      <Filter>Rendering</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\program\\ObjImportDialog.cpp\">\n      <Filter>Program</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\SOIL2\\wfETC.c\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\SOIL2\\image_DXT.c\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\SOIL2\\image_helper.c\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\SOIL2\\SOIL2.c\">\n      <Filter>Libraries\\SOIL2</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\LZ4F\\lz4file.c\">\n      <Filter>Libraries\\LZ4F</Filter>\n    </ClCompile>\n    <ClCompile Include=\"src\\files\\SFMorphFile.cpp\">\n      <Filter>Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"lib\\nifly\\src\\NifUtil.cpp\">\n      <Filter>Libraries\\nifly\\src</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <Xml Include=\"Config.xml\">\n      <Filter>Resources</Filter>\n    </Xml>\n    <Xml Include=\"res\\xrc\\SliderDataImport.xrc\">\n      <Filter>Resources</Filter>\n    </Xml>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "OutfitStudio.xml",
    "content": "<OutfitStudioConfig>\n</OutfitStudioConfig>\n"
  },
  {
    "path": "README.md",
    "content": "BodySlide-and-Outfit-Studio\n===========================\n\nBodySlide and Outfit Studio, a tool to convert, create, and customize outfits and bodies for The Elder Scrolls and Fallout.\n\n**Created by and/or with the help of:**\n* Caliente\n* ousnius\n* jonwd7 for NIF and general help\n* degenerated1123 for help with shaders\n* NifTools team\n\n**Libraries used:**\n* OpenGL\n* OpenGL Image (GLI)\n* Simple OpenGL Image Library 2 (SOIL2)\n* TinyXML-2\n* FSEngine (BSA/BA2 library)\n* Autodesk FBX SDK\n* half - IEEE 754-based half-precision floating point library\n* Miniball\n* LZ4(F)\n* wxWidgets\n\nhttps://github.com/ousnius/BodySlide-and-Outfit-Studio/wiki"
  },
  {
    "path": "Readme-linux.txt",
    "content": "Building BodySlide and Outfit Studio on Linux\n\nThere's just one file that specifies the build process: CMakeLists.txt.\n\nInstall wxWidgets 3.1.3 or newer.  If you get errors about an ABI\nmismatch, that means you compiled wxWidgets with a different compiler\nversion than BS&OS.  Either gtk2 or gtk3 works.  With gtk2, you have\nmore background color problems; with gtk3, many widgets are distorted\nbecause they don't have enough space.  Note that many of wxWidget's\nconfigure options (such as --enable-universal) result in a broken\nwxWidgets library, so prefer to use as few options as possible.\nAlso note that some distribution-provided wxWidgets packages are\nbroken, so it's likely that you'll have to build wxWidgets yourself\n(which is really easy).\n\nInstall FBX SDK.  Put the path to your FBX SDK installation in the\nfbxsdk_dir variable in CMakeLists.txt.\n\nMake sure GLEW is installed.\n\nThen go to your BodySlide-and-Outfit-Studio directory and do:\nmkdir Release\ncd Release\ncmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=\"-Wall\" ..\nmake\n\nThe possible values for CMAKE_BUILD_TYPE:\n\tRelease\n\tRelWithDebInfo\n\tDebug\n\tMinSizeRel\n\t(nothing)\n\nThe -Wall option is optional.  If you don't care about compiler\nwarnings, you should probably skip this option.\n\nTo specify the compiler, set CC and CXX before running cmake.\nThe build directory must be completely empty, or cmake will ignore CC\nand CXX and use the same compilers as it did last time.  Don't forget\nto build wxWidgets with the same compiler; the wxWidgets configure script\nalso uses the CC and CXX environment variables.\n\nSome useful make options:\nmake VERBOSE=1\nmake -j 4\n\nThe BodySlide and OutfitStudio executables need to be able to find\nthe res directory, which contains important program data such as xrc\nfiles and icons.  By default, the executables search for the res\ndirectory in the same directory as the executables.  So, when you\ncopy the executables into the BodySlide directory within your game,\nyou need to copy the entire res directory too.\n\nIf you don't want to copy the executables to the BodySlide\ndirectory within your game, set WX_BODYSLIDE_DATA_DIR and\nWX_OUTFITSTUDIO_DATA_DIR to the BodySlide directory.  The res directory\nmust still be copied into the BodySlide directory.\n"
  },
  {
    "path": "RefTemplates.xml",
    "content": "<!-- Reference templates are shortcuts to loading a slider set as a reference in Outfit Studio -->\n<RefTemplates>\n</RefTemplates>\n"
  },
  {
    "path": "lang/BodySlide.pot",
    "content": "#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: BodySlide\\n\"\n\"POT-Creation-Date: \\n\"\n\"PO-Revision-Date: \\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: en\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.9\\n\"\n\"X-Poedit-KeywordsList: _\\n\"\n\"X-Poedit-Basepath: ..\\n\"\n\"X-Poedit-SearchPath-0: src\\n\"\n\"X-Poedit-SearchPath-1: lang/xrctext.cpp\\n\"\n\n#: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:510\nmsgid \"About\"\nmsgstr \"\"\n\n#: res/xrc/About.xrc:145 res/xrc/Automation.xrc:2554\n#: res/xrc/GroupManager.xrc:189\nmsgid \"Close\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:6\nmsgid \"Apply a vertex position\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:15\nmsgid \"This permanently moves a single vertex straight to the given location.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499\n#: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:862 res/xrc/Actions.xrc:938\n#: res/xrc/Actions.xrc:1014 res/xrc/Actions.xrc:1062 res/xrc/Actions.xrc:1341\n#: res/xrc/Actions.xrc:1442 res/xrc/BatchBuild.xrc:127 res/xrc/EditUV.xrc:32\n#: res/xrc/EditUV.xrc:258 res/xrc/EditUV.xrc:333 res/xrc/EditUV.xrc:454\n#: res/xrc/EditUV.xrc:588 res/xrc/ImportDialog.xrc:174 res/xrc/Project.xrc:778\n#: res/xrc/Project.xrc:955 res/xrc/Settings.xrc:524\n#: res/xrc/ShapeProperties.xrc:831 res/xrc/Skeleton.xrc:36\n#: res/xrc/Skeleton.xrc:259 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238\n#: res/xrc/SliderDataImport.xrc:90 res/xrc/WeightCopy.xrc:228\nmsgid \"&OK\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506\n#: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:869 res/xrc/Actions.xrc:945\n#: res/xrc/Actions.xrc:1021 res/xrc/Actions.xrc:1069 res/xrc/Actions.xrc:1348\n#: res/xrc/Actions.xrc:1449 res/xrc/Actions.xrc:1780 res/xrc/BatchBuild.xrc:57\n#: res/xrc/BatchBuild.xrc:135 res/xrc/EditUV.xrc:39 res/xrc/EditUV.xrc:265\n#: res/xrc/EditUV.xrc:340 res/xrc/EditUV.xrc:461 res/xrc/EditUV.xrc:595\n#: res/xrc/ImportDialog.xrc:181 res/xrc/Project.xrc:570 res/xrc/Project.xrc:785\n#: res/xrc/Project.xrc:962 res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:531\n#: res/xrc/Setup.xrc:302 res/xrc/ShapeProperties.xrc:838\n#: res/xrc/Skeleton.xrc:43 res/xrc/Skeleton.xrc:266 res/xrc/Slider.xrc:71\n#: res/xrc/Slider.xrc:246 res/xrc/SliderDataImport.xrc:97\n#: res/xrc/WeightCopy.xrc:236\nmsgid \"&Cancel\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:110\nmsgid \"Move Shape\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:254\nmsgid \"Mirror Axis\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:320\nmsgid \"Scale Shape\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:329\nmsgid \"Scaling will adjust the size of a mesh. This permanently affects vertices.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667\n#: res/xrc/ShapeProperties.xrc:711 res/xrc/Skeleton.xrc:133\nmsgid \"Origin\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678\nmsgid \"Zero (0, 0, 0)\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679\nmsgid \"Center of selected shapes(s)\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:484 res/xrc/Actions.xrc:847\nmsgid \"Uniform (XYZ)\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:517\nmsgid \"Rotate Shape\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:712\nmsgid \"Inflate Shape\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:721\nmsgid \"Inflate/deflate a mesh along its normals. This permanently affects vertices.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:880 res/xrc/Automation.xrc:1577\nmsgid \"Mirror Shape\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:924\nmsgid \"Swap bones on X axis (L/R)\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:956\nmsgid \"Smooth Seams\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1032\nmsgid \"Set Shape Textures\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1079\nmsgid \"Conforming...\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1088\nmsgid \"Each vertex of the reference will copy its slider data to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become conformed and work well. Often, the default values are sufficient.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1108 res/xrc/WeightCopy.xrc:35\nmsgid \"Search Radius\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1137 res/xrc/WeightCopy.xrc:64\nmsgid \"Max Vertex Targets\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1166 res/xrc/WeightCopy.xrc:95\nmsgid \"No Target Limit\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1189\nmsgid \"No Squeeze\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1212\nmsgid \"Solid Mode\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1235\nmsgid \"Axis\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1285 res/xrc/BodySlide.xrc:97\n#: res/xrc/NormalsGenDlg.xrc:191 src/ui/PreviewPanel.cpp:41\nmsgid \"Preset\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1301 src/program/OutfitStudio.cpp:8844\nmsgid \"Default\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1310\nmsgid \"Even Movement\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1319\nmsgid \"Solid Object\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1358\nmsgid \"Merge Geometry\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1367\nmsgid \"This function copies vertices and triangles from one shape to another.  Partitions/segments of source and target shapes must match.  It is the user's responsibility to check that all other shape and shader properties are compatible, or merging will likely have side effects.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1382\nmsgid \"Source\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1400 src/program/AutomationDialog.cpp:88\nmsgid \"Target\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1429\nmsgid \"Delete source shape\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1459\nmsgid \"Mask symmetric vertices\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1468\nmsgid \"Masks all vertices that do not have any of the selected asymmetries.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1494\nmsgid \"Vertices currently unmasked:\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1522\nmsgid \"Unmatched Vertices:\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1544\nmsgid \"Vertex Data Asymmetries\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1577 res/xrc/OutfitStudio.xrc:808\n#: res/xrc/OutfitStudio.xrc:1072 res/xrc/ShapeProperties.xrc:84\n#: res/xrc/ShapeProperties.xrc:620 src/program/AutomationDialog.cpp:87\nmsgid \"Type\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1586\nmsgid \"Average\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1595\nmsgid \"Count\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1613\nmsgid \"Position\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1681 res/xrc/Automation.xrc:1501 res/xrc/Project.xrc:746\nmsgid \"Sliders\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1728 res/xrc/OutfitStudio.xrc:393\n#: res/xrc/OutfitStudio.xrc:2539 res/xrc/OutfitStudio.xrc:2583\nmsgid \"Bones\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1747\nmsgid \"Vertices that will still be unmasked:\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1773\nmsgid \"&Mask\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:5\nmsgid \"Automation Script\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:22\nmsgid \"Automation:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:30\nmsgid \"Select an automation to load, or type a name for a new one\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:31\nmsgid \"Automation name...\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:39 res/xrc/BodySlide.xrc:143\n#: res/xrc/GroupManager.xrc:44 res/xrc/OutfitStudio.xrc:1272\n#: res/xrc/OutfitStudio.xrc:1349\nmsgid \"Save\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:40\nmsgid \"Save the automation script\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:48 res/xrc/OutfitStudio.xrc:1281\n#: res/xrc/OutfitStudio.xrc:1367 res/xrc/OutfitStudio.xrc:2563\nmsgid \"Delete\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:49\nmsgid \"Delete the current automation script\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:57\nmsgid \"Open Folder\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:58\nmsgid \"Open the Automations folder in file explorer\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:99\nmsgid \"Step Settings\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:114\nmsgid \"Type:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:121\nmsgid \"Bones: Add Custom Bone\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:122\nmsgid \"Bones: Copy Bone Weights\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:123\nmsgid \"Bones: Delete Bones\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:124\nmsgid \"Bones: Edit Custom Bone\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:125\nmsgid \"Bones: Remove Skinning\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:126\nmsgid \"Export: File\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:127\nmsgid \"Export: Save Project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:128\nmsgid \"Import: File\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:129\nmsgid \"Import: Slider Data\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:130\nmsgid \"Project: Add Project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:131\nmsgid \"Project: Clear Project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:132\nmsgid \"Project: Clear Reference\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:133\nmsgid \"Project: Load Reference\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:134\nmsgid \"Project: Set Base Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:135\nmsgid \"Project: Set Reference Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:136\nmsgid \"Shapes: Apply Pose\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:137\nmsgid \"Shapes: Delete Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:138\nmsgid \"Shapes: Duplicate Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:139\nmsgid \"Shapes: Fix Clipping\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:140\nmsgid \"Shapes: Invert UVs\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:141\nmsgid \"Shapes: Mirror Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:142\nmsgid \"Shapes: Refine Mesh\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:143\nmsgid \"Shapes: Rename Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:144\nmsgid \"Shapes: Reset Transforms\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:145\nmsgid \"Shapes: Transform Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:146\nmsgid \"Sliders: Conform Sliders\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:147\nmsgid \"Sliders: Delete Slider\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:148\nmsgid \"Sliders: Set Slider Values\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:149\nmsgid \"Sliders: Set Slider Properties\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:150\nmsgid \"Masks: Load Mask\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:151\nmsgid \"Nodes: Remove Unused Nodes\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:159\nmsgid \"Active:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:165\nmsgid \"Execute this step\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:173\nmsgid \"Target Shapes:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:185\nmsgid \"Comma-separated list of shape names. Leave empty to target all shapes.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:186 res/xrc/Automation.xrc:934\nmsgid \"Comma-separated shape list\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:192 res/xrc/Automation.xrc:2451\n#: res/xrc/Automation.xrc:2502\nmsgid \"Regex\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:193\nmsgid \"Use regex matching for target shape names\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:202\nmsgid \"Note:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:210\nmsgid \"A note to describe what this step does and how to configure it.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:211\nmsgid \"Description of this step...\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:232 res/xrc/Skeleton.xrc:53\nmsgid \"Add Custom Bone\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:246 res/xrc/Automation.xrc:489\nmsgid \"Bone Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:252 res/xrc/Automation.xrc:496\nmsgid \"Bone name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:259 res/xrc/Automation.xrc:503\nmsgid \"Parent Bone:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:265 res/xrc/Automation.xrc:509\nmsgid \"Name of the parent bone (leave empty for no parent)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:266 res/xrc/Automation.xrc:510\nmsgid \"Parent bone name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:273 res/xrc/Automation.xrc:517\nmsgid \"Translation:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:314 res/xrc/Automation.xrc:558\nmsgid \"Rotation:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:362 res/xrc/ConvertBodyReference.xrc:183\n#: res/xrc/OutfitStudio.xrc:2017 res/xrc/OutfitStudio.xrc:2495\n#: res/xrc/WeightCopy.xrc:6\nmsgid \"Copy Bone Weights\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:376 res/xrc/Automation.xrc:1869\nmsgid \"Proximity Radius:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:390 res/xrc/Automation.xrc:1883\nmsgid \"Max Results:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:404\nmsgid \"Bone List:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:410\nmsgid \"Comma-separated list of bone names. Leave empty to copy all bones.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:411 res/xrc/Automation.xrc:446\nmsgid \"Comma-separated bone list\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:425\nmsgid \"Delete Bones\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:439\nmsgid \"Bone Names:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:445\nmsgid \"Comma-separated list of bone names to delete\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:453 res/xrc/Automation.xrc:962\n#: res/xrc/Automation.xrc:1025 res/xrc/Automation.xrc:1493\nmsgid \"Mode:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:459\nmsgid \"Delete bone entirely from project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:461\nmsgid \"If checked, deletes the bone from all shapes and the NIF. If unchecked, only removes bone weights from target shapes.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:475\nmsgid \"Edit Bone\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:495\nmsgid \"Name of the custom bone to edit\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:606 res/xrc/OutfitStudio.xrc:1902\nmsgid \"Remove Skinning\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:612\nmsgid \"\"\n\"Removes skinning from target shapes (or all shapes if Target Meshes is empty).\\n\"\n\"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tThis deletes all bone weights and skinning data from the shapes.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:626\nmsgid \"Export File\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:640 src/program/AutomationDialog.cpp:3596\nmsgid \"Export File Path:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:650\nmsgid \"Select export file path\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:658\nmsgid \"Select export folder\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:668 res/xrc/Automation.xrc:834\n#: res/xrc/Automation.xrc:1067 res/xrc/Automation.xrc:1143\n#: res/xrc/Automation.xrc:1277 res/xrc/Automation.xrc:1897\n#: res/xrc/Automation.xrc:2419\nmsgid \"Options:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:677\nmsgid \"Use original file path from batch operation\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:682\nmsgid \"Export with reference shape (.nif only)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:692\nmsgid \"Filename Prefix:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:698\n#, c++-format\nmsgid \"Prefix to add before the filename. Supports {{PLACEHOLDER}} variables.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:699\nmsgid \"e.g. prefix_\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:706\nmsgid \"Filename Suffix:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:712\n#, c++-format\nmsgid \"Suffix to add after the filename before the extension. Supports {{PLACEHOLDER}} variables.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:713\nmsgid \"e.g. &suffix\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:727\nmsgid \"Save Project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:733\nmsgid \"Use original project from batch\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:750\nmsgid \"Display Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:756\n#, c++-format\nmsgid \"Name shown in BodySlide (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:757\nmsgid \"Display name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:764\nmsgid \"Output File Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:770\n#, c++-format\nmsgid \"Base filename for the output NIF (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:771\nmsgid \"Output filename\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:778\nmsgid \"Output Data Path:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:784\n#, c++-format\nmsgid \"Game data path for output (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:792\nmsgid \"Slider Set File:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:798\n#, c++-format\nmsgid \"Slider set project file (.osp) (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:806\nmsgid \"Shape Data Folder:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:812\n#, c++-format\nmsgid \"Folder for slider data files (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:820\nmsgid \"Shape Data File:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:826\n#, c++-format\nmsgid \"Base NIF filename (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:843\nmsgid \"Generate low/high weight outputs\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:849\nmsgid \"Copy reference to output\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:873\nmsgid \"Replace (from):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:879\nmsgid \"Text to find and replace in original project fields (batch only)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:880\nmsgid \"Find text\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:887\nmsgid \"Replace (to):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:893\nmsgid \"Replacement text for matching text in original project fields (batch only)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:894\nmsgid \"Replace with\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:901\nmsgid \"Suffix:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:907\nmsgid \"Suffix to append to Display Name, Shape Data Folder, and Shape Data File name (batch only)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:908\nmsgid \"e.g. &modified\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:924\nmsgid \"Copy reference based on loaded project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:925\nmsgid \"If the loaded project had a reference shape, include it in the output. Otherwise, exclude it. Overrides the option above. (batch only)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:933\nmsgid \"Only treat these shape names as the reference (comma-separated). Leave empty to use any reference shape.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:948\nmsgid \"Import File\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:968\nmsgid \"Import all files from folder\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:975\nmsgid \"File:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:981\nmsgid \"Select file to import\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:990 res/xrc/Automation.xrc:1053\n#: res/xrc/Automation.xrc:2390\nmsgid \"Folder:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:996\nmsgid \"Select folder to import from\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1011\nmsgid \"Import Slider Data\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1031\nmsgid \"Import all files from folder (ShapeName#SliderName.ext)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1038\nmsgid \"Slider Data File:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1044\nmsgid \"Select slider data file\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1059\nmsgid \"Select folder with slider data files\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1073\nmsgid \"Merge into existing sliders\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1080 res/xrc/Automation.xrc:1526\n#: res/xrc/Automation.xrc:1955 res/xrc/Automation.xrc:2038\n#: res/xrc/Automation.xrc:2088\nmsgid \"Slider Names:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1086\nmsgid \"Comma-separated list of slider names. Leave empty to import all sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1087 res/xrc/Automation.xrc:1533\n#: res/xrc/Automation.xrc:1962 res/xrc/Automation.xrc:2045\n#: res/xrc/Automation.xrc:2095\nmsgid \"Comma-separated slider list\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1101\nmsgid \"Add Project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1115 res/xrc/Automation.xrc:1236\nmsgid \"Source File:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1121\nmsgid \"Select project file\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1130 res/xrc/Automation.xrc:1251\n#: res/xrc/Project.xrc:106 res/xrc/Project.xrc:672\nmsgid \"Slider Set:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1136\nmsgid \"Name of the slider set to add\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1152 res/xrc/Automation.xrc:1304\n#: res/xrc/Project.xrc:756\nmsgid \"Append new sliders\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1169\nmsgid \"Clear Project\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1175\nmsgid \"\"\n\"Clears the current project (removes all shapes, sliders, and references).\\n\"\n\"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tNo additional parameters needed.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1189 res/xrc/Project.xrc:146 res/xrc/Project.xrc:712\nmsgid \"Clear Reference\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1195\nmsgid \"\"\n\"Removes the current reference/base shape from the project. Slider data for the reference is moved to the morpher.\\n\"\n\"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tNo additional parameters needed.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1209 res/xrc/Project.xrc:579\nmsgid \"Load Reference\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1223\nmsgid \"Template:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1229\nmsgid \"Select a reference template to auto-fill the fields below\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1242\nmsgid \"Select reference file\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1257\nmsgid \"Name of the slider set within the source file\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1264 res/xrc/Project.xrc:124 res/xrc/Project.xrc:690\nmsgid \"Shape:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1270\nmsgid \"Name of the reference shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1286\nmsgid \"Load all shapes\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1292\nmsgid \"Merge sliders\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1298\nmsgid \"Merge zaps\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1321 res/xrc/OutfitStudio.xrc:2079\nmsgid \"Set Base Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1327\nmsgid \"\"\n\"Bakes the current slider values into the base geometry of all shapes and zeros all sliders.\\n\"\n\"\\n\"\n\"Equivalent to \\\"Slider -> Set Base Shape\\\" in the menu.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1342\nmsgid \"Set Reference Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1356\nmsgid \"Shape Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1362\nmsgid \"Name of the shape to set as reference (highlighted green).\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1363\nmsgid \"Shape name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1373\nmsgid \"Unset Reference\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1374\nmsgid \"Unset the reference shape instead of setting one. Morph data will be moved.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1388\nmsgid \"Apply Pose\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1402\nmsgid \"Pose Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1408\nmsgid \"Name of the pose from PoseData to apply to meshes\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1409\nmsgid \"Pose name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1423\nmsgid \"Delete Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1429\nmsgid \"\"\n\"Deletes the shapes specified in the Target Meshes field above.\\n\"\n\"\\n\"\n\"If Target Meshes is empty, all non-reference shapes are deleted. Use Regex mode for pattern matching.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1444 src/program/OutfitStudio.cpp:10348\nmsgid \"Duplicate Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1458 res/xrc/Automation.xrc:1670\nmsgid \"New Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1464\n#, c++-format\nmsgid \"Name for the duplicated shape. Supports {{PLACEHOLDER}} variables.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1465 res/xrc/Automation.xrc:1677\nmsgid \"New shape name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1479 res/xrc/BodySlide.xrc:432\n#: src/program/OutfitStudio.cpp:8938 src/program/OutfitStudio.cpp:8996\n#: src/program/OutfitStudio.cpp:9002 src/program/OutfitStudio.cpp:10067\nmsgid \"Fix Clipping\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1500\nmsgid \"Shapes\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1504\nmsgid \"Shapes: fix base geometry of target shapes. Sliders: fix clipping for each slider individually.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1511\nmsgid \"Strength (0 - 100):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1518\nmsgid \"Clipping fix strength between 0 and 100.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1532\nmsgid \"Comma-separated list of slider names to fix clipping for (Sliders mode only). Leave empty to process all non-zap/non-UV sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1547\nmsgid \"Invert UVs\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1556 res/xrc/ImportDialog.xrc:53\nmsgid \"Invert U\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1563 res/xrc/ImportDialog.xrc:62\nmsgid \"Invert V\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1586\nmsgid \"Mirror X\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1594\nmsgid \"Mirror Y\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1601\nmsgid \"Mirror Z\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1608\nmsgid \"Swap bones left/right (X axis)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1622 res/xrc/OutfitStudio.xrc:1963\n#: res/xrc/OutfitStudio.xrc:2461\nmsgid \"Refine Mesh\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1628\nmsgid \"\"\n\"Subdivides/refines meshes by splitting edges.\\n\"\n\"\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tAll unmasked vertices are refined. Use the Target Meshes field above to select which shapes to refine.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1642 src/program/OutfitStudio.cpp:5150\n#: src/program/OutfitStudio.cpp:9335\nmsgid \"Rename Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1656\nmsgid \"Old Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1662\n#, c++-format\nmsgid \"Current name of the shape (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1663\nmsgid \"Current shape name\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1676\n#, c++-format\nmsgid \"New name for the shape (supports {{PLACEHOLDER}} variables)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1691 res/xrc/OutfitStudio.xrc:1894\nmsgid \"Reset Transforms\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1697\nmsgid \"Resets global-to-skin transforms for all skinned meshes. No additional parameters needed.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1710\nmsgid \"Transform Shape\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1724\nmsgid \"Move:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1731\nmsgid \"Move X\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1739\nmsgid \"Move Y\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1747\nmsgid \"Move Z\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1755\nmsgid \"Rotate (Ã‚Â°):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1762\nmsgid \"Rotate X (degrees)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1770\nmsgid \"Rotate Y (degrees)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1778\nmsgid \"Rotate Z (degrees)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1786\nmsgid \"Scale:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1793\nmsgid \"Scale X\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1801\nmsgid \"Scale Y\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1809\nmsgid \"Scale Z\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1817\nmsgid \"Inflate:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1824\nmsgid \"Inflate X (along normals)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1832\nmsgid \"Inflate Y (along normals)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1840\nmsgid \"Inflate Z (along normals)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1855 res/xrc/ConvertBodyReference.xrc:165\nmsgid \"Conform Sliders\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1906\nmsgid \"No squeeze\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1911\nmsgid \"Solid mode\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1920\nmsgid \"Axes:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1931\nmsgid \"X\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1939\nmsgid \"Y\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1945\nmsgid \"Z\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1961\nmsgid \"Comma-separated list of slider names to conform. Leave empty to conform all visible sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1976\nmsgid \"Delete Slider\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1990\nmsgid \"Slider Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1996\nmsgid \"Name of the slider to delete. If regex is checked, matches slider names by pattern.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:1997\nmsgid \"Slider name or pattern\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2004\nmsgid \"Regex:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2010\nmsgid \"Match slider names by regex pattern\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2024\nmsgid \"Set Slider Values\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2044\nmsgid \"Comma-separated list of slider names. Leave empty to set all visible sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2052\nmsgid \"Value (0 - 100):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2059\nmsgid \"Slider value between 0 and 100 (percentage)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2074\nmsgid \"Set Slider Properties\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2094\nmsgid \"Comma-separated list of slider names. Leave empty to apply to all sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2102\nmsgid \"Zap:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2109 res/xrc/Automation.xrc:2127\n#: res/xrc/Automation.xrc:2145\nmsgid \"No change\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2110 res/xrc/Automation.xrc:2128\n#: src/program/OutfitStudio.cpp:548 src/program/ShapeProperties.cpp:135\nmsgid \"No\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2111 res/xrc/Automation.xrc:2129\n#: src/program/OutfitStudio.cpp:546 src/program/ShapeProperties.cpp:135\nmsgid \"Yes\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2113\nmsgid \"Set the zap flag on matching sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2120\nmsgid \"Hidden:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2131\nmsgid \"Set the hidden flag on matching sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2138\nmsgid \"Default Zapped:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2146\nmsgid \"Not zapped\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2147 res/xrc/Slider.xrc:148\nmsgid \"Zapped\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2149\nmsgid \"Whether matching zap sliders are zapped by default.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2155\nmsgid \"Default (Small):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2161\nmsgid \"Default small value (0-100). Leave empty for no change.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2169\nmsgid \"Default (Big):\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2175\nmsgid \"Default big value (0-100). Leave empty for no change.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2190\nmsgid \"Load Mask\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2204\nmsgid \"Mask File:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2210\nmsgid \"Select a mask XML file\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2219\nmsgid \"Mask Name:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2225\nmsgid \"Select a mask entry from the loaded mask file.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2239\nmsgid \"Remove Unused Nodes\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2245\nmsgid \"Removes all unreferenced nodes from the NIF.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2265\nmsgid \"Placeholder Variables\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2274\n#, c++-format\nmsgid \"Define {{KEY}} = Value pairs. These are substituted in all text fields before execution.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2291\nmsgid \"Key:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2297\nmsgid \"Value:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2304\nmsgid \"KEY\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2310 res/xrc/ShapeProperties.xrc:638\nmsgid \"Value\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2323\nmsgid \"+ Add\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2331\nmsgid \"- Remove\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2348\nmsgid \"Batch Operation\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2358\nmsgid \"Mode\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2361\nmsgid \"None (run on current project)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2362\nmsgid \"Folder scan (repeat on files in folder)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2363\nmsgid \"Slider sets (repeat on installed slider sets)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2377\nmsgid \"Folder Scan Settings\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2396\nmsgid \"Select folder to scan\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2404\nmsgid \"Extension:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2411\nmsgid \"File extension to scan for (e.g. .nif, .obj)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2425\nmsgid \"Include subdirectories\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2432\nmsgid \"File Filter:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2444\nmsgid \"Filter file/folder names (substring or regex)\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2445 res/xrc/Automation.xrc:2496\nmsgid \"Filter pattern...\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2470\nmsgid \"Slider Set Settings\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2483\nmsgid \"Filter:\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2495\nmsgid \"Filter slider set names (substring or regex). Leave empty for all.\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2526\nmsgid \"Output Log\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2543 src/program/AutomationDialog.cpp:1531\nmsgid \"Execute\"\nmsgstr \"\"\n\n#: res/xrc/Automation.xrc:2544\nmsgid \"Execute all active steps in order\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:6\nmsgid \"Batch Build\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:21\nmsgid \"Select the slider sets for the batch build process. Use the group and outfit filters to show the outfits you want!\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:50\nmsgid \"&Build\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:67\nmsgid \"Choose output set\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:78\nmsgid \"\"\n\"The following sets will override the same files.\\n\"\n\"Please decide which one to use and select it in the list below.\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:88\nmsgid \"Type and hit enter to choose output...\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:114 res/xrc/WeightCopy.xrc:204\nmsgid \"&Preview\"\nmsgstr \"\"\n\n#: res/xrc/BatchBuild.xrc:115\nmsgid \"Open a preview window showing the conflicting outfits for the selected group\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:7\nmsgid \"BodySlide\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:28 src/ui/PreviewPanel.cpp:36\nmsgid \"Outfit/Body\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:44\nmsgid \"Select an outfit to modify\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:58\nmsgid \"Deletes a project from its project file\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:74\nmsgid \"Opens the current project in Outfit Studio\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:113\nmsgid \"Choose from a list of slider settings presets\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:127\nmsgid \"Deletes a preset from its preset file\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:142\nmsgid \"Saves the new slider values to the currently selected preset\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:153\nmsgid \"Save the current slider settings as a new preset\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:154 res/xrc/GroupManager.xrc:53\n#: res/xrc/OutfitStudio.xrc:1358\nmsgid \"Save As...\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:165\nmsgid \"Opens the group manager where you can edit existing or create new groups\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:166 res/xrc/GroupManager.xrc:7\n#: res/xrc/Project.xrc:1084\nmsgid \"Group Manager\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:240\nmsgid \"Single Weight\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:267\nmsgid \"Low Weight\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:284\nmsgid \"High Weight\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:325\nmsgid \"Copy the low weight slider values to the high weight section.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:342\nmsgid \"Default outfit choice in Batch Build\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:353\nmsgid \"Output Path (which the game would use for this outfit)\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:365\nmsgid \"(right-click to view alternatives)\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:385\nmsgid \"\"\n\"Build multiple outfits using the currently active slider values.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to custom directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:386\nmsgid \"Batch Build...\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:401\nmsgid \"Build Morphs\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:402\nmsgid \"Builds a morphs (.tri) file alongside the meshes for accessing the sliders in-game. Requires other mods to make use of the morph data.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:412\nmsgid \"Force Body Normals\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:413\nmsgid \"Adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:442\nmsgid \"Controls how far outfit vertices are pushed away from the body surface.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:460\nmsgid \"Show a preview window for this outfit.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:461 res/xrc/NormalsGenDlg.xrc:166\n#: src/program/PreviewWindow.cpp:19 src/program/PreviewWindow.cpp:33\nmsgid \"Preview\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:479\nmsgid \"\"\n\"Creates the currently selected outfit/body.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to working directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:480\nmsgid \"Build\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:492\nmsgid \"Copy the high weight slider values to the low weight section.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:519 res/xrc/OutfitStudio.xrc:1815\nmsgid \"Open settings dialog.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:520 res/xrc/OutfitStudio.xrc:1814\n#: res/xrc/Settings.xrc:5\nmsgid \"Settings\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:529\nmsgid \"Open Outfit Studio, a full-featured tool for creating and converting outfits.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:530 res/xrc/OutfitStudio.xrc:7\nmsgid \"Outfit Studio\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:540 res/xrc/BodySlide.xrc:552\nmsgid \"Filter Options\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:542\nmsgid \"Choose groups...\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:543\nmsgid \"Choose groups to display in the Outfit menu\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:547\nmsgid \"Refresh Groups\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:548\nmsgid \"Refresh group information\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:554\nmsgid \"Refresh Outfits\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:555\nmsgid \"Reloads outfit list\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:559\nmsgid \"Regular Expressions\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:560\nmsgid \"Allow the use of regular expressions (regex) for filtering.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:564\nmsgid \"Has Zap Options\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:565\nmsgid \"Show only outfits that have zap options.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:570\nmsgid \"Browse outfit folder...\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:571\nmsgid \"Browses to the shape data folder of the current outfit in the file explorer.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:574\nmsgid \"Save Outfit list as group...\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:575\nmsgid \"Save the current filtered outfit list as a group\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:580 res/xrc/Project.xrc:1101\n#: res/xrc/SliderDataImport.xrc:106 src/program/AutomationDialog.cpp:1525\nmsgid \"Select None\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:583 res/xrc/EditUV.xrc:118 res/xrc/Project.xrc:1104\n#: res/xrc/SliderDataImport.xrc:109 src/program/AutomationDialog.cpp:1524\nmsgid \"Select All\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:586 res/xrc/EditUV.xrc:122 res/xrc/Project.xrc:1107\n#: res/xrc/SliderDataImport.xrc:112 src/program/AutomationDialog.cpp:1526\nmsgid \"Invert Selection\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:6\nmsgid \"Convert / Replace Body Reference\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:16 res/xrc/ConvertBodyReference.xrc:219\nmsgid \"This wizard aids in the conversion to another body/reference..\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:25\nmsgid \"Reference Bodies\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:36\nmsgid \"Select a conversion reference (or 'None' to skip converting):\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:58\nmsgid \"Conversion Body Reference\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:78\nmsgid \"Select a body reference to convert to:\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:100\nmsgid \"New Body Reference\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:130 res/xrc/NormalsGenDlg.xrc:108\n#: res/xrc/Slider.xrc:161\nmsgid \"Options\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:136 res/xrc/SliderDataImport.xrc:77\nmsgid \"Merge Sliders\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:145\nmsgid \"Merge Zaps\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:174\nmsgid \"Skip conform popup (use default settings)\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:192\nmsgid \"Skip bone weights popup (use default settings)\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:203\nmsgid \"Delete reference after completion\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:228\nmsgid \"Rename Project (optional)\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:239\nmsgid \"Specify text to be removed from the project name (comma-delimited):\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:260\nmsgid \"Remove from project name\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:277\nmsgid \"Specify any text to be prepended to project name:\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:298\nmsgid \"Prepend to project name\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:315\nmsgid \"NOTE: Game file output path is unaffected by this\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:326\nmsgid \"Extras (optional)\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:337\nmsgid \"Remove the following shapes before conversion (comma-delimited):\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:359\nmsgid \"Shapes to delete\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:375\nmsgid \"Add the following bones after conversion (comma-delimited):\"\nmsgstr \"\"\n\n#: res/xrc/ConvertBodyReference.xrc:396\nmsgid \"Bones to add\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:5\nmsgid \"Edit UV\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:52\nmsgid \"Box Selection\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:53\nmsgid \"\"\n\"Box Selection\\n\"\n\"Shortcut: 1\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:60\nmsgid \"Vertex Selection\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:61\nmsgid \"\"\n\"Vertex Selection\\n\"\n\"Shortcut: 2\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:78\n#: res/xrc/OutfitStudio.xrc:2234\nmsgid \"Move\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:68\nmsgid \"\"\n\"Move\\n\"\n\"Shortcut: 3\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:74 res/xrc/EditUV.xrc:350 res/xrc/ImportDialog.xrc:71\n#: res/xrc/OutfitStudio.xrc:1590 res/xrc/ShapeProperties.xrc:672\n#: src/program/NormalsGenDialog.cpp:304\nmsgid \"Scale\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:75\nmsgid \"\"\n\"Scale\\n\"\n\"Shortcut: 4\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:81 res/xrc/EditUV.xrc:275\nmsgid \"Rotate\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:82\nmsgid \"\"\n\"Rotate\\n\"\n\"Shortcut: 5\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89\nmsgid \"Show Seam Edges\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1696\nmsgid \"Menu\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1698 res/xrc/Settings.xrc:457\n#: src/program/NormalsGenDialog.cpp:288\nmsgid \"File\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:101\nmsgid \"Export UV Template...\\tCtrl+E\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:102\nmsgid \"Export the UV layout as an image file.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:1823\nmsgid \"Edit\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:108 res/xrc/OutfitStudio.xrc:1825\nmsgid \"Undo\\tCtrl+Z\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:109 res/xrc/OutfitStudio.xrc:1826\nmsgid \"Undo the previous action.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:112 res/xrc/OutfitStudio.xrc:1829\nmsgid \"Redo\\tCtrl+Y\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:113 res/xrc/OutfitStudio.xrc:42\n#: res/xrc/OutfitStudio.xrc:1830\nmsgid \"Redo the next undone action.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:117\nmsgid \"Select All\\tCtrl+A\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:121\nmsgid \"Invert Selection\\tCtrl+I\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:125\nmsgid \"Select Less\\tA\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:126\nmsgid \"Select less adjacent points in the selected islands.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:129\nmsgid \"Select More\\tD\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:130\nmsgid \"Select more adjacent points in the selected islands.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:134\nmsgid \"Mask Selection\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:135\nmsgid \"Create a mask from the current UV selection for the mesh in the main viewport.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:139\nmsgid \"Translate...\\tT\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:140\nmsgid \"Show a dialog to translate the current selection.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:143\nmsgid \"Rotate...\\tR\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:144\nmsgid \"Show a dialog to rotate the current selection.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:147\nmsgid \"Scale...\\tS\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:148\nmsgid \"Show a dialog to scale the current selection.\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:155\nmsgid \"Translate\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:296\nmsgid \"Angle\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:439\nmsgid \"Uniform (UV)\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:470\nmsgid \"Export UV Template\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:487 src/program/NormalsGenDialog.cpp:271\nmsgid \"Resolution\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:507\nmsgid \"Wire Color\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:520 res/xrc/Settings.xrc:341\nmsgid \"Background Color\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:535\nmsgid \"Transparent Background\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:545\nmsgid \"Include Texture\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:553\nmsgid \"Wrap Mode\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:561\nmsgid \"Wrap\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:562\nmsgid \"Clamp\"\nmsgstr \"\"\n\n#: res/xrc/EditUV.xrc:573\nmsgid \"Anti-Aliasing\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:17\nmsgid \"Choose a group and add or remove members by selecting them in the lists.\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:1016\nmsgid \"Select a group XML file\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:71\nmsgid \"Groups\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:101\nmsgid \"Add Group\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:110\nmsgid \"Remove Group\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:122\nmsgid \"Members\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:137\nmsgid \"Remove >>\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:151\nmsgid \"Outfits\"\nmsgstr \"\"\n\n#: res/xrc/GroupManager.xrc:172\nmsgid \"<< Add\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:5\nmsgid \"Import Options...\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:89\nmsgid \"Rotate (X)\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:98\nmsgid \"Choose X rotation.\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:113\nmsgid \"Rotate (Y)\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:122\nmsgid \"Choose Y rotation.\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:137\nmsgid \"Rotate (Z)\"\nmsgstr \"\"\n\n#: res/xrc/ImportDialog.xrc:146\nmsgid \"Choose Z rotation.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:6\nmsgid \"Normal Map Generator\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:21\nmsgid \"Layers\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:37\nmsgid \"Load or save preset layer settings.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:61\nmsgid \"Add a new layer after the current one in the layer list.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:62\nmsgid \"Add Layer\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:71\nmsgid \"Move selected layer up one position.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:72 src/program/AutomationDialog.cpp:403\nmsgid \"Move Up\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:87\nmsgid \"Delete the selected layer.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:88\nmsgid \"Delete Layer\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:114\nmsgid \"Save a copy of an existing normal map if one already exists. File is saved in the original directory.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:115\nmsgid \"Backup destination file\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:124\nmsgid \"Compress output file using BC7 compression. This can make saving the file take a VERY long time!\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:125\nmsgid \"Compress output \"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:134\nmsgid \"Use the file name specified in the background layer to save the normal map.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:135\nmsgid \"Save to background layer file\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:145\nmsgid \"Choose an output file...\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:149\nmsgid \"Location to save normal map to.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:165\nmsgid \"Display current settings on mesh in preview window.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:181\nmsgid \"Generate and save the normal map file.\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:182\nmsgid \"Generate\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2084\nmsgid \"Load Preset...\"\nmsgstr \"\"\n\n#: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2088\nmsgid \"Save Preset...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5\nmsgid \"New Project\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:23\nmsgid \"Create a new project by selecting a reference body slider set, and outfit model files.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:28\nmsgid \"Load Project\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:29\nmsgid \"Load a previously created slider set for editing.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:34\nmsgid \"Undo\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:35\nmsgid \"Undo a previous action.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:41\nmsgid \"Redo\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2213\nmsgid \"Select\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2214\nmsgid \"Navigate and select meshes (or vertices in vertex mode).\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2218\n#: src/program/NormalsGenDialog.cpp:295\nmsgid \"Mask\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:58 res/xrc/OutfitStudio.xrc:2219\nmsgid \"\"\n\"Mask vertices to prevent them from being transformed.\\n\"\n\"Hold down the ALT key to remove masking.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2223\nmsgid \"Inflate\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:65 res/xrc/OutfitStudio.xrc:2224\nmsgid \"Increase mesh volume in an area.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2229\nmsgid \"Deflate\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:72 res/xrc/OutfitStudio.xrc:2230\nmsgid \"Decrease mesh volume in an area.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:79 res/xrc/OutfitStudio.xrc:2235\nmsgid \"Move vertices over a plane parallel to the view.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:85 res/xrc/OutfitStudio.xrc:2239\nmsgid \"Smooth\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:86 res/xrc/OutfitStudio.xrc:2240\nmsgid \"Smooth an area of a mesh.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2244\nmsgid \"Undiff\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2245\nmsgid \"Undiff an area of a slider.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:99 res/xrc/OutfitStudio.xrc:2249\nmsgid \"Weight Paint\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:100\nmsgid \"\"\n\"Apply animation weight values for currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:107 res/xrc/OutfitStudio.xrc:2255\nmsgid \"Color Paint\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2256\nmsgid \"\"\n\"Apply vertex colors.\\n\"\n\"Hold down the ALT key to remove colors.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2261\nmsgid \"Alpha Paint\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2262\nmsgid \"\"\n\"Apply vertex alpha.\\n\"\n\"Hold down the ALT key to remove alpha.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2267\nmsgid \"Collapse Vertex\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:124 res/xrc/OutfitStudio.xrc:2268\nmsgid \"Deletes vertices with no more than three connections, without creating a hole.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:130 res/xrc/OutfitStudio.xrc:2272\nmsgid \"Flip Edge\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:131 res/xrc/OutfitStudio.xrc:2273\nmsgid \"Flips mesh edges so that the opposite pair of vertices is connected.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:137 res/xrc/OutfitStudio.xrc:2277\nmsgid \"Split Edge\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:138 res/xrc/OutfitStudio.xrc:2278\nmsgid \"Splits a mesh edge in two with a new vertex.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:144 res/xrc/OutfitStudio.xrc:2282\nmsgid \"Move Vertex\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:145 res/xrc/OutfitStudio.xrc:2283\nmsgid \"Moves a vertex.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:152\nmsgid \"Depth Clip\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:154\nmsgid \"Simulates lower depth buffer precision to help with depth-related clipping\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:161\nmsgid \"Field of View\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:165\nmsgid \"Field of View: 65\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:170\nmsgid \"Brush Settings\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:175\nmsgid \"Open Discord invite link.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:180\nmsgid \"Open GitHub link.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:185\nmsgid \"Open PayPal link.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:206\nmsgid \"Transform\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:207 res/xrc/OutfitStudio.xrc:2289\nmsgid \"Shows a transform tool to manipulate shapes and vertices with.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:213\nmsgid \"Pivot\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:214 res/xrc/OutfitStudio.xrc:2294\nmsgid \"Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:220\nmsgid \"Vertex Edit\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:221\nmsgid \"\"\n\"Lets you select vertices to add to or remove from the mask.\\n\"\n\"Click on a vertex to select/unmask it.\\n\"\n\"Hold down CTRL to unselect/mask it.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:228\nmsgid \"View Front\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:229\nmsgid \"Change camera view to the front.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:233\nmsgid \"View Back\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:234\nmsgid \"Change camera view to the back.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:238\nmsgid \"View Left\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:239\nmsgid \"Change camera view to the left.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:243\nmsgid \"View Right\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:244\nmsgid \"Change camera view to the right.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:248 res/xrc/Settings.xrc:326\nmsgid \"Perspective View\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:249\nmsgid \"Toggle perspective view.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:255\nmsgid \"Show Nodes\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:256\nmsgid \"Toggle rendering of nodes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:261\nmsgid \"Show Bones\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:262\nmsgid \"Toggle rendering of bones.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:267\nmsgid \"Show Floor\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:268\nmsgid \"Toggle rendering of the floor grid.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:274\nmsgid \"X Mirror\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:275 res/xrc/OutfitStudio.xrc:1835\nmsgid \"Mirror edits across the X axis.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:282 res/xrc/OutfitStudio.xrc:1841\nmsgid \"Edit Connected Only\\tC\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:283\nmsgid \"Edit only vertices that are connected to the ones under the brush within the brush radius.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:289 res/xrc/OutfitStudio.xrc:1848\nmsgid \"Merge Vertex\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:290 res/xrc/OutfitStudio.xrc:1849\nmsgid \"Merges two vertices and fills any gaps.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:296 res/xrc/OutfitStudio.xrc:1855\nmsgid \"Weld Vertex\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:297 res/xrc/OutfitStudio.xrc:1856\nmsgid \"Welds two vertices while keeping the texture coordinates (UV) distinct.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:303 res/xrc/OutfitStudio.xrc:1862\nmsgid \"Restrict To Surface\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:304 res/xrc/OutfitStudio.xrc:1863\nmsgid \"Restricts motion to a mesh surface.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:310 res/xrc/OutfitStudio.xrc:1869\nmsgid \"Restrict To Plane\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:311 res/xrc/OutfitStudio.xrc:1870\nmsgid \"Restricts motion to parallel to the surface.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:317 res/xrc/OutfitStudio.xrc:1876\nmsgid \"Restrict To Normal\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:318 res/xrc/OutfitStudio.xrc:1877\nmsgid \"Restricts motion to perpendicular to the surface.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:381\nmsgid \"Meshes\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:405 res/xrc/OutfitStudio.xrc:2597\n#: res/xrc/OutfitStudio.xrc:2623\nmsgid \"Segments\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:417 res/xrc/OutfitStudio.xrc:2630\n#: res/xrc/OutfitStudio.xrc:2641\nmsgid \"Partitions\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:429\nmsgid \"Colors\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:441\nmsgid \"Lights\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:481\nmsgid \"Total Bones: 0\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:491\nmsgid \"Shape Selection Bones: 0\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:521\nmsgid \"Brush Color\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:530\nmsgid \"Color of the brush.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:552\nmsgid \"Clamp Max Value\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:595 src/program/OutfitStudio.cpp:3526\n#: src/program/OutfitStudio.cpp:7385\nmsgid \"Edit Alpha\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:604\nmsgid \"Mask matching color\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:650 res/xrc/OutfitStudio.xrc:1054\n#: res/xrc/OutfitStudio.xrc:1155 src/program/OutfitStudio.cpp:7100\n#: src/program/OutfitStudio.cpp:12189 src/ui/wxBrushSettingsPopup.cpp:186\nmsgid \"Reset\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:663\nmsgid \"Ambient\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:688\nmsgid \"Frontal\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:713\nmsgid \"Directional 1\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:738\nmsgid \"Directional 2\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:763\nmsgid \"Directional 3\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:931\nmsgid \"Slot\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1006 src/program/OutfitStudio.cpp:6048\nmsgid \"SSF File\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1026\nmsgid \"Set\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1044 res/xrc/OutfitStudio.xrc:1145\n#: src/program/OutfitStudio.cpp:7100\nmsgid \"Apply\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1173\nmsgid \"De-/Select Sliders\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1192\nmsgid \"Fixed Weight Brush\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1203\nmsgid \"Normalize Weights\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1220\nmsgid \"X-Mirror Bone\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1245\nmsgid \"Masks\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1297\nmsgid \"Export...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1306\nmsgid \"Import...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1322\nmsgid \"Posing\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1383\nmsgid \"Show Pose\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1401\nmsgid \"Reset Bone\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1421\nmsgid \"Rotation X\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1449\nmsgid \"Rotation Y\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1477\nmsgid \"Rotation Z\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1505\nmsgid \"Offset X\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1533\nmsgid \"Offset Y\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1561\nmsgid \"Offset Z\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1623\nmsgid \"Reset All\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1631\nmsgid \"Apply to Mesh\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1659\nmsgid \"Notes\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1700\nmsgid \"New Project...\\tCtrl+N\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1701\nmsgid \"Create a new outfit project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1704\nmsgid \"Load Project..\\tCtrl+O\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1705\nmsgid \"Load a project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1708\nmsgid \"Add Project..\\tCtrl+Shift+O\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1709\nmsgid \"Add a project without replacing the current one.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1712\nmsgid \"Unload Project...\\tCtrl+W\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1713\nmsgid \"Unloads the project and creates an empty new one.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1716\nmsgid \"Recent Projects...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1721\nmsgid \"Load Reference...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1722\nmsgid \"Load a new reference slider set, replacing any current reference objects.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1725\nmsgid \"Load Outfit...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1726\nmsgid \"Load a NIF file as the working outfit, replacing any current outfit objects.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1730\nmsgid \"Convert / Replace Reference...\\tCtrl+Shift+R\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1731\nmsgid \"Convert to or replace an outfit's body/reference\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1734\nmsgid \"Open Automation...\\tCtrl+Shift+A\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1735\nmsgid \"Open the automation dialog to create, load and execute automation scripts.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1739\nmsgid \"Save Project\\tCtrl+S\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1740\nmsgid \"Save the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1744\nmsgid \"Save Project As...\\tCtrl+Shift+S\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1745\nmsgid \"Save the project under a new name.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1749 res/xrc/OutfitStudio.xrc:2106\n#: src/program/OutfitStudio.cpp:8031 src/program/OutfitStudio.cpp:8142\n#: src/program/OutfitStudio.cpp:8274\nmsgid \"Import\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1751\nmsgid \"From NIF...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1752\nmsgid \"Choose a NIF file to import into the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1755\nmsgid \"From OBJ...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1756\nmsgid \"Import an OBJ file as a new shape in the outfit.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1759\nmsgid \"From FBX...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1760\nmsgid \"Import an FBX file as a new shape in the outfit.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1763\nmsgid \"From TRI (Head)...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1764\nmsgid \"Import shape and morphs from a head TRI file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1767\nmsgid \"Import Data\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1769\nmsgid \"Import BSClothExtraData From HKX\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1770\nmsgid \"Choose an HKX file to import as a BSClothExtraData block into the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1775 res/xrc/OutfitStudio.xrc:1909\n#: res/xrc/OutfitStudio.xrc:2142 res/xrc/OutfitStudio.xrc:2407\nmsgid \"Export\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1777\nmsgid \"To NIF...\\tCtrl+E\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1778\nmsgid \"Save the current project as a NIF file (without reference)\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1781\nmsgid \"To NIF With Reference...\\tCtrl+Alt+E\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1782\nmsgid \"Save the current project as a NIF file (including reference)\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1785 res/xrc/OutfitStudio.xrc:1915\n#: res/xrc/OutfitStudio.xrc:2413\nmsgid \"To OBJ...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1786\nmsgid \"Export the current project as an OBJ file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1789 res/xrc/OutfitStudio.xrc:1919\n#: res/xrc/OutfitStudio.xrc:2417\nmsgid \"To FBX...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1790\nmsgid \"Export the current project as an FBX file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1793 res/xrc/OutfitStudio.xrc:1923\n#: res/xrc/OutfitStudio.xrc:2421\nmsgid \"To TRI (Head)...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1794 res/xrc/OutfitStudio.xrc:1924\n#: res/xrc/OutfitStudio.xrc:2422\nmsgid \"Export head morphs to a TRI file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1797\nmsgid \"Export Data\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1799\nmsgid \"Export BSClothExtraData As HKX\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1800\nmsgid \"Save one of the currently loaded BSClothExtraData blocks to an HKX file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1805\nmsgid \"Make Conversion Reference\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1806\nmsgid \"Using the current slider settings for the reference shape, create a new reference that will morph from the current shape back to the base shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1810 res/xrc/Project.xrc:972\nmsgid \"Pack Projects...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1811\nmsgid \"Pack one or more projects into a folder or archive for sharing.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1818\nmsgid \"Exit\\tAlt+F4\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1819\nmsgid \"Exit Outfit Studio.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1834\nmsgid \"X Mirror\\tX\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1842\nmsgid \"Edit only vertices that are connected to the ones under the brush within the brush radius\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1884\nmsgid \"Recalculate Normals\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1885\nmsgid \"Recalculate normals on active mesh\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1888\nmsgid \"Disable Normals Calculation\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1889\nmsgid \"Turn off all automatic recalculation of normals on all meshes. Only applies to Outfit Studio.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1895\nmsgid \"Resets the shape and skin transforms.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1898 src/program/OutfitStudio.cpp:11640\nmsgid \"Delete Unreferenced Nodes\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1899\nmsgid \"Deletes all nodes from the project that aren't used in any other block.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1903\nmsgid \"Removes skinning of all shapes and all unused nodes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1907 res/xrc/OutfitStudio.xrc:2405\nmsgid \"Shape\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1911 res/xrc/OutfitStudio.xrc:2409\nmsgid \"To NIF...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1912 res/xrc/OutfitStudio.xrc:2410\nmsgid \"Export only the selected shapes to a NIF file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1916 res/xrc/OutfitStudio.xrc:2414\nmsgid \"Export only the selected shapes to an OBJ file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1920 res/xrc/OutfitStudio.xrc:2418\nmsgid \"Export only the selected shapes to an FBX file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1928 res/xrc/OutfitStudio.xrc:2426\n#: res/xrc/Slider.xrc:200\nmsgid \"UV\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1930 res/xrc/OutfitStudio.xrc:2428\nmsgid \"Edit...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1931 res/xrc/OutfitStudio.xrc:2429\nmsgid \"Edit the texture coordinates.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1934\nmsgid \"Invert X (Mirror)\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1935\nmsgid \"Inverts the X-axis to mirror the texture coordinates.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1938\nmsgid \"Invert Y (Flip)\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1939\nmsgid \"Inverts the Y-axis to flip the texture coordinates.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1943 res/xrc/OutfitStudio.xrc:2441\nmsgid \"Delete Vertices...\\tShift+Del\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1944 res/xrc/OutfitStudio.xrc:2442\nmsgid \"Deletes all unmasked vertices of the currently selected shapes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1947 res/xrc/OutfitStudio.xrc:2445\nmsgid \"Separate Vertices...\\tShift+S\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1948 res/xrc/OutfitStudio.xrc:2446\nmsgid \"Separate the current shape into two by using the mask.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1951 res/xrc/OutfitStudio.xrc:2449\nmsgid \"Mirror Shape...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1952 res/xrc/OutfitStudio.xrc:2450\nmsgid \"Mirror the selected shapes on any axis.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1955 res/xrc/OutfitStudio.xrc:2453\nmsgid \"Merge Geometry...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1956 res/xrc/OutfitStudio.xrc:2454\nmsgid \"Copies vertices and triangles from one shape to another.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1959 res/xrc/OutfitStudio.xrc:2457\nmsgid \"Duplicate...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1960 res/xrc/OutfitStudio.xrc:2458\nmsgid \"Duplicate the current shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1964 res/xrc/OutfitStudio.xrc:2462\nmsgid \"Splits all edges between unmasked vertices\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1967 res/xrc/OutfitStudio.xrc:2465\nmsgid \"Rename...\\tF2\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1968 res/xrc/OutfitStudio.xrc:2466\nmsgid \"Change the name of the current shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1971 res/xrc/OutfitStudio.xrc:2469\nmsgid \"Set Reference\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1972 res/xrc/OutfitStudio.xrc:2470\nmsgid \"Turn the shape into the reference shape of the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1976 res/xrc/OutfitStudio.xrc:2474\nmsgid \"Move...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1977 res/xrc/OutfitStudio.xrc:2475\nmsgid \"Apply an offset adjustment to the mesh vertices. This permanently moves vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1980 res/xrc/OutfitStudio.xrc:2478\nmsgid \"Scale...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1981 res/xrc/OutfitStudio.xrc:2479\nmsgid \"Apply a scale adjustment to the shape. This permanently moves vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1984 res/xrc/OutfitStudio.xrc:2482\nmsgid \"Rotate...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1985 res/xrc/OutfitStudio.xrc:2483\nmsgid \"Apply a rotation to the mesh vertices. This permanently moves vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1988 res/xrc/OutfitStudio.xrc:2486\nmsgid \"Inflate...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1989 res/xrc/OutfitStudio.xrc:2487\nmsgid \"Inflates/deflates a shape along its normals. This permanently moves vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1992 res/xrc/OutfitStudio.xrc:2074\n#: res/xrc/OutfitStudio.xrc:2490\nmsgid \"Fix Clipping...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1993 res/xrc/OutfitStudio.xrc:2491\nmsgid \"Fixes clipping of outfit vertices that penetrate the reference shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1997\nmsgid \"Normals\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1999\nmsgid \"Smooth Seam Normals\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2000\nmsgid \"Smooths edges of seams (usually found at texture borders), disable if this causes odd normals on the shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2005\nmsgid \"Edit Smoothing Angle...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2006\nmsgid \"Angle, in degrees, that controls the threshold at which normal seams are smoothed.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2009\nmsgid \"Lock Normals\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2010\nmsgid \"Locks the mesh normals. Enable if you want to keep custom normals intact.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2018 res/xrc/OutfitStudio.xrc:2496\nmsgid \"Copies all bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2021 res/xrc/OutfitStudio.xrc:2499\nmsgid \"Transfer Selected Weights\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2022 res/xrc/OutfitStudio.xrc:2500\nmsgid \"Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2025 res/xrc/OutfitStudio.xrc:2503\n#: res/xrc/OutfitStudio.xrc:2578\nmsgid \"Mask Weighted Vertices\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2026 res/xrc/OutfitStudio.xrc:2504\nmsgid \"Masks vertices with bone weights, so you can manually assign weights to unweighted vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2029\nmsgid \"Check For Bad Bones...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2030 res/xrc/OutfitStudio.xrc:2508\nmsgid \"Looks for bones with inconsistencies in their transforms.  If any are found, a dialog is opened to give options for fixing them.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2034 res/xrc/OutfitStudio.xrc:2512\nmsgid \"Copy Partitions/Segments...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2035 res/xrc/OutfitStudio.xrc:2513\nmsgid \"Copies partitions/segments and all triangle assignments from the reference shape to the current shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2039 res/xrc/OutfitStudio.xrc:2517\nmsgid \"Mask Symmetric Vertices...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2040 res/xrc/OutfitStudio.xrc:2518\nmsgid \"Masks unmasked vertices that have a mirrored vertex with identical data.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2043 res/xrc/OutfitStudio.xrc:2521\nmsgid \"Symmetrize Vertices...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2044 res/xrc/OutfitStudio.xrc:2522\nmsgid \"Changes vertex data to be identical to mirrored vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2047 res/xrc/OutfitStudio.xrc:2525\nmsgid \"Mask Symmetric Triangles\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2048 res/xrc/OutfitStudio.xrc:2526\nmsgid \"Masks triangles that can be matched to a mirrored triangle.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2052 res/xrc/OutfitStudio.xrc:2530\nmsgid \"Delete\\tDel\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2053 res/xrc/OutfitStudio.xrc:2531\nmsgid \"Removes the currently selected shape from the outfit.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2059 res/xrc/OutfitStudio.xrc:2534\nmsgid \"Properties...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2060 res/xrc/OutfitStudio.xrc:2535\nmsgid \"Opens the properties dialog for shader, texture and more settings of the selected shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2064\nmsgid \"Slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2066\nmsgid \"Conform Selected\\tCtrl+C\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2067\nmsgid \"Conform selected outfit shape to all checked sliders.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2070\nmsgid \"Conform All\\tCtrl+Shift+C\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2071\nmsgid \"Conform all outfit shapes to all checked sliders.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2075\nmsgid \"Fixes clipping of outfit vertices that penetrate the reference shape for the active slider.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2080\nmsgid \"Set the current outfit shape as the base shape and clear slider data.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2085\nmsgid \"Load and preview a slider preset. Inverted sliders will have inverted values.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2089\nmsgid \"Save a slider preset with the current values. Inverted sliders will have inverted values.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2093\nmsgid \"New Slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2094\nmsgid \"Create a new shape transformation slider.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2097\nmsgid \"Coalesce sliders\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2098\nmsgid \"Create a new shape transformation slider based on the current slider values\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2101\nmsgid \"New Zap Slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2102\nmsgid \"Create a new Zap slider based on unmasked vertices\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2108\nmsgid \"Import OSD...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2109\nmsgid \"Imports OSD file and creates sliders for shapes with a matching name.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2112\nmsgid \"Import TRI Morphs...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2113\nmsgid \"Imports TRI morphs from a TRI file and creates sliders for shapes with a matching name.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2116\nmsgid \"Import Starfield morphs...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2117\nmsgid \"Imports Starfield morph.dat file and creates sliders for shapes with a matching name.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2121\nmsgid \"Import to active slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2123\nmsgid \"Import NIF...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2124\nmsgid \"Import a NIF file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2127\nmsgid \"Import BSD...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2128\nmsgid \"Import a BodySlide BSD file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2131\nmsgid \"Import OBJ...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2132\nmsgid \"Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2135\nmsgid \"Import FBX...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2136\nmsgid \"Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2144\nmsgid \"Export OSD...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2145\nmsgid \"Exports all currently loaded slider data to an OSD file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2148\nmsgid \"Export TRI Morphs...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2149\nmsgid \"Exports TRI morphs to a TRI file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2152\nmsgid \"Export Starfield morphs...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2153\nmsgid \"Exports Starfield morph.dat file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2156\nmsgid \"Export to OBJs...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2157\nmsgid \"Export all sliders to an OBJ file per slider.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2161\nmsgid \"Export active slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2163\nmsgid \"Export NIF...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2164\nmsgid \"Exports the current slider's data as a NIF file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2167\nmsgid \"Export BSD...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2168\nmsgid \"Exports the current slider's data as a BodySlide BSD file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2171\nmsgid \"Export OBJ...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2172\nmsgid \"Exports the current slider's data as an OBJ file.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2179 src/program/OutfitStudio.cpp:8681\nmsgid \"Clone Slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2180\nmsgid \"Clones the current slider.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2184\nmsgid \"Negate Slider\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2185\nmsgid \"Negates the current slider, reversing it's effect\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2189\nmsgid \"Mask Affected Vertices\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2190\nmsgid \"Masks the vertices the slider is affecting for all selected shapes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2194\nmsgid \"Clear Slider Data\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2195\nmsgid \"Erases the slider data without removing the slider itself. (Cannot be undone)\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2198\nmsgid \"Delete Slider\\tCtrl+Del\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2199\nmsgid \"Delete the active slider from the project. (Cannot be undone)\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2203\nmsgid \"Properties...\\tTab\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2204 src/ui/wxSliderPanel.cpp:71\nmsgid \"Display and edit the active slider's properties.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2209\nmsgid \"Tool\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2211\nmsgid \"Current Tool\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2250\nmsgid \"\"\n\"Apply animation weight values for the currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2288\nmsgid \"Transform\\tF\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2293\nmsgid \"Pivot\\tP\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2298\nmsgid \"Vertex Edit\\tQ\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2299\nmsgid \"\"\n\"Shows vertex points and lets you mask/unmask them.\\n\"\n\"Without any brush active, click on a vertex to unmask it.\\n\"\n\"Hold down CTRL to mask it.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2304\nmsgid \"Increase Brush Size\\tShift++\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2305\nmsgid \"Increase brush diameter\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2308\nmsgid \"Decrease Brush Size\\tShift+-\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2309\nmsgid \"Decrease brush diameter\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2312\nmsgid \"Increase Brush Strength\\tCtrl++\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2313\nmsgid \"Increase brush strength\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2316\nmsgid \"Decrease Brush Strength\\tCtrl+-\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2317\nmsgid \"Decrease brush strength\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2321\nmsgid \"Mask Less\\tA\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2322\nmsgid \"Mask Less\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2325\nmsgid \"Mask More\\tD\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2326\nmsgid \"Mask More\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2330\nmsgid \"Invert Mask\\tCtrl+I\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2331\nmsgid \"Invert Mask\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2334\nmsgid \"Clear Mask\\tCtrl+A\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2335\nmsgid \"Clear Mask\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2339\nmsgid \"View\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2341\nmsgid \"Front\\tShift+1\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2344\nmsgid \"Back\\tShift+2\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2347\nmsgid \"Left\\tShift+3\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2350\nmsgid \"Right\\tShift+4\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2353\nmsgid \"Perspective\\tShift+5\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2358\nmsgid \"Toggle Rotation Center\\tShift+R\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2359\nmsgid \"Switch between the different rotation center modes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2362\nmsgid \"Show Nodes\\tShift+N\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2366\nmsgid \"Show Bones\\tShift+B\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2370\nmsgid \"Show Floor\\tG\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2375\nmsgid \"Toggle Visibility\\tE\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2376\nmsgid \"Switch between the different visibility modes for the selected shapes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2379\nmsgid \"Show Wireframe\\tW\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2380\nmsgid \"Show wireframe on all models.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2384\nmsgid \"Enable Lighting\\tL\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2385\nmsgid \"Turn on or off lighting.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2390\nmsgid \"Enable Textures\\tT\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2391\nmsgid \"Display texture maps on models.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2396\nmsgid \"Enable Vertex Colors\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2397\nmsgid \"Display vertex colors on models.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2432\nmsgid \"Invert X\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2433\nmsgid \"Inverts the X-axis of the texture coordinates.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2436\nmsgid \"Invert Y\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2437\nmsgid \"Inverts the Y-axis of the texture coordinates.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2507\nmsgid \"Check For Bad Bones\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2541\nmsgid \"Bad Bone\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2543\nmsgid \"Set Skin Transform From Node\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2544\nmsgid \"Fixes the bad bone by calculating a new skin-to-bone transform.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2547\nmsgid \"Set Node Transform From Skin\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2548\nmsgid \"Fixes the bad custom bone by calculating a new bone-to-global transform.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2552 res/xrc/OutfitStudio.xrc:2585\n#: res/xrc/ShapeProperties.xrc:280 res/xrc/ShapeProperties.xrc:438\n#: res/xrc/ShapeProperties.xrc:611\nmsgid \"Add\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2554 res/xrc/OutfitStudio.xrc:2587\nmsgid \"From Skeleton...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2555 res/xrc/OutfitStudio.xrc:2588\nmsgid \"Choose a bone from the reference skeleton to add to the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2558 res/xrc/OutfitStudio.xrc:2591\nmsgid \"Custom Bone...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2559 res/xrc/OutfitStudio.xrc:2592\nmsgid \"Add a custom bone to the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2565\nmsgid \"From Project\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2566\nmsgid \"Delete bone(s) from all shapes of the project.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2569\nmsgid \"From Selected Shapes\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2570\nmsgid \"Delete bone(s) from only the selected shapes.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2574\nmsgid \"Edit Bone...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2575\nmsgid \"Edit a custom bone or view a standard bone.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2579\nmsgid \"Masks vertices with weights for the selected bones.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2599 res/xrc/OutfitStudio.xrc:2625\nmsgid \"Add Segment...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2600 res/xrc/OutfitStudio.xrc:2626\nmsgid \"Choose a segment to add to the shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2603 res/xrc/OutfitStudio.xrc:2614\nmsgid \"Add Sub Segment...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2604 res/xrc/OutfitStudio.xrc:2615\nmsgid \"Add a new sub segment to the currently selected segment.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2607\nmsgid \"Delete Segment...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2608\nmsgid \"Delete segment and all of its sub segments from the shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2612\nmsgid \"Sub Segments\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2618\nmsgid \"Delete Sub Segment...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2619\nmsgid \"Delete the selected sub segment.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2632 res/xrc/OutfitStudio.xrc:2643\nmsgid \"Add Partition...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2633 res/xrc/OutfitStudio.xrc:2644\nmsgid \"Adds a new partition to the shape.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2636\nmsgid \"Delete Partition...\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2637\nmsgid \"Deletes the partition from the shape.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:16\nmsgid \"\"\n\"Welcome to the New Project wizard!\\n\"\n\"\\n\"\n\"First, please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:32 res/xrc/Project.xrc:598\nmsgid \"Reference\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:50 res/xrc/Project.xrc:616\nmsgid \"From Template\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272\n#: res/xrc/Project.xrc:635 res/xrc/Project.xrc:851 res/xrc/Project.xrc:923\nmsgid \"From File\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:79 res/xrc/Project.xrc:645\nmsgid \"Select a project or NIF file\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:162\nmsgid \"Next, select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:818\nmsgid \"Display Name\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:197 res/xrc/Project.xrc:838\nmsgid \"Outfit/Mesh\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:220 res/xrc/Project.xrc:861\nmsgid \"Select a file to load as an outfit/mesh\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:232 res/xrc/Project.xrc:873\nmsgid \"Clear Outfit\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:250 res/xrc/Project.xrc:901\nmsgid \"Textures\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:257 res/xrc/Project.xrc:908\nmsgid \"Automatically search for textures\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:282 res/xrc/Project.xrc:933\nmsgid \"Select a texture file\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:297\nmsgid \"Save Project As...\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:328\nmsgid \"The name of the outfit and slider set, as it will appear in BodySlide.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:337\nmsgid \"Copies the current display name to the project text fields below.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:338\nmsgid \"To Project\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:354\nmsgid \"Output File Name\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:363\nmsgid \"The name of the outfit file that will end up in the game data path when BodySlide builds it. Should not include _1 or _0 in the name, e.g: lovelydress\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:389\nmsgid \"Output Data Path\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:398\nmsgid \"The location in the game's data path where BodySlide-built outfit files will be placed, e.g: meshes\\\\clothes\\\\lovelydress\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:410\nmsgid \"If this is enabled, BodySlide creates a low and high weight model when it generates the final outfit.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:411\nmsgid \"Low/High Weight Output\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:419\nmsgid \"If this is enabled, only one output file will be created (useful for single-weighted things like hair).\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:420\nmsgid \"Single Weight Output\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:431\nmsgid \"Project\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:443\nmsgid \"Slider Set File\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:453\nmsgid \"The .osp slider set project file\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:454\nmsgid \"Select slider set .osp file name\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:472\nmsgid \"Shape Data Folder\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:482\nmsgid \"The folder where all the slider data will go, as well as the base outfit NIF file.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:483\nmsgid \"Select slider data folder\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:500\nmsgid \"Shape Data File\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:510\nmsgid \"The name of the output's base NIF file.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:511\nmsgid \"Select output NIF file name\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:523\nmsgid \"Outfits require the reference body to be a part of the output file. Disable this if you've already copied the reference over or you don't want it included.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:524\nmsgid \"Copy reference shape into output\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:533\nmsgid \"Prevents the building of morph .tri files in BodySlide for this project.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:534\nmsgid \"Prevent morph file building in BodySlide\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:543\nmsgid \"Prevents the removal of fully zapped shapes when building in BodySlide. Useful when the shape order and count matters, like for retextures using texture sets.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:544\nmsgid \"Prevent removal of fully zapped shapes in BodySlide\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:563 res/xrc/SavePreset.xrc:78\nmsgid \"&Save\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:588\nmsgid \"Please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:724\nmsgid \"Merge\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:736\nmsgid \"Zaps\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:737\nmsgid \"Merge existing zaps with new sliders\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:747\nmsgid \"Merge new sliders with existing sliders\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:757\nmsgid \"Append new sliders that aren't in the project at the end of the list (or don't)\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:794\nmsgid \"Load Outfit\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:803\nmsgid \"Please select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:882\nmsgid \"Keep other shapes\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1006\nmsgid \"Group file (optional):\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1015\nmsgid \"Group file to pack (optional).\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1032\nmsgid \"Merged file name:\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1040\nmsgid \"File name to use for the merged project file.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1066\nmsgid \"Pack Folder...\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1075\nmsgid \"Pack Archive...\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:1092 src/program/AutomationDialog.cpp:1532\n#: src/program/OutfitStudio.cpp:4225 src/program/OutfitStudio.cpp:7100\n#: src/program/OutfitStudio.cpp:8031 src/program/OutfitStudio.cpp:8142\n#: src/program/OutfitStudio.cpp:8274 src/program/OutfitStudio.cpp:12189\n#: src/program/ShapeProperties.cpp:135\nmsgid \"Cancel\"\nmsgstr \"\"\n\n#: res/xrc/SavePreset.xrc:6\nmsgid \"Enter preset name...\"\nmsgstr \"\"\n\n#: res/xrc/SavePreset.xrc:15\nmsgid \"Please enter a name for the new preset:\"\nmsgstr \"\"\n\n#: res/xrc/SavePreset.xrc:38\nmsgid \"Select groups to assign to the new preset:\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:15\nmsgid \"Game\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:5793\nmsgid \"Target Game\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:37\nmsgid \"Choose the target game you want to use the program for here.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:67\nmsgid \"Game Data Path\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:77\nmsgid \"Select the data path of the game...\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:79\nmsgid \"Data path to load textures from.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:91\nmsgid \"Advanced\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:108\nmsgid \"Output Path\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:118\nmsgid \"Select the output path...\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:120\nmsgid \"Data path to build files to. If empty, Game Data Path will be used instead.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:137\nmsgid \"Project Path\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:147\nmsgid \"Select the project path...\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:149\nmsgid \"Project path where files related to BodySlide are loaded from. If empty, executable directory will be used instead.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:165\nmsgid \"With this turned on, BodySlide receives a new checkbox \\\"Force Body Normals\\\". Using it when building adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:166\nmsgid \"Show 'Force Body Normals'\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:184\nmsgid \"General\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:196\nmsgid \"Enables/disables the dialog for choosing which set to build during a batch build if overrides happen.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:197\nmsgid \"Override Warning\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:206\nmsgid \"Enables/disables scanning BSAs in the game data folder for textures to load.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:207\nmsgid \"BSA Textures\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:224\nmsgid \"Enables/disables panning the camera with the left mouse button in Outfit Studio.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:225\nmsgid \"Left Mouse Pan\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:234\nmsgid \"Enables/disables opening the brush settings near the mouse cursor when hitting the 'space' key.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:235\nmsgid \"Brush Settings Near Cursor\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:244\nmsgid \"Enables/disables the undo history for the mask brush and vertex selection.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:245\nmsgid \"Mask History\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:263\nmsgid \"Single Instance\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:272\nmsgid \"Controls behavior when opening files and another instance is already running.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:275\nmsgid \"Ask (Message Box)\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:276\nmsgid \"Open in Existing\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:277\nmsgid \"Open in New\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:295\nmsgid \"Language\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:304\nmsgid \"Use the selected language for the program.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:319\nmsgid \"Rendering\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:325\nmsgid \"Enables/disables the perspective view in the rendering window.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:350\nmsgid \"Background color of the renderer.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:367\nmsgid \"Wireframe Color\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:376\nmsgid \"Wireframe color of the renderer.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:393\nmsgid \"Point Color (normal/masked)\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:402\nmsgid \"Color of points in the renderer.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:411\nmsgid \"Color of masked points in the renderer.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:426\nmsgid \"Data Files\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:444\nmsgid \"Reference Skeleton\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:467\nmsgid \"Select a reference skeleton .nif file...\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:470\nmsgid \"The reference skeleton file for Outfit Studio.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:487\nmsgid \"Root Node\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:496\nmsgid \"The root node name of the reference skeleton. Can differ from game to game.\"\nmsgstr \"\"\n\n#: res/xrc/Setup.xrc:5\nmsgid \"Setup\"\nmsgstr \"\"\n\n#: res/xrc/Setup.xrc:15\nmsgid \"\"\n\"Please select the data folder and your target game.\\n\"\n\"You can only choose one game at a time, but it is possible to change the selection in the settings.\"\nmsgstr \"\"\n\n#: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102\n#: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189\n#: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247 res/xrc/Setup.xrc:276\nmsgid \"Game not found! Select the data folder manually...\"\nmsgstr \"\"\n\n#: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103\n#: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190\n#: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248 res/xrc/Setup.xrc:277\nmsgid \"Select a folder\"\nmsgstr \"\"\n\n#: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113\n#: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200\n#: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258 res/xrc/Setup.xrc:287\nmsgid \"Choose Game\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:5\nmsgid \"Shape Properties\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:16\nmsgid \"Shader\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:629\n#: res/xrc/Skeleton.xrc:94\nmsgid \"Name\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:102\nmsgid \"Specular Color\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:120\nmsgid \"Specular Strength\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:139\nmsgid \"Specular Power\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:179\nmsgid \"Emissive Color\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:197\nmsgid \"Emissive Multiple\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:216\nmsgid \"Alpha\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:235\nmsgid \"Vertex Colors\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:252\nmsgid \"Double Sided\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:289 res/xrc/ShapeProperties.xrc:447\nmsgid \"Remove\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:298\nmsgid \"Textures...\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:310\nmsgid \"Transparency\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:333\nmsgid \"Threshold\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:373\nmsgid \"Vertex Alpha\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:391\nmsgid \"Alpha Test\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:409\nmsgid \"Alpha Blend\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:460\nmsgid \"Copy from shape...\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:468\nmsgid \"Geometry\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:488\nmsgid \"Full Precision\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:507\nmsgid \"Sub Index\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:526\nmsgid \"Skinned\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:544\nmsgid \"Dynamic\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:590\nmsgid \"Extra Data\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:648\nmsgid \"Coordinates\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:657\nmsgid \"Transform from shape to global coordinates:\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:720 res/xrc/Skeleton.xrc:142\nmsgid \"Rotation\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:806 res/xrc/WeightCopy.xrc:187\nmsgid \"Recalculate geometry's coordinates so it doesn't move\"\nmsgstr \"\"\n\n#: res/xrc/ShapeProperties.xrc:807 res/xrc/WeightCopy.xrc:188\nmsgid \"Transform geometry so its position in global coordinates does not change.\"\nmsgstr \"\"\n\n#: res/xrc/Skeleton.xrc:6\nmsgid \"Select a bone to add\"\nmsgstr \"\"\n\n#: res/xrc/Skeleton.xrc:15\nmsgid \"Bones in the current reference skeleton:\"\nmsgstr \"\"\n\n#: res/xrc/Skeleton.xrc:68\nmsgid \"Parent\"\nmsgstr \"\"\n\n#: res/xrc/Skeleton.xrc:234\nmsgid \"Add Count #\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:6\nmsgid \"Select a slider preset\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:15\nmsgid \"Choose a preset:\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:40\nmsgid \"Low weight\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:49\nmsgid \"High weight\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:81\nmsgid \"Slider Properties\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:91\nmsgid \"Slider Name\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:108\nmsgid \"Default Values\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:114\nmsgid \"Low\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:131\nmsgid \"High\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:173\nmsgid \"Invert\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:182\nmsgid \"Hidden\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:191\nmsgid \"Zap\"\nmsgstr \"\"\n\n#: res/xrc/Slider.xrc:211\nmsgid \"Toggle Zaps:\"\nmsgstr \"\"\n\n#: res/xrc/SliderDataImport.xrc:6\nmsgid \"Slider Data Import Options...\"\nmsgstr \"\"\n\n#: res/xrc/SliderDataImport.xrc:21\nmsgid \"Select the shapes that slider data will be imported for:\"\nmsgstr \"\"\n\n#: res/xrc/SliderDataImport.xrc:52\nmsgid \"Select the sliders to be imported\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:15\nmsgid \"Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient.\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:104\nmsgid \"Bones to copy (click to preview weights):\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:127\nmsgid \"Check All\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:135\nmsgid \"Uncheck All\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:151\nmsgid \"Pose:\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:167\nmsgid \"The skin coordinate system doesn't match the reference shape's. Do you want to copy the transforms?\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:177\nmsgid \"Copy skin transform from reference\"\nmsgstr \"\"\n\n#: res/xrc/WeightCopy.xrc:205\nmsgid \"Run the weight copy and preview the results. Click again to update the preview.\"\nmsgstr \"\"\n\n#: src/components/Anim.cpp:570\nmsgid \"Bone information incomplete. Exported data will not contain correct bone entries! Be sure to load a reference NIF prior to export.\"\nmsgstr \"\"\n\n#: src/components/Anim.cpp:571\nmsgid \"Export Warning\"\nmsgstr \"\"\n\n#: src/components/Anim.cpp:794\n#, c-format\nmsgid \"Failed to load skeleton '%s'!\"\nmsgstr \"\"\n\n#: src/components/Anim.cpp:802\n#, c-format\nmsgid \"Root '%s' not found in skeleton '%s'!\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:86\nmsgid \"Active\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:89\nmsgid \"Note\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:95\nmsgid \"Right-click to add steps...\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:150 src/program/AutomationDialog.cpp:321\nmsgid \"Ready.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:291 src/program/BodySlideApp.cpp:3725\n#: src/program/OutfitStudio.h:1105\nmsgid \"Starting...\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:398\nmsgid \"Add Step\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:401\nmsgid \"Remove Step\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:404\nmsgid \"Move Down\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:406\nmsgid \"Execute Selected\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1211 src/program/AutomationDialog.cpp:1286\nmsgid \"<New>\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1254\n#, c-format\nmsgid \"Failed to load automation script (error %d).\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1254 src/program/AutomationDialog.cpp:1333\n#: src/program/BodySlideApp.cpp:1122 src/program/BodySlideApp.cpp:2442\n#: src/program/BodySlideApp.cpp:2755 src/program/BodySlideApp.cpp:4375\n#: src/program/BodySlideApp.cpp:4382 src/program/BodySlideApp.cpp:5280\n#: src/program/EditUV.cpp:276 src/program/OutfitStudio.cpp:1186\n#: src/program/OutfitStudio.cpp:1192 src/program/OutfitStudio.cpp:1769\n#: src/program/OutfitStudio.cpp:1780 src/program/OutfitStudio.cpp:1816\n#: src/program/OutfitStudio.cpp:1827 src/program/OutfitStudio.cpp:1837\n#: src/program/OutfitStudio.cpp:1846 src/program/OutfitStudio.cpp:1857\n#: src/program/OutfitStudio.cpp:1868 src/program/OutfitStudio.cpp:1880\n#: src/program/OutfitStudio.cpp:1919 src/program/OutfitStudio.cpp:1927\n#: src/program/OutfitStudio.cpp:1934 src/program/OutfitStudio.cpp:1970\n#: src/program/OutfitStudio.cpp:1978 src/program/OutfitStudio.cpp:1985\n#: src/program/OutfitStudio.cpp:1995 src/program/OutfitStudio.cpp:2004\n#: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2019\n#: src/program/OutfitStudio.cpp:2030 src/program/OutfitStudio.cpp:2039\n#: src/program/OutfitStudio.cpp:2046 src/program/OutfitStudio.cpp:2361\n#: src/program/OutfitStudio.cpp:2398 src/program/OutfitStudio.cpp:2413\n#: src/program/OutfitStudio.cpp:2499 src/program/OutfitStudio.cpp:2508\n#: src/program/OutfitStudio.cpp:2516 src/program/OutfitStudio.cpp:2530\n#: src/program/OutfitStudio.cpp:2539 src/program/OutfitStudio.cpp:2545\n#: src/program/OutfitStudio.cpp:2582 src/program/OutfitStudio.cpp:4112\n#: src/program/OutfitStudio.cpp:4119 src/program/OutfitStudio.cpp:4670\n#: src/program/OutfitStudio.cpp:4865 src/program/OutfitStudio.cpp:4965\n#: src/program/OutfitStudio.cpp:4984 src/program/OutfitStudio.cpp:5097\n#: src/program/OutfitStudio.cpp:5116 src/program/OutfitStudio.cpp:5144\n#: src/program/OutfitStudio.cpp:5195 src/program/OutfitStudio.cpp:5212\n#: src/program/OutfitStudio.cpp:5219 src/program/OutfitStudio.cpp:5233\n#: src/program/OutfitStudio.cpp:7842 src/program/OutfitStudio.cpp:7900\n#: src/program/OutfitStudio.cpp:7909 src/program/OutfitStudio.cpp:7920\n#: src/program/OutfitStudio.cpp:7934 src/program/OutfitStudio.cpp:7955\n#: src/program/OutfitStudio.cpp:7966 src/program/OutfitStudio.cpp:7977\n#: src/program/OutfitStudio.cpp:7990 src/program/OutfitStudio.cpp:8105\n#: src/program/OutfitStudio.cpp:8118 src/program/OutfitStudio.cpp:8221\n#: src/program/OutfitStudio.cpp:8237 src/program/OutfitStudio.cpp:8243\n#: src/program/OutfitStudio.cpp:8345 src/program/OutfitStudio.cpp:8356\n#: src/program/OutfitStudio.cpp:8373 src/program/OutfitStudio.cpp:8396\n#: src/program/OutfitStudio.cpp:8408 src/program/OutfitStudio.cpp:8440\n#: src/program/OutfitStudio.cpp:8463 src/program/OutfitStudio.cpp:8472\n#: src/program/OutfitStudio.cpp:8483 src/program/OutfitStudio.cpp:8490\n#: src/program/OutfitStudio.cpp:8501 src/program/OutfitStudio.cpp:8508\n#: src/program/OutfitStudio.cpp:8522 src/program/OutfitStudio.cpp:8529\n#: src/program/OutfitStudio.cpp:8665 src/program/OutfitStudio.cpp:8701\n#: src/program/OutfitStudio.cpp:8717 src/program/OutfitStudio.cpp:8928\n#: src/program/OutfitStudio.cpp:10390 src/program/OutfitStudio.cpp:10431\n#: src/program/OutfitStudio.cpp:10436 src/program/OutfitStudio.cpp:10457\n#: src/program/OutfitStudio.cpp:10475 src/program/OutfitStudio.cpp:10684\n#: src/program/OutfitStudio.cpp:10692 src/program/OutfitStudio.cpp:10733\n#: src/program/OutfitStudio.cpp:10992 src/program/OutfitStudio.cpp:11120\n#: src/program/OutfitStudio.cpp:11125 src/program/OutfitStudio.cpp:11132\n#: src/program/OutfitStudio.cpp:11254 src/program/OutfitStudio.cpp:11288\n#: src/program/OutfitStudio.cpp:13434 src/program/OutfitStudio.cpp:13754\n#: src/program/OutfitStudio.cpp:13793 src/program/OutfitStudio.cpp:13798\n#: src/program/OutfitStudio.cpp:13811 src/program/OutfitStudio.cpp:15222\nmsgid \"Error\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1319\nmsgid \"Please enter an automation name.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1319 src/program/AutomationDialog.cpp:1344\n#: src/program/AutomationDialog.cpp:1352 src/program/AutomationDialog.cpp:1578\n#: src/program/AutomationDialog.cpp:1592 src/program/AutomationDialog.cpp:1606\n#: src/program/AutomationDialog.cpp:1630 src/program/AutomationDialog.cpp:1643\n#: src/program/AutomationDialog.cpp:1656 src/program/AutomationDialog.cpp:1679\n#: src/program/AutomationDialog.cpp:1758 src/program/AutomationDialog.cpp:3924\n#: src/program/AutomationDialog.cpp:4033 src/program/AutomationDialog.cpp:4038\n#: src/program/AutomationDialog.cpp:4208\nmsgid \"Automation\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1333\n#, c-format\nmsgid \"Failed to save automation script (error %d).\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1344\nmsgid \"No automation selected to delete.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1352\nmsgid \"Automation file not found.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1357\n#, c-format\nmsgid \"\"\n\"Delete automation '%s'?\\n\"\n\"This cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1358 src/program/OutfitStudio.cpp:10140\n#: src/program/OutfitStudio.cpp:10483 src/program/OutfitStudio.cpp:10514\n#: src/program/OutfitStudio.cpp:10524 src/program/OutfitStudio.cpp:10532\n#: src/program/OutfitStudio.cpp:10539\nmsgid \"Confirm Delete\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1578\nmsgid \"No active steps to execute.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1592 src/program/AutomationDialog.cpp:3924\nmsgid \"No files found matching the batch folder scan criteria.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1602\nmsgid \"Batch Files\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1602\n#, c-format\nmsgid \"Select files to process (%d found):\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1606\nmsgid \"No files selected.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1619\n#, c-format\nmsgid \"\"\n\"Folder: %s\\n\"\n\"Extension: %s\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1623\n#, c-format\nmsgid \"\"\n\"\\n\"\n\"File filter: %s%s\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1630 src/program/AutomationDialog.cpp:4038\nmsgid \"No slider sets found matching the filter criteria.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1639\nmsgid \"Batch Slider Sets\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1639\n#, c-format\nmsgid \"Select slider sets to process (%d found):\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1643\nmsgid \"No slider sets selected.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1656\nmsgid \"No items found matching the batch criteria.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1660\n#, c-format\nmsgid \"\"\n\"Execute %zu active step(s) on %d item(s)?\\n\"\n\"\\n\"\n\"%s\\n\"\n\"\\n\"\n\"This may take a while.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1662\nmsgid \"Batch Confirmation\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1669\n#, c-format\nmsgid \"Execute %zu active step(s) on the current project?\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1669\nmsgid \"Confirm Execution\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1679\nmsgid \"No step selected.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1719\nmsgid \"Running automation script...\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1724\n#, c-format\nmsgid \"Step %d/%d: %s\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1734\n#, c-format\nmsgid \"\"\n\"Step %d (%s) failed with error %d.\\n\"\n\"\\n\"\n\"%s\\n\"\n\"\\n\"\n\"Continue with remaining steps?\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1740\nmsgid \"Automation Error\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1742\nmsgid \"Automation aborted.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1755\nmsgid \"Automation complete.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:1757\n#, c-format\nmsgid \"Automation completed: %d step(s) executed.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:3596\nmsgid \"Export Folder:\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:3919\nmsgid \"Preparing...\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:3938 src/program/AutomationDialog.cpp:4051\n#, c-format\nmsgid \"Processing %d/%d: %s\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:4025 src/program/AutomationDialog.cpp:4200\nmsgid \"Batch complete.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:4031\n#, c-format\nmsgid \"Batch completed: %d/%d items processed successfully.\"\nmsgstr \"\"\n\n#: src/program/AutomationDialog.cpp:4206\n#, c-format\nmsgid \"Batch completed: %d/%d slider sets processed successfully.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:210 src/program/OutfitStudio.cpp:634\nmsgid \"\"\n\"No read/write permission for game data path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the game data path in the settings is correct.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:211 src/program/BodySlideApp.cpp:221\n#: src/program/BodySlideApp.cpp:2421 src/program/BodySlideApp.cpp:5498\n#: src/program/OutfitStudio.cpp:635 src/program/OutfitStudio.cpp:645\n#: src/program/OutfitStudio.cpp:845 src/program/OutfitStudio.cpp:852\nmsgid \"Warning\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:220 src/program/OutfitStudio.cpp:644\nmsgid \"\"\n\"No read/write permission for project path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the project path in the settings is correct.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:307 src/program/OutfitStudio.cpp:702\n#, c-format\nmsgid \"Unexpected exception has occurred: %s, the program will terminate.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:307 src/program/OutfitStudio.cpp:702\nmsgid \"Unexpected exception\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:330 src/program/OutfitStudio.cpp:722\n#, c-format\nmsgid \"Unhandled exception has occurred: %s, the program will terminate.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:330 src/program/OutfitStudio.cpp:722\nmsgid \"Unhandled exception\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:341 src/program/OutfitStudio.cpp:730\nmsgid \"Fatal exception has occurred, the program will terminate.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:341 src/program/OutfitStudio.cpp:730\nmsgid \"Fatal exception\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:1122\nmsgid \"Failed to launch Outfit Studio executable!\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2421 src/program/OutfitStudio.cpp:852\nmsgid \"Failed to find game install path registry key or GameDataPath in the config.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2667 src/program/OutfitStudio.cpp:1098\n#, c-format\nmsgid \"System language '%d' is wrong.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2676 src/program/OutfitStudio.cpp:1107\n#, c-format\nmsgid \"The system language '%d' is not supported by your system. Try installing support for this language.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2755\nmsgid \"Failed to create group file.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2769\nmsgid \"That group already exists in the specified file, do you wish to overwrite the group?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2769\nmsgid \"Group already exists\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2984\nmsgid \"WARNING: Game data path not configured. Would you like to show BodySlide where it is?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2985 src/program/BodySlideApp.cpp:3485\n#: src/program/BodySlideApp.cpp:3490\nmsgid \"Game not found\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:2993\nmsgid \"Please choose a directory to set as your Data path\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3011\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folder, potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3012\nmsgid \"Clean Build\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3020\nmsgid \"Removed the following files:\\n\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3032 src/program/BodySlideApp.cpp:3045\nmsgid \" (no action)\\n\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3036 src/program/BodySlideApp.cpp:3048\n#: src/program/BodySlideApp.cpp:3364\nmsgid \"Process Successful\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3251\n#, c-format\nmsgid \"\"\n\"Failed to write TRI file to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3251 src/program/BodySlideApp.cpp:3307\n#: src/program/BodySlideApp.cpp:3342\nmsgid \"Unable to process\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3307 src/program/BodySlideApp.cpp:3342\n#, c-format\nmsgid \"\"\n\"Failed to build set to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3309 src/program/BodySlideApp.cpp:3344\nmsgid \"Choose alternate file name\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3356\nmsgid \"Successfully processed the following files:\\n\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3436\n#, c-format\nmsgid \"Preview - %s\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3470\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folders, potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3471\nmsgid \"Clean Batch Build\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3485\nmsgid \"WARNING: Game data path not configured. Files can't be removed that way.\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3489\nmsgid \"WARNING: Game data path not configured. Continue saving files to the working directory?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3542\nmsgid \"Choice\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3543\nmsgid \"Source File\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3574\nmsgid \"<no source>\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3725\nmsgid \"Processing Outfits\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3737\n#, c-format\nmsgid \"Processing '%s' (%d of %d)...\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3745\nmsgid \"No recorded outfit name source\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3756\nmsgid \"Unable to get slider set from file: \"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3761\nmsgid \"Unable to open slider set file: \"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:3796\nmsgid \"Unable to load input nif: \"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4084\nmsgid \"Unable to create destination directory: \"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4161 src/program/BodySlideApp.cpp:4169\n#: src/program/BodySlideApp.cpp:4180\nmsgid \"Unable to save nif file: \"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4300 src/program/BodySlideApp.cpp:5628\nmsgid \"The following sets failed\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4300 src/program/BodySlideApp.cpp:5628\nmsgid \"Failed\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4375\nmsgid \"Failed to load BodySlide.xrc file!\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4382\nmsgid \"Failed to load BodySlide frame!\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4463\nmsgid \"Filter groups...\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4469\nmsgid \"Filter outfits...\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4475\nmsgid \"Filter sliders...\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4480\nmsgid \"Filter presets...\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4539 src/program/BodySlideApp.cpp:5462\nmsgid \"Hide Preview\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:4541 src/program/BodySlideApp.cpp:5462\nmsgid \"Show Preview\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5154\nmsgid \"Choose groups to filter outfit list\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5154\nmsgid \"Choose Groups\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5190\nmsgid \"Choose or create group file\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5203\nmsgid \"What would you like the new group to be called?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5203\nmsgid \"New Group Name\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5249\nmsgid \"Do you really wish to delete the selected project?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5249\nmsgid \"Delete Project\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5258\nmsgid \"Do you really wish to delete the selected preset?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5258\nmsgid \"Delete Preset\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5280 src/program/OutfitStudio.cpp:7900\n#, c-format\nmsgid \"Failed to save preset (%d)!\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5308\n#, c-format\nmsgid \"Failed to save preset as '%s' (%d)!\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5494\nmsgid \"\"\n\"Fix Clipping is enabled for this batch build.\\n\"\n\"\\n\"\n\"Use this carefully: applying clipping fixes to many outfits at once can create unwelcome side effects on some meshes.\\n\"\n\"\\n\"\n\"Consider building outfits one-by-one and checking each result in Preview.\\n\"\n\"\\n\"\n\"Do you want to continue with batch build?\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5603\nmsgid \"Choose a folder to contain the saved files\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5618\nmsgid \"All sets processed successfully!\"\nmsgstr \"\"\n\n#: src/program/BodySlideApp.cpp:5618\nmsgid \"Complete\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:121\nmsgid \"Starting conversion...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:139\nmsgid \"Updating Project Output Settings\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:178\nmsgid \"Deleting Shapes...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:199\nmsgid \"Loading conversion reference...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:201\n#: src/program/ConvertBodyReferenceDialog.cpp:234\nmsgid \"Load Error\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:209\n#: src/program/ConvertBodyReferenceDialog.cpp:253\nmsgid \"Conforming outfit parts...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:213\n#: src/program/ConvertBodyReferenceDialog.cpp:255\nmsgid \"Conform Error\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:216\nmsgid \"Updating conversion Slider...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:220\nmsgid \"Setting the base shape and removing the conversion reference\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:227\nmsgid \"Skipping conversion reference...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:232\nmsgid \"Loading new reference...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:242\nmsgid \"Missing Base Shape\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:246\nmsgid \"Copying bones...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:248\nmsgid \"Copy Bone Weights Error\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:260\nmsgid \"Adding Bones...\"\nmsgstr \"\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:289\nmsgid \"Conversion finished.\"\nmsgstr \"\"\n\n#: src/program/EditUV.cpp:264\nmsgid \"Save UV template image\"\nmsgstr \"\"\n\n#: src/program/EditUV.cpp:276\nmsgid \"Failed to export UV template.\"\nmsgstr \"\"\n\n#: src/program/EditUV.cpp:575 src/program/OutfitStudio.cpp:12438\nmsgid \"Outfit Studio: OpenGL context is not OK.\"\nmsgstr \"\"\n\n#: src/program/EditUV.cpp:575 src/program/OutfitStudio.cpp:12438\n#: src/render/GLDialog.cpp:33 src/render/GLSurface.cpp:2266\n#: src/render/GLSurface.cpp:2283 src/render/GLSurface.cpp:2300\n#: src/ui/PreviewPanel.cpp:151\nmsgid \"OpenGL Error\"\nmsgstr \"\"\n\n#: src/program/FBXImportDialog.cpp:163 src/program/ObjImportDialog.cpp:168\n#: src/program/OutfitStudio.cpp:10431 src/program/OutfitStudio.cpp:13793\nmsgid \"The shape has reached the vertex count limit.\"\nmsgstr \"\"\n\n#: src/program/FBXImportDialog.cpp:167 src/program/ObjImportDialog.cpp:172\n#: src/program/OutfitStudio.cpp:10436 src/program/OutfitStudio.cpp:13798\nmsgid \"The shape has reached the triangle count limit.\"\nmsgstr \"\"\n\n#: src/program/GroupManager.cpp:143\nmsgid \"Please enter a new unique name for the group.\"\nmsgstr \"\"\n\n#: src/program/GroupManager.cpp:143\nmsgid \"Rename Group\"\nmsgstr \"\"\n\n#: src/program/GroupManager.cpp:323\nmsgid \"Save changes to group file?\"\nmsgstr \"\"\n\n#: src/program/GroupManager.cpp:323\nmsgid \"Save Changes\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:90\nmsgid \"Enter a name for the new layer.\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:90\nmsgid \"Name new layer\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:209\nmsgid \"Choose a normals generator preset file...\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:226\nmsgid \"Save normals generator preset to...\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:244\nmsgid \"Layer\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:267\nmsgid \"Background File\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:268\nmsgid \"File source for this layer.\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:269\nmsgid \"Color\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:270\nmsgid \"Solid background color (if file is not set).\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:273\nmsgid \"Output texture dimensions. By default all images will be scaled to fit this size.\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:290\nmsgid \"File containing normals data to combine. Note this file should fit the mesh UVs.\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:292\nmsgid \"Is Tangent Space?\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:293\nmsgid \"True if the normals data in the layer file is in tangent space, false if they are in model space (msn).\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:296\nmsgid \"A greyscale image used to mask updates to destination image.\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:298\nmsgid \"X Offset\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:299 src/program/NormalsGenDialog.cpp:302\nmsgid \"Offset to apply to image position.\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:301\nmsgid \"Y Offset\"\nmsgstr \"\"\n\n#: src/program/NormalsGenDialog.cpp:305\nmsgid \"If true, scale image to match background resolution.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:60\nmsgid \"Checking destination...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:121\nmsgid \"Adding reference shapes...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:146 src/program/OutfitProject.cpp:2513\nmsgid \"Adding outfit shapes...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:205\nmsgid \"Calculating slider data...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:213\nmsgid \"Creating slider set file...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:220\nmsgid \"Failed to open or create slider set file: \"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:227\nmsgid \"Saving slider set file...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:230\nmsgid \"Failed to write to slider set file: \"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:234\nmsgid \"Saving NIF file...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:267\nmsgid \"Failed to write base .nif file: \"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:273 src/program/OutfitProject.cpp:1915\n#: src/program/OutfitProject.cpp:1945 src/program/OutfitStudio.cpp:3972\nmsgid \"Finished\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:1809 src/program/OutfitProject.cpp:1901\nmsgid \"Gathering bones...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:1837\nmsgid \"Initializing proximity data...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:1883 src/program/OutfitStudio.cpp:11015\nmsgid \"Copying bone weights...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:1921 src/program/OutfitStudio.cpp:11145\nmsgid \"Transferring bone weights...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2167\nmsgid \"Template source entries are invalid.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2167 src/program/OutfitProject.cpp:2197\n#: src/program/OutfitProject.cpp:2202 src/program/OutfitProject.cpp:2264\n#: src/program/OutfitProject.cpp:2286 src/program/OutfitProject.cpp:2293\n#: src/program/OutfitProject.cpp:2303 src/program/OutfitProject.cpp:2315\nmsgid \"Reference Error\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2194 src/program/OutfitProject.cpp:2283\n#: src/program/OutfitProject.cpp:5057\n#, c-format\nmsgid \"\"\n\"NIF version not supported!\\n\"\n\"\\n\"\n\"File: %s\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2202 src/program/OutfitProject.cpp:2293\n#, c-format\nmsgid \"Could not load reference NIF file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2244 src/program/OutfitProject.cpp:2392\nmsgid \"The following shapes were deleted. Rename the duplicates yourself beforehand if you wish to keep them.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2245 src/program/OutfitProject.cpp:2394\nmsgid \"Deleted Shapes\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2264\n#, c-format\nmsgid \"Could not load slider set file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2303\n#, c-format\nmsgid \"Reference NIF file '%s' does not contain any shapes.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2315\n#, c-format\nmsgid \"Shape '%s' not found in reference NIF file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2403\nmsgid \"Loading slider set...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2410 src/program/OutfitProject.cpp:2503\nmsgid \"Retrieving sliders...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2420\nmsgid \"Loading outfit shapes...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2463 src/program/OutfitProject.cpp:2569\nmsgid \"Updating slider data...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2495\nmsgid \"Adding slider set...\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2562\nmsgid \"The following shapes were renamed and won't have slider data attached. Rename the duplicates yourself beforehand.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:2564\nmsgid \"Renamed Shapes\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5060 src/program/OutfitProject.cpp:5065\nmsgid \"NIF Error\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5065\n#, c-format\nmsgid \"Could not load NIF file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5203\nmsgid \"There was cloth physics data loaded at some point (BSClothExtraData). Please choose all the origins to use in the output.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5204\nmsgid \"Choose cloth data\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5405\nmsgid \"No reference has been loaded.  For correct bone transforms, you might need to load a reference before importing OBJ files.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5413\n#, c-format\nmsgid \"Could not load OBJ file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5413 src/program/OutfitProject.cpp:5437\n#: src/program/OutfitProject.cpp:5499 src/program/OutfitProject.cpp:5666\nmsgid \"OBJ Error\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5419 src/program/OutfitProject.cpp:5585\nmsgid \"The reference shape has a skin coordinate system that is different from the global coordinate system.  Would you like to copy the reference's global-to-skin transform to the imported shapes?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5421 src/program/OutfitProject.cpp:5587\nmsgid \"Copy skin coordinates\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5437\n#, c-format\nmsgid \"Could not copy data from OBJ file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5454\nmsgid \"The vertex count of the selected .obj file matches the currently selected outfit shape.  Do you wish to update the current shape?  (click No to create a new shape)\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5456 src/program/OutfitProject.cpp:5613\nmsgid \"Merge or New\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5460 src/program/OutfitProject.cpp:5617\nmsgid \"Update Vertex Positions?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5460 src/program/OutfitProject.cpp:5617\nmsgid \"Vertex Position Update\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5465 src/program/OutfitProject.cpp:5622\nmsgid \"Update Texture Coordinates?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5465 src/program/OutfitProject.cpp:5622\nmsgid \"UV Update\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5471 src/program/OutfitProject.cpp:5628\nmsgid \"Update Normals?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5471 src/program/OutfitProject.cpp:5628\nmsgid \"Normals Update\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5481 src/program/OutfitProject.cpp:5644\nmsgid \"Please specify a name for the new shape\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5481 src/program/OutfitProject.cpp:5644\nmsgid \"New Shape Name\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5492 src/program/OutfitProject.cpp:5659\n#, c-format\nmsgid \"\"\n\"The vertex or triangle limit for '%s' was exceeded.\\n\"\n\"Remaining data was dropped.\\n\"\n\"\\n\"\n\"Vertices (current/max): %zu/%zu\\n\"\n\"Triangles (current/max): %zu/%zu\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5573\nmsgid \"No reference has been loaded.  For correct bone transforms, you might need to load a reference before importing FBX files.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5611\nmsgid \"The vertex count of the selected .fbx file matches the currently selected outfit shape.  Do you wish to update the current shape?  (click No to create a new shape)\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5635\nmsgid \"Update Animation Weighting?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5635\nmsgid \"Animation Weight Update\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5793\nmsgid \"Would you like Skyrim NIFs to be optimized for SSE during this session?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5810\nmsgid \"File format doesn't match the current game. Use FBX export, then start a new project and import the FBX file there.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5811\nmsgid \"Version\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5824\n#, c-format\nmsgid \"Unable to locate external mesh data for shape. Expected path: %s\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5825\nmsgid \"External Mesh Data Load Failure\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5935\nmsgid \"No Bad Bones Found.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5935\nmsgid \"No Bad Bones\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6050\nmsgid \"Bad Bones\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6071\nmsgid \"Error in rotation\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6072\nmsgid \"Error in translation\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6073\nmsgid \"Error in scale\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6100\n#, c-format\nmsgid \"Bad standard bones for shape \\\"%s\\\"\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6103\n#, c-format\nmsgid \"%zu bones in shape \\\"%s\\\" had inconsistencies between their NIF skin transforms and the standard skeleton:\\n\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6118\nmsgid \"Update skin (recommended)\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6126 src/program/OutfitProject.cpp:6190\n#: src/program/OutfitProject.cpp:6213\nmsgid \"Details\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6126\nmsgid \"Bone\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6131 src/program/OutfitProject.cpp:6227\nmsgid \"Do nothing\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6143\n#, c-format\nmsgid \"Bad Custom Bone \\\"%s\\\"\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6146\n#, c-format\nmsgid \"\"\n\"Custom bone \\\"%s\\\" had inconsistent NIF node and skin transforms for the following shapes:\\n\"\n\"\\\"\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6166\nmsgid \"Trust node and skins \\\"\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6168\nmsgid \"Trust node and skin \\\"\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6176\nmsgid \"\\\", and update other skins (recommended)\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6179\nmsgid \"Trust node, and update skins\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6181\nmsgid \"Trust node, and update skin\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6190\nmsgid \"Skin\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6199\nmsgid \"Trust skin \\\"\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6201\nmsgid \"\\\", and update node\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6203\nmsgid \"\\\", and update node and other skins\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6213\nmsgid \"With\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6214\nmsgid \"Node\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:6240\nmsgid \"Fix nothing\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:403 src/program/OutfitStudio.cpp:404\n#: src/program/OutfitStudio.cpp:15159 src/program/OutfitStudio.cpp:15160\nmsgid \"Adding NIF file...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:408 src/program/OutfitStudio.cpp:419\n#: src/program/OutfitStudio.cpp:431 src/program/OutfitStudio.cpp:4749\n#: src/program/OutfitStudio.cpp:15164 src/program/OutfitStudio.cpp:15175\n#: src/program/OutfitStudio.cpp:15187\nmsgid \"Refreshing GUI...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:415 src/program/OutfitStudio.cpp:15171\nmsgid \"Adding OBJ file...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:426 src/program/OutfitStudio.cpp:427\n#: src/program/OutfitStudio.cpp:15182 src/program/OutfitStudio.cpp:15183\nmsgid \"Adding FBX file...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:537\nmsgid \"Open in existing instance?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:542\nmsgid \"An instance of Outfit Studio is already running. Open file(s) in the existing instance?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:547\nmsgid \"Yes (always)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:549\nmsgid \"No (never)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:845\nmsgid \"Failed to find game install path registry value or GameDataPath in the config.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1186\nmsgid \"Failed to load OutfitStudio.xrc file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1192\nmsgid \"Failed to load Outfit Studio frame!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1211 src/program/OutfitStudio.cpp:4241\n#: src/program/OutfitStudio.h:1135\nmsgid \"Ready!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1743 src/program/OutfitStudio.cpp:1748\nmsgid \"Packing projects to folder...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1769 src/program/OutfitStudio.cpp:1816\n#: src/program/OutfitStudio.cpp:1919\n#, c-format\nmsgid \"Failed to open input file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1780\n#, c-format\nmsgid \"Failed to copy input file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1827\n#, c-format\nmsgid \"Failed to copy data file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1837 src/program/OutfitStudio.cpp:1995\n#, c-format\nmsgid \"Failed to save merged project file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1846 src/program/OutfitStudio.cpp:2004\n#, c-format\nmsgid \"Failed to open project file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1857\n#, c-format\nmsgid \"Failed to copy merged project file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1868 src/program/OutfitStudio.cpp:2030\n#, c-format\nmsgid \"Failed to open group file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1880\n#, c-format\nmsgid \"Failed to copy group file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1886 src/program/OutfitStudio.cpp:2052\nmsgid \"Packing finished.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1890 src/program/OutfitStudio.cpp:1895\nmsgid \"Packing projects to archive...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1927 src/program/OutfitStudio.cpp:1978\n#: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2039\nmsgid \"Failed to put new entry into archive!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1934 src/program/OutfitStudio.cpp:1985\n#: src/program/OutfitStudio.cpp:2019 src/program/OutfitStudio.cpp:2046\nmsgid \"Failed to copy file contents to archive!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:1970\n#, c-format\nmsgid \"Failed to open data file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2361 src/program/OutfitStudio.cpp:2413\n#: src/program/OutfitStudio.cpp:4112 src/program/OutfitStudio.cpp:4119\n#: src/program/OutfitStudio.cpp:5195 src/program/OutfitStudio.cpp:5219\n#: src/program/OutfitStudio.cpp:7977 src/program/OutfitStudio.cpp:8105\n#: src/program/OutfitStudio.cpp:8221 src/program/OutfitStudio.cpp:8472\n#: src/program/OutfitStudio.cpp:8490 src/program/OutfitStudio.cpp:8508\n#: src/program/OutfitStudio.cpp:8529\nmsgid \"There are no valid shapes loaded!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2369 src/program/OutfitStudio.cpp:2555\n#, c-format\nmsgid \"Saving project '%s'...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2399 src/program/OutfitStudio.cpp:2583\nmsgid \"Saving failed.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2404 src/program/OutfitStudio.cpp:2578\nmsgid \"Saved.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2499\nmsgid \"Invalid or no slider set file specified! Please try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2508\nmsgid \"No outfit name specified! Please try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2516\nmsgid \"No data folder specified! Please try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2530\nmsgid \"An invalid or no base outfit .nif file name specified! Please try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2539\nmsgid \"No game file path specified! Please try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2545\nmsgid \"No game file name specified! Please try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2595\n#, c-format\nmsgid \"Failed to open '%s' as a slider set file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2595 src/program/OutfitStudio.cpp:2659\nmsgid \"Slider Set Error\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2614\nmsgid \"Please choose an outfit to load\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2614\nmsgid \"Load a slider set\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2625\nmsgid \"Loading project...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2645\nmsgid \"Loading outfit data...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2659\n#, c-format\nmsgid \"Failed to create project '%s' from file '%s' (%d)!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2673\n#, c-format\nmsgid \"Loading reference shape '%s'...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2687\nmsgid \"Loading textures...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2692 src/program/OutfitStudio.cpp:3954\n#: src/program/OutfitStudio.cpp:4214\nmsgid \"Creating outfit...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2696 src/program/OutfitStudio.cpp:3964\n#: src/program/OutfitStudio.cpp:4102\n#, c-format\nmsgid \"Creating %zu slider(s)...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2725\nmsgid \"Creating sliders...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2728\nmsgid \"Clearing old sliders...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2739\nmsgid \"Loading slider: \"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2817 src/program/OutfitStudio.cpp:8649\nmsgid \"Enter a name for the new slider:\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2817 src/program/OutfitStudio.cpp:8649\nmsgid \"Create New Slider\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2958\n#, c-format\nmsgid \"Total Bones: %zu\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:2973\n#, c-format\nmsgid \"Shape Selection Bones: %zu\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3537\nmsgid \"Edit Color\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3703\nmsgid \"You are trying to edit a slider's morph with that slider set to zero.  Do you wish to set the slider to one now?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3720\nmsgid \"You can only use the undiff brush while editing a slider. Note, use the pencil button next to a slider to enable editing of that slider's morph.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3731\nmsgid \"You can only edit the base shape when all sliders are zero. Do you wish to set all sliders to zero now?  Note, use the pencil button next to a slider to enable editing of that slider's morph.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3818\n#, c-format\nmsgid \"You have unsaved changes to '%s'. Would you like to save them now?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3819\nmsgid \"Unsaved Changes\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3874\n#, c-format\nmsgid \"Creating project '%s'...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3891 src/program/OutfitStudio.cpp:4038\nmsgid \"Loading reference...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3931 src/program/OutfitStudio.cpp:4170\n#: src/program/OutfitStudio.cpp:4179\nmsgid \"Loading outfit...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3979\nmsgid \"Select a slider set to load\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:3996\nmsgid \"Select a slider set to add\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4013 src/program/OutfitStudio.cpp:4124\n#: src/program/OutfitStudio.cpp:4139 src/program/OutfitStudio.cpp:10116\n#: src/program/OutfitStudio.cpp:10169 src/program/OutfitStudio.cpp:10261\n#: src/program/OutfitStudio.cpp:10385\nmsgid \"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4044\nmsgid \"Loading reference set...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4098\nmsgid \"Creating reference...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4224\nmsgid \"Unload the project? All unsaved changes will be lost\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4224\nmsgid \"Unload Project\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4225\nmsgid \"Unload\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4670 src/program/OutfitStudio.cpp:15222\nmsgid \"There is no shape selected!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4736\nmsgid \"Import NIF file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4743 src/program/OutfitStudio.cpp:4744\nmsgid \"Importing NIF file...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4765\nmsgid \"\"\n\"Starfield supports two modes for mesh geometry data:\\n\"\n\"\\n\"\n\"Internal: Mesh data is embedded directly in the NIF file.\\n\"\n\"Simpler for modding - single file, no external dependencies.\\n\"\n\"\\n\"\n\"External: Mesh data is stored in separate .mesh files under geometries/.\\n\"\n\"Can be streamed from BA2 archives for better game performance.\\n\"\n\"\\n\"\n\"Would you like to embed the geometry data in the NIF (internal)?\\n\"\n\"Choose 'Yes' for internal or 'No' for external.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4772\nmsgid \"Starfield Geometry Mode\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4786\nmsgid \"Export outfit NIF\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4806\n#, c-format\nmsgid \"Failed to save NIF file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4806 src/program/OutfitStudio.cpp:4840\n#: src/program/OutfitStudio.cpp:4925 src/program/OutfitStudio.cpp:5053\n#: src/program/OutfitStudio.cpp:5279\nmsgid \"Export Error\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4822\nmsgid \"Export project NIF\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4840\n#, c-format\nmsgid \"Failed to save NIF file '%s' with reference!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4851\nmsgid \"Export selected shapes to NIF\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4865\nmsgid \"Failed to export selected shapes to NIF file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4870\nmsgid \"Import .obj file for new shape\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4908\nmsgid \"Some of the shapes have coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to global coordinates in the OBJ?  (This is not recommended.)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4910 src/program/OutfitStudio.cpp:4943\n#: src/program/OutfitStudio.cpp:5038 src/program/OutfitStudio.cpp:5075\nmsgid \"Transform to global\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4917\nmsgid \"Export project as an .obj file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4925 src/program/OutfitStudio.cpp:4965\n#: src/program/OutfitStudio.cpp:4984 src/program/OutfitStudio.cpp:8463\nmsgid \"Failed to export OBJ file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4941\nmsgid \"Some of the shapes have skin coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to global coordinates in the OBJ?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4952\nmsgid \"Export selected shapes as an .obj file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4969\nmsgid \"Export shape as an .obj file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4991\nmsgid \"Import .fbx file for new shape\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5017 src/program/OutfitStudio.cpp:5056\n#: src/program/OutfitStudio.cpp:5120 src/program/OutfitStudio.cpp:8364\nmsgid \"FBX is only supported in 64-bit builds of Outfit Studio. Start \\\"OutfitStudio x64\\\" instead.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5017 src/program/OutfitStudio.cpp:5056\n#: src/program/OutfitStudio.cpp:5120 src/program/OutfitStudio.cpp:5257\n#: src/program/OutfitStudio.cpp:7122 src/program/OutfitStudio.cpp:7893\n#: src/program/OutfitStudio.cpp:8364\nmsgid \"Info\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5036\nmsgid \"Some of the shapes have skin coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to global coordinates in the FBX?  (This is not recommended.)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5045\nmsgid \"Export project as an .fbx file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5053 src/program/OutfitStudio.cpp:5097\n#: src/program/OutfitStudio.cpp:5116\nmsgid \"Failed to export FBX file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5073\nmsgid \"Some of the shapes have skin coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to global coordinates in the FBX?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5084\nmsgid \"Export selected shapes as an .fbx file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5101\nmsgid \"Export shape as an .fbx file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5125 src/program/OutfitStudio.cpp:8109\nmsgid \"Import .tri morphs\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5144 src/program/OutfitStudio.cpp:8118\nmsgid \"Failed to load TRI file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5150 src/program/OutfitStudio.cpp:9335\nmsgid \"Please enter a new unique name for the shape.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5202 src/program/OutfitStudio.cpp:5226\n#: src/program/OutfitStudio.cpp:8494\nmsgid \"Export .tri morphs\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5212 src/program/OutfitStudio.cpp:5233\n#: src/program/OutfitStudio.cpp:8501\nmsgid \"Failed to export TRI file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5238\nmsgid \"Import physics data to project\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5245\n#, c-format\nmsgid \"Failed to import physics data file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5245\nmsgid \"Import Error\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5257\nmsgid \"There is no physics data loaded!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5265\nmsgid \"Please choose the physics data source you want to export.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5265\nmsgid \"Choose physics data\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5273\nmsgid \"Export physics data\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5279\n#, c-format\nmsgid \"Failed to save physics data file '%s'!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5286\nmsgid \"This function requires at least one slider position to be non-zero.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5298\nmsgid \"Create a conversion slider for the current slider settings with the following name: \"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:5298\nmsgid \"Create New Conversion Slider\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:6048\nmsgid \"Please enter an SSF file path.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:6888\n#, c-format\nmsgid \"Field of View: %d\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7097\nmsgid \"Your changes were not applied yet. Do you want to apply or reset them?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7098\nmsgid \"Pending Changes\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7122\nmsgid \"You must have exactly one mesh selected in order to edit partitions or segments.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7842\nmsgid \"There are no sliders loaded!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7893\nmsgid \"No changes were made to the sliders, so no preset was saved!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7909 src/program/OutfitStudio.cpp:7934\n#: src/program/OutfitStudio.cpp:7955 src/program/OutfitStudio.cpp:8345\nmsgid \"There is no slider in edit mode to import data to!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7913\nmsgid \"Import .nif file for slider calculation\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7920\nmsgid \"No mesh found in the .nif file that matches currently selected shape!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7938\nmsgid \"Import .bsd slider data\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7959\nmsgid \"Import .obj file for slider calculation\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7966 src/program/OutfitStudio.cpp:8356\nmsgid \"Vertex count of .obj file mesh does not match currently selected shape!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7981\nmsgid \"Import .osd file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7990\nmsgid \"Failed to import OSD file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8030 src/program/OutfitStudio.cpp:8141\n#: src/program/OutfitStudio.cpp:8273\nmsgid \"This will delete all loaded sliders. Are you sure?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8030 src/program/OutfitStudio.cpp:8100\nmsgid \"OSD Import\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8100 src/program/OutfitStudio.cpp:8216\n#: src/program/OutfitStudio.cpp:8336\n#, c-format\nmsgid \"\"\n\"Added morphs for the following shapes:\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8141 src/program/OutfitStudio.cpp:8216\nmsgid \"TRI Import\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8228\nmsgid \"Import Starfield morph.dat file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8237 src/program/OutfitStudio.cpp:8243\nmsgid \"Failed to import Starfield morph file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8273 src/program/OutfitStudio.cpp:8336\nmsgid \"Starfield Morph Import\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8349\nmsgid \"Import .fbx file for slider calculation\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8373 src/program/OutfitStudio.cpp:8408\n#: src/program/OutfitStudio.cpp:8440\nmsgid \"There is no slider in edit mode to export data from!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8378\nmsgid \"Export .nif slider data to directory\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8389\nmsgid \"Export .nif slider data\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8396\nmsgid \"Failed to export NIF file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8413\nmsgid \"Export .bsd slider data to directory\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8424\nmsgid \"Export .bsd slider data\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8445 src/program/OutfitStudio.cpp:8533\nmsgid \"Export .obj slider data to directory\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8456\nmsgid \"Export .obj slider data\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8476\nmsgid \"Export .osd file\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8483\nmsgid \"Failed to export OSD file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8515\nmsgid \"Export Starfield morph.dat\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8522\nmsgid \"Failed to export Starfield morph.dat file!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8560\nmsgid \"Are you sure you wish to clear the unmasked slider data for the selected shapes?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8561 src/program/OutfitStudio.cpp:8566\nmsgid \"Confirm data erase\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8564\n#, c-format\nmsgid \"Are you sure you wish to clear the unmasked slider data for the shape '%s'?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8618\nmsgid \"Enter a name for the new zap:\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8618\nmsgid \"Create New Zap\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8665\nmsgid \"There is no slider in edit mode to clone!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8681\nmsgid \"Enter a name for the cloned slider:\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8701\nmsgid \"There is no slider in edit mode to negate!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8717\nmsgid \"There is no slider in edit mode to create a mask from!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8727\nmsgid \"Are you sure you wish to delete the selected slider(s)?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8728\nmsgid \"Confirm slider delete\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8928\nmsgid \"There is no slider in edit mode to show properties for!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8941 src/program/OutfitStudio.cpp:8946\n#, c-format\nmsgid \"Strength: %d\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:8996\nmsgid \"You must be in slider edit mode to fix clipping for a slider.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:9002 src/program/OutfitStudio.cpp:10067\nmsgid \"No reference shape set.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:9070 src/program/OutfitStudio.cpp:9120\nmsgid \"Conforming: \"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:9101\nmsgid \"Conforming shapes...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:9131\nmsgid \"All shapes conformed.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10140\nmsgid \"Are you sure you wish to delete parts of the selected shapes?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10181\nmsgid \"Please enter a unique name for the new separated shape.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10181\nmsgid \"Separate Vertices...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10231\nmsgid \"No errors found!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10237\nmsgid \"Errors:\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10239\nmsgid \"Target must be different from source.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10241\nmsgid \"Partitions do not match. Make sure the amount of partitions and their slots match up.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10243\nmsgid \"Segments do not match. Make sure the amount of segments, sub segments and their info as well as the segmentation file match.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10245\nmsgid \"Resulting shape would have too many vertices.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10247\nmsgid \"Resulting shape would have too many triangles.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10249\nmsgid \"Shaders do not match. Make sure both shapes either have or don't have a shader and their shader type matches.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10251\nmsgid \"Base texture doesn't match. Make sure both shapes have the same base/diffuse texture path.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10253\nmsgid \"Alpha property mismatch. Make sure both shapes either have or don't have an alpha property and their flags + threshold match.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10340\nmsgid \"You can only copy shapes into an outfit, and there is no outfit in the current project. Load one first!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10348\nmsgid \"Please enter a unique name for the duplicated shape.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10390\nmsgid \"There is more than one shape selected.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10457\nmsgid \"Some edges have multiple triangles of the same orientation. They have been highlighted and masked. Correct the orientations before refining.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10475\nmsgid \"Can't delete shape while in slider edit mode.  Use CTRL+Delete to delete sliders instead.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10483\nmsgid \"Are you sure you wish to delete the selected shapes?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10514\nmsgid \"Delete selected bones?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10524\nmsgid \"Delete bones from selected shape(s)?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10532\nmsgid \"Delete partition?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10539\nmsgid \"Delete segment?  This action cannot be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10684\nmsgid \"No bone name was entered!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10692 src/program/OutfitStudio.cpp:10733\n#, c-format\nmsgid \"Bone '%s' already exists in the project!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10791\nmsgid \"View Standard Bone\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10802\nmsgid \"Edit Custom Bone\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10885\nmsgid \"The following shapes have unweighted vertices, which can cause issues. The affected vertices have been put under a mask. Do you want to save anyway?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10888\nmsgid \"Unweighted Vertices\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10992 src/program/OutfitStudio.cpp:11120\n#: src/program/OutfitStudio.cpp:11254\nmsgid \"There is no reference shape!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11001\nmsgid \"Sorry, you can't copy weights from the reference shape to itself. Skipping this shape.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11001\nmsgid \"Can't copy weights\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11125\nmsgid \"Sorry, you can't copy weights from the reference shape to itself.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11132\nmsgid \"The vertex count of the reference and chosen shape is not the same!\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11263\nmsgid \"Sorry, you can't copy partitions/segments from the reference shape to itself. Skipping this shape.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11263\nmsgid \"Can't copy segments/partitions\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11268\nmsgid \"Triangles will be assigned to the partition/segment of the nearest triangle in the reference.  Existing partitions/segments are cleared.  This action can't be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11268\nmsgid \"Copy Partitions/Segments\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11277\nmsgid \"Copying segments/partitions...\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11288\n#, c-format\nmsgid \"The partitions/segments could not be copied for '%s' because %d triangles could not be matched.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11339\nmsgid \" sliders\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11341\nmsgid \" bones\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11477\nmsgid \"Symmetrize Vertices\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11479\nmsgid \"Eliminates the selected asymmetries from unmasked vertices by adjusting vertex data to be consistent with mirror vertices.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11481\nmsgid \"  (Hint: To choose which non-selected bones are adjusted during weight normalization, unlock them in the bones list in the Bones tab.)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11485\nmsgid \"Vertices that will be symmetrized:\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11486\nmsgid \"&Symmetrize\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11639\n#, c-format\nmsgid \"%d unreferenced nodes were deleted.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11944\nmsgid \"No masks to export.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11944 src/program/OutfitStudio.cpp:11948\n#: src/program/OutfitStudio.cpp:11978\nmsgid \"Export Masks\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11978\nmsgid \"Failed to save mask file.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11982 src/program/OutfitStudio.cpp:11993\nmsgid \"Import Masks\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:11993\nmsgid \"Failed to load mask file.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12000\nmsgid \"Imported Mask\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12188\nmsgid \"Reset all bone poses?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12188\nmsgid \"Reset Pose\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12344\nmsgid \"Please enter a new unique name for the pose.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12344\nmsgid \"New Pose\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12395\n#, c-format\nmsgid \"Are you sure you wish to delete the pose '%s'?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12396\nmsgid \"Confirm pose delete\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13434\nmsgid \"The vertex picked has more than three connections.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13669\nmsgid \"Neither the selected nor target vertices are on the mesh boundary.  It is recommended that you only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13670\nmsgid \"The selected vertex is not on the mesh boundary.  It is recommended that you only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13671\nmsgid \"The target vertex is not on the mesh boundary.  It is recommended that you only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13672\nmsgid \"Weld/Merge Non-Boundary Vertices\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13754\nmsgid \"The edge picked is on the surface boundary.  Pick an interior edge.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:13811\nmsgid \"The edge picked has multiple triangles of the same orientation.  Correct the orientations before splitting.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:15233 src/program/OutfitStudio.cpp:15234\nmsgid \"Loading slider file...\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:104\nmsgid \"Material\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:117\n#, c-format\nmsgid \"%zu shapes selected\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:132\n#, c-format\nmsgid \"This action will affect all %zu selected shapes. Are you sure?\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:133\nmsgid \"Confirmation\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:352\nmsgid \"Choose material file\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:666\nmsgid \"Please choose a shape to copy from\"\nmsgstr \"\"\n\n#: src/program/ShapeProperties.cpp:666\nmsgid \"Choose shape\"\nmsgstr \"\"\n\n#: src/render/GLDialog.cpp:33 src/ui/PreviewPanel.cpp:151\nmsgid \"Preview failed: OpenGL context is not OK.\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:57\nmsgid \"Show the Normal Map Generator dialog.\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:61\nmsgid \"Lock Shape\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:62\nmsgid \"Set the current preview shape to both low and high weight sliders.\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:66\nmsgid \"Show Reference\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:67\nmsgid \"Show the reference shape from the source project for clipping preview.\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:75\nmsgid \"Pop out preview into a separate window\"\nmsgstr \"\"\n\n#: src/ui/PreviewPanel.cpp:103\nmsgid \"Loading preview...\"\nmsgstr \"\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:133\nmsgid \"Size\"\nmsgstr \"\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:137\nmsgid \"Shortcut: 'S' + mouse wheel\"\nmsgstr \"\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:146\nmsgid \"Strength\"\nmsgstr \"\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:158\nmsgid \"Focus\"\nmsgstr \"\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:170\nmsgid \"Spacing\"\nmsgstr \"\"\n\n#: src/ui/wxSliderPanel.cpp:65\nmsgid \"Turn on edit mode for this slider.\"\nmsgstr \"\"\n\n#: src/ui/wxSliderPanel.cpp:77\nmsgid \"Weaken slider data by 1%.\"\nmsgstr \"\"\n\n#: src/ui/wxSliderPanel.cpp:84\nmsgid \"Strengthen slider data by 1%.\"\nmsgstr \"\"\n"
  },
  {
    "path": "lang/af/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/af/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/an/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/an/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ar/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ar/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ca/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ca/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/cs/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/cs/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/da/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/da/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/de/BodySlide.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: BodySlide\\n\"\n\"POT-Creation-Date: \\n\"\n\"PO-Revision-Date: \\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: de\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\"X-Poedit-KeywordsList: _\\n\"\n\n#: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:457\nmsgid \"About\"\nmsgstr \"Über\"\n\n#: res/xrc/About.xrc:145 res/xrc/GroupManager.xrc:189\nmsgid \"Close\"\nmsgstr \"Schließen\"\n\n#: res/xrc/Actions.xrc:6\nmsgid \"Apply a vertex position\"\nmsgstr \"Setzt eine Vertex Position\"\n\n#: res/xrc/Actions.xrc:15\nmsgid \"This permanently moves a single vertex straight to the given location.\"\nmsgstr \"Dies bewegt einen einzelnen Vertex permanent zur angegebenen Position.\"\n\n#: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499\n#: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:862 res/xrc/Actions.xrc:938\n#: res/xrc/Actions.xrc:1014 res/xrc/Actions.xrc:1062 res/xrc/Actions.xrc:1212\n#: res/xrc/Actions.xrc:1491 res/xrc/Actions.xrc:1592 res/xrc/BatchBuild.xrc:112\n#: res/xrc/EditUV.xrc:32 res/xrc/EditUV.xrc:251 res/xrc/EditUV.xrc:326\n#: res/xrc/EditUV.xrc:447 res/xrc/ImportDialog.xrc:174 res/xrc/Project.xrc:773\n#: res/xrc/Project.xrc:950 res/xrc/Settings.xrc:459\n#: res/xrc/ShapeProperties.xrc:831 res/xrc/Skeleton.xrc:36\n#: res/xrc/Skeleton.xrc:259 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238\n#: res/xrc/SliderDataImport.xrc:90\nmsgid \"&OK\"\nmsgstr \"&OK\"\n\n#: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506\n#: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:869 res/xrc/Actions.xrc:945\n#: res/xrc/Actions.xrc:1021 res/xrc/Actions.xrc:1069 res/xrc/Actions.xrc:1219\n#: res/xrc/Actions.xrc:1498 res/xrc/Actions.xrc:1599 res/xrc/Actions.xrc:1930\n#: res/xrc/BatchBuild.xrc:57 res/xrc/BatchBuild.xrc:119 res/xrc/EditUV.xrc:39\n#: res/xrc/EditUV.xrc:258 res/xrc/EditUV.xrc:333 res/xrc/EditUV.xrc:454\n#: res/xrc/ImportDialog.xrc:181 res/xrc/Project.xrc:570 res/xrc/Project.xrc:780\n#: res/xrc/Project.xrc:957 res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:466\n#: res/xrc/Setup.xrc:302 res/xrc/ShapeProperties.xrc:838\n#: res/xrc/Skeleton.xrc:43 res/xrc/Skeleton.xrc:266 res/xrc/Slider.xrc:71\n#: res/xrc/Slider.xrc:246 res/xrc/SliderDataImport.xrc:97\nmsgid \"&Cancel\"\nmsgstr \"&Abbrechen\"\n\n#: res/xrc/Actions.xrc:110\nmsgid \"Move Shape\"\nmsgstr \"Modell verschieben\"\n\n#: res/xrc/Actions.xrc:254\nmsgid \"Mirror Axis\"\nmsgstr \"Spiegelachse\"\n\n#: res/xrc/Actions.xrc:320\nmsgid \"Scale Shape\"\nmsgstr \"Modell skalieren\"\n\n#: res/xrc/Actions.xrc:329\nmsgid \"\"\n\"Scaling will adjust the size of a mesh. This permanently affects vertices.\"\nmsgstr \"\"\n\"Skalierung verändert die Größe eines Modells. Dies beeinflusst Vertices \"\n\"permanent.\"\n\n#: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667\n#: res/xrc/ShapeProperties.xrc:711 res/xrc/Skeleton.xrc:133\nmsgid \"Origin\"\nmsgstr \"Ausgangspunkt\"\n\n#: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678\nmsgid \"Zero (0, 0, 0)\"\nmsgstr \"Nullpunkt (0, 0, 0)\"\n\n#: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679\nmsgid \"Center of selected shapes(s)\"\nmsgstr \"Mitte der ausgewählten Modelle\"\n\n#: res/xrc/Actions.xrc:484 res/xrc/Actions.xrc:847\nmsgid \"Uniform (XYZ)\"\nmsgstr \"Proportionen beibehalten (XYZ)\"\n\n#: res/xrc/Actions.xrc:517\nmsgid \"Rotate Shape\"\nmsgstr \"Modell rotieren\"\n\n#: res/xrc/Actions.xrc:712\nmsgid \"Inflate Shape\"\nmsgstr \"Modell aufblasen\"\n\n#: res/xrc/Actions.xrc:721\nmsgid \"\"\n\"Inflate/deflate a mesh along its normals. This permanently affects vertices.\"\nmsgstr \"\"\n\"Aufblasen vergrößert ein Modell entlang dessen Normals. Dies beeinflusst \"\n\"Vertices permanent.\"\n\n#: res/xrc/Actions.xrc:880\nmsgid \"Mirror Shape\"\nmsgstr \"Modell spiegeln\"\n\n#: res/xrc/Actions.xrc:924\nmsgid \"Swap bones on X axis (L/R)\"\nmsgstr \"Bones auf X-Achse tauschen (L/R)\"\n\n#: res/xrc/Actions.xrc:956\nmsgid \"Smooth Seams\"\nmsgstr \"Normals an Rändern glätten\"\n\n#: res/xrc/Actions.xrc:1032\nmsgid \"Set Shape Textures\"\nmsgstr \"Modelltexturen setzen\"\n\n#: res/xrc/Actions.xrc:1079 res/xrc/ConvertBodyReference.xrc:183\n#: res/xrc/OutfitStudio.xrc:1953 res/xrc/OutfitStudio.xrc:2413\nmsgid \"Copy Bone Weights\"\nmsgstr \"Bone Weighting kopieren\"\n\n#: res/xrc/Actions.xrc:1088\nmsgid \"\"\n\"Each vertex of the reference will copy its weights to the nearest collection \"\n\"of vertices within the given radius. Bear in mind that some geometry will \"\n\"always require manual tweaking to become weighted and work well. Often, the \"\n\"default values are sufficient.\"\nmsgstr \"\"\n\"Jeder Vertex der Referenz wird sein Weighting auf die nächste Sammlung an \"\n\"Vertices innerhalb des gegebenen Radius kopieren. Allerdings müssen manche \"\n\"Modelle trotzdem noch manuell bearbeitet werden, um Weighting abzubekommen \"\n\"oder gut damit zu funktionieren. Meist genügen die Standardwerte.\"\n\n#: res/xrc/Actions.xrc:1108 res/xrc/Actions.xrc:1258\nmsgid \"Search Radius\"\nmsgstr \"Suchradius\"\n\n#: res/xrc/Actions.xrc:1137 res/xrc/Actions.xrc:1287\nmsgid \"Max Vertex Targets\"\nmsgstr \"Max Vertex Ziele\"\n\n#: res/xrc/Actions.xrc:1168 res/xrc/Actions.xrc:1316\nmsgid \"No Target Limit\"\nmsgstr \"Keine Ziellimitierung\"\n\n#: res/xrc/Actions.xrc:1177\nmsgid \"\"\n\"The skin coordinate system doesn't match the reference shape's. Do you want \"\n\"to copy the transforms?\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1187\nmsgid \"Copy skin transform from reference\"\nmsgstr \"Skin-Transformation der Referenz kopieren\"\n\n#: res/xrc/Actions.xrc:1197 res/xrc/ShapeProperties.xrc:806\nmsgid \"Recalculate geometry's coordinates so it doesn't move\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1198 res/xrc/ShapeProperties.xrc:807\nmsgid \"\"\n\"Transform geometry so its position in global coordinates does not change.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1229\nmsgid \"Conforming...\"\nmsgstr \"Übertrage...\"\n\n#: res/xrc/Actions.xrc:1238\nmsgid \"\"\n\"Each vertex of the reference will copy its slider data to the nearest \"\n\"collection of vertices within the given radius. Bear in mind that some \"\n\"geometry will always require manual tweaking to become conformed and work \"\n\"well. Often, the default values are sufficient.\"\nmsgstr \"\"\n\"Jeder Vertex der Referenz wird seine Sliderdaten auf die nächste Sammlung an \"\n\"Vertices innerhalb des gegebenen Radius kopieren. Allerdings müssen manche \"\n\"Modelle trotzdem noch manuell bearbeitet werden, um die Sliderdaten \"\n\"abzubekommen oder gut damit zu funktionieren. Meist genügen die \"\n\"Standardwerte.\"\n\n#: res/xrc/Actions.xrc:1339\nmsgid \"No Squeeze\"\nmsgstr \"Nicht quetschen\"\n\n#: res/xrc/Actions.xrc:1362\nmsgid \"Solid Mode\"\nmsgstr \"Festmodus\"\n\n#: res/xrc/Actions.xrc:1385\nmsgid \"Axis\"\nmsgstr \"Achse\"\n\n#: res/xrc/Actions.xrc:1435 res/xrc/BodySlide.xrc:97\n#: res/xrc/NormalsGenDlg.xrc:191\nmsgid \"Preset\"\nmsgstr \"Preset\"\n\n#: res/xrc/Actions.xrc:1451 src/program/OutfitStudio.cpp:8177\nmsgid \"Default\"\nmsgstr \"Standard\"\n\n#: res/xrc/Actions.xrc:1460\nmsgid \"Even Movement\"\nmsgstr \"Glatte Bewegung\"\n\n#: res/xrc/Actions.xrc:1469\nmsgid \"Solid Object\"\nmsgstr \"Festes Objekt\"\n\n#: res/xrc/Actions.xrc:1508\nmsgid \"Merge Geometry\"\nmsgstr \"Geometrie zusammenführen\"\n\n#: res/xrc/Actions.xrc:1517\nmsgid \"\"\n\"This function copies vertices and triangles from one shape to another.  \"\n\"Partitions/segments of source and target shapes must match.  It is the \"\n\"user's responsibility to check that all other shape and shader properties \"\n\"are compatible, or merging will likely have side effects.\"\nmsgstr \"\"\n\n#: res/xrc/Actions.xrc:1532\nmsgid \"Source\"\nmsgstr \"Quelle\"\n\n#: res/xrc/Actions.xrc:1550\nmsgid \"Target\"\nmsgstr \"Ziel\"\n\n#: res/xrc/Actions.xrc:1579\nmsgid \"Delete source shape\"\nmsgstr \"Quellmodell löschen\"\n\n#: res/xrc/Actions.xrc:1609\nmsgid \"Mask symmetric vertices\"\nmsgstr \"Symmetrische Vertices maskieren\"\n\n#: res/xrc/Actions.xrc:1618\nmsgid \"Masks all vertices that do not have any of the selected asymmetries.\"\nmsgstr \"\"\n\"Maskiert alle Vertices, welche keine der ausgewählten Asymmetrien vorweisen.\"\n\n#: res/xrc/Actions.xrc:1644\nmsgid \"Vertices currently unmasked:\"\nmsgstr \"Vertices ohne Maskierung:\"\n\n#: res/xrc/Actions.xrc:1672\nmsgid \"Unmatched Vertices:\"\nmsgstr \"Nicht zutreffende Vertices:\"\n\n#: res/xrc/Actions.xrc:1694\nmsgid \"Vertex Data Asymmetries\"\nmsgstr \"Asymmetrien der Vertexdaten\"\n\n#: res/xrc/Actions.xrc:1727 res/xrc/OutfitStudio.xrc:793\n#: res/xrc/OutfitStudio.xrc:1057 res/xrc/ShapeProperties.xrc:84\n#: res/xrc/ShapeProperties.xrc:620\nmsgid \"Type\"\nmsgstr \"Typ\"\n\n#: res/xrc/Actions.xrc:1736\nmsgid \"Average\"\nmsgstr \"Durchschnitt\"\n\n#: res/xrc/Actions.xrc:1745\nmsgid \"Count\"\nmsgstr \"Anzahl\"\n\n#: res/xrc/Actions.xrc:1763\nmsgid \"Position\"\nmsgstr \"Position\"\n\n#: res/xrc/Actions.xrc:1831 res/xrc/Project.xrc:751\nmsgid \"Sliders\"\nmsgstr \"Slider\"\n\n#: res/xrc/Actions.xrc:1878 res/xrc/OutfitStudio.xrc:387\n#: res/xrc/OutfitStudio.xrc:2461 res/xrc/OutfitStudio.xrc:2505\nmsgid \"Bones\"\nmsgstr \"Bones\"\n\n#: res/xrc/Actions.xrc:1897\nmsgid \"Vertices that will still be unmasked:\"\nmsgstr \"Vertices die weiterhin unmaskiert sein werden:\"\n\n#: res/xrc/Actions.xrc:1923\nmsgid \"&Mask\"\nmsgstr \"&Maskieren\"\n\n#: res/xrc/BatchBuild.xrc:6\nmsgid \"Batch Build\"\nmsgstr \"Batch-Erstellung\"\n\n#: res/xrc/BatchBuild.xrc:21\nmsgid \"\"\n\"Select the slider sets for the batch build process. Use the group and outfit \"\n\"filters to show the outfits you want!\"\nmsgstr \"\"\n\"Wählen Sie die Sets für den Batch-Erstellungsprozess. Mithilfe der Gruppen- \"\n\"und Outfitfilter können Sie die Auswahl eingrenzen!\"\n\n#: res/xrc/BatchBuild.xrc:50\nmsgid \"&Build\"\nmsgstr \"&Erstellen\"\n\n#: res/xrc/BatchBuild.xrc:67 src/program/BodySlideApp.cpp:2448\nmsgid \"Choose output set\"\nmsgstr \"Ausgabe-Set auswählen\"\n\n#: res/xrc/BatchBuild.xrc:78\nmsgid \"\"\n\"The following sets will override the same files.\\n\"\n\"Please decide which one to use and select it in the list below.\"\nmsgstr \"\"\n\"Die folgenden Sets würde die selben Dateien überschreiben.\\n\"\n\"Bitte entscheiden Sie, welche davon verwendet werden sollen.\"\n\n#: res/xrc/BatchBuild.xrc:88\nmsgid \"Type and hit enter to choose output...\"\nmsgstr \"Hier tippen und Enter betätigen, um die Ausgabe zu wählen...\"\n\n#: res/xrc/BodySlide.xrc:7\nmsgid \"BodySlide\"\nmsgstr \"BodySlide\"\n\n#: res/xrc/BodySlide.xrc:28\nmsgid \"Outfit/Body\"\nmsgstr \"Outfit/Körper\"\n\n#: res/xrc/BodySlide.xrc:44\nmsgid \"Select an outfit to modify\"\nmsgstr \"Wählen Sie das zu bearbeitende Outfit\"\n\n#: res/xrc/BodySlide.xrc:58\nmsgid \"Deletes a project from its project file\"\nmsgstr \"Löscht ein Projekt aus der Projektdatei\"\n\n#: res/xrc/BodySlide.xrc:74\nmsgid \"Opens the current project in Outfit Studio\"\nmsgstr \"Öffnet das aktuelle Projekt in Outfit Studio\"\n\n#: res/xrc/BodySlide.xrc:113\nmsgid \"Choose from a list of slider settings presets\"\nmsgstr \"Wählen Sie aus einer Liste von Presets\"\n\n#: res/xrc/BodySlide.xrc:127\nmsgid \"Deletes a preset from its preset file\"\nmsgstr \"Löscht ein Preset aus der Presetdatei\"\n\n#: res/xrc/BodySlide.xrc:142\nmsgid \"Saves the new slider values to the currently selected preset\"\nmsgstr \"Speichert die neuen Sliderwerte in das derzeit gewählte Preset\"\n\n#: res/xrc/BodySlide.xrc:143 res/xrc/GroupManager.xrc:44\n#: res/xrc/OutfitStudio.xrc:1257 res/xrc/OutfitStudio.xrc:1318\nmsgid \"Save\"\nmsgstr \"Speichern\"\n\n#: res/xrc/BodySlide.xrc:153\nmsgid \"Save the current slider settings as a new preset\"\nmsgstr \"Speichert die aktuellen Sliderwerte als ein neues Preset\"\n\n#: res/xrc/BodySlide.xrc:154 res/xrc/GroupManager.xrc:53\n#: res/xrc/OutfitStudio.xrc:1266 res/xrc/OutfitStudio.xrc:1327\nmsgid \"Save As...\"\nmsgstr \"Speichern unter...\"\n\n#: res/xrc/BodySlide.xrc:165\nmsgid \"\"\n\"Opens the group manager where you can edit existing or create new groups\"\nmsgstr \"Öffnet den Gruppenmanager zum Bearbeiten oder Erstellen von Gruppen\"\n\n#: res/xrc/BodySlide.xrc:166 res/xrc/GroupManager.xrc:7\n#: res/xrc/Project.xrc:1079\nmsgid \"Group Manager\"\nmsgstr \"Gruppenmanager\"\n\n#: res/xrc/BodySlide.xrc:218\nmsgid \"Single Weight\"\nmsgstr \"Einzelnes Gewicht\"\n\n#: res/xrc/BodySlide.xrc:245\nmsgid \"Low Weight\"\nmsgstr \"Unteres Gewicht\"\n\n#: res/xrc/BodySlide.xrc:262\nmsgid \"High Weight\"\nmsgstr \"Oberes Gewicht\"\n\n#: res/xrc/BodySlide.xrc:303\nmsgid \"Copy the low weight slider values to the high weight section.\"\nmsgstr \"Kopiert die unteren Sliderwerte in den oberen Bereich.\"\n\n#: res/xrc/BodySlide.xrc:320\nmsgid \"Default outfit choice in Batch Build\"\nmsgstr \"Standardmäßige Wahl in Batch-Erstellung\"\n\n#: res/xrc/BodySlide.xrc:331\nmsgid \"Output Path (which the game would use for this outfit)\"\nmsgstr \"Ausgabepfad (den das Spiel für dieses Outfit verwendet)\"\n\n#: res/xrc/BodySlide.xrc:343\nmsgid \"(right-click to view alternatives)\"\nmsgstr \"(Rechtsklick zur Anzeige von Alternativen)\"\n\n#: res/xrc/BodySlide.xrc:363\nmsgid \"\"\n\"Build multiple outfits using the currently active slider values.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to custom directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"Erstellt mehrere Outfits unter Verwendung der derzeit aktiven Sliderwerte.\\n\"\n\"\\n\"\n\"STRG gedrückt halten = Benutzerdefiniertes Verzeichnis auswählen\\n\"\n\"ALT gedrückt halten = Aus dem Ausgabeverzeichnis löschen\"\n\n#: res/xrc/BodySlide.xrc:364\nmsgid \"Batch Build...\"\nmsgstr \"Batch-Erstellung...\"\n\n#: res/xrc/BodySlide.xrc:379\nmsgid \"Build Morphs\"\nmsgstr \"Morphs erstellen\"\n\n#: res/xrc/BodySlide.xrc:380\nmsgid \"\"\n\"Builds a morphs (.tri) file alongside the meshes for accessing the sliders \"\n\"in-game. Requires other mods to make use of the morph data.\"\nmsgstr \"\"\n\"Erstellt eine Morphdatei (.tri) neben den Meshes zum Verwenden der Slider \"\n\"innerhalb des Spiels. Benötigt weitere Mods zur Verwendung der Morphs.\"\n\n#: res/xrc/BodySlide.xrc:390\nmsgid \"Force Body Normals\"\nmsgstr \"Körper Normals erzwingen\"\n\n#: res/xrc/BodySlide.xrc:391\nmsgid \"\"\n\"Adds normal and tangent data to the body meshes (including bodies within \"\n\"outfits) for Skyrim. Use this only if you have a tangent space body mod.\"\nmsgstr \"\"\n\n#: res/xrc/BodySlide.xrc:407\nmsgid \"Show a preview window for this outfit.\"\nmsgstr \"Zeigt eine Vorschau für dieses Outfit.\"\n\n#: res/xrc/BodySlide.xrc:408 res/xrc/NormalsGenDlg.xrc:166\n#: src/program/PreviewWindow.cpp:27\nmsgid \"Preview\"\nmsgstr \"Vorschau\"\n\n#: res/xrc/BodySlide.xrc:426\nmsgid \"\"\n\"Creates the currently selected outfit/body.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to working directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"Erstellt das derzeit ausgewählte Outfit/den Körper.\\n\"\n\"\\n\"\n\"STRG gedrückt halten = Im Arbeitsverzeichnis erstellen\\n\"\n\"ALT gedrückt halten = Vom Ausgabeverzeichnis entfernen\"\n\n#: res/xrc/BodySlide.xrc:427\nmsgid \"Build\"\nmsgstr \"Erstellen\"\n\n#: res/xrc/BodySlide.xrc:439\nmsgid \"Copy the high weight slider values to the low weight section.\"\nmsgstr \"Kopiert die oberen Sliderwerte in den unteren Bereich.\"\n\n#: res/xrc/BodySlide.xrc:466 res/xrc/OutfitStudio.xrc:1755\nmsgid \"Open settings dialog.\"\nmsgstr \"Öffnet die Einstellungen.\"\n\n#: res/xrc/BodySlide.xrc:467 res/xrc/OutfitStudio.xrc:1754\n#: res/xrc/Settings.xrc:5\nmsgid \"Settings\"\nmsgstr \"Einstellungen\"\n\n#: res/xrc/BodySlide.xrc:476\nmsgid \"\"\n\"Open Outfit Studio, a full-featured tool for creating and converting outfits.\"\nmsgstr \"\"\n\"Öffnet Outfit Studio, ein mit vielen Funktionen ausgestattetes Werkzeug zum \"\n\"Erstellen und Konvertieren von Outfits.\"\n\n#: res/xrc/BodySlide.xrc:477 res/xrc/OutfitStudio.xrc:7\nmsgid \"Outfit Studio\"\nmsgstr \"Outfit Studio\"\n\n#: res/xrc/BodySlide.xrc:487 res/xrc/BodySlide.xrc:499\nmsgid \"Filter Options\"\nmsgstr \"Filter Optionen\"\n\n#: res/xrc/BodySlide.xrc:489\nmsgid \"Choose groups...\"\nmsgstr \"Gruppen auswählen...\"\n\n#: res/xrc/BodySlide.xrc:490\nmsgid \"Choose groups to display in the Outfit menu\"\nmsgstr \"Gruppen an Outfits zum Anzeigen in der Liste auswählen\"\n\n#: res/xrc/BodySlide.xrc:494\nmsgid \"Refresh Groups\"\nmsgstr \"Gruppen aktualisieren\"\n\n#: res/xrc/BodySlide.xrc:495\nmsgid \"Refresh group information\"\nmsgstr \"Gruppeninformationen werden neu geladen\"\n\n#: res/xrc/BodySlide.xrc:501\nmsgid \"Refresh Outfits\"\nmsgstr \"Outfits aktualisieren\"\n\n#: res/xrc/BodySlide.xrc:502\nmsgid \"Reloads outfit list\"\nmsgstr \"Outfit-Liste wird neu geladen\"\n\n#: res/xrc/BodySlide.xrc:506\nmsgid \"Regular Expressions\"\nmsgstr \"Reguläre Ausdrücke\"\n\n#: res/xrc/BodySlide.xrc:507\nmsgid \"Allow the use of regular expressions (regex) for filtering.\"\nmsgstr \"Erlaubt die Verwendung von regulären Ausdrücken (Regex) zur Filterung.\"\n\n#: res/xrc/BodySlide.xrc:511\nmsgid \"Has Zap Options\"\nmsgstr \"Hat Zap-Möglichkeiten\"\n\n#: res/xrc/BodySlide.xrc:512\nmsgid \"Show only outfits that have zap options.\"\nmsgstr \"Nur Outfits mit Zap-Möglichkeiten anzeigen.\"\n\n#: res/xrc/BodySlide.xrc:517\nmsgid \"Browse outfit folder...\"\nmsgstr \"Outfit-Ordner durchsuchen...\"\n\n#: res/xrc/BodySlide.xrc:518\nmsgid \"\"\n\"Browses to the shape data folder of the current outfit in the file explorer.\"\nmsgstr \"ShapeData-Verzeichnis des aktuellen Outfits im Datei-Explorer öffnen.\"\n\n#: res/xrc/BodySlide.xrc:521\nmsgid \"Save Outfit list as group...\"\nmsgstr \"Outfit-Liste als Gruppe speichern...\"\n\n#: res/xrc/BodySlide.xrc:522\nmsgid \"Save the current filtered outfit list as a group\"\nmsgstr \"Speichert die derzeit gefilterten Outfits als neue Gruppe\"\n\n#: res/xrc/BodySlide.xrc:527 res/xrc/Project.xrc:1096\n#: res/xrc/SliderDataImport.xrc:106\nmsgid \"Select None\"\nmsgstr \"Nichts auswählen\"\n\n#: res/xrc/BodySlide.xrc:530 res/xrc/EditUV.xrc:111 res/xrc/Project.xrc:1099\n#: res/xrc/SliderDataImport.xrc:109\nmsgid \"Select All\"\nmsgstr \"Alle auswählen\"\n\n#: res/xrc/BodySlide.xrc:533 res/xrc/EditUV.xrc:115 res/xrc/Project.xrc:1102\n#: res/xrc/SliderDataImport.xrc:112\nmsgid \"Invert Selection\"\nmsgstr \"Auswahl umkehren\"\n\n#: res/xrc/ConvertBodyReference.xrc:6\nmsgid \"Convert / Replace Body Reference\"\nmsgstr \"Körperreferenz konvertieren/ersetzen\"\n\n#: res/xrc/ConvertBodyReference.xrc:16 res/xrc/ConvertBodyReference.xrc:219\nmsgid \"This wizard aids in the conversion to another body/reference..\"\nmsgstr \"\"\n\"Dieser Assistent hilft bei der Konvertierung zu einem anderen Körper/\"\n\"Referenz.\"\n\n#: res/xrc/ConvertBodyReference.xrc:25\nmsgid \"Reference Bodies\"\nmsgstr \"Referenzkörper\"\n\n#: res/xrc/ConvertBodyReference.xrc:36\nmsgid \"Select a conversion reference (or 'None' to skip converting):\"\nmsgstr \"\"\n\"Wählen Sie eine Konvertierungsreferenz (oder 'None' um die Konvertierung zu \"\n\"überspringen):\"\n\n#: res/xrc/ConvertBodyReference.xrc:58\nmsgid \"Conversion Body Reference\"\nmsgstr \"Konvertierungsreferenz\"\n\n#: res/xrc/ConvertBodyReference.xrc:78\nmsgid \"Select a body reference to convert to:\"\nmsgstr \"Wählen Sie eine Körperreferenz zu der konvertiert wird:\"\n\n#: res/xrc/ConvertBodyReference.xrc:100\nmsgid \"New Body Reference\"\nmsgstr \"Neue Körperreferenz\"\n\n#: res/xrc/ConvertBodyReference.xrc:130 res/xrc/NormalsGenDlg.xrc:108\n#: res/xrc/Slider.xrc:161\nmsgid \"Options\"\nmsgstr \"Optionen\"\n\n#: res/xrc/ConvertBodyReference.xrc:136 res/xrc/SliderDataImport.xrc:77\nmsgid \"Merge Sliders\"\nmsgstr \"Slider zusammenführen\"\n\n#: res/xrc/ConvertBodyReference.xrc:145\nmsgid \"Merge Zaps\"\nmsgstr \"Zaps zusammenführen\"\n\n#: res/xrc/ConvertBodyReference.xrc:165\nmsgid \"Conform Sliders\"\nmsgstr \"Slider übertragen\"\n\n#: res/xrc/ConvertBodyReference.xrc:174\nmsgid \"Skip conform popup (use default settings)\"\nmsgstr \"Conform-Popup überspringen (Standardwerte verwenden)\"\n\n#: res/xrc/ConvertBodyReference.xrc:192\nmsgid \"Skip bone weights popup (use default settings)\"\nmsgstr \"Bone Weights-Popup überspringen (Standardwerte verwenden)\"\n\n#: res/xrc/ConvertBodyReference.xrc:203\nmsgid \"Delete reference after completion\"\nmsgstr \"Referenz nach Abschluss entfernen\"\n\n#: res/xrc/ConvertBodyReference.xrc:228\nmsgid \"Rename Project (optional)\"\nmsgstr \"Projekt umbenennen (optional)\"\n\n#: res/xrc/ConvertBodyReference.xrc:239\nmsgid \"Specify text to be removed from the project name (comma-delimited):\"\nmsgstr \"\"\n\"Geben Sie einen Text an, der vom Projektnamen entfernt werden soll \"\n\"(kommagetrennt):\"\n\n#: res/xrc/ConvertBodyReference.xrc:260\nmsgid \"Remove from project name\"\nmsgstr \"Vom Projektnamen entfernen\"\n\n#: res/xrc/ConvertBodyReference.xrc:277\nmsgid \"Specify any text to be prepended to project name:\"\nmsgstr \"\"\n\"Geben Sie einen Text an, der dem Projektnamen vorangestellt werden soll:\"\n\n#: res/xrc/ConvertBodyReference.xrc:298\nmsgid \"Prepend to project name\"\nmsgstr \"Vor den Projektnamen anfügen\"\n\n#: res/xrc/ConvertBodyReference.xrc:315\nmsgid \"NOTE: Game file output path is unaffected by this\"\nmsgstr \"HINWEIS: Ausgabepfad für Spiel wird hiervon nicht beeinflusst\"\n\n#: res/xrc/ConvertBodyReference.xrc:326\nmsgid \"Extras (optional)\"\nmsgstr \"Extras (optional)\"\n\n#: res/xrc/ConvertBodyReference.xrc:337\nmsgid \"Remove the following shapes before conversion (comma-delimited):\"\nmsgstr \"Folgende Modelle vor der Konvertierung entfernen (kommagetrennt):\"\n\n#: res/xrc/ConvertBodyReference.xrc:359\nmsgid \"Shapes to delete\"\nmsgstr \"Modelle entfernen\"\n\n#: res/xrc/ConvertBodyReference.xrc:375\nmsgid \"Add the following bones after conversion (comma-delimited):\"\nmsgstr \"Folgende Bones nach der Konvertierung hinzufügen (kommagetrennt):\"\n\n#: res/xrc/ConvertBodyReference.xrc:396\nmsgid \"Bones to add\"\nmsgstr \"Bones hinzufügen\"\n\n#: res/xrc/EditUV.xrc:5\nmsgid \"Edit UV\"\nmsgstr \"Texturkoordinaten bearbeiten\"\n\n#: res/xrc/EditUV.xrc:52\nmsgid \"Box Selection\"\nmsgstr \"Auswahlrechteck\"\n\n#: res/xrc/EditUV.xrc:53\nmsgid \"\"\n\"Box Selection\\n\"\n\"Shortcut: 1\"\nmsgstr \"\"\n\"Auswahlrechteck\\n\"\n\"Tastenkürzel: 1\"\n\n#: res/xrc/EditUV.xrc:60\nmsgid \"Vertex Selection\"\nmsgstr \"Vertex-Auswahl\"\n\n#: res/xrc/EditUV.xrc:61\nmsgid \"\"\n\"Vertex Selection\\n\"\n\"Shortcut: 2\"\nmsgstr \"\"\n\"Vertex-Auswahl\\n\"\n\"Tastenkürzel: 2\"\n\n#: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:78\n#: res/xrc/OutfitStudio.xrc:2156\nmsgid \"Move\"\nmsgstr \"Bewegen\"\n\n#: res/xrc/EditUV.xrc:68\nmsgid \"\"\n\"Move\\n\"\n\"Shortcut: 3\"\nmsgstr \"\"\n\"Bewegen\\n\"\n\"Tastenkürzel: 3\"\n\n#: res/xrc/EditUV.xrc:74 res/xrc/EditUV.xrc:343 res/xrc/ImportDialog.xrc:71\n#: res/xrc/OutfitStudio.xrc:1559 res/xrc/ShapeProperties.xrc:672\n#: src/program/NormalsGenDialog.cpp:300\nmsgid \"Scale\"\nmsgstr \"Skalierung\"\n\n#: res/xrc/EditUV.xrc:75\nmsgid \"\"\n\"Scale\\n\"\n\"Shortcut: 4\"\nmsgstr \"\"\n\"Skalierung\\n\"\n\"Tastenkürzel: 4\"\n\n#: res/xrc/EditUV.xrc:81 res/xrc/EditUV.xrc:268\nmsgid \"Rotate\"\nmsgstr \"Rotieren\"\n\n#: res/xrc/EditUV.xrc:82\nmsgid \"\"\n\"Rotate\\n\"\n\"Shortcut: 5\"\nmsgstr \"\"\n\"Rotieren\\n\"\n\"Tastenkürzel: 5\"\n\n#: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89\nmsgid \"Show Seam Edges\"\nmsgstr \"Nahtkanten anzeigen\"\n\n#: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1640\nmsgid \"Menu\"\nmsgstr \"Menü\"\n\n#: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1763\nmsgid \"Edit\"\nmsgstr \"Bearbeiten\"\n\n#: res/xrc/EditUV.xrc:101 res/xrc/OutfitStudio.xrc:1765\nmsgid \"Undo\\tCtrl+Z\"\nmsgstr \"Rückgängig\\tCtrl+Z\"\n\n#: res/xrc/EditUV.xrc:102 res/xrc/OutfitStudio.xrc:1766\nmsgid \"Undo the previous action.\"\nmsgstr \"Macht die letzte Aktion rückgängig.\"\n\n#: res/xrc/EditUV.xrc:105 res/xrc/OutfitStudio.xrc:1769\nmsgid \"Redo\\tCtrl+Y\"\nmsgstr \"Wiederherstellen\\tCtrl+Y\"\n\n#: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:42\n#: res/xrc/OutfitStudio.xrc:1770\nmsgid \"Redo the next undone action.\"\nmsgstr \"Stellt die letzte Aktion wieder her.\"\n\n#: res/xrc/EditUV.xrc:110\nmsgid \"Select All\\tCtrl+A\"\nmsgstr \"Alle auswählen\\tCtrl+A\"\n\n#: res/xrc/EditUV.xrc:114\nmsgid \"Invert Selection\\tCtrl+I\"\nmsgstr \"Auswahl umkehren\\tCtrl+I\"\n\n#: res/xrc/EditUV.xrc:118\nmsgid \"Select Less\\tA\"\nmsgstr \"Weniger auswählen\\tD\"\n\n#: res/xrc/EditUV.xrc:119\nmsgid \"Select less adjacent points in the selected islands.\"\nmsgstr \"Weniger angrenzende Punkte in den ausgewählten Islands markieren.\"\n\n#: res/xrc/EditUV.xrc:122\nmsgid \"Select More\\tD\"\nmsgstr \"Mehr auswählen\\tD\"\n\n#: res/xrc/EditUV.xrc:123\nmsgid \"Select more adjacent points in the selected islands.\"\nmsgstr \"Mehr angrenzende Punkte in den ausgewählten Islands markieren.\"\n\n#: res/xrc/EditUV.xrc:127\nmsgid \"Mask Selection\"\nmsgstr \"Auswahl maskieren\"\n\n#: res/xrc/EditUV.xrc:128\nmsgid \"\"\n\"Create a mask from the current UV selection for the mesh in the main \"\n\"viewport.\"\nmsgstr \"Maskiert die aktuelle UV-Selektion des Meshes im Haupt-Viewport.\"\n\n#: res/xrc/EditUV.xrc:132\nmsgid \"Translate...\\tT\"\nmsgstr \"Bewegen...\\tT\"\n\n#: res/xrc/EditUV.xrc:133\nmsgid \"Show a dialog to translate the current selection.\"\nmsgstr \"Öffnet einen Dialog zum Bewegen der aktuellen Auswahl.\"\n\n#: res/xrc/EditUV.xrc:136\nmsgid \"Rotate...\\tR\"\nmsgstr \"Rotieren...\\tR\"\n\n#: res/xrc/EditUV.xrc:137\nmsgid \"Show a dialog to rotate the current selection.\"\nmsgstr \"Öffnet einen Dialog zum Rotieren der aktuellen Auswahl.\"\n\n#: res/xrc/EditUV.xrc:140\nmsgid \"Scale...\\tS\"\nmsgstr \"Skalieren...\\tS\"\n\n#: res/xrc/EditUV.xrc:141\nmsgid \"Show a dialog to scale the current selection.\"\nmsgstr \"Öffnet einen Dialog zum Skalieren der aktuellen Auswahl.\"\n\n#: res/xrc/EditUV.xrc:148\nmsgid \"Translate\"\nmsgstr \"Bewegen\"\n\n#: res/xrc/EditUV.xrc:289\nmsgid \"Angle\"\nmsgstr \"Winkel\"\n\n#: res/xrc/EditUV.xrc:432\nmsgid \"Uniform (UV)\"\nmsgstr \"Proportionen beibehalten (UV)\"\n\n#: res/xrc/GroupManager.xrc:17\nmsgid \"\"\n\"Choose a group and add or remove members by selecting them in the lists.\"\nmsgstr \"\"\n\"Wählen Sie eine Gruppe zum Hinzufügen oder Entfernen von Mitgliedern aus.\"\n\n#: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:1011\nmsgid \"Select a group XML file\"\nmsgstr \"Wählen Sie eine Gruppen-Datei\"\n\n#: res/xrc/GroupManager.xrc:71\nmsgid \"Groups\"\nmsgstr \"Gruppen\"\n\n#: res/xrc/GroupManager.xrc:101\nmsgid \"Add Group\"\nmsgstr \"Gruppe hinzufügen\"\n\n#: res/xrc/GroupManager.xrc:110\nmsgid \"Remove Group\"\nmsgstr \"Gruppe entfernen\"\n\n#: res/xrc/GroupManager.xrc:122\nmsgid \"Members\"\nmsgstr \"Mitglieder\"\n\n#: res/xrc/GroupManager.xrc:137\nmsgid \"Remove >>\"\nmsgstr \"Entfernen >>\"\n\n#: res/xrc/GroupManager.xrc:151\nmsgid \"Outfits\"\nmsgstr \"Outfits\"\n\n#: res/xrc/GroupManager.xrc:172\nmsgid \"<< Add\"\nmsgstr \"<< Hinzufügen\"\n\n#: res/xrc/ImportDialog.xrc:5\nmsgid \"Import Options...\"\nmsgstr \"Import Optionen...\"\n\n#: res/xrc/ImportDialog.xrc:53\nmsgid \"Invert U\"\nmsgstr \"U invertieren\"\n\n#: res/xrc/ImportDialog.xrc:62\nmsgid \"Invert V\"\nmsgstr \"V invertieren\"\n\n#: res/xrc/ImportDialog.xrc:89\nmsgid \"Rotate (X)\"\nmsgstr \"Rotieren (X)\"\n\n#: res/xrc/ImportDialog.xrc:98\nmsgid \"Choose X rotation.\"\nmsgstr \"X-Rotation wählen.\"\n\n#: res/xrc/ImportDialog.xrc:113\nmsgid \"Rotate (Y)\"\nmsgstr \"Rotieren (Y)\"\n\n#: res/xrc/ImportDialog.xrc:122\nmsgid \"Choose Y rotation.\"\nmsgstr \"Y-Rotation wählen.\"\n\n#: res/xrc/ImportDialog.xrc:137\nmsgid \"Rotate (Z)\"\nmsgstr \"Rotieren (Z)\"\n\n#: res/xrc/ImportDialog.xrc:146\nmsgid \"Choose Z rotation.\"\nmsgstr \"Z-Rotation wählen.\"\n\n#: res/xrc/NormalsGenDlg.xrc:6\nmsgid \"Normal Map Generator\"\nmsgstr \"Normal Map Generator\"\n\n#: res/xrc/NormalsGenDlg.xrc:21\nmsgid \"Layers\"\nmsgstr \"Schichten\"\n\n#: res/xrc/NormalsGenDlg.xrc:37\nmsgid \"Load or save preset layer settings.\"\nmsgstr \"Schichteneinstellungen laden oder speichern.\"\n\n#: res/xrc/NormalsGenDlg.xrc:61\nmsgid \"Add a new layer after the current one in the layer list.\"\nmsgstr \"\"\n\"Fügt eine neue Schicht nach der aktuell in der Liste ausgewählten hinzu.\"\n\n#: res/xrc/NormalsGenDlg.xrc:62\nmsgid \"Add Layer\"\nmsgstr \"Schicht hinzufügen\"\n\n#: res/xrc/NormalsGenDlg.xrc:71\nmsgid \"Move selected layer up one position.\"\nmsgstr \"Bewegt die ausgewählte Schicht um eins nach oben.\"\n\n#: res/xrc/NormalsGenDlg.xrc:72\nmsgid \"Move Up\"\nmsgstr \"Nach oben\"\n\n#: res/xrc/NormalsGenDlg.xrc:87\nmsgid \"Delete the selected layer.\"\nmsgstr \"Die ausgewählte Schicht löschen.\"\n\n#: res/xrc/NormalsGenDlg.xrc:88\nmsgid \"Delete Layer\"\nmsgstr \"Schicht löschen\"\n\n#: res/xrc/NormalsGenDlg.xrc:114\nmsgid \"\"\n\"Save a copy of an existing normal map if one already exists. File is saved \"\n\"in the original directory.\"\nmsgstr \"\"\n\"Speichert eine Kopie einer existierenden Normal Map, wenn bereits eine \"\n\"existiert. Die Datei wird im selben Verzeichnis gespeichert.\"\n\n#: res/xrc/NormalsGenDlg.xrc:115\nmsgid \"Backup destination file\"\nmsgstr \"Zieldatei sichern\"\n\n#: res/xrc/NormalsGenDlg.xrc:124\nmsgid \"\"\n\"Compress output file using BC7 compression. This can make saving the file \"\n\"take a VERY long time!\"\nmsgstr \"\"\n\"Ausgabedatei mit BC7 kompromieren. Dies kann die Speicherzeit um einiges \"\n\"erhöhen!\"\n\n#: res/xrc/NormalsGenDlg.xrc:125\nmsgid \"Compress output \"\nmsgstr \"Ausgabe komprimieren \"\n\n#: res/xrc/NormalsGenDlg.xrc:134\nmsgid \"\"\n\"Use the file name specified in the background layer to save the normal map.\"\nmsgstr \"\"\n\"Verwende zum Speichern der Normal Map den Dateinamen, der in der \"\n\"Hintergrundschicht angegeben wurde.\"\n\n#: res/xrc/NormalsGenDlg.xrc:135\nmsgid \"Save to background layer file\"\nmsgstr \"Zur Hintergrund-Datei speichern\"\n\n#: res/xrc/NormalsGenDlg.xrc:145\nmsgid \"Choose an output file...\"\nmsgstr \"Ausgabedatei auswählen...\"\n\n#: res/xrc/NormalsGenDlg.xrc:149\nmsgid \"Location to save normal map to.\"\nmsgstr \"Pfad zum Speichern der Normal Map.\"\n\n#: res/xrc/NormalsGenDlg.xrc:165\nmsgid \"Display current settings on mesh in preview window.\"\nmsgstr \"Zeige die aktuellen Einstellungen auf dem Modell in der Vorschau.\"\n\n#: res/xrc/NormalsGenDlg.xrc:181\nmsgid \"Generate and save the normal map file.\"\nmsgstr \"Normal Map-Datei generieren und abspeichern.\"\n\n#: res/xrc/NormalsGenDlg.xrc:182\nmsgid \"Generate\"\nmsgstr \"Generieren\"\n\n#: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2017\nmsgid \"Load Preset...\"\nmsgstr \"Preset laden...\"\n\n#: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2021\nmsgid \"Save Preset...\"\nmsgstr \"Preset speichern...\"\n\n#: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5\nmsgid \"New Project\"\nmsgstr \"Neues Projekte\"\n\n#: res/xrc/OutfitStudio.xrc:23\nmsgid \"\"\n\"Create a new project by selecting a reference body slider set, and outfit \"\n\"model files.\"\nmsgstr \"\"\n\"Erstellt ein neues Projekt durch auswählen einer Referenz und eines Outfit \"\n\"Modells.\"\n\n#: res/xrc/OutfitStudio.xrc:28\nmsgid \"Load Project\"\nmsgstr \"Projekt laden\"\n\n#: res/xrc/OutfitStudio.xrc:29\nmsgid \"Load a previously created slider set for editing.\"\nmsgstr \"Läd ein zuvor erstelltes Set zur Bearbeitung.\"\n\n#: res/xrc/OutfitStudio.xrc:34\nmsgid \"Undo\"\nmsgstr \"Rückgängig\"\n\n#: res/xrc/OutfitStudio.xrc:35\nmsgid \"Undo a previous action.\"\nmsgstr \"Macht die letzte Aktion rückgängig.\"\n\n#: res/xrc/OutfitStudio.xrc:41\nmsgid \"Redo\"\nmsgstr \"Wiederherstellen\"\n\n#: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2135\nmsgid \"Select\"\nmsgstr \"Auswählen\"\n\n#: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2136\nmsgid \"Navigate and select meshes (or vertices in vertex mode).\"\nmsgstr \"\"\n\"Navigiert durch Modelle und wählt sie aus (oder Vertices im Vertexmodus).\"\n\n#: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2140\n#: src/program/NormalsGenDialog.cpp:291\nmsgid \"Mask\"\nmsgstr \"Maskieren\"\n\n#: res/xrc/OutfitStudio.xrc:58 res/xrc/OutfitStudio.xrc:2141\nmsgid \"\"\n\"Mask vertices to prevent them from being transformed.\\n\"\n\"Hold down the ALT key to remove masking.\"\nmsgstr \"\"\n\"Maskiert Vertices, um zu verhindern, dass sie transformiert werden.\\n\"\n\"ALT gedrückt halten, um Maskierungen zu entfernen.\"\n\n#: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2145\nmsgid \"Inflate\"\nmsgstr \"Vergrößern\"\n\n#: res/xrc/OutfitStudio.xrc:65 res/xrc/OutfitStudio.xrc:2146\nmsgid \"Increase mesh volume in an area.\"\nmsgstr \"Vergrößert das Meshvolumen im Bereich.\"\n\n#: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2151\nmsgid \"Deflate\"\nmsgstr \"Reduzieren\"\n\n#: res/xrc/OutfitStudio.xrc:72 res/xrc/OutfitStudio.xrc:2152\nmsgid \"Decrease mesh volume in an area.\"\nmsgstr \"Reduziert das Meshvolumen im Bereich.\"\n\n#: res/xrc/OutfitStudio.xrc:79 res/xrc/OutfitStudio.xrc:2157\nmsgid \"Move vertices over a plane parallel to the view.\"\nmsgstr \"Bewegt Vertices auf einer Ebene parallel zur Blickrichtung.\"\n\n#: res/xrc/OutfitStudio.xrc:85 res/xrc/OutfitStudio.xrc:2161\nmsgid \"Smooth\"\nmsgstr \"Glätten\"\n\n#: res/xrc/OutfitStudio.xrc:86 res/xrc/OutfitStudio.xrc:2162\nmsgid \"Smooth an area of a mesh.\"\nmsgstr \"Glättet einen Bereich eines Meshes.\"\n\n#: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2166\nmsgid \"Undiff\"\nmsgstr \"Undiff\"\n\n#: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2167\nmsgid \"Undiff an area of a slider.\"\nmsgstr \"Entfernt Slider-Daten eines Bereichs.\"\n\n#: res/xrc/OutfitStudio.xrc:99 res/xrc/OutfitStudio.xrc:2171\nmsgid \"Weight Paint\"\nmsgstr \"Weight Pinsel\"\n\n#: res/xrc/OutfitStudio.xrc:100\nmsgid \"\"\n\"Apply animation weight values for currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"Wendet Animations-Weighting für den derzeit gewählten Bone an.\\n\"\n\"ALT gedrückt halten, um das Weighting abzuschwächen.\"\n\n#: res/xrc/OutfitStudio.xrc:107 res/xrc/OutfitStudio.xrc:2177\nmsgid \"Color Paint\"\nmsgstr \"Farbe\"\n\n#: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2178\nmsgid \"\"\n\"Apply vertex colors.\\n\"\n\"Hold down the ALT key to remove colors.\"\nmsgstr \"Vertexfarben anwenden. ALT gedrückt halten zum Entfernen.\"\n\n#: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2183\nmsgid \"Alpha Paint\"\nmsgstr \"Alpha\"\n\n#: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2184\nmsgid \"\"\n\"Apply vertex alpha.\\n\"\n\"Hold down the ALT key to remove alpha.\"\nmsgstr \"Vertex Alpha anwenden. ALT gedrückt halten zum Entfernen.\"\n\n#: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2189\nmsgid \"Collapse Vertex\"\nmsgstr \"Collapse Vertex\"\n\n#: res/xrc/OutfitStudio.xrc:124 res/xrc/OutfitStudio.xrc:2190\nmsgid \"\"\n\"Deletes vertices with no more than three connections, without creating a \"\n\"hole.\"\nmsgstr \"\"\n\"Entfernt Vertices mit nicht mehr als drei Verbindungen ohne ein Loch dabei \"\n\"zu erzeugen.\"\n\n#: res/xrc/OutfitStudio.xrc:130 res/xrc/OutfitStudio.xrc:2194\nmsgid \"Flip Edge\"\nmsgstr \"Kante umkehren\"\n\n#: res/xrc/OutfitStudio.xrc:131 res/xrc/OutfitStudio.xrc:2195\nmsgid \"Flips mesh edges so that the opposite pair of vertices is connected.\"\nmsgstr \"\"\n\"Kehrt Kanten um, sodass das gegenüberliegende Paar an Vertices verbunden \"\n\"wird.\"\n\n#: res/xrc/OutfitStudio.xrc:137 res/xrc/OutfitStudio.xrc:2199\nmsgid \"Split Edge\"\nmsgstr \"Kante aufteilen\"\n\n#: res/xrc/OutfitStudio.xrc:138 res/xrc/OutfitStudio.xrc:2200\nmsgid \"Splits a mesh edge in two with a new vertex.\"\nmsgstr \"Teilt eine Kante mit einem neuen Vertex in zwei.\"\n\n#: res/xrc/OutfitStudio.xrc:144 res/xrc/OutfitStudio.xrc:2204\nmsgid \"Move Vertex\"\nmsgstr \"Vertex bewegen\"\n\n#: res/xrc/OutfitStudio.xrc:145 res/xrc/OutfitStudio.xrc:2205\nmsgid \"Moves a vertex.\"\nmsgstr \"Bewegt ein Vertex.\"\n\n#: res/xrc/OutfitStudio.xrc:155\nmsgid \"Field of View\"\nmsgstr \"Sichtfeld\"\n\n#: res/xrc/OutfitStudio.xrc:159\nmsgid \"Field of View: 65\"\nmsgstr \"Sichtfeld: 65\"\n\n#: res/xrc/OutfitStudio.xrc:164\nmsgid \"Brush Settings\"\nmsgstr \"Pinseleinstellungen\"\n\n#: res/xrc/OutfitStudio.xrc:169\nmsgid \"Open Discord invite link.\"\nmsgstr \"Discord Einladungslink öffnen.\"\n\n#: res/xrc/OutfitStudio.xrc:174\nmsgid \"Open GitHub link.\"\nmsgstr \"GitHub-Link öffnen.\"\n\n#: res/xrc/OutfitStudio.xrc:179\nmsgid \"Open PayPal link.\"\nmsgstr \"PayPal-Link öffnen.\"\n\n#: res/xrc/OutfitStudio.xrc:200\nmsgid \"Transform\"\nmsgstr \"Transformieren\"\n\n#: res/xrc/OutfitStudio.xrc:201 res/xrc/OutfitStudio.xrc:2211\nmsgid \"Shows a transform tool to manipulate shapes and vertices with.\"\nmsgstr \"\"\n\"Zeigt ein Transformierwerkzeug an, mit welchem Modelle und Vertices \"\n\"manipuliert werden können.\"\n\n#: res/xrc/OutfitStudio.xrc:207\nmsgid \"Pivot\"\nmsgstr \"Pivot\"\n\n#: res/xrc/OutfitStudio.xrc:208 res/xrc/OutfitStudio.xrc:2216\nmsgid \"\"\n\"Shows a pivot that can be moved and makes it the center of mesh operations \"\n\"like rotation and scale.\"\nmsgstr \"\"\n\"Zeigt einen verschiebbaren Pivot an und macht diesen das Zentrum von \"\n\"Modelloperationen wie das Rotieren oder Skalieren.\"\n\n#: res/xrc/OutfitStudio.xrc:214\nmsgid \"Vertex Edit\"\nmsgstr \"Vertex Bearbeitung\"\n\n#: res/xrc/OutfitStudio.xrc:215\nmsgid \"\"\n\"Lets you select vertices to add to or remove from the mask.\\n\"\n\"Click on a vertex to select/unmask it.\\n\"\n\"Hold down CTRL to unselect/mask it.\"\nmsgstr \"\"\n\"Hier können Sie Vertices auswählen, die der Maske hinzugefügt oder daraus \"\n\"entfernt werden sollen.\\n\"\n\"Klicken Sie auf einen Vertex, um ihn auszuwählen/zu demaskieren.\\n\"\n\"Halten Sie die STRG gedrückt zum maskieren.\"\n\n#: res/xrc/OutfitStudio.xrc:222\nmsgid \"View Front\"\nmsgstr \"Vorderansicht\"\n\n#: res/xrc/OutfitStudio.xrc:223\nmsgid \"Change camera view to the front.\"\nmsgstr \"Ändert die Kameraansicht nach vorne.\"\n\n#: res/xrc/OutfitStudio.xrc:227\nmsgid \"View Back\"\nmsgstr \"Hinteransicht\"\n\n#: res/xrc/OutfitStudio.xrc:228\nmsgid \"Change camera view to the back.\"\nmsgstr \"Ändert die Kameraansicht nach hinten.\"\n\n#: res/xrc/OutfitStudio.xrc:232\nmsgid \"View Left\"\nmsgstr \"Linksansicht\"\n\n#: res/xrc/OutfitStudio.xrc:233\nmsgid \"Change camera view to the left.\"\nmsgstr \"Ändert die Kameraansicht nach links.\"\n\n#: res/xrc/OutfitStudio.xrc:237\nmsgid \"View Right\"\nmsgstr \"Rechtsansicht\"\n\n#: res/xrc/OutfitStudio.xrc:238\nmsgid \"Change camera view to the right.\"\nmsgstr \"Ändert die Kameraansicht nach rechts.\"\n\n#: res/xrc/OutfitStudio.xrc:242 res/xrc/Settings.xrc:294\nmsgid \"Perspective View\"\nmsgstr \"Perspektivische Ansicht\"\n\n#: res/xrc/OutfitStudio.xrc:243\nmsgid \"Toggle perspective view.\"\nmsgstr \"Perspektivische Ansicht umschalten.\"\n\n#: res/xrc/OutfitStudio.xrc:249\nmsgid \"Show Nodes\"\nmsgstr \"Knoten anzeigen\"\n\n#: res/xrc/OutfitStudio.xrc:250\nmsgid \"Toggle rendering of nodes.\"\nmsgstr \"Knotenansicht umschalten.\"\n\n#: res/xrc/OutfitStudio.xrc:255\nmsgid \"Show Bones\"\nmsgstr \"Bones anzeigen\"\n\n#: res/xrc/OutfitStudio.xrc:256\nmsgid \"Toggle rendering of bones.\"\nmsgstr \"Bones-Ansicht umschalten.\"\n\n#: res/xrc/OutfitStudio.xrc:261\nmsgid \"Show Floor\"\nmsgstr \"Boden anzeigen\"\n\n#: res/xrc/OutfitStudio.xrc:262\nmsgid \"Toggle rendering of the floor grid.\"\nmsgstr \"Bodengitter umschalten.\"\n\n#: res/xrc/OutfitStudio.xrc:268\nmsgid \"X Mirror\"\nmsgstr \"X-Spiegelung\"\n\n#: res/xrc/OutfitStudio.xrc:269 res/xrc/OutfitStudio.xrc:1775\nmsgid \"Mirror edits across the X axis.\"\nmsgstr \"Spiegelt die Änderungen auf der X-Achse.\"\n\n#: res/xrc/OutfitStudio.xrc:276 res/xrc/OutfitStudio.xrc:1781\nmsgid \"Edit Connected Only\\tC\"\nmsgstr \"Nur Verbundenes bearbeiten\\tC\"\n\n#: res/xrc/OutfitStudio.xrc:277\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius.\"\nmsgstr \"\"\n\"Bearbeitet nur Vertices, die mit denen verbunden sind, die der Pinselradius \"\n\"erreicht.\"\n\n#: res/xrc/OutfitStudio.xrc:283 res/xrc/OutfitStudio.xrc:1788\nmsgid \"Merge Vertex\"\nmsgstr \"Vertex verschmelzen\"\n\n#: res/xrc/OutfitStudio.xrc:284 res/xrc/OutfitStudio.xrc:1789\nmsgid \"Merges two vertices and fills any gaps.\"\nmsgstr \"Verschmilzt zwei Vertices und füllt jegliche Lücken.\"\n\n#: res/xrc/OutfitStudio.xrc:290 res/xrc/OutfitStudio.xrc:1795\nmsgid \"Weld Vertex\"\nmsgstr \"Vertex angleichen\"\n\n#: res/xrc/OutfitStudio.xrc:291 res/xrc/OutfitStudio.xrc:1796\nmsgid \"Welds two vertices while keeping the texture coordinates (UV) distinct.\"\nmsgstr \"\"\n\"Gleicht zwei Vertices an, aber behält getrennte Texturkoordinaten (UV).\"\n\n#: res/xrc/OutfitStudio.xrc:297 res/xrc/OutfitStudio.xrc:1802\nmsgid \"Restrict To Surface\"\nmsgstr \"Auf Oberfläche beschränken\"\n\n#: res/xrc/OutfitStudio.xrc:298 res/xrc/OutfitStudio.xrc:1803\nmsgid \"Restricts motion to a mesh surface.\"\nmsgstr \"Beschränkt Bewegung auf eine Modelloberfläche.\"\n\n#: res/xrc/OutfitStudio.xrc:304 res/xrc/OutfitStudio.xrc:1809\nmsgid \"Restrict To Plane\"\nmsgstr \"Auf Ebene beschränken\"\n\n#: res/xrc/OutfitStudio.xrc:305 res/xrc/OutfitStudio.xrc:1810\nmsgid \"Restricts motion to parallel to the surface.\"\nmsgstr \"Beschränkt Bewegung auf parallel zur Oberfläche.\"\n\n#: res/xrc/OutfitStudio.xrc:311 res/xrc/OutfitStudio.xrc:1816\nmsgid \"Restrict To Normal\"\nmsgstr \"Auf Normal beschränken\"\n\n#: res/xrc/OutfitStudio.xrc:312 res/xrc/OutfitStudio.xrc:1817\nmsgid \"Restricts motion to perpendicular to the surface.\"\nmsgstr \"Beschränkt Bewegung auf aufrecht zur Oberfläche.\"\n\n#: res/xrc/OutfitStudio.xrc:375\nmsgid \"Meshes\"\nmsgstr \"Modelle\"\n\n#: res/xrc/OutfitStudio.xrc:399 res/xrc/OutfitStudio.xrc:2519\n#: res/xrc/OutfitStudio.xrc:2545\nmsgid \"Segments\"\nmsgstr \"Segmente\"\n\n#: res/xrc/OutfitStudio.xrc:411 res/xrc/OutfitStudio.xrc:2552\n#: res/xrc/OutfitStudio.xrc:2563\nmsgid \"Partitions\"\nmsgstr \"Partitionen\"\n\n#: res/xrc/OutfitStudio.xrc:423\nmsgid \"Colors\"\nmsgstr \"Farben\"\n\n#: res/xrc/OutfitStudio.xrc:435\nmsgid \"Lights\"\nmsgstr \"Beleuchtung\"\n\n#: res/xrc/OutfitStudio.xrc:475\nmsgid \"Total Bones: 0\"\nmsgstr \"Bones insgesamt: 0\"\n\n#: res/xrc/OutfitStudio.xrc:485\nmsgid \"Shape Selection Bones: 0\"\nmsgstr \"Bones Modellauswahl: 0\"\n\n#: res/xrc/OutfitStudio.xrc:515\nmsgid \"Brush Color\"\nmsgstr \"Pinselfarbe\"\n\n#: res/xrc/OutfitStudio.xrc:524\nmsgid \"Color of the brush.\"\nmsgstr \"Farbe des Pinsels.\"\n\n#: res/xrc/OutfitStudio.xrc:546\nmsgid \"Clamp Max Value\"\nmsgstr \"Maximalwert\"\n\n#: res/xrc/OutfitStudio.xrc:589 src/program/OutfitStudio.cpp:3173\n#: src/program/OutfitStudio.cpp:6817\nmsgid \"Edit Alpha\"\nmsgstr \"Alpha bearbeiten\"\n\n#: res/xrc/OutfitStudio.xrc:635 res/xrc/OutfitStudio.xrc:1039\n#: res/xrc/OutfitStudio.xrc:1140 src/program/OutfitStudio.cpp:6531\n#: src/program/OutfitStudio.cpp:11359 src/ui/wxBrushSettingsPopup.cpp:186\nmsgid \"Reset\"\nmsgstr \"Zurücksetzen\"\n\n#: res/xrc/OutfitStudio.xrc:648\nmsgid \"Ambient\"\nmsgstr \"Umgebung\"\n\n#: res/xrc/OutfitStudio.xrc:673\nmsgid \"Frontal\"\nmsgstr \"Frontal\"\n\n#: res/xrc/OutfitStudio.xrc:698\nmsgid \"Directional 1\"\nmsgstr \"Richtung 1\"\n\n#: res/xrc/OutfitStudio.xrc:723\nmsgid \"Directional 2\"\nmsgstr \"Richtung 2\"\n\n#: res/xrc/OutfitStudio.xrc:748\nmsgid \"Directional 3\"\nmsgstr \"Richtung 3\"\n\n#: res/xrc/OutfitStudio.xrc:916\nmsgid \"Slot\"\nmsgstr \"Slot\"\n\n#: res/xrc/OutfitStudio.xrc:991 src/program/OutfitStudio.cpp:5601\nmsgid \"SSF File\"\nmsgstr \"SSF-Datei\"\n\n#: res/xrc/OutfitStudio.xrc:1011\nmsgid \"Set\"\nmsgstr \"Setzen\"\n\n#: res/xrc/OutfitStudio.xrc:1029 res/xrc/OutfitStudio.xrc:1130\n#: src/program/OutfitStudio.cpp:6531\nmsgid \"Apply\"\nmsgstr \"Anwenden\"\n\n#: res/xrc/OutfitStudio.xrc:1158\nmsgid \"De-/Select Sliders\"\nmsgstr \"Slider ab-/anwählen\"\n\n#: res/xrc/OutfitStudio.xrc:1177\nmsgid \"Fixed Weight Brush\"\nmsgstr \"Fixierte Pinselstärke\"\n\n#: res/xrc/OutfitStudio.xrc:1188\nmsgid \"Normalize Weights\"\nmsgstr \"Weights normalisieren\"\n\n#: res/xrc/OutfitStudio.xrc:1205\nmsgid \"X-Mirror Bone\"\nmsgstr \"Bone spiegeln\"\n\n#: res/xrc/OutfitStudio.xrc:1230\nmsgid \"Masks\"\nmsgstr \"Masken\"\n\n#: res/xrc/OutfitStudio.xrc:1275 res/xrc/OutfitStudio.xrc:1336\n#: res/xrc/OutfitStudio.xrc:2485\nmsgid \"Delete\"\nmsgstr \"Entfernen\"\n\n#: res/xrc/OutfitStudio.xrc:1291\nmsgid \"Posing\"\nmsgstr \"Posen\"\n\n#: res/xrc/OutfitStudio.xrc:1352\nmsgid \"Show Pose\"\nmsgstr \"Pose anzeigen\"\n\n#: res/xrc/OutfitStudio.xrc:1370\nmsgid \"Reset Bone\"\nmsgstr \"Bone zurücksetzen\"\n\n#: res/xrc/OutfitStudio.xrc:1390\nmsgid \"Rotation X\"\nmsgstr \"Rotation X\"\n\n#: res/xrc/OutfitStudio.xrc:1418\nmsgid \"Rotation Y\"\nmsgstr \"Rotation Y\"\n\n#: res/xrc/OutfitStudio.xrc:1446\nmsgid \"Rotation Z\"\nmsgstr \"Rotation Z\"\n\n#: res/xrc/OutfitStudio.xrc:1474\nmsgid \"Offset X\"\nmsgstr \"X-Verschiebung\"\n\n#: res/xrc/OutfitStudio.xrc:1502\nmsgid \"Offset Y\"\nmsgstr \"Y-Verschiebung\"\n\n#: res/xrc/OutfitStudio.xrc:1530\nmsgid \"Offset Z\"\nmsgstr \"Z-Verschiebung\"\n\n#: res/xrc/OutfitStudio.xrc:1592\nmsgid \"Reset All\"\nmsgstr \"Alle zurücksetzen\"\n\n#: res/xrc/OutfitStudio.xrc:1600\nmsgid \"Apply to Mesh\"\nmsgstr \"Auf Modell anwenden\"\n\n#: res/xrc/OutfitStudio.xrc:1642 res/xrc/Settings.xrc:392\n#: src/program/NormalsGenDialog.cpp:284\nmsgid \"File\"\nmsgstr \"Datei\"\n\n#: res/xrc/OutfitStudio.xrc:1644\nmsgid \"New Project...\\tCtrl+N\"\nmsgstr \"Neues Projekt...\\tCtrl+N\"\n\n#: res/xrc/OutfitStudio.xrc:1645\nmsgid \"Create a new outfit project.\"\nmsgstr \"Erstellt ein neues Outfit Projekt.\"\n\n#: res/xrc/OutfitStudio.xrc:1648\nmsgid \"Load Project..\\tCtrl+O\"\nmsgstr \"Projekt laden..\\tCtrl+O\"\n\n#: res/xrc/OutfitStudio.xrc:1649\nmsgid \"Load a project.\"\nmsgstr \"Läd ein existierendes Projekt.\"\n\n#: res/xrc/OutfitStudio.xrc:1652\nmsgid \"Add Project..\\tCtrl+Shift+O\"\nmsgstr \"Projekt hinzufügen..\\tCtrl+Shift+O\"\n\n#: res/xrc/OutfitStudio.xrc:1653\nmsgid \"Add a project without replacing the current one.\"\nmsgstr \"Fügt ein Projekt hinzu, ohne das aktuelle zu ersetzen.\"\n\n#: res/xrc/OutfitStudio.xrc:1656\nmsgid \"Unload Project...\\tCtrl+W\"\nmsgstr \"Projekt entladen...\\tCtrl+W\"\n\n#: res/xrc/OutfitStudio.xrc:1657\nmsgid \"Unloads the project and creates an empty new one.\"\nmsgstr \"Entläd das Projekt und erstellt ein leeres neues.\"\n\n#: res/xrc/OutfitStudio.xrc:1660\nmsgid \"Recent Projects...\"\nmsgstr \"Zuletzt verwendete Projekte...\"\n\n#: res/xrc/OutfitStudio.xrc:1665\nmsgid \"Load Reference...\"\nmsgstr \"Referenz laden...\"\n\n#: res/xrc/OutfitStudio.xrc:1666\nmsgid \"\"\n\"Load a new reference slider set, replacing any current reference objects.\"\nmsgstr \"Läd ein neues Referenzset. Ersetzt alle aktuellen Referenzobjekte.\"\n\n#: res/xrc/OutfitStudio.xrc:1669\nmsgid \"Load Outfit...\"\nmsgstr \"Outfit laden...\"\n\n#: res/xrc/OutfitStudio.xrc:1670\nmsgid \"\"\n\"Load a NIF file as the working outfit, replacing any current outfit objects.\"\nmsgstr \"\"\n\"Läd eine NIF-Datei als Arbeitsoutfit. Ersetzt alle aktuellen Outfit Objekte.\"\n\n#: res/xrc/OutfitStudio.xrc:1674\nmsgid \"Convert / Replace Reference...\\tCtrl+Shift+R\"\nmsgstr \"Referenz konvertieren / ersetzen...\\tCtrl+Shift+R\"\n\n#: res/xrc/OutfitStudio.xrc:1675\nmsgid \"Convert to or replace an outfit's body/reference\"\nmsgstr \"Referenz/Körper konvertieren oder ersetzen\"\n\n#: res/xrc/OutfitStudio.xrc:1679\nmsgid \"Save Project\\tCtrl+S\"\nmsgstr \"Projekt speichern\\tCtrl+S\"\n\n#: res/xrc/OutfitStudio.xrc:1680\nmsgid \"Save the project.\"\nmsgstr \"Speichert das Projekt.\"\n\n#: res/xrc/OutfitStudio.xrc:1684\nmsgid \"Save Project As...\\tCtrl+Shift+S\"\nmsgstr \"Projekt speichern unter...\\tCtrl+Shift+S\"\n\n#: res/xrc/OutfitStudio.xrc:1685\nmsgid \"Save the project under a new name.\"\nmsgstr \"Speichert das Projekt unter einem neuen Namen.\"\n\n#: res/xrc/OutfitStudio.xrc:1689 src/program/OutfitStudio.cpp:7392\n#: src/program/OutfitStudio.cpp:7502 src/program/OutfitStudio.cpp:7628\nmsgid \"Import\"\nmsgstr \"Import\"\n\n#: res/xrc/OutfitStudio.xrc:1691\nmsgid \"From NIF...\"\nmsgstr \"Aus NIF...\"\n\n#: res/xrc/OutfitStudio.xrc:1692\nmsgid \"Choose a NIF file to import into the project.\"\nmsgstr \"Wählen Sie eine NIF-Datei, die dem Projekt hinzugefügt werden soll.\"\n\n#: res/xrc/OutfitStudio.xrc:1695\nmsgid \"From OBJ...\"\nmsgstr \"Aus OBJ...\"\n\n#: res/xrc/OutfitStudio.xrc:1696\nmsgid \"Import an OBJ file as a new shape in the outfit.\"\nmsgstr \"Importiert eine OBJ-Datei als neues Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:1699\nmsgid \"From FBX...\"\nmsgstr \"Aus FBX...\"\n\n#: res/xrc/OutfitStudio.xrc:1700\nmsgid \"Import an FBX file as a new shape in the outfit.\"\nmsgstr \"Importiert eine FBX-Datei als neues Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:1703\nmsgid \"From TRI (Head)...\"\nmsgstr \"Aus TRI (Kopf)...\"\n\n#: res/xrc/OutfitStudio.xrc:1704\nmsgid \"Import shape and morphs from a head TRI file.\"\nmsgstr \"Importiert Modell und Morphs aus einer (Kopf) TRI-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1707\nmsgid \"Import Data\"\nmsgstr \"Daten importieren\"\n\n#: res/xrc/OutfitStudio.xrc:1709\nmsgid \"Import BSClothExtraData From HKX\"\nmsgstr \"BSClothExtraData aus HKX importieren\"\n\n#: res/xrc/OutfitStudio.xrc:1710\nmsgid \"\"\n\"Choose an HKX file to import as a BSClothExtraData block into the project.\"\nmsgstr \"Wählen Sie eine HKX-Datei zum Importieren als BSClothExtraData-Block.\"\n\n#: res/xrc/OutfitStudio.xrc:1715 res/xrc/OutfitStudio.xrc:1849\n#: res/xrc/OutfitStudio.xrc:2329\nmsgid \"Export\"\nmsgstr \"Export\"\n\n#: res/xrc/OutfitStudio.xrc:1717\nmsgid \"To NIF...\\tCtrl+E\"\nmsgstr \"Als NIF...\\tCtrl+E\"\n\n#: res/xrc/OutfitStudio.xrc:1718\nmsgid \"Save the current project as a NIF file (without reference)\"\nmsgstr \"Speichert das aktuelle Projekt als NIF-Datei (ohne Referenz)\"\n\n#: res/xrc/OutfitStudio.xrc:1721\nmsgid \"To NIF With Reference...\\tCtrl+Alt+E\"\nmsgstr \"Als NIF mit Referenz...\\tCtrl+Alt+E\"\n\n#: res/xrc/OutfitStudio.xrc:1722\nmsgid \"Save the current project as a NIF file (including reference)\"\nmsgstr \"Speichert das aktuelle Projekt als NIF-Datei (inklusive Referenz)\"\n\n#: res/xrc/OutfitStudio.xrc:1725 res/xrc/OutfitStudio.xrc:1855\n#: res/xrc/OutfitStudio.xrc:2335\nmsgid \"To OBJ...\"\nmsgstr \"Als OBJ...\"\n\n#: res/xrc/OutfitStudio.xrc:1726\nmsgid \"Export the current project as an OBJ file.\"\nmsgstr \"Exportiert das aktuelle Projekt als OBJ-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1729 res/xrc/OutfitStudio.xrc:1859\n#: res/xrc/OutfitStudio.xrc:2339\nmsgid \"To FBX...\"\nmsgstr \"Als FBX...\"\n\n#: res/xrc/OutfitStudio.xrc:1730\nmsgid \"Export the current project as an FBX file.\"\nmsgstr \"Exportiert das aktuelle Projekt als FBX-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1733 res/xrc/OutfitStudio.xrc:1863\n#: res/xrc/OutfitStudio.xrc:2343\nmsgid \"To TRI (Head)...\"\nmsgstr \"Als TRI (Kopf)...\"\n\n#: res/xrc/OutfitStudio.xrc:1734 res/xrc/OutfitStudio.xrc:1864\n#: res/xrc/OutfitStudio.xrc:2344\nmsgid \"Export head morphs to a TRI file.\"\nmsgstr \"Exportiert Kopf-Morphs als TRI-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1737\nmsgid \"Export Data\"\nmsgstr \"Daten exportieren\"\n\n#: res/xrc/OutfitStudio.xrc:1739\nmsgid \"Export BSClothExtraData As HKX\"\nmsgstr \"BSClothExtraData als HKX exportieren\"\n\n#: res/xrc/OutfitStudio.xrc:1740\nmsgid \"\"\n\"Save one of the currently loaded BSClothExtraData blocks to an HKX file.\"\nmsgstr \"\"\n\"Speichert einen der aktuell geladenen BSClothExtraData-Blocks als HKX-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1745\nmsgid \"Make Conversion Reference\"\nmsgstr \"Konvertierungsreferenz erstellen\"\n\n#: res/xrc/OutfitStudio.xrc:1746\nmsgid \"\"\n\"Using the current slider settings for the reference shape, create a new \"\n\"reference that will morph from the current shape back to the base shape.\"\nmsgstr \"\"\n\"Mithilfe der aktuellen Sliderwerte wird eine neue Referenz erstellt, die \"\n\"sich von der aktuellen Form zurück zur Basisform bewegt.\"\n\n#: res/xrc/OutfitStudio.xrc:1750 res/xrc/Project.xrc:967\nmsgid \"Pack Projects...\"\nmsgstr \"Projekte packen...\"\n\n#: res/xrc/OutfitStudio.xrc:1751\nmsgid \"Pack one or more projects into a folder or archive for sharing.\"\nmsgstr \"Projekte in einen Ordner oder ein Archiv packen.\"\n\n#: res/xrc/OutfitStudio.xrc:1758\nmsgid \"Exit\\tAlt+F4\"\nmsgstr \"Beenden\\tAlt+F4\"\n\n#: res/xrc/OutfitStudio.xrc:1759\nmsgid \"Exit Outfit Studio.\"\nmsgstr \"Outfit Studio beenden.\"\n\n#: res/xrc/OutfitStudio.xrc:1774\nmsgid \"X Mirror\\tX\"\nmsgstr \"X-Spiegelung\\tX\"\n\n#: res/xrc/OutfitStudio.xrc:1782\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius\"\nmsgstr \"\"\n\"Bearbeitet nur Vertices, die mit denen verbunden sind, die der Pinselradius \"\n\"erreicht\"\n\n#: res/xrc/OutfitStudio.xrc:1824\nmsgid \"Recalculate Normals\"\nmsgstr \"Normals neu berechnen\"\n\n#: res/xrc/OutfitStudio.xrc:1825\nmsgid \"Recalculate normals on active mesh\"\nmsgstr \"Berechnet die Normals des aktiven Meshes neu\"\n\n#: res/xrc/OutfitStudio.xrc:1828\nmsgid \"Disable Normals Calculation\"\nmsgstr \"Normals-Aktualisierung deaktivieren\"\n\n#: res/xrc/OutfitStudio.xrc:1829\nmsgid \"\"\n\"Turn off all automatic recalculation of normals on all meshes. Only applies \"\n\"to Outfit Studio.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1834\nmsgid \"Reset Transforms\"\nmsgstr \"Transforms zurücksetzen\"\n\n#: res/xrc/OutfitStudio.xrc:1835\nmsgid \"Resets the shape and skin transforms.\"\nmsgstr \"Setzt Modell- und Skinning-Transforms zurück.\"\n\n#: res/xrc/OutfitStudio.xrc:1838 src/program/OutfitStudio.cpp:10876\nmsgid \"Delete Unreferenced Nodes\"\nmsgstr \"Unreferenzierte Nodes entfernen\"\n\n#: res/xrc/OutfitStudio.xrc:1839\nmsgid \"Deletes all nodes from the project that aren't used in any other block.\"\nmsgstr \"\"\n\"Entfernt alle Nodes des Projekts, die nicht in keinem anderen Block \"\n\"verwendet werden.\"\n\n#: res/xrc/OutfitStudio.xrc:1842\nmsgid \"Remove Skinning\"\nmsgstr \"Skinning entfernen\"\n\n#: res/xrc/OutfitStudio.xrc:1843\nmsgid \"Removes skinning of all shapes and all unused nodes.\"\nmsgstr \"Skinning aller Modelle und unverwendete Nodes entfernen.\"\n\n#: res/xrc/OutfitStudio.xrc:1847 res/xrc/OutfitStudio.xrc:2327\nmsgid \"Shape\"\nmsgstr \"Modell\"\n\n#: res/xrc/OutfitStudio.xrc:1851 res/xrc/OutfitStudio.xrc:2331\nmsgid \"To NIF...\"\nmsgstr \"Als NIF...\"\n\n#: res/xrc/OutfitStudio.xrc:1852 res/xrc/OutfitStudio.xrc:2332\nmsgid \"Export only the selected shapes to a NIF file.\"\nmsgstr \"Exportiert nur die ausgewählten Modelle als NIF-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1856 res/xrc/OutfitStudio.xrc:2336\nmsgid \"Export only the selected shapes to an OBJ file.\"\nmsgstr \"Exportiert nur die ausgewählten Modelle als OBJ-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1860 res/xrc/OutfitStudio.xrc:2340\nmsgid \"Export only the selected shapes to an FBX file.\"\nmsgstr \"Exportiert nur die ausgewählten Modelle als FBX-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:1868 res/xrc/OutfitStudio.xrc:2348\n#: res/xrc/Slider.xrc:200\nmsgid \"UV\"\nmsgstr \"UV\"\n\n#: res/xrc/OutfitStudio.xrc:1870 res/xrc/OutfitStudio.xrc:2350\nmsgid \"Edit...\"\nmsgstr \"Bearbeiten...\"\n\n#: res/xrc/OutfitStudio.xrc:1871 res/xrc/OutfitStudio.xrc:2351\nmsgid \"Edit the texture coordinates.\"\nmsgstr \"Bearbeitung der Texturkoordinaten.\"\n\n#: res/xrc/OutfitStudio.xrc:1874 res/xrc/OutfitStudio.xrc:2354\nmsgid \"Invert X\"\nmsgstr \"X umkehren\"\n\n#: res/xrc/OutfitStudio.xrc:1875 res/xrc/OutfitStudio.xrc:2355\nmsgid \"Inverts the X-axis of the texture coordinates.\"\nmsgstr \"Kehrt die X-Achse der Texturkoordinaten um.\"\n\n#: res/xrc/OutfitStudio.xrc:1878 res/xrc/OutfitStudio.xrc:2358\nmsgid \"Invert Y\"\nmsgstr \"Y umkehren\"\n\n#: res/xrc/OutfitStudio.xrc:1879 res/xrc/OutfitStudio.xrc:2359\nmsgid \"Inverts the Y-axis of the texture coordinates.\"\nmsgstr \"Kehrt die Y-Achse der Texturkoordinaten um.\"\n\n#: res/xrc/OutfitStudio.xrc:1883 res/xrc/OutfitStudio.xrc:2363\nmsgid \"Delete Vertices...\\tShift+Del\"\nmsgstr \"Vertices löschen...\\tShift+Del\"\n\n#: res/xrc/OutfitStudio.xrc:1884 res/xrc/OutfitStudio.xrc:2364\nmsgid \"Deletes all unmasked vertices of the currently selected shapes.\"\nmsgstr \"\"\n\"Löscht alle nicht maskierten Vertices des aktuell ausgewählten Modells.\"\n\n#: res/xrc/OutfitStudio.xrc:1887 res/xrc/OutfitStudio.xrc:2367\nmsgid \"Separate Vertices...\\tShift+S\"\nmsgstr \"Vertices aufteilen...\\tShift+S\"\n\n#: res/xrc/OutfitStudio.xrc:1888 res/xrc/OutfitStudio.xrc:2368\nmsgid \"Separate the current shape into two by using the mask.\"\nmsgstr \"Teilt das ausgewählte Modell mithilfe der Maske in zwei auf.\"\n\n#: res/xrc/OutfitStudio.xrc:1891 res/xrc/OutfitStudio.xrc:2371\nmsgid \"Mirror Shape...\"\nmsgstr \"Modell spiegeln...\"\n\n#: res/xrc/OutfitStudio.xrc:1892 res/xrc/OutfitStudio.xrc:2372\nmsgid \"Mirror the selected shapes on any axis.\"\nmsgstr \"Spiegelt die ausgewählten Modelle auf einer Achse.\"\n\n#: res/xrc/OutfitStudio.xrc:1895 res/xrc/OutfitStudio.xrc:2375\nmsgid \"Merge Geometry...\"\nmsgstr \"Geometrie zusammenführen...\"\n\n#: res/xrc/OutfitStudio.xrc:1896 res/xrc/OutfitStudio.xrc:2376\nmsgid \"Copies vertices and triangles from one shape to another.\"\nmsgstr \"Vertices und Triangles von einem Modell zum anderen kopieren.\"\n\n#: res/xrc/OutfitStudio.xrc:1899 res/xrc/OutfitStudio.xrc:2379\nmsgid \"Duplicate...\"\nmsgstr \"Duplizieren...\"\n\n#: res/xrc/OutfitStudio.xrc:1900 res/xrc/OutfitStudio.xrc:2380\nmsgid \"Duplicate the current shape.\"\nmsgstr \"Dupliziert das aktuelle Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:1903 res/xrc/OutfitStudio.xrc:2383\nmsgid \"Refine Mesh\"\nmsgstr \"Modell verfeinern\"\n\n#: res/xrc/OutfitStudio.xrc:1904 res/xrc/OutfitStudio.xrc:2384\nmsgid \"Splits all edges between unmasked vertices\"\nmsgstr \"Teilt alle Kanten zwischen den unmaskierten Vertices\"\n\n#: res/xrc/OutfitStudio.xrc:1907 res/xrc/OutfitStudio.xrc:2387\nmsgid \"Rename...\\tF2\"\nmsgstr \"Umbenennen...\\tF2\"\n\n#: res/xrc/OutfitStudio.xrc:1908 res/xrc/OutfitStudio.xrc:2388\nmsgid \"Change the name of the current shape.\"\nmsgstr \"Ändert den Namen des aktuellen Modells.\"\n\n#: res/xrc/OutfitStudio.xrc:1911 res/xrc/OutfitStudio.xrc:2391\nmsgid \"Set Reference\"\nmsgstr \"Referenz setzen\"\n\n#: res/xrc/OutfitStudio.xrc:1912 res/xrc/OutfitStudio.xrc:2392\nmsgid \"Turn the shape into the reference shape of the project.\"\nmsgstr \"Wandelt das Modell in ein Referenzmodell des Projekts um.\"\n\n#: res/xrc/OutfitStudio.xrc:1916 res/xrc/OutfitStudio.xrc:2396\nmsgid \"Move...\"\nmsgstr \"Verschieben...\"\n\n#: res/xrc/OutfitStudio.xrc:1917 res/xrc/OutfitStudio.xrc:2397\nmsgid \"\"\n\"Apply an offset adjustment to the mesh vertices. This permanently moves \"\n\"vertices.\"\nmsgstr \"Verschiebt die Vertices des Modells permanent.\"\n\n#: res/xrc/OutfitStudio.xrc:1920 res/xrc/OutfitStudio.xrc:2400\nmsgid \"Scale...\"\nmsgstr \"Skalieren...\"\n\n#: res/xrc/OutfitStudio.xrc:1921 res/xrc/OutfitStudio.xrc:2401\nmsgid \"Apply a scale adjustment to the shape. This permanently moves vertices.\"\nmsgstr \"Skaliert die Vertices des Modells permanent.\"\n\n#: res/xrc/OutfitStudio.xrc:1924 res/xrc/OutfitStudio.xrc:2404\nmsgid \"Rotate...\"\nmsgstr \"Rotieren...\"\n\n#: res/xrc/OutfitStudio.xrc:1925 res/xrc/OutfitStudio.xrc:2405\nmsgid \"Apply a rotation to the mesh vertices. This permanently moves vertices.\"\nmsgstr \"Rotiert die Vertices des Modells permanent.\"\n\n#: res/xrc/OutfitStudio.xrc:1928 res/xrc/OutfitStudio.xrc:2408\nmsgid \"Inflate...\"\nmsgstr \"Aufblasen...\"\n\n#: res/xrc/OutfitStudio.xrc:1929 res/xrc/OutfitStudio.xrc:2409\nmsgid \"\"\n\"Inflates/deflates a shape along its normals. This permanently moves vertices.\"\nmsgstr \"\"\n\"Aufblasen vergrößert ein Modell entlang dessen Normals. Dies beeinflusst \"\n\"Vertices permanent.\"\n\n#: res/xrc/OutfitStudio.xrc:1933\nmsgid \"Normals\"\nmsgstr \"Normals\"\n\n#: res/xrc/OutfitStudio.xrc:1935\nmsgid \"Smooth Seam Normals\"\nmsgstr \"Rand-Normals glätten\"\n\n#: res/xrc/OutfitStudio.xrc:1936\nmsgid \"\"\n\"Smooths edges of seams (usually found at texture borders), disable if this \"\n\"causes odd normals on the shape.\"\nmsgstr \"\"\n\"Glättet Kanten von Rändern (normalerweise bei Texturgrenzen). Deaktivieren \"\n\"bei seltsamen Normals.\"\n\n#: res/xrc/OutfitStudio.xrc:1941\nmsgid \"Edit Smoothing Angle...\"\nmsgstr \"Winkel für Glättung bearbeiten...\"\n\n#: res/xrc/OutfitStudio.xrc:1942\nmsgid \"\"\n\"Angle, in degrees, that controls the threshold at which normal seams are \"\n\"smoothed.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1945\nmsgid \"Lock Normals\"\nmsgstr \"Normals sperren\"\n\n#: res/xrc/OutfitStudio.xrc:1946\nmsgid \"\"\n\"Locks the mesh normals. Enable if you want to keep custom normals intact.\"\nmsgstr \"\"\n\"Sperrt die Normals des Modells. Aktivieren, wenn manuell angepasste Normals \"\n\"intakt bleiben sollen.\"\n\n#: res/xrc/OutfitStudio.xrc:1954 res/xrc/OutfitStudio.xrc:2414\nmsgid \"Copies all bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\"Kopiert das Bone Weighting des Referenzmodells auf das aktuelle Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:1957 res/xrc/OutfitStudio.xrc:2417\nmsgid \"Copy Selected Weights\"\nmsgstr \"Ausgewähltes Weighting kopieren\"\n\n#: res/xrc/OutfitStudio.xrc:1958 res/xrc/OutfitStudio.xrc:2418\nmsgid \"\"\n\"Copies selected bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\"Kopiert das ausgewählte Weighting vom Referenzmodell auf das aktuelle Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:1961 res/xrc/OutfitStudio.xrc:2421\nmsgid \"Transfer Selected Weights\"\nmsgstr \"Ausgewähltes Weighting transferieren\"\n\n#: res/xrc/OutfitStudio.xrc:1962 res/xrc/OutfitStudio.xrc:2422\nmsgid \"\"\n\"Transfers selected weights from the reference shape to the current shape. \"\n\"Requires same vertex count and order.\"\nmsgstr \"\"\n\"Transferiert das ausgewählte Weighting vom Referenzmodell auf das aktuelle \"\n\"Modell. Benötigt die selbe Anzahl und Reihenfolge an Vertices.\"\n\n#: res/xrc/OutfitStudio.xrc:1965 res/xrc/OutfitStudio.xrc:2425\n#: res/xrc/OutfitStudio.xrc:2500\nmsgid \"Mask Weighted Vertices\"\nmsgstr \"Gewichtete Vertices maskieren\"\n\n#: res/xrc/OutfitStudio.xrc:1966 res/xrc/OutfitStudio.xrc:2426\nmsgid \"\"\n\"Masks vertices with bone weights, so you can manually assign weights to \"\n\"unweighted vertices.\"\nmsgstr \"Maskiert Vertices mit Bone Weighting.\"\n\n#: res/xrc/OutfitStudio.xrc:1969\nmsgid \"Check For Bad Bones...\"\nmsgstr \"Auf mangelhafte Bones prüfen...\"\n\n#: res/xrc/OutfitStudio.xrc:1970 res/xrc/OutfitStudio.xrc:2430\nmsgid \"\"\n\"Looks for bones with inconsistencies in their transforms.  If any are found, \"\n\"a dialog is opened to give options for fixing them.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1974 res/xrc/OutfitStudio.xrc:2434\nmsgid \"Copy Partitions/Segments...\"\nmsgstr \"Partitionen/Segmente kopieren...\"\n\n#: res/xrc/OutfitStudio.xrc:1975 res/xrc/OutfitStudio.xrc:2435\nmsgid \"\"\n\"Copies partitions/segments and all triangle assignments from the reference \"\n\"shape to the current shape.\"\nmsgstr \"\"\n\"Kopiert Partitionen/Segmente und deren Triangle-Zuweisungen vom \"\n\"Referenzmodell zum ausgewählten Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:1979 res/xrc/OutfitStudio.xrc:2439\nmsgid \"Mask Symmetric Vertices...\"\nmsgstr \"Symmetrische Vertices maskieren...\"\n\n#: res/xrc/OutfitStudio.xrc:1980 res/xrc/OutfitStudio.xrc:2440\nmsgid \"\"\n\"Masks unmasked vertices that have a mirrored vertex with identical data.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1983 res/xrc/OutfitStudio.xrc:2443\nmsgid \"Symmetrize Vertices...\"\nmsgstr \"Vertices symmetrisieren...\"\n\n#: res/xrc/OutfitStudio.xrc:1984 res/xrc/OutfitStudio.xrc:2444\nmsgid \"Changes vertex data to be identical to mirrored vertices.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1987 res/xrc/OutfitStudio.xrc:2447\nmsgid \"Mask Symmetric Triangles\"\nmsgstr \"Symmetrische Triangles maskieren\"\n\n#: res/xrc/OutfitStudio.xrc:1988 res/xrc/OutfitStudio.xrc:2448\nmsgid \"Masks triangles that can be matched to a mirrored triangle.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:1992 res/xrc/OutfitStudio.xrc:2452\nmsgid \"Delete\\tDel\"\nmsgstr \"Entfernen\\tDel\"\n\n#: res/xrc/OutfitStudio.xrc:1993 res/xrc/OutfitStudio.xrc:2453\nmsgid \"Removes the currently selected shape from the outfit.\"\nmsgstr \"Entfernt das derzeit ausgewählte Modell aus dem Outfit.\"\n\n#: res/xrc/OutfitStudio.xrc:1996 res/xrc/OutfitStudio.xrc:2456\nmsgid \"Properties...\"\nmsgstr \"Eigenschaften...\"\n\n#: res/xrc/OutfitStudio.xrc:1997 res/xrc/OutfitStudio.xrc:2457\nmsgid \"\"\n\"Opens the properties dialog for shader, texture and more settings of the \"\n\"selected shape.\"\nmsgstr \"\"\n\"Öffnet das Eigenschaftenfenster für Shader, Texturen und mehr des aktuellen \"\n\"Modells.\"\n\n#: res/xrc/OutfitStudio.xrc:2001\nmsgid \"Slider\"\nmsgstr \"Slider\"\n\n#: res/xrc/OutfitStudio.xrc:2003\nmsgid \"Conform Selected\\tCtrl+C\"\nmsgstr \"Ausgewählte übertragen\\tCtrl+C\"\n\n#: res/xrc/OutfitStudio.xrc:2004\nmsgid \"Conform selected outfit shape to all checked sliders.\"\nmsgstr \"Überträgt alle angehakten Slider auf die ausgewählten Modelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2007\nmsgid \"Conform All\\tCtrl+Shift+C\"\nmsgstr \"Alle übertragen\\tCtrl+Shift+C\"\n\n#: res/xrc/OutfitStudio.xrc:2008\nmsgid \"Conform all outfit shapes to all checked sliders.\"\nmsgstr \"Überträgt alle angehakten Slider auf alle Modelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2012\nmsgid \"Set Base Shape\"\nmsgstr \"Grundform setzen\"\n\n#: res/xrc/OutfitStudio.xrc:2013\nmsgid \"Set the current outfit shape as the base shape and clear slider data.\"\nmsgstr \"\"\n\"Setzt die aktuelle Form der Outfitmodelle als Grundform und löscht \"\n\"Sliderdaten.\"\n\n#: res/xrc/OutfitStudio.xrc:2018\nmsgid \"\"\n\"Load and preview a slider preset. Inverted sliders will have inverted values.\"\nmsgstr \"\"\n\"Läd ein Preset zur Vorschau. Umgekehrte Slider bekommen umgekehrte Werte.\"\n\n#: res/xrc/OutfitStudio.xrc:2022\nmsgid \"\"\n\"Save a slider preset with the current values. Inverted sliders will have \"\n\"inverted values.\"\nmsgstr \"\"\n\"Speichert ein Preset mit den aktuellen Werten. Umgekehrte Slider bekommen \"\n\"umgekehrte Werte.\"\n\n#: res/xrc/OutfitStudio.xrc:2026\nmsgid \"New Slider\"\nmsgstr \"Neuer Slider\"\n\n#: res/xrc/OutfitStudio.xrc:2027\nmsgid \"Create a new shape transformation slider.\"\nmsgstr \"Erstellt einen neuen Slider zum Transformieren von Modellen.\"\n\n#: res/xrc/OutfitStudio.xrc:2030\nmsgid \"Coalesce sliders\"\nmsgstr \"Slider zusammenfügen\"\n\n#: res/xrc/OutfitStudio.xrc:2031\nmsgid \"\"\n\"Create a new shape transformation slider based on the current slider values\"\nmsgstr \"\"\n\"Erstellt einen neuen Slider, der auf den aktuellen Sliderwerten basiert\"\n\n#: res/xrc/OutfitStudio.xrc:2034\nmsgid \"New Zap Slider\"\nmsgstr \"Neuer Zap Slider\"\n\n#: res/xrc/OutfitStudio.xrc:2035\nmsgid \"Create a new Zap slider based on unmasked vertices\"\nmsgstr \"\"\n\"Erstellt einen neuen Zap Slider, der auf allen nicht maskierten Vertices \"\n\"basiert\"\n\n#: res/xrc/OutfitStudio.xrc:2039\nmsgid \"Import OSD...\"\nmsgstr \"OSD importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2040\nmsgid \"Imports OSD file and creates sliders for shapes with a matching name.\"\nmsgstr \"\"\n\"Importiert eine OSD-Datei und erstellt daraus Slider für Modelle mit \"\n\"passendem Namen.\"\n\n#: res/xrc/OutfitStudio.xrc:2043\nmsgid \"Export OSD...\"\nmsgstr \"OSD exportieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2044\nmsgid \"Exports all currently loaded slider data to an OSD file.\"\nmsgstr \"Exportiert alle derzeit geladenen Sliderdaten in eine OSD-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:2047\nmsgid \"Import TRI Morphs...\"\nmsgstr \"TRI-Morphs importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2048\nmsgid \"\"\n\"Imports TRI morphs from a TRI file and creates sliders for shapes with a \"\n\"matching name.\"\nmsgstr \"\"\n\"Importiert TRI-Morphs aus einer TRI-Datei und erstellt daraus Slider für \"\n\"Modelle mit passendem Namen.\"\n\n#: res/xrc/OutfitStudio.xrc:2051\nmsgid \"Export TRI Morphs...\"\nmsgstr \"TRI-Morphs exportieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2052\nmsgid \"Exports TRI morphs to a TRI file.\"\nmsgstr \"Exportiert TRI-Morphs in eine TRI-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:2055\nmsgid \"Import Starfield morphs...\"\nmsgstr \"Starfield-Morphs importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2056\nmsgid \"\"\n\"Imports Starfield morph.dat file and creates sliders for shapes with a \"\n\"matching name.\"\nmsgstr \"\"\n\"Importiert eine Starfield morph.dat-Datei und erstellt daraus Slider für \"\n\"Modelle mit passendem Namen.\"\n\n#: res/xrc/OutfitStudio.xrc:2059\nmsgid \"Export to OBJs...\"\nmsgstr \"OBJs exportieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2060\nmsgid \"Export all sliders to an OBJ file per slider.\"\nmsgstr \"Exportiert alle Slider als eine OBJ-Datei je Slider.\"\n\n#: res/xrc/OutfitStudio.xrc:2064\nmsgid \"Import Slider Data\"\nmsgstr \"Sliderdaten importieren\"\n\n#: res/xrc/OutfitStudio.xrc:2066\nmsgid \"Import NIF...\"\nmsgstr \"NIF importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2067\nmsgid \"Import a NIF file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\"Importiert eine BodySlide NIF-Datei und überschreibt die Sliderdaten des \"\n\"aktuellen Modells.\"\n\n#: res/xrc/OutfitStudio.xrc:2070\nmsgid \"Import BSD...\"\nmsgstr \"BSD importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2071\nmsgid \"\"\n\"Import a BodySlide BSD file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\"Importiert eine BodySlide BSD-Datei und überschreibt die Sliderdaten des \"\n\"aktuellen Modells.\"\n\n#: res/xrc/OutfitStudio.xrc:2074\nmsgid \"Import OBJ...\"\nmsgstr \"OBJ importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2075\nmsgid \"\"\n\"Import an OBJ file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"\"\n\"Importiert eine OBJ-Datei, die mit der Vertex Anzahl des aktuellen Modells \"\n\"übereinstimmt, und berechnet Sliderdaten aus der Differenz.\"\n\n#: res/xrc/OutfitStudio.xrc:2078\nmsgid \"Import FBX...\"\nmsgstr \"FBX importieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2079\nmsgid \"\"\n\"Import an FBX file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"\"\n\"Importiert eine FBX-Datei, die mit der Vertex Anzahl des aktuellen Modells \"\n\"übereinstimmt, und berechnet Sliderdaten aus der Differenz.\"\n\n#: res/xrc/OutfitStudio.xrc:2084\nmsgid \"Export Slider Data\"\nmsgstr \"Sliderdaten exportieren\"\n\n#: res/xrc/OutfitStudio.xrc:2086\nmsgid \"Export NIF...\"\nmsgstr \"NIF exportieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2087\nmsgid \"Exports the current slider's data as a NIF file.\"\nmsgstr \"Exportiert die Daten des aktuellen Sliders als BodySlide NIF-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:2090\nmsgid \"Export BSD...\"\nmsgstr \"BSD exportieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2091\nmsgid \"Exports the current slider's data as a BodySlide BSD file.\"\nmsgstr \"Exportiert die Daten des aktuellen Sliders als BodySlide BSD-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:2094\nmsgid \"Export OBJ...\"\nmsgstr \"OBJ exportieren...\"\n\n#: res/xrc/OutfitStudio.xrc:2095\nmsgid \"Exports the current slider's data as an OBJ file.\"\nmsgstr \"Exportiert die Daten des aktuellen Sliders als BodySlide OBJ-Datei.\"\n\n#: res/xrc/OutfitStudio.xrc:2101 src/program/OutfitStudio.cpp:8013\nmsgid \"Clone Slider\"\nmsgstr \"Slider duplizieren\"\n\n#: res/xrc/OutfitStudio.xrc:2102\nmsgid \"Clones the current slider.\"\nmsgstr \"Dupliziert den aktuellen Slider.\"\n\n#: res/xrc/OutfitStudio.xrc:2106\nmsgid \"Negate Slider\"\nmsgstr \"Slider negieren\"\n\n#: res/xrc/OutfitStudio.xrc:2107\nmsgid \"Negates the current slider, reversing it's effect\"\nmsgstr \"Negiert den aktuellen Slider zum Umkehren seines Effektes\"\n\n#: res/xrc/OutfitStudio.xrc:2111\nmsgid \"Mask Affected Vertices\"\nmsgstr \"Beeinflusste Vertices maskieren\"\n\n#: res/xrc/OutfitStudio.xrc:2112\nmsgid \"Masks the vertices the slider is affecting for all selected shapes.\"\nmsgstr \"\"\n\"Maskiert die Vertices aller ausgewählten Modelle, welche der Slider \"\n\"beeinflusst.\"\n\n#: res/xrc/OutfitStudio.xrc:2116\nmsgid \"Clear Slider Data\"\nmsgstr \"Sliderdaten löschen\"\n\n#: res/xrc/OutfitStudio.xrc:2117\nmsgid \"\"\n\"Erases the slider data without removing the slider itself. (Cannot be undone)\"\nmsgstr \"\"\n\"Löscht die Sliderdaten, ohne den Slider selbst zu entfernen. (Kann nicht \"\n\"rückgängig gemacht werden)\"\n\n#: res/xrc/OutfitStudio.xrc:2120\nmsgid \"Delete Slider\\tCtrl+Del\"\nmsgstr \"Slider entfernen\\tCtrl+Del\"\n\n#: res/xrc/OutfitStudio.xrc:2121\nmsgid \"Delete the active slider from the project. (Cannot be undone)\"\nmsgstr \"\"\n\"Entfernt den aktiven Slider aus dem Projekt. (Kann nicht rückgängig gemacht \"\n\"werden)\"\n\n#: res/xrc/OutfitStudio.xrc:2125\nmsgid \"Properties...\\tTab\"\nmsgstr \"Eigenschaften...\\tTab\"\n\n#: res/xrc/OutfitStudio.xrc:2126 src/ui/wxSliderPanel.cpp:69\nmsgid \"Display and edit the active slider's properties.\"\nmsgstr \"Zeigt die Eigenschaften des aktiven Sliders zur Bearbeitung an.\"\n\n#: res/xrc/OutfitStudio.xrc:2131\nmsgid \"Tool\"\nmsgstr \"Werkzeug\"\n\n#: res/xrc/OutfitStudio.xrc:2133\nmsgid \"Current Tool\"\nmsgstr \"Aktuelles Werkzeug\"\n\n#: res/xrc/OutfitStudio.xrc:2172\nmsgid \"\"\n\"Apply animation weight values for the currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"Wendet Animations-Weighting für den derzeit gewählten Bone an.\\n\"\n\"ALT gedrückt halten, um das Weighting abzuschwächen.\"\n\n#: res/xrc/OutfitStudio.xrc:2210\nmsgid \"Transform\\tF\"\nmsgstr \"Transformieren\\tF\"\n\n#: res/xrc/OutfitStudio.xrc:2215\nmsgid \"Pivot\\tP\"\nmsgstr \"Pivot\\tP\"\n\n#: res/xrc/OutfitStudio.xrc:2220\nmsgid \"Vertex Edit\\tQ\"\nmsgstr \"Vertex Bearbeitung\\tQ\"\n\n#: res/xrc/OutfitStudio.xrc:2221\nmsgid \"\"\n\"Shows vertex points and lets you mask/unmask them.\\n\"\n\"Without any brush active, click on a vertex to unmask it.\\n\"\n\"Hold down CTRL to mask it.\"\nmsgstr \"\"\n\"Zeigt Vertexpunkte und ermöglicht es, diese zur Maske hinzuzufügen oder zu \"\n\"entfernen.\\n\"\n\"Ohne einen aktiven Pinsel auf einen Vertex klicken, um ihn zu demaskieren.\\n\"\n\"STRG gedrückt halten, um ihn zu maskieren.\"\n\n#: res/xrc/OutfitStudio.xrc:2226\nmsgid \"Increase Brush Size\\tShift++\"\nmsgstr \"Pinselgröße erhöhen\\tShift++\"\n\n#: res/xrc/OutfitStudio.xrc:2227\nmsgid \"Increase brush diameter\"\nmsgstr \"Erhöht den Durchmesser des Pinsels\"\n\n#: res/xrc/OutfitStudio.xrc:2230\nmsgid \"Decrease Brush Size\\tShift+-\"\nmsgstr \"Pinselgröße verringern\\tShift+-\"\n\n#: res/xrc/OutfitStudio.xrc:2231\nmsgid \"Decrease brush diameter\"\nmsgstr \"Verringert den Durchmesser des Pinsels\"\n\n#: res/xrc/OutfitStudio.xrc:2234\nmsgid \"Increase Brush Strength\\tCtrl++\"\nmsgstr \"Pinselstärke erhöhen\\tCtrl++\"\n\n#: res/xrc/OutfitStudio.xrc:2235\nmsgid \"Increase brush strength\"\nmsgstr \"Erhöht die Stärke des Pinsels\"\n\n#: res/xrc/OutfitStudio.xrc:2238\nmsgid \"Decrease Brush Strength\\tCtrl+-\"\nmsgstr \"Pinselstärke verringern\\tCtrl+-\"\n\n#: res/xrc/OutfitStudio.xrc:2239\nmsgid \"Decrease brush strength\"\nmsgstr \"Verringert die Stärke des Pinsels\"\n\n#: res/xrc/OutfitStudio.xrc:2243\nmsgid \"Mask Less\\tA\"\nmsgstr \"Weniger maskieren\\tA\"\n\n#: res/xrc/OutfitStudio.xrc:2244\nmsgid \"Mask Less\"\nmsgstr \"Weniger maskieren\"\n\n#: res/xrc/OutfitStudio.xrc:2247\nmsgid \"Mask More\\tD\"\nmsgstr \"Mehr maskieren\\tD\"\n\n#: res/xrc/OutfitStudio.xrc:2248\nmsgid \"Mask More\"\nmsgstr \"Mehr maskieren\"\n\n#: res/xrc/OutfitStudio.xrc:2252\nmsgid \"Invert Mask\\tCtrl+I\"\nmsgstr \"Maske umkehren\\tCtrl+I\"\n\n#: res/xrc/OutfitStudio.xrc:2253\nmsgid \"Invert Mask\"\nmsgstr \"Maske umkehren\"\n\n#: res/xrc/OutfitStudio.xrc:2256\nmsgid \"Clear Mask\\tCtrl+A\"\nmsgstr \"Maske löschen\\tCtrl+A\"\n\n#: res/xrc/OutfitStudio.xrc:2257\nmsgid \"Clear Mask\"\nmsgstr \"Maske entfernen\"\n\n#: res/xrc/OutfitStudio.xrc:2261\nmsgid \"View\"\nmsgstr \"Ansicht\"\n\n#: res/xrc/OutfitStudio.xrc:2263\nmsgid \"Front\\tShift+1\"\nmsgstr \"Vorne\\tShift+1\"\n\n#: res/xrc/OutfitStudio.xrc:2266\nmsgid \"Back\\tShift+2\"\nmsgstr \"Hinten\\tShift+2\"\n\n#: res/xrc/OutfitStudio.xrc:2269\nmsgid \"Left\\tShift+3\"\nmsgstr \"Links\\tShift+3\"\n\n#: res/xrc/OutfitStudio.xrc:2272\nmsgid \"Right\\tShift+4\"\nmsgstr \"Rechts\\tShift+4\"\n\n#: res/xrc/OutfitStudio.xrc:2275\nmsgid \"Perspective\\tShift+5\"\nmsgstr \"Perspektive\\tShift+5\"\n\n#: res/xrc/OutfitStudio.xrc:2280\nmsgid \"Toggle Rotation Center\\tShift+R\"\nmsgstr \"Rotationszentrum umschalten\\tShift+R\"\n\n#: res/xrc/OutfitStudio.xrc:2281\nmsgid \"Switch between the different rotation center modes.\"\nmsgstr \"Schaltet zwischen den verschiedenen Rotationszentrum-Modi um.\"\n\n#: res/xrc/OutfitStudio.xrc:2284\nmsgid \"Show Nodes\\tShift+N\"\nmsgstr \"Knoten anzeigen\\tShift+N\"\n\n#: res/xrc/OutfitStudio.xrc:2288\nmsgid \"Show Bones\\tShift+B\"\nmsgstr \"Bones anzeigen\\tShift+B\"\n\n#: res/xrc/OutfitStudio.xrc:2292\nmsgid \"Show Floor\\tG\"\nmsgstr \"Boden anzeigen\\tG\"\n\n#: res/xrc/OutfitStudio.xrc:2297\nmsgid \"Toggle Visibility\\tE\"\nmsgstr \"Sichtbarkeit umschalten\\tE\"\n\n#: res/xrc/OutfitStudio.xrc:2298\nmsgid \"Switch between the different visibility modes for the selected shapes.\"\nmsgstr \"\"\n\"Schaltet für die ausgewählten Modelle zwischen den verschiedenen \"\n\"Sichtbarkeitsmodi um.\"\n\n#: res/xrc/OutfitStudio.xrc:2301\nmsgid \"Show Wireframe\\tW\"\nmsgstr \"Gitternetz anzeigen\\tW\"\n\n#: res/xrc/OutfitStudio.xrc:2302\nmsgid \"Show wireframe on all models.\"\nmsgstr \"Gitternetz auf allen Modellen anzeigen.\"\n\n#: res/xrc/OutfitStudio.xrc:2306\nmsgid \"Enable Lighting\\tL\"\nmsgstr \"Beleuchtung aktivieren\\tL\"\n\n#: res/xrc/OutfitStudio.xrc:2307\nmsgid \"Turn on or off lighting.\"\nmsgstr \"Schaltet die Beleuchtung an oder aus.\"\n\n#: res/xrc/OutfitStudio.xrc:2312\nmsgid \"Enable Textures\\tT\"\nmsgstr \"Texturen aktivieren\\tT\"\n\n#: res/xrc/OutfitStudio.xrc:2313\nmsgid \"Display texture maps on models.\"\nmsgstr \"Zeigt Texturen der Modelle an.\"\n\n#: res/xrc/OutfitStudio.xrc:2318\nmsgid \"Enable Vertex Colors\"\nmsgstr \"Vertex-Farben aktivieren\"\n\n#: res/xrc/OutfitStudio.xrc:2319\nmsgid \"Display vertex colors on models.\"\nmsgstr \"Zeigt Vertex-Farben der Modelle an.\"\n\n#: res/xrc/OutfitStudio.xrc:2429\nmsgid \"Check For Bad Bones\"\nmsgstr \"Auf mangelhafte Bones prüfen\"\n\n#: res/xrc/OutfitStudio.xrc:2463\nmsgid \"Bad Bone\"\nmsgstr \"Mangelhafter Bone\"\n\n#: res/xrc/OutfitStudio.xrc:2465\nmsgid \"Set Skin Transform From Node\"\nmsgstr \"Skin-Transformation aus Node setzen\"\n\n#: res/xrc/OutfitStudio.xrc:2466\nmsgid \"Fixes the bad bone by calculating a new skin-to-bone transform.\"\nmsgstr \"\"\n\"Korrigiert den mangelhaften Bone durch Berechnen einer neuen Skin-to-Bone \"\n\"Transformation.\"\n\n#: res/xrc/OutfitStudio.xrc:2469\nmsgid \"Set Node Transform From Skin\"\nmsgstr \"Node-Transformation aus Skin setzen\"\n\n#: res/xrc/OutfitStudio.xrc:2470\nmsgid \"\"\n\"Fixes the bad custom bone by calculating a new bone-to-global transform.\"\nmsgstr \"\"\n\n#: res/xrc/OutfitStudio.xrc:2474 res/xrc/OutfitStudio.xrc:2507\n#: res/xrc/ShapeProperties.xrc:280 res/xrc/ShapeProperties.xrc:438\n#: res/xrc/ShapeProperties.xrc:611\nmsgid \"Add\"\nmsgstr \"Hinzufügen\"\n\n#: res/xrc/OutfitStudio.xrc:2476 res/xrc/OutfitStudio.xrc:2509\nmsgid \"From Skeleton...\"\nmsgstr \"Aus Skelett...\"\n\n#: res/xrc/OutfitStudio.xrc:2477 res/xrc/OutfitStudio.xrc:2510\nmsgid \"Choose a bone from the reference skeleton to add to the project.\"\nmsgstr \"\"\n\"Wählen Sie einen Bone aus dem Referenzskelett, um ihn dem Projekt \"\n\"hinzuzufügen.\"\n\n#: res/xrc/OutfitStudio.xrc:2480 res/xrc/OutfitStudio.xrc:2513\nmsgid \"Custom Bone...\"\nmsgstr \"Benutzerdefinierter Bone...\"\n\n#: res/xrc/OutfitStudio.xrc:2481 res/xrc/OutfitStudio.xrc:2514\nmsgid \"Add a custom bone to the project.\"\nmsgstr \"Fügt einen benutzerdefinierten Bone dem Projekt hinzu.\"\n\n#: res/xrc/OutfitStudio.xrc:2487\nmsgid \"From Project\"\nmsgstr \"Aus Projekt\"\n\n#: res/xrc/OutfitStudio.xrc:2488\nmsgid \"Delete bone(s) from all shapes of the project.\"\nmsgstr \"Bone(s) von allen Modellen des Projektes entfernen.\"\n\n#: res/xrc/OutfitStudio.xrc:2491\nmsgid \"From Selected Shapes\"\nmsgstr \"Von ausgewählten Modellen\"\n\n#: res/xrc/OutfitStudio.xrc:2492\nmsgid \"Delete bone(s) from only the selected shapes.\"\nmsgstr \"Bone(s) nur von ausgewählten Modellen entfernen.\"\n\n#: res/xrc/OutfitStudio.xrc:2496\nmsgid \"Edit Bone...\"\nmsgstr \"Bone bearbeiten...\"\n\n#: res/xrc/OutfitStudio.xrc:2497\nmsgid \"Edit a custom bone or view a standard bone.\"\nmsgstr \"Bone bearbeiten oder Standard-Bone anzeigen.\"\n\n#: res/xrc/OutfitStudio.xrc:2501\nmsgid \"Masks vertices with weights for the selected bones.\"\nmsgstr \"Maskiert die Vertices mit Weights für die ausgewählten Bones.\"\n\n#: res/xrc/OutfitStudio.xrc:2521 res/xrc/OutfitStudio.xrc:2547\nmsgid \"Add Segment...\"\nmsgstr \"Segment hinzufügen...\"\n\n#: res/xrc/OutfitStudio.xrc:2522 res/xrc/OutfitStudio.xrc:2548\nmsgid \"Choose a segment to add to the shape.\"\nmsgstr \"Segment zum Hinzufügen wählen.\"\n\n#: res/xrc/OutfitStudio.xrc:2525 res/xrc/OutfitStudio.xrc:2536\nmsgid \"Add Sub Segment...\"\nmsgstr \"Untersegment hinzufügen...\"\n\n#: res/xrc/OutfitStudio.xrc:2526 res/xrc/OutfitStudio.xrc:2537\nmsgid \"Add a new sub segment to the currently selected segment.\"\nmsgstr \"Neues Untersegment am aktuell ausgewählten Segment hinzufügen.\"\n\n#: res/xrc/OutfitStudio.xrc:2529\nmsgid \"Delete Segment...\"\nmsgstr \"Segment löschen...\"\n\n#: res/xrc/OutfitStudio.xrc:2530\nmsgid \"Delete segment and all of its sub segments from the shape.\"\nmsgstr \"Entfernt das Segment und all seine Untersegmente vom Modell.\"\n\n#: res/xrc/OutfitStudio.xrc:2534\nmsgid \"Sub Segments\"\nmsgstr \"Untersegmente\"\n\n#: res/xrc/OutfitStudio.xrc:2540\nmsgid \"Delete Sub Segment...\"\nmsgstr \"Untersegment löschen...\"\n\n#: res/xrc/OutfitStudio.xrc:2541\nmsgid \"Delete the selected sub segment.\"\nmsgstr \"Ausgewähltes Untersegment löschen.\"\n\n#: res/xrc/OutfitStudio.xrc:2554 res/xrc/OutfitStudio.xrc:2565\nmsgid \"Add Partition...\"\nmsgstr \"Partition hinzufügen...\"\n\n#: res/xrc/OutfitStudio.xrc:2555 res/xrc/OutfitStudio.xrc:2566\nmsgid \"Adds a new partition to the shape.\"\nmsgstr \"Fügt dem Modell eine neue Partition hinzu.\"\n\n#: res/xrc/OutfitStudio.xrc:2558\nmsgid \"Delete Partition...\"\nmsgstr \"Partition entfernen...\"\n\n#: res/xrc/OutfitStudio.xrc:2559\nmsgid \"Deletes the partition from the shape.\"\nmsgstr \"Entfernt die Partition vom Modell.\"\n\n#: res/xrc/Project.xrc:16\nmsgid \"\"\n\"Welcome to the New Project wizard!\\n\"\n\"\\n\"\n\"First, please choose a reference. Typically, this is a body (such as CBBE) \"\n\"or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"Willkommen zum Assistenten für ein neues Projekt!\\n\"\n\"\\n\"\n\"Zuerst, wählen Sie bitte eine Referenz. Normalerweise ist dies ein Körper \"\n\"(wie z.B. CBBE) oder ein Konvertierungsset (wie z.B. Vanilla zu CBBE) und \"\n\"kommt mit seinen eigenen Slidern.\"\n\n#: res/xrc/Project.xrc:32 res/xrc/Project.xrc:598\nmsgid \"Reference\"\nmsgstr \"Referenz\"\n\n#: res/xrc/Project.xrc:50 res/xrc/Project.xrc:616\nmsgid \"From Template\"\nmsgstr \"Aus Vorlage\"\n\n#: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272\n#: res/xrc/Project.xrc:635 res/xrc/Project.xrc:846 res/xrc/Project.xrc:918\nmsgid \"From File\"\nmsgstr \"Aus Datei\"\n\n#: res/xrc/Project.xrc:79 res/xrc/Project.xrc:645\nmsgid \"Select a project or NIF file\"\nmsgstr \"Wählen Sie eine Projekt- oder NIF-Datei\"\n\n#: res/xrc/Project.xrc:106 res/xrc/Project.xrc:672\nmsgid \"Slider Set:\"\nmsgstr \"Slider Set:\"\n\n#: res/xrc/Project.xrc:124 res/xrc/Project.xrc:690\nmsgid \"Shape:\"\nmsgstr \"Modell:\"\n\n#: res/xrc/Project.xrc:146 res/xrc/Project.xrc:712\nmsgid \"Clear Reference\"\nmsgstr \"Referenz entfernen\"\n\n#: res/xrc/Project.xrc:162\nmsgid \"Next, select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\"Als nächstes, wählen Sie ein Outfit/Modell zum Bearbeiten und geben Sie \"\n\"einen Anzeigenamen dafür ein.\"\n\n#: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:813\nmsgid \"Display Name\"\nmsgstr \"Anzeigename\"\n\n#: res/xrc/Project.xrc:197 res/xrc/Project.xrc:833\nmsgid \"Outfit/Mesh\"\nmsgstr \"Outfit/Modell\"\n\n#: res/xrc/Project.xrc:220 res/xrc/Project.xrc:856\nmsgid \"Select a file to load as an outfit/mesh\"\nmsgstr \"Wählen Sie eine Datei zum Laden als Outfit/Modell\"\n\n#: res/xrc/Project.xrc:232 res/xrc/Project.xrc:868\nmsgid \"Clear Outfit\"\nmsgstr \"Outfit entfernen\"\n\n#: res/xrc/Project.xrc:250 res/xrc/Project.xrc:896\nmsgid \"Textures\"\nmsgstr \"Texturen\"\n\n#: res/xrc/Project.xrc:257 res/xrc/Project.xrc:903\nmsgid \"Automatically search for textures\"\nmsgstr \"Automatisch nach Texturen suchen\"\n\n#: res/xrc/Project.xrc:282 res/xrc/Project.xrc:928\nmsgid \"Select a texture file\"\nmsgstr \"Wählen Sie eine Textur-Datei\"\n\n#: res/xrc/Project.xrc:297\nmsgid \"Save Project As...\"\nmsgstr \"Projekte speichern unter...\"\n\n#: res/xrc/Project.xrc:328\nmsgid \"The name of the outfit and slider set, as it will appear in BodySlide.\"\nmsgstr \"\"\n\"Der Name des Outfits und Slidersets, wie er in BodySlide erscheinen wird.\"\n\n#: res/xrc/Project.xrc:337\nmsgid \"Copies the current display name to the project text fields below.\"\nmsgstr \"\"\n\"Kopiert den aktuellen Anzeigenamen in alle Projekt Textfelder unterhalb.\"\n\n#: res/xrc/Project.xrc:338\nmsgid \"To Project\"\nmsgstr \"Zu Projekt\"\n\n#: res/xrc/Project.xrc:354\nmsgid \"Output File Name\"\nmsgstr \"Ausgabe Dateiname\"\n\n#: res/xrc/Project.xrc:363\nmsgid \"\"\n\"The name of the outfit file that will end up in the game data path when \"\n\"BodySlide builds it. Should not include _1 or _0 in the name, e.g: \"\n\"lovelydress\"\nmsgstr \"\"\n\"Der Name der Outfit-Datei, die im Data Ordner des Spiels von BodySlide \"\n\"erstellt wird. Sollte nicht _1 oder _0 enthalten, z.B. lovelydress\"\n\n#: res/xrc/Project.xrc:389\nmsgid \"Output Data Path\"\nmsgstr \"Ausgabe Dateipfad\"\n\n#: res/xrc/Project.xrc:398\nmsgid \"\"\n\"The location in the game's data path where BodySlide-built outfit files will \"\n\"be placed, e.g: meshes\\\\clothes\\\\lovelydress\"\nmsgstr \"\"\n\"Der Ordner innerhalb der Spieldaten, in welchem BodySlide die Outfit-Dateien \"\n\"erstellen wird, z.B. meshes\\\\clothes\\\\lovelydress\"\n\n#: res/xrc/Project.xrc:410\nmsgid \"\"\n\"If this is enabled, BodySlide creates a low and high weight model when it \"\n\"generates the final outfit.\"\nmsgstr \"\"\n\"Wenn dies aktiviert ist, wird BodySlide Dateien für ein unteres und oberes \"\n\"Gewicht erstellen.\"\n\n#: res/xrc/Project.xrc:411\nmsgid \"Low/High Weight Output\"\nmsgstr \"Unteres/Oberes Gewicht\"\n\n#: res/xrc/Project.xrc:419\nmsgid \"\"\n\"If this is enabled, only one output file will be created (useful for single-\"\n\"weighted things like hair).\"\nmsgstr \"Wenn dies aktiviert ist, wird nur eine einzelne Datei ausgegeben.\"\n\n#: res/xrc/Project.xrc:420\nmsgid \"Single Weight Output\"\nmsgstr \"Einzelnes Gewicht\"\n\n#: res/xrc/Project.xrc:431\nmsgid \"Project\"\nmsgstr \"Projekt\"\n\n#: res/xrc/Project.xrc:443\nmsgid \"Slider Set File\"\nmsgstr \"Slider Set Datei\"\n\n#: res/xrc/Project.xrc:453\nmsgid \"The .osp slider set project file\"\nmsgstr \"Die .osp Sliderset Projekt-Datei\"\n\n#: res/xrc/Project.xrc:454\nmsgid \"Select slider set .osp file name\"\nmsgstr \"Wählen Sie einen Slider Set .osp Dateinamen\"\n\n#: res/xrc/Project.xrc:472\nmsgid \"Shape Data Folder\"\nmsgstr \"Shape Data Ordner\"\n\n#: res/xrc/Project.xrc:482\nmsgid \"\"\n\"The folder where all the slider data will go, as well as the base outfit NIF \"\n\"file.\"\nmsgstr \"\"\n\"Der Ordner, indem alle Sliderdaten und NIF-Dateien des Basisoutfits \"\n\"gespeichert werden.\"\n\n#: res/xrc/Project.xrc:483\nmsgid \"Select slider data folder\"\nmsgstr \"Wählen Sie den Sliderdaten Ordner\"\n\n#: res/xrc/Project.xrc:500\nmsgid \"Shape Data File\"\nmsgstr \"Shape Data Datei\"\n\n#: res/xrc/Project.xrc:510\nmsgid \"The name of the output's base NIF file.\"\nmsgstr \"Der Name der Ausgabe NIF-Datei.\"\n\n#: res/xrc/Project.xrc:511\nmsgid \"Select output NIF file name\"\nmsgstr \"Wählen Sie einen Ausgabe NIF-Dateinamen\"\n\n#: res/xrc/Project.xrc:523\nmsgid \"\"\n\"Outfits require the reference body to be a part of the output file. Disable \"\n\"this if you've already copied the reference over or you don't want it \"\n\"included.\"\nmsgstr \"\"\n\"Outfits benötigen den Referenzkörper innerhalb der Ausgabedatei. Deaktiviere \"\n\"dies, wenn du die Referenz bereits kopiert hast oder sie nicht in der \"\n\"Ausgabe benötigst.\"\n\n#: res/xrc/Project.xrc:524\nmsgid \"Copy reference shape into output\"\nmsgstr \"Referenzmodell in die Ausgabe kopieren\"\n\n#: res/xrc/Project.xrc:533\nmsgid \"\"\n\"Prevents the building of morph .tri files in BodySlide for this project.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:534\nmsgid \"Prevent morph file building in BodySlide\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:543\nmsgid \"\"\n\"Prevents the removal of fully zapped shapes when building in BodySlide. \"\n\"Useful when the shape order and count matters, like for retextures using \"\n\"texture sets.\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:544\nmsgid \"Prevent removal of fully zapped shapes in BodySlide\"\nmsgstr \"\"\n\n#: res/xrc/Project.xrc:563 res/xrc/SavePreset.xrc:78\nmsgid \"&Save\"\nmsgstr \"&Speichern\"\n\n#: res/xrc/Project.xrc:579\nmsgid \"Load Reference\"\nmsgstr \"Referenz laden\"\n\n#: res/xrc/Project.xrc:588\nmsgid \"\"\n\"Please choose a reference. Typically, this is a body (such as CBBE) or a \"\n\"conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"Wählen Sie bitte eine Referenz. Normalerweise ist dies ein Körper (wie z.B. \"\n\"CBBE) oder ein Konvertierungsset (wie z.B. Vanilla zu CBBE) und kommt mit \"\n\"seinen eigenen Slidern.\"\n\n#: res/xrc/Project.xrc:724\nmsgid \"Merge\"\nmsgstr \"Zusammenführen\"\n\n#: res/xrc/Project.xrc:741\nmsgid \"Zaps\"\nmsgstr \"Zaps\"\n\n#: res/xrc/Project.xrc:742\nmsgid \"Merge existing zaps with new sliders\"\nmsgstr \"Existierende Slider mit neuen zusammenführen\"\n\n#: res/xrc/Project.xrc:752\nmsgid \"Merge new sliders with existing sliders\"\nmsgstr \"Neue Slider mit existierenden verschmelzen\"\n\n#: res/xrc/Project.xrc:789\nmsgid \"Load Outfit\"\nmsgstr \"Outfit laden\"\n\n#: res/xrc/Project.xrc:798\nmsgid \"\"\n\"Please select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\"Wählen Sie ein Outfit/Modell zum Bearbeiten und geben Sie einen Anzeigenamen \"\n\"dafür ein.\"\n\n#: res/xrc/Project.xrc:877\nmsgid \"Keep other shapes\"\nmsgstr \"Andere Modelle behalten\"\n\n#: res/xrc/Project.xrc:1001\nmsgid \"Group file (optional):\"\nmsgstr \"Gruppendatei (optional):\"\n\n#: res/xrc/Project.xrc:1010\nmsgid \"Group file to pack (optional).\"\nmsgstr \"Gruppendatei zum Packen (optional).\"\n\n#: res/xrc/Project.xrc:1027\nmsgid \"Merged file name:\"\nmsgstr \"Zusammengefügte Datei:\"\n\n#: res/xrc/Project.xrc:1035\nmsgid \"File name to use for the merged project file.\"\nmsgstr \"Dateiname für die zusammengefügte Projektdatei.\"\n\n#: res/xrc/Project.xrc:1061\nmsgid \"Pack Folder...\"\nmsgstr \"Ordner packen...\"\n\n#: res/xrc/Project.xrc:1070\nmsgid \"Pack Archive...\"\nmsgstr \"Archiv packen...\"\n\n#: res/xrc/Project.xrc:1087 src/program/OutfitStudio.cpp:3846\n#: src/program/OutfitStudio.cpp:6531 src/program/OutfitStudio.cpp:7392\n#: src/program/OutfitStudio.cpp:7502 src/program/OutfitStudio.cpp:7628\n#: src/program/OutfitStudio.cpp:11359 src/program/ShapeProperties.cpp:135\nmsgid \"Cancel\"\nmsgstr \"Abbrechen\"\n\n#: res/xrc/SavePreset.xrc:6\nmsgid \"Enter preset name...\"\nmsgstr \"Preset-Name eingeben...\"\n\n#: res/xrc/SavePreset.xrc:15\nmsgid \"Please enter a name for the new preset:\"\nmsgstr \"Bitte geben Sie einen Namen für das neue Preset ein:\"\n\n#: res/xrc/SavePreset.xrc:38\nmsgid \"Select groups to assign to the new preset:\"\nmsgstr \"Wählen Sie die erwünschten Gruppen aus:\"\n\n#: res/xrc/Settings.xrc:15\nmsgid \"Game\"\nmsgstr \"Spiel\"\n\n#: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:5226\nmsgid \"Target Game\"\nmsgstr \"Verwendetes Spiel\"\n\n#: res/xrc/Settings.xrc:37\nmsgid \"Choose the target game you want to use the program for here.\"\nmsgstr \"\"\n\"Wählen Sie das Spiel, für welches Sie dieses Programm verwenden möchten.\"\n\n#: res/xrc/Settings.xrc:67\nmsgid \"Game Data Path\"\nmsgstr \"Data Ordner\"\n\n#: res/xrc/Settings.xrc:77\nmsgid \"Select the data path of the game...\"\nmsgstr \"Wählen Sie den Data Ordner des Spiels aus...\"\n\n#: res/xrc/Settings.xrc:79\nmsgid \"Data path to load textures from.\"\nmsgstr \"Verzeichnis, aus dem Texturen geladen werden sollen.\"\n\n#: res/xrc/Settings.xrc:91\nmsgid \"Advanced\"\nmsgstr \"Erweitert\"\n\n#: res/xrc/Settings.xrc:108\nmsgid \"Output Path\"\nmsgstr \"Ausgabe Ordner\"\n\n#: res/xrc/Settings.xrc:118\nmsgid \"Select the output path...\"\nmsgstr \"Wählen Sie den Ausgabeordner aus...\"\n\n#: res/xrc/Settings.xrc:120\nmsgid \"\"\n\"Data path to build files to. If empty, Game Data Path will be used instead.\"\nmsgstr \"\"\n\"Verzeichnis, in dem Ausgabedateien erstellt werden sollen. Falls leer, wird \"\n\"stattdessen der Data-Ordner verwendet.\"\n\n#: res/xrc/Settings.xrc:137\nmsgid \"Project Path\"\nmsgstr \"Projekt-Pfad\"\n\n#: res/xrc/Settings.xrc:147\nmsgid \"Select the project path...\"\nmsgstr \"Wählen Sie den Projektordner aus...\"\n\n#: res/xrc/Settings.xrc:149\nmsgid \"\"\n\"Project path where files related to BodySlide are loaded from. If empty, \"\n\"executable directory will be used instead.\"\nmsgstr \"\"\n\"Projektverzeichnis, aus dem BodySlide-Dateien geladen werden sollen. Falls \"\n\"leer, wird stattdessen das Programmverzeichnis verwendet.\"\n\n#: res/xrc/Settings.xrc:165\nmsgid \"\"\n\"With this turned on, BodySlide receives a new checkbox \\\"Force Body \"\n\"Normals\\\". Using it when building adds normal and tangent data to the body \"\n\"meshes (including bodies within outfits) for Skyrim. Use this only if you \"\n\"have a tangent space body mod.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:166\nmsgid \"Show 'Force Body Normals'\"\nmsgstr \"'Körper Normals erzwingen' anzeigen\"\n\n#: res/xrc/Settings.xrc:184\nmsgid \"General\"\nmsgstr \"Allgemein\"\n\n#: res/xrc/Settings.xrc:196\nmsgid \"\"\n\"Enables/disables the dialog for choosing which set to build during a batch \"\n\"build if overrides happen.\"\nmsgstr \"\"\n\"Aktiviert/Deaktiviert den Auswahldialog der erscheint, wenn es zu \"\n\"Überschreibungen in der Batch-Erstellung kommt.\"\n\n#: res/xrc/Settings.xrc:197\nmsgid \"Override Warning\"\nmsgstr \"Überschreibungswarnung\"\n\n#: res/xrc/Settings.xrc:206\nmsgid \"\"\n\"Enables/disables scanning BSAs in the game data folder for textures to load.\"\nmsgstr \"\"\n\"Aktiviert/Deaktiviert das Scannen von BSAs im Data Ordner zum Laden von \"\n\"Texturen.\"\n\n#: res/xrc/Settings.xrc:207\nmsgid \"BSA Textures\"\nmsgstr \"BSA Texturen\"\n\n#: res/xrc/Settings.xrc:224\nmsgid \"\"\n\"Enables/disables panning the camera with the left mouse button in Outfit \"\n\"Studio.\"\nmsgstr \"\"\n\"Aktiviert/Deaktiviert das Verschieben der Kamera in Outfit Studio mit einem \"\n\"Linksklick.\"\n\n#: res/xrc/Settings.xrc:225\nmsgid \"Left Mouse Pan\"\nmsgstr \"Linksklick zum Verschieben\"\n\n#: res/xrc/Settings.xrc:234\nmsgid \"\"\n\"Enables/disables opening the brush settings near the mouse cursor when \"\n\"hitting the 'space' key.\"\nmsgstr \"\"\n\"Aktiviert/deaktiviert das Öffnen der Pinseleinstellungen in der Nähe des \"\n\"Mauszeigers bei Betätigung der Leertaste.\"\n\n#: res/xrc/Settings.xrc:235\nmsgid \"Brush Settings Near Cursor\"\nmsgstr \"Pinseleinstellungen bei Mauszeiger\"\n\n#: res/xrc/Settings.xrc:244\nmsgid \"\"\n\"Enables/disables the undo history for the mask brush and vertex selection.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:245\nmsgid \"Mask History\"\nmsgstr \"Maskenverlauf\"\n\n#: res/xrc/Settings.xrc:263\nmsgid \"Language\"\nmsgstr \"Sprache\"\n\n#: res/xrc/Settings.xrc:272\nmsgid \"Use the selected language for the program.\"\nmsgstr \"Verwende die ausgewählte Sprache für das Programm.\"\n\n#: res/xrc/Settings.xrc:287\nmsgid \"Rendering\"\nmsgstr \"Rendering\"\n\n#: res/xrc/Settings.xrc:293\nmsgid \"Enables/disables the perspective view in the rendering window.\"\nmsgstr \"\"\n\n#: res/xrc/Settings.xrc:310\nmsgid \"Background Color\"\nmsgstr \"Hintergrundfarbe\"\n\n#: res/xrc/Settings.xrc:319\nmsgid \"Background color of the renderer.\"\nmsgstr \"Hintergrundfarbe des Renderers.\"\n\n#: res/xrc/Settings.xrc:337\nmsgid \"Wireframe Color\"\nmsgstr \"Wireframe-Farbe\"\n\n#: res/xrc/Settings.xrc:346\nmsgid \"Wireframe color of the renderer.\"\nmsgstr \"Wireframe-Farbe des Renderers.\"\n\n#: res/xrc/Settings.xrc:361\nmsgid \"Data Files\"\nmsgstr \"Datendateien\"\n\n#: res/xrc/Settings.xrc:379\nmsgid \"Reference Skeleton\"\nmsgstr \"Referenzskelett\"\n\n#: res/xrc/Settings.xrc:402\nmsgid \"Select a reference skeleton .nif file...\"\nmsgstr \"Wählen Sie eine .nif-Datei als Referenzskelett aus...\"\n\n#: res/xrc/Settings.xrc:405\nmsgid \"The reference skeleton file for Outfit Studio.\"\nmsgstr \"Die Referenzskelett-Datei für Outfit Studio.\"\n\n#: res/xrc/Settings.xrc:422\nmsgid \"Root Node\"\nmsgstr \"Root Knoten\"\n\n#: res/xrc/Settings.xrc:431\nmsgid \"\"\n\"The root node name of the reference skeleton. Can differ from game to game.\"\nmsgstr \"\"\n\"Der Name des Root Knotens des Referenzskeletts. Kann von Spiel zu Spiel \"\n\"abweichen.\"\n\n#: res/xrc/Setup.xrc:5\nmsgid \"Setup\"\nmsgstr \"Setup\"\n\n#: res/xrc/Setup.xrc:15\nmsgid \"\"\n\"Please select the data folder and your target game.\\n\"\n\"You can only choose one game at a time, but it is possible to change the \"\n\"selection in the settings.\"\nmsgstr \"\"\n\"Bitte wählen Sie den Data-Ordner und Ihr Spiel.\\n\"\n\"Es kann nur ein Spiel gleichzeitig aktiv sein, aber es ist in den \"\n\"Einstellungen möglich die Auswahl abzuändern.\"\n\n#: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102\n#: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189\n#: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247 res/xrc/Setup.xrc:276\nmsgid \"Game not found! Select the data folder manually...\"\nmsgstr \"Spiel nicht gefunden! Wählen Sie den Data-Ordner manuell...\"\n\n#: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103\n#: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190\n#: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248 res/xrc/Setup.xrc:277\nmsgid \"Select a folder\"\nmsgstr \"Verzeichnis wählen\"\n\n#: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113\n#: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200\n#: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258 res/xrc/Setup.xrc:287\nmsgid \"Choose Game\"\nmsgstr \"Spiel wählen\"\n\n#: res/xrc/ShapeProperties.xrc:5\nmsgid \"Shape Properties\"\nmsgstr \"Modelleigenschaften\"\n\n#: res/xrc/ShapeProperties.xrc:16\nmsgid \"Shader\"\nmsgstr \"Shader\"\n\n#: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:629\n#: res/xrc/Skeleton.xrc:94\nmsgid \"Name\"\nmsgstr \"Name\"\n\n#: res/xrc/ShapeProperties.xrc:102\nmsgid \"Specular Color\"\nmsgstr \"Specular Farbe\"\n\n#: res/xrc/ShapeProperties.xrc:120\nmsgid \"Specular Strength\"\nmsgstr \"Specular Stärke\"\n\n#: res/xrc/ShapeProperties.xrc:139\nmsgid \"Specular Power\"\nmsgstr \"Specular Kraft\"\n\n#: res/xrc/ShapeProperties.xrc:179\nmsgid \"Emissive Color\"\nmsgstr \"Emissive Farbe\"\n\n#: res/xrc/ShapeProperties.xrc:197\nmsgid \"Emissive Multiple\"\nmsgstr \"Emissive Multiplikator\"\n\n#: res/xrc/ShapeProperties.xrc:216\nmsgid \"Alpha\"\nmsgstr \"Alpha\"\n\n#: res/xrc/ShapeProperties.xrc:235\nmsgid \"Vertex Colors\"\nmsgstr \"Vertex Farben\"\n\n#: res/xrc/ShapeProperties.xrc:252\nmsgid \"Double Sided\"\nmsgstr \"Zweiseitig\"\n\n#: res/xrc/ShapeProperties.xrc:289 res/xrc/ShapeProperties.xrc:447\nmsgid \"Remove\"\nmsgstr \"Entfernen\"\n\n#: res/xrc/ShapeProperties.xrc:298\nmsgid \"Textures...\"\nmsgstr \"Texturen...\"\n\n#: res/xrc/ShapeProperties.xrc:310\nmsgid \"Transparency\"\nmsgstr \"Transparenz\"\n\n#: res/xrc/ShapeProperties.xrc:333\nmsgid \"Threshold\"\nmsgstr \"Grenzwert\"\n\n#: res/xrc/ShapeProperties.xrc:373\nmsgid \"Vertex Alpha\"\nmsgstr \"Vertex Alpha\"\n\n#: res/xrc/ShapeProperties.xrc:391\nmsgid \"Alpha Test\"\nmsgstr \"Alpha Test\"\n\n#: res/xrc/ShapeProperties.xrc:409\nmsgid \"Alpha Blend\"\nmsgstr \"Alpha Blend\"\n\n#: res/xrc/ShapeProperties.xrc:460\nmsgid \"Copy from shape...\"\nmsgstr \"Kopieren von Modell...\"\n\n#: res/xrc/ShapeProperties.xrc:468\nmsgid \"Geometry\"\nmsgstr \"Geometrie\"\n\n#: res/xrc/ShapeProperties.xrc:488\nmsgid \"Full Precision\"\nmsgstr \"Volle Präzision\"\n\n#: res/xrc/ShapeProperties.xrc:507\nmsgid \"Sub Index\"\nmsgstr \"Sub Index\"\n\n#: res/xrc/ShapeProperties.xrc:526\nmsgid \"Skinned\"\nmsgstr \"Skinned\"\n\n#: res/xrc/ShapeProperties.xrc:544\nmsgid \"Dynamic\"\nmsgstr \"Dynamisch\"\n\n#: res/xrc/ShapeProperties.xrc:590\nmsgid \"Extra Data\"\nmsgstr \"Extra Daten\"\n\n#: res/xrc/ShapeProperties.xrc:638\nmsgid \"Value\"\nmsgstr \"Wert\"\n\n#: res/xrc/ShapeProperties.xrc:648\nmsgid \"Coordinates\"\nmsgstr \"Koordinaten\"\n\n#: res/xrc/ShapeProperties.xrc:657\nmsgid \"Transform from shape to global coordinates:\"\nmsgstr \"Von Modell- nach globale Koordinaten transformieren:\"\n\n#: res/xrc/ShapeProperties.xrc:720 res/xrc/Skeleton.xrc:142\nmsgid \"Rotation\"\nmsgstr \"Rotation\"\n\n#: res/xrc/Skeleton.xrc:6\nmsgid \"Select a bone to add\"\nmsgstr \"Wählen Sie einen hinzuzufügenden Bone\"\n\n#: res/xrc/Skeleton.xrc:15\nmsgid \"Bones in the current reference skeleton:\"\nmsgstr \"Bones im aktuellen Referenzskelett:\"\n\n#: res/xrc/Skeleton.xrc:53\nmsgid \"Add Custom Bone\"\nmsgstr \"Benutzerdefinierten Bone hinzufügen\"\n\n#: res/xrc/Skeleton.xrc:68\nmsgid \"Parent\"\nmsgstr \"Parent\"\n\n#: res/xrc/Skeleton.xrc:234\nmsgid \"Add Count #\"\nmsgstr \"Anzahl Neu #\"\n\n#: res/xrc/Slider.xrc:6\nmsgid \"Select a slider preset\"\nmsgstr \"Wählen Sie ein Slider Preset\"\n\n#: res/xrc/Slider.xrc:15\nmsgid \"Choose a preset:\"\nmsgstr \"Wählen Sie ein Preset:\"\n\n#: res/xrc/Slider.xrc:40\nmsgid \"Low weight\"\nmsgstr \"Unteres Gewicht\"\n\n#: res/xrc/Slider.xrc:49\nmsgid \"High weight\"\nmsgstr \"Oberes Gewicht\"\n\n#: res/xrc/Slider.xrc:81\nmsgid \"Slider Properties\"\nmsgstr \"Slidereigenschaften\"\n\n#: res/xrc/Slider.xrc:91\nmsgid \"Slider Name\"\nmsgstr \"Slidername\"\n\n#: res/xrc/Slider.xrc:108\nmsgid \"Default Values\"\nmsgstr \"Standardwerte\"\n\n#: res/xrc/Slider.xrc:114\nmsgid \"Low\"\nmsgstr \"Niedrig\"\n\n#: res/xrc/Slider.xrc:131\nmsgid \"High\"\nmsgstr \"Hoch\"\n\n#: res/xrc/Slider.xrc:148\nmsgid \"Zapped\"\nmsgstr \"Zapped\"\n\n#: res/xrc/Slider.xrc:173\nmsgid \"Invert\"\nmsgstr \"Invertieren\"\n\n#: res/xrc/Slider.xrc:182\nmsgid \"Hidden\"\nmsgstr \"Versteckt\"\n\n#: res/xrc/Slider.xrc:191\nmsgid \"Zap\"\nmsgstr \"Zap\"\n\n#: res/xrc/Slider.xrc:211\nmsgid \"Toggle Zaps:\"\nmsgstr \"Zap-Umschaltung:\"\n\n#: res/xrc/SliderDataImport.xrc:6\nmsgid \"Slider Data Import Options...\"\nmsgstr \"Sliderdaten Import-Optionen...\"\n\n#: res/xrc/SliderDataImport.xrc:21\nmsgid \"Select the shapes that slider data will be imported for:\"\nmsgstr \"Wählen Sie die Modelle für die Sliderdaten importiert werden:\"\n\n#: res/xrc/SliderDataImport.xrc:52\nmsgid \"Select the sliders to be imported\"\nmsgstr \"Wählen Sie die zu importierenden Slider\"\n\n#: src/components/Anim.cpp:570\nmsgid \"\"\n\"Bone information incomplete. Exported data will not contain correct bone \"\n\"entries! Be sure to load a reference NIF prior to export.\"\nmsgstr \"\"\n\"Bone-Informationen sind unvollständig. Exportierte Daten werden keine \"\n\"korrekten Bone-Einträge besitzen! Stelle sicher, dass du eine Referenz vor \"\n\"dem Export geladen hast.\"\n\n#: src/components/Anim.cpp:571\nmsgid \"Export Warning\"\nmsgstr \"Export Warnung\"\n\n#: src/components/Anim.cpp:764\n#, c-format\nmsgid \"Failed to load skeleton '%s'!\"\nmsgstr \"Konnte Skelett '%s' nicht laden!\"\n\n#: src/components/Anim.cpp:772\n#, c-format\nmsgid \"Root '%s' not found in skeleton '%s'!\"\nmsgstr \"Root '%s' konnte nicht im Skelett '%s' gefunden werden!\"\n\n#: src/program/BodySlideApp.cpp:189 src/program/OutfitStudio.cpp:423\nmsgid \"\"\n\"No read/write permission for game data path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the game data \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"Kein Schreib-/Lesezugriff auf den Spieldaten-Ordner!\\n\"\n\"\\n\"\n\"Bitte starten Sie das Programm mit Admin-Rechten und stellen Sie sicher, \"\n\"dass der Spieldaten-Pfad in den Einstellungen korrekt ist.\"\n\n#: src/program/BodySlideApp.cpp:190 src/program/BodySlideApp.cpp:200\n#: src/program/BodySlideApp.cpp:1535 src/program/OutfitStudio.cpp:424\n#: src/program/OutfitStudio.cpp:434 src/program/OutfitStudio.cpp:660\n#: src/program/OutfitStudio.cpp:667\nmsgid \"Warning\"\nmsgstr \"Warnung\"\n\n#: src/program/BodySlideApp.cpp:199 src/program/OutfitStudio.cpp:433\nmsgid \"\"\n\"No read/write permission for project path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the project \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"Kein Schreib-/Lesezugriff auf den Projekte-Ordner!\\n\"\n\"\\n\"\n\"Bitte starten Sie das Programm mit Admin-Rechten und stellen Sie sicher, \"\n\"dass der Projekte-Pfad in den Einstellungen korrekt ist.\"\n\n#: src/program/BodySlideApp.cpp:272 src/program/OutfitStudio.cpp:521\n#, c-format\nmsgid \"Unexpected exception has occurred: %s, the program will terminate.\"\nmsgstr \"\"\n\"Unerwartete Ausnahme trat auf: %s, das Programm wird sich jetzt beenden.\"\n\n#: src/program/BodySlideApp.cpp:272 src/program/OutfitStudio.cpp:521\nmsgid \"Unexpected exception\"\nmsgstr \"Unerwartete Ausnahme\"\n\n#: src/program/BodySlideApp.cpp:295 src/program/OutfitStudio.cpp:541\n#, c-format\nmsgid \"Unhandled exception has occurred: %s, the program will terminate.\"\nmsgstr \"\"\n\"Unbehandelte Ausnahme trat auf: %s, das Programm wird sich jetzt beenden.\"\n\n#: src/program/BodySlideApp.cpp:295 src/program/OutfitStudio.cpp:541\nmsgid \"Unhandled exception\"\nmsgstr \"Unbehandelte Ausnahme\"\n\n#: src/program/BodySlideApp.cpp:306 src/program/OutfitStudio.cpp:549\nmsgid \"Fatal exception has occurred, the program will terminate.\"\nmsgstr \"Ein fataler Fehler trat auf, das Programm wird sich jetzt beenden.\"\n\n#: src/program/BodySlideApp.cpp:306 src/program/OutfitStudio.cpp:549\nmsgid \"Fatal exception\"\nmsgstr \"Fataler Fehler\"\n\n#: src/program/BodySlideApp.cpp:1012\nmsgid \"Failed to launch Outfit Studio executable!\"\nmsgstr \"Fehler beim Starten von Outfit Studio!\"\n\n#: src/program/BodySlideApp.cpp:1012 src/program/BodySlideApp.cpp:1556\n#: src/program/BodySlideApp.cpp:1868 src/program/BodySlideApp.cpp:3037\n#: src/program/BodySlideApp.cpp:3044 src/program/BodySlideApp.cpp:3849\n#: src/program/OutfitStudio.cpp:1001 src/program/OutfitStudio.cpp:1007\n#: src/program/OutfitStudio.cpp:1560 src/program/OutfitStudio.cpp:1571\n#: src/program/OutfitStudio.cpp:1607 src/program/OutfitStudio.cpp:1618\n#: src/program/OutfitStudio.cpp:1628 src/program/OutfitStudio.cpp:1637\n#: src/program/OutfitStudio.cpp:1648 src/program/OutfitStudio.cpp:1659\n#: src/program/OutfitStudio.cpp:1671 src/program/OutfitStudio.cpp:1710\n#: src/program/OutfitStudio.cpp:1718 src/program/OutfitStudio.cpp:1725\n#: src/program/OutfitStudio.cpp:1761 src/program/OutfitStudio.cpp:1769\n#: src/program/OutfitStudio.cpp:1776 src/program/OutfitStudio.cpp:1786\n#: src/program/OutfitStudio.cpp:1795 src/program/OutfitStudio.cpp:1803\n#: src/program/OutfitStudio.cpp:1810 src/program/OutfitStudio.cpp:1821\n#: src/program/OutfitStudio.cpp:1830 src/program/OutfitStudio.cpp:1837\n#: src/program/OutfitStudio.cpp:2112 src/program/OutfitStudio.cpp:2146\n#: src/program/OutfitStudio.cpp:2161 src/program/OutfitStudio.cpp:2247\n#: src/program/OutfitStudio.cpp:2256 src/program/OutfitStudio.cpp:2264\n#: src/program/OutfitStudio.cpp:2278 src/program/OutfitStudio.cpp:2287\n#: src/program/OutfitStudio.cpp:2293 src/program/OutfitStudio.cpp:2327\n#: src/program/OutfitStudio.cpp:3745 src/program/OutfitStudio.cpp:3752\n#: src/program/OutfitStudio.cpp:4404 src/program/OutfitStudio.cpp:4423\n#: src/program/OutfitStudio.cpp:4489 src/program/OutfitStudio.cpp:4525\n#: src/program/OutfitStudio.cpp:4544 src/program/OutfitStudio.cpp:4614\n#: src/program/OutfitStudio.cpp:4650 src/program/OutfitStudio.cpp:4669\n#: src/program/OutfitStudio.cpp:4694 src/program/OutfitStudio.cpp:4744\n#: src/program/OutfitStudio.cpp:4749 src/program/OutfitStudio.cpp:4763\n#: src/program/OutfitStudio.cpp:4770 src/program/OutfitStudio.cpp:4775\n#: src/program/OutfitStudio.cpp:4786 src/program/OutfitStudio.cpp:7203\n#: src/program/OutfitStudio.cpp:7261 src/program/OutfitStudio.cpp:7267\n#: src/program/OutfitStudio.cpp:7271 src/program/OutfitStudio.cpp:7282\n#: src/program/OutfitStudio.cpp:7292 src/program/OutfitStudio.cpp:7296\n#: src/program/OutfitStudio.cpp:7313 src/program/OutfitStudio.cpp:7317\n#: src/program/OutfitStudio.cpp:7328 src/program/OutfitStudio.cpp:7338\n#: src/program/OutfitStudio.cpp:7351 src/program/OutfitStudio.cpp:7465\n#: src/program/OutfitStudio.cpp:7478 src/program/OutfitStudio.cpp:7580\n#: src/program/OutfitStudio.cpp:7585 src/program/OutfitStudio.cpp:7598\n#: src/program/OutfitStudio.cpp:7692 src/program/OutfitStudio.cpp:7696\n#: src/program/OutfitStudio.cpp:7707 src/program/OutfitStudio.cpp:7717\n#: src/program/OutfitStudio.cpp:7721 src/program/OutfitStudio.cpp:7744\n#: src/program/OutfitStudio.cpp:7753 src/program/OutfitStudio.cpp:7757\n#: src/program/OutfitStudio.cpp:7786 src/program/OutfitStudio.cpp:7790\n#: src/program/OutfitStudio.cpp:7813 src/program/OutfitStudio.cpp:7822\n#: src/program/OutfitStudio.cpp:7833 src/program/OutfitStudio.cpp:7840\n#: src/program/OutfitStudio.cpp:7851 src/program/OutfitStudio.cpp:7858\n#: src/program/OutfitStudio.cpp:7885 src/program/OutfitStudio.cpp:7936\n#: src/program/OutfitStudio.cpp:7997 src/program/OutfitStudio.cpp:8029\n#: src/program/OutfitStudio.cpp:8033 src/program/OutfitStudio.cpp:8046\n#: src/program/OutfitStudio.cpp:8050 src/program/OutfitStudio.cpp:8261\n#: src/program/OutfitStudio.cpp:8428 src/program/OutfitStudio.cpp:8447\n#: src/program/OutfitStudio.cpp:8531 src/program/OutfitStudio.cpp:8555\n#: src/program/OutfitStudio.cpp:8593 src/program/OutfitStudio.cpp:8745\n#: src/program/OutfitStudio.cpp:8934 src/program/OutfitStudio.cpp:9086\n#: src/program/OutfitStudio.cpp:9262 src/program/OutfitStudio.cpp:9317\n#: src/program/OutfitStudio.cpp:9531 src/program/OutfitStudio.cpp:9541\n#: src/program/OutfitStudio.cpp:9582 src/program/OutfitStudio.cpp:9587\n#: src/program/OutfitStudio.cpp:9596 src/program/OutfitStudio.cpp:9612\n#: src/program/OutfitStudio.cpp:9617 src/program/OutfitStudio.cpp:9785\n#: src/program/OutfitStudio.cpp:9793 src/program/OutfitStudio.cpp:9834\n#: src/program/OutfitStudio.cpp:10156 src/program/OutfitStudio.cpp:10161\n#: src/program/OutfitStudio.cpp:10247 src/program/OutfitStudio.cpp:10252\n#: src/program/OutfitStudio.cpp:10340 src/program/OutfitStudio.cpp:10346\n#: src/program/OutfitStudio.cpp:10351 src/program/OutfitStudio.cpp:10358\n#: src/program/OutfitStudio.cpp:10385 src/program/OutfitStudio.cpp:10430\n#: src/program/OutfitStudio.cpp:10481 src/program/OutfitStudio.cpp:10486\n#: src/program/OutfitStudio.cpp:10520 src/program/OutfitStudio.cpp:10732\n#: src/program/OutfitStudio.cpp:10782 src/program/OutfitStudio.cpp:10889\n#: src/program/OutfitStudio.cpp:11031 src/program/OutfitStudio.cpp:11115\n#: src/program/OutfitStudio.cpp:12499 src/program/OutfitStudio.cpp:12819\n#: src/program/OutfitStudio.cpp:12856 src/program/OutfitStudio.cpp:12861\n#: src/program/OutfitStudio.cpp:12873 src/program/OutfitStudio.cpp:14209\nmsgid \"Error\"\nmsgstr \"Fehler\"\n\n#: src/program/BodySlideApp.cpp:1535 src/program/OutfitStudio.cpp:667\nmsgid \"\"\n\"Failed to find game install path registry key or GameDataPath in the config.\"\nmsgstr \"\"\n\"Konnte den Registry-Key des Spielpfades oder den GameDataPath in der \"\n\"Konfiguration nicht finden.\"\n\n#: src/program/BodySlideApp.cpp:1781 src/program/OutfitStudio.cpp:913\n#, c-format\nmsgid \"System language '%d' is wrong.\"\nmsgstr \"Systemsprache '%d' ist ungültig.\"\n\n#: src/program/BodySlideApp.cpp:1790 src/program/OutfitStudio.cpp:922\n#, c-format\nmsgid \"\"\n\"The system language '%d' is not supported by your system. Try installing \"\n\"support for this language.\"\nmsgstr \"\"\n\"Die Systemsprache '%d' wird nicht von Ihrem System unterstützt. Sie können \"\n\"versuchen, die Unterstützung der Sprache zu installieren.\"\n\n#: src/program/BodySlideApp.cpp:1868\nmsgid \"Failed to create group file.\"\nmsgstr \"Konnte Gruppen-Datei nicht erstellen.\"\n\n#: src/program/BodySlideApp.cpp:1882\nmsgid \"\"\n\"That group already exists in the specified file, do you wish to overwrite \"\n\"the group?\"\nmsgstr \"\"\n\"Diese Gruppe existiert bereits in der angegebenen Datei, willst du sie \"\n\"überschreiben?\"\n\n#: src/program/BodySlideApp.cpp:1882\nmsgid \"Group already exists\"\nmsgstr \"Gruppe existiert bereits\"\n\n#: src/program/BodySlideApp.cpp:2062\nmsgid \"\"\n\"WARNING: Game data path not configured. Would you like to show BodySlide \"\n\"where it is?\"\nmsgstr \"\"\n\"WARNUNG: Spieldaten-Pfad nicht konfiguriert. Möchtest du BodySlide zeigen, \"\n\"wo dieser ist?\"\n\n#: src/program/BodySlideApp.cpp:2063 src/program/BodySlideApp.cpp:2386\n#: src/program/BodySlideApp.cpp:2391\nmsgid \"Game not found\"\nmsgstr \"Spiel nicht gefunden\"\n\n#: src/program/BodySlideApp.cpp:2071\nmsgid \"Please choose a directory to set as your Data path\"\nmsgstr \"Bitte wählen Sie ein Verzeichnis für den Spieldaten-Pfad\"\n\n#: src/program/BodySlideApp.cpp:2089\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folder, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"WARNUNG: Dies wird die Ausgabedateien vom Ausgabeordner löschen, was \"\n\"potenziell zu Problem führen kann.\\n\"\n\"\\n\"\n\"Willst du fortsetzen?\"\n\n#: src/program/BodySlideApp.cpp:2090\nmsgid \"Clean Build\"\nmsgstr \"Säuberungs-Erstellung\"\n\n#: src/program/BodySlideApp.cpp:2098\nmsgid \"Removed the following files:\\n\"\nmsgstr \"Folgende Dateien wurden entfernt:\\n\"\n\n#: src/program/BodySlideApp.cpp:2110 src/program/BodySlideApp.cpp:2123\nmsgid \" (no action)\\n\"\nmsgstr \" (keine Aktion)\\n\"\n\n#: src/program/BodySlideApp.cpp:2114 src/program/BodySlideApp.cpp:2126\n#: src/program/BodySlideApp.cpp:2357\nmsgid \"Process Successful\"\nmsgstr \"Prozess erfolgreich\"\n\n#: src/program/BodySlideApp.cpp:2244\n#, c-format\nmsgid \"\"\n\"Failed to write TRI file to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Konnte TRI-Datei nicht an die folgende Stelle schreiben\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/BodySlideApp.cpp:2244 src/program/BodySlideApp.cpp:2300\n#: src/program/BodySlideApp.cpp:2335\nmsgid \"Unable to process\"\nmsgstr \"Konnte nicht verarbeitet werden\"\n\n#: src/program/BodySlideApp.cpp:2300 src/program/BodySlideApp.cpp:2335\n#, c-format\nmsgid \"\"\n\"Failed to build set to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Konnte das Set nicht an der folgenden Stelle erstellen\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/BodySlideApp.cpp:2302 src/program/BodySlideApp.cpp:2337\nmsgid \"Choose alternate file name\"\nmsgstr \"Wählen Sie einen alternativen Dateinamen\"\n\n#: src/program/BodySlideApp.cpp:2349\nmsgid \"Successfully processed the following files:\\n\"\nmsgstr \"Erfolgreich die folgenden Dateien verarbeitet:\\n\"\n\n#: src/program/BodySlideApp.cpp:2371\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folders, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"WARNUNG: Dies wird die Ausgabedateien aus den Ausgabeordnern löschen, was \"\n\"potenziell zu Problem führen kann.\\n\"\n\"\\n\"\n\"Willst du fortsetzen?\"\n\n#: src/program/BodySlideApp.cpp:2372\nmsgid \"Clean Batch Build\"\nmsgstr \"Säuberungs-Batch-Erstellung\"\n\n#: src/program/BodySlideApp.cpp:2386\nmsgid \"\"\n\"WARNING: Game data path not configured. Files can't be removed that way.\"\nmsgstr \"\"\n\"WARNUNG: Spieldaten-Pfad ist nicht konfiguriert. Dateien können so nicht \"\n\"entfernt werden.\"\n\n#: src/program/BodySlideApp.cpp:2390\nmsgid \"\"\n\"WARNING: Game data path not configured. Continue saving files to the working \"\n\"directory?\"\nmsgstr \"\"\n\"WARNUNG: Spieldaten-Pfad nicht konfiguriert. Dateien stattdessen in das \"\n\"Arbeitsverzeichnis speichern?\"\n\n#: src/program/BodySlideApp.cpp:2519\nmsgid \"Processing Outfits\"\nmsgstr \"Verarbeite Outfits\"\n\n#: src/program/BodySlideApp.cpp:2519 src/program/OutfitStudio.h:1075\nmsgid \"Starting...\"\nmsgstr \"Starten...\"\n\n#: src/program/BodySlideApp.cpp:2531\n#, c-format\nmsgid \"Processing '%s' (%d of %d)...\"\nmsgstr \"Verarbeite '%s' (%d von %d)...\"\n\n#: src/program/BodySlideApp.cpp:2539\nmsgid \"No recorded outfit name source\"\nmsgstr \"Keine aufgenommene Outfitnamen-Quelle\"\n\n#: src/program/BodySlideApp.cpp:2550\nmsgid \"Unable to get slider set from file: \"\nmsgstr \"Konnte Slider Set nicht aus Datei bekommen: \"\n\n#: src/program/BodySlideApp.cpp:2555\nmsgid \"Unable to open slider set file: \"\nmsgstr \"Konnte Slider Set Datei nicht öffnen: \"\n\n#: src/program/BodySlideApp.cpp:2590\nmsgid \"Unable to load input nif: \"\nmsgstr \"Konnte Eingabe NIF nicht lesen: \"\n\n#: src/program/BodySlideApp.cpp:2795\nmsgid \"Unable to create destination directory: \"\nmsgstr \"Konnte Ziel-Verzeichnis nicht erstellen: \"\n\n#: src/program/BodySlideApp.cpp:2872 src/program/BodySlideApp.cpp:2880\n#: src/program/BodySlideApp.cpp:2891\nmsgid \"Unable to save nif file: \"\nmsgstr \"Konnte NIF-Datei nicht speichern: \"\n\n#: src/program/BodySlideApp.cpp:2965 src/program/BodySlideApp.cpp:4088\nmsgid \"The following sets failed\"\nmsgstr \"Die folgenden Sets sind fehlgeschlagen\"\n\n#: src/program/BodySlideApp.cpp:2965 src/program/BodySlideApp.cpp:4088\nmsgid \"Failed\"\nmsgstr \"Fehlgeschlagen\"\n\n#: src/program/BodySlideApp.cpp:3037\nmsgid \"Failed to load BodySlide.xrc file!\"\nmsgstr \"Konnte die BodySlide.xrc Datei nicht laden!\"\n\n#: src/program/BodySlideApp.cpp:3044\nmsgid \"Failed to load BodySlide frame!\"\nmsgstr \"Konnte das BodySlide-Fenster nicht laden!\"\n\n#: src/program/BodySlideApp.cpp:3077\nmsgid \"Filter groups...\"\nmsgstr \"Gruppen filtern...\"\n\n#: src/program/BodySlideApp.cpp:3083\nmsgid \"Filter outfits...\"\nmsgstr \"Outfits filtern...\"\n\n#: src/program/BodySlideApp.cpp:3089\nmsgid \"Filter sliders...\"\nmsgstr \"Slider filtern...\"\n\n#: src/program/BodySlideApp.cpp:3727\nmsgid \"Choose groups to filter outfit list\"\nmsgstr \"Wählen Sie Gruppen zum Filtern der Outfitliste\"\n\n#: src/program/BodySlideApp.cpp:3727\nmsgid \"Choose Groups\"\nmsgstr \"Gruppen auswählen\"\n\n#: src/program/BodySlideApp.cpp:3759\nmsgid \"Choose or create group file\"\nmsgstr \"Wählen Sie oder erstelle eine Gruppen-Datei\"\n\n#: src/program/BodySlideApp.cpp:3772\nmsgid \"What would you like the new group to be called?\"\nmsgstr \"Wie möchten Sie die neue Gruppe nennen?\"\n\n#: src/program/BodySlideApp.cpp:3772\nmsgid \"New Group Name\"\nmsgstr \"Neuer Gruppenname\"\n\n#: src/program/BodySlideApp.cpp:3818\nmsgid \"Do you really wish to delete the selected project?\"\nmsgstr \"\"\n\"Sind Sie sich sicher, dass Sie das ausgewählte Projekt löschen möchten?\"\n\n#: src/program/BodySlideApp.cpp:3818\nmsgid \"Delete Project\"\nmsgstr \"Projekt löschen\"\n\n#: src/program/BodySlideApp.cpp:3827\nmsgid \"Do you really wish to delete the selected preset?\"\nmsgstr \"Sind Sie sich sicher, dass Sie das ausgwählte Preset löschen möchten?\"\n\n#: src/program/BodySlideApp.cpp:3827\nmsgid \"Delete Preset\"\nmsgstr \"Preset löschen\"\n\n#: src/program/BodySlideApp.cpp:3849 src/program/OutfitStudio.cpp:7261\n#, c-format\nmsgid \"Failed to save preset (%d)!\"\nmsgstr \"Konnte Preset nicht speichern (%d)!\"\n\n#: src/program/BodySlideApp.cpp:3877\n#, c-format\nmsgid \"Failed to save preset as '%s' (%d)!\"\nmsgstr \"Konnte Preset nicht als '%s' speichern (%d)!\"\n\n#: src/program/BodySlideApp.cpp:4063\nmsgid \"Choose a folder to contain the saved files\"\nmsgstr \"Wählen Sie einen Ordner, der die gespeicherten Dateien beinhalten soll\"\n\n#: src/program/BodySlideApp.cpp:4078\nmsgid \"All sets processed successfully!\"\nmsgstr \"Alle Sets erfolgreich vearbeitet!\"\n\n#: src/program/BodySlideApp.cpp:4078\nmsgid \"Complete\"\nmsgstr \"Abgeschlossen\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:121\nmsgid \"Starting conversion...\"\nmsgstr \"Starte Konvertierung...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:139\nmsgid \"Updating Project Output Settings\"\nmsgstr \"Aktualisiere Projektausgabe-Einstellungen\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:178\nmsgid \"Deleting Shapes...\"\nmsgstr \"Lösche Modelle...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:199\nmsgid \"Loading conversion reference...\"\nmsgstr \"Lade Konvertierungsreferenz...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:209\n#: src/program/ConvertBodyReferenceDialog.cpp:253\nmsgid \"Conforming outfit parts...\"\nmsgstr \"Übertrage Slider...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:216\nmsgid \"Updating conversion Slider...\"\nmsgstr \"Aktualisiere Konvertierungs-Slider...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:220\nmsgid \"Setting the base shape and removing the conversion reference\"\nmsgstr \"Basismodell setzen und Konvertierungsreferenz entfernen\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:227\nmsgid \"Skipping conversion reference...\"\nmsgstr \"Überspringe Konvertierungsreferenz...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:232\nmsgid \"Loading new reference...\"\nmsgstr \"Lade neue Referenz...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:246\nmsgid \"Copying bones...\"\nmsgstr \"Kopiere Bones...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:260\nmsgid \"Adding Bones...\"\nmsgstr \"Füge Bones hinzu...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:289\nmsgid \"Conversion finished.\"\nmsgstr \"Konvertierung abgeschlossen.\"\n\n#: src/program/EditUV.cpp:519 src/program/OutfitStudio.cpp:11603\nmsgid \"Outfit Studio: OpenGL context is not OK.\"\nmsgstr \"Outfit Studio: OpenGL-Kontext ist nicht OK.\"\n\n#: src/program/EditUV.cpp:519 src/program/OutfitStudio.cpp:11603\n#: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:33\n#: src/render/GLSurface.cpp:2116 src/render/GLSurface.cpp:2133\nmsgid \"OpenGL Error\"\nmsgstr \"OpenGL Fehler\"\n\n#: src/program/FBXImportDialog.cpp:161 src/program/ObjImportDialog.cpp:168\n#: src/program/OutfitStudio.cpp:9582 src/program/OutfitStudio.cpp:12856\nmsgid \"The shape has reached the vertex count limit.\"\nmsgstr \"Das Modell hat das Vertex-Limit erreicht.\"\n\n#: src/program/FBXImportDialog.cpp:165 src/program/ObjImportDialog.cpp:172\n#: src/program/OutfitStudio.cpp:9587 src/program/OutfitStudio.cpp:12861\nmsgid \"The shape has reached the triangle count limit.\"\nmsgstr \"Das Modell hat das Triangle-Limit erreicht.\"\n\n#: src/program/GroupManager.cpp:143\nmsgid \"Please enter a new unique name for the group.\"\nmsgstr \"Bitte geben Sie einen neuen, einzigartigen Namen für die Gruppe ein.\"\n\n#: src/program/GroupManager.cpp:143\nmsgid \"Rename Group\"\nmsgstr \"Gruppe umbenennen\"\n\n#: src/program/GroupManager.cpp:323\nmsgid \"Save changes to group file?\"\nmsgstr \"Änderungen in Gruppen-Datei speichern?\"\n\n#: src/program/GroupManager.cpp:323\nmsgid \"Save Changes\"\nmsgstr \"Änderungen speichern\"\n\n#: src/program/NormalsGenDialog.cpp:90\nmsgid \"Enter a name for the new layer.\"\nmsgstr \"Geben Sie einen Namen für die neue Ebene ein.\"\n\n#: src/program/NormalsGenDialog.cpp:90\nmsgid \"Name new layer\"\nmsgstr \"Neue Ebene benennen\"\n\n#: src/program/NormalsGenDialog.cpp:205\nmsgid \"Choose a normals generator preset file...\"\nmsgstr \"Normal-Generator Voreinstellungsdatei auswählen...\"\n\n#: src/program/NormalsGenDialog.cpp:222\nmsgid \"Save normals generator preset to...\"\nmsgstr \"Normal-Generator Voreinstellung speichern nach...\"\n\n#: src/program/NormalsGenDialog.cpp:240\nmsgid \"Layer\"\nmsgstr \"Ebene\"\n\n#: src/program/NormalsGenDialog.cpp:263\nmsgid \"Background File\"\nmsgstr \"Hintergrunddatei\"\n\n#: src/program/NormalsGenDialog.cpp:264\nmsgid \"File source for this layer.\"\nmsgstr \"Dateiquelle für diese Ebene.\"\n\n#: src/program/NormalsGenDialog.cpp:265\nmsgid \"Color\"\nmsgstr \"Farbe\"\n\n#: src/program/NormalsGenDialog.cpp:266\nmsgid \"Solid background color (if file is not set).\"\nmsgstr \"Einheitliche Hintergrundfarbe (wenn Datei nicht gesetzt).\"\n\n#: src/program/NormalsGenDialog.cpp:267\nmsgid \"Resolution\"\nmsgstr \"Auflösung\"\n\n#: src/program/NormalsGenDialog.cpp:269\nmsgid \"\"\n\"Output texture dimensions. By default all images will be scaled to fit this \"\n\"size.\"\nmsgstr \"\"\n\"Dimensionen der Ausgabetextur. Standardmäßig werden alle Texturen auf diese \"\n\"Größe angepasst.\"\n\n#: src/program/NormalsGenDialog.cpp:286\nmsgid \"\"\n\"File containing normals data to combine. Note this file should fit the mesh \"\n\"UVs.\"\nmsgstr \"\"\n\"Datei mit den zu kombinierenden Normals-Daten. Diese Datei sollte an die UVs \"\n\"des Modells angepasst sein.\"\n\n#: src/program/NormalsGenDialog.cpp:288\nmsgid \"Is Tangent Space?\"\nmsgstr \"Ist Tangent Space?\"\n\n#: src/program/NormalsGenDialog.cpp:289\nmsgid \"\"\n\"True if the normals data in the layer file is in tangent space, false if \"\n\"they are in model space (msn).\"\nmsgstr \"\"\n\"Ja, wenn die Normals-Daten in der Schichtdatei im Tangent Space ist. Nein, \"\n\"wenn sie im Model Space (msn) ist.\"\n\n#: src/program/NormalsGenDialog.cpp:292\nmsgid \"A greyscale image used to mask updates to destination image.\"\nmsgstr \"Graustufenbild um Änderungen an der Ausgabetextur zur maskieren.\"\n\n#: src/program/NormalsGenDialog.cpp:294\nmsgid \"X Offset\"\nmsgstr \"X-Verschiebung\"\n\n#: src/program/NormalsGenDialog.cpp:295 src/program/NormalsGenDialog.cpp:298\nmsgid \"Offset to apply to image position.\"\nmsgstr \"Verschiebung der Bildposition.\"\n\n#: src/program/NormalsGenDialog.cpp:297\nmsgid \"Y Offset\"\nmsgstr \"Y-Verschiebung\"\n\n#: src/program/NormalsGenDialog.cpp:301\nmsgid \"If true, scale image to match background resolution.\"\nmsgstr \"Wenn ja, wird das Bild an die Hintergrundauflösung angepasst.\"\n\n#: src/program/OutfitProject.cpp:53\nmsgid \"Checking destination...\"\nmsgstr \"Überprüfe Ziel...\"\n\n#: src/program/OutfitProject.cpp:113\nmsgid \"Adding reference shapes...\"\nmsgstr \"Füge Referenzmodelle hinzu...\"\n\n#: src/program/OutfitProject.cpp:134 src/program/OutfitProject.cpp:2245\nmsgid \"Adding outfit shapes...\"\nmsgstr \"Füge Outfit-Modelle hinzu...\"\n\n#: src/program/OutfitProject.cpp:193\nmsgid \"Calculating slider data...\"\nmsgstr \"Berechne Sliderdaten...\"\n\n#: src/program/OutfitProject.cpp:201\nmsgid \"Creating slider set file...\"\nmsgstr \"Erstelle Slider Set Datei...\"\n\n#: src/program/OutfitProject.cpp:208\nmsgid \"Failed to open or create slider set file: \"\nmsgstr \"Konnte Slider Set Datei nicht öffnen oder erstellen: \"\n\n#: src/program/OutfitProject.cpp:215\nmsgid \"Saving slider set file...\"\nmsgstr \"Speichere Slider Set Datei...\"\n\n#: src/program/OutfitProject.cpp:218\nmsgid \"Failed to write to slider set file: \"\nmsgstr \"Konnte Slider Set Datei nicht schreiben: \"\n\n#: src/program/OutfitProject.cpp:222\nmsgid \"Saving NIF file...\"\nmsgstr \"Speichere NIF-Datei...\"\n\n#: src/program/OutfitProject.cpp:252\nmsgid \"Failed to write base .nif file: \"\nmsgstr \"Konnte Basis NIF-Datei nicht schreiben: \"\n\n#: src/program/OutfitProject.cpp:258 src/program/OutfitProject.cpp:1700\n#: src/program/OutfitProject.cpp:1730 src/program/OutfitStudio.cpp:3608\nmsgid \"Finished\"\nmsgstr \"Abgeschlossen\"\n\n#: src/program/OutfitProject.cpp:1594 src/program/OutfitProject.cpp:1686\nmsgid \"Gathering bones...\"\nmsgstr \"Sammle Bones...\"\n\n#: src/program/OutfitProject.cpp:1622\nmsgid \"Initializing proximity data...\"\nmsgstr \"Initialisiere Umgebungsdaten...\"\n\n#: src/program/OutfitProject.cpp:1668 src/program/OutfitStudio.cpp:10180\nmsgid \"Copying bone weights...\"\nmsgstr \"Kopiere Bone Weighting...\"\n\n#: src/program/OutfitProject.cpp:1706 src/program/OutfitStudio.cpp:10371\nmsgid \"Transferring bone weights...\"\nmsgstr \"Transferiere Bone Weighting...\"\n\n#: src/program/OutfitProject.cpp:1951\nmsgid \"Template source entries are invalid.\"\nmsgstr \"Vorlagen Quelleinträge sind ungültig.\"\n\n#: src/program/OutfitProject.cpp:1951 src/program/OutfitProject.cpp:1981\n#: src/program/OutfitProject.cpp:1986 src/program/OutfitProject.cpp:2031\n#: src/program/OutfitProject.cpp:2053 src/program/OutfitProject.cpp:2060\n#: src/program/OutfitProject.cpp:2070 src/program/OutfitProject.cpp:2082\nmsgid \"Reference Error\"\nmsgstr \"Referenz Fehler\"\n\n#: src/program/OutfitProject.cpp:1978 src/program/OutfitProject.cpp:2050\n#: src/program/OutfitProject.cpp:4637\n#, c-format\nmsgid \"\"\n\"NIF version not supported!\\n\"\n\"\\n\"\n\"File: %s\\n\"\n\"%s\"\nmsgstr \"\"\n\"NIF-Version wird nicht unterstützt!\\n\"\n\"\\n\"\n\"Datei: %s\\n\"\n\"%s\"\n\n#: src/program/OutfitProject.cpp:1986 src/program/OutfitProject.cpp:2060\n#, c-format\nmsgid \"Could not load reference NIF file '%s'!\"\nmsgstr \"Konnte Referenz NIF-Datei '%s' nicht laden!\"\n\n#: src/program/OutfitProject.cpp:2031\n#, c-format\nmsgid \"Could not load slider set file '%s'!\"\nmsgstr \"Konnte Slider Set Datei '%s' nicht laden!\"\n\n#: src/program/OutfitProject.cpp:2070\n#, c-format\nmsgid \"Reference NIF file '%s' does not contain any shapes.\"\nmsgstr \"Referenz NIF-Datei '%s' beinhaltet keine Modelle.\"\n\n#: src/program/OutfitProject.cpp:2082\n#, c-format\nmsgid \"Shape '%s' not found in reference NIF file '%s'!\"\nmsgstr \"\"\n\"Modell '%s' konnte nicht in der Referenz NIF-Datei '%s' gefunden werden!\"\n\n#: src/program/OutfitProject.cpp:2142\nmsgid \"Loading slider set...\"\nmsgstr \"Lade Slider Set...\"\n\n#: src/program/OutfitProject.cpp:2149 src/program/OutfitProject.cpp:2235\nmsgid \"Retrieving sliders...\"\nmsgstr \"Rufe Slider ab...\"\n\n#: src/program/OutfitProject.cpp:2159\nmsgid \"Loading outfit shapes...\"\nmsgstr \"Lade Outfit-Modelle...\"\n\n#: src/program/OutfitProject.cpp:2202 src/program/OutfitProject.cpp:2301\nmsgid \"Updating slider data...\"\nmsgstr \"Aktualisiere Sliderdaten...\"\n\n#: src/program/OutfitProject.cpp:2227\nmsgid \"Adding slider set...\"\nmsgstr \"Füge Slider Set hinzu...\"\n\n#: src/program/OutfitProject.cpp:2294\nmsgid \"\"\n\"The following shapes were renamed and won't have slider data attached. \"\n\"Rename the duplicates yourself beforehand.\"\nmsgstr \"\"\n\"Die folgenden Modelle wurden umbenannt und werden keine Sliderdaten haben. \"\n\"Die Duplikate müssen vorher umbenannt werden.\"\n\n#: src/program/OutfitProject.cpp:2296\nmsgid \"Renamed Shapes\"\nmsgstr \"Umbenannte Modelle\"\n\n#: src/program/OutfitProject.cpp:4640 src/program/OutfitProject.cpp:4645\nmsgid \"NIF Error\"\nmsgstr \"NIF Fehler\"\n\n#: src/program/OutfitProject.cpp:4645\n#, c-format\nmsgid \"Could not load NIF file '%s'!\"\nmsgstr \"Konnte NIF-Datei '%s' nicht laden!\"\n\n#: src/program/OutfitProject.cpp:4777\nmsgid \"\"\n\"There was cloth physics data loaded at some point (BSClothExtraData). Please \"\n\"choose all the origins to use in the output.\"\nmsgstr \"\"\n\"Es wurden zu einem bestimmten Punkt Physikdaten geladen (BSClothExtraData). \"\n\"Bitte wählen Sie alle, die in der Ausgabe verwendet werden sollen.\"\n\n#: src/program/OutfitProject.cpp:4778\nmsgid \"Choose cloth data\"\nmsgstr \"Physikdaten auswählen\"\n\n#: src/program/OutfitProject.cpp:4848\nmsgid \"\"\n\"No reference has been loaded.  For correct bone transforms, you might need \"\n\"to load a reference before importing OBJ files.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:4856\n#, c-format\nmsgid \"Could not load OBJ file '%s'!\"\nmsgstr \"Konnte OBJ-Datei '%s' nicht laden!\"\n\n#: src/program/OutfitProject.cpp:4856 src/program/OutfitProject.cpp:4880\n#: src/program/OutfitProject.cpp:4942 src/program/OutfitProject.cpp:5108\nmsgid \"OBJ Error\"\nmsgstr \"OBJ Fehler\"\n\n#: src/program/OutfitProject.cpp:4862 src/program/OutfitProject.cpp:5027\nmsgid \"\"\n\"The reference shape has a skin coordinate system that is different from the \"\n\"global coordinate system.  Would you like to copy the reference's global-to-\"\n\"skin transform to the imported shapes?\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:4864 src/program/OutfitProject.cpp:5029\nmsgid \"Copy skin coordinates\"\nmsgstr \"Skin-Koordinaten kopieren\"\n\n#: src/program/OutfitProject.cpp:4880\n#, c-format\nmsgid \"Could not copy data from OBJ file '%s'!\"\nmsgstr \"Konnte Daten nicht von OBJ-Datei '%s' kopieren!\"\n\n#: src/program/OutfitProject.cpp:4897\nmsgid \"\"\n\"The vertex count of the selected .obj file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"Die Anzahl an Vertices der ausgewählten OBJ-Datei stimmt nicht mit der des \"\n\"derzeit ausgewählten Outfit-Modells überein. Möchten Sie das aktuelle Modell \"\n\"aktualisieren? ('Nein' zum Erstellen eines neuen Modells)\"\n\n#: src/program/OutfitProject.cpp:4899 src/program/OutfitProject.cpp:5055\nmsgid \"Merge or New\"\nmsgstr \"Verschmelzen oder neu\"\n\n#: src/program/OutfitProject.cpp:4903 src/program/OutfitProject.cpp:5059\nmsgid \"Update Vertex Positions?\"\nmsgstr \"Vertex-Positionen aktualisieren?\"\n\n#: src/program/OutfitProject.cpp:4903 src/program/OutfitProject.cpp:5059\nmsgid \"Vertex Position Update\"\nmsgstr \"Vertex-Positionen Aktualisierung\"\n\n#: src/program/OutfitProject.cpp:4908 src/program/OutfitProject.cpp:5064\nmsgid \"Update Texture Coordinates?\"\nmsgstr \"Texturkoordinaten aktualisieren?\"\n\n#: src/program/OutfitProject.cpp:4908 src/program/OutfitProject.cpp:5064\nmsgid \"UV Update\"\nmsgstr \"UV Aktualisierung\"\n\n#: src/program/OutfitProject.cpp:4914 src/program/OutfitProject.cpp:5070\nmsgid \"Update Normals?\"\nmsgstr \"Normals aktualisieren?\"\n\n#: src/program/OutfitProject.cpp:4914 src/program/OutfitProject.cpp:5070\nmsgid \"Normals Update\"\nmsgstr \"Normals Aktualisierung\"\n\n#: src/program/OutfitProject.cpp:4924 src/program/OutfitProject.cpp:5086\nmsgid \"Please specify a name for the new shape\"\nmsgstr \"Bitte geben Sie einen Namen für das neue Modell an\"\n\n#: src/program/OutfitProject.cpp:4924 src/program/OutfitProject.cpp:5086\nmsgid \"New Shape Name\"\nmsgstr \"Neuer Modellname\"\n\n#: src/program/OutfitProject.cpp:4935 src/program/OutfitProject.cpp:5101\n#, c-format\nmsgid \"\"\n\"The vertex or triangle limit for '%s' was exceeded.\\n\"\n\"Remaining data was dropped.\\n\"\n\"\\n\"\n\"Vertices (current/max): %zu/%zu\\n\"\n\"Triangles (current/max): %zu/%zu\"\nmsgstr \"\"\n\"Das Vertex- oder Triangle Limit für '%s' wurde überschritten.\\n\"\n\"Die übrigen Daten wurden entfernt.\\n\"\n\"\\n\"\n\"Vertices (current/max): %zu/%zu\\n\"\n\"Triangles (current/max): %zu/%zu\"\n\n#: src/program/OutfitProject.cpp:5015\nmsgid \"\"\n\"No reference has been loaded.  For correct bone transforms, you might need \"\n\"to load a reference before importing FBX files.\"\nmsgstr \"\"\n\n#: src/program/OutfitProject.cpp:5053\nmsgid \"\"\n\"The vertex count of the selected .fbx file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"Die Anzahl an Vertices der ausgewählten FBX-Datei stimmt nicht mit der des \"\n\"derzeit ausgewählten Outfit-Modells überein. Möchten Sie das aktuelle Modell \"\n\"aktualisieren? ('Nein' zum Erstellen eines neuen Modells)\"\n\n#: src/program/OutfitProject.cpp:5077\nmsgid \"Update Animation Weighting?\"\nmsgstr \"Animationen-Weighting aktualisieren?\"\n\n#: src/program/OutfitProject.cpp:5077\nmsgid \"Animation Weight Update\"\nmsgstr \"Animationen-Weighting Aktualisierung\"\n\n#: src/program/OutfitProject.cpp:5226\nmsgid \"Would you like Skyrim NIFs to be optimized for SSE during this session?\"\nmsgstr \"Sollen Skyrim NIFs während dieser Session für SSE optimiert werden?\"\n\n#: src/program/OutfitProject.cpp:5243\nmsgid \"\"\n\"File format doesn't match the current game. Use FBX export, then start a new \"\n\"project and import the FBX file there.\"\nmsgstr \"\"\n\"Dateiformat stimmt nicht mit dem aktuellen Spiel überein. Bitte FBX-Export \"\n\"verwenden, dann ein neues Projekt öffnen und die FBX-Datei dort importieren.\"\n\n#: src/program/OutfitProject.cpp:5244\nmsgid \"Version\"\nmsgstr \"Version\"\n\n#: src/program/OutfitProject.cpp:5257\n#, c-format\nmsgid \"Unable to locate external mesh data for shape. Expected path: %s\"\nmsgstr \"Konnte externe Mesh-Daten für Modell nicht laden. Erwarteter Pfad: %s\"\n\n#: src/program/OutfitProject.cpp:5258\nmsgid \"External Mesh Data Load Failure\"\nmsgstr \"Ladefehler externer Mesh-Daten\"\n\n#: src/program/OutfitProject.cpp:5368\nmsgid \"No Bad Bones Found.\"\nmsgstr \"Keine mangelhaften Bones gefunden.\"\n\n#: src/program/OutfitProject.cpp:5368\nmsgid \"No Bad Bones\"\nmsgstr \"Keine mangelhaften Bones\"\n\n#: src/program/OutfitProject.cpp:5483\nmsgid \"Bad Bones\"\nmsgstr \"Mangelhafte Bones\"\n\n#: src/program/OutfitProject.cpp:5504\nmsgid \"Error in rotation\"\nmsgstr \"Fehler in Rotation\"\n\n#: src/program/OutfitProject.cpp:5505\nmsgid \"Error in translation\"\nmsgstr \"Fehler in Position\"\n\n#: src/program/OutfitProject.cpp:5506\nmsgid \"Error in scale\"\nmsgstr \"Fehler in Skalierung\"\n\n#: src/program/OutfitProject.cpp:5533\n#, c-format\nmsgid \"Bad standard bones for shape \\\"%s\\\"\"\nmsgstr \"Mangelhafte Standard-Bones für Modell \\\"%s\\\"\"\n\n#: src/program/OutfitProject.cpp:5536\n#, c-format\nmsgid \"\"\n\"%zu bones in shape \\\"%s\\\" had inconsistencies between their NIF skin \"\n\"transforms and the standard skeleton:\\n\"\nmsgstr \"\"\n\"%zu Bones in Modell \\\"%s\\\" hatten Inkonsistenzen zwischen ihren NIF Skin-\"\n\"Transformationen und dem Standard-Skelett:\\n\"\n\n#: src/program/OutfitProject.cpp:5551\nmsgid \"Update skin (recommended)\"\nmsgstr \"Skinning aktualisieren (empfohlen)\"\n\n#: src/program/OutfitProject.cpp:5559 src/program/OutfitProject.cpp:5623\n#: src/program/OutfitProject.cpp:5646\nmsgid \"Details\"\nmsgstr \"Details\"\n\n#: src/program/OutfitProject.cpp:5559\nmsgid \"Bone\"\nmsgstr \"Bone\"\n\n#: src/program/OutfitProject.cpp:5564 src/program/OutfitProject.cpp:5660\nmsgid \"Do nothing\"\nmsgstr \"Nichts tun\"\n\n#: src/program/OutfitProject.cpp:5576\n#, c-format\nmsgid \"Bad Custom Bone \\\"%s\\\"\"\nmsgstr \"Mangelhafter benutzerdefinierter Bone \\\"%s\\\"\"\n\n#: src/program/OutfitProject.cpp:5579\n#, c-format\nmsgid \"\"\n\"Custom bone \\\"%s\\\" had inconsistent NIF node and skin transforms for the \"\n\"following shapes:\\n\"\n\"\\\"\"\nmsgstr \"\"\n\"Benutzerdefinierter Bone \\\"%s\\\" hatte inkonsistente NIF Node- und Skin-\"\n\"Transformationen für folgende Modelle:\\n\"\n\"\\\"\"\n\n#: src/program/OutfitProject.cpp:5599\nmsgid \"Trust node and skins \\\"\"\nmsgstr \"Nodes und Skinnings vertrauen \\\"\"\n\n#: src/program/OutfitProject.cpp:5601\nmsgid \"Trust node and skin \\\"\"\nmsgstr \"Node und Skinning vertrauen \\\"\"\n\n#: src/program/OutfitProject.cpp:5609\nmsgid \"\\\", and update other skins (recommended)\"\nmsgstr \"\\\", und andere Skinnings aktualisieren (empfohlen)\"\n\n#: src/program/OutfitProject.cpp:5612\nmsgid \"Trust node, and update skins\"\nmsgstr \"Node vertrauen und Skinnings aktualisieren\"\n\n#: src/program/OutfitProject.cpp:5614\nmsgid \"Trust node, and update skin\"\nmsgstr \"Node vertrauen und Skinning aktualisieren\"\n\n#: src/program/OutfitProject.cpp:5623\nmsgid \"Skin\"\nmsgstr \"Skin\"\n\n#: src/program/OutfitProject.cpp:5632\nmsgid \"Trust skin \\\"\"\nmsgstr \"Skinning vertrauen \\\"\"\n\n#: src/program/OutfitProject.cpp:5634\nmsgid \"\\\", and update node\"\nmsgstr \"\\\", und Node aktualisieren\"\n\n#: src/program/OutfitProject.cpp:5636\nmsgid \"\\\", and update node and other skins\"\nmsgstr \"\\\", und Node und andere Skinnings aktualisieren\"\n\n#: src/program/OutfitProject.cpp:5646\nmsgid \"With\"\nmsgstr \"Mit\"\n\n#: src/program/OutfitProject.cpp:5647\nmsgid \"Node\"\nmsgstr \"Node\"\n\n#: src/program/OutfitProject.cpp:5673\nmsgid \"Fix nothing\"\nmsgstr \"Nichts beheben\"\n\n#: src/program/OutfitStudio.cpp:449 src/program/OutfitStudio.cpp:450\n#: src/program/OutfitStudio.cpp:14152 src/program/OutfitStudio.cpp:14153\nmsgid \"Adding NIF file...\"\nmsgstr \"Füge NIF-Datei hinzu...\"\n\n#: src/program/OutfitStudio.cpp:454 src/program/OutfitStudio.cpp:465\n#: src/program/OutfitStudio.cpp:476 src/program/OutfitStudio.cpp:4331\n#: src/program/OutfitStudio.cpp:14157 src/program/OutfitStudio.cpp:14168\n#: src/program/OutfitStudio.cpp:14179\nmsgid \"Refreshing GUI...\"\nmsgstr \"Aktualisiere GUI...\"\n\n#: src/program/OutfitStudio.cpp:461 src/program/OutfitStudio.cpp:14164\nmsgid \"Adding OBJ file...\"\nmsgstr \"Füge OBJ-Datei hinzu...\"\n\n#: src/program/OutfitStudio.cpp:471 src/program/OutfitStudio.cpp:472\n#: src/program/OutfitStudio.cpp:14174 src/program/OutfitStudio.cpp:14175\nmsgid \"Adding FBX file...\"\nmsgstr \"Füge FBX-Datei hinzu...\"\n\n#: src/program/OutfitStudio.cpp:660\nmsgid \"\"\n\"Failed to find game install path registry value or GameDataPath in the \"\n\"config.\"\nmsgstr \"\"\n\"Konnte den Registry-Wert des Spielpfades oder den GameDataPath in der \"\n\"Konfiguration nicht finden.\"\n\n#: src/program/OutfitStudio.cpp:1001\nmsgid \"Failed to load OutfitStudio.xrc file!\"\nmsgstr \"Konnte OutfitStudio.xrc Datei nicht laden!\"\n\n#: src/program/OutfitStudio.cpp:1007\nmsgid \"Failed to load Outfit Studio frame!\"\nmsgstr \"Konnte Outfit Studio Fenster nicht laden!\"\n\n#: src/program/OutfitStudio.cpp:1025 src/program/OutfitStudio.cpp:3872\n#: src/program/OutfitStudio.h:1105\nmsgid \"Ready!\"\nmsgstr \"Bereit!\"\n\n#: src/program/OutfitStudio.cpp:1534 src/program/OutfitStudio.cpp:1539\nmsgid \"Packing projects to folder...\"\nmsgstr \"Projekte in einen Ordner packen...\"\n\n#: src/program/OutfitStudio.cpp:1560 src/program/OutfitStudio.cpp:1607\n#: src/program/OutfitStudio.cpp:1710\n#, c-format\nmsgid \"Failed to open input file '%s'!\"\nmsgstr \"Konnte Eingabedatei '%s' nicht öffnen!\"\n\n#: src/program/OutfitStudio.cpp:1571\n#, c-format\nmsgid \"Failed to copy input file '%s'!\"\nmsgstr \"Konnte Eingabedatei '%s' nicht kopieren!\"\n\n#: src/program/OutfitStudio.cpp:1618\n#, c-format\nmsgid \"Failed to copy data file '%s'!\"\nmsgstr \"Konnte Datendatei '%s' nicht kopieren!\"\n\n#: src/program/OutfitStudio.cpp:1628 src/program/OutfitStudio.cpp:1786\n#, c-format\nmsgid \"Failed to save merged project file '%s'!\"\nmsgstr \"Konnte zusammengefügte Projektdatei '%s' nicht speichern!\"\n\n#: src/program/OutfitStudio.cpp:1637 src/program/OutfitStudio.cpp:1795\n#, c-format\nmsgid \"Failed to open project file '%s'!\"\nmsgstr \"Konnte Projektdatei '%s' nicht öffnen!\"\n\n#: src/program/OutfitStudio.cpp:1648\n#, c-format\nmsgid \"Failed to copy merged project file '%s'!\"\nmsgstr \"Konnte zusammengefügte Projektdatei '%s' nicht kopieren!\"\n\n#: src/program/OutfitStudio.cpp:1659 src/program/OutfitStudio.cpp:1821\n#, c-format\nmsgid \"Failed to open group file '%s'!\"\nmsgstr \"Konnte Gruppendatei '%s' nicht öffnen!\"\n\n#: src/program/OutfitStudio.cpp:1671\n#, c-format\nmsgid \"Failed to copy group file '%s'!\"\nmsgstr \"Konnte Gruppendatei '%s' nicht kopieren!\"\n\n#: src/program/OutfitStudio.cpp:1677 src/program/OutfitStudio.cpp:1843\nmsgid \"Packing finished.\"\nmsgstr \"Packen abgeschlossen.\"\n\n#: src/program/OutfitStudio.cpp:1681 src/program/OutfitStudio.cpp:1686\nmsgid \"Packing projects to archive...\"\nmsgstr \"Projekte in ein Archiv packen...\"\n\n#: src/program/OutfitStudio.cpp:1718 src/program/OutfitStudio.cpp:1769\n#: src/program/OutfitStudio.cpp:1803 src/program/OutfitStudio.cpp:1830\nmsgid \"Failed to put new entry into archive!\"\nmsgstr \"Konnte keinen neuen Eintrag im Archiv erstellen!\"\n\n#: src/program/OutfitStudio.cpp:1725 src/program/OutfitStudio.cpp:1776\n#: src/program/OutfitStudio.cpp:1810 src/program/OutfitStudio.cpp:1837\nmsgid \"Failed to copy file contents to archive!\"\nmsgstr \"Konnte Dateiinhalt nicht in Archiv kopieren!\"\n\n#: src/program/OutfitStudio.cpp:1761\n#, c-format\nmsgid \"Failed to open data file '%s'!\"\nmsgstr \"Konnte Datendatei '%s' nicht öffnen!\"\n\n#: src/program/OutfitStudio.cpp:2112 src/program/OutfitStudio.cpp:2161\n#: src/program/OutfitStudio.cpp:3745 src/program/OutfitStudio.cpp:3752\n#: src/program/OutfitStudio.cpp:4744 src/program/OutfitStudio.cpp:4770\n#: src/program/OutfitStudio.cpp:7338 src/program/OutfitStudio.cpp:7465\n#: src/program/OutfitStudio.cpp:7580 src/program/OutfitStudio.cpp:7822\n#: src/program/OutfitStudio.cpp:7840 src/program/OutfitStudio.cpp:7858\nmsgid \"There are no valid shapes loaded!\"\nmsgstr \"Es sind keine gültigen Modelle geladen!\"\n\n#: src/program/OutfitStudio.cpp:2120 src/program/OutfitStudio.cpp:2303\n#, c-format\nmsgid \"Saving project '%s'...\"\nmsgstr \"Speichere Projekt '%s'...\"\n\n#: src/program/OutfitStudio.cpp:2147 src/program/OutfitStudio.cpp:2328\nmsgid \"Saving failed.\"\nmsgstr \"Speichern fehlgeschlagen.\"\n\n#: src/program/OutfitStudio.cpp:2152 src/program/OutfitStudio.cpp:2323\nmsgid \"Saved.\"\nmsgstr \"Gespeichert.\"\n\n#: src/program/OutfitStudio.cpp:2247\nmsgid \"Invalid or no slider set file specified! Please try again.\"\nmsgstr \"\"\n\"Ungültige oder keine Slider Set Datei angegeben! Bitte versuche es erneut.\"\n\n#: src/program/OutfitStudio.cpp:2256\nmsgid \"No outfit name specified! Please try again.\"\nmsgstr \"Kein Outfitname angegeben! Bitte versuche es erneut.\"\n\n#: src/program/OutfitStudio.cpp:2264\nmsgid \"No data folder specified! Please try again.\"\nmsgstr \"Kein Daten-Ordner angegeben! Bitte versuche es erneut.\"\n\n#: src/program/OutfitStudio.cpp:2278\nmsgid \"\"\n\"An invalid or no base outfit .nif file name specified! Please try again.\"\nmsgstr \"\"\n\"Ungültige oder keine Basis Outfit NIF-Datei angegeben! Bitte versuche es \"\n\"erneut.\"\n\n#: src/program/OutfitStudio.cpp:2287\nmsgid \"No game file path specified! Please try again.\"\nmsgstr \"Kein Spiel Dateipfad angegeben! Bitte versuche es erneut.\"\n\n#: src/program/OutfitStudio.cpp:2293\nmsgid \"No game file name specified! Please try again.\"\nmsgstr \"Kein Spiel Dateinamen angegeben! Bitte versuche es erneut.\"\n\n#: src/program/OutfitStudio.cpp:2340\n#, c-format\nmsgid \"Failed to open '%s' as a slider set file!\"\nmsgstr \"Konnte '%s' nicht als Slider Set Datei öffnen!\"\n\n#: src/program/OutfitStudio.cpp:2340 src/program/OutfitStudio.cpp:2404\nmsgid \"Slider Set Error\"\nmsgstr \"Slider Set Fehler\"\n\n#: src/program/OutfitStudio.cpp:2359\nmsgid \"Please choose an outfit to load\"\nmsgstr \"Wählen Sie bitte ein Outfit zum Laden\"\n\n#: src/program/OutfitStudio.cpp:2359\nmsgid \"Load a slider set\"\nmsgstr \"Lade ein Slider Set\"\n\n#: src/program/OutfitStudio.cpp:2370\nmsgid \"Loading project...\"\nmsgstr \"Lade Projekt...\"\n\n#: src/program/OutfitStudio.cpp:2390\nmsgid \"Loading outfit data...\"\nmsgstr \"Lade Outfit-Daten...\"\n\n#: src/program/OutfitStudio.cpp:2404\n#, c-format\nmsgid \"Failed to create project '%s' from file '%s' (%d)!\"\nmsgstr \"Konnte Projekt '%s' nicht aus Datei '%s' erstellen (%d)!\"\n\n#: src/program/OutfitStudio.cpp:2418\n#, c-format\nmsgid \"Loading reference shape '%s'...\"\nmsgstr \"Lade Referenzmodell '%s'...\"\n\n#: src/program/OutfitStudio.cpp:2432\nmsgid \"Loading textures...\"\nmsgstr \"Lade Texturen...\"\n\n#: src/program/OutfitStudio.cpp:2437 src/program/OutfitStudio.cpp:3590\n#: src/program/OutfitStudio.cpp:3835\nmsgid \"Creating outfit...\"\nmsgstr \"Erstelle Outfit...\"\n\n#: src/program/OutfitStudio.cpp:2441 src/program/OutfitStudio.cpp:3600\n#: src/program/OutfitStudio.cpp:3735\n#, c-format\nmsgid \"Creating %zu slider(s)...\"\nmsgstr \"Erstelle %zu Slider...\"\n\n#: src/program/OutfitStudio.cpp:2460\nmsgid \"Creating sliders...\"\nmsgstr \"Erstelle Slider...\"\n\n#: src/program/OutfitStudio.cpp:2463\nmsgid \"Clearing old sliders...\"\nmsgstr \"Lösche alte Slider...\"\n\n#: src/program/OutfitStudio.cpp:2474\nmsgid \"Loading slider: \"\nmsgstr \"Lade Slider: \"\n\n#: src/program/OutfitStudio.cpp:2534 src/program/OutfitStudio.cpp:7981\nmsgid \"Enter a name for the new slider:\"\nmsgstr \"Geben Sie einen Namen für den neuen Slider ein:\"\n\n#: src/program/OutfitStudio.cpp:2534 src/program/OutfitStudio.cpp:7981\nmsgid \"Create New Slider\"\nmsgstr \"Neuen Slider erstellen\"\n\n#: src/program/OutfitStudio.cpp:2668\n#, c-format\nmsgid \"Total Bones: %zu\"\nmsgstr \"Bones insgesamt: %zu\"\n\n#: src/program/OutfitStudio.cpp:2683\n#, c-format\nmsgid \"Shape Selection Bones: %zu\"\nmsgstr \"Bones Modellauswahl: %zu\"\n\n#: src/program/OutfitStudio.cpp:3183\nmsgid \"Edit Color\"\nmsgstr \"Farbe bearbeiten\"\n\n#: src/program/OutfitStudio.cpp:3349\nmsgid \"\"\n\"You are trying to edit a slider's morph with that slider set to zero.  Do \"\n\"you wish to set the slider to one now?\"\nmsgstr \"\"\n\"Sie versuchen einen Slider auf 0% zu bearbeiten.  Soll dieser auf 100% \"\n\"gesetzt werden?\"\n\n#: src/program/OutfitStudio.cpp:3366\nmsgid \"\"\n\"You can only use the undiff brush while editing a slider. Note, use the \"\n\"pencil button next to a slider to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"Sie können den Undiff Pinsel nur verwenden, während ein Slider bearbeitet \"\n\"wird. Der Pinsel-Knopf neben jedem Slider kann den Bearbeitungsmodus dieses \"\n\"aktivieren.\"\n\n#: src/program/OutfitStudio.cpp:3377\nmsgid \"\"\n\"You can only edit the base shape when all sliders are zero. Do you wish to \"\n\"set all sliders to zero now?  Note, use the pencil button next to a slider \"\n\"to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"Sie können das Basismodell nur bearbeiten, wenn alle Slider auf Null sind. \"\n\"Möchtest du jetzt alle Slider auf Null setzen? Der Pinsel-Knopf neben jedem \"\n\"Slider kann den Bearbeitungsmodus dieses aktivieren.\"\n\n#: src/program/OutfitStudio.cpp:3456\n#, c-format\nmsgid \"You have unsaved changes to '%s'. Would you like to save them now?\"\nmsgstr \"\"\n\"Es gibt ungespeicherte Änderungen an '%s'. Möchten Sie diese speichern?\"\n\n#: src/program/OutfitStudio.cpp:3457\nmsgid \"Unsaved Changes\"\nmsgstr \"Ungespeicherte Änderungen\"\n\n#: src/program/OutfitStudio.cpp:3512\n#, c-format\nmsgid \"Creating project '%s'...\"\nmsgstr \"Erstelle Projekt '%s'...\"\n\n#: src/program/OutfitStudio.cpp:3529 src/program/OutfitStudio.cpp:3673\nmsgid \"Loading reference...\"\nmsgstr \"Lade Referenz...\"\n\n#: src/program/OutfitStudio.cpp:3569 src/program/OutfitStudio.cpp:3793\n#: src/program/OutfitStudio.cpp:3802\nmsgid \"Loading outfit...\"\nmsgstr \"Lade Outfit...\"\n\n#: src/program/OutfitStudio.cpp:3615\nmsgid \"Select a slider set to load\"\nmsgstr \"Wählen Sie ein Slider Set zum Laden\"\n\n#: src/program/OutfitStudio.cpp:3632\nmsgid \"Select a slider set to add\"\nmsgstr \"Wählen Sie ein Slider Set zum Hinzufügen\"\n\n#: src/program/OutfitStudio.cpp:3649 src/program/OutfitStudio.cpp:3757\n#: src/program/OutfitStudio.cpp:9267 src/program/OutfitStudio.cpp:9322\n#: src/program/OutfitStudio.cpp:9413 src/program/OutfitStudio.cpp:9536\nmsgid \"\"\n\"You're currently editing slider data, please exit the slider's edit mode \"\n\"(pencil button) and try again.\"\nmsgstr \"\"\n\"Sie bearbeiten im Moment Sliderdaten. Bitte verlassen Sie den \"\n\"Bearbeitungsmodus des Sliders (Pinsel-Knopf) und versuchen es erneut.\"\n\n#: src/program/OutfitStudio.cpp:3679\nmsgid \"Loading reference set...\"\nmsgstr \"Lade Referenz-Set...\"\n\n#: src/program/OutfitStudio.cpp:3731\nmsgid \"Creating reference...\"\nmsgstr \"Erstelle Referenz...\"\n\n#: src/program/OutfitStudio.cpp:3845\nmsgid \"Unload the project? All unsaved changes will be lost\"\nmsgstr \"\"\n\"Wollen Sie das Projekt wirklich entladen? Alle nicht gespeicherten \"\n\"Änderungen gehen verloren\"\n\n#: src/program/OutfitStudio.cpp:3845\nmsgid \"Unload Project\"\nmsgstr \"Projekt entladen\"\n\n#: src/program/OutfitStudio.cpp:3846\nmsgid \"Unload\"\nmsgstr \"Entladen\"\n\n#: src/program/OutfitStudio.cpp:4318\nmsgid \"Import NIF file\"\nmsgstr \"NIF-Datei importieren\"\n\n#: src/program/OutfitStudio.cpp:4325 src/program/OutfitStudio.cpp:4326\nmsgid \"Importing NIF file...\"\nmsgstr \"Importiere NIF-Datei...\"\n\n#: src/program/OutfitStudio.cpp:4348\nmsgid \"Export outfit NIF\"\nmsgstr \"Outfit NIF exportieren\"\n\n#: src/program/OutfitStudio.cpp:4366\n#, c-format\nmsgid \"Failed to save NIF file '%s'!\"\nmsgstr \"Konnte NIF-Datei '%s' nicht speichern!\"\n\n#: src/program/OutfitStudio.cpp:4366 src/program/OutfitStudio.cpp:4398\n#: src/program/OutfitStudio.cpp:4483 src/program/OutfitStudio.cpp:4608\n#: src/program/OutfitStudio.cpp:4832\nmsgid \"Export Error\"\nmsgstr \"Export Fehler\"\n\n#: src/program/OutfitStudio.cpp:4382\nmsgid \"Export project NIF\"\nmsgstr \"Projekt NIF exportieren\"\n\n#: src/program/OutfitStudio.cpp:4398\n#, c-format\nmsgid \"Failed to save NIF file '%s' with reference!\"\nmsgstr \"Konnte NIF-Datei '%s' mit Referenz nicht speichern!\"\n\n#: src/program/OutfitStudio.cpp:4404 src/program/OutfitStudio.cpp:4489\n#: src/program/OutfitStudio.cpp:4614 src/program/OutfitStudio.cpp:4749\n#: src/program/OutfitStudio.cpp:4775 src/program/OutfitStudio.cpp:7267\n#: src/program/OutfitStudio.cpp:7292 src/program/OutfitStudio.cpp:7313\n#: src/program/OutfitStudio.cpp:7585 src/program/OutfitStudio.cpp:7692\n#: src/program/OutfitStudio.cpp:7717 src/program/OutfitStudio.cpp:7753\n#: src/program/OutfitStudio.cpp:7786 src/program/OutfitStudio.cpp:7885\n#: src/program/OutfitStudio.cpp:7936 src/program/OutfitStudio.cpp:8029\n#: src/program/OutfitStudio.cpp:8046 src/program/OutfitStudio.cpp:8428\n#: src/program/OutfitStudio.cpp:8447 src/program/OutfitStudio.cpp:8531\n#: src/program/OutfitStudio.cpp:8555 src/program/OutfitStudio.cpp:8593\n#: src/program/OutfitStudio.cpp:8745 src/program/OutfitStudio.cpp:8934\n#: src/program/OutfitStudio.cpp:9086 src/program/OutfitStudio.cpp:9262\n#: src/program/OutfitStudio.cpp:9317 src/program/OutfitStudio.cpp:9531\n#: src/program/OutfitStudio.cpp:9617 src/program/OutfitStudio.cpp:10156\n#: src/program/OutfitStudio.cpp:10247 src/program/OutfitStudio.cpp:10340\n#: src/program/OutfitStudio.cpp:10385 src/program/OutfitStudio.cpp:10430\n#: src/program/OutfitStudio.cpp:10481 src/program/OutfitStudio.cpp:10732\n#: src/program/OutfitStudio.cpp:10782 src/program/OutfitStudio.cpp:10889\n#: src/program/OutfitStudio.cpp:11031 src/program/OutfitStudio.cpp:11115\n#: src/program/OutfitStudio.cpp:14209\nmsgid \"There is no shape selected!\"\nmsgstr \"Es ist kein Modell ausgewählt!\"\n\n#: src/program/OutfitStudio.cpp:4411\nmsgid \"Export selected shapes to NIF\"\nmsgstr \"Ausgewählten Modelle als NIF-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4423\nmsgid \"Failed to export selected shapes to NIF file!\"\nmsgstr \"Konnte ausgewählte Modelle nicht als NIF-Datei exportieren!\"\n\n#: src/program/OutfitStudio.cpp:4428\nmsgid \"Import .obj file for new shape\"\nmsgstr \"OBJ-Datei mit neuem Modell importieren\"\n\n#: src/program/OutfitStudio.cpp:4466\nmsgid \"\"\n\"Some of the shapes have coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the OBJ?  (This is not recommended.)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4468 src/program/OutfitStudio.cpp:4503\n#: src/program/OutfitStudio.cpp:4593 src/program/OutfitStudio.cpp:4628\nmsgid \"Transform to global\"\nmsgstr \"Nach Globalkoordinaten transformieren\"\n\n#: src/program/OutfitStudio.cpp:4475\nmsgid \"Export project as an .obj file\"\nmsgstr \"Projekt als OBJ-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4483 src/program/OutfitStudio.cpp:4525\n#: src/program/OutfitStudio.cpp:4544 src/program/OutfitStudio.cpp:7813\nmsgid \"Failed to export OBJ file!\"\nmsgstr \"Konnte OBJ-Datei nicht exportieren!\"\n\n#: src/program/OutfitStudio.cpp:4501\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the OBJ?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4512\nmsgid \"Export selected shapes as an .obj file\"\nmsgstr \"Ausgewählte Modelle als OBJ-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4529\nmsgid \"Export shape as an .obj file\"\nmsgstr \"Modell als OBJ-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4550\nmsgid \"Import .fbx file for new shape\"\nmsgstr \"FBX-Datei mit neuem Modell importieren\"\n\n#: src/program/OutfitStudio.cpp:4591\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the FBX?  (This is not recommended.)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4600\nmsgid \"Export project as an .fbx file\"\nmsgstr \"Projekt als FBX-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4608 src/program/OutfitStudio.cpp:4650\n#: src/program/OutfitStudio.cpp:4669\nmsgid \"Failed to export FBX file!\"\nmsgstr \"Konnte FBX-Datei nicht exportieren!\"\n\n#: src/program/OutfitStudio.cpp:4626\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the FBX?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:4637\nmsgid \"Export selected shapes as an .fbx file\"\nmsgstr \"Ausgewählte Modelle als FBX-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4654\nmsgid \"Export shape as an .fbx file\"\nmsgstr \"Modell als FBX-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:4675 src/program/OutfitStudio.cpp:7469\nmsgid \"Import .tri morphs\"\nmsgstr \"TRI-Morphs importieren\"\n\n#: src/program/OutfitStudio.cpp:4694 src/program/OutfitStudio.cpp:7478\nmsgid \"Failed to load TRI file!\"\nmsgstr \"Konnte TRI-Datei nicht importieren!\"\n\n#: src/program/OutfitStudio.cpp:4700 src/program/OutfitStudio.cpp:8537\nmsgid \"Please enter a new unique name for the shape.\"\nmsgstr \"Bitte geben Sie einen neuen, einzigartigen Namen für das Modell ein.\"\n\n#: src/program/OutfitStudio.cpp:4700 src/program/OutfitStudio.cpp:8537\nmsgid \"Rename Shape\"\nmsgstr \"Modell umbenennen\"\n\n#: src/program/OutfitStudio.cpp:4753 src/program/OutfitStudio.cpp:4779\n#: src/program/OutfitStudio.cpp:7844\nmsgid \"Export .tri morphs\"\nmsgstr \"TRI-Morphs exportieren\"\n\n#: src/program/OutfitStudio.cpp:4763 src/program/OutfitStudio.cpp:4786\n#: src/program/OutfitStudio.cpp:7851\nmsgid \"Failed to export TRI file!\"\nmsgstr \"Konnte TRI-Datei nicht exportieren!\"\n\n#: src/program/OutfitStudio.cpp:4791\nmsgid \"Import physics data to project\"\nmsgstr \"Physikdaten in Projekt importieren\"\n\n#: src/program/OutfitStudio.cpp:4798\n#, c-format\nmsgid \"Failed to import physics data file '%s'!\"\nmsgstr \"Konnte Physikdaten-Datei '%s' nicht importieren!\"\n\n#: src/program/OutfitStudio.cpp:4798\nmsgid \"Import Error\"\nmsgstr \"Import Fehler\"\n\n#: src/program/OutfitStudio.cpp:4810\nmsgid \"There is no physics data loaded!\"\nmsgstr \"Es sind keine Physikdaten geladen!\"\n\n#: src/program/OutfitStudio.cpp:4810 src/program/OutfitStudio.cpp:6553\n#: src/program/OutfitStudio.cpp:7254\nmsgid \"Info\"\nmsgstr \"Info\"\n\n#: src/program/OutfitStudio.cpp:4818\nmsgid \"Please choose the physics data source you want to export.\"\nmsgstr \"Wählen Sie die Physikdaten-Quelle, die Sie exportieren möchten.\"\n\n#: src/program/OutfitStudio.cpp:4818\nmsgid \"Choose physics data\"\nmsgstr \"Physikdaten wählen\"\n\n#: src/program/OutfitStudio.cpp:4826\nmsgid \"Export physics data\"\nmsgstr \"Physikdaten exportieren\"\n\n#: src/program/OutfitStudio.cpp:4832\n#, c-format\nmsgid \"Failed to save physics data file '%s'!\"\nmsgstr \"Konnte Physikdaten-Datei '%s' nicht speichern!\"\n\n#: src/program/OutfitStudio.cpp:4839\nmsgid \"This function requires at least one slider position to be non-zero.\"\nmsgstr \"\"\n\"Diese Funktion benötigt mindestens einen Slider, der nicht auf Null steht.\"\n\n#: src/program/OutfitStudio.cpp:4851\nmsgid \"\"\n\"Create a conversion slider for the current slider settings with the \"\n\"following name: \"\nmsgstr \"\"\n\"Einen Konvertierungs-Slider für die aktuellen Sliderwerte mit folgendem \"\n\"Namen erstellen: \"\n\n#: src/program/OutfitStudio.cpp:4851\nmsgid \"Create New Conversion Slider\"\nmsgstr \"Neuen Konvertierungs-Slider erstellen\"\n\n#: src/program/OutfitStudio.cpp:5601\nmsgid \"Please enter an SSF file path.\"\nmsgstr \"Bitte geben Sie einen SSF-Dateipfad an.\"\n\n#: src/program/OutfitStudio.cpp:6398\n#, c-format\nmsgid \"Field of View: %d\"\nmsgstr \"Sichtfeld: %d\"\n\n#: src/program/OutfitStudio.cpp:6528\nmsgid \"Your changes were not applied yet. Do you want to apply or reset them?\"\nmsgstr \"\"\n\"Ihre Änderungen wurden noch nicht angewandt. Wollen Sie diese anwenden oder \"\n\"zurücksetzen?\"\n\n#: src/program/OutfitStudio.cpp:6529\nmsgid \"Pending Changes\"\nmsgstr \"Ungespeicherte Änderungen\"\n\n#: src/program/OutfitStudio.cpp:6553\nmsgid \"\"\n\"You must have exactly one mesh selected in order to edit partitions or \"\n\"segments.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:7203\nmsgid \"There are no sliders loaded!\"\nmsgstr \"Es sind keine Slider geladen!\"\n\n#: src/program/OutfitStudio.cpp:7254\nmsgid \"No changes were made to the sliders, so no preset was saved!\"\nmsgstr \"\"\n\"Es wurden keine Veränderungen an Slidern vorgenommen, daher wurde auch kein \"\n\"Preset gespeichert!\"\n\n#: src/program/OutfitStudio.cpp:7271 src/program/OutfitStudio.cpp:7296\n#: src/program/OutfitStudio.cpp:7317 src/program/OutfitStudio.cpp:7696\nmsgid \"There is no slider in edit mode to import data to!\"\nmsgstr \"\"\n\"Es ist kein Slider im Bearbeitungsmodus, für den man Daten importieren \"\n\"könnte!\"\n\n#: src/program/OutfitStudio.cpp:7275\nmsgid \"Import .nif file for slider calculation\"\nmsgstr \"NIF-Datei zur Sliderberechnung importieren\"\n\n#: src/program/OutfitStudio.cpp:7282\nmsgid \"No mesh found in the .nif file that matches currently selected shape!\"\nmsgstr \"\"\n\"Anzahl an Vertices des Modells in der NIF-Datei stimmt nicht mit dem derzeit \"\n\"ausgewählten Modell überein!\"\n\n#: src/program/OutfitStudio.cpp:7300\nmsgid \"Import .bsd slider data\"\nmsgstr \"BSD Sliderdaten importieren\"\n\n#: src/program/OutfitStudio.cpp:7321\nmsgid \"Import .obj file for slider calculation\"\nmsgstr \"OBJ-Datei zur Sliderberechnung importieren\"\n\n#: src/program/OutfitStudio.cpp:7328 src/program/OutfitStudio.cpp:7707\nmsgid \"Vertex count of .obj file mesh does not match currently selected shape!\"\nmsgstr \"\"\n\"Anzahl an Vertices des Modells in der OBJ-Datei stimmt nicht mit dem derzeit \"\n\"ausgewählten Modell überein!\"\n\n#: src/program/OutfitStudio.cpp:7342\nmsgid \"Import .osd file\"\nmsgstr \"OSD-Datei importieren\"\n\n#: src/program/OutfitStudio.cpp:7351\nmsgid \"Failed to import OSD file!\"\nmsgstr \"Konnte OSD-Datei nicht importieren!\"\n\n#: src/program/OutfitStudio.cpp:7391 src/program/OutfitStudio.cpp:7501\n#: src/program/OutfitStudio.cpp:7627\nmsgid \"This will delete all loaded sliders. Are you sure?\"\nmsgstr \"Dies löscht alle geladenen Slider. Sind Sie sich sicher?\"\n\n#: src/program/OutfitStudio.cpp:7391 src/program/OutfitStudio.cpp:7460\nmsgid \"OSD Import\"\nmsgstr \"OSD Import\"\n\n#: src/program/OutfitStudio.cpp:7460 src/program/OutfitStudio.cpp:7575\n#: src/program/OutfitStudio.cpp:7687\n#, c-format\nmsgid \"\"\n\"Added morphs for the following shapes:\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Für die folgenden Modelle wurden Morphs hinzugefügt:\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/OutfitStudio.cpp:7501 src/program/OutfitStudio.cpp:7575\nmsgid \"TRI Import\"\nmsgstr \"TRI Import\"\n\n#: src/program/OutfitStudio.cpp:7589\nmsgid \"Import Starfield morph.dat file\"\nmsgstr \"Starfield morph.dat-Datei importieren\"\n\n#: src/program/OutfitStudio.cpp:7598\nmsgid \"Failed to import Starfield morph file!\"\nmsgstr \"Konnte Starfield morph.dat-Datei nicht importieren!\"\n\n#: src/program/OutfitStudio.cpp:7627 src/program/OutfitStudio.cpp:7687\nmsgid \"Starfield Morph Import\"\nmsgstr \"Starfield Morph-Import\"\n\n#: src/program/OutfitStudio.cpp:7700\nmsgid \"Import .fbx file for slider calculation\"\nmsgstr \"FBX-Datei zur Sliderberechnung importieren\"\n\n#: src/program/OutfitStudio.cpp:7721 src/program/OutfitStudio.cpp:7757\n#: src/program/OutfitStudio.cpp:7790\nmsgid \"There is no slider in edit mode to export data from!\"\nmsgstr \"\"\n\"Es ist kein Slider im Bearbeitungsmodus, von dem man Daten exportieren \"\n\"könnte!\"\n\n#: src/program/OutfitStudio.cpp:7726\nmsgid \"Export .nif slider data to directory\"\nmsgstr \"NIF Sliderdaten in Verzeichnis exportieren\"\n\n#: src/program/OutfitStudio.cpp:7737\nmsgid \"Export .nif slider data\"\nmsgstr \"NIF Sliderdaten exportieren\"\n\n#: src/program/OutfitStudio.cpp:7744\nmsgid \"Failed to export NIF file!\"\nmsgstr \"Konnte NIF-Datei nicht exportieren!\"\n\n#: src/program/OutfitStudio.cpp:7762\nmsgid \"Export .bsd slider data to directory\"\nmsgstr \"BSD Sliderdaten in Verzeichnis exportieren\"\n\n#: src/program/OutfitStudio.cpp:7773\nmsgid \"Export .bsd slider data\"\nmsgstr \"BSD Sliderdaten exportieren\"\n\n#: src/program/OutfitStudio.cpp:7795 src/program/OutfitStudio.cpp:7862\nmsgid \"Export .obj slider data to directory\"\nmsgstr \"OBJ Sliderdaten in Verzeichnis exportieren\"\n\n#: src/program/OutfitStudio.cpp:7806\nmsgid \"Export .obj slider data\"\nmsgstr \"OBJ Sliderdaten exportieren\"\n\n#: src/program/OutfitStudio.cpp:7826\nmsgid \"Export .osd file\"\nmsgstr \"OSD-Datei exportieren\"\n\n#: src/program/OutfitStudio.cpp:7833\nmsgid \"Failed to export OSD file!\"\nmsgstr \"Konnte OSD-Datei nicht exportieren!\"\n\n#: src/program/OutfitStudio.cpp:7891\nmsgid \"\"\n\"Are you sure you wish to clear the unmasked slider data for the selected \"\n\"shapes?  This action cannot be undone.\"\nmsgstr \"\"\n\"Sind Sie sich sicher, dass Sie die unmaskierten Slider-Daten löschen \"\n\"wollen?  Dies kann nicht rückgängig gemacht werden.\"\n\n#: src/program/OutfitStudio.cpp:7892 src/program/OutfitStudio.cpp:7897\nmsgid \"Confirm data erase\"\nmsgstr \"Datenlöschung bestätigen\"\n\n#: src/program/OutfitStudio.cpp:7895\n#, c-format\nmsgid \"\"\n\"Are you sure you wish to clear the unmasked slider data for the shape '%s'?  \"\n\"This action cannot be undone.\"\nmsgstr \"\"\n\"Sind Sie sich sicher, dass Sie die unmaskierten Slider-Daten für das Modell \"\n\"'%s' löschen wollen?  Dies kann nicht rückgängig gemacht werden.\"\n\n#: src/program/OutfitStudio.cpp:7950\nmsgid \"Enter a name for the new zap:\"\nmsgstr \"Gib einen Namen für den neuen Zap ein:\"\n\n#: src/program/OutfitStudio.cpp:7950\nmsgid \"Create New Zap\"\nmsgstr \"Neuen Zap erstellen\"\n\n#: src/program/OutfitStudio.cpp:7997\nmsgid \"There is no slider in edit mode to clone!\"\nmsgstr \"\"\n\"Es befindet sich kein Slider im Bearbeitungsmodus, der dupliziert werden \"\n\"könnte!\"\n\n#: src/program/OutfitStudio.cpp:8013\nmsgid \"Enter a name for the cloned slider:\"\nmsgstr \"Geben Sie einen Namen für den duplizierten Slider ein:\"\n\n#: src/program/OutfitStudio.cpp:8033\nmsgid \"There is no slider in edit mode to negate!\"\nmsgstr \"\"\n\"Es befindet sich kein Slider im Bearbeitungsmodus, den man negieren könnte!\"\n\n#: src/program/OutfitStudio.cpp:8050\nmsgid \"There is no slider in edit mode to create a mask from!\"\nmsgstr \"\"\n\"Es befindet sich kein Slider im Bearbeitungsmodus, aus dem man eine Maske \"\n\"erstellen könnte!\"\n\n#: src/program/OutfitStudio.cpp:8060\nmsgid \"Are you sure you wish to delete the selected slider(s)?\"\nmsgstr \"Sind Sie sich sicher, dass Sie die ausgewählten Slider löschen wollen?\"\n\n#: src/program/OutfitStudio.cpp:8061\nmsgid \"Confirm slider delete\"\nmsgstr \"Sliderlöschung bestätigen\"\n\n#: src/program/OutfitStudio.cpp:8261\nmsgid \"There is no slider in edit mode to show properties for!\"\nmsgstr \"\"\n\"Es befindet sich kein Slider im Bearbeitungsmodus, für den man Eigenschaften \"\n\"anzeigen könnte!\"\n\n#: src/program/OutfitStudio.cpp:8274 src/program/OutfitStudio.cpp:8318\nmsgid \"Conforming: \"\nmsgstr \"Übertrage: \"\n\n#: src/program/OutfitStudio.cpp:8305\nmsgid \"Conforming shapes...\"\nmsgstr \"Übertrage auf Modelle...\"\n\n#: src/program/OutfitStudio.cpp:8329\nmsgid \"All shapes conformed.\"\nmsgstr \"Auf alle Modelle übertragen.\"\n\n#: src/program/OutfitStudio.cpp:9291\nmsgid \"Are you sure you wish to delete parts of the selected shapes?\"\nmsgstr \"\"\n\"Sind Sie sich sicher, dass Sie Teile des ausgewählten Modells löschen wollen?\"\n\n#: src/program/OutfitStudio.cpp:9291 src/program/OutfitStudio.cpp:9621\nmsgid \"Confirm Delete\"\nmsgstr \"Löschen bestätigen\"\n\n#: src/program/OutfitStudio.cpp:9333\nmsgid \"Please enter a unique name for the new separated shape.\"\nmsgstr \"\"\n\"Bitte geben Sie einen einzigartigen Namen für das neu aufgeteilte Modell ein.\"\n\n#: src/program/OutfitStudio.cpp:9333\nmsgid \"Separate Vertices...\"\nmsgstr \"Vertices aufteilen...\"\n\n#: src/program/OutfitStudio.cpp:9383\nmsgid \"No errors found!\"\nmsgstr \"Keine Fehler gefunden!\"\n\n#: src/program/OutfitStudio.cpp:9389\nmsgid \"Errors:\"\nmsgstr \"Fehler:\"\n\n#: src/program/OutfitStudio.cpp:9391\nmsgid \"Target must be different from source.\"\nmsgstr \"Ziel muss sich von der Quelle unterscheiden.\"\n\n#: src/program/OutfitStudio.cpp:9393\nmsgid \"\"\n\"Partitions do not match. Make sure the amount of partitions and their slots \"\n\"match up.\"\nmsgstr \"\"\n\"Partitionen stimmen nicht überein. Bitte stellen Sie sicher, dass die Anzahl \"\n\"und Slots der Partitionen übereinstimmen.\"\n\n#: src/program/OutfitStudio.cpp:9395\nmsgid \"\"\n\"Segments do not match. Make sure the amount of segments, sub segments and \"\n\"their info as well as the segmentation file match.\"\nmsgstr \"\"\n\"Segmente stimmen nicht überein. Bitte stellen Sie sicher, dass die Anzahl \"\n\"und Informationen der Segmente und Untersegmente übereinstimmen.\"\n\n#: src/program/OutfitStudio.cpp:9397\nmsgid \"Resulting shape would have too many vertices.\"\nmsgstr \"Entstehendes Modell hätte zu viele Vertices.\"\n\n#: src/program/OutfitStudio.cpp:9399\nmsgid \"Resulting shape would have too many triangles.\"\nmsgstr \"Entstehendes Modell hätte zu viele Triangles.\"\n\n#: src/program/OutfitStudio.cpp:9401\nmsgid \"\"\n\"Shaders do not match. Make sure both shapes either have or don't have a \"\n\"shader and their shader type matches.\"\nmsgstr \"\"\n\"Shader stimmen nicht überein. Bitte stellen Sie sicher, dass beide Modelle \"\n\"entweder einen Shader haben oder nicht haben und deren Shadertyp \"\n\"übereinstimmt.\"\n\n#: src/program/OutfitStudio.cpp:9403\nmsgid \"\"\n\"Base texture doesn't match. Make sure both shapes have the same base/diffuse \"\n\"texture path.\"\nmsgstr \"\"\n\"Basistextur stimmt nicht überein. Bitte stellen Sie sicher, dass beide \"\n\"Modelle den selben Basis-/Diffuse-Texturpfad besitzen.\"\n\n#: src/program/OutfitStudio.cpp:9405\nmsgid \"\"\n\"Alpha property mismatch. Make sure both shapes either have or don't have an \"\n\"alpha property and their flags + threshold match.\"\nmsgstr \"\"\n\"Alpha-Property stimmt nicht überein. Bitte stellen Sie sicher, dass beide \"\n\"Modelle entweder eine Alpha-Property haben oder nicht haben und deren Flags \"\n\"+ Threshold übereinstimmt.\"\n\n#: src/program/OutfitStudio.cpp:9492\nmsgid \"\"\n\"You can only copy shapes into an outfit, and there is no outfit in the \"\n\"current project. Load one first!\"\nmsgstr \"\"\n\"Sie können nur Modelle in ein Outfit kopieren, und im Moment ist keines im \"\n\"Projekte. Laden Sie zuerst eines!\"\n\n#: src/program/OutfitStudio.cpp:9499\nmsgid \"Please enter a unique name for the duplicated shape.\"\nmsgstr \"\"\n\"Bitte geben Sie einen einzigartigen Namen für das duplizierte Modell ein.\"\n\n#: src/program/OutfitStudio.cpp:9499\nmsgid \"Duplicate Shape\"\nmsgstr \"Modell duplizieren\"\n\n#: src/program/OutfitStudio.cpp:9541\nmsgid \"There is more than one shape selected.\"\nmsgstr \"Es ist mehr als ein Modell ausgewählt.\"\n\n#: src/program/OutfitStudio.cpp:9596\nmsgid \"\"\n\"An edge has multiple triangles of the same orientation.  Correct the \"\n\"orientations before splitting.\"\nmsgstr \"\"\n\"Eine Kante ist mit mehrere Triangles derselben Ausrichtung verbunden.  \"\n\"Korrigieren Sie die Ausrichtung vor dem Aufteilen.\"\n\n#: src/program/OutfitStudio.cpp:9612\nmsgid \"\"\n\"Can't delete shape while in slider edit mode.  Use CTRL+Delete to delete \"\n\"sliders instead.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:9621\nmsgid \"\"\n\"Are you sure you wish to delete the selected shapes?  This action cannot be \"\n\"undone.\"\nmsgstr \"\"\n\"Sind Sie sich sicher, dass Sie die ausgewählten Modelle löschen wollen?  \"\n\"Dies kann nicht rückgängig gemacht werden.\"\n\n#: src/program/OutfitStudio.cpp:9785\nmsgid \"No bone name was entered!\"\nmsgstr \"Es wurde kein Bone-Name eingegeben!\"\n\n#: src/program/OutfitStudio.cpp:9793 src/program/OutfitStudio.cpp:9834\n#, c-format\nmsgid \"Bone '%s' already exists in the project!\"\nmsgstr \"Bone '%s' existiert bereits im Projekt!\"\n\n#: src/program/OutfitStudio.cpp:9892\nmsgid \"View Standard Bone\"\nmsgstr \"Standard-Bone anzeigen\"\n\n#: src/program/OutfitStudio.cpp:9903\nmsgid \"Edit Custom Bone\"\nmsgstr \"Benutzerdefinierten Bone bearbeiten\"\n\n#: src/program/OutfitStudio.cpp:9986\nmsgid \"\"\n\"The following shapes have unweighted vertices, which can cause issues. The \"\n\"affected vertices have been put under a mask. Do you want to save anyway?\"\nmsgstr \"\"\n\"Die folgenden Modelle haben Vertices ohne Weighting, was Probleme \"\n\"verursachen kann. Die betroffenen Vertices wurden unter eine Maske versetzt. \"\n\"Trotzdem speichern?\"\n\n#: src/program/OutfitStudio.cpp:9989\nmsgid \"Unweighted Vertices\"\nmsgstr \"Vertices ohne Weighting\"\n\n#: src/program/OutfitStudio.cpp:10161 src/program/OutfitStudio.cpp:10252\n#: src/program/OutfitStudio.cpp:10346 src/program/OutfitStudio.cpp:10486\nmsgid \"There is no reference shape!\"\nmsgstr \"Es ist kein Referenz-Modell vorhanden!\"\n\n#: src/program/OutfitStudio.cpp:10170 src/program/OutfitStudio.cpp:10320\nmsgid \"\"\n\"Sorry, you can't copy weights from the reference shape to itself. Skipping \"\n\"this shape.\"\nmsgstr \"\"\n\"Sie können leider kein Weighting vom Referenzmodell auf es selbst kopieren. \"\n\"Überspringe dieses Modell.\"\n\n#: src/program/OutfitStudio.cpp:10170 src/program/OutfitStudio.cpp:10320\nmsgid \"Can't copy weights\"\nmsgstr \"Weighting kann nicht kopiert werden\"\n\n#: src/program/OutfitStudio.cpp:10290\nmsgid \"Copying selected bone weights...\"\nmsgstr \"Kopieren ausgewähltes Bone-Weighting...\"\n\n#: src/program/OutfitStudio.cpp:10351\nmsgid \"Sorry, you can't copy weights from the reference shape to itself.\"\nmsgstr \"\"\n\"Sie können leider kein Weighting vom Referenzmodell auf es selbst kopieren.\"\n\n#: src/program/OutfitStudio.cpp:10358\nmsgid \"The vertex count of the reference and chosen shape is not the same!\"\nmsgstr \"\"\n\"Die Anzahl an Vertices in der Referenz und dem gewählten Modell stimmt nicht \"\n\"überein!\"\n\n#: src/program/OutfitStudio.cpp:10495\nmsgid \"\"\n\"Sorry, you can't copy partitions/segments from the reference shape to \"\n\"itself. Skipping this shape.\"\nmsgstr \"\"\n\"Sie können leider keine Partitionen/Segmente vom Referenzmodell auf es \"\n\"selbst kopieren. Überspringe dieses Modell.\"\n\n#: src/program/OutfitStudio.cpp:10495\nmsgid \"Can't copy segments/partitions\"\nmsgstr \"Kann Segmente/Partitionen nicht kopieren\"\n\n#: src/program/OutfitStudio.cpp:10500\nmsgid \"\"\n\"Triangles will be assigned to the partition/segment of the nearest triangle \"\n\"in the reference.  Existing partitions/segments are cleared.  This action \"\n\"can't be undone.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10500\nmsgid \"Copy Partitions/Segments\"\nmsgstr \"Partitionen/Segmente kopieren\"\n\n#: src/program/OutfitStudio.cpp:10509\nmsgid \"Copying segments/partitions...\"\nmsgstr \"Kopiere Segments/Partitionen...\"\n\n#: src/program/OutfitStudio.cpp:10520\n#, c-format\nmsgid \"\"\n\"The partitions/segments could not be copied for '%s' because %d triangles \"\n\"could not be matched.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10571\nmsgid \" sliders\"\nmsgstr \" Slider\"\n\n#: src/program/OutfitStudio.cpp:10573\nmsgid \" bones\"\nmsgstr \" Bones\"\n\n#: src/program/OutfitStudio.cpp:10709\nmsgid \"Symmetrize Vertices\"\nmsgstr \"Vertices symmetrisieren\"\n\n#: src/program/OutfitStudio.cpp:10711\nmsgid \"\"\n\"Eliminates the selected asymmetries from unmasked vertices by adjusting \"\n\"vertex data to be consistent with mirror vertices.\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10713\nmsgid \"\"\n\"  (Hint: To choose which non-selected bones are adjusted during weight \"\n\"normalization, unlock them in the bones list in the Bones tab.)\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:10717\nmsgid \"Vertices that will be symmetrized:\"\nmsgstr \"Vertices, die symmetrisiert werden:\"\n\n#: src/program/OutfitStudio.cpp:10718\nmsgid \"&Symmetrize\"\nmsgstr \"&Symmetrisieren\"\n\n#: src/program/OutfitStudio.cpp:10875\n#, c-format\nmsgid \"%d unreferenced nodes were deleted.\"\nmsgstr \"%d unreferenzierte Nodes wurden entfernt.\"\n\n#: src/program/OutfitStudio.cpp:11173\nmsgid \"Please enter a new unique name for the mask.\"\nmsgstr \"Bitte geben Sie einen neuen, einzigartigen Namen für die Maske ein.\"\n\n#: src/program/OutfitStudio.cpp:11173\nmsgid \"New Mask\"\nmsgstr \"Neue Maske\"\n\n#: src/program/OutfitStudio.cpp:11358\nmsgid \"Reset all bone poses?\"\nmsgstr \"Pose aller Bones zurücksetzen?\"\n\n#: src/program/OutfitStudio.cpp:11358\nmsgid \"Reset Pose\"\nmsgstr \"Pose zurücksetzen\"\n\n#: src/program/OutfitStudio.cpp:11509\nmsgid \"Please enter a new unique name for the pose.\"\nmsgstr \"Bitte geben Sie einen neuen, einzigartigen Namen für die Pose ein.\"\n\n#: src/program/OutfitStudio.cpp:11509\nmsgid \"New Pose\"\nmsgstr \"Neue Pose\"\n\n#: src/program/OutfitStudio.cpp:11560\n#, c-format\nmsgid \"Are you sure you wish to delete the pose '%s'?\"\nmsgstr \"Sind Sie sich sicher, dass Sie die Pose '%s' löschen wollen?\"\n\n#: src/program/OutfitStudio.cpp:11561\nmsgid \"Confirm pose delete\"\nmsgstr \"Posenlöschung bestätigen\"\n\n#: src/program/OutfitStudio.cpp:12499\nmsgid \"The vertex picked has more than three connections.\"\nmsgstr \"Das gewählte Vertex hat mehr als drei Verbindungen.\"\n\n#: src/program/OutfitStudio.cpp:12734\nmsgid \"\"\n\"Neither the selected nor target vertices are on the mesh boundary.  It is \"\n\"recommended that you only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12735\nmsgid \"\"\n\"The selected vertex is not on the mesh boundary.  It is recommended that you \"\n\"only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12736\nmsgid \"\"\n\"The target vertex is not on the mesh boundary.  It is recommended that you \"\n\"only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12737\nmsgid \"Weld/Merge Non-Boundary Vertices\"\nmsgstr \"\"\n\n#: src/program/OutfitStudio.cpp:12819\nmsgid \"The edge picked is on the surface boundary.  Pick an interior edge.\"\nmsgstr \"\"\n\"Die ausgewählte Kante ist am Oberflächenrand. Wählen Sie eine innere Kante.\"\n\n#: src/program/OutfitStudio.cpp:12873\nmsgid \"\"\n\"The edge picked has multiple triangles of the same orientation.  Correct the \"\n\"orientations before splitting.\"\nmsgstr \"\"\n\"Die ausgewählte Kante hat mehrere Triangles mit der selben Ausrichtung. \"\n\"Bitte korrigieren Sie die Ausrichtung vor der Aufteilung.\"\n\n#: src/program/OutfitStudio.cpp:14220 src/program/OutfitStudio.cpp:14221\nmsgid \"Loading slider file...\"\nmsgstr \"Lade Slider-Datei...\"\n\n#: src/program/PreviewWindow.cpp:39\nmsgid \"Show the Normal Map Generator dialog.\"\nmsgstr \"Zeige den Normal Map Generator-Dialog.\"\n\n#: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:33\nmsgid \"Preview failed: OpenGL context is not OK.\"\nmsgstr \"Vorschau fehlgeschlagen: OpenGL-Kontext ist nicht OK.\"\n\n#: src/program/ShapeProperties.cpp:104\nmsgid \"Material\"\nmsgstr \"Material\"\n\n#: src/program/ShapeProperties.cpp:117\n#, c-format\nmsgid \"%zu shapes selected\"\nmsgstr \"%zu Modelle ausgewählt\"\n\n#: src/program/ShapeProperties.cpp:132\n#, c-format\nmsgid \"This action will affect all %zu selected shapes. Are you sure?\"\nmsgstr \"\"\n\"Diese Aktion betrifft alle %zu ausgewählten Modelle. Sind Sie sich sicher?\"\n\n#: src/program/ShapeProperties.cpp:133\nmsgid \"Confirmation\"\nmsgstr \"Bestätigung\"\n\n#: src/program/ShapeProperties.cpp:135\nmsgid \"Yes\"\nmsgstr \"Ja\"\n\n#: src/program/ShapeProperties.cpp:135\nmsgid \"No\"\nmsgstr \"Nein\"\n\n#: src/program/ShapeProperties.cpp:352\nmsgid \"Choose material file\"\nmsgstr \"Material-Datei auswählen\"\n\n#: src/program/ShapeProperties.cpp:662\nmsgid \"Please choose a shape to copy from\"\nmsgstr \"Bitte wählen Sie ein Modell für die Kopie aus\"\n\n#: src/program/ShapeProperties.cpp:662\nmsgid \"Choose shape\"\nmsgstr \"Modell auswählen\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:133\nmsgid \"Size\"\nmsgstr \"Größe\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:137\nmsgid \"Shortcut: 'S' + mouse wheel\"\nmsgstr \"Tastaturkürzel: 'S' + Mausrad\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:146\nmsgid \"Strength\"\nmsgstr \"Stärke\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:158\nmsgid \"Focus\"\nmsgstr \"Fokus\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:170\nmsgid \"Spacing\"\nmsgstr \"Abstand\"\n\n#: src/ui/wxSliderPanel.cpp:63\nmsgid \"Turn on edit mode for this slider.\"\nmsgstr \"Schalte den Bearbeitungsmodus dieses Sliders an.\"\n\n#: src/ui/wxSliderPanel.cpp:75\nmsgid \"Weaken slider data by 1%.\"\nmsgstr \"Sliderdaten um 1% abschwächen.\"\n\n#: src/ui/wxSliderPanel.cpp:82\nmsgid \"Strengthen slider data by 1%.\"\nmsgstr \"Sliderdaten um 1% verstärken.\"\n\n#~ msgid \"Mirror\"\n#~ msgstr \"Spiegeln\"\n\n#~ msgid \"Mirror the selected shapes on the Y-axis.\"\n#~ msgstr \"Spiegelt die ausgewählten Modelle auf der Y-Achse.\"\n\n#~ msgid \"Mirror the selected shapes on the Z-axis.\"\n#~ msgstr \"Spiegelt die ausgewählten Modelle auf der Z-Achse.\"\n\n#~ msgid \"Group Filter\"\n#~ msgstr \"Gruppenfilter\"\n\n#~ msgid \"Outfit Filter\"\n#~ msgstr \"Outfitfilter\"\n"
  },
  {
    "path": "lang/el/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/el/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/es/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/es/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/eu/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/eu/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/fi/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/fi/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/fr/BodySlide.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: BodySlide\\n\"\n\"POT-Creation-Date: \\n\"\n\"PO-Revision-Date: \\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: fr_FR\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"X-Generator: Poedit 3.0\\n\"\n\"X-Poedit-KeywordsList: _\\n\"\n\"Plural-Forms: nplurals=2; plural=(n > 1);\\n\"\n\n#: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:410\nmsgid \"About\"\nmsgstr \"À propos\"\n\n#: res/xrc/About.xrc:145 res/xrc/GroupManager.xrc:189\nmsgid \"Close\"\nmsgstr \"Fermer\"\n\n#: res/xrc/Actions.xrc:6\nmsgid \"Apply a vertex position\"\nmsgstr \"Appliquez une position de vertex\"\n\n#: res/xrc/Actions.xrc:15\nmsgid \"This permanently moves a single vertex straight to the given location.\"\nmsgstr \"\"\n\"Cela déplace en permanence un seul vertex directement vers l'emplacement \"\n\"donné.\"\n\n#: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499\n#: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:741 res/xrc/Actions.xrc:891\n#: res/xrc/Actions.xrc:1170 res/xrc/Actions.xrc:1271 res/xrc/BatchBuild.xrc:103\n#: res/xrc/EditUV.xrc:32 res/xrc/FBXImport.xrc:45 res/xrc/Project.xrc:712\n#: res/xrc/Project.xrc:891 res/xrc/Settings.xrc:410\n#: res/xrc/ShapeProperties.xrc:755 res/xrc/Skeleton.xrc:36\n#: res/xrc/Skeleton.xrc:232 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238\nmsgid \"&OK\"\nmsgstr \"&D'accord\"\n\n#: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506\n#: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:748 res/xrc/Actions.xrc:898\n#: res/xrc/Actions.xrc:1177 res/xrc/Actions.xrc:1278 res/xrc/BatchBuild.xrc:57\n#: res/xrc/BatchBuild.xrc:110 res/xrc/EditUV.xrc:39 res/xrc/FBXImport.xrc:52\n#: res/xrc/Project.xrc:546 res/xrc/Project.xrc:719 res/xrc/Project.xrc:898\n#: res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:417 res/xrc/Setup.xrc:273\n#: res/xrc/ShapeProperties.xrc:762 res/xrc/Skeleton.xrc:43\n#: res/xrc/Skeleton.xrc:239 res/xrc/Slider.xrc:71 res/xrc/Slider.xrc:246\nmsgid \"&Cancel\"\nmsgstr \"&Annuler\"\n\n#: res/xrc/Actions.xrc:110\nmsgid \"Move Shape\"\nmsgstr \"Bougez la Forme\"\n\n#: res/xrc/Actions.xrc:254\nmsgid \"Mirror Axis\"\nmsgstr \"Axe Miroir\"\n\n#: res/xrc/Actions.xrc:320\nmsgid \"Scale Shape\"\nmsgstr \"Échelle la Forme\"\n\n#: res/xrc/Actions.xrc:329\nmsgid \"\"\n\"Scaling will adjust the size of a mesh. This permanently affects vertices.\"\nmsgstr \"\"\n\"La mise à l'échelle ajustera la taille d'un maillage. Cela affecte en \"\n\"permanence les vertices.\"\n\n#: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667\n#: res/xrc/ShapeProperties.xrc:635 res/xrc/Skeleton.xrc:133\nmsgid \"Origin\"\nmsgstr \"Origine\"\n\n#: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678\nmsgid \"Zero (0, 0, 0)\"\nmsgstr \"Zéro (0, 0, 0)\"\n\n#: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679\nmsgid \"Center of selected shapes(s)\"\nmsgstr \"Centre de formes sélectionnées(s)\"\n\n#: res/xrc/Actions.xrc:484\nmsgid \"Uniform (XYZ)\"\nmsgstr \"Uniforme (XYZ)\"\n\n#: res/xrc/Actions.xrc:517\nmsgid \"Rotate Shape\"\nmsgstr \"Tournez la Forme\"\n\n#: res/xrc/Actions.xrc:711\nmsgid \"Set Shape Textures\"\nmsgstr \"Définir les Textures des Formes\"\n\n#: res/xrc/Actions.xrc:758 res/xrc/OutfitStudio.xrc:2031\n#: res/xrc/OutfitStudio.xrc:2394\nmsgid \"Copy Bone Weights\"\nmsgstr \"Copier les poids des os\"\n\n#: res/xrc/Actions.xrc:767\nmsgid \"\"\n\"Each vertex of the reference will copy its weights to the nearest collection \"\n\"of vertices within the given radius. Bear in mind that some geometry will \"\n\"always require manual tweaking to become weighted and work well. Often, the \"\n\"default values are sufficient.\"\nmsgstr \"\"\n\"Chaque vertex de la référence copiera ses poids dans la collection de \"\n\"vertices la plus proche dans le rayon donné. Gardez à l'esprit que certaines \"\n\"géométries nécessiteront toujours des ajustements manuels pour devenir \"\n\"pondérées et fonctionner correctement. Souvent, les valeurs par défaut sont \"\n\"suffisantes.\"\n\n#: res/xrc/Actions.xrc:787 res/xrc/Actions.xrc:937\nmsgid \"Search Radius\"\nmsgstr \"Rayon de Recherche\"\n\n#: res/xrc/Actions.xrc:816 res/xrc/Actions.xrc:966\nmsgid \"Max Vertex Targets\"\nmsgstr \"Max Vertex Cibles\"\n\n#: res/xrc/Actions.xrc:847 res/xrc/Actions.xrc:995\nmsgid \"No Target Limit\"\nmsgstr \"Aucune Limite Cible\"\n\n#: res/xrc/Actions.xrc:856\nmsgid \"\"\n\"The skin coordinate system doesn't match the reference shape's. Do you want \"\n\"to copy the transforms?\"\nmsgstr \"\"\n\"Le système de coordonnées cutanées ne correspond pas à la forme de \"\n\"référence. Voulez-vous copier les transformations?\"\n\n#: res/xrc/Actions.xrc:866\nmsgid \"Copy skin transform from reference\"\nmsgstr \"Copie de la transformation de la peau à partir de la référence\"\n\n#: res/xrc/Actions.xrc:876 res/xrc/ShapeProperties.xrc:730\nmsgid \"Recalculate geometry's coordinates so it doesn't move\"\nmsgstr \"Recalculer les coordonnées de la géométrie pour qu’elle ne bouge pas\"\n\n#: res/xrc/Actions.xrc:877 res/xrc/ShapeProperties.xrc:731\nmsgid \"\"\n\"Transform geometry so its position in global coordinates does not change.\"\nmsgstr \"\"\n\"Transformez la géométrie de sorte que sa position dans les coordonnées \"\n\"globales ne change pas.\"\n\n#: res/xrc/Actions.xrc:908\nmsgid \"Conforming...\"\nmsgstr \"Conforme...\"\n\n#: res/xrc/Actions.xrc:917\nmsgid \"\"\n\"Each vertex of the reference will copy its slider data to the nearest \"\n\"collection of vertices within the given radius. Bear in mind that some \"\n\"geometry will always require manual tweaking to become conformed and work \"\n\"well. Often, the default values are sufficient.\"\nmsgstr \"\"\n\"Chaque vertex de la référence copiera ses données de slider dans la \"\n\"collection de vertices la plus proche dans le rayon donné. Gardez à l'esprit \"\n\"que certaines géométries nécessiteront toujours des ajustements manuels pour \"\n\"devenir pondérées et fonctionner correctement. Souvent, les valeurs par \"\n\"défaut sont suffisantes.\"\n\n#: res/xrc/Actions.xrc:1018\nmsgid \"No Squeeze\"\nmsgstr \"Aucune Pression\"\n\n#: res/xrc/Actions.xrc:1041\nmsgid \"Solid Mode\"\nmsgstr \"Mode Solide\"\n\n#: res/xrc/Actions.xrc:1064\nmsgid \"Axis\"\nmsgstr \"L'Axe\"\n\n#: res/xrc/Actions.xrc:1114 res/xrc/BodySlide.xrc:97\n#: res/xrc/NormalsGenDlg.xrc:191\nmsgid \"Preset\"\nmsgstr \"Préréglage\"\n\n#: res/xrc/Actions.xrc:1130\nmsgid \"Default\"\nmsgstr \"Valeurs par Défaut\"\n\n#: res/xrc/Actions.xrc:1139\nmsgid \"Even Movement\"\nmsgstr \"Même Mouvement\"\n\n#: res/xrc/Actions.xrc:1148\nmsgid \"Solid Object\"\nmsgstr \"Objet Solide\"\n\n#: res/xrc/Actions.xrc:1187\nmsgid \"Copy Geometry\"\nmsgstr \"Copier la Géométrie\"\n\n#: res/xrc/Actions.xrc:1196\nmsgid \"\"\n\"This function copies vertices and triangles from one shape to another.  \"\n\"Partitions/segments of source and target shapes must match.  It is the \"\n\"user's responsibility to check that all other shape and shader properties \"\n\"are compatible, or merging will likely have side effects.\"\nmsgstr \"\"\n\"Cette fonction copie les vertices et les triangles d'une forme à une autre. \"\n\"Les partitions/segments des formes source et cible doivent correspondre. Il \"\n\"est de la responsabilité de l'utilisateur de vérifier que toutes les autres \"\n\"propriétés de forme et de shader sont compatibles, ou la fusion aura \"\n\"probablement des effets secondaires.\"\n\n#: res/xrc/Actions.xrc:1211\nmsgid \"Source\"\nmsgstr \"Source\"\n\n#: res/xrc/Actions.xrc:1229\nmsgid \"Target\"\nmsgstr \"Cible\"\n\n#: res/xrc/Actions.xrc:1258\nmsgid \"Delete source shape\"\nmsgstr \"Effacer la forme source\"\n\n#: res/xrc/BatchBuild.xrc:6\nmsgid \"Batch Build\"\nmsgstr \"Construction Par Lots\"\n\n#: res/xrc/BatchBuild.xrc:21\nmsgid \"\"\n\"Select the slider sets for the batch build process. Use the group and outfit \"\n\"filters to show the outfits you want!\"\nmsgstr \"\"\n\"Sélectionnez les ensembles de glissières pour le processus de construction \"\n\"par lots. Utilisez les filtres de groupe et de tenue pour afficher les \"\n\"tenues que vous souhaitez !\"\n\n#: res/xrc/BatchBuild.xrc:50\nmsgid \"&Build\"\nmsgstr \"&Construire\"\n\n#: res/xrc/BatchBuild.xrc:67 src/program/BodySlideApp.cpp:2065\nmsgid \"Choose output set\"\nmsgstr \"Choisir l'ensemble de sortie\"\n\n#: res/xrc/BatchBuild.xrc:78\nmsgid \"\"\n\"The following sets will override the same files.\\n\"\n\"Please decide which one to use and select it in the list below.\"\nmsgstr \"\"\n\"Les ensembles suivants remplaceront les mêmes fichiers.\\n\"\n\"Veuillez décider lequel utiliser et sélectionnez-le dans la liste ci-dessous.\"\n\n#: res/xrc/BodySlide.xrc:7\nmsgid \"BodySlide\"\nmsgstr \"Bodyslide\"\n\n#: res/xrc/BodySlide.xrc:28\nmsgid \"Outfit/Body\"\nmsgstr \"Vêtement/Corps\"\n\n#: res/xrc/BodySlide.xrc:44\nmsgid \"Select an outfit to modify\"\nmsgstr \"Sélectionnez une tenue à modifier\"\n\n#: res/xrc/BodySlide.xrc:58\nmsgid \"Deletes a project from its project file\"\nmsgstr \"Supprime un projet de son fichier de projet\"\n\n#: res/xrc/BodySlide.xrc:74\nmsgid \"Opens the current project in Outfit Studio\"\nmsgstr \"Ouvre le projet en cours dans Outfit Studio\"\n\n#: res/xrc/BodySlide.xrc:113\nmsgid \"Choose from a list of slider settings presets\"\nmsgstr \"Choisissez parmi une liste de paramètres prédéfinis de slider\"\n\n#: res/xrc/BodySlide.xrc:127\nmsgid \"Deletes a preset from its preset file\"\nmsgstr \"Supprime un préréglage de son fichier de préréglage\"\n\n#: res/xrc/BodySlide.xrc:142\nmsgid \"Saves the new slider values to the currently selected preset\"\nmsgstr \"\"\n\"Enregistre les nouvelles valeurs du slider dans le préréglage actuellement \"\n\"sélectionné\"\n\n#: res/xrc/BodySlide.xrc:143 res/xrc/GroupManager.xrc:44\n#: res/xrc/OutfitStudio.xrc:1310\nmsgid \"Save\"\nmsgstr \"Sauvegarder\"\n\n#: res/xrc/BodySlide.xrc:152\nmsgid \"Save the current slider settings as a new preset\"\nmsgstr \"\"\n\"Sauvegarder les paramètres actuels du slider comme un nouveau préréglage\"\n\n#: res/xrc/BodySlide.xrc:153 res/xrc/GroupManager.xrc:53\n#: res/xrc/OutfitStudio.xrc:1319\nmsgid \"Save As...\"\nmsgstr \"Sauvegarder sous...\"\n\n#: res/xrc/BodySlide.xrc:164\nmsgid \"\"\n\"Opens the group manager where you can edit existing or create new groups\"\nmsgstr \"\"\n\"Ouvre le gestionnaire de groupe dans lequel vous pouvez modifier des groupes \"\n\"existants ou créer de nouveaux groupes\"\n\n#: res/xrc/BodySlide.xrc:165 res/xrc/GroupManager.xrc:7\n#: res/xrc/Project.xrc:1020\nmsgid \"Group Manager\"\nmsgstr \"Gerante de Groupe\"\n\n#: res/xrc/BodySlide.xrc:189\nmsgid \"Single Weight\"\nmsgstr \"Poids Seul\"\n\n#: res/xrc/BodySlide.xrc:216\nmsgid \"Low Weight\"\nmsgstr \"Poids Faible\"\n\n#: res/xrc/BodySlide.xrc:233\nmsgid \"High Weight\"\nmsgstr \"Poids Haut\"\n\n#: res/xrc/BodySlide.xrc:276\nmsgid \"Copy the low weight slider values to the high weight section.\"\nmsgstr \"\"\n\"Copiez les valeurs du slider de poids faible dans la section de poids haut.\"\n\n#: res/xrc/BodySlide.xrc:298\nmsgid \"\"\n\"Build multiple outfits using the currently active slider values.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to custom directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"Créez plusieurs tenues en utilisant les valeurs du slider actif.\\n\"\n\"\\n\"\n\"Maintenir CTRL = Construire dans le répertoire personnalisé\\n\"\n\"Maintenir ALT = Supprimer du répertoire de sortie\"\n\n#: res/xrc/BodySlide.xrc:299\nmsgid \"Batch Build...\"\nmsgstr \"Construction par lots...\"\n\n#: res/xrc/BodySlide.xrc:314\nmsgid \"Build Morphs\"\nmsgstr \"Construire des morphes\"\n\n#: res/xrc/BodySlide.xrc:315\nmsgid \"\"\n\"Builds a morphs (.tri) file alongside the meshes for accessing the sliders \"\n\"in-game. Requires other mods to make use of the morph data.\"\nmsgstr \"\"\n\"Construit un fichier morphs (.tri) à côté des maillages pour accéder aux \"\n\"sliders dans le jeu. Nécessite d'autres mods pour utiliser les données de \"\n\"morphing.\"\n\n#: res/xrc/BodySlide.xrc:325\nmsgid \"Force Body Normals\"\nmsgstr \"Obliger Normales du Corps\"\n\n#: res/xrc/BodySlide.xrc:326\nmsgid \"\"\n\"Adds normal and tangent data to the body meshes (including bodies within \"\n\"outfits) for Skyrim. Use this only if you have a tangent space body mod.\"\nmsgstr \"\"\n\"Ajoute des données normales et tangentes aux maillages corporels (y compris \"\n\"les corps dans les tenues) pour Skyrim. Utilisez ceci uniquement si vous \"\n\"avez un mod de corps d'espace tangent.\"\n\n#: res/xrc/BodySlide.xrc:349\nmsgid \"Show a preview window for this outfit.\"\nmsgstr \"Afficher une fenêtre d'aperçu pour cette tenue.\"\n\n#: res/xrc/BodySlide.xrc:350 res/xrc/NormalsGenDlg.xrc:166\n#: src/program/PreviewWindow.cpp:28\nmsgid \"Preview\"\nmsgstr \"Aperçu\"\n\n#: res/xrc/BodySlide.xrc:367\nmsgid \"\"\n\"Creates the currently selected outfit/body.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to working directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"Crée la tenue/corps actuellement sélectionnée.\\n\"\n\"\\n\"\n\"Maintenir CTRL = Construire dans le répertoire de travail\\n\"\n\"Maintenir ALT = Supprimer du répertoire de sortie\"\n\n#: res/xrc/BodySlide.xrc:368\nmsgid \"Build\"\nmsgstr \"Construire\"\n\n#: res/xrc/BodySlide.xrc:387\nmsgid \"Copy the high weight slider values to the low weight section.\"\nmsgstr \"\"\n\"Copiez les valeurs du slider de poids haut dans la section de poids faible.\"\n\n#: res/xrc/BodySlide.xrc:419 res/xrc/OutfitStudio.xrc:1820\nmsgid \"Open settings dialog.\"\nmsgstr \"Ouvrez la boîte de dialogue des paramètres.\"\n\n#: res/xrc/BodySlide.xrc:420 res/xrc/OutfitStudio.xrc:1819\n#: res/xrc/Settings.xrc:5\nmsgid \"Settings\"\nmsgstr \"Paramètres\"\n\n#: res/xrc/BodySlide.xrc:429\nmsgid \"\"\n\"Open Outfit Studio, a full-featured tool for creating and converting outfits.\"\nmsgstr \"\"\n\"Ouvrez Outfit Studio, un outil complet pour créer et convertir des tenues.\"\n\n#: res/xrc/BodySlide.xrc:430 res/xrc/OutfitStudio.xrc:7\nmsgid \"Outfit Studio\"\nmsgstr \"Outfit Studio\"\n\n#: res/xrc/BodySlide.xrc:442 res/xrc/BodySlide.xrc:453\nmsgid \"Filter Options\"\nmsgstr \"Options de filtre\"\n\n#: res/xrc/BodySlide.xrc:444\nmsgid \"Choose groups...\"\nmsgstr \"Choisissez des groupes...\"\n\n#: res/xrc/BodySlide.xrc:445\nmsgid \"Choose groups to display in the Outfit menu\"\nmsgstr \"Choisissez les groupes à afficher dans le menu Outfit\"\n\n#: res/xrc/BodySlide.xrc:448\nmsgid \"Refresh Groups\"\nmsgstr \"Rafraîchir les groupes\"\n\n#: res/xrc/BodySlide.xrc:449\nmsgid \"Refresh group information\"\nmsgstr \"Rafraîchir les informations du groupe\"\n\n#: res/xrc/BodySlide.xrc:455\nmsgid \"Save Outfit list as group...\"\nmsgstr \"Sauvegarder la liste des tenues comme groupe...\"\n\n#: res/xrc/BodySlide.xrc:456\nmsgid \"Save the current filtered outfit list as a group\"\nmsgstr \"Sauvegarder la liste de tenues filtrée actuelle en tant que groupe\"\n\n#: res/xrc/BodySlide.xrc:459\nmsgid \"Refresh Outfits\"\nmsgstr \"Rafraîchir les tenues\"\n\n#: res/xrc/BodySlide.xrc:460\nmsgid \"Reloads outfit list\"\nmsgstr \"Recharge la liste des tenues\"\n\n#: res/xrc/BodySlide.xrc:465 res/xrc/Project.xrc:1037\nmsgid \"Select None\"\nmsgstr \"Ne sélectionnez aucun\"\n\n#: res/xrc/BodySlide.xrc:468 res/xrc/EditUV.xrc:110 res/xrc/Project.xrc:1040\nmsgid \"Select All\"\nmsgstr \"Sélectionnez tout\"\n\n#: res/xrc/BodySlide.xrc:471 res/xrc/EditUV.xrc:114 res/xrc/Project.xrc:1043\nmsgid \"Invert Selection\"\nmsgstr \"Sélection d'inversion\"\n\n#: res/xrc/EditUV.xrc:5\nmsgid \"Edit UV\"\nmsgstr \"Modifiez UV\"\n\n#: res/xrc/EditUV.xrc:52\nmsgid \"Box Selection\"\nmsgstr \"Sélection de Boîtes\"\n\n#: res/xrc/EditUV.xrc:53\nmsgid \"\"\n\"Box Selection\\n\"\n\"Shortcut: 1\"\nmsgstr \"\"\n\"Sélection de Boîtes\\n\"\n\"Raccourci: 1\"\n\n#: res/xrc/EditUV.xrc:60\nmsgid \"Vertex Selection\"\nmsgstr \"Sélection de Vertex\"\n\n#: res/xrc/EditUV.xrc:61\nmsgid \"\"\n\"Vertex Selection\\n\"\n\"Shortcut: 2\"\nmsgstr \"\"\n\"Sélection de Vertex\\n\"\n\"Raccourci: 2\"\n\n#: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:63\n#: res/xrc/OutfitStudio.xrc:2203\nmsgid \"Move\"\nmsgstr \"Bougez\"\n\n#: res/xrc/EditUV.xrc:68\nmsgid \"\"\n\"Move\\n\"\n\"Shortcut: 3\"\nmsgstr \"\"\n\"Bougez\\n\"\n\"Raccourci: 3\"\n\n#: res/xrc/EditUV.xrc:74 res/xrc/ShapeProperties.xrc:596\n#: src/program/NormalsGenDialog.cpp:320\nmsgid \"Scale\"\nmsgstr \"Échelle\"\n\n#: res/xrc/EditUV.xrc:75\nmsgid \"\"\n\"Scale\\n\"\n\"Shortcut: 4\"\nmsgstr \"\"\n\"Échelle\\n\"\n\"Raccourci: 4\"\n\n#: res/xrc/EditUV.xrc:81\nmsgid \"Rotate\"\nmsgstr \"Rotation\"\n\n#: res/xrc/EditUV.xrc:82\nmsgid \"\"\n\"Rotate\\n\"\n\"Shortcut: 5\"\nmsgstr \"\"\n\"Rotation\\n\"\n\"Raccourci: 5\"\n\n#: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89\nmsgid \"Show Seam Edges\"\nmsgstr \"Afficher les Bords de Couture\"\n\n#: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1714\nmsgid \"Menu\"\nmsgstr \"Menu\"\n\n#: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1828\nmsgid \"Edit\"\nmsgstr \"Modifiez\"\n\n#: res/xrc/EditUV.xrc:101 res/xrc/OutfitStudio.xrc:1830\nmsgid \"Undo\\tCtrl+Z\"\nmsgstr \"Annulez\\tCtrl+Z\"\n\n#: res/xrc/EditUV.xrc:102 res/xrc/OutfitStudio.xrc:1831\nmsgid \"Undo the previous action.\"\nmsgstr \"Annulez l'action précédente.\"\n\n#: res/xrc/EditUV.xrc:105 res/xrc/OutfitStudio.xrc:1834\nmsgid \"Redo\\tCtrl+Y\"\nmsgstr \"Refaire\\tCtrl+Y\"\n\n#: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:1835\nmsgid \"Redo the next undone action.\"\nmsgstr \"Refaire l'action suivante non effectuée.\"\n\n#: res/xrc/EditUV.xrc:109\nmsgid \"Select All\\tCtrl+A\"\nmsgstr \"Sélectionnez tout\\tCtrl+A\"\n\n#: res/xrc/EditUV.xrc:113\nmsgid \"Invert Selection\\tCtrl+I\"\nmsgstr \"Sélection d'inversion\\tCtrl+I\"\n\n#: res/xrc/EditUV.xrc:117\nmsgid \"Select Less\\tA\"\nmsgstr \"Sélectionnez moins\\tA\"\n\n#: res/xrc/EditUV.xrc:118\nmsgid \"Select less adjacent points in the selected islands.\"\nmsgstr \"Sélectionnez moins de points adjacents dans les îles sélectionnées.\"\n\n#: res/xrc/EditUV.xrc:121\nmsgid \"Select More\\tD\"\nmsgstr \"Sélectionnez plus\\tD\"\n\n#: res/xrc/EditUV.xrc:122\nmsgid \"Select more adjacent points in the selected islands.\"\nmsgstr \"Sélectionnez plus de points adjacents dans les îles sélectionnées.\"\n\n#: res/xrc/FBXImport.xrc:6\nmsgid \"FBX Import Options...\"\nmsgstr \"Options d'importation FBX...\"\n\n#: res/xrc/FBXImport.xrc:21\nmsgid \"Invert U\"\nmsgstr \"Inversez U\"\n\n#: res/xrc/FBXImport.xrc:30\nmsgid \"Invert V\"\nmsgstr \"Inversez V\"\n\n#: res/xrc/GroupManager.xrc:17\nmsgid \"\"\n\"Choose a group and add or remove members by selecting them in the lists.\"\nmsgstr \"\"\n\"Choisissez un groupe et ajoutez ou supprimez des membres en les \"\n\"sélectionnant dans les listes.\"\n\n#: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:952\nmsgid \"Select a group XML file\"\nmsgstr \"Sélectionnez un fichier XML de groupe\"\n\n#: res/xrc/GroupManager.xrc:71\nmsgid \"Groups\"\nmsgstr \"Groupes\"\n\n#: res/xrc/GroupManager.xrc:101\nmsgid \"Add Group\"\nmsgstr \"Ajouter le groupe\"\n\n#: res/xrc/GroupManager.xrc:110\nmsgid \"Remove Group\"\nmsgstr \"Supprimer le groupe\"\n\n#: res/xrc/GroupManager.xrc:122\nmsgid \"Members\"\nmsgstr \"Membres\"\n\n#: res/xrc/GroupManager.xrc:137\nmsgid \"Remove >>\"\nmsgstr \"Supprimer>>\"\n\n#: res/xrc/GroupManager.xrc:151\nmsgid \"Outfits\"\nmsgstr \"Tenues\"\n\n#: res/xrc/GroupManager.xrc:172\nmsgid \"<< Add\"\nmsgstr \"<< Ajouter\"\n\n#: res/xrc/NormalsGenDlg.xrc:6\nmsgid \"Normal Map Generator\"\nmsgstr \"Normal Map Generator\"\n\n#: res/xrc/NormalsGenDlg.xrc:21\nmsgid \"Layers\"\nmsgstr \"Couches\"\n\n#: res/xrc/NormalsGenDlg.xrc:37\nmsgid \"Load or save preset layer settings.\"\nmsgstr \"Chargez ou enregistrez les paramètres de couche prédéfinis.\"\n\n#: res/xrc/NormalsGenDlg.xrc:61\nmsgid \"Add a new layer after the current one in the layer list.\"\nmsgstr \"\"\n\"Ajoutez un nouveau calque après le calque actuel dans la liste des calques.\"\n\n#: res/xrc/NormalsGenDlg.xrc:62\nmsgid \"Add Layer\"\nmsgstr \"Ajouter une Couche\"\n\n#: res/xrc/NormalsGenDlg.xrc:71\nmsgid \"Move selected layer up one position.\"\nmsgstr \"Déplacer le calque sélectionné d'une position vers le haut.\"\n\n#: res/xrc/NormalsGenDlg.xrc:72\nmsgid \"Move Up\"\nmsgstr \"Déplacer vers le haut\"\n\n#: res/xrc/NormalsGenDlg.xrc:87\nmsgid \"Delete the selected layer.\"\nmsgstr \"Effacez la couche sélectionnée.\"\n\n#: res/xrc/NormalsGenDlg.xrc:88\nmsgid \"Delete Layer\"\nmsgstr \"Effacez une Couche\"\n\n#: res/xrc/NormalsGenDlg.xrc:108 res/xrc/Slider.xrc:161\nmsgid \"Options\"\nmsgstr \"Options\"\n\n#: res/xrc/NormalsGenDlg.xrc:114\nmsgid \"\"\n\"Save a copy of an existing normal map if one already exists. File is saved \"\n\"in the original directory.\"\nmsgstr \"\"\n\"Enregistrez une copie d'une carte normale existante s'il en existe déjà une. \"\n\"Le fichier est enregistré dans le répertoire d'origine.\"\n\n#: res/xrc/NormalsGenDlg.xrc:115\nmsgid \"Backup destination file\"\nmsgstr \"Fichier de destination de la sauvegarde\"\n\n#: res/xrc/NormalsGenDlg.xrc:124\nmsgid \"\"\n\"Compress output file using BC7 compression. This can make saving the file \"\n\"take a VERY long time!\"\nmsgstr \"\"\n\"Compressez le fichier de sortie à l'aide de la compression BC7. Cela peut \"\n\"rendre l'enregistrement du fichier TRÈS long!\"\n\n#: res/xrc/NormalsGenDlg.xrc:125\nmsgid \"Compress output \"\nmsgstr \"Compressez la sortie \"\n\n#: res/xrc/NormalsGenDlg.xrc:134\nmsgid \"\"\n\"Use the file name specified in the background layer to save the normal map.\"\nmsgstr \"\"\n\"Utilisez le nom de fichier spécifié dans la couche de fond pour enregistrer \"\n\"la carte normale.\"\n\n#: res/xrc/NormalsGenDlg.xrc:135\nmsgid \"Save to background layer file\"\nmsgstr \"Enregistrer dans le fichier de la couche de fond\"\n\n#: res/xrc/NormalsGenDlg.xrc:145\nmsgid \"Choose an output file...\"\nmsgstr \"Choisissez le fichier de sortie...\"\n\n#: res/xrc/NormalsGenDlg.xrc:149\nmsgid \"Location to save normal map to.\"\nmsgstr \"Emplacement où enregistrer la carte normale.\"\n\n#: res/xrc/NormalsGenDlg.xrc:165\nmsgid \"Display current settings on mesh in preview window.\"\nmsgstr \"\"\n\"Affiche les paramètres actuels sur le maillage dans la fenêtre d'aperçu.\"\n\n#: res/xrc/NormalsGenDlg.xrc:181\nmsgid \"Generate and save the normal map file.\"\nmsgstr \"Générez et enregistrez le fichier de carte normale.\"\n\n#: res/xrc/NormalsGenDlg.xrc:182\nmsgid \"Generate\"\nmsgstr \"Générez\"\n\n#: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2073\nmsgid \"Load Preset...\"\nmsgstr \"Chargez le préréglage...\"\n\n#: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2077\nmsgid \"Save Preset...\"\nmsgstr \"Sauvegarder le préréglage...\"\n\n#: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5\nmsgid \"New Project\"\nmsgstr \"Nouveau Projet\"\n\n#: res/xrc/OutfitStudio.xrc:23\nmsgid \"\"\n\"Create a new project by selecting a reference body slider set, and outfit \"\n\"model files.\"\nmsgstr \"\"\n\"Créez un nouveau projet en sélectionnant un jeu de slider de corps de \"\n\"référence et des fichiers de modèles d'équipement.\"\n\n#: res/xrc/OutfitStudio.xrc:28\nmsgid \"Load Project\"\nmsgstr \"Chargez Projet\"\n\n#: res/xrc/OutfitStudio.xrc:29\nmsgid \"Load a previously created slider set for editing.\"\nmsgstr \"Chargez un jeu de slider précédemment créé pour l'éditer.\"\n\n#: res/xrc/OutfitStudio.xrc:34 res/xrc/OutfitStudio.xrc:2182\nmsgid \"Select\"\nmsgstr \"Sélectionnez\"\n\n#: res/xrc/OutfitStudio.xrc:35 res/xrc/OutfitStudio.xrc:2183\nmsgid \"Navigate and select meshes (or vertices in vertex mode).\"\nmsgstr \"Naviguez et sélectionnez des mailles (ou des vertices en mode vertex).\"\n\n#: res/xrc/OutfitStudio.xrc:42 res/xrc/OutfitStudio.xrc:2187\n#: src/program/NormalsGenDialog.cpp:311\nmsgid \"Mask\"\nmsgstr \"Masque\"\n\n#: res/xrc/OutfitStudio.xrc:43 res/xrc/OutfitStudio.xrc:2188\nmsgid \"\"\n\"Mask vertices to prevent them from being transformed.\\n\"\n\"Hold down the ALT key to remove masking.\"\nmsgstr \"\"\n\"Masque les vertices pour éviter qu'ils ne soient transformés.\\n\"\n\"Maintenez la touche ALT enfoncée pour supprimer le masquage.\"\n\n#: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2192\nmsgid \"Inflate\"\nmsgstr \"Augmentez\"\n\n#: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2193\nmsgid \"Increase mesh volume in an area.\"\nmsgstr \"Augmentez le volume de la maille dans une zone.\"\n\n#: res/xrc/OutfitStudio.xrc:56 res/xrc/OutfitStudio.xrc:2198\nmsgid \"Deflate\"\nmsgstr \"Diminuez\"\n\n#: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2199\nmsgid \"Decrease mesh volume in an area.\"\nmsgstr \"Diminuer le volume de la maille dans une zone.\"\n\n#: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2204\nmsgid \"Move vertices over a plane parallel to the view.\"\nmsgstr \"Déplace les vertices sur un plan parallèle à la vue.\"\n\n#: res/xrc/OutfitStudio.xrc:70 res/xrc/OutfitStudio.xrc:2208\nmsgid \"Smooth\"\nmsgstr \"Lissez\"\n\n#: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2209\nmsgid \"Smooth an area of a mesh.\"\nmsgstr \"Lisser une zone d'une maille.\"\n\n#: res/xrc/OutfitStudio.xrc:77 res/xrc/OutfitStudio.xrc:2213\nmsgid \"Undiff\"\nmsgstr \"Undiff\"\n\n#: res/xrc/OutfitStudio.xrc:78 res/xrc/OutfitStudio.xrc:2214\nmsgid \"Undiff an area of a slider.\"\nmsgstr \"Undiff une zone d'un curseur.\"\n\n#: res/xrc/OutfitStudio.xrc:84 res/xrc/OutfitStudio.xrc:2218\nmsgid \"Weight Paint\"\nmsgstr \"Peinture de Poids\"\n\n#: res/xrc/OutfitStudio.xrc:85\nmsgid \"\"\n\"Apply animation weight values for currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"Appliquez des valeurs de poids d'animation pour l'os actuellement \"\n\"sélectionné.\\n\"\n\"Maintenez la touche ALT enfoncée pour affaiblir la pondération.\"\n\n#: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2224\nmsgid \"Color Paint\"\nmsgstr \"Peinture de Couleur\"\n\n#: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2225\nmsgid \"\"\n\"Apply vertex colors.\\n\"\n\"Hold down the ALT key to remove colors.\"\nmsgstr \"\"\n\"Appliquer les couleurs des vertex.\\n\"\n\"Maintenez la touche ALT enfoncée pour supprimer les couleurs.\"\n\n#: res/xrc/OutfitStudio.xrc:100 res/xrc/OutfitStudio.xrc:2230\nmsgid \"Alpha Paint\"\nmsgstr \"Peinture de l'Alpha\"\n\n#: res/xrc/OutfitStudio.xrc:101 res/xrc/OutfitStudio.xrc:2231\nmsgid \"\"\n\"Apply vertex alpha.\\n\"\n\"Hold down the ALT key to remove alpha.\"\nmsgstr \"\"\n\"Appliquer l'alpha de vertex.\\n\"\n\"Maintenez la touche ALT enfoncée pour supprimer l'alpha.\"\n\n#: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2236\nmsgid \"Collapse Vertex\"\nmsgstr \"Collapse Vertex\"\n\n#: res/xrc/OutfitStudio.xrc:109 res/xrc/OutfitStudio.xrc:2237\nmsgid \"\"\n\"Deletes vertices with no more than three connections, without creating a \"\n\"hole.\"\nmsgstr \"\"\n\"Supprime les vertices n'ayant pas plus de trois connexions, sans créer de \"\n\"trou.\"\n\n#: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2241\nmsgid \"Flip Edge\"\nmsgstr \"Retourner le Bord\"\n\n#: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2242\nmsgid \"Flips mesh edges so that the opposite pair of vertices is connected.\"\nmsgstr \"\"\n\"Retourne bords de la maille de manière à ce que la paire de vertices opposée \"\n\"soit connectée.\"\n\n#: res/xrc/OutfitStudio.xrc:122 res/xrc/OutfitStudio.xrc:2246\nmsgid \"Split Edge\"\nmsgstr \"Séparer le Bord\"\n\n#: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2247\nmsgid \"Splits a mesh edge in two with a new vertex.\"\nmsgstr \"Séparer un bord du maillage en deux avec un nouveau vertex.\"\n\n#: res/xrc/OutfitStudio.xrc:134\nmsgid \"Field of View\"\nmsgstr \"Champ de Vision\"\n\n#: res/xrc/OutfitStudio.xrc:138\nmsgid \"Field of View: 65\"\nmsgstr \"Champ de Vision: 65\"\n\n#: res/xrc/OutfitStudio.xrc:143\nmsgid \"Open Discord invite link.\"\nmsgstr \"Ouvrir le lien d'invitation Discord.\"\n\n#: res/xrc/OutfitStudio.xrc:148\nmsgid \"Open GitHub link.\"\nmsgstr \"Ouvrir le lien GitHub.\"\n\n#: res/xrc/OutfitStudio.xrc:153\nmsgid \"Open PayPal link.\"\nmsgstr \"Ouvrir le lien PayPal.\"\n\n#: res/xrc/OutfitStudio.xrc:174\nmsgid \"Transform\"\nmsgstr \"Transformez\"\n\n#: res/xrc/OutfitStudio.xrc:175 res/xrc/OutfitStudio.xrc:2253\nmsgid \"Shows a transform tool to manipulate shapes and vertices with.\"\nmsgstr \"\"\n\"Affiche un outil de transformation pour manipuler les formes et les vertices \"\n\"avec.\"\n\n#: res/xrc/OutfitStudio.xrc:181\nmsgid \"Pivot\"\nmsgstr \"Pivot\"\n\n#: res/xrc/OutfitStudio.xrc:182 res/xrc/OutfitStudio.xrc:2258\nmsgid \"\"\n\"Shows a pivot that can be moved and makes it the center of mesh operations \"\n\"like rotation and scale.\"\nmsgstr \"\"\n\"Affiche un pivot qui peut être déplacé et en fait le centre des opérations \"\n\"de maillage comme la rotation et l'échelle.\"\n\n#: res/xrc/OutfitStudio.xrc:188\nmsgid \"Vertex Edit\"\nmsgstr \"Modifiez Vertex\"\n\n#: res/xrc/OutfitStudio.xrc:189\nmsgid \"\"\n\"Lets you select vertices to add to or remove from the mask.\\n\"\n\"Click on a vertex to select/unmask it.\\n\"\n\"Hold down CTRL to unselect/mask it.\"\nmsgstr \"\"\n\"Vous permet de sélectionner les vertices à ajouter ou à retirer du masque.\\n\"\n\"Cliquez sur un vertex pour le sélectionner/démasquer.\\n\"\n\"Maintenez la touche CTRL enfoncée pour le désélectionner/masquer.\"\n\n#: res/xrc/OutfitStudio.xrc:196\nmsgid \"X Mirror\"\nmsgstr \"Miroir X\"\n\n#: res/xrc/OutfitStudio.xrc:197 res/xrc/OutfitStudio.xrc:1840\nmsgid \"Mirror edits across the X axis.\"\nmsgstr \"Miroir des modifications sur l'axe X.\"\n\n#: res/xrc/OutfitStudio.xrc:205 res/xrc/OutfitStudio.xrc:1846\nmsgid \"Edit Connected Only\\tC\"\nmsgstr \"Modifiez connecté uniquement\\tC\"\n\n#: res/xrc/OutfitStudio.xrc:206\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius.\"\nmsgstr \"\"\n\"Modifiez uniquement les vertices connectés à ceux situés sous le pinceau \"\n\"dans le rayon de la brosse.\"\n\n#: res/xrc/OutfitStudio.xrc:212 res/xrc/OutfitStudio.xrc:1852\nmsgid \"Global Brush Collision\\tB\"\nmsgstr \"Collision globale de brosses\\tB\"\n\n#: res/xrc/OutfitStudio.xrc:213\nmsgid \"\"\n\"Allows for the brushes to collide with all currently selected meshes at the \"\n\"same time.\"\nmsgstr \"\"\n\"Permet aux brosses d'entrer en collision avec toutes les mailles \"\n\"sélectionnées en même temps.\"\n\n#: res/xrc/OutfitStudio.xrc:220\nmsgid \"View Front\"\nmsgstr \"Voir l'avant\"\n\n#: res/xrc/OutfitStudio.xrc:221\nmsgid \"Change camera view to the front.\"\nmsgstr \"Changez la vue de la caméra vers l'avant.\"\n\n#: res/xrc/OutfitStudio.xrc:225\nmsgid \"View Back\"\nmsgstr \"Voir le dos\"\n\n#: res/xrc/OutfitStudio.xrc:226\nmsgid \"Change camera view to the back.\"\nmsgstr \"Changez la vue de la caméra vers le dos.\"\n\n#: res/xrc/OutfitStudio.xrc:230\nmsgid \"View Left\"\nmsgstr \"Voir à gauche\"\n\n#: res/xrc/OutfitStudio.xrc:231\nmsgid \"Change camera view to the left.\"\nmsgstr \"Changez la vue de la caméra vers la gauche.\"\n\n#: res/xrc/OutfitStudio.xrc:235\nmsgid \"View Right\"\nmsgstr \"Voir à droit\"\n\n#: res/xrc/OutfitStudio.xrc:236\nmsgid \"Change camera view to the right.\"\nmsgstr \"Changez la vue de la caméra vers la droit.\"\n\n#: res/xrc/OutfitStudio.xrc:240\nmsgid \"Perspective View\"\nmsgstr \"Voir Perspective\"\n\n#: res/xrc/OutfitStudio.xrc:241\nmsgid \"Toggle perspective view.\"\nmsgstr \"Basculez la vue en perspective.\"\n\n#: res/xrc/OutfitStudio.xrc:247\nmsgid \"Show Nodes\"\nmsgstr \"Affichez les Nœuds\"\n\n#: res/xrc/OutfitStudio.xrc:248\nmsgid \"Toggle rendering of nodes.\"\nmsgstr \"Basculer le rendu des noeuds.\"\n\n#: res/xrc/OutfitStudio.xrc:253\nmsgid \"Show Bones\"\nmsgstr \"Affichez les Os\"\n\n#: res/xrc/OutfitStudio.xrc:254\nmsgid \"Toggle rendering of bones.\"\nmsgstr \"Basculer le rendu des os.\"\n\n#: res/xrc/OutfitStudio.xrc:259\nmsgid \"Show Floor\"\nmsgstr \"Afficher l'Étage\"\n\n#: res/xrc/OutfitStudio.xrc:260\nmsgid \"Toggle rendering of the floor grid.\"\nmsgstr \"Basculer le rendu de grille l'étage.\"\n\n#: res/xrc/OutfitStudio.xrc:287\nmsgid \"Brush Settings\"\nmsgstr \"Paramètres des brosses\"\n\n#: res/xrc/OutfitStudio.xrc:302\nmsgid \"Size\"\nmsgstr \"Taille\"\n\n#: res/xrc/OutfitStudio.xrc:332\nmsgid \"Strength\"\nmsgstr \"Force\"\n\n#: res/xrc/OutfitStudio.xrc:362\nmsgid \"Focus\"\nmsgstr \"Concentrer\"\n\n#: res/xrc/OutfitStudio.xrc:392\nmsgid \"Spacing\"\nmsgstr \"Espacement\"\n\n#: res/xrc/OutfitStudio.xrc:469\nmsgid \"Meshes\"\nmsgstr \"Mailles\"\n\n#: res/xrc/OutfitStudio.xrc:481 res/xrc/OutfitStudio.xrc:2420\n#: res/xrc/OutfitStudio.xrc:2453\nmsgid \"Bones\"\nmsgstr \"Os\"\n\n#: res/xrc/OutfitStudio.xrc:493 res/xrc/OutfitStudio.xrc:2467\n#: res/xrc/OutfitStudio.xrc:2493\nmsgid \"Segments\"\nmsgstr \"Segments\"\n\n#: res/xrc/OutfitStudio.xrc:505 res/xrc/OutfitStudio.xrc:2500\n#: res/xrc/OutfitStudio.xrc:2511\nmsgid \"Partitions\"\nmsgstr \"Partitions\"\n\n#: res/xrc/OutfitStudio.xrc:517\nmsgid \"Colors\"\nmsgstr \"Les Couleurs\"\n\n#: res/xrc/OutfitStudio.xrc:529\nmsgid \"Lights\"\nmsgstr \"Lumières\"\n\n#: res/xrc/OutfitStudio.xrc:569\nmsgid \"Total Bones: 0\"\nmsgstr \"Total des Os: 0\"\n\n#: res/xrc/OutfitStudio.xrc:579\nmsgid \"Shape Selection Bones: 0\"\nmsgstr \"Sélection des Formes Os: 0\"\n\n#: res/xrc/OutfitStudio.xrc:607\nmsgid \"Brush Color\"\nmsgstr \"Couleur de Brosse\"\n\n#: res/xrc/OutfitStudio.xrc:616\nmsgid \"Color of the brush.\"\nmsgstr \"La couleur de la brosse.\"\n\n#: res/xrc/OutfitStudio.xrc:628 src/program/OutfitStudio.cpp:2952\n#: src/program/OutfitStudio.cpp:6292\nmsgid \"Edit Alpha\"\nmsgstr \"Modifiez l'Alpha\"\n\n#: res/xrc/OutfitStudio.xrc:674 res/xrc/OutfitStudio.xrc:1066\n#: res/xrc/OutfitStudio.xrc:1167 src/program/OutfitStudio.cpp:5967\n#: src/program/OutfitStudio.cpp:9666\nmsgid \"Reset\"\nmsgstr \"Réinitialiser\"\n\n#: res/xrc/OutfitStudio.xrc:687\nmsgid \"Ambient\"\nmsgstr \"Ambiante\"\n\n#: res/xrc/OutfitStudio.xrc:712\nmsgid \"Frontal\"\nmsgstr \"Frontale\"\n\n#: res/xrc/OutfitStudio.xrc:737\nmsgid \"Directional 1\"\nmsgstr \"Directionnel 1\"\n\n#: res/xrc/OutfitStudio.xrc:762\nmsgid \"Directional 2\"\nmsgstr \"Directionnel 2\"\n\n#: res/xrc/OutfitStudio.xrc:787\nmsgid \"Directional 3\"\nmsgstr \"Directionnel 3\"\n\n#: res/xrc/OutfitStudio.xrc:832 res/xrc/OutfitStudio.xrc:1084\n#: res/xrc/ShapeProperties.xrc:84 res/xrc/ShapeProperties.xrc:544\nmsgid \"Type\"\nmsgstr \"Catégorie\"\n\n#: res/xrc/OutfitStudio.xrc:955\nmsgid \"Slot\"\nmsgstr \"Fente\"\n\n#: res/xrc/OutfitStudio.xrc:1018 src/program/OutfitStudio.cpp:5122\nmsgid \"SSF File\"\nmsgstr \"Fichier SSF\"\n\n#: res/xrc/OutfitStudio.xrc:1038\nmsgid \"Set\"\nmsgstr \"Définir\"\n\n#: res/xrc/OutfitStudio.xrc:1056 res/xrc/OutfitStudio.xrc:1157\n#: src/program/OutfitStudio.cpp:5967 src/program/OutfitStudio.cpp:9693\nmsgid \"Apply\"\nmsgstr \"Appliquez\"\n\n#: res/xrc/OutfitStudio.xrc:1185\nmsgid \"De-/Select Sliders\"\nmsgstr \"Dé-/Sélectionnez les sliders\"\n\n#: res/xrc/OutfitStudio.xrc:1204\nmsgid \"Fixed Weight Brush\"\nmsgstr \"Brosse de poids fixe\"\n\n#: res/xrc/OutfitStudio.xrc:1215\nmsgid \"Normalize Weights\"\nmsgstr \"Normaliser les Poids\"\n\n#: res/xrc/OutfitStudio.xrc:1232\nmsgid \"X-Mirror Bone\"\nmsgstr \"Os du Miroir X\"\n\n#: res/xrc/OutfitStudio.xrc:1257\nmsgid \"Preview Scaling\"\nmsgstr \"Mise à l'échelle de l'aperçu\"\n\n#: res/xrc/OutfitStudio.xrc:1284\nmsgid \"Masks\"\nmsgstr \"Masques\"\n\n#: res/xrc/OutfitStudio.xrc:1328 res/xrc/OutfitStudio.xrc:2433\nmsgid \"Delete\"\nmsgstr \"Effacer\"\n\n#: res/xrc/OutfitStudio.xrc:1344\nmsgid \"Posing\"\nmsgstr \"Posant\"\n\n#: res/xrc/OutfitStudio.xrc:1361\nmsgid \"Show Pose\"\nmsgstr \"Afficher la Pose\"\n\n#: res/xrc/OutfitStudio.xrc:1379\nmsgid \"Reset Bone\"\nmsgstr \"Réinitialiser l'Os\"\n\n#: res/xrc/OutfitStudio.xrc:1399\nmsgid \"Rotation X\"\nmsgstr \"Rotation X\"\n\n#: res/xrc/OutfitStudio.xrc:1427\nmsgid \"Rotation Y\"\nmsgstr \"Rotation Y\"\n\n#: res/xrc/OutfitStudio.xrc:1455\nmsgid \"Rotation Z\"\nmsgstr \"Rotation Z\"\n\n#: res/xrc/OutfitStudio.xrc:1483\nmsgid \"Offset X\"\nmsgstr \"Décalage X\"\n\n#: res/xrc/OutfitStudio.xrc:1511\nmsgid \"Offset Y\"\nmsgstr \"Décalage Y\"\n\n#: res/xrc/OutfitStudio.xrc:1540\nmsgid \"Offset Z\"\nmsgstr \"Décalage Z\"\n\n#: res/xrc/OutfitStudio.xrc:1573\nmsgid \"Reset All\"\nmsgstr \"Réinitialiser Toute\"\n\n#: res/xrc/OutfitStudio.xrc:1581\nmsgid \"Apply to Mesh\"\nmsgstr \"Appliquer à la Maille\"\n\n#: res/xrc/OutfitStudio.xrc:1716 res/xrc/Settings.xrc:343\n#: src/program/NormalsGenDialog.cpp:304\nmsgid \"File\"\nmsgstr \"Fichier\"\n\n#: res/xrc/OutfitStudio.xrc:1718\nmsgid \"New Project...\\tCtrl+N\"\nmsgstr \"Nouveau Projet...\\tCtrl+N\"\n\n#: res/xrc/OutfitStudio.xrc:1719\nmsgid \"Create a new outfit project.\"\nmsgstr \"Créez un nouveau projet de tenue.\"\n\n#: res/xrc/OutfitStudio.xrc:1722\nmsgid \"Load Project..\\tCtrl+O\"\nmsgstr \"Chargez le Projet..\\tCtrl+O\"\n\n#: res/xrc/OutfitStudio.xrc:1723\nmsgid \"Load a project.\"\nmsgstr \"Chargez un projet.\"\n\n#: res/xrc/OutfitStudio.xrc:1726\nmsgid \"Add Project..\\tCtrl+Shift+O\"\nmsgstr \"Ajoutez un Projet...\\tCtrl+Shift+O\"\n\n#: res/xrc/OutfitStudio.xrc:1727\nmsgid \"Add a project without replacing the current one.\"\nmsgstr \"Ajouter un projet sans remplacer le projet actuel.\"\n\n#: res/xrc/OutfitStudio.xrc:1730\nmsgid \"Unload Project...\\tCtrl+W\"\nmsgstr \"Déchargez le Projet...\\tCtrl+W\"\n\n#: res/xrc/OutfitStudio.xrc:1731\nmsgid \"Unloads the project and creates an empty new one.\"\nmsgstr \"Décharge le projet et crée un nouveau projet vide.\"\n\n#: res/xrc/OutfitStudio.xrc:1735\nmsgid \"Load Reference...\"\nmsgstr \"Chargez un référence...\"\n\n#: res/xrc/OutfitStudio.xrc:1736\nmsgid \"\"\n\"Load a new reference slider set, replacing any current reference objects.\"\nmsgstr \"\"\n\"Chargez un nouveau slider set de référence, remplaçant tous les objets de \"\n\"référence actuels.\"\n\n#: res/xrc/OutfitStudio.xrc:1739\nmsgid \"Load Outfit...\"\nmsgstr \"Chargez la tenue...\"\n\n#: res/xrc/OutfitStudio.xrc:1740\nmsgid \"\"\n\"Load a NIF file as the working outfit, replacing any current outfit objects.\"\nmsgstr \"\"\n\"Chargez un fichier NIF comme tenue de travail, en remplaçant tous les objets \"\n\"de la tenue actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:1744\nmsgid \"Save Project\\tCtrl+S\"\nmsgstr \"Sauvegarder le Projet\\tCtrl+S\"\n\n#: res/xrc/OutfitStudio.xrc:1745\nmsgid \"Save the project.\"\nmsgstr \"Sauvegarder le projet.\"\n\n#: res/xrc/OutfitStudio.xrc:1749\nmsgid \"Save Project As...\\tCtrl+Shift+S\"\nmsgstr \"Sauvegarder le Projet Sous...\\tCtrl+Shift+S\"\n\n#: res/xrc/OutfitStudio.xrc:1750\nmsgid \"Save the project under a new name.\"\nmsgstr \"Sauvegarder le projet sous un nouveau nom.\"\n\n#: res/xrc/OutfitStudio.xrc:1754 src/program/OutfitStudio.cpp:6823\n#: src/program/OutfitStudio.cpp:6913\nmsgid \"Import\"\nmsgstr \"Importez\"\n\n#: res/xrc/OutfitStudio.xrc:1756\nmsgid \"From NIF...\"\nmsgstr \"De NIF...\"\n\n#: res/xrc/OutfitStudio.xrc:1757\nmsgid \"Choose a NIF file to import into the project.\"\nmsgstr \"Choisissez un fichier NIF à importer dans le projet.\"\n\n#: res/xrc/OutfitStudio.xrc:1760\nmsgid \"From OBJ...\"\nmsgstr \"De OBJ...\"\n\n#: res/xrc/OutfitStudio.xrc:1761\nmsgid \"Import an OBJ file as a new shape in the outfit.\"\nmsgstr \"Importez un fichier OBJ comme une nouvelle forme dans l'équipement.\"\n\n#: res/xrc/OutfitStudio.xrc:1764\nmsgid \"From FBX...\"\nmsgstr \"De FBX...\"\n\n#: res/xrc/OutfitStudio.xrc:1765\nmsgid \"Import an FBX file as a new shape in the outfit.\"\nmsgstr \"Importez un fichier FBX comme une nouvelle forme dans l'équipement.\"\n\n#: res/xrc/OutfitStudio.xrc:1768\nmsgid \"From TRI (Head)...\"\nmsgstr \"De TRI (Tête)...\"\n\n#: res/xrc/OutfitStudio.xrc:1769\nmsgid \"Import shape and morphs from a head TRI file.\"\nmsgstr \"Importez des formes et des morphes à partir d'un fichier TRI de tête.\"\n\n#: res/xrc/OutfitStudio.xrc:1772\nmsgid \"Import Data\"\nmsgstr \"Importez des données\"\n\n#: res/xrc/OutfitStudio.xrc:1774\nmsgid \"Import BSClothExtraData From HKX\"\nmsgstr \"Importez BSClothExtraData de HKX\"\n\n#: res/xrc/OutfitStudio.xrc:1775\nmsgid \"\"\n\"Choose an HKX file to import as a BSClothExtraData block into the project.\"\nmsgstr \"\"\n\"Choisissez un fichier HKX à importer comme bloc BSClothExtraData dans le \"\n\"projet.\"\n\n#: res/xrc/OutfitStudio.xrc:1780 res/xrc/OutfitStudio.xrc:1932\n#: res/xrc/OutfitStudio.xrc:2307\nmsgid \"Export\"\nmsgstr \"Exporter\"\n\n#: res/xrc/OutfitStudio.xrc:1782\nmsgid \"To NIF...\\tCtrl+E\"\nmsgstr \"Vers NIF...\\tCtrl+E\"\n\n#: res/xrc/OutfitStudio.xrc:1783\nmsgid \"Save the current project as a NIF file (without reference)\"\nmsgstr \"Sauvegarder le projet en cours comme un fichier NIF (sans référence)\"\n\n#: res/xrc/OutfitStudio.xrc:1786\nmsgid \"To NIF With Reference...\\tCtrl+Alt+E\"\nmsgstr \"Vers NIF avec Référence...\\tCtrl+Alt+E\"\n\n#: res/xrc/OutfitStudio.xrc:1787\nmsgid \"Save the current project as a NIF file (including reference)\"\nmsgstr \"\"\n\"Sauvegarder le projet en cours comme un fichier NIF (y compris la référence)\"\n\n#: res/xrc/OutfitStudio.xrc:1790 res/xrc/OutfitStudio.xrc:1938\n#: res/xrc/OutfitStudio.xrc:2313\nmsgid \"To OBJ...\"\nmsgstr \"Vers OBJ...\"\n\n#: res/xrc/OutfitStudio.xrc:1791\nmsgid \"Export the current project as an OBJ file.\"\nmsgstr \"Exportez le projet en cours sous forme de fichier OBJ.\"\n\n#: res/xrc/OutfitStudio.xrc:1794 res/xrc/OutfitStudio.xrc:1942\n#: res/xrc/OutfitStudio.xrc:2317\nmsgid \"To FBX...\"\nmsgstr \"Vers FBX...\"\n\n#: res/xrc/OutfitStudio.xrc:1795\nmsgid \"Export the current project as an FBX file.\"\nmsgstr \"Exportez le projet en cours sous forme de fichier FBX.\"\n\n#: res/xrc/OutfitStudio.xrc:1798 res/xrc/OutfitStudio.xrc:1946\n#: res/xrc/OutfitStudio.xrc:2321\nmsgid \"To TRI (Head)...\"\nmsgstr \"Vers TRI (Tête)...\"\n\n#: res/xrc/OutfitStudio.xrc:1799 res/xrc/OutfitStudio.xrc:1947\n#: res/xrc/OutfitStudio.xrc:2322\nmsgid \"Export head morphs to a TRI file.\"\nmsgstr \"Exportez les morphes de tête dans un fichier TRI.\"\n\n#: res/xrc/OutfitStudio.xrc:1802\nmsgid \"Export Data\"\nmsgstr \"Exporter des données\"\n\n#: res/xrc/OutfitStudio.xrc:1804\nmsgid \"Export BSClothExtraData As HKX\"\nmsgstr \"Exporter BSClothExtraData comme HKX\"\n\n#: res/xrc/OutfitStudio.xrc:1805\nmsgid \"\"\n\"Save one of the currently loaded BSClothExtraData blocks to an HKX file.\"\nmsgstr \"\"\n\"Sauvegarder l'un des blocs BSClothExtraData actuellement chargés dans un \"\n\"fichier HKX.\"\n\n#: res/xrc/OutfitStudio.xrc:1810\nmsgid \"Make Conversion Reference\"\nmsgstr \"Créer une référence de conversion\"\n\n#: res/xrc/OutfitStudio.xrc:1811\nmsgid \"\"\n\"Using the current slider settings for the reference shape, create a new \"\n\"reference that will morph from the current shape back to the base shape.\"\nmsgstr \"\"\n\"À l'aide des paramètres de slider actuels pour la forme de référence, créez \"\n\"une nouvelle référence qui passera de la forme actuelle à la forme de base.\"\n\n#: res/xrc/OutfitStudio.xrc:1815 res/xrc/Project.xrc:908\nmsgid \"Pack Projects...\"\nmsgstr \"Emballez des Projets...\"\n\n#: res/xrc/OutfitStudio.xrc:1816\nmsgid \"Pack one or more projects into a folder or archive for sharing.\"\nmsgstr \"\"\n\"Emballez un ou plusieurs projets dans un dossier ou une archive pour les \"\n\"partager.\"\n\n#: res/xrc/OutfitStudio.xrc:1823\nmsgid \"Exit\\tAlt+F4\"\nmsgstr \"Sortir\\tAlt+F4\"\n\n#: res/xrc/OutfitStudio.xrc:1824\nmsgid \"Exit Outfit Studio.\"\nmsgstr \"Sortie de l'Outfit Studio.\"\n\n#: res/xrc/OutfitStudio.xrc:1839\nmsgid \"X Mirror\\tX\"\nmsgstr \"Miroir X\\tX\"\n\n#: res/xrc/OutfitStudio.xrc:1847\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius\"\nmsgstr \"\"\n\"Modifiez uniquement les vertices connectés à ceux situés sous le pinceau \"\n\"dans le rayon du pinceau\"\n\n#: res/xrc/OutfitStudio.xrc:1853\nmsgid \"\"\n\"Allows for the brushes to collide with all currently selected meshes at the \"\n\"same time\"\nmsgstr \"\"\n\"Permet aux brosses d'entrer en collision avec toutes les mailles \"\n\"sélectionnées en même temps\"\n\n#: res/xrc/OutfitStudio.xrc:1859\nmsgid \"Recalculate Normals\\tR\"\nmsgstr \"Recalculer les normales\\tR\"\n\n#: res/xrc/OutfitStudio.xrc:1860\nmsgid \"Recalculate normals on active mesh\"\nmsgstr \"Recalculer les normales sur le maillage actif\"\n\n#: res/xrc/OutfitStudio.xrc:1863\nmsgid \"Reset Transforms\"\nmsgstr \"Réinitialisation des transformations\"\n\n#: res/xrc/OutfitStudio.xrc:1864\nmsgid \"Resets the shape and skin transforms.\"\nmsgstr \"Réinitialise la forme et la peau se transforme.\"\n\n#: res/xrc/OutfitStudio.xrc:1867 src/program/OutfitStudio.cpp:9255\nmsgid \"Delete Unreferenced Nodes\"\nmsgstr \"Effacer les Nœuds Non Référencés\"\n\n#: res/xrc/OutfitStudio.xrc:1868\nmsgid \"Deletes all nodes from the project that aren't used in any other block.\"\nmsgstr \"\"\n\"Effacer tous les nœuds du projet qui ne sont pas utilisés dans un autre bloc.\"\n\n#: res/xrc/OutfitStudio.xrc:1871\nmsgid \"Remove Skinning\"\nmsgstr \"Supprimer l'Habillage\"\n\n#: res/xrc/OutfitStudio.xrc:1872\nmsgid \"Removes skinning of all shapes and all unused nodes.\"\nmsgstr \"\"\n\"Supprime l'habillage de toutes les formes et de tous les nœuds inutilisés.\"\n\n#: res/xrc/OutfitStudio.xrc:1876\nmsgid \"View\"\nmsgstr \"Voir\"\n\n#: res/xrc/OutfitStudio.xrc:1878\nmsgid \"Front\\tShift+1\"\nmsgstr \"Avant\\tShift+1\"\n\n#: res/xrc/OutfitStudio.xrc:1881\nmsgid \"Back\\tShift+2\"\nmsgstr \"Dos\\tShift+2\"\n\n#: res/xrc/OutfitStudio.xrc:1884\nmsgid \"Left\\tShift+3\"\nmsgstr \"Gauche\\tShift+3\"\n\n#: res/xrc/OutfitStudio.xrc:1887\nmsgid \"Right\\tShift+4\"\nmsgstr \"Droit\\tShift+4\"\n\n#: res/xrc/OutfitStudio.xrc:1890\nmsgid \"Perspective\\tShift+5\"\nmsgstr \"Perspective\\tShift+5\"\n\n#: res/xrc/OutfitStudio.xrc:1895\nmsgid \"Show Nodes\\tShift+N\"\nmsgstr \"Affichez les Nœuds\\tShift+N\"\n\n#: res/xrc/OutfitStudio.xrc:1899\nmsgid \"Show Bones\\tShift+B\"\nmsgstr \"Affichez les Os\\tShift+B\"\n\n#: res/xrc/OutfitStudio.xrc:1903\nmsgid \"Show Floor\\tG\"\nmsgstr \"Afficher l'Étage\\tG\"\n\n#: res/xrc/OutfitStudio.xrc:1908\nmsgid \"Toggle Visibility\\tE\"\nmsgstr \"Basculez la visibilité\\tE\"\n\n#: res/xrc/OutfitStudio.xrc:1909\nmsgid \"Switch between the different visibility modes for the selected shapes.\"\nmsgstr \"\"\n\"Basculez entre les différents modes de visibilité des formes sélectionnées.\"\n\n#: res/xrc/OutfitStudio.xrc:1912\nmsgid \"Show Wireframe\\tW\"\nmsgstr \"Affichez le filaire\\tW\"\n\n#: res/xrc/OutfitStudio.xrc:1913\nmsgid \"Show wireframe on all models.\"\nmsgstr \"Affichez le filaire sur tous les modèles.\"\n\n#: res/xrc/OutfitStudio.xrc:1917\nmsgid \"Enable Lighting\\tL\"\nmsgstr \"Activer l'éclairage\\tL\"\n\n#: res/xrc/OutfitStudio.xrc:1918\nmsgid \"Turn on or off lighting.\"\nmsgstr \"Allumez ou éteignez l'éclairage.\"\n\n#: res/xrc/OutfitStudio.xrc:1923\nmsgid \"Enable Textures\\tT\"\nmsgstr \"Activer Textures\\tT\"\n\n#: res/xrc/OutfitStudio.xrc:1924\nmsgid \"Display texture maps on models.\"\nmsgstr \"Affichez les cartes de texture sur les modèles.\"\n\n#: res/xrc/OutfitStudio.xrc:1930 res/xrc/OutfitStudio.xrc:2305\nmsgid \"Shape\"\nmsgstr \"Forme\"\n\n#: res/xrc/OutfitStudio.xrc:1934 res/xrc/OutfitStudio.xrc:2309\nmsgid \"To NIF...\"\nmsgstr \"Vers NIF...\"\n\n#: res/xrc/OutfitStudio.xrc:1935 res/xrc/OutfitStudio.xrc:2310\nmsgid \"Export only the selected shapes to a NIF file.\"\nmsgstr \"Exportez uniquement les formes sélectionnées vers un fichier NIF.\"\n\n#: res/xrc/OutfitStudio.xrc:1939 res/xrc/OutfitStudio.xrc:2314\nmsgid \"Export only the selected shapes to an OBJ file.\"\nmsgstr \"Exporter uniquement les formes sélectionnées vers un fichier OBJ.\"\n\n#: res/xrc/OutfitStudio.xrc:1943 res/xrc/OutfitStudio.xrc:2318\nmsgid \"Export only the selected shapes to an FBX file.\"\nmsgstr \"Exportez uniquement les formes sélectionnées vers un fichier FBX.\"\n\n#: res/xrc/OutfitStudio.xrc:1951 res/xrc/OutfitStudio.xrc:2326\n#: res/xrc/Slider.xrc:200\nmsgid \"UV\"\nmsgstr \"UV\"\n\n#: res/xrc/OutfitStudio.xrc:1953 res/xrc/OutfitStudio.xrc:2328\nmsgid \"Edit...\"\nmsgstr \"Modifiez...\"\n\n#: res/xrc/OutfitStudio.xrc:1954 res/xrc/OutfitStudio.xrc:2329\nmsgid \"Edit the texture coordinates.\"\nmsgstr \"Modifiez les coordonnées de la texture.\"\n\n#: res/xrc/OutfitStudio.xrc:1957 res/xrc/OutfitStudio.xrc:2332\nmsgid \"Invert X\"\nmsgstr \"Inversez X\"\n\n#: res/xrc/OutfitStudio.xrc:1958 res/xrc/OutfitStudio.xrc:2333\nmsgid \"Inverts the X-axis of the texture coordinates.\"\nmsgstr \"Inverse l'axe X des coordonnées de la texture.\"\n\n#: res/xrc/OutfitStudio.xrc:1961 res/xrc/OutfitStudio.xrc:2336\nmsgid \"Invert Y\"\nmsgstr \"Inversez Y\"\n\n#: res/xrc/OutfitStudio.xrc:1962 res/xrc/OutfitStudio.xrc:2337\nmsgid \"Inverts the Y-axis of the texture coordinates.\"\nmsgstr \"Inverse l'axe Y des coordonnées de la texture.\"\n\n#: res/xrc/OutfitStudio.xrc:1966 res/xrc/OutfitStudio.xrc:2341\nmsgid \"Mirror\"\nmsgstr \"Miroir\"\n\n#: res/xrc/OutfitStudio.xrc:1969 res/xrc/OutfitStudio.xrc:2344\nmsgid \"Mirror the selected shapes on the X-axis.\"\nmsgstr \"Miroir les formes sélectionnées sur l'axe X.\"\n\n#: res/xrc/OutfitStudio.xrc:1973 res/xrc/OutfitStudio.xrc:2348\nmsgid \"Mirror the selected shapes on the Y-axis.\"\nmsgstr \"Miroir les formes sélectionnées sur l'axe Y.\"\n\n#: res/xrc/OutfitStudio.xrc:1977 res/xrc/OutfitStudio.xrc:2352\nmsgid \"Mirror the selected shapes on the Z-axis.\"\nmsgstr \"Miroir les formes sélectionnées sur l'axe Z.\"\n\n#: res/xrc/OutfitStudio.xrc:1981 res/xrc/OutfitStudio.xrc:2356\nmsgid \"Delete Vertices...\\tShift+Del\"\nmsgstr \"Effacer Vertices...\\tShift+Del\"\n\n#: res/xrc/OutfitStudio.xrc:1982 res/xrc/OutfitStudio.xrc:2357\nmsgid \"Deletes all unmasked vertices of the currently selected shapes.\"\nmsgstr \"\"\n\"Supprime tous les vertices non masqués des formes actuellement sélectionnées.\"\n\n#: res/xrc/OutfitStudio.xrc:1985 res/xrc/OutfitStudio.xrc:2360\n#: src/program/OutfitStudio.cpp:8329\nmsgid \"Separate Vertices...\\tShift+S\"\nmsgstr \"Vertices séparés...\\tShift+S\"\n\n#: res/xrc/OutfitStudio.xrc:1986 res/xrc/OutfitStudio.xrc:2361\nmsgid \"Separate the current shape into two by using the mask.\"\nmsgstr \"Séparez la forme actuelle en deux à l'aide du masque.\"\n\n#: res/xrc/OutfitStudio.xrc:1989 res/xrc/OutfitStudio.xrc:2364\nmsgid \"Copy Geometry...\"\nmsgstr \"Copier la Géométrie...\"\n\n#: res/xrc/OutfitStudio.xrc:1990 res/xrc/OutfitStudio.xrc:2365\nmsgid \"Copies vertices and triangles from one shape to another.\"\nmsgstr \"Copie les vertices et les triangles d'une forme à une autre.\"\n\n#: res/xrc/OutfitStudio.xrc:1993 res/xrc/OutfitStudio.xrc:2368\nmsgid \"Duplicate...\"\nmsgstr \"Dupliquez...\"\n\n#: res/xrc/OutfitStudio.xrc:1994 res/xrc/OutfitStudio.xrc:2369\nmsgid \"Duplicate the current shape.\"\nmsgstr \"Dupliquez la forme actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:1997 res/xrc/OutfitStudio.xrc:2372\nmsgid \"Rename...\\tF2\"\nmsgstr \"Renommez...\\tF2\"\n\n#: res/xrc/OutfitStudio.xrc:1998 res/xrc/OutfitStudio.xrc:2373\nmsgid \"Change the name of the current shape.\"\nmsgstr \"Change le nom de la forme actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2001 res/xrc/OutfitStudio.xrc:2376\nmsgid \"Set Reference\"\nmsgstr \"Définir la référence\"\n\n#: res/xrc/OutfitStudio.xrc:2002 res/xrc/OutfitStudio.xrc:2377\nmsgid \"Turn the shape into the reference shape of the project.\"\nmsgstr \"Transformez la forme en forme de référence du projet.\"\n\n#: res/xrc/OutfitStudio.xrc:2006 res/xrc/OutfitStudio.xrc:2381\nmsgid \"Move...\"\nmsgstr \"Bougez...\"\n\n#: res/xrc/OutfitStudio.xrc:2007 res/xrc/OutfitStudio.xrc:2382\nmsgid \"\"\n\"Apply an offset adjustment to the mesh vertices. This permanently moves \"\n\"vertices.\"\nmsgstr \"\"\n\"Appliquez un ajustement de décalage aux vertices du maillage. Cela déplace \"\n\"définitivement les vertices.\"\n\n#: res/xrc/OutfitStudio.xrc:2010 res/xrc/OutfitStudio.xrc:2385\nmsgid \"Scale...\"\nmsgstr \"Échelle...\"\n\n#: res/xrc/OutfitStudio.xrc:2011 res/xrc/OutfitStudio.xrc:2386\nmsgid \"Apply a scale adjustment to the shape. This permanently moves vertices.\"\nmsgstr \"\"\n\"Appliquez un ajustement d'échelle à la forme. Cela déplace définitivement \"\n\"les vertices.\"\n\n#: res/xrc/OutfitStudio.xrc:2014 res/xrc/OutfitStudio.xrc:2389\nmsgid \"Rotate...\"\nmsgstr \"Rotation...\"\n\n#: res/xrc/OutfitStudio.xrc:2015 res/xrc/OutfitStudio.xrc:2390\nmsgid \"Apply a rotation to the mesh vertices. This permanently moves vertices.\"\nmsgstr \"\"\n\"Appliquez une rotation aux vertices du maillage. Cela déplace définitivement \"\n\"les vertices.\"\n\n#: res/xrc/OutfitStudio.xrc:2018\nmsgid \"Smooth Seam Normals\"\nmsgstr \"Couture lisse normales\"\n\n#: res/xrc/OutfitStudio.xrc:2019\nmsgid \"\"\n\"Smooths edges of seams (usually found at texture borders), disable if this \"\n\"causes odd normals on the shape.\"\nmsgstr \"\"\n\"Lisse les bords des coutures (généralement présentes aux bordures de \"\n\"texture), désactivez si cela provoque des normales impaires sur la forme.\"\n\n#: res/xrc/OutfitStudio.xrc:2024\nmsgid \"Lock Normals\"\nmsgstr \"Verrouiller les normales\"\n\n#: res/xrc/OutfitStudio.xrc:2025\nmsgid \"\"\n\"Locks the mesh normals. Enable if you want to keep custom normals intact.\"\nmsgstr \"\"\n\"Verrouille les normales du maillage. Activez si vous voulez garder les \"\n\"normales personnalisées intactes.\"\n\n#: res/xrc/OutfitStudio.xrc:2032 res/xrc/OutfitStudio.xrc:2395\nmsgid \"Copies all bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\"Copie tous les poids des os de la forme de référence vers la forme actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2035 res/xrc/OutfitStudio.xrc:2398\nmsgid \"Copy Selected Weights\"\nmsgstr \"Copier les poids sélectionnés\"\n\n#: res/xrc/OutfitStudio.xrc:2036 res/xrc/OutfitStudio.xrc:2399\nmsgid \"\"\n\"Copies selected bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\"Copie les poids des os sélectionnés de la forme de référence vers la forme \"\n\"actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2039 res/xrc/OutfitStudio.xrc:2402\nmsgid \"Transfer Selected Weights\"\nmsgstr \"Transférer les poids sélectionnés\"\n\n#: res/xrc/OutfitStudio.xrc:2040 res/xrc/OutfitStudio.xrc:2403\nmsgid \"\"\n\"Transfers selected weights from the reference shape to the current shape. \"\n\"Requires same vertex count and order.\"\nmsgstr \"\"\n\"Transfère les poids sélectionnés de la forme de référence à la forme \"\n\"actuelle. Nécessite le même nombre de vertex et le même ordre.\"\n\n#: res/xrc/OutfitStudio.xrc:2043 res/xrc/OutfitStudio.xrc:2406\n#: res/xrc/OutfitStudio.xrc:2448\nmsgid \"Mask Weighted Vertices\"\nmsgstr \"Masquer les Vertices Pondérés\"\n\n#: res/xrc/OutfitStudio.xrc:2044 res/xrc/OutfitStudio.xrc:2407\nmsgid \"\"\n\"Masks vertices with bone weights, so you can manually assign weights to \"\n\"unweighted vertices.\"\nmsgstr \"\"\n\"Masque les vertices avec des poids d'os, afin que vous puissiez attribuer \"\n\"manuellement des poids aux vertices non pondérés.\"\n\n#: res/xrc/OutfitStudio.xrc:2048 res/xrc/OutfitStudio.xrc:2411\nmsgid \"Delete\\tDel\"\nmsgstr \"Effacer\\tDel\"\n\n#: res/xrc/OutfitStudio.xrc:2049 res/xrc/OutfitStudio.xrc:2412\nmsgid \"Removes the currently selected shape from the outfit.\"\nmsgstr \"Supprime la forme actuellement sélectionnée de la tenue.\"\n\n#: res/xrc/OutfitStudio.xrc:2052 res/xrc/OutfitStudio.xrc:2415\nmsgid \"Properties...\"\nmsgstr \"Propriétés...\"\n\n#: res/xrc/OutfitStudio.xrc:2053 res/xrc/OutfitStudio.xrc:2416\nmsgid \"\"\n\"Opens the properties dialog for shader, texture and more settings of the \"\n\"selected shape.\"\nmsgstr \"\"\n\"Ouvre la boîte de dialogue des propriétés pour les paramètres d'ombrage, de \"\n\"texture et autres de la forme sélectionnée.\"\n\n#: res/xrc/OutfitStudio.xrc:2057\nmsgid \"Slider\"\nmsgstr \"Curseur\"\n\n#: res/xrc/OutfitStudio.xrc:2059\nmsgid \"Conform Selected\\tCtrl+C\"\nmsgstr \"Conforme sélectionné\\tCtrl+C\"\n\n#: res/xrc/OutfitStudio.xrc:2060\nmsgid \"Conform selected outfit shape to all checked sliders.\"\nmsgstr \"Conforme la forme de la tenue sélectionnée à tous les sliders cochés.\"\n\n#: res/xrc/OutfitStudio.xrc:2063\nmsgid \"Conform All\\tCtrl+Shift+C\"\nmsgstr \"Conforme tout\\tCtrl+Shift+C\"\n\n#: res/xrc/OutfitStudio.xrc:2064\nmsgid \"Conform all outfit shapes to all checked sliders.\"\nmsgstr \"Conforme toutes les formes de tenue à tous les sliders cochés.\"\n\n#: res/xrc/OutfitStudio.xrc:2068\nmsgid \"Set Base Shape\"\nmsgstr \"Définir la forme de la base\"\n\n#: res/xrc/OutfitStudio.xrc:2069\nmsgid \"Set the current outfit shape as the base shape and clear slider data.\"\nmsgstr \"\"\n\"Définir la forme de la tenue actuelle comme forme de base et effacer les \"\n\"données du slider.\"\n\n#: res/xrc/OutfitStudio.xrc:2074\nmsgid \"\"\n\"Load and preview a slider preset. Inverted sliders will have inverted values.\"\nmsgstr \"\"\n\"Chargez et prévisualisez un préréglage de slider. Les sliders inversés \"\n\"auront des valeurs inversées.\"\n\n#: res/xrc/OutfitStudio.xrc:2078\nmsgid \"\"\n\"Save a slider preset with the current values. Inverted sliders will have \"\n\"inverted values.\"\nmsgstr \"\"\n\"Sauvegarder un préréglage de slider avec les valeurs actuelles. Les valeurs \"\n\"des sliders inversés seront inversées.\"\n\n#: res/xrc/OutfitStudio.xrc:2082\nmsgid \"New Slider\"\nmsgstr \"Nouveau slider\"\n\n#: res/xrc/OutfitStudio.xrc:2083\nmsgid \"Create a new shape transformation slider.\"\nmsgstr \"Créez un nouveau slider de transformation de forme.\"\n\n#: res/xrc/OutfitStudio.xrc:2086\nmsgid \"Coalesce sliders\"\nmsgstr \"Coalescez les sliders\"\n\n#: res/xrc/OutfitStudio.xrc:2087\nmsgid \"\"\n\"Create a new shape transformation slider based on the current slider values\"\nmsgstr \"\"\n\"Créer un nouveau slider de transformation de forme basé sur les valeurs \"\n\"actuelles du slider\"\n\n#: res/xrc/OutfitStudio.xrc:2090\nmsgid \"New Zap Slider\"\nmsgstr \"Nouveau slider Zap\"\n\n#: res/xrc/OutfitStudio.xrc:2091\nmsgid \"Create a new Zap slider based on unmasked vertices\"\nmsgstr \"Créer un nouveau slider Zap basé sur les vertices non masqués\"\n\n#: res/xrc/OutfitStudio.xrc:2095\nmsgid \"Import OSD...\"\nmsgstr \"Importez OSD...\"\n\n#: res/xrc/OutfitStudio.xrc:2096\nmsgid \"Imports OSD file and creates sliders for shapes with a matching name.\"\nmsgstr \"\"\n\"Importe le fichier OSD et crée des sliders pour les formes dont le nom \"\n\"correspond.\"\n\n#: res/xrc/OutfitStudio.xrc:2099\nmsgid \"Export OSD...\"\nmsgstr \"Exportez OSD...\"\n\n#: res/xrc/OutfitStudio.xrc:2100\nmsgid \"Exports all currently loaded slider data to an OSD file.\"\nmsgstr \"\"\n\"Exporte toutes les données des sliders actuellement chargés vers un fichier \"\n\"OSD.\"\n\n#: res/xrc/OutfitStudio.xrc:2103\nmsgid \"Import TRI Morphs...\"\nmsgstr \"Importez TRI Morphs...\"\n\n#: res/xrc/OutfitStudio.xrc:2104\nmsgid \"\"\n\"Imports TRI morphs from a TRI file and creates sliders for shapes with a \"\n\"matching name.\"\nmsgstr \"\"\n\"Importe des TRI Morphs à partir d'un fichier TRI et crée des sliders pour \"\n\"les formes avec un nom correspondant.\"\n\n#: res/xrc/OutfitStudio.xrc:2107\nmsgid \"Export TRI Morphs...\"\nmsgstr \"Exportez TRI Morphs...\"\n\n#: res/xrc/OutfitStudio.xrc:2108\nmsgid \"Exports TRI morphs to a TRI file.\"\nmsgstr \"Exporte des TRI Morphs dans un fichier TRI.\"\n\n#: res/xrc/OutfitStudio.xrc:2111\nmsgid \"Export to OBJs...\"\nmsgstr \"Exportez vers OBJs...\"\n\n#: res/xrc/OutfitStudio.xrc:2112\nmsgid \"Export all sliders to an OBJ file per slider.\"\nmsgstr \"Exportez tous les sliders dans un fichier OBJ par slider.\"\n\n#: res/xrc/OutfitStudio.xrc:2116\nmsgid \"Import Slider Data\"\nmsgstr \"Importez les données du slider\"\n\n#: res/xrc/OutfitStudio.xrc:2118\nmsgid \"Import NIF...\"\nmsgstr \"Importez NIF...\"\n\n#: res/xrc/OutfitStudio.xrc:2119\nmsgid \"Import a NIF file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\"Importez un fichier NIF et écrase les données du slider de la forme actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2122\nmsgid \"Import BSD...\"\nmsgstr \"Importez BSD...\"\n\n#: res/xrc/OutfitStudio.xrc:2123\nmsgid \"\"\n\"Import a BodySlide BSD file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\"Importez un fichier BSD BodySlide et écrase les données du slider de la \"\n\"forme actuelle.\"\n\n#: res/xrc/OutfitStudio.xrc:2126\nmsgid \"Import OBJ...\"\nmsgstr \"Importez OBJ...\"\n\n#: res/xrc/OutfitStudio.xrc:2127\nmsgid \"\"\n\"Import an OBJ file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"\"\n\"Importez un fichier OBJ correspondant au nombre de vertex de la forme \"\n\"actuelle et calculez les données du slider à partir de la différence.\"\n\n#: res/xrc/OutfitStudio.xrc:2130\nmsgid \"Import FBX...\"\nmsgstr \"Importez FBX...\"\n\n#: res/xrc/OutfitStudio.xrc:2131\nmsgid \"\"\n\"Import an FBX file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"\"\n\"Importez un fichier FBX correspondant au nombre de vertex de la forme \"\n\"actuelle et calculez les données du slider à partir de la différence.\"\n\n#: res/xrc/OutfitStudio.xrc:2136\nmsgid \"Export Slider Data\"\nmsgstr \"Exportez les données du slider\"\n\n#: res/xrc/OutfitStudio.xrc:2138\nmsgid \"Export NIF...\"\nmsgstr \"Exportez NIF...\"\n\n#: res/xrc/OutfitStudio.xrc:2139\nmsgid \"Exports the current slider's data as a NIF file.\"\nmsgstr \"Exporte les données du slider actuel sous forme de fichier NIF.\"\n\n#: res/xrc/OutfitStudio.xrc:2142\nmsgid \"Export BSD...\"\nmsgstr \"Exportez BSD...\"\n\n#: res/xrc/OutfitStudio.xrc:2143\nmsgid \"Exports the current slider's data as a BodySlide BSD file.\"\nmsgstr \"\"\n\"Exporte les données du slider actuel sous forme de fichier BSD BodySlide.\"\n\n#: res/xrc/OutfitStudio.xrc:2146\nmsgid \"Export OBJ...\"\nmsgstr \"Export OBJ...\"\n\n#: res/xrc/OutfitStudio.xrc:2147\nmsgid \"Exports the current slider's data as an OBJ file.\"\nmsgstr \"Exporte les données du slider actuel sous forme de fichier OBJ.\"\n\n#: res/xrc/OutfitStudio.xrc:2153\nmsgid \"Negate Slider\"\nmsgstr \"Annuler le slider\"\n\n#: res/xrc/OutfitStudio.xrc:2154\nmsgid \"Negates the current slider, reversing it's effect\"\nmsgstr \"Annule le slider actuel, inversant son effet\"\n\n#: res/xrc/OutfitStudio.xrc:2158\nmsgid \"Mask Affected Vertices\"\nmsgstr \"Masquer les vertices affectés\"\n\n#: res/xrc/OutfitStudio.xrc:2159\nmsgid \"Masks the vertices the slider is affecting for all selected shapes.\"\nmsgstr \"\"\n\"Masque les vertices que le slider affecte pour toutes les formes \"\n\"sélectionnées.\"\n\n#: res/xrc/OutfitStudio.xrc:2163\nmsgid \"Clear Slider Data\"\nmsgstr \"Effacer les données du slider\"\n\n#: res/xrc/OutfitStudio.xrc:2164\nmsgid \"\"\n\"Erases the slider data without removing the slider itself. (Cannot be undone)\"\nmsgstr \"\"\n\"Efface les données du slider sans supprimer le slider lui-même. (Ne peut pas \"\n\"être défait)\"\n\n#: res/xrc/OutfitStudio.xrc:2167\nmsgid \"Delete Slider\"\nmsgstr \"Effacer slider\"\n\n#: res/xrc/OutfitStudio.xrc:2168\nmsgid \"Delete the active slider from the project. (Cannot be undone)\"\nmsgstr \"Supprime le slider actif du projet. (Ne peut être annulé)\"\n\n#: res/xrc/OutfitStudio.xrc:2172\nmsgid \"Properties...\\tTab\"\nmsgstr \"Propriétés...\\tTab\"\n\n#: res/xrc/OutfitStudio.xrc:2173\nmsgid \"Display and edit the active slider's properties.\"\nmsgstr \"Affichez et modifiez les propriétés du slider actif.\"\n\n#: res/xrc/OutfitStudio.xrc:2178\nmsgid \"Tool\"\nmsgstr \"Outil\"\n\n#: res/xrc/OutfitStudio.xrc:2180\nmsgid \"Current Tool\"\nmsgstr \"Outil Actuel\"\n\n#: res/xrc/OutfitStudio.xrc:2219\nmsgid \"\"\n\"Apply animation weight values for the currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"Appliquez des valeurs de poids d'animation pour l'os actuellement \"\n\"sélectionné.\\n\"\n\"Maintenez la touche ALT enfoncée pour affaiblir la pondération.\"\n\n#: res/xrc/OutfitStudio.xrc:2252\nmsgid \"Transform\\tF\"\nmsgstr \"Transformez\\tF\"\n\n#: res/xrc/OutfitStudio.xrc:2257\nmsgid \"Pivot\\tP\"\nmsgstr \"Pivot\\tP\"\n\n#: res/xrc/OutfitStudio.xrc:2262\nmsgid \"Vertex Edit\\tQ\"\nmsgstr \"Modifiez Vertex\\tQ\"\n\n#: res/xrc/OutfitStudio.xrc:2263\nmsgid \"\"\n\"Shows vertex points and lets you mask/unmask them.\\n\"\n\"Without any brush active, click on a vertex to unmask it.\\n\"\n\"Hold down CTRL to mask it.\"\nmsgstr \"\"\n\"Affiche les points de vertex et vous permet de les masquer/démasquer.\\n\"\n\"Sans brosses actif, cliquez sur un vertex pour le démasquer.\\n\"\n\"Maintenez la touche CTRL enfoncée pour le masquer.\"\n\n#: res/xrc/OutfitStudio.xrc:2268\nmsgid \"Increase Brush Size\\tShift++\"\nmsgstr \"Augmentez la taille de la brosse\\tShift++\"\n\n#: res/xrc/OutfitStudio.xrc:2269\nmsgid \"Increase brush diameter\"\nmsgstr \"Augmentez le diamètre de la brosse\"\n\n#: res/xrc/OutfitStudio.xrc:2272\nmsgid \"Decrease Brush Size\\tShift+-\"\nmsgstr \"Diminuez la taille de la brosse\\tShift+-\"\n\n#: res/xrc/OutfitStudio.xrc:2273\nmsgid \"Decrease brush diameter\"\nmsgstr \"Diminuez le diamètre de la brosse\"\n\n#: res/xrc/OutfitStudio.xrc:2276\nmsgid \"Increase Brush Strength\\tCtrl++\"\nmsgstr \"Augmenter la force de la brosse\\tCtrl++\"\n\n#: res/xrc/OutfitStudio.xrc:2277\nmsgid \"Increase brush strength\"\nmsgstr \"Augmenter la force de la brosse\"\n\n#: res/xrc/OutfitStudio.xrc:2280\nmsgid \"Decrease Brush Strength\\tCtrl+-\"\nmsgstr \"Diminuez la force de la brosse\\tCtrl+-\"\n\n#: res/xrc/OutfitStudio.xrc:2281\nmsgid \"Decrease brush strength\"\nmsgstr \"Diminuez la force de la brosse\"\n\n#: res/xrc/OutfitStudio.xrc:2285\nmsgid \"Mask Less\\tA\"\nmsgstr \"Masque Moins\\tA\"\n\n#: res/xrc/OutfitStudio.xrc:2286\nmsgid \"Mask Less\"\nmsgstr \"Masque moins\"\n\n#: res/xrc/OutfitStudio.xrc:2289\nmsgid \"Mask More\\tD\"\nmsgstr \"Masque Plus\\tD\"\n\n#: res/xrc/OutfitStudio.xrc:2290\nmsgid \"Mask More\"\nmsgstr \"Masque plus\"\n\n#: res/xrc/OutfitStudio.xrc:2294\nmsgid \"Invert Mask\\tCtrl+I\"\nmsgstr \"Inversez le Masque\\tCtrl+I\"\n\n#: res/xrc/OutfitStudio.xrc:2295\nmsgid \"Invert Mask\"\nmsgstr \"Inversez le Masque\"\n\n#: res/xrc/OutfitStudio.xrc:2298\nmsgid \"Clear Mask\\tCtrl+A\"\nmsgstr \"Effacez le Masque\\tCtrl+A\"\n\n#: res/xrc/OutfitStudio.xrc:2299\nmsgid \"Clear Mask\"\nmsgstr \"Effacez le Masque\"\n\n#: res/xrc/OutfitStudio.xrc:2422 res/xrc/OutfitStudio.xrc:2455\n#: res/xrc/ShapeProperties.xrc:244 res/xrc/ShapeProperties.xrc:366\n#: res/xrc/ShapeProperties.xrc:535\nmsgid \"Add\"\nmsgstr \"Ajouter\"\n\n#: res/xrc/OutfitStudio.xrc:2424 res/xrc/OutfitStudio.xrc:2457\nmsgid \"From Skeleton...\"\nmsgstr \"Du Squelette...\"\n\n#: res/xrc/OutfitStudio.xrc:2425 res/xrc/OutfitStudio.xrc:2458\nmsgid \"Choose a bone from the reference skeleton to add to the project.\"\nmsgstr \"Choisissez un os dans le squelette de référence à ajouter au projet.\"\n\n#: res/xrc/OutfitStudio.xrc:2428 res/xrc/OutfitStudio.xrc:2461\nmsgid \"Custom Bone...\"\nmsgstr \"Os personnalisé...\"\n\n#: res/xrc/OutfitStudio.xrc:2429 res/xrc/OutfitStudio.xrc:2462\nmsgid \"Add a custom bone to the project.\"\nmsgstr \"Ajoutez un os personnalisé au projet.\"\n\n#: res/xrc/OutfitStudio.xrc:2435\nmsgid \"From Project\"\nmsgstr \"De Projet\"\n\n#: res/xrc/OutfitStudio.xrc:2436\nmsgid \"Delete bone(s) from all shapes of the project.\"\nmsgstr \"Supprimer le ou / les os de toutes les formes du projet.\"\n\n#: res/xrc/OutfitStudio.xrc:2439\nmsgid \"From Selected Shapes\"\nmsgstr \"À partir de Formes Sélectionnées\"\n\n#: res/xrc/OutfitStudio.xrc:2440\nmsgid \"Delete bone(s) from only the selected shapes.\"\nmsgstr \"Supprimer le ou / les os à partir des formes sélectionnées uniquement.\"\n\n#: res/xrc/OutfitStudio.xrc:2444\nmsgid \"Edit Bone...\"\nmsgstr \"Modifiez l'Os...\"\n\n#: res/xrc/OutfitStudio.xrc:2445\nmsgid \"Edit a custom bone or view a standard bone.\"\nmsgstr \"Modifiez un os personnalisé ou visualiser un os standard.\"\n\n#: res/xrc/OutfitStudio.xrc:2449\nmsgid \"Masks vertices with weights for the selected bones.\"\nmsgstr \"Masque les vertices avec des poids pour les os sélectionnés.\"\n\n#: res/xrc/OutfitStudio.xrc:2469 res/xrc/OutfitStudio.xrc:2495\nmsgid \"Add Segment...\"\nmsgstr \"Ajouter Segment...\"\n\n#: res/xrc/OutfitStudio.xrc:2470 res/xrc/OutfitStudio.xrc:2496\nmsgid \"Choose a segment to add to the shape.\"\nmsgstr \"Choisissez un segment à ajouter à la forme.\"\n\n#: res/xrc/OutfitStudio.xrc:2473 res/xrc/OutfitStudio.xrc:2484\nmsgid \"Add Sub Segment...\"\nmsgstr \"Ajouter un Sous-Segment...\"\n\n#: res/xrc/OutfitStudio.xrc:2474 res/xrc/OutfitStudio.xrc:2485\nmsgid \"Add a new sub segment to the currently selected segment.\"\nmsgstr \"Ajouter un nouveau sous-segment au segment actuellement sélectionné.\"\n\n#: res/xrc/OutfitStudio.xrc:2477\nmsgid \"Delete Segment...\"\nmsgstr \"Effacer Segment...\"\n\n#: res/xrc/OutfitStudio.xrc:2478\nmsgid \"Delete segment and all of its sub segments from the shape.\"\nmsgstr \"Effacer le segment et tous ses sous-segments de la forme.\"\n\n#: res/xrc/OutfitStudio.xrc:2482\nmsgid \"Sub Segments\"\nmsgstr \"Sous-Segments\"\n\n#: res/xrc/OutfitStudio.xrc:2488\nmsgid \"Delete Sub Segment...\"\nmsgstr \"Effacer Sous-Segment...\"\n\n#: res/xrc/OutfitStudio.xrc:2489\nmsgid \"Delete the selected sub segment.\"\nmsgstr \"Effacez la sous-segment sélectionnée.\"\n\n#: res/xrc/OutfitStudio.xrc:2502 res/xrc/OutfitStudio.xrc:2513\nmsgid \"Add Partition...\"\nmsgstr \"Ajouter une partition...\"\n\n#: res/xrc/OutfitStudio.xrc:2503 res/xrc/OutfitStudio.xrc:2514\nmsgid \"Adds a new partition to the shape.\"\nmsgstr \"Créez un nouveau partition de forme.\"\n\n#: res/xrc/OutfitStudio.xrc:2506\nmsgid \"Delete Partition...\"\nmsgstr \"Effacer une partition...\"\n\n#: res/xrc/OutfitStudio.xrc:2507\nmsgid \"Deletes the partition from the shape.\"\nmsgstr \"Effacer le partition de la forme.\"\n\n#: res/xrc/Project.xrc:16\nmsgid \"\"\n\"Welcome to the New Project wizard!\\n\"\n\"\\n\"\n\"First, please choose a reference. Typically, this is a body (such as CBBE) \"\n\"or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"Bienvenue dans l'assistant Nouveau Projet!\\n\"\n\"\\n\"\n\"Tout d'abord, veuillez choisir une référence. En règle générale, il s'agit \"\n\"d'un corps (tel que CBBE) ou d'un jeu de conversion (tel que Vanilla To \"\n\"CBBE) et est livré avec ses sliders.\"\n\n#: res/xrc/Project.xrc:32 res/xrc/Project.xrc:574\nmsgid \"Reference\"\nmsgstr \"Référence\"\n\n#: res/xrc/Project.xrc:50 res/xrc/Project.xrc:592\nmsgid \"From Template\"\nmsgstr \"Du Modèle\"\n\n#: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272\n#: res/xrc/Project.xrc:611 res/xrc/Project.xrc:785 res/xrc/Project.xrc:857\nmsgid \"From File\"\nmsgstr \"De Fichier\"\n\n#: res/xrc/Project.xrc:79 res/xrc/Project.xrc:621\nmsgid \"Select a project or NIF file\"\nmsgstr \"Sélectionnez un projet ou un fichier NIF\"\n\n#: res/xrc/Project.xrc:106 res/xrc/Project.xrc:648\nmsgid \"Slider Set:\"\nmsgstr \"Ensemble de Slider:\"\n\n#: res/xrc/Project.xrc:124 res/xrc/Project.xrc:666\nmsgid \"Shape:\"\nmsgstr \"Forme:\"\n\n#: res/xrc/Project.xrc:146 res/xrc/Project.xrc:688\nmsgid \"Clear Reference\"\nmsgstr \"Effacez la Référence\"\n\n#: res/xrc/Project.xrc:162\nmsgid \"Next, select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\"Ensuite, sélectionnez une tenue / un maillage sur lequel travailler et \"\n\"entrez un nom d'affichage pour celui-ci.\"\n\n#: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:752\nmsgid \"Display Name\"\nmsgstr \"Nom d'affichage\"\n\n#: res/xrc/Project.xrc:197 res/xrc/Project.xrc:772\nmsgid \"Outfit/Mesh\"\nmsgstr \"Tenue/Maillage\"\n\n#: res/xrc/Project.xrc:220 res/xrc/Project.xrc:795\nmsgid \"Select a file to load as an outfit/mesh\"\nmsgstr \"Sélectionnez un fichier à chargez comme tenue/maillage\"\n\n#: res/xrc/Project.xrc:232 res/xrc/Project.xrc:807\nmsgid \"Clear Outfit\"\nmsgstr \"Effacez la Tenue\"\n\n#: res/xrc/Project.xrc:250 res/xrc/Project.xrc:835\nmsgid \"Textures\"\nmsgstr \"Textures\"\n\n#: res/xrc/Project.xrc:257 res/xrc/Project.xrc:842\nmsgid \"Automatically search for textures\"\nmsgstr \"Recherchez automatique de textures\"\n\n#: res/xrc/Project.xrc:282 res/xrc/Project.xrc:867\nmsgid \"Select a texture file\"\nmsgstr \"Sélectionnez un fichier de la texture\"\n\n#: res/xrc/Project.xrc:297\nmsgid \"Save Project As...\"\nmsgstr \"Sauvegarder le Projet Sous...\"\n\n#: res/xrc/Project.xrc:328\nmsgid \"The name of the outfit and slider set, as it will appear in BodySlide.\"\nmsgstr \"\"\n\"Le nom de la tenue et slider ensemble, comme il apparaîtra dans BodySlide.\"\n\n#: res/xrc/Project.xrc:337\nmsgid \"Copies the current display name to the project text fields below.\"\nmsgstr \"\"\n\"Copie le nom d’affichage actuel aux champs de texte du projet ci-dessous.\"\n\n#: res/xrc/Project.xrc:338\nmsgid \"To Project\"\nmsgstr \"A la Projet\"\n\n#: res/xrc/Project.xrc:354\nmsgid \"Output File Name\"\nmsgstr \"Nom du fichier de sortie\"\n\n#: res/xrc/Project.xrc:363\nmsgid \"\"\n\"The name of the outfit file that will end up in the game data path when \"\n\"BodySlide builds it. Should not include _1 or _0 in the name, e.g: \"\n\"lovelydress\"\nmsgstr \"\"\n\"Le nom du fichier de tenue qui se retrouvera dans le chemin de données de \"\n\"jeu lorsque BodySlide le construit. Ne doit pas inclure _1 ou _0 dans le \"\n\"nom, par exemple: lovelydress\"\n\n#: res/xrc/Project.xrc:389\nmsgid \"Output Data Path\"\nmsgstr \"Chemin de données de sortie\"\n\n#: res/xrc/Project.xrc:398\nmsgid \"\"\n\"The location in the game's data path where BodySlide-built outfit files will \"\n\"be placed, e.g: meshes\\\\clothes\\\\lovelydress\"\nmsgstr \"\"\n\"L’emplacement dans le chemin de données du jeu où bodyslide construit \"\n\"fichiers de tenue seront placés, par exemple: mailles \\\\clothes\\\\lovelydress\"\n\n#: res/xrc/Project.xrc:410\nmsgid \"\"\n\"If this is enabled, BodySlide creates a low and high weight model when it \"\n\"generates the final outfit.\"\nmsgstr \"\"\n\"Si cela est activé, BodySlide crée un modèle de faible et de haut poids \"\n\"quand il génère la tenue finale.\"\n\n#: res/xrc/Project.xrc:411\nmsgid \"Low/High Weight Output\"\nmsgstr \"Poids Faible/Haut de Sortie\"\n\n#: res/xrc/Project.xrc:419\nmsgid \"\"\n\"If this is enabled, only one output file will be created (useful for single-\"\n\"weighted things like hair).\"\nmsgstr \"\"\n\"Si cela est activé, un seul fichier de sortie sera créé (utile pour les \"\n\"choses mono pondérées comme les cheveux).\"\n\n#: res/xrc/Project.xrc:420\nmsgid \"Single Weight Output\"\nmsgstr \"Sortie Poids Unique\"\n\n#: res/xrc/Project.xrc:431\nmsgid \"Project\"\nmsgstr \"Projet\"\n\n#: res/xrc/Project.xrc:443\nmsgid \"Slider Set File\"\nmsgstr \"Fichier Slider Set\"\n\n#: res/xrc/Project.xrc:453\nmsgid \"The .osp slider set project file\"\nmsgstr \"Le fichier de projet slider set .osp\"\n\n#: res/xrc/Project.xrc:454\nmsgid \"Select slider set .osp file name\"\nmsgstr \"Sélectionnez le nom du fichier slider set .osp\"\n\n#: res/xrc/Project.xrc:472\nmsgid \"Shape Data Folder\"\nmsgstr \"Dossier de données de forme\"\n\n#: res/xrc/Project.xrc:482\nmsgid \"\"\n\"The folder where all the slider data will go, as well as the base outfit NIF \"\n\"file.\"\nmsgstr \"\"\n\"Le dossier où toutes les données du slider ira, ainsi que la tenue de base \"\n\"fichier NIF.\"\n\n#: res/xrc/Project.xrc:483\nmsgid \"Select slider data folder\"\nmsgstr \"Sélectionnez le dossier de données du slider\"\n\n#: res/xrc/Project.xrc:500\nmsgid \"Shape Data File\"\nmsgstr \"Fichier de données de forme\"\n\n#: res/xrc/Project.xrc:510\nmsgid \"The name of the output's base NIF file.\"\nmsgstr \"Le nom du fichier NIF de base de la sortie.\"\n\n#: res/xrc/Project.xrc:511\nmsgid \"Select output NIF file name\"\nmsgstr \"Sélectionnez le nom du fichier NIF de sortie\"\n\n#: res/xrc/Project.xrc:523\nmsgid \"\"\n\"Outfits require the reference body to be a part of the output file. Disable \"\n\"this if you've already copied the reference over or you don't want it \"\n\"included.\"\nmsgstr \"\"\n\"Les tenues exigent que le corps de référence fait partie du fichier de \"\n\"sortie. Désactivez cela si vous avez déjà copié la référence ou si vous ne \"\n\"voulez pas qu’elle soit incluse.\"\n\n#: res/xrc/Project.xrc:524\nmsgid \"Copy reference shape into output\"\nmsgstr \"Copier la forme de référence en sortie\"\n\n#: res/xrc/Project.xrc:539 res/xrc/SavePreset.xrc:78\nmsgid \"&Save\"\nmsgstr \"&Sauvegarder\"\n\n#: res/xrc/Project.xrc:555\nmsgid \"Load Reference\"\nmsgstr \"Chargez un Référence\"\n\n#: res/xrc/Project.xrc:564\nmsgid \"\"\n\"Please choose a reference. Typically, this is a body (such as CBBE) or a \"\n\"conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"Choisir une référence. En règle générale, il s'agit d'un corps (tel que \"\n\"CBBE) ou d'un jeu de conversion (tel que Vanilla To CBBE) et est livré avec \"\n\"ses sliders.\"\n\n#: res/xrc/Project.xrc:697\nmsgid \"Merge new sliders with existing sliders\"\nmsgstr \"Fusionner les nouveaux sliders avec les sliders existants\"\n\n#: res/xrc/Project.xrc:728\nmsgid \"Load Outfit\"\nmsgstr \"Chargez la Tenue\"\n\n#: res/xrc/Project.xrc:737\nmsgid \"\"\n\"Please select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\"Sélectionnez une tenue / un maillage sur lequel travailler et entrez un nom \"\n\"d'affichage pour celui-ci.\"\n\n#: res/xrc/Project.xrc:816\nmsgid \"Keep other shapes\"\nmsgstr \"Gardez d'autres formes\"\n\n#: res/xrc/Project.xrc:942\nmsgid \"Group file (optional):\"\nmsgstr \"Fichier de groupe (facultatif):\"\n\n#: res/xrc/Project.xrc:951\nmsgid \"Group file to pack (optional).\"\nmsgstr \"Fichier de groupe à emballer (facultatif).\"\n\n#: res/xrc/Project.xrc:968\nmsgid \"Merged file name:\"\nmsgstr \"Nom de fichier fusionné:\"\n\n#: res/xrc/Project.xrc:976\nmsgid \"File name to use for the merged project file.\"\nmsgstr \"Nom de fichier à utiliser pour le fichier de projet fusionné.\"\n\n#: res/xrc/Project.xrc:1002\nmsgid \"Pack Folder...\"\nmsgstr \"Emballez le Dossier...\"\n\n#: res/xrc/Project.xrc:1011\nmsgid \"Pack Archive...\"\nmsgstr \"Emballez Archive...\"\n\n#: res/xrc/Project.xrc:1028 src/program/OutfitStudio.cpp:3429\n#: src/program/OutfitStudio.cpp:5967 src/program/OutfitStudio.cpp:6823\n#: src/program/OutfitStudio.cpp:6913 src/program/OutfitStudio.cpp:9666\n#: src/program/OutfitStudio.cpp:9693\nmsgid \"Cancel\"\nmsgstr \"Annuler\"\n\n#: res/xrc/SavePreset.xrc:6\nmsgid \"Enter preset name...\"\nmsgstr \"Entrez le nom du préréglage ...\"\n\n#: res/xrc/SavePreset.xrc:15\nmsgid \"Please enter a name for the new preset:\"\nmsgstr \"Veuillez saisir un nom pour le nouveau préréglage:\"\n\n#: res/xrc/SavePreset.xrc:38\nmsgid \"Select groups to assign to the new preset:\"\nmsgstr \"Sélectionnez les groupes à affecter au nouveau préréglage:\"\n\n#: res/xrc/Settings.xrc:15\nmsgid \"Game\"\nmsgstr \"Jeu\"\n\n#: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:3902\nmsgid \"Target Game\"\nmsgstr \"Jeu de cible\"\n\n#: res/xrc/Settings.xrc:37\nmsgid \"Choose the target game you want to use the program for here.\"\nmsgstr \"\"\n\"Choisissez ici le jeu cible pour lequel vous souhaitez utiliser le programme.\"\n\n#: res/xrc/Settings.xrc:66\nmsgid \"Game Data Path\"\nmsgstr \"Chemin des données du jeu\"\n\n#: res/xrc/Settings.xrc:76\nmsgid \"Select the data path of the game...\"\nmsgstr \"Sélectionnez le chemin des données du jeu ...\"\n\n#: res/xrc/Settings.xrc:78\nmsgid \"Data path to load textures from.\"\nmsgstr \"Chemin de données à partir duquel charger les textures.\"\n\n#: res/xrc/Settings.xrc:90\nmsgid \"Advanced\"\nmsgstr \"Avancée\"\n\n#: res/xrc/Settings.xrc:107\nmsgid \"Output Path\"\nmsgstr \"Chemin de sortie\"\n\n#: res/xrc/Settings.xrc:117\nmsgid \"Select the output path...\"\nmsgstr \"Sélectionnez le chemin de sortie...\"\n\n#: res/xrc/Settings.xrc:119\nmsgid \"\"\n\"Data path to build files to. If empty, Game Data Path will be used instead.\"\nmsgstr \"\"\n\"Chemin des données pour construire les fichiers. S'il est vide, le chemin de \"\n\"données du jeu sera utilisé à la place.\"\n\n#: res/xrc/Settings.xrc:136\nmsgid \"Project Path\"\nmsgstr \"Chemin du Projet\"\n\n#: res/xrc/Settings.xrc:146\nmsgid \"Select the project path...\"\nmsgstr \"Sélectionnez le chemin du projet...\"\n\n#: res/xrc/Settings.xrc:148\nmsgid \"\"\n\"Project path where files related to BodySlide are loaded from. If empty, \"\n\"executable directory will be used instead.\"\nmsgstr \"\"\n\"Chemin du projet à partir duquel les fichiers liés à BodySlide sont chargés. \"\n\"S'il est vide, le répertoire exécutable sera utilisé à la place.\"\n\n#: res/xrc/Settings.xrc:165\nmsgid \"General\"\nmsgstr \"Général\"\n\n#: res/xrc/Settings.xrc:177\nmsgid \"\"\n\"Enables/disables the dialog for choosing which set to build during a batch \"\n\"build if overrides happen.\"\nmsgstr \"\"\n\"Active/désactive la boîte de dialogue pour choisir le jeu à construire lors \"\n\"d'une génération par lots si des remplacements se produisent.\"\n\n#: res/xrc/Settings.xrc:178\nmsgid \"Override Warning\"\nmsgstr \"Avertissement de remplacement\"\n\n#: res/xrc/Settings.xrc:187\nmsgid \"\"\n\"Enables/disables scanning BSAs in the game data folder for textures to load.\"\nmsgstr \"\"\n\"Active/désactive l'analyse des BSA dans le dossier de données du jeu pour le \"\n\"chargement des textures.\"\n\n#: res/xrc/Settings.xrc:188\nmsgid \"BSA Textures\"\nmsgstr \"BSA Textures\"\n\n#: res/xrc/Settings.xrc:205\nmsgid \"\"\n\"Enables/disables panning the camera with the left mouse button in Outfit \"\n\"Studio.\"\nmsgstr \"\"\n\"Active/désactive le panoramique de la caméra avec le bouton gauche de la \"\n\"souris dans Outfit Studio.\"\n\n#: res/xrc/Settings.xrc:206\nmsgid \"Left Mouse Pan\"\nmsgstr \"Panoramique gauche de la souris\"\n\n#: res/xrc/Settings.xrc:224\nmsgid \"Language\"\nmsgstr \"Langue\"\n\n#: res/xrc/Settings.xrc:233\nmsgid \"Use the selected language for the program.\"\nmsgstr \"Utilisez la langue sélectionnée pour le programme.\"\n\n#: res/xrc/Settings.xrc:248\nmsgid \"Rendering\"\nmsgstr \"Rendu\"\n\n#: res/xrc/Settings.xrc:261\nmsgid \"Background Color\"\nmsgstr \"Couleur de Fond\"\n\n#: res/xrc/Settings.xrc:270\nmsgid \"Background color of the renderer.\"\nmsgstr \"Couleur de fond du moteur de rendu.\"\n\n#: res/xrc/Settings.xrc:288\nmsgid \"Wireframe Color\"\nmsgstr \"Couleur de l'Image Filaire\"\n\n#: res/xrc/Settings.xrc:297\nmsgid \"Wireframe color of the renderer.\"\nmsgstr \"Couleur de l'image filaire du moteur de rendu.\"\n\n#: res/xrc/Settings.xrc:312\nmsgid \"Data Files\"\nmsgstr \"Fichier de données\"\n\n#: res/xrc/Settings.xrc:330\nmsgid \"Reference Skeleton\"\nmsgstr \"Squelette de référence\"\n\n#: res/xrc/Settings.xrc:353\nmsgid \"Select a reference skeleton .nif file...\"\nmsgstr \"Sélectionnez un fichier .nif de squelette de référence...\"\n\n#: res/xrc/Settings.xrc:356\nmsgid \"The reference skeleton file for Outfit Studio.\"\nmsgstr \"Le fichier squelette de référence pour Outfit Studio.\"\n\n#: res/xrc/Settings.xrc:373\nmsgid \"Root Node\"\nmsgstr \"Nœud racine\"\n\n#: res/xrc/Settings.xrc:382\nmsgid \"\"\n\"The root node name of the reference skeleton. Can differ from game to game.\"\nmsgstr \"\"\n\"Le nom du nœud racine du squelette de référence. Peut différer d'un jeu à \"\n\"l'autre.\"\n\n#: res/xrc/Setup.xrc:5\nmsgid \"Setup\"\nmsgstr \"Configuration\"\n\n#: res/xrc/Setup.xrc:15\nmsgid \"\"\n\"Please select the data folder and your target game.\\n\"\n\"You can only choose one game at a time, but it is possible to change the \"\n\"selection in the settings.\"\nmsgstr \"\"\n\"Veuillez sélectionner le dossier de données et votre jeu cible.\\n\"\n\"Vous ne pouvez choisir qu'un seul jeu à la fois, mais il est possible de \"\n\"modifier la sélection dans les paramètres.\"\n\n#: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102\n#: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189\n#: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247\nmsgid \"Game not found! Select the data folder manually...\"\nmsgstr \"Jeu non trouvé! Sélectionnez manuellement le dossier de données...\"\n\n#: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103\n#: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190\n#: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248\nmsgid \"Select a folder\"\nmsgstr \"Sélectionnez une dossier\"\n\n#: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113\n#: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200\n#: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258\nmsgid \"Choose Game\"\nmsgstr \"Choisissez le Jeu\"\n\n#: res/xrc/ShapeProperties.xrc:5\nmsgid \"Shape Properties\"\nmsgstr \"Propriétés de la forme\"\n\n#: res/xrc/ShapeProperties.xrc:16\nmsgid \"Shader\"\nmsgstr \"Ombrage\"\n\n#: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:553\n#: res/xrc/Skeleton.xrc:68\nmsgid \"Name\"\nmsgstr \"Nom\"\n\n#: res/xrc/ShapeProperties.xrc:102\nmsgid \"Specular Color\"\nmsgstr \"Couleur Spéculaire\"\n\n#: res/xrc/ShapeProperties.xrc:120\nmsgid \"Specular Strength\"\nmsgstr \"Force Spéculaire\"\n\n#: res/xrc/ShapeProperties.xrc:139\nmsgid \"Specular Power\"\nmsgstr \"Puissance Spéculaire\"\n\n#: res/xrc/ShapeProperties.xrc:179\nmsgid \"Emissive Color\"\nmsgstr \"Couleur Émissive\"\n\n#: res/xrc/ShapeProperties.xrc:197\nmsgid \"Emissive Multiple\"\nmsgstr \"Multiples Émissive\"\n\n#: res/xrc/ShapeProperties.xrc:216\nmsgid \"Vertex Colors\"\nmsgstr \"Couleurs des Vertex\"\n\n#: res/xrc/ShapeProperties.xrc:253 res/xrc/ShapeProperties.xrc:375\nmsgid \"Remove\"\nmsgstr \"Supprimer\"\n\n#: res/xrc/ShapeProperties.xrc:262\nmsgid \"Textures...\"\nmsgstr \"Textures...\"\n\n#: res/xrc/ShapeProperties.xrc:274\nmsgid \"Transparency\"\nmsgstr \"Transparence\"\n\n#: res/xrc/ShapeProperties.xrc:297\nmsgid \"Threshold\"\nmsgstr \"Seuil\"\n\n#: res/xrc/ShapeProperties.xrc:337\nmsgid \"Vertex Alpha\"\nmsgstr \"Alpha des Vertex\"\n\n#: res/xrc/ShapeProperties.xrc:388\nmsgid \"Copy from shape...\"\nmsgstr \"Copie de la forme...\"\n\n#: res/xrc/ShapeProperties.xrc:396\nmsgid \"Geometry\"\nmsgstr \"Géométrie\"\n\n#: res/xrc/ShapeProperties.xrc:416\nmsgid \"Full Precision\"\nmsgstr \"Précision Totale\"\n\n#: res/xrc/ShapeProperties.xrc:434\nmsgid \"Sub Index\"\nmsgstr \"Sous-index\"\n\n#: res/xrc/ShapeProperties.xrc:452\nmsgid \"Skinned\"\nmsgstr \"Écorché\"\n\n#: res/xrc/ShapeProperties.xrc:469\nmsgid \"Dynamic\"\nmsgstr \"Dynamique\"\n\n#: res/xrc/ShapeProperties.xrc:514\nmsgid \"Extra Data\"\nmsgstr \"Données Supplémentaires\"\n\n#: res/xrc/ShapeProperties.xrc:562\nmsgid \"Value\"\nmsgstr \"Valeur\"\n\n#: res/xrc/ShapeProperties.xrc:572\nmsgid \"Coordinates\"\nmsgstr \"Coordonnées\"\n\n#: res/xrc/ShapeProperties.xrc:581\nmsgid \"Transform from global to skin coordinates:\"\nmsgstr \"Transformez les coordonnées globales en coordonnées de la peau:\"\n\n#: res/xrc/ShapeProperties.xrc:644 res/xrc/Skeleton.xrc:142\nmsgid \"Rotation\"\nmsgstr \"Rotation\"\n\n#: res/xrc/Skeleton.xrc:6\nmsgid \"Select a bone to add\"\nmsgstr \"Sélectionnez un os à ajouter\"\n\n#: res/xrc/Skeleton.xrc:15\nmsgid \"Bones in the current reference skeleton:\"\nmsgstr \"Os dans le squelette de référence actuel :\"\n\n#: res/xrc/Skeleton.xrc:53\nmsgid \"Add Custom Bone\"\nmsgstr \"Ajouter l’os personnalisé\"\n\n#: res/xrc/Skeleton.xrc:93\nmsgid \"Parent\"\nmsgstr \"Parent\"\n\n#: res/xrc/Slider.xrc:6\nmsgid \"Select a slider preset\"\nmsgstr \"Sélectionnez un préréglage du slider\"\n\n#: res/xrc/Slider.xrc:15\nmsgid \"Choose a preset:\"\nmsgstr \"Choisissez un préréglage:\"\n\n#: res/xrc/Slider.xrc:40\nmsgid \"Low weight\"\nmsgstr \"Poids Faible\"\n\n#: res/xrc/Slider.xrc:49\nmsgid \"High weight\"\nmsgstr \"Poids Haut\"\n\n#: res/xrc/Slider.xrc:81\nmsgid \"Slider Properties\"\nmsgstr \"Propriétés slider\"\n\n#: res/xrc/Slider.xrc:91\nmsgid \"Slider Name\"\nmsgstr \"Nom du Slider\"\n\n#: res/xrc/Slider.xrc:108\nmsgid \"Default Values\"\nmsgstr \"Valeurs par Défaut\"\n\n#: res/xrc/Slider.xrc:114\nmsgid \"Low\"\nmsgstr \"Faible\"\n\n#: res/xrc/Slider.xrc:131\nmsgid \"High\"\nmsgstr \"Élevé\"\n\n#: res/xrc/Slider.xrc:148\nmsgid \"Zapped\"\nmsgstr \"Zappé\"\n\n#: res/xrc/Slider.xrc:173\nmsgid \"Invert\"\nmsgstr \"Inverser\"\n\n#: res/xrc/Slider.xrc:182\nmsgid \"Hidden\"\nmsgstr \"Caché\"\n\n#: res/xrc/Slider.xrc:191\nmsgid \"Zap\"\nmsgstr \"Zap\"\n\n#: res/xrc/Slider.xrc:211\nmsgid \"Toggle Zaps:\"\nmsgstr \"Basculez Zaps:\"\n\n#: src/components/Anim.cpp:509\nmsgid \"\"\n\"Bone information incomplete. Exported data will not contain correct bone \"\n\"entries! Be sure to load a reference NIF prior to export.\"\nmsgstr \"\"\n\"Information osseuse incomplète. Les données exportées ne contiendront pas \"\n\"les entrées d'os correctes! Assurez-vous de charger un NIF de référence \"\n\"avant l'exportation.\"\n\n#: src/components/Anim.cpp:509\nmsgid \"Export Warning\"\nmsgstr \"Avertissement de Exporter\"\n\n#: src/components/Anim.cpp:575\n#, c-format\nmsgid \"Failed to load skeleton '%s'!\"\nmsgstr \"Échec du chargement du squelette '%s'!\"\n\n#: src/components/Anim.cpp:583\n#, c-format\nmsgid \"Root '%s' not found in skeleton '%s'!\"\nmsgstr \"Racine '%s' non trouvée dans le squelette '%s'!\"\n\n#: src/program/BodySlideApp.cpp:181 src/program/OutfitStudio.cpp:394\nmsgid \"\"\n\"No read/write permission for game data path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the game data \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"Aucune permission de lecture/écriture pour le chemin des données du jeu!\\n\"\n\"\\n\"\n\"Veuillez lancer le programme avec l'autorisation de l'administrateur et \"\n\"vérifiez que le chemin des données du jeu dans les paramètres est correct.\"\n\n#: src/program/BodySlideApp.cpp:181 src/program/BodySlideApp.cpp:188\n#: src/program/BodySlideApp.cpp:1246 src/program/BodySlideApp.cpp:1253\n#: src/program/OutfitStudio.cpp:394 src/program/OutfitStudio.cpp:401\n#: src/program/OutfitStudio.cpp:627 src/program/OutfitStudio.cpp:634\nmsgid \"Warning\"\nmsgstr \"Avertissement\"\n\n#: src/program/BodySlideApp.cpp:188 src/program/OutfitStudio.cpp:401\nmsgid \"\"\n\"No read/write permission for project path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the project \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"Aucune permission de lecture/écriture pour le chemin du projet!\\n\"\n\"\\n\"\n\"Veuillez lancer le programme avec l'autorisation de l'administrateur et \"\n\"vérifiez que le chemin du projet dans les paramètres est correct.\"\n\n#: src/program/BodySlideApp.cpp:259 src/program/OutfitStudio.cpp:489\n#, c-format\nmsgid \"Unexpected exception has occurred: %s, the program will terminate.\"\nmsgstr \"Une exception inattendue s'est produite: %s, le programme s'arrête.\"\n\n#: src/program/BodySlideApp.cpp:259 src/program/OutfitStudio.cpp:489\nmsgid \"Unexpected exception\"\nmsgstr \"Exception inattendue\"\n\n#: src/program/BodySlideApp.cpp:282 src/program/OutfitStudio.cpp:509\n#, c-format\nmsgid \"Unhandled exception has occurred: %s, the program will terminate.\"\nmsgstr \"Une exception non gérée s'est produite: %s, le programme s'arrête.\"\n\n#: src/program/BodySlideApp.cpp:282 src/program/OutfitStudio.cpp:509\nmsgid \"Unhandled exception\"\nmsgstr \"Exception non gérée\"\n\n#: src/program/BodySlideApp.cpp:293 src/program/OutfitStudio.cpp:517\nmsgid \"Fatal exception has occurred, the program will terminate.\"\nmsgstr \"Une exception fatale s'est produite, le programme se terminera.\"\n\n#: src/program/BodySlideApp.cpp:293 src/program/OutfitStudio.cpp:517\nmsgid \"Fatal exception\"\nmsgstr \"Exception fatale\"\n\n#: src/program/BodySlideApp.cpp:743\nmsgid \"Failed to launch Outfit Studio executable!\"\nmsgstr \"Impossible de lancer l'exécutable d'Outfit Studio !\"\n\n#: src/program/BodySlideApp.cpp:743 src/program/BodySlideApp.cpp:1274\n#: src/program/BodySlideApp.cpp:1566 src/program/BodySlideApp.cpp:2562\n#: src/program/BodySlideApp.cpp:2569 src/program/BodySlideApp.cpp:3252\n#: src/program/OutfitStudio.cpp:918 src/program/OutfitStudio.cpp:924\n#: src/program/OutfitStudio.cpp:1361 src/program/OutfitStudio.cpp:1372\n#: src/program/OutfitStudio.cpp:1409 src/program/OutfitStudio.cpp:1420\n#: src/program/OutfitStudio.cpp:1430 src/program/OutfitStudio.cpp:1439\n#: src/program/OutfitStudio.cpp:1450 src/program/OutfitStudio.cpp:1461\n#: src/program/OutfitStudio.cpp:1473 src/program/OutfitStudio.cpp:1512\n#: src/program/OutfitStudio.cpp:1520 src/program/OutfitStudio.cpp:1527\n#: src/program/OutfitStudio.cpp:1564 src/program/OutfitStudio.cpp:1572\n#: src/program/OutfitStudio.cpp:1579 src/program/OutfitStudio.cpp:1589\n#: src/program/OutfitStudio.cpp:1598 src/program/OutfitStudio.cpp:1606\n#: src/program/OutfitStudio.cpp:1613 src/program/OutfitStudio.cpp:1624\n#: src/program/OutfitStudio.cpp:1633 src/program/OutfitStudio.cpp:1640\n#: src/program/OutfitStudio.cpp:1888 src/program/OutfitStudio.cpp:1911\n#: src/program/OutfitStudio.cpp:1925 src/program/OutfitStudio.cpp:2009\n#: src/program/OutfitStudio.cpp:2018 src/program/OutfitStudio.cpp:2026\n#: src/program/OutfitStudio.cpp:2040 src/program/OutfitStudio.cpp:2049\n#: src/program/OutfitStudio.cpp:2055 src/program/OutfitStudio.cpp:2083\n#: src/program/OutfitStudio.cpp:3953 src/program/OutfitStudio.cpp:3973\n#: src/program/OutfitStudio.cpp:4037 src/program/OutfitStudio.cpp:4070\n#: src/program/OutfitStudio.cpp:4084 src/program/OutfitStudio.cpp:4152\n#: src/program/OutfitStudio.cpp:4185 src/program/OutfitStudio.cpp:4199\n#: src/program/OutfitStudio.cpp:4224 src/program/OutfitStudio.cpp:4275\n#: src/program/OutfitStudio.cpp:4280 src/program/OutfitStudio.cpp:4294\n#: src/program/OutfitStudio.cpp:4301 src/program/OutfitStudio.cpp:4306\n#: src/program/OutfitStudio.cpp:4317 src/program/OutfitStudio.cpp:6681\n#: src/program/OutfitStudio.cpp:6737 src/program/OutfitStudio.cpp:6743\n#: src/program/OutfitStudio.cpp:6747 src/program/OutfitStudio.cpp:6758\n#: src/program/OutfitStudio.cpp:6768 src/program/OutfitStudio.cpp:6772\n#: src/program/OutfitStudio.cpp:6789 src/program/OutfitStudio.cpp:6793\n#: src/program/OutfitStudio.cpp:6804 src/program/OutfitStudio.cpp:6814\n#: src/program/OutfitStudio.cpp:6832 src/program/OutfitStudio.cpp:6904\n#: src/program/OutfitStudio.cpp:6922 src/program/OutfitStudio.cpp:6996\n#: src/program/OutfitStudio.cpp:7000 src/program/OutfitStudio.cpp:7011\n#: src/program/OutfitStudio.cpp:7021 src/program/OutfitStudio.cpp:7025\n#: src/program/OutfitStudio.cpp:7048 src/program/OutfitStudio.cpp:7057\n#: src/program/OutfitStudio.cpp:7061 src/program/OutfitStudio.cpp:7090\n#: src/program/OutfitStudio.cpp:7094 src/program/OutfitStudio.cpp:7117\n#: src/program/OutfitStudio.cpp:7126 src/program/OutfitStudio.cpp:7137\n#: src/program/OutfitStudio.cpp:7144 src/program/OutfitStudio.cpp:7155\n#: src/program/OutfitStudio.cpp:7162 src/program/OutfitStudio.cpp:7186\n#: src/program/OutfitStudio.cpp:7236 src/program/OutfitStudio.cpp:7296\n#: src/program/OutfitStudio.cpp:7300 src/program/OutfitStudio.cpp:7313\n#: src/program/OutfitStudio.cpp:7317 src/program/OutfitStudio.cpp:7379\n#: src/program/OutfitStudio.cpp:7688 src/program/OutfitStudio.cpp:7705\n#: src/program/OutfitStudio.cpp:7723 src/program/OutfitStudio.cpp:7747\n#: src/program/OutfitStudio.cpp:7782 src/program/OutfitStudio.cpp:7928\n#: src/program/OutfitStudio.cpp:8112 src/program/OutfitStudio.cpp:8259\n#: src/program/OutfitStudio.cpp:8313 src/program/OutfitStudio.cpp:8529\n#: src/program/OutfitStudio.cpp:8669 src/program/OutfitStudio.cpp:8677\n#: src/program/OutfitStudio.cpp:8972 src/program/OutfitStudio.cpp:8977\n#: src/program/OutfitStudio.cpp:9046 src/program/OutfitStudio.cpp:9051\n#: src/program/OutfitStudio.cpp:9137 src/program/OutfitStudio.cpp:9143\n#: src/program/OutfitStudio.cpp:9148 src/program/OutfitStudio.cpp:9155\n#: src/program/OutfitStudio.cpp:9184 src/program/OutfitStudio.cpp:9214\n#: src/program/OutfitStudio.cpp:9266 src/program/OutfitStudio.cpp:9440\n#: src/program/OutfitStudio.cpp:10646 src/program/OutfitStudio.cpp:10700\n#: src/program/OutfitStudio.cpp:10734 src/program/OutfitStudio.cpp:10739\n#: src/program/OutfitStudio.cpp:10761 src/program/OutfitStudio.cpp:11891\nmsgid \"Error\"\nmsgstr \"Erreur\"\n\n#: src/program/BodySlideApp.cpp:1246 src/program/OutfitStudio.cpp:627\nmsgid \"\"\n\"Failed to find game install path registry value or GameDataPath in the \"\n\"config.\"\nmsgstr \"\"\n\"Impossible de trouver la valeur de registre du chemin d'installation du jeu \"\n\"ou GameDataPath dans la configuration.\"\n\n#: src/program/BodySlideApp.cpp:1253 src/program/OutfitStudio.cpp:634\nmsgid \"\"\n\"Failed to find game install path registry key or GameDataPath in the config.\"\nmsgstr \"\"\n\"Impossible de trouver la clé de registre du chemin d'installation du jeu ou \"\n\"GameDataPath dans la configuration.\"\n\n#: src/program/BodySlideApp.cpp:1479 src/program/OutfitStudio.cpp:860\n#, c-format\nmsgid \"System language '%d' is wrong.\"\nmsgstr \"La langue du système '%d' est incorrecte.\"\n\n#: src/program/BodySlideApp.cpp:1488 src/program/OutfitStudio.cpp:869\n#, c-format\nmsgid \"\"\n\"The system language '%d' is not supported by your system. Try installing \"\n\"support for this language.\"\nmsgstr \"\"\n\"La langue système '%d' n'est pas prise en charge par votre système. Essayez \"\n\"d'installer le support pour cette langue.\"\n\n#: src/program/BodySlideApp.cpp:1566\nmsgid \"Failed to create group file.\"\nmsgstr \"Échec de la création du fichier de groupe.\"\n\n#: src/program/BodySlideApp.cpp:1580\nmsgid \"\"\n\"That group already exists in the specified file, do you wish to overwrite \"\n\"the group?\"\nmsgstr \"\"\n\"Ce groupe existe déjà dans le fichier spécifié, souhaitez-vous écraser le \"\n\"groupe?\"\n\n#: src/program/BodySlideApp.cpp:1580\nmsgid \"Group already exists\"\nmsgstr \"Le groupe existe déjà\"\n\n#: src/program/BodySlideApp.cpp:1714\nmsgid \"\"\n\"WARNING: Game data path not configured. Would you like to show BodySlide \"\n\"where it is?\"\nmsgstr \"\"\n\"AVERTISSEMENT: Le chemin des données du jeu n'est pas configuré. Voulez-vous \"\n\"montrer BodySlide où il se trouve?\"\n\n#: src/program/BodySlideApp.cpp:1714 src/program/BodySlideApp.cpp:2001\n#: src/program/BodySlideApp.cpp:2005\nmsgid \"Game not found\"\nmsgstr \"Jeu non trouvé\"\n\n#: src/program/BodySlideApp.cpp:1721\nmsgid \"Please choose a directory to set as your Data path\"\nmsgstr \"Veuillez choisir un répertoire à définir comme chemin de données\"\n\n#: src/program/BodySlideApp.cpp:1739\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folder, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"AVERTISSEMENT: Cela supprimera les fichiers de sortie du dossier de sortie, \"\n\"ce qui pourrait provoquer des pannes.\\n\"\n\"\\n\"\n\"Voulez-vous continuer?\"\n\n#: src/program/BodySlideApp.cpp:1739\nmsgid \"Clean Build\"\nmsgstr \"Construire Proprement\"\n\n#: src/program/BodySlideApp.cpp:1746\nmsgid \"Removed the following files:\\n\"\nmsgstr \"Suppression des fichiers suivants:\\n\"\n\n#: src/program/BodySlideApp.cpp:1758 src/program/BodySlideApp.cpp:1771\nmsgid \" (no action)\\n\"\nmsgstr \" (aucune action)\\n\"\n\n#: src/program/BodySlideApp.cpp:1762 src/program/BodySlideApp.cpp:1774\n#: src/program/BodySlideApp.cpp:1977\nmsgid \"Process Successful\"\nmsgstr \"Succès du Processus\"\n\n#: src/program/BodySlideApp.cpp:1864\n#, c-format\nmsgid \"\"\n\"Failed to write TRI file to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Échec de l'écriture du fichier TRI à l'emplacement suivant\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/BodySlideApp.cpp:1864 src/program/BodySlideApp.cpp:1920\n#: src/program/BodySlideApp.cpp:1955\nmsgid \"Unable to process\"\nmsgstr \"Impossible à traiter\"\n\n#: src/program/BodySlideApp.cpp:1920 src/program/BodySlideApp.cpp:1955\n#, c-format\nmsgid \"\"\n\"Failed to build set to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Échec de la création de l'ensemble à l'emplacement suivant\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/BodySlideApp.cpp:1922 src/program/BodySlideApp.cpp:1957\nmsgid \"Choose alternate file name\"\nmsgstr \"Choisissez un autre nom de fichier\"\n\n#: src/program/BodySlideApp.cpp:1969\nmsgid \"Successfully processed the following files:\\n\"\nmsgstr \"Traitement réussi des fichiers suivants:\\n\"\n\n#: src/program/BodySlideApp.cpp:1988\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folders, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"AVERTISSEMENT: Cela supprimera les fichiers de sortie des dossier de sortie, \"\n\"ce qui pourrait provoquer des pannes.\\n\"\n\"\\n\"\n\"Voulez-vous continuer?\"\n\n#: src/program/BodySlideApp.cpp:1988\nmsgid \"Clean Batch Build\"\nmsgstr \"Proprement Construction par lots\"\n\n#: src/program/BodySlideApp.cpp:2001\nmsgid \"\"\n\"WARNING: Game data path not configured. Files can't be removed that way.\"\nmsgstr \"\"\n\"AVERTISSEMENT: le chemin des données du jeu n'est pas configuré. Les \"\n\"fichiers ne peuvent pas être supprimés de cette façon.\"\n\n#: src/program/BodySlideApp.cpp:2005\nmsgid \"\"\n\"WARNING: Game data path not configured. Continue saving files to the working \"\n\"directory?\"\nmsgstr \"\"\n\"AVERTISSEMENT: le chemin des données du jeu n'est pas configuré. Continuer à \"\n\"enregistrer les fichiers dans le répertoire de travail?\"\n\n#: src/program/BodySlideApp.cpp:2114\nmsgid \"Processing Outfits\"\nmsgstr \"Tenues de traitement\"\n\n#: src/program/BodySlideApp.cpp:2114 src/program/OutfitStudio.h:1089\nmsgid \"Starting...\"\nmsgstr \"Commencer...\"\n\n#: src/program/BodySlideApp.cpp:2131\n#, c-format\nmsgid \"Processing '%s' (%d of %d)...\"\nmsgstr \"Traitement'%s' (%d of %d)...\"\n\n#: src/program/BodySlideApp.cpp:2139\nmsgid \"No recorded outfit name source\"\nmsgstr \"Aucune source de nom de tenue enregistrée\"\n\n#: src/program/BodySlideApp.cpp:2150\nmsgid \"Unable to get slider set from file: \"\nmsgstr \"Impossible d'obtenir le slider set du fichier: \"\n\n#: src/program/BodySlideApp.cpp:2155\nmsgid \"Unable to open slider set file: \"\nmsgstr \"Impossible d'ouvrir le fichier de slider set: \"\n\n#: src/program/BodySlideApp.cpp:2190\nmsgid \"Unable to load input nif: \"\nmsgstr \"Impossible de charger l'entrée nif: \"\n\n#: src/program/BodySlideApp.cpp:2337\nmsgid \"Unable to create destination directory: \"\nmsgstr \"Impossible de créer le répertoire de destination: \"\n\n#: src/program/BodySlideApp.cpp:2401 src/program/BodySlideApp.cpp:2409\n#: src/program/BodySlideApp.cpp:2420\nmsgid \"Unable to save nif file: \"\nmsgstr \"Impossible d'enregistrer le fichier nif: \"\n\n#: src/program/BodySlideApp.cpp:2490 src/program/BodySlideApp.cpp:3427\nmsgid \"The following sets failed\"\nmsgstr \"Les ensembles suivants ont échoué\"\n\n#: src/program/BodySlideApp.cpp:2490 src/program/BodySlideApp.cpp:3427\nmsgid \"Failed\"\nmsgstr \"Échec\"\n\n#: src/program/BodySlideApp.cpp:2562\nmsgid \"Failed to load BodySlide.xrc file!\"\nmsgstr \"Échec du chargement du fichier Bodyslide.xrc!\"\n\n#: src/program/BodySlideApp.cpp:2569\nmsgid \"Failed to load BodySlide frame!\"\nmsgstr \"Échec du chargement du cadre BodySlide!\"\n\n#: src/program/BodySlideApp.cpp:2589\nmsgid \"Group Filter\"\nmsgstr \"Filtre de Groupe\"\n\n#: src/program/BodySlideApp.cpp:2590\nmsgid \"Filter by group\"\nmsgstr \"Filtrer par groupe\"\n\n#: src/program/BodySlideApp.cpp:2596\nmsgid \"Outfit Filter\"\nmsgstr \"Filtre de Tenue\"\n\n#: src/program/BodySlideApp.cpp:2597\nmsgid \"Filter by outfit\"\nmsgstr \"Filtre par tenue\"\n\n#: src/program/BodySlideApp.cpp:3161\nmsgid \"Choose groups to filter outfit list\"\nmsgstr \"Choisissez des groupes pour filtrer la liste des tenues\"\n\n#: src/program/BodySlideApp.cpp:3161\nmsgid \"Choose Groups\"\nmsgstr \"Choisissez des Groupes\"\n\n#: src/program/BodySlideApp.cpp:3178\nmsgid \"Choose or create group file\"\nmsgstr \"Choisissez ou créez un fichier de groupe\"\n\n#: src/program/BodySlideApp.cpp:3187\nmsgid \"What would you like the new group to be called?\"\nmsgstr \"Comment aimeriez-vous que le nouveau groupe soit appelé?\"\n\n#: src/program/BodySlideApp.cpp:3187\nmsgid \"New Group Name\"\nmsgstr \"Nouveau Nom de Groupes\"\n\n#: src/program/BodySlideApp.cpp:3224\nmsgid \"Do you really wish to delete the selected project?\"\nmsgstr \"Voulez-vous vraiment supprimer le projet sélectionné ?\"\n\n#: src/program/BodySlideApp.cpp:3224\nmsgid \"Delete Project\"\nmsgstr \"Supprimer le Projet\"\n\n#: src/program/BodySlideApp.cpp:3233\nmsgid \"Do you really wish to delete the selected preset?\"\nmsgstr \"Voulez-vous vraiment supprimer le préréglage sélectionné?\"\n\n#: src/program/BodySlideApp.cpp:3233\nmsgid \"Delete Preset\"\nmsgstr \"Supprimer le préréglage\"\n\n#: src/program/BodySlideApp.cpp:3252 src/program/OutfitStudio.cpp:6737\n#, c-format\nmsgid \"Failed to save preset (%d)!\"\nmsgstr \"Échec de l'enregistrement du préréglage (%d)!\"\n\n#: src/program/BodySlideApp.cpp:3279\n#, c-format\nmsgid \"Failed to save preset as '%s' (%d)!\"\nmsgstr \"Échec de l'enregistrement du préréglage sous '%s' (%d)!\"\n\n#: src/program/BodySlideApp.cpp:3402\nmsgid \"Choose a folder to contain the saved files\"\nmsgstr \"Choisissez un dossier pour contenir les fichiers enregistrés\"\n\n#: src/program/BodySlideApp.cpp:3417\nmsgid \"All sets processed successfully!\"\nmsgstr \"Tous les jeux ont été traités avec succès!\"\n\n#: src/program/BodySlideApp.cpp:3417\nmsgid \"Complete\"\nmsgstr \"Finir\"\n\n#: src/program/EditUV.cpp:329 src/program/OutfitStudio.cpp:9768\nmsgid \"Outfit Studio: OpenGL context is not OK.\"\nmsgstr \"Outfit Studio: OpenGL le contexte n'est pas OK.\"\n\n#: src/program/EditUV.cpp:329 src/program/OutfitStudio.cpp:9768\n#: src/program/PreviewWindow.cpp:66 src/render/GLSurface.cpp:1880\n#: src/render/GLSurface.cpp:1897\nmsgid \"OpenGL Error\"\nmsgstr \"OpenGL Erreur\"\n\n#: src/program/GroupManager.cpp:139\nmsgid \"Please enter a new unique name for the group.\"\nmsgstr \"Veuillez saisir un nouveau nom unique pour la groupe.\"\n\n#: src/program/GroupManager.cpp:139\nmsgid \"Rename Group\"\nmsgstr \"Renommez la Groupe\"\n\n#: src/program/GroupManager.cpp:321\nmsgid \"Save changes to group file?\"\nmsgstr \"Sauvegarder les modifications dans le fichier de groupe?\"\n\n#: src/program/GroupManager.cpp:321\nmsgid \"Save Changes\"\nmsgstr \"Sauvegarder les modifications\"\n\n#: src/program/NormalsGenDialog.cpp:97\nmsgid \"Enter a name for the new layer.\"\nmsgstr \"Entrez un nom pour la nouvelle couche.\"\n\n#: src/program/NormalsGenDialog.cpp:97\nmsgid \"Name new layer\"\nmsgstr \"Nommez la nouvelle couche\"\n\n#: src/program/NormalsGenDialog.cpp:220\nmsgid \"Choose a normals generator preset file...\"\nmsgstr \"Choisissez un fichier de préréglage du générateur de normales...\"\n\n#: src/program/NormalsGenDialog.cpp:238\nmsgid \"Save normals generator preset to...\"\nmsgstr \"Enregistrer le préréglage du générateur de normales dans...\"\n\n#: src/program/NormalsGenDialog.cpp:257\nmsgid \"Layer\"\nmsgstr \"Couche\"\n\n#: src/program/NormalsGenDialog.cpp:282\nmsgid \"Background File\"\nmsgstr \"Fichier de Fond\"\n\n#: src/program/NormalsGenDialog.cpp:283\nmsgid \"File source for this layer.\"\nmsgstr \"Source du fichier pour cette couche.\"\n\n#: src/program/NormalsGenDialog.cpp:284\nmsgid \"Color\"\nmsgstr \"Couleur\"\n\n#: src/program/NormalsGenDialog.cpp:285\nmsgid \"Solid background color (if file is not set).\"\nmsgstr \"Couleur de fond solide (si le fichier n'est pas défini).\"\n\n#: src/program/NormalsGenDialog.cpp:286\nmsgid \"Resolution\"\nmsgstr \"Résolution\"\n\n#: src/program/NormalsGenDialog.cpp:288\nmsgid \"\"\n\"Output texture dimensions. By default all images will be scaled to fit this \"\n\"size.\"\nmsgstr \"\"\n\"Dimensions de la texture de sortie. Par défaut, toutes les images seront \"\n\"mises à l'échelle pour correspondre à cette taille.\"\n\n#: src/program/NormalsGenDialog.cpp:306\nmsgid \"\"\n\"File containing normals data to combine. Note this file should fit the mesh \"\n\"UVs.\"\nmsgstr \"\"\n\"Fichier contenant des données normales à combiner. Notez que ce fichier doit \"\n\"s'adapter aux UV du maillage.\"\n\n#: src/program/NormalsGenDialog.cpp:308\nmsgid \"Is Tangent Space?\"\nmsgstr \"C'est l'espace Tangent?\"\n\n#: src/program/NormalsGenDialog.cpp:309\nmsgid \"\"\n\"True if the normals data in the layer file is in tangent space, false if \"\n\"they are in model space (msn).\"\nmsgstr \"\"\n\"Vrai si les données normales dans le fichier de couche sont dans l'espace \"\n\"tangent, faux si elles sont dans l'espace modèle (msn).\"\n\n#: src/program/NormalsGenDialog.cpp:312\nmsgid \"A greyscale image used to mask updates to destination image.\"\nmsgstr \"\"\n\"Une image en niveaux de gris utilisée pour masquer les mises à jour de \"\n\"l'image de destination.\"\n\n#: src/program/NormalsGenDialog.cpp:314\nmsgid \"X Offset\"\nmsgstr \"X Décalage\"\n\n#: src/program/NormalsGenDialog.cpp:315 src/program/NormalsGenDialog.cpp:318\nmsgid \"Offset to apply to image position.\"\nmsgstr \"Décalage à appliquer à la position de l'image.\"\n\n#: src/program/NormalsGenDialog.cpp:317\nmsgid \"Y Offset\"\nmsgstr \"Y Décalage\"\n\n#: src/program/NormalsGenDialog.cpp:321\nmsgid \"If true, scale image to match background resolution.\"\nmsgstr \"\"\n\"Si vrai, mettre l'image à l'échelle pour qu'elle corresponde à la résolution \"\n\"du fond.\"\n\n#: src/program/OutfitProject.cpp:51\nmsgid \"Checking destination...\"\nmsgstr \"Vérification de la destination...\"\n\n#: src/program/OutfitProject.cpp:101\nmsgid \"Adding reference shapes...\"\nmsgstr \"Ajout de formes de référence...\"\n\n#: src/program/OutfitProject.cpp:119 src/program/OutfitProject.cpp:2163\nmsgid \"Adding outfit shapes...\"\nmsgstr \"Ajouter des formes de tenues...\"\n\n#: src/program/OutfitProject.cpp:176\nmsgid \"Calculating slider data...\"\nmsgstr \"Calculer les données du slider...\"\n\n#: src/program/OutfitProject.cpp:184\nmsgid \"Creating slider set file...\"\nmsgstr \"Création d'un fichier de slider set...\"\n\n#: src/program/OutfitProject.cpp:194\nmsgid \"Failed to open or create slider set file: \"\nmsgstr \"Impossible d'ouvrir ou de créer le fichier du slider set: \"\n\n#: src/program/OutfitProject.cpp:211\nmsgid \"Saving slider set file...\"\nmsgstr \"Sauvegarde du fichier de slider set...\"\n\n#: src/program/OutfitProject.cpp:214\nmsgid \"Failed to write to slider set file: \"\nmsgstr \"Échec de l'écriture dans le fichier de slider set: \"\n\n#: src/program/OutfitProject.cpp:218\nmsgid \"Saving NIF file...\"\nmsgstr \"Sauvegarde du fichier NIF...\"\n\n#: src/program/OutfitProject.cpp:248\nmsgid \"Failed to write base .nif file: \"\nmsgstr \"Échec de l'écriture du fichier .nif de base: \"\n\n#: src/program/OutfitProject.cpp:254 src/program/OutfitProject.cpp:1626\n#: src/program/OutfitProject.cpp:1656 src/program/OutfitProject.cpp:2139\n#: src/program/OutfitProject.cpp:2217 src/program/OutfitStudio.cpp:423\n#: src/program/OutfitStudio.cpp:435 src/program/OutfitStudio.cpp:447\n#: src/program/OutfitStudio.cpp:2206 src/program/OutfitStudio.cpp:3228\n#: src/program/OutfitStudio.cpp:3351 src/program/OutfitStudio.cpp:3423\n#: src/program/OutfitStudio.cpp:7558 src/program/OutfitStudio.cpp:7597\n#: src/program/OutfitStudio.cpp:9036 src/program/OutfitStudio.cpp:9127\n#: src/program/OutfitStudio.cpp:9176 src/program/OutfitStudio.cpp:11841\n#: src/program/OutfitStudio.cpp:11853 src/program/OutfitStudio.cpp:11865\n#: src/program/OutfitStudio.cpp:11915\nmsgid \"Finished\"\nmsgstr \"Fini\"\n\n#: src/program/OutfitProject.cpp:1522 src/program/OutfitProject.cpp:1612\nmsgid \"Gathering bones...\"\nmsgstr \"Rassembler les os...\"\n\n#: src/program/OutfitProject.cpp:1550\nmsgid \"Initializing proximity data...\"\nmsgstr \"Initialisation des données de proximité...\"\n\n#: src/program/OutfitProject.cpp:1594 src/program/OutfitStudio.cpp:8986\nmsgid \"Copying bone weights...\"\nmsgstr \"Copie des poids osseux...\"\n\n#: src/program/OutfitProject.cpp:1632 src/program/OutfitStudio.cpp:9168\nmsgid \"Transferring bone weights...\"\nmsgstr \"Transfert de poids osseux...\"\n\n#: src/program/OutfitProject.cpp:1880\nmsgid \"Template source entries are invalid.\"\nmsgstr \"Les entrées de source du modèle ne sont pas valides.\"\n\n#: src/program/OutfitProject.cpp:1880 src/program/OutfitProject.cpp:1909\n#: src/program/OutfitProject.cpp:1914 src/program/OutfitProject.cpp:1957\n#: src/program/OutfitProject.cpp:1980 src/program/OutfitProject.cpp:1987\n#: src/program/OutfitProject.cpp:1997 src/program/OutfitProject.cpp:2009\nmsgid \"Reference Error\"\nmsgstr \"Erreur de Référence\"\n\n#: src/program/OutfitProject.cpp:1905 src/program/OutfitProject.cpp:1976\n#: src/program/OutfitProject.cpp:3410\n#, c-format\nmsgid \"\"\n\"NIF version not supported!\\n\"\n\"\\n\"\n\"File: %s\\n\"\n\"%s\"\nmsgstr \"\"\n\"Version NIF non prise en charge!\\n\"\n\"\\n\"\n\"File: %s\\n\"\n\"%s\"\n\n#: src/program/OutfitProject.cpp:1914 src/program/OutfitProject.cpp:1987\n#, c-format\nmsgid \"Could not load reference NIF file '%s'!\"\nmsgstr \"Impossible de charger le fichier NIF de référence '%s'!\"\n\n#: src/program/OutfitProject.cpp:1957\n#, c-format\nmsgid \"Could not load slider set file '%s'!\"\nmsgstr \"Impossible de charger le fichier de slider set '%s'!\"\n\n#: src/program/OutfitProject.cpp:1997\n#, c-format\nmsgid \"Reference NIF file '%s' does not contain any shapes.\"\nmsgstr \"Le fichier NIF de référence '%s' ne contient aucune forme.\"\n\n#: src/program/OutfitProject.cpp:2009\n#, c-format\nmsgid \"Shape '%s' not found in reference NIF file '%s'!\"\nmsgstr \"Forme '%s' non trouvée dans le fichier NIF de référence '%s'!\"\n\n#: src/program/OutfitProject.cpp:2061\nmsgid \"Loading slider set...\"\nmsgstr \"Chargement du slider set...\"\n\n#: src/program/OutfitProject.cpp:2068 src/program/OutfitProject.cpp:2153\nmsgid \"Retrieving sliders...\"\nmsgstr \"Récupérer les sliders...\"\n\n#: src/program/OutfitProject.cpp:2078\nmsgid \"Loading outfit shapes...\"\nmsgstr \"Chargement des formes de tenues...\"\n\n#: src/program/OutfitProject.cpp:2121 src/program/OutfitProject.cpp:2214\nmsgid \"Updating slider data...\"\nmsgstr \"Mise à jour des données du slider...\"\n\n#: src/program/OutfitProject.cpp:2145\nmsgid \"Adding slider set...\"\nmsgstr \"Ajout d'un slider set...\"\n\n#: src/program/OutfitProject.cpp:2211\nmsgid \"\"\n\"The following shapes were renamed and won't have slider data attached. \"\n\"Rename the duplicates yourself beforehand.\"\nmsgstr \"\"\n\"Les formes suivantes ont été renommées et n'auront pas de données de slider \"\n\"attachées. Renommez les doublons vous-même au préalable.\"\n\n#: src/program/OutfitProject.cpp:2211\nmsgid \"Renamed Shapes\"\nmsgstr \"Formes Renommées\"\n\n#: src/program/OutfitProject.cpp:3414 src/program/OutfitProject.cpp:3419\nmsgid \"NIF Error\"\nmsgstr \"Erreur NIF\"\n\n#: src/program/OutfitProject.cpp:3419\n#, c-format\nmsgid \"Could not load NIF file '%s'!\"\nmsgstr \"Impossible de charger le fichier NIF '%s'!\"\n\n#: src/program/OutfitProject.cpp:3550\nmsgid \"\"\n\"There was cloth physics data loaded at some point (BSClothExtraData). Please \"\n\"choose all the origins to use in the output.\"\nmsgstr \"\"\n\"Des données de physique du tissu ont été chargées à un moment donné \"\n\"(BSClothExtraData). Veuillez choisir toutes les origines à utiliser dans la \"\n\"sortie.\"\n\n#: src/program/OutfitProject.cpp:3550\nmsgid \"Choose cloth data\"\nmsgstr \"Choisir les données du tissu\"\n\n#: src/program/OutfitProject.cpp:3601\nmsgid \"\"\n\"No reference has been loaded.  For correct bone transforms, you might need \"\n\"to load a reference before importing OBJ files.  Import anyway?\"\nmsgstr \"\"\n\"Aucune référence n'a été chargée.  Pour des transformations osseuses \"\n\"correctes, il peut être nécessaire de charger une référence avant d'importer \"\n\"des fichiers OBJ.  Importer quand même?\"\n\n#: src/program/OutfitProject.cpp:3601 src/program/OutfitProject.cpp:3743\nmsgid \"Import without reference\"\nmsgstr \"Importez sans Référence\"\n\n#: src/program/OutfitProject.cpp:3608 src/program/OutfitProject.cpp:3750\nmsgid \"\"\n\"The reference shape has a skin coordinate system that is different from the \"\n\"global coordinate system.  Would you like to copy the reference's global-to-\"\n\"skin transform to the imported shapes?\"\nmsgstr \"\"\n\"La forme de référence a un système de coordonnées de peau qui est différent \"\n\"du système de coordonnées global.  Voulez-vous copier la transformation \"\n\"globale-peau de la référence sur les formes importées?\"\n\n#: src/program/OutfitProject.cpp:3608 src/program/OutfitProject.cpp:3750\nmsgid \"Copy skin coordinates\"\nmsgstr \"Transformez les coordonnées de la peau\"\n\n#: src/program/OutfitProject.cpp:3625\n#, c-format\nmsgid \"Could not load OBJ file '%s'!\"\nmsgstr \"Impossible de charger le fichier OBJ '%s'!\"\n\n#: src/program/OutfitProject.cpp:3625 src/program/OutfitProject.cpp:3637\n#: src/program/OutfitProject.cpp:3682 src/program/OutfitProject.cpp:3822\nmsgid \"OBJ Error\"\nmsgstr \"Erreur OBJ\"\n\n#: src/program/OutfitProject.cpp:3637\n#, c-format\nmsgid \"Could not copy data from OBJ file '%s'!\"\nmsgstr \"Impossible de copier les données du fichier OBJ '%s'!\"\n\n#: src/program/OutfitProject.cpp:3654\nmsgid \"\"\n\"The vertex count of the selected .obj file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"Le nombre de vertex du fichier .obj sélectionné correspond à la forme de la \"\n\"tenue actuellement sélectionnée.  Souhaitez-vous mettre à jour la forme \"\n\"actuelle?  (cliquez sur Non pour créer une nouvelle forme)\"\n\n#: src/program/OutfitProject.cpp:3654 src/program/OutfitProject.cpp:3784\nmsgid \"Merge or New\"\nmsgstr \"Fusionner ou Nouveaux\"\n\n#: src/program/OutfitProject.cpp:3656 src/program/OutfitProject.cpp:3786\nmsgid \"Update Vertex Positions?\"\nmsgstr \"Mettre à jour les positions des vertex?\"\n\n#: src/program/OutfitProject.cpp:3656 src/program/OutfitProject.cpp:3786\nmsgid \"Vertex Position Update\"\nmsgstr \"Mise à jour de la position des vertex\"\n\n#: src/program/OutfitProject.cpp:3660 src/program/OutfitProject.cpp:3790\nmsgid \"Update Texture Coordinates?\"\nmsgstr \"Mettre à jour les coordonnées de texture?\"\n\n#: src/program/OutfitProject.cpp:3660 src/program/OutfitProject.cpp:3790\nmsgid \"UV Update\"\nmsgstr \"Mise à jour UV\"\n\n#: src/program/OutfitProject.cpp:3667 src/program/OutfitProject.cpp:3803\nmsgid \"Please specify a name for the new shape\"\nmsgstr \"Veuillez saisir un nom pour le nouveau forme\"\n\n#: src/program/OutfitProject.cpp:3667 src/program/OutfitProject.cpp:3803\nmsgid \"New Shape Name\"\nmsgstr \"Nouveau Nom de Forme\"\n\n#: src/program/OutfitProject.cpp:3681 src/program/OutfitProject.cpp:3821\n#, c-format\nmsgid \"\"\n\"The vertex or triangle limit for '%s' was exceeded.\\n\"\n\"Remaining data was dropped.\\n\"\n\"\\n\"\n\"Vertices (current/max): %zu/%zu\\n\"\n\"Triangles (current/max): %zu/%zu\"\nmsgstr \"\"\n\"La limite de vertex ou de triangles pour '%s' a été dépassée.\\n\"\n\"Les données restantes ont été abandonnées.\\n\"\n\"\\n\"\n\"Vertices (actuels/maximaux): %zu/%zu\\n\"\n\"Triangles (actuels/maximaux): %zu/%zu\"\n\n#: src/program/OutfitProject.cpp:3743\nmsgid \"\"\n\"No reference has been loaded.  For correct bone transforms, you might need \"\n\"to load a reference before importing FBX files.  Import anyway?\"\nmsgstr \"\"\n\"Aucune référence n'a été chargée.  Pour des transformations osseuses \"\n\"correctes, il peut être nécessaire de charger une référence avant d'importer \"\n\"des fichiers FBX.  Importer quand même?\"\n\n#: src/program/OutfitProject.cpp:3784\nmsgid \"\"\n\"The vertex count of the selected .fbx file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"Le nombre de vertex du fichier .fbx sélectionné correspond à la forme de la \"\n\"tenue actuellement sélectionnée.  Souhaitez-vous mettre à jour la forme \"\n\"actuelle?  (cliquez sur Non pour créer une nouvelle forme)\"\n\n#: src/program/OutfitProject.cpp:3794\nmsgid \"Update Animation Weighting?\"\nmsgstr \"Mise à jour de la Pondération des Animations?\"\n\n#: src/program/OutfitProject.cpp:3794\nmsgid \"Animation Weight Update\"\nmsgstr \"Mise à jour des Poids d'Animation\"\n\n#: src/program/OutfitProject.cpp:3902\nmsgid \"Would you like Skyrim NIFs to be optimized for SSE during this session?\"\nmsgstr \"\"\n\"Souhaitez-vous que les NIFs de Skyrim soient optimisés pour SSE pendant \"\n\"cette session?\"\n\n#: src/program/OutfitProject.cpp:3919\nmsgid \"\"\n\"Version of NIF file doesn't match current target game. To use the meshes for \"\n\"the target game, export to OBJ/FBX and reload them again.\"\nmsgstr \"\"\n\"La version du fichier NIF ne correspond pas au jeu cible actuel. Pour \"\n\"utiliser les maillages pour le jeu cible, exportez-les vers OBJ/FBX et \"\n\"rechargez-les à nouveau.\"\n\n#: src/program/OutfitProject.cpp:3919\nmsgid \"Version\"\nmsgstr \"Version\"\n\n#: src/program/OutfitStudio.cpp:415 src/program/OutfitStudio.cpp:416\n#: src/program/OutfitStudio.cpp:11833 src/program/OutfitStudio.cpp:11834\nmsgid \"Adding NIF file...\"\nmsgstr \"Ajout d'un fichier NIF...\"\n\n#: src/program/OutfitStudio.cpp:420 src/program/OutfitStudio.cpp:432\n#: src/program/OutfitStudio.cpp:444 src/program/OutfitStudio.cpp:3885\n#: src/program/OutfitStudio.cpp:11838 src/program/OutfitStudio.cpp:11850\n#: src/program/OutfitStudio.cpp:11862\nmsgid \"Refreshing GUI...\"\nmsgstr \"Rafraîchissante GUI...\"\n\n#: src/program/OutfitStudio.cpp:428 src/program/OutfitStudio.cpp:11846\nmsgid \"Adding OBJ file...\"\nmsgstr \"Ajout d'un fichier OBJ...\"\n\n#: src/program/OutfitStudio.cpp:439 src/program/OutfitStudio.cpp:440\n#: src/program/OutfitStudio.cpp:11857 src/program/OutfitStudio.cpp:11858\nmsgid \"Adding FBX file...\"\nmsgstr \"Ajout d'un fichier FBX...\"\n\n#: src/program/OutfitStudio.cpp:918\nmsgid \"Failed to load OutfitStudio.xrc file!\"\nmsgstr \"Échec du chargement du fichier OutfitStudio.xrc!\"\n\n#: src/program/OutfitStudio.cpp:924\nmsgid \"Failed to load Outfit Studio frame!\"\nmsgstr \"Échec du chargement du cadre Outfit Studio!\"\n\n#: src/program/OutfitStudio.cpp:942 src/program/OutfitStudio.h:1113\nmsgid \"Ready!\"\nmsgstr \"Prêt!\"\n\n#: src/program/OutfitStudio.cpp:1335 src/program/OutfitStudio.cpp:1340\nmsgid \"Packing projects to folder...\"\nmsgstr \"Emballage des projets dans les dossiers...\"\n\n#: src/program/OutfitStudio.cpp:1361 src/program/OutfitStudio.cpp:1409\n#: src/program/OutfitStudio.cpp:1512\n#, c-format\nmsgid \"Failed to open input file '%s'!\"\nmsgstr \"Échec de l'ouverture le fichier d'entrée '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1372\n#, c-format\nmsgid \"Failed to copy input file '%s'!\"\nmsgstr \"Échec de copier le fichier d'entrée '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1420\n#, c-format\nmsgid \"Failed to copy data file '%s'!\"\nmsgstr \"Échec de copier le fichier de données '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1430 src/program/OutfitStudio.cpp:1589\n#, c-format\nmsgid \"Failed to save merged project file '%s'!\"\nmsgstr \"Échec de l'enregistrement du fichier de projet fusionné '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1439 src/program/OutfitStudio.cpp:1598\n#, c-format\nmsgid \"Failed to open project file '%s'!\"\nmsgstr \"Échec de l'ouverture du fichier de projet '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1450\n#, c-format\nmsgid \"Failed to copy merged project file '%s'!\"\nmsgstr \"Échec de la copie du fichier de projet fusionné '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1461 src/program/OutfitStudio.cpp:1624\n#, c-format\nmsgid \"Failed to open group file '%s'!\"\nmsgstr \"Échec de l'ouverture le fichier de groupe '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1473\n#, c-format\nmsgid \"Failed to copy group file '%s'!\"\nmsgstr \"Échec de copier le fichier de groupe '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1483 src/program/OutfitStudio.cpp:1488\nmsgid \"Packing projects to archive...\"\nmsgstr \"Emballage des projets dans l'archive...\"\n\n#: src/program/OutfitStudio.cpp:1520 src/program/OutfitStudio.cpp:1572\n#: src/program/OutfitStudio.cpp:1606 src/program/OutfitStudio.cpp:1633\nmsgid \"Failed to put new entry into archive!\"\nmsgstr \"Échec de la mise la nouvelle entrée dans l'archive!\"\n\n#: src/program/OutfitStudio.cpp:1527 src/program/OutfitStudio.cpp:1579\n#: src/program/OutfitStudio.cpp:1613 src/program/OutfitStudio.cpp:1640\nmsgid \"Failed to copy file contents to archive!\"\nmsgstr \"Échec de la copie du contenu du fichier dans l'archive!\"\n\n#: src/program/OutfitStudio.cpp:1564\n#, c-format\nmsgid \"Failed to open data file '%s'!\"\nmsgstr \"Échec de l'ouverture le fichier de données '%s'!\"\n\n#: src/program/OutfitStudio.cpp:1888 src/program/OutfitStudio.cpp:1925\n#: src/program/OutfitStudio.cpp:4275 src/program/OutfitStudio.cpp:4301\n#: src/program/OutfitStudio.cpp:6814 src/program/OutfitStudio.cpp:6904\n#: src/program/OutfitStudio.cpp:7126 src/program/OutfitStudio.cpp:7144\n#: src/program/OutfitStudio.cpp:7162\nmsgid \"There are no valid shapes loaded!\"\nmsgstr \"Il n'y a pas de formes valides chargées!\"\n\n#: src/program/OutfitStudio.cpp:1896 src/program/OutfitStudio.cpp:2063\n#, c-format\nmsgid \"Saving project '%s'...\"\nmsgstr \"Sauvegarde du projet '%s'...\"\n\n#: src/program/OutfitStudio.cpp:2009\nmsgid \"Invalid or no slider set file specified! Please try again.\"\nmsgstr \"Fichier de slider set non valide ou non spécifié! Veuillez réessayer.\"\n\n#: src/program/OutfitStudio.cpp:2018\nmsgid \"No outfit name specified! Please try again.\"\nmsgstr \"Aucun nom de tenue n'a été spécifié! Veuillez réessayer.\"\n\n#: src/program/OutfitStudio.cpp:2026\nmsgid \"No data folder specified! Please try again.\"\nmsgstr \"Aucun dossier de données n'a été spécifié! Veuillez réessayer.\"\n\n#: src/program/OutfitStudio.cpp:2040\nmsgid \"\"\n\"An invalid or no base outfit .nif file name specified! Please try again.\"\nmsgstr \"\"\n\"Un nom de fichier .nif invalide ou sans tenue de base a été spécifié! \"\n\"Veuillez réessayer.\"\n\n#: src/program/OutfitStudio.cpp:2049\nmsgid \"No game file path specified! Please try again.\"\nmsgstr \"Aucun chemin de fichier de jeu n'a été spécifié! Veuillez réessayer.\"\n\n#: src/program/OutfitStudio.cpp:2055\nmsgid \"No game file name specified! Please try again.\"\nmsgstr \"Aucun nom de fichier de jeu n'a été spécifié! Veuillez réessayer.\"\n\n#: src/program/OutfitStudio.cpp:2096\n#, c-format\nmsgid \"Failed to open '%s' as a slider set file!\"\nmsgstr \"Impossible d'ouvrir '%s' comme fichier de slider set!\"\n\n#: src/program/OutfitStudio.cpp:2096 src/program/OutfitStudio.cpp:2160\nmsgid \"Slider Set Error\"\nmsgstr \"Slider Set Erreur\"\n\n#: src/program/OutfitStudio.cpp:2115\nmsgid \"Please choose an outfit to load\"\nmsgstr \"Choisissez une tenue à charger\"\n\n#: src/program/OutfitStudio.cpp:2115\nmsgid \"Load a slider set\"\nmsgstr \"Chargez un slider set\"\n\n#: src/program/OutfitStudio.cpp:2126\nmsgid \"Loading project...\"\nmsgstr \"Chargement projet...\"\n\n#: src/program/OutfitStudio.cpp:2146\nmsgid \"Loading outfit data...\"\nmsgstr \"Chargement des données de tenues...\"\n\n#: src/program/OutfitStudio.cpp:2160\n#, c-format\nmsgid \"Failed to create project '%s' from file '%s' (%d)!\"\nmsgstr \"Impossible de créer le projet '%s' à partir du fichier '%s' (%d)!\"\n\n#: src/program/OutfitStudio.cpp:2174\n#, c-format\nmsgid \"Loading reference shape '%s'...\"\nmsgstr \"Chargement la forme référence '%s'...\"\n\n#: src/program/OutfitStudio.cpp:2188\nmsgid \"Loading textures...\"\nmsgstr \"Chargement textures...\"\n\n#: src/program/OutfitStudio.cpp:2193 src/program/OutfitStudio.cpp:3208\n#: src/program/OutfitStudio.cpp:3417\nmsgid \"Creating outfit...\"\nmsgstr \"Créer des tenues...\"\n\n#: src/program/OutfitStudio.cpp:2197 src/program/OutfitStudio.cpp:3218\n#: src/program/OutfitStudio.cpp:3344\n#, c-format\nmsgid \"Creating %zu slider(s)...\"\nmsgstr \"Créer %zu slider(s)...\"\n\n#: src/program/OutfitStudio.cpp:2220\nmsgid \"Creating sliders...\"\nmsgstr \"Créer des sliders...\"\n\n#: src/program/OutfitStudio.cpp:2223\nmsgid \"Clearing old sliders...\"\nmsgstr \"Nettoyage des anciens sliders...\"\n\n#: src/program/OutfitStudio.cpp:2237\nmsgid \"Loading slider: \"\nmsgstr \"Chargement du slider: \"\n\n#: src/program/OutfitStudio.cpp:2268\nmsgid \"Turn on edit mode for this slider.\"\nmsgstr \"Activez le mode d'édition pour ce slider.\"\n\n#: src/program/OutfitStudio.cpp:2272\nmsgid \"Weaken slider data by 1%.\"\nmsgstr \"Affaiblir les données du slider de 1%.\"\n\n#: src/program/OutfitStudio.cpp:2278\nmsgid \"Strengthen slider data by 1%.\"\nmsgstr \"Renforcer les données du slider de 1%.\"\n\n#: src/program/OutfitStudio.cpp:2335 src/program/OutfitStudio.cpp:7281\nmsgid \"Enter a name for the new slider:\"\nmsgstr \"Entrez un nom pour le nouveau slider:\"\n\n#: src/program/OutfitStudio.cpp:2335 src/program/OutfitStudio.cpp:7281\nmsgid \"Create New Slider\"\nmsgstr \"Créez Slider Nouveau\"\n\n#: src/program/OutfitStudio.cpp:2462\n#, c-format\nmsgid \"Total Bones: %zu\"\nmsgstr \"Total des Os: %zu\"\n\n#: src/program/OutfitStudio.cpp:2477\n#, c-format\nmsgid \"Shape Selection Bones: %zu\"\nmsgstr \"Sélection des Formes Os: %zu\"\n\n#: src/program/OutfitStudio.cpp:2959\nmsgid \"Edit Color\"\nmsgstr \"Modifiez Couleur\"\n\n#: src/program/OutfitStudio.cpp:3014\nmsgid \"\"\n\"You are trying to edit a slider's morph with that slider set to zero.  Do \"\n\"you wish to set the slider to one now?\"\nmsgstr \"\"\n\"Vous essayez de modifier la morphologie d'un slider alors que celui-ci est \"\n\"réglé sur zéro.  Voulez-vous mettre le slider à un maintenant ?\"\n\n#: src/program/OutfitStudio.cpp:3029\nmsgid \"\"\n\"You can only use the undiff brush while editing a slider. Note, use the \"\n\"pencil button next to a slider to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"Vous ne pouvez utiliser le pinceau d'undiff que lorsque vous modifiez un \"\n\"slider. Remarque, utilisez le bouton crayon à côté d'un slider pour activer \"\n\"l'édition de la morphologie de ce slider.\"\n\n#: src/program/OutfitStudio.cpp:3037\nmsgid \"\"\n\"You can only edit the base shape when all sliders are zero. Do you wish to \"\n\"set all sliders to zero now?  Note, use the pencil button next to a slider \"\n\"to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"Vous ne pouvez modifier la forme de base que lorsque tous les sliders sont à \"\n\"zéro. Voulez-vous mettre tous les sliders à zéro maintenant ?  Remarque, \"\n\"utilisez le bouton crayon à côté d'un slider pour activer l'édition de la \"\n\"morphologie de ce slider.\"\n\n#: src/program/OutfitStudio.cpp:3067\n#, c-format\nmsgid \"You have unsaved changes to '%s'. Would you like to save them now?\"\nmsgstr \"\"\n\"Vous avez des modifications non sauvegardées sur '%s'. Voulez-vous les \"\n\"sauvegarder maintenant?\"\n\n#: src/program/OutfitStudio.cpp:3067\nmsgid \"Unsaved Changes\"\nmsgstr \"Modifications Non Sauvegarder\"\n\n#: src/program/OutfitStudio.cpp:3126\n#, c-format\nmsgid \"Creating project '%s'...\"\nmsgstr \"Créer le projet '%s'...\"\n\n#: src/program/OutfitStudio.cpp:3143 src/program/OutfitStudio.cpp:3284\nmsgid \"Loading reference...\"\nmsgstr \"Chargement référence...\"\n\n#: src/program/OutfitStudio.cpp:3187 src/program/OutfitStudio.cpp:3375\n#: src/program/OutfitStudio.cpp:3384\nmsgid \"Loading outfit...\"\nmsgstr \"Chargement de tenues...\"\n\n#: src/program/OutfitStudio.cpp:3234\nmsgid \"Select a slider set to load\"\nmsgstr \"Sélectionnez un slider set à charger\"\n\n#: src/program/OutfitStudio.cpp:3246\nmsgid \"Select a slider set to add\"\nmsgstr \"Sélectionnez un slider set à ajouter\"\n\n#: src/program/OutfitStudio.cpp:3259 src/program/OutfitStudio.cpp:8264\n#: src/program/OutfitStudio.cpp:8318 src/program/OutfitStudio.cpp:8407\nmsgid \"\"\n\"You're currently editing slider data, please exit the slider's edit mode \"\n\"(pencil button) and try again.\"\nmsgstr \"\"\n\"Vous êtes en train de modifier les données du slider, veuillez quitter le \"\n\"mode d'édition du slider (bouton crayon) et réessayer.\"\n\n#: src/program/OutfitStudio.cpp:3290\nmsgid \"Loading reference set...\"\nmsgstr \"Chargement du jeu de références...\"\n\n#: src/program/OutfitStudio.cpp:3340\nmsgid \"Creating reference...\"\nmsgstr \"Créer une référence...\"\n\n#: src/program/OutfitStudio.cpp:3428\nmsgid \"Unload the project? All unsaved changes will be lost\"\nmsgstr \"\"\n\"Décharger le projet? Toutes les modifications non sauvegardées seront perdues\"\n\n#: src/program/OutfitStudio.cpp:3428\nmsgid \"Unload Project\"\nmsgstr \"Déchargez le Projet\"\n\n#: src/program/OutfitStudio.cpp:3429\nmsgid \"Unload\"\nmsgstr \"Déchargez\"\n\n#: src/program/OutfitStudio.cpp:3872\nmsgid \"Import NIF file\"\nmsgstr \"Importer un fichier NIF\"\n\n#: src/program/OutfitStudio.cpp:3879 src/program/OutfitStudio.cpp:3880\nmsgid \"Importing NIF file...\"\nmsgstr \"Importation d'un fichier NIF...\"\n\n#: src/program/OutfitStudio.cpp:3891\nmsgid \"Finished.\"\nmsgstr \"Fini.\"\n\n#: src/program/OutfitStudio.cpp:3902\nmsgid \"Export outfit NIF\"\nmsgstr \"Exporter la tenue NIF\"\n\n#: src/program/OutfitStudio.cpp:3917\n#, c-format\nmsgid \"Failed to save NIF file '%s'!\"\nmsgstr \"Échec de l'enregistrement du fichier NIF '%s'!\"\n\n#: src/program/OutfitStudio.cpp:3917 src/program/OutfitStudio.cpp:3947\n#: src/program/OutfitStudio.cpp:4031 src/program/OutfitStudio.cpp:4146\n#: src/program/OutfitStudio.cpp:4363\nmsgid \"Export Error\"\nmsgstr \"Erreur d'Exportation\"\n\n#: src/program/OutfitStudio.cpp:3933\nmsgid \"Export project NIF\"\nmsgstr \"Exporter la projet NIF\"\n\n#: src/program/OutfitStudio.cpp:3947\n#, c-format\nmsgid \"Failed to save NIF file '%s' with reference!\"\nmsgstr \"Échec de l'enregistrement du fichier NIF '%s' avec référence!\"\n\n#: src/program/OutfitStudio.cpp:3953 src/program/OutfitStudio.cpp:4037\n#: src/program/OutfitStudio.cpp:4152 src/program/OutfitStudio.cpp:4280\n#: src/program/OutfitStudio.cpp:4306 src/program/OutfitStudio.cpp:6743\n#: src/program/OutfitStudio.cpp:6768 src/program/OutfitStudio.cpp:6789\n#: src/program/OutfitStudio.cpp:6996 src/program/OutfitStudio.cpp:7021\n#: src/program/OutfitStudio.cpp:7057 src/program/OutfitStudio.cpp:7090\n#: src/program/OutfitStudio.cpp:7186 src/program/OutfitStudio.cpp:7236\n#: src/program/OutfitStudio.cpp:7296 src/program/OutfitStudio.cpp:7313\n#: src/program/OutfitStudio.cpp:7688 src/program/OutfitStudio.cpp:7705\n#: src/program/OutfitStudio.cpp:7723 src/program/OutfitStudio.cpp:7747\n#: src/program/OutfitStudio.cpp:7782 src/program/OutfitStudio.cpp:7928\n#: src/program/OutfitStudio.cpp:8112 src/program/OutfitStudio.cpp:8259\n#: src/program/OutfitStudio.cpp:8313 src/program/OutfitStudio.cpp:8529\n#: src/program/OutfitStudio.cpp:8972 src/program/OutfitStudio.cpp:9046\n#: src/program/OutfitStudio.cpp:9137 src/program/OutfitStudio.cpp:9184\n#: src/program/OutfitStudio.cpp:9214 src/program/OutfitStudio.cpp:9266\n#: src/program/OutfitStudio.cpp:9440 src/program/OutfitStudio.cpp:11891\nmsgid \"There is no shape selected!\"\nmsgstr \"Il n'y a pas de forme sélectionnée!\"\n\n#: src/program/OutfitStudio.cpp:3960\nmsgid \"Export selected shapes to NIF\"\nmsgstr \"Exportez les formes sélectionnées vers NIF\"\n\n#: src/program/OutfitStudio.cpp:3973\nmsgid \"Failed to export selected shapes to NIF file!\"\nmsgstr \"Impossible d'exporter les formes sélectionnées vers le fichier NIF!\"\n\n#: src/program/OutfitStudio.cpp:3978\nmsgid \"Import .obj file for new shape\"\nmsgstr \"Importez un fichier .obj pour une nouvelle forme\"\n\n#: src/program/OutfitStudio.cpp:4016\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the OBJ?  (This is not recommended.)\"\nmsgstr \"\"\n\"Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont \"\n\"pas les mêmes que le système de coordonnées global.  La géométrie doit-elle \"\n\"être transformée en coordonnées globales dans l'OBJ?  (Ceci n'est pas \"\n\"recommandé).\"\n\n#: src/program/OutfitStudio.cpp:4016 src/program/OutfitStudio.cpp:4049\n#: src/program/OutfitStudio.cpp:4131 src/program/OutfitStudio.cpp:4164\nmsgid \"Transform to global\"\nmsgstr \"Transformez a la globales\"\n\n#: src/program/OutfitStudio.cpp:4022\nmsgid \"Export project as an .obj file\"\nmsgstr \"Exporter la projet sous forme de fichier .obj\"\n\n#: src/program/OutfitStudio.cpp:4031 src/program/OutfitStudio.cpp:4070\n#: src/program/OutfitStudio.cpp:4084 src/program/OutfitStudio.cpp:7117\nmsgid \"Failed to export OBJ file!\"\nmsgstr \"Échec de l'exportation du fichier OBJ!\"\n\n#: src/program/OutfitStudio.cpp:4049\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the OBJ?\"\nmsgstr \"\"\n\"Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont \"\n\"pas les mêmes que le système de coordonnées global.  La géométrie doit-elle \"\n\"être transformée en coordonnées globales dans l'OBJ?\"\n\n#: src/program/OutfitStudio.cpp:4056\nmsgid \"Export selected shapes as an .obj file\"\nmsgstr \"Exporter les formes sélectionnées sous forme de fichier .obj\"\n\n#: src/program/OutfitStudio.cpp:4074\nmsgid \"Export shape as an .obj file\"\nmsgstr \"Exporter la forme sous forme de fichier .obj\"\n\n#: src/program/OutfitStudio.cpp:4090\nmsgid \"Import .fbx file for new shape\"\nmsgstr \"Importez un fichier .fbx pour une nouvelle forme\"\n\n#: src/program/OutfitStudio.cpp:4131\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the FBX?  (This is not recommended.)\"\nmsgstr \"\"\n\"Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont \"\n\"pas les mêmes que le système de coordonnées global.  La géométrie doit-elle \"\n\"être transformée en coordonnées globales dans le FBX?  (Ceci n'est pas \"\n\"recommandé).\"\n\n#: src/program/OutfitStudio.cpp:4137\nmsgid \"Export project as an .fbx file\"\nmsgstr \"Exporter la projet sous forme de fichier .fbx\"\n\n#: src/program/OutfitStudio.cpp:4146 src/program/OutfitStudio.cpp:4185\n#: src/program/OutfitStudio.cpp:4199\nmsgid \"Failed to export FBX file!\"\nmsgstr \"Échec de l'exportation du fichier FBX!\"\n\n#: src/program/OutfitStudio.cpp:4164\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the FBX?\"\nmsgstr \"\"\n\"Certaines des formes ont des systèmes de coordonnées de la peau qui ne sont \"\n\"pas les mêmes que le système de coordonnées global.  La géométrie doit-elle \"\n\"être transformée en coordonnées globales dans le FBX?\"\n\n#: src/program/OutfitStudio.cpp:4171\nmsgid \"Export selected shapes as an .fbx file\"\nmsgstr \"Exporter les formes sélectionnées sous forme de fichier .fbx\"\n\n#: src/program/OutfitStudio.cpp:4189\nmsgid \"Export shape as an .fbx file\"\nmsgstr \"Exporter la forme sous forme de fichier .fbx\"\n\n#: src/program/OutfitStudio.cpp:4205 src/program/OutfitStudio.cpp:6908\nmsgid \"Import .tri morphs\"\nmsgstr \"Importez .tri morphs\"\n\n#: src/program/OutfitStudio.cpp:4224 src/program/OutfitStudio.cpp:6922\nmsgid \"Failed to load TRI file!\"\nmsgstr \"Échec du chargement du fichier TRI!\"\n\n#: src/program/OutfitStudio.cpp:4230 src/program/OutfitStudio.cpp:7729\nmsgid \"Please enter a new unique name for the shape.\"\nmsgstr \"Veuillez saisir un nouveau nom unique pour la forme.\"\n\n#: src/program/OutfitStudio.cpp:4230 src/program/OutfitStudio.cpp:7729\nmsgid \"Rename Shape\"\nmsgstr \"Renommez la Forme\"\n\n#: src/program/OutfitStudio.cpp:4284 src/program/OutfitStudio.cpp:4310\n#: src/program/OutfitStudio.cpp:7148\nmsgid \"Export .tri morphs\"\nmsgstr \"Exportez .tri morphs\"\n\n#: src/program/OutfitStudio.cpp:4294 src/program/OutfitStudio.cpp:4317\n#: src/program/OutfitStudio.cpp:7155\nmsgid \"Failed to export TRI file!\"\nmsgstr \"Échec de l'exportation du fichier TRI!\"\n\n#: src/program/OutfitStudio.cpp:4322\nmsgid \"Import physics data to project\"\nmsgstr \"Importer des données physiques dans le projet\"\n\n#: src/program/OutfitStudio.cpp:4329\n#, c-format\nmsgid \"Failed to import physics data file '%s'!\"\nmsgstr \"Échec de l'importation du fichier de données physiques '%s'!\"\n\n#: src/program/OutfitStudio.cpp:4329\nmsgid \"Import Error\"\nmsgstr \"Erreur d'Importation\"\n\n#: src/program/OutfitStudio.cpp:4341\nmsgid \"There is no physics data loaded!\"\nmsgstr \"Il n'y a pas de données physiques chargées!\"\n\n#: src/program/OutfitStudio.cpp:4341 src/program/OutfitStudio.cpp:6730\nmsgid \"Info\"\nmsgstr \"Info\"\n\n#: src/program/OutfitStudio.cpp:4349\nmsgid \"Please choose the physics data source you want to export.\"\nmsgstr \"\"\n\"Veuillez choisir la source de données physiques que vous souhaitez exporter.\"\n\n#: src/program/OutfitStudio.cpp:4349\nmsgid \"Choose physics data\"\nmsgstr \"Choisir de données physiques\"\n\n#: src/program/OutfitStudio.cpp:4357\nmsgid \"Export physics data\"\nmsgstr \"Exportez de données physiques\"\n\n#: src/program/OutfitStudio.cpp:4363\n#, c-format\nmsgid \"Failed to save physics data file '%s'!\"\nmsgstr \"Échec de l'enregistrement du fichier de données physiques '%s'!\"\n\n#: src/program/OutfitStudio.cpp:4370\nmsgid \"This function requires at least one slider position to be non-zero.\"\nmsgstr \"\"\n\"Cette fonction nécessite qu'au moins une position de slider soit différente \"\n\"de zéro.\"\n\n#: src/program/OutfitStudio.cpp:4381\nmsgid \"\"\n\"Create a conversion slider for the current slider settings with the \"\n\"following name: \"\nmsgstr \"\"\n\"Créez un slider de conversion pour les paramètres de slider actuels avec le \"\n\"nom suivant: \"\n\n#: src/program/OutfitStudio.cpp:4381\nmsgid \"Create New Conversion Slider\"\nmsgstr \"Créez Slider Conversion Nouveau\"\n\n#: src/program/OutfitStudio.cpp:5122\nmsgid \"Please enter an SSF file path.\"\nmsgstr \"Veuillez saisir un chemin d'accès au fichier SSF.\"\n\n#: src/program/OutfitStudio.cpp:5844\n#, c-format\nmsgid \"Field of View: %d\"\nmsgstr \"Champ de Vision: %d\"\n\n#: src/program/OutfitStudio.cpp:5966\nmsgid \"Your changes were not applied yet. Do you want to apply or reset them?\"\nmsgstr \"\"\n\"Vos modifications n'ont pas encore été appliquées. Voulez-vous les appliquer \"\n\"ou les réinitialiser?\"\n\n#: src/program/OutfitStudio.cpp:5966\nmsgid \"Pending Changes\"\nmsgstr \"Modifications en Attente\"\n\n#: src/program/OutfitStudio.cpp:6681\nmsgid \"There are no sliders loaded!\"\nmsgstr \"Il n'y a pas de sliders chargés!\"\n\n#: src/program/OutfitStudio.cpp:6730\nmsgid \"No changes were made to the sliders, so no preset was saved!\"\nmsgstr \"\"\n\"Aucune modification n'a été apportée aux sliders, donc aucun préréglage n'a \"\n\"été enregistré!\"\n\n#: src/program/OutfitStudio.cpp:6747 src/program/OutfitStudio.cpp:6772\n#: src/program/OutfitStudio.cpp:6793 src/program/OutfitStudio.cpp:7000\nmsgid \"There is no slider in edit mode to import data to!\"\nmsgstr \"Il n'y a pas de slider en mode édition pour importer des données!\"\n\n#: src/program/OutfitStudio.cpp:6751\nmsgid \"Import .nif file for slider calculation\"\nmsgstr \"Importez un fichier .nif pour le calcul du slider\"\n\n#: src/program/OutfitStudio.cpp:6758\nmsgid \"No mesh found in the .nif file that matches currently selected shape!\"\nmsgstr \"\"\n\"Aucun maillage trouvé dans le fichier .nif qui correspond à la forme \"\n\"actuellement sélectionnée!\"\n\n#: src/program/OutfitStudio.cpp:6776\nmsgid \"Import .bsd slider data\"\nmsgstr \"Importez les données du slider .bsd\"\n\n#: src/program/OutfitStudio.cpp:6797\nmsgid \"Import .obj file for slider calculation\"\nmsgstr \"Importez un fichier .obj pour le calcul du slider\"\n\n#: src/program/OutfitStudio.cpp:6804 src/program/OutfitStudio.cpp:7011\nmsgid \"Vertex count of .obj file mesh does not match currently selected shape!\"\nmsgstr \"\"\n\"Le nombre de vertex du maillage du fichier .obj ne correspond pas à la forme \"\n\"actuellement sélectionnée!\"\n\n#: src/program/OutfitStudio.cpp:6818\nmsgid \"Import .osd file\"\nmsgstr \"Importez un fichier .osd\"\n\n#: src/program/OutfitStudio.cpp:6822 src/program/OutfitStudio.cpp:6912\nmsgid \"This will delete all loaded sliders. Are you sure?\"\nmsgstr \"Cela supprimera tous les sliders chargés. Êtes-vous sûr?\"\n\n#: src/program/OutfitStudio.cpp:6822 src/program/OutfitStudio.cpp:6899\nmsgid \"OSD Import\"\nmsgstr \"Importez OSD\"\n\n#: src/program/OutfitStudio.cpp:6832\nmsgid \"Failed to import OSD file!\"\nmsgstr \"Échec de l'importation du fichier OSD!\"\n\n#: src/program/OutfitStudio.cpp:6899 src/program/OutfitStudio.cpp:6991\n#, c-format\nmsgid \"\"\n\"Added morphs for the following shapes:\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Ajout de morphes pour les formes suivantes:\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/OutfitStudio.cpp:6912 src/program/OutfitStudio.cpp:6991\nmsgid \"TRI Import\"\nmsgstr \"TRI Importer\"\n\n#: src/program/OutfitStudio.cpp:7004\nmsgid \"Import .fbx file for slider calculation\"\nmsgstr \"Importez un fichier .fbx pour le calcul du slider\"\n\n#: src/program/OutfitStudio.cpp:7025 src/program/OutfitStudio.cpp:7061\n#: src/program/OutfitStudio.cpp:7094\nmsgid \"There is no slider in edit mode to export data from!\"\nmsgstr \"\"\n\"Il n'y a pas de slider en mode d'édition à partir duquel exporter des \"\n\"données!\"\n\n#: src/program/OutfitStudio.cpp:7030\nmsgid \"Export .nif slider data to directory\"\nmsgstr \"Exporter les données du slider .nif vers le répertoire\"\n\n#: src/program/OutfitStudio.cpp:7041\nmsgid \"Export .nif slider data\"\nmsgstr \"Exporter les données du slider .nif\"\n\n#: src/program/OutfitStudio.cpp:7048\nmsgid \"Failed to export NIF file!\"\nmsgstr \"Échec de l'exportation du fichier NIF!\"\n\n#: src/program/OutfitStudio.cpp:7066\nmsgid \"Export .bsd slider data to directory\"\nmsgstr \"Exporter les données du slider .bsd vers le répertoire\"\n\n#: src/program/OutfitStudio.cpp:7077\nmsgid \"Export .bsd slider data\"\nmsgstr \"Exporter les données du slider .bsd\"\n\n#: src/program/OutfitStudio.cpp:7099 src/program/OutfitStudio.cpp:7166\nmsgid \"Export .obj slider data to directory\"\nmsgstr \"Exporter les données du slider .obj vers le répertoire\"\n\n#: src/program/OutfitStudio.cpp:7110\nmsgid \"Export .obj slider data\"\nmsgstr \"Exporter les données du slider .obj\"\n\n#: src/program/OutfitStudio.cpp:7130\nmsgid \"Export .osd file\"\nmsgstr \"Exporter un fichier .osd\"\n\n#: src/program/OutfitStudio.cpp:7137\nmsgid \"Failed to export OSD file!\"\nmsgstr \"Échec de l'exportation du fichier OSD!\"\n\n#: src/program/OutfitStudio.cpp:7192\nmsgid \"\"\n\"Are you sure you wish to clear the unmasked slider data for the selected \"\n\"shapes?  This action cannot be undone.\"\nmsgstr \"\"\n\"Voulez-vous vraiment effacer les vertices non masqués des formes \"\n\"sélectionnées? Cette action ne peut pas être annulée.\"\n\n#: src/program/OutfitStudio.cpp:7193 src/program/OutfitStudio.cpp:7197\nmsgid \"Confirm data erase\"\nmsgstr \"Confirmer l'effacement des données\"\n\n#: src/program/OutfitStudio.cpp:7196\n#, c-format\nmsgid \"\"\n\"Are you sure you wish to clear the unmasked slider data for the shape '%s'?  \"\n\"This action cannot be undone.\"\nmsgstr \"\"\n\"Voulez-vous vraiment effacer les vertices non masqués des formes '%s'? Cette \"\n\"action ne peut pas être annulée.\"\n\n#: src/program/OutfitStudio.cpp:7250\nmsgid \"Enter a name for the new zap:\"\nmsgstr \"Entrez un nom pour le nouveau zap:\"\n\n#: src/program/OutfitStudio.cpp:7250\nmsgid \"Create New Zap\"\nmsgstr \"Créer Nouveau Zap\"\n\n#: src/program/OutfitStudio.cpp:7300\nmsgid \"There is no slider in edit mode to negate!\"\nmsgstr \"Il n'y a pas de slider en mode édition pour annuler!\"\n\n#: src/program/OutfitStudio.cpp:7317\nmsgid \"There is no slider in edit mode to create a mask from!\"\nmsgstr \"Il n'y a pas de slider en mode édition pour créer un masque!\"\n\n#: src/program/OutfitStudio.cpp:7327\nmsgid \"Are you sure you wish to delete the selected slider(s)?\"\nmsgstr \"Voulez-vous vraiment supprimer le(s) slider(s) sélectionné(s)?\"\n\n#: src/program/OutfitStudio.cpp:7328\nmsgid \"Confirm slider delete\"\nmsgstr \"Confirmer la suppression du slider\"\n\n#: src/program/OutfitStudio.cpp:7379\nmsgid \"There is no slider in edit mode to show properties for!\"\nmsgstr \"Il n'y a pas de slider en mode édition pour afficher les propriétés!\"\n\n#: src/program/OutfitStudio.cpp:7526 src/program/OutfitStudio.cpp:7581\nmsgid \"Conforming: \"\nmsgstr \"Conforme: \"\n\n#: src/program/OutfitStudio.cpp:7543\nmsgid \"Initializing data...\"\nmsgstr \"Initialisation des données...\"\n\n#: src/program/OutfitStudio.cpp:7553\nmsgid \"Shape(s) conformed.\"\nmsgstr \"Le(s) formes se sont conformées.\"\n\n#: src/program/OutfitStudio.cpp:7574\nmsgid \"Conforming all shapes...\"\nmsgstr \"Conforme à toutes les formes...\"\n\n#: src/program/OutfitStudio.cpp:7592\nmsgid \"All shapes conformed.\"\nmsgstr \"Toutes les formes se sont conformées.\"\n\n#: src/program/OutfitStudio.cpp:8288\nmsgid \"Are you sure you wish to delete parts of the selected shapes?\"\nmsgstr \"Voulez-vous vraiment effacer des parties des formes sélectionnées?\"\n\n#: src/program/OutfitStudio.cpp:8288 src/program/OutfitStudio.cpp:8533\nmsgid \"Confirm Delete\"\nmsgstr \"Confirmation de la suppression\"\n\n#: src/program/OutfitStudio.cpp:8329\nmsgid \"Please enter a unique name for the new separated shape.\"\nmsgstr \"Veuillez saisir un nom unique pour la nouvelle forme séparée.\"\n\n#: src/program/OutfitStudio.cpp:8377\nmsgid \"No errors found!\"\nmsgstr \"Aucune erreur trouvée!\"\n\n#: src/program/OutfitStudio.cpp:8383\nmsgid \"Errors:\"\nmsgstr \"Erreur:\"\n\n#: src/program/OutfitStudio.cpp:8385\nmsgid \"Target must be different from source.\"\nmsgstr \"La cible doit être différente de la source.\"\n\n#: src/program/OutfitStudio.cpp:8387\nmsgid \"\"\n\"Partitions do not match. Make sure the amount of partitions and their slots \"\n\"match up.\"\nmsgstr \"\"\n\"Les partitions ne correspondent pas. Assurez-vous que le nombre de \"\n\"partitions et leurs emplacements correspondent.\"\n\n#: src/program/OutfitStudio.cpp:8389\nmsgid \"\"\n\"Segments do not match. Make sure the amount of segments, sub segments and \"\n\"their info as well as the segmentation file match.\"\nmsgstr \"\"\n\"Les segments ne correspondent pas. Assurez-vous que la quantité de segments, \"\n\"de sous-segments et leurs informations ainsi que le fichier de segmentation \"\n\"correspondent.\"\n\n#: src/program/OutfitStudio.cpp:8391\nmsgid \"Resulting shape would have too many vertices.\"\nmsgstr \"La forme résultante aurait trop de vertices.\"\n\n#: src/program/OutfitStudio.cpp:8393\nmsgid \"Resulting shape would have too many triangles.\"\nmsgstr \"La forme résultante aurait trop de triangles.\"\n\n#: src/program/OutfitStudio.cpp:8395\nmsgid \"\"\n\"Shaders do not match. Make sure both shapes either have or don't have a \"\n\"shader and their shader type matches.\"\nmsgstr \"\"\n\"Les shaders ne correspondent pas. Assurez-vous que les deux formes ont ou \"\n\"n'ont pas de shader et que leur type de shader correspond.\"\n\n#: src/program/OutfitStudio.cpp:8397\nmsgid \"\"\n\"Base texture doesn't match. Make sure both shapes have the same base/diffuse \"\n\"texture path.\"\nmsgstr \"\"\n\"La texture de base ne correspond pas. Assurez-vous que les deux formes ont \"\n\"le même chemin de texture de base/diffuse.\"\n\n#: src/program/OutfitStudio.cpp:8399\nmsgid \"\"\n\"Alpha property mismatch. Make sure both shapes either have or don't have an \"\n\"alpha property and their flags + threshold match.\"\nmsgstr \"\"\n\"Mauvaise correspondance des propriétés alpha. Assurez-vous que les deux \"\n\"formes ont ou n'ont pas une propriété alpha et que leurs drapeaux + seuil \"\n\"correspondent.\"\n\n#: src/program/OutfitStudio.cpp:8485\nmsgid \"\"\n\"You can only copy shapes into an outfit, and there is no outfit in the \"\n\"current project. Load one first!\"\nmsgstr \"\"\n\"Vous ne pouvez copier que des formes dans une tenue et il n'y a aucune tenue \"\n\"dans le projet en cours. Chargez-en un en premier!\"\n\n#: src/program/OutfitStudio.cpp:8490\nmsgid \"Please enter a unique name for the duplicated shape.\"\nmsgstr \"Veuillez saisir un nom unique pour la forme dupliquée.\"\n\n#: src/program/OutfitStudio.cpp:8490\nmsgid \"Duplicate Shape\"\nmsgstr \"Forme Dupliquée\"\n\n#: src/program/OutfitStudio.cpp:8533\nmsgid \"\"\n\"Are you sure you wish to delete the selected shapes?  This action cannot be \"\n\"undone.\"\nmsgstr \"\"\n\"Voulez-vous vraiment supprimer des formes sélectionnées? Cette action ne \"\n\"peut pas être annulée.\"\n\n#: src/program/OutfitStudio.cpp:8669\nmsgid \"No bone name was entered!\"\nmsgstr \"Aucun nom d'os n'a été entré!\"\n\n#: src/program/OutfitStudio.cpp:8677\n#, c-format\nmsgid \"Bone '%s' already exists in the project!\"\nmsgstr \"L'os '%s' existe déjà dans le projet!\"\n\n#: src/program/OutfitStudio.cpp:8804\nmsgid \"\"\n\"The following shapes have unweighted vertices, which can cause issues. The \"\n\"affected vertices have been put under a mask. Do you want to save anyway?\"\nmsgstr \"\"\n\"Les formes suivantes ont des vertices non pondérés, ce qui peut causer des \"\n\"problèmes. Les vertices concernés ont été placés sous un masque. Voulez-vous \"\n\"quand même enregistrer?\"\n\n#: src/program/OutfitStudio.cpp:8804\nmsgid \"Unweighted Vertices\"\nmsgstr \"Vertices non Pondérés\"\n\n#: src/program/OutfitStudio.cpp:8977 src/program/OutfitStudio.cpp:9051\n#: src/program/OutfitStudio.cpp:9143\nmsgid \"There is no reference shape!\"\nmsgstr \"Il n'y a pas de forme de référence!\"\n\n#: src/program/OutfitStudio.cpp:9027 src/program/OutfitStudio.cpp:9118\nmsgid \"\"\n\"Sorry, you can't copy weights from the reference shape to itself. Skipping \"\n\"this shape.\"\nmsgstr \"\"\n\"Désolé, vous ne pouvez pas copier les poids de la forme de référence sur \"\n\"elle-même. Sauter cette forme.\"\n\n#: src/program/OutfitStudio.cpp:9027 src/program/OutfitStudio.cpp:9118\nmsgid \"Can't copy weights\"\nmsgstr \"Ne pouvez pas copier les poids\"\n\n#: src/program/OutfitStudio.cpp:9089\nmsgid \"Copying selected bone weights...\"\nmsgstr \"Copie des poids des os sélectionnés...\"\n\n#: src/program/OutfitStudio.cpp:9148\nmsgid \"Sorry, you can't copy weights from the reference shape to itself.\"\nmsgstr \"\"\n\"Désolé, vous ne pouvez pas copier les poids de la forme de référence sur \"\n\"elle-même.\"\n\n#: src/program/OutfitStudio.cpp:9155\nmsgid \"The vertex count of the reference and chosen shape is not the same!\"\nmsgstr \"\"\n\"Le nombre de vertex de la forme de référence et de la forme choisie n'est \"\n\"pas le même!\"\n\n#: src/program/OutfitStudio.cpp:9254\n#, c-format\nmsgid \"%d unreferenced nodes were deleted.\"\nmsgstr \"%d nœuds non référencés ont été supprimés.\"\n\n#: src/program/OutfitStudio.cpp:9497\nmsgid \"Please enter a new unique name for the mask.\"\nmsgstr \"Veuillez saisir un nouveau nom unique pour la masque.\"\n\n#: src/program/OutfitStudio.cpp:9497\nmsgid \"New Mask\"\nmsgstr \"Nouveaux Masque\"\n\n#: src/program/OutfitStudio.cpp:9665\nmsgid \"Reset all bone poses?\"\nmsgstr \"Réinitialiser toutes les poses d'os?\"\n\n#: src/program/OutfitStudio.cpp:9665\nmsgid \"Reset Pose\"\nmsgstr \"Réinitialiser la Pose\"\n\n#: src/program/OutfitStudio.cpp:9692\nmsgid \"Permanently apply the pose to the mesh?\"\nmsgstr \"Appliquer définitivement la pose au maillage?\"\n\n#: src/program/OutfitStudio.cpp:9692\nmsgid \"Apply Pose to Mesh\"\nmsgstr \"Appliquer la Pose au Maillage\"\n\n#: src/program/OutfitStudio.cpp:10646\nmsgid \"The vertex picked has more than three connections.\"\nmsgstr \"Le vertex choisi a plus de trois connexions.\"\n\n#: src/program/OutfitStudio.cpp:10700\nmsgid \"The edge picked is on the surface boundary.  Pick an interior edge.\"\nmsgstr \"\"\n\"Le bord sélectionné se trouve sur la limite de la surface. Choisissez un \"\n\"bord intérieur.\"\n\n#: src/program/OutfitStudio.cpp:10734\nmsgid \"The shape has reached the vertex count limit.\"\nmsgstr \"La forme a atteint la limite du nombre de vertex.\"\n\n#: src/program/OutfitStudio.cpp:10739\nmsgid \"The shape has reached the triangle count limit.\"\nmsgstr \"La forme a atteint la limite du nombre de triangles.\"\n\n#: src/program/OutfitStudio.cpp:10761\nmsgid \"\"\n\"The edge picked has multiple triangles of the same orientation.  Correct the \"\n\"orientations before splitting.\"\nmsgstr \"\"\n\"Le bord sélectionné a plusieurs triangles de la même orientation. Corrigez \"\n\"les orientations avant de fractionner.\"\n\n#: src/program/OutfitStudio.cpp:11902 src/program/OutfitStudio.cpp:11903\nmsgid \"Loading slider file...\"\nmsgstr \"Chargement du fichier de slider...\"\n\n#: src/program/PreviewWindow.cpp:39\nmsgid \"Show the Normal Map Generator dialog.\"\nmsgstr \"Affichez la boîte de dialogue Normal Map Generator.\"\n\n#: src/program/PreviewWindow.cpp:66\nmsgid \"Preview failed: OpenGL context is not OK.\"\nmsgstr \"L'aperçu a échoué: OpenGL le contexte n'est pas OK.\"\n\n#: src/program/ShapeProperties.cpp:100\nmsgid \"Material\"\nmsgstr \"Matériel\"\n\n#: src/program/ShapeProperties.cpp:260\nmsgid \"Choose material file\"\nmsgstr \"Choisissez le fichier matériel\"\n\n#: src/program/ShapeProperties.cpp:497\nmsgid \"Please choose a shape to copy from\"\nmsgstr \"Veuillez choisir une forme à copier\"\n\n#: src/program/ShapeProperties.cpp:497\nmsgid \"Choose shape\"\nmsgstr \"Choisissez du forme\"\n"
  },
  {
    "path": "lang/hi/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/hi/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/hu/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/hu/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/id/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/id/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/it/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/it/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ja/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ja/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ko/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ko/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/lt/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/lt/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/lv/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/lv/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ms/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ms/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/nb/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/nb/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ne/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ne/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/nl/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/nl/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/pl/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/pl/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/pt/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/pt/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ro/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ro/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ru/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ru/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/sk/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/sk/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/sl/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/sl/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/sq/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/sq/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/sv/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/sv/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/ta/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/ta/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/tr/BodySlide.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: BodySlide\\n\"\n\"POT-Creation-Date: \\n\"\n\"PO-Revision-Date: \\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: \\n\"\n\"Language: tr\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n\"X-Generator: Poedit 3.2\\n\"\n\"X-Poedit-KeywordsList: _\\n\"\n\"X-Poedit-Basepath: ..\\n\"\n\"X-Poedit-SearchPath-0: src\\n\"\n\"X-Poedit-SearchPath-1: lang/xrctext.cpp\\n\"\n\n#: res/xrc/About.xrc:5 res/xrc/BodySlide.xrc:429\nmsgid \"About\"\nmsgstr \"Hakkında\"\n\n#: res/xrc/About.xrc:145 res/xrc/GroupManager.xrc:189\nmsgid \"Close\"\nmsgstr \"Kapat\"\n\n#: res/xrc/Actions.xrc:6\nmsgid \"Apply a vertex position\"\nmsgstr \"Tepe Noktası Uygula\"\n\n#: res/xrc/Actions.xrc:15\nmsgid \"This permanently moves a single vertex straight to the given location.\"\nmsgstr \"\"\n\"Bu ayar, tek bir tepe noktasını kalıcı olarak doğrudan verilen konuma taşır.\"\n\n#: res/xrc/Actions.xrc:93 res/xrc/Actions.xrc:302 res/xrc/Actions.xrc:499\n#: res/xrc/Actions.xrc:694 res/xrc/Actions.xrc:741 res/xrc/Actions.xrc:891\n#: res/xrc/Actions.xrc:1170 res/xrc/Actions.xrc:1271 res/xrc/BatchBuild.xrc:112\n#: res/xrc/EditUV.xrc:32 res/xrc/EditUV.xrc:244 res/xrc/EditUV.xrc:319\n#: res/xrc/EditUV.xrc:440 res/xrc/ImportDialog.xrc:174 res/xrc/Project.xrc:753\n#: res/xrc/Project.xrc:930 res/xrc/Settings.xrc:438\n#: res/xrc/ShapeProperties.xrc:810 res/xrc/Skeleton.xrc:36\n#: res/xrc/Skeleton.xrc:232 res/xrc/Slider.xrc:64 res/xrc/Slider.xrc:238\n#: res/xrc/SliderDataImport.xrc:90\nmsgid \"&OK\"\nmsgstr \"&TAMAM\"\n\n#: res/xrc/Actions.xrc:100 res/xrc/Actions.xrc:309 res/xrc/Actions.xrc:506\n#: res/xrc/Actions.xrc:701 res/xrc/Actions.xrc:748 res/xrc/Actions.xrc:898\n#: res/xrc/Actions.xrc:1177 res/xrc/Actions.xrc:1278 res/xrc/Actions.xrc:1609\n#: res/xrc/BatchBuild.xrc:57 res/xrc/BatchBuild.xrc:119 res/xrc/EditUV.xrc:39\n#: res/xrc/EditUV.xrc:251 res/xrc/EditUV.xrc:326 res/xrc/EditUV.xrc:447\n#: res/xrc/ImportDialog.xrc:181 res/xrc/Project.xrc:550 res/xrc/Project.xrc:760\n#: res/xrc/Project.xrc:937 res/xrc/SavePreset.xrc:85 res/xrc/Settings.xrc:445\n#: res/xrc/Setup.xrc:273 res/xrc/ShapeProperties.xrc:817\n#: res/xrc/Skeleton.xrc:43 res/xrc/Skeleton.xrc:239 res/xrc/Slider.xrc:71\n#: res/xrc/Slider.xrc:246 res/xrc/SliderDataImport.xrc:97\nmsgid \"&Cancel\"\nmsgstr \"&İptal\"\n\n#: res/xrc/Actions.xrc:110\nmsgid \"Move Shape\"\nmsgstr \"Kalıbı Taşı\"\n\n#: res/xrc/Actions.xrc:254\nmsgid \"Mirror Axis\"\nmsgstr \"Yansıtıcı Ekseni\"\n\n#: res/xrc/Actions.xrc:320\nmsgid \"Scale Shape\"\nmsgstr \"Kalıp Ölçeği\"\n\n#: res/xrc/Actions.xrc:329\nmsgid \"\"\n\"Scaling will adjust the size of a mesh. This permanently affects vertices.\"\nmsgstr \"\"\n\"Ölçekleme bir kafesin boyutunu ayarlayacaktır. Bu, sürekli olarak köşe \"\n\"noktalarını etkiler.\"\n\n#: res/xrc/Actions.xrc:461 res/xrc/Actions.xrc:667\n#: res/xrc/ShapeProperties.xrc:690 res/xrc/Skeleton.xrc:133\nmsgid \"Origin\"\nmsgstr \"Baslangıç\"\n\n#: res/xrc/Actions.xrc:472 res/xrc/Actions.xrc:678\nmsgid \"Zero (0, 0, 0)\"\nmsgstr \"Sıfır\"\n\n#: res/xrc/Actions.xrc:473 res/xrc/Actions.xrc:679\nmsgid \"Center of selected shapes(s)\"\nmsgstr \"Seçili Kalıp(ların) Merkezi\"\n\n#: res/xrc/Actions.xrc:484\nmsgid \"Uniform (XYZ)\"\nmsgstr \"Giydirme (XYZ)\"\n\n#: res/xrc/Actions.xrc:517\nmsgid \"Rotate Shape\"\nmsgstr \"Kalıbı Döndür\"\n\n#: res/xrc/Actions.xrc:711\nmsgid \"Set Shape Textures\"\nmsgstr \"Kalıp Dokusunu Ayarla\"\n\n#: res/xrc/Actions.xrc:758 res/xrc/ConvertBodyReference.xrc:183\n#: res/xrc/OutfitStudio.xrc:1946 res/xrc/OutfitStudio.xrc:2404\nmsgid \"Copy Bone Weights\"\nmsgstr \"Beden Ağırlıklarını Kopyala\"\n\n#: res/xrc/Actions.xrc:767\nmsgid \"\"\n\"Each vertex of the reference will copy its weights to the nearest collection \"\n\"of vertices within the given radius. Bear in mind that some geometry will \"\n\"always require manual tweaking to become weighted and work well. Often, the \"\n\"default values are sufficient.\"\nmsgstr \"\"\n\"Örneğin her köşesi, ağırlıkları verilen yarıçaptaki en yakın tepe noktası \"\n\"koleksiyonuna kopyalanır. Bazı geometrilerin, baskın hale gelmesi ve daha \"\n\"iyi çalışması için her zaman el ile  ayarlamayı gerektireceğini unutma. Çoğu \"\n\"zaman, varsayılan değerler yeterlidir.\"\n\n#: res/xrc/Actions.xrc:787 res/xrc/Actions.xrc:937\nmsgid \"Search Radius\"\nmsgstr \"Yarıçap Taraması\"\n\n#: res/xrc/Actions.xrc:816 res/xrc/Actions.xrc:966\nmsgid \"Max Vertex Targets\"\nmsgstr \"Max Köşe Hedeflemesi\"\n\n#: res/xrc/Actions.xrc:847 res/xrc/Actions.xrc:995\nmsgid \"No Target Limit\"\nmsgstr \"Hedef Limiti Yok\"\n\n#: res/xrc/Actions.xrc:856\nmsgid \"\"\n\"The skin coordinate system doesn't match the reference shape's. Do you want \"\n\"to copy the transforms?\"\nmsgstr \"\"\n\"Dış görünüm koordinatı, referans şekliyle eşleşmiyor. Dönüşümleri kopyalamak \"\n\"istiyor musun?\"\n\n#: res/xrc/Actions.xrc:866\nmsgid \"Copy skin transform from reference\"\nmsgstr \"Cilt dönüşümünü referanstan kopyala\"\n\n#: res/xrc/Actions.xrc:876 res/xrc/ShapeProperties.xrc:785\nmsgid \"Recalculate geometry's coordinates so it doesn't move\"\nmsgstr \"Hareket etmemesi için geometrinin koordinatlarını yeniden hesapla\"\n\n#: res/xrc/Actions.xrc:877 res/xrc/ShapeProperties.xrc:786\nmsgid \"\"\n\"Transform geometry so its position in global coordinates does not change.\"\nmsgstr \"\"\n\"Geometriyi, küresel koordinat konumunu değiştirmeyecek şekilde dönüştür.\"\n\n#: res/xrc/Actions.xrc:908\nmsgid \"Conforming...\"\nmsgstr \"Uyum sağlanıyor...\"\n\n#: res/xrc/Actions.xrc:917\nmsgid \"\"\n\"Each vertex of the reference will copy its slider data to the nearest \"\n\"collection of vertices within the given radius. Bear in mind that some \"\n\"geometry will always require manual tweaking to become conformed and work \"\n\"well. Often, the default values are sufficient.\"\nmsgstr \"\"\n\"Örneğin her köşesi, ağırlıkları verilen yarıçap içindeki en yakın köşe \"\n\"noktasına kopyalanır. Bazı geometrilerin, baskın hale gelmesi ve daha iyi \"\n\"çalışması için her zaman el ile  ayarlamayı gerektireceğini unutma. Çoğu \"\n\"zaman, varsayılan değerler yeterlidir.\"\n\n#: res/xrc/Actions.xrc:1018\nmsgid \"No Squeeze\"\nmsgstr \"Sıkıstırma Yok\"\n\n#: res/xrc/Actions.xrc:1041\nmsgid \"Solid Mode\"\nmsgstr \"Koyu Mod\"\n\n#: res/xrc/Actions.xrc:1064\nmsgid \"Axis\"\nmsgstr \"Eksen\"\n\n#: res/xrc/Actions.xrc:1114 res/xrc/BodySlide.xrc:97\n#: res/xrc/NormalsGenDlg.xrc:191\nmsgid \"Preset\"\nmsgstr \"Hazır Ayar\"\n\n#: res/xrc/Actions.xrc:1130\nmsgid \"Default\"\nmsgstr \"Varsayılan\"\n\n#: res/xrc/Actions.xrc:1139\nmsgid \"Even Movement\"\nmsgstr \"Düz Hareket\"\n\n#: res/xrc/Actions.xrc:1148\nmsgid \"Solid Object\"\nmsgstr \"Katı Nesne\"\n\n#: res/xrc/Actions.xrc:1187\nmsgid \"Merge Geometry\"\nmsgstr \"Geometriyi Birleştir\"\n\n#: res/xrc/Actions.xrc:1196\nmsgid \"\"\n\"This function copies vertices and triangles from one shape to another.  \"\n\"Partitions/segments of source and target shapes must match.  It is the \"\n\"user's responsibility to check that all other shape and shader properties \"\n\"are compatible, or merging will likely have side effects.\"\nmsgstr \"\"\n\"Bu ayar, köşeleri ve üçgenleri bir şekilden diğerine kopyalar. Kaynak ve \"\n\"hedef şekillerin bölümleri/segmentleri eşleşmelidir. Diğer tüm şekil ve \"\n\"gölgelendirici özelliklerinin uyumlu olup olmadığını kontrol etmek \"\n\"kullanıcının sorumluluğundadır, aksi takdirde birleştirmenin yan etkileri \"\n\"olabilir.\"\n\n#: res/xrc/Actions.xrc:1211\nmsgid \"Source\"\nmsgstr \"Kaynak\"\n\n#: res/xrc/Actions.xrc:1229\nmsgid \"Target\"\nmsgstr \"Hedef\"\n\n#: res/xrc/Actions.xrc:1258\nmsgid \"Delete source shape\"\nmsgstr \"Kaynak Kalıbını Sil\"\n\n#: res/xrc/Actions.xrc:1288\nmsgid \"Mask symmetric vertices\"\nmsgstr \"Simetrik köşeleri maskele\"\n\n#: res/xrc/Actions.xrc:1297\nmsgid \"Masks all vertices that do not have any of the selected asymmetries.\"\nmsgstr \"\"\n\"Seçilen asimetrilerden herhangi birine sahip olmayan tüm köşeleri maskeler.\"\n\n#: res/xrc/Actions.xrc:1323\nmsgid \"Vertices currently unmasked:\"\nmsgstr \"Şu anda maskelenmemiş tepe noktaları:\"\n\n#: res/xrc/Actions.xrc:1351\nmsgid \"Unmatched Vertices:\"\nmsgstr \"Benzersiz Tepe Noktaları:\"\n\n#: res/xrc/Actions.xrc:1373\nmsgid \"Vertex Data Asymmetries\"\nmsgstr \"Tepe Noktası Veri Asimetrisi\"\n\n#: res/xrc/Actions.xrc:1406 res/xrc/OutfitStudio.xrc:793\n#: res/xrc/OutfitStudio.xrc:1057 res/xrc/ShapeProperties.xrc:84\n#: res/xrc/ShapeProperties.xrc:599\nmsgid \"Type\"\nmsgstr \"Tip\"\n\n#: res/xrc/Actions.xrc:1415\nmsgid \"Average\"\nmsgstr \"Ortalama\"\n\n#: res/xrc/Actions.xrc:1424\nmsgid \"Count\"\nmsgstr \"Hesaplama\"\n\n#: res/xrc/Actions.xrc:1442\nmsgid \"Position\"\nmsgstr \"Konum\"\n\n#: res/xrc/Actions.xrc:1510 res/xrc/Project.xrc:731\nmsgid \"Sliders\"\nmsgstr \"Kaydırıcılar\"\n\n#: res/xrc/Actions.xrc:1557 res/xrc/OutfitStudio.xrc:387\n#: res/xrc/OutfitStudio.xrc:2452 res/xrc/OutfitStudio.xrc:2496\nmsgid \"Bones\"\nmsgstr \"İskeletler\"\n\n#: res/xrc/Actions.xrc:1576\nmsgid \"Vertices that will still be unmasked:\"\nmsgstr \"Hâlâ maskelenmemiş köşeler:\"\n\n#: res/xrc/Actions.xrc:1602\nmsgid \"&Mask\"\nmsgstr \"&Maske\"\n\n#: res/xrc/BatchBuild.xrc:6\nmsgid \"Batch Build\"\nmsgstr \"Toplu Yapılandırma\"\n\n#: res/xrc/BatchBuild.xrc:21\nmsgid \"\"\n\"Select the slider sets for the batch build process. Use the group and outfit \"\n\"filters to show the outfits you want!\"\nmsgstr \"\"\n\"Toplu yapılandırma işlemi için kaydırıcı kümelerini seç. İstediğin \"\n\"kıyafetleri göstermek için grup ve kıyafet filtrelerini kullan!\"\n\n#: res/xrc/BatchBuild.xrc:50\nmsgid \"&Build\"\nmsgstr \"&Beden\"\n\n#: res/xrc/BatchBuild.xrc:67 src/program/BodySlideApp.cpp:2292\nmsgid \"Choose output set\"\nmsgstr \"Çıkış setini seç\"\n\n#: res/xrc/BatchBuild.xrc:78\nmsgid \"\"\n\"The following sets will override the same files.\\n\"\n\"Please decide which one to use and select it in the list below.\"\nmsgstr \"\"\n\"Aşağıdaki bazı ayarlar aynı dosyaları geçersiz kılabilir.\\n\"\n\"Lütfen hangisini kullanacağına karar ver ve listeden seçimini yap.\"\n\n#: res/xrc/BatchBuild.xrc:88\nmsgid \"Type and hit enter to choose output...\"\nmsgstr \"Çıkış setini seç ve Enter'a bas...\"\n\n#: res/xrc/BodySlide.xrc:7\nmsgid \"BodySlide\"\nmsgstr \"Beden Yapılandırması\"\n\n#: res/xrc/BodySlide.xrc:28\nmsgid \"Outfit/Body\"\nmsgstr \"Kıyafet/Beden\"\n\n#: res/xrc/BodySlide.xrc:44\nmsgid \"Select an outfit to modify\"\nmsgstr \"Ayarlanacak bir kıyafeti seç\"\n\n#: res/xrc/BodySlide.xrc:58\nmsgid \"Deletes a project from its project file\"\nmsgstr \"Proje dosyasından bir projeyi siler\"\n\n#: res/xrc/BodySlide.xrc:74\nmsgid \"Opens the current project in Outfit Studio\"\nmsgstr \"Mevcut projeyi Outfit Studio programında açar\"\n\n#: res/xrc/BodySlide.xrc:113\nmsgid \"Choose from a list of slider settings presets\"\nmsgstr \"Listeden önceden hazırlanmış bir dosyayı seç\"\n\n#: res/xrc/BodySlide.xrc:127\nmsgid \"Deletes a preset from its preset file\"\nmsgstr \"Hazır ayarlı bir dosyadan bir hazır ayarı siler\"\n\n#: res/xrc/BodySlide.xrc:142\nmsgid \"Saves the new slider values to the currently selected preset\"\nmsgstr \"Yeni dosya değerlerini seçili olan hazır ayar dosyasına kaydeder\"\n\n#: res/xrc/BodySlide.xrc:143 res/xrc/GroupManager.xrc:44\n#: res/xrc/OutfitStudio.xrc:1257 res/xrc/OutfitStudio.xrc:1318\nmsgid \"Save\"\nmsgstr \"Kaydet\"\n\n#: res/xrc/BodySlide.xrc:153\nmsgid \"Save the current slider settings as a new preset\"\nmsgstr \"Mevcut ayarlarını yeni bir hazır ayar olarak kaydet\"\n\n#: res/xrc/BodySlide.xrc:154 res/xrc/GroupManager.xrc:53\n#: res/xrc/OutfitStudio.xrc:1266 res/xrc/OutfitStudio.xrc:1327\nmsgid \"Save As...\"\nmsgstr \"Farklı Kaydet...\"\n\n#: res/xrc/BodySlide.xrc:165\nmsgid \"\"\n\"Opens the group manager where you can edit existing or create new groups\"\nmsgstr \"\"\n\"Mevcut hazır ayarlarını veya yeni gruplar oluşturabileceğin grup \"\n\"yöneticisini açar\"\n\n#: res/xrc/BodySlide.xrc:166 res/xrc/GroupManager.xrc:7\n#: res/xrc/Project.xrc:1059\nmsgid \"Group Manager\"\nmsgstr \"Gurup Yöneticisi\"\n\n#: res/xrc/BodySlide.xrc:190\nmsgid \"Single Weight\"\nmsgstr \"Tekil Ağırlık\"\n\n#: res/xrc/BodySlide.xrc:217\nmsgid \"Low Weight\"\nmsgstr \"Düsük Ağırlık\"\n\n#: res/xrc/BodySlide.xrc:234\nmsgid \"High Weight\"\nmsgstr \"Yüksek Ağırlık\"\n\n#: res/xrc/BodySlide.xrc:275\nmsgid \"Copy the low weight slider values to the high weight section.\"\nmsgstr \"Düşük ağırlık değerlerini yüksek ağırlık bölümüne kopyalar.\"\n\n#: res/xrc/BodySlide.xrc:292\nmsgid \"Default outfit choice in Batch Build\"\nmsgstr \"Toplu Oluşturma'da Varsayılan Kıyafet Seçimi\"\n\n#: res/xrc/BodySlide.xrc:303\nmsgid \"Output Path (which the game would use for this outfit)\"\nmsgstr \"Çıkış Veri Yolu (oyunda bu kıyafet kullanılacak)\"\n\n#: res/xrc/BodySlide.xrc:315\nmsgid \"(right-click to view alternatives)\"\nmsgstr \"(alternatifleri görmek için sağ tuşa tıkla)\"\n\n#: res/xrc/BodySlide.xrc:335\nmsgid \"\"\n\"Build multiple outfits using the currently active slider values.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to custom directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"Mevcut değerleri kullanarak birden fazla kıyafeti oluştur.\\n\"\n\"\\n\"\n\"CTRL Basılı Tut = Özel dizin olarak kaydeder\\n\"\n\"ALT Basılı Tut = Kıyafet dizinini siler\"\n\n#: res/xrc/BodySlide.xrc:336\nmsgid \"Batch Build...\"\nmsgstr \"Toplu Yapılandırma...\"\n\n#: res/xrc/BodySlide.xrc:351\nmsgid \"Build Morphs\"\nmsgstr \"Beden Oluştur\"\n\n#: res/xrc/BodySlide.xrc:352\nmsgid \"\"\n\"Builds a morphs (.tri) file alongside the meshes for accessing the sliders \"\n\"in-game. Requires other mods to make use of the morph data.\"\nmsgstr \"\"\n\"Oyundaki beden yapılarına erişmek için oyun-içi dosyalarının yanında bir \"\n\"morphs yani (.tri) dosyası oluşturur. Morph verisini kullanmak için başka \"\n\"modlarda gereklidir.\"\n\n#: res/xrc/BodySlide.xrc:362\nmsgid \"Force Body Normals\"\nmsgstr \"Normal Bedensel Değerler\"\n\n#: res/xrc/BodySlide.xrc:363\nmsgid \"\"\n\"Adds normal and tangent data to the body meshes (including bodies within \"\n\"outfits) for Skyrim. Use this only if you have a tangent space body mod.\"\nmsgstr \"\"\n\"Skyrim için gövde ağlarına (kıyafetli bedenler dahil) normal ve sonradan \"\n\"eklenen verileri ekler. Bunu yalnızca beden değiştirme modunuz varsa \"\n\"kullanın.\"\n\n#: res/xrc/BodySlide.xrc:379\nmsgid \"Show a preview window for this outfit.\"\nmsgstr \"Bu kıyafet için bir önizleme penceresi açılır.\"\n\n#: res/xrc/BodySlide.xrc:380 res/xrc/NormalsGenDlg.xrc:166\n#: src/program/PreviewWindow.cpp:27\nmsgid \"Preview\"\nmsgstr \"Ön İzleme\"\n\n#: res/xrc/BodySlide.xrc:398\nmsgid \"\"\n\"Creates the currently selected outfit/body.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to working directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"Şuanda seçili olan kıyafet/beden.\\n\"\n\"\\n\"\n\"CTRL Basılı Tut = Özel dizin olarak kaydeder\\n\"\n\"ALT Basılı Tut = Bedeni ve Kıyafeti siler\"\n\n#: res/xrc/BodySlide.xrc:399\nmsgid \"Build\"\nmsgstr \"Olustur\"\n\n#: res/xrc/BodySlide.xrc:411\nmsgid \"Copy the high weight slider values to the low weight section.\"\nmsgstr \"Yüksek ağırlık değerlerini düşük ağırlık bölümüne kopyalar.\"\n\n#: res/xrc/BodySlide.xrc:438 res/xrc/OutfitStudio.xrc:1755\nmsgid \"Open settings dialog.\"\nmsgstr \"Ayarlar menüsünü aç.\"\n\n#: res/xrc/BodySlide.xrc:439 res/xrc/OutfitStudio.xrc:1754\n#: res/xrc/Settings.xrc:5\nmsgid \"Settings\"\nmsgstr \"Ayarlar\"\n\n#: res/xrc/BodySlide.xrc:448\nmsgid \"\"\n\"Open Outfit Studio, a full-featured tool for creating and converting outfits.\"\nmsgstr \"\"\n\"Başlatılan Outfit Studio (Kıyafet Stüdyosu), kıyafetler oluşturmak ve \"\n\"dönüştürmek için tam özellikli bir araçtır.\"\n\n#: res/xrc/BodySlide.xrc:449 res/xrc/OutfitStudio.xrc:7\nmsgid \"Outfit Studio\"\nmsgstr \"Kıyafet Dünyası\"\n\n#: res/xrc/BodySlide.xrc:459 res/xrc/BodySlide.xrc:470\nmsgid \"Filter Options\"\nmsgstr \"Filtre Ayarları\"\n\n#: res/xrc/BodySlide.xrc:461\nmsgid \"Choose groups...\"\nmsgstr \"Gurup seç...\"\n\n#: res/xrc/BodySlide.xrc:462\nmsgid \"Choose groups to display in the Outfit menu\"\nmsgstr \"Kıyafet menüsünde görüntülenecek gurupları seçebilirsin\"\n\n#: res/xrc/BodySlide.xrc:465\nmsgid \"Refresh Groups\"\nmsgstr \"Grupları Yenile\"\n\n#: res/xrc/BodySlide.xrc:466\nmsgid \"Refresh group information\"\nmsgstr \"Gurup bilgilerini yenile\"\n\n#: res/xrc/BodySlide.xrc:472\nmsgid \"Save Outfit list as group...\"\nmsgstr \"Kıyafet Listesini gurup olarak kaydet...\"\n\n#: res/xrc/BodySlide.xrc:473\nmsgid \"Save the current filtered outfit list as a group\"\nmsgstr \"Filtrelenen mevcut kıyafet listesini bir grup olarak kaydet\"\n\n#: res/xrc/BodySlide.xrc:476\nmsgid \"Refresh Outfits\"\nmsgstr \"Kıyafetleri Yenile\"\n\n#: res/xrc/BodySlide.xrc:477\nmsgid \"Reloads outfit list\"\nmsgstr \"Yeniden yüklenen kıyafet listesi\"\n\n#: res/xrc/BodySlide.xrc:480\nmsgid \"Regular Expressions\"\nmsgstr \"Düzenli İfadeler\"\n\n#: res/xrc/BodySlide.xrc:481\nmsgid \"Allow the use of regular expressions (regex) for filtering.\"\nmsgstr \"Filtreleme için ifadelerin (Normal) kullanımına izin ver.\"\n\n#: res/xrc/BodySlide.xrc:487 res/xrc/Project.xrc:1076\n#: res/xrc/SliderDataImport.xrc:106\nmsgid \"Select None\"\nmsgstr \"Hiçbirini Seçme\"\n\n#: res/xrc/BodySlide.xrc:490 res/xrc/EditUV.xrc:110 res/xrc/Project.xrc:1079\n#: res/xrc/SliderDataImport.xrc:109\nmsgid \"Select All\"\nmsgstr \"Tümünü Seç\"\n\n#: res/xrc/BodySlide.xrc:493 res/xrc/EditUV.xrc:114 res/xrc/Project.xrc:1082\n#: res/xrc/SliderDataImport.xrc:112\nmsgid \"Invert Selection\"\nmsgstr \"Tersine Seçim Yap\"\n\n#: res/xrc/ConvertBodyReference.xrc:6\nmsgid \"Convert / Replace Body Reference\"\nmsgstr \"Örnek Bedeni Değiştir / Dönüştür\"\n\n#: res/xrc/ConvertBodyReference.xrc:16 res/xrc/ConvertBodyReference.xrc:219\nmsgid \"This wizard aids in the conversion to another body/reference..\"\nmsgstr \"\"\n\"Bu sihirbaz, başka bir gövdeye/örnek bedene dönüştürmeye yardımcı olur..\"\n\n#: res/xrc/ConvertBodyReference.xrc:25\nmsgid \"Reference Bodies\"\nmsgstr \"Örnek Beden\"\n\n#: res/xrc/ConvertBodyReference.xrc:36\nmsgid \"Select a conversion reference (or 'None' to skip converting):\"\nmsgstr \"Bir örnek beden seçin (ya da 'Yok' seçeneğiyle dönüşümü atlayın):\"\n\n#: res/xrc/ConvertBodyReference.xrc:58\nmsgid \"Conversion Body Reference\"\nmsgstr \"Örnek Beden Dönüşümü\"\n\n#: res/xrc/ConvertBodyReference.xrc:78\nmsgid \"Select a body reference to convert to:\"\nmsgstr \"Dönüştürmek için Örnek Gövde'yi seç:\"\n\n#: res/xrc/ConvertBodyReference.xrc:100\nmsgid \"New Body Reference\"\nmsgstr \"Yeni Örnek Beden\"\n\n#: res/xrc/ConvertBodyReference.xrc:130 res/xrc/NormalsGenDlg.xrc:108\n#: res/xrc/Slider.xrc:161\nmsgid \"Options\"\nmsgstr \"Ayarlar\"\n\n#: res/xrc/ConvertBodyReference.xrc:136 res/xrc/SliderDataImport.xrc:77\nmsgid \"Merge Sliders\"\nmsgstr \"Kaydırıcıları Birleştir\"\n\n#: res/xrc/ConvertBodyReference.xrc:145\nmsgid \"Merge Zaps\"\nmsgstr \"Zap'ları Birleştir\"\n\n#: res/xrc/ConvertBodyReference.xrc:165\nmsgid \"Conform Sliders\"\nmsgstr \"Uyumlu Kaydırıcılar\"\n\n#: res/xrc/ConvertBodyReference.xrc:174\nmsgid \"Skip conform popup (use default settings)\"\nmsgstr \"Açılan Uyumlu penceresini atla (varsayılan ayarları kullan)\"\n\n#: res/xrc/ConvertBodyReference.xrc:192\nmsgid \"Skip bone weights popup (use default settings)\"\nmsgstr \"Kemik ağırlıkları penceresini atla (varsayılan ayarları kullan)\"\n\n#: res/xrc/ConvertBodyReference.xrc:203\nmsgid \"Delete reference after completion\"\nmsgstr \"Tamamlandıktan sonra örnek referansı sil\"\n\n#: res/xrc/ConvertBodyReference.xrc:228\nmsgid \"Rename Project (optional)\"\nmsgstr \"Projeyi Yeniden Adlandır (isteğe bağlı)\"\n\n#: res/xrc/ConvertBodyReference.xrc:239\nmsgid \"Specify text to be removed from the project name (comma-delimited):\"\nmsgstr \"Proje adından kaldırılacak metni belirt (virgülle ayrılan):\"\n\n#: res/xrc/ConvertBodyReference.xrc:260\nmsgid \"Remove from project name\"\nmsgstr \"Proje adını sil\"\n\n#: res/xrc/ConvertBodyReference.xrc:277\nmsgid \"Specify any text to be prepended to project name:\"\nmsgstr \"Proje adının başına eklenecek metni belirt:\"\n\n#: res/xrc/ConvertBodyReference.xrc:298\nmsgid \"Prepend to project name\"\nmsgstr \"Proje adının önüne ekle\"\n\n#: res/xrc/ConvertBodyReference.xrc:315\nmsgid \"NOTE: Game file output path is unaffected by this\"\nmsgstr \"NOT: Oyun dosyasının çıkış yolu bundan etkilenmez\"\n\n#: res/xrc/ConvertBodyReference.xrc:326\nmsgid \"Extras (optional)\"\nmsgstr \"Ekstra Ayarlar (isteğe bağlı)\"\n\n#: res/xrc/ConvertBodyReference.xrc:337\nmsgid \"Remove the following shapes before conversion (comma-delimited):\"\nmsgstr \"Dönüştürmeden önce belirtilen şekilleri kaldır (virgülle ayrılan):\"\n\n#: res/xrc/ConvertBodyReference.xrc:359\nmsgid \"Shapes to delete\"\nmsgstr \"Kalıpları Sil\"\n\n#: res/xrc/ConvertBodyReference.xrc:375\nmsgid \"Add the following bones after conversion (comma-delimited):\"\nmsgstr \"Dönüştürmeden sonra belirtilen iskeletleri ekle (virgülle ayrılan):\"\n\n#: res/xrc/ConvertBodyReference.xrc:396\nmsgid \"Bones to add\"\nmsgstr \"Yüklenen İskeletler\"\n\n#: res/xrc/EditUV.xrc:5\nmsgid \"Edit UV\"\nmsgstr \"UV Düzenleme\"\n\n#: res/xrc/EditUV.xrc:52\nmsgid \"Box Selection\"\nmsgstr \"Kutu Seçimi\"\n\n#: res/xrc/EditUV.xrc:53\nmsgid \"\"\n\"Box Selection\\n\"\n\"Shortcut: 1\"\nmsgstr \"\"\n\"Seçilen Kutu\\n\"\n\"Kısayol: 1\"\n\n#: res/xrc/EditUV.xrc:60\nmsgid \"Vertex Selection\"\nmsgstr \"Tepe Noktası Seçimi\"\n\n#: res/xrc/EditUV.xrc:61\nmsgid \"\"\n\"Vertex Selection\\n\"\n\"Shortcut: 2\"\nmsgstr \"\"\n\"Seçilen Tepe Noktası\\n\"\n\"Kısayol: 2\"\n\n#: res/xrc/EditUV.xrc:67 res/xrc/OutfitStudio.xrc:78\n#: res/xrc/OutfitStudio.xrc:2140\nmsgid \"Move\"\nmsgstr \"Hareket\"\n\n#: res/xrc/EditUV.xrc:68\nmsgid \"\"\n\"Move\\n\"\n\"Shortcut: 3\"\nmsgstr \"\"\n\"Hareket\\n\"\n\"Kısayol: 3\"\n\n#: res/xrc/EditUV.xrc:74 res/xrc/EditUV.xrc:336 res/xrc/ImportDialog.xrc:71\n#: res/xrc/OutfitStudio.xrc:1559 res/xrc/ShapeProperties.xrc:651\n#: src/program/NormalsGenDialog.cpp:300\nmsgid \"Scale\"\nmsgstr \"Derece\"\n\n#: res/xrc/EditUV.xrc:75\nmsgid \"\"\n\"Scale\\n\"\n\"Shortcut: 4\"\nmsgstr \"\"\n\"Derece\\n\"\n\"Kısayol: 4\"\n\n#: res/xrc/EditUV.xrc:81 res/xrc/EditUV.xrc:261\nmsgid \"Rotate\"\nmsgstr \"Dönüş\"\n\n#: res/xrc/EditUV.xrc:82\nmsgid \"\"\n\"Rotate\\n\"\n\"Shortcut: 5\"\nmsgstr \"\"\n\"Dönüş\\n\"\n\"Kısayol: 5\"\n\n#: res/xrc/EditUV.xrc:88 res/xrc/EditUV.xrc:89\nmsgid \"Show Seam Edges\"\nmsgstr \"Dikiş Kenarları\"\n\n#: res/xrc/EditUV.xrc:97 res/xrc/OutfitStudio.xrc:1640\nmsgid \"Menu\"\nmsgstr \"Menü\"\n\n#: res/xrc/EditUV.xrc:99 res/xrc/OutfitStudio.xrc:1763\nmsgid \"Edit\"\nmsgstr \"Düzenle\"\n\n#: res/xrc/EditUV.xrc:101 res/xrc/OutfitStudio.xrc:1765\nmsgid \"Undo\\tCtrl+Z\"\nmsgstr \"Geri Al\\tCtrl+Z\"\n\n#: res/xrc/EditUV.xrc:102 res/xrc/OutfitStudio.xrc:1766\nmsgid \"Undo the previous action.\"\nmsgstr \"Önceki eylemi geri al.\"\n\n#: res/xrc/EditUV.xrc:105 res/xrc/OutfitStudio.xrc:1769\nmsgid \"Redo\\tCtrl+Y\"\nmsgstr \"Yinele\\tCtrl+Y\"\n\n#: res/xrc/EditUV.xrc:106 res/xrc/OutfitStudio.xrc:42\n#: res/xrc/OutfitStudio.xrc:1770\nmsgid \"Redo the next undone action.\"\nmsgstr \"Son yaptığın işlemi tekrarla.\"\n\n#: res/xrc/EditUV.xrc:109\nmsgid \"Select All\\tCtrl+A\"\nmsgstr \"Tümünü Seç\\tCtrl+A\"\n\n#: res/xrc/EditUV.xrc:113\nmsgid \"Invert Selection\\tCtrl+I\"\nmsgstr \"Tersine Seçim\\tCtrl+I\"\n\n#: res/xrc/EditUV.xrc:117\nmsgid \"Select Less\\tA\"\nmsgstr \"Daha Az Seçim\\tA\"\n\n#: res/xrc/EditUV.xrc:118\nmsgid \"Select less adjacent points in the selected islands.\"\nmsgstr \"Seçili adalardan daha az bitişik noktayı seç.\"\n\n#: res/xrc/EditUV.xrc:121\nmsgid \"Select More\\tD\"\nmsgstr \"Daha Fazla Seçim\\tD\"\n\n#: res/xrc/EditUV.xrc:122\nmsgid \"Select more adjacent points in the selected islands.\"\nmsgstr \"Seçili adalardan daha çok bitişik noktayı seç.\"\n\n#: res/xrc/EditUV.xrc:125\nmsgid \"Translate...\\tT\"\nmsgstr \"Dönüşüm...\\tT\"\n\n#: res/xrc/EditUV.xrc:126\nmsgid \"Show a dialog to translate the current selection.\"\nmsgstr \"Geçerli seçimi tersine çevirmek için bir iletişim kutusu göster.\"\n\n#: res/xrc/EditUV.xrc:129\nmsgid \"Rotate...\\tR\"\nmsgstr \"Dönüş...\\tR\"\n\n#: res/xrc/EditUV.xrc:130\nmsgid \"Show a dialog to rotate the current selection.\"\nmsgstr \"Geçerli seçimi döndürmek için bir iletişim kutusu göster.\"\n\n#: res/xrc/EditUV.xrc:133\nmsgid \"Scale...\\tS\"\nmsgstr \"Derece...\\tS\"\n\n#: res/xrc/EditUV.xrc:134\nmsgid \"Show a dialog to scale the current selection.\"\nmsgstr \"Geçerli seçimi ölçeklendirmek için bir iletişim kutusu göster.\"\n\n#: res/xrc/EditUV.xrc:141\nmsgid \"Translate\"\nmsgstr \"Dönüşüm\"\n\n#: res/xrc/EditUV.xrc:282\nmsgid \"Angle\"\nmsgstr \"Açı / Köşe\"\n\n#: res/xrc/EditUV.xrc:425\nmsgid \"Uniform (UV)\"\nmsgstr \"(UV) Kaplama\"\n\n#: res/xrc/GroupManager.xrc:17\nmsgid \"\"\n\"Choose a group and add or remove members by selecting them in the lists.\"\nmsgstr \"\"\n\"Bir gruptan tercihini yap ve listelerinden seçerek üyelerini ekle veya \"\n\"kaldır.\"\n\n#: res/xrc/GroupManager.xrc:33 res/xrc/Project.xrc:991\nmsgid \"Select a group XML file\"\nmsgstr \"XML dosya gurubundan seçimini yap\"\n\n#: res/xrc/GroupManager.xrc:71\nmsgid \"Groups\"\nmsgstr \"Guruplar\"\n\n#: res/xrc/GroupManager.xrc:101\nmsgid \"Add Group\"\nmsgstr \"Gurup Yükle\"\n\n#: res/xrc/GroupManager.xrc:110\nmsgid \"Remove Group\"\nmsgstr \"Gurup Sil\"\n\n#: res/xrc/GroupManager.xrc:122\nmsgid \"Members\"\nmsgstr \"Üyeler\"\n\n#: res/xrc/GroupManager.xrc:137\nmsgid \"Remove >>\"\nmsgstr \"Sil >>\"\n\n#: res/xrc/GroupManager.xrc:151\nmsgid \"Outfits\"\nmsgstr \"Kıyafetler\"\n\n#: res/xrc/GroupManager.xrc:172\nmsgid \"<< Add\"\nmsgstr \"<< Yükle\"\n\n#: res/xrc/ImportDialog.xrc:5\nmsgid \"Import Options...\"\nmsgstr \"Çıkartma Seçenekleri...\"\n\n#: res/xrc/ImportDialog.xrc:53\nmsgid \"Invert U\"\nmsgstr \"U Çıkartma\"\n\n#: res/xrc/ImportDialog.xrc:62\nmsgid \"Invert V\"\nmsgstr \"V Çıkartma\"\n\n#: res/xrc/ImportDialog.xrc:89\nmsgid \"Rotate (X)\"\nmsgstr \"Döndür (X)\"\n\n#: res/xrc/ImportDialog.xrc:98\nmsgid \"Choose X rotation.\"\nmsgstr \"X Konumuna Döndür.\"\n\n#: res/xrc/ImportDialog.xrc:113\nmsgid \"Rotate (Y)\"\nmsgstr \"Döndür (Y)\"\n\n#: res/xrc/ImportDialog.xrc:122\nmsgid \"Choose Y rotation.\"\nmsgstr \"Y Konumuna Döndür.\"\n\n#: res/xrc/ImportDialog.xrc:137\nmsgid \"Rotate (Z)\"\nmsgstr \"Döndür (Z)\"\n\n#: res/xrc/ImportDialog.xrc:146\nmsgid \"Choose Z rotation.\"\nmsgstr \"Z Konumuna Döndür.\"\n\n#: res/xrc/NormalsGenDlg.xrc:6\nmsgid \"Normal Map Generator\"\nmsgstr \"Normal Harita Üreticisi\"\n\n#: res/xrc/NormalsGenDlg.xrc:21\nmsgid \"Layers\"\nmsgstr \"Katmanlar\"\n\n#: res/xrc/NormalsGenDlg.xrc:37\nmsgid \"Load or save preset layer settings.\"\nmsgstr \"Önceden hazır olarak ayarlanmış katman değerlerini yükle veya kaydet.\"\n\n#: res/xrc/NormalsGenDlg.xrc:61\nmsgid \"Add a new layer after the current one in the layer list.\"\nmsgstr \"Katman listesindeki mevcut satırdan sonra yeni bir katmanı ekler.\"\n\n#: res/xrc/NormalsGenDlg.xrc:62\nmsgid \"Add Layer\"\nmsgstr \"Katman Ekle\"\n\n#: res/xrc/NormalsGenDlg.xrc:71\nmsgid \"Move selected layer up one position.\"\nmsgstr \"Seçilen katmanı bir konum yukarı taşır.\"\n\n#: res/xrc/NormalsGenDlg.xrc:72\nmsgid \"Move Up\"\nmsgstr \"Yukarı Taşı\"\n\n#: res/xrc/NormalsGenDlg.xrc:87\nmsgid \"Delete the selected layer.\"\nmsgstr \"Seçilen katmanı sil.\"\n\n#: res/xrc/NormalsGenDlg.xrc:88\nmsgid \"Delete Layer\"\nmsgstr \"Katmanı Sil\"\n\n#: res/xrc/NormalsGenDlg.xrc:114\nmsgid \"\"\n\"Save a copy of an existing normal map if one already exists. File is saved \"\n\"in the original directory.\"\nmsgstr \"\"\n\"Kopyala ve kaydet, normal bir haritanın bir kopyasını kaydedin. Dosya \"\n\"orijinal dizinde kaydedilir.\"\n\n#: res/xrc/NormalsGenDlg.xrc:115\nmsgid \"Backup destination file\"\nmsgstr \"Hedef dosyayı Yedekle\"\n\n#: res/xrc/NormalsGenDlg.xrc:124\nmsgid \"\"\n\"Compress output file using BC7 compression. This can make saving the file \"\n\"take a VERY long time!\"\nmsgstr \"\"\n\"BC7 sıkıştırma biçemini kullanarak çıktı dosyasını sıkıştırır. Bu, dosyanın \"\n\"çok uzun süre korunmasını sağlayabilir!\"\n\n#: res/xrc/NormalsGenDlg.xrc:125\nmsgid \"Compress output \"\nmsgstr \"Çıktı sıkıştırması \"\n\n#: res/xrc/NormalsGenDlg.xrc:134\nmsgid \"\"\n\"Use the file name specified in the background layer to save the normal map.\"\nmsgstr \"\"\n\"Normal haritayı kaydetmek için arka plan katmanında belirtilen dosya adını \"\n\"kullanın.\"\n\n#: res/xrc/NormalsGenDlg.xrc:135\nmsgid \"Save to background layer file\"\nmsgstr \"Arka plan katman dosyasına kaydet\"\n\n#: res/xrc/NormalsGenDlg.xrc:145\nmsgid \"Choose an output file...\"\nmsgstr \"Bir çıktı dosyasını seç...\"\n\n#: res/xrc/NormalsGenDlg.xrc:149\nmsgid \"Location to save normal map to.\"\nmsgstr \"Normal haritayı kaydetme konumu.\"\n\n#: res/xrc/NormalsGenDlg.xrc:165\nmsgid \"Display current settings on mesh in preview window.\"\nmsgstr \"Ön izleme penceresindeki geçerli ayarlarını kafes olarak görüntüle.\"\n\n#: res/xrc/NormalsGenDlg.xrc:181\nmsgid \"Generate and save the normal map file.\"\nmsgstr \"Normal harita dosyasını oluştur ve kaydet.\"\n\n#: res/xrc/NormalsGenDlg.xrc:182\nmsgid \"Generate\"\nmsgstr \"Oluştur\"\n\n#: res/xrc/NormalsGenDlg.xrc:193 res/xrc/OutfitStudio.xrc:2010\nmsgid \"Load Preset...\"\nmsgstr \"Hazır Ayarı Yükle...\"\n\n#: res/xrc/NormalsGenDlg.xrc:197 res/xrc/OutfitStudio.xrc:2014\nmsgid \"Save Preset...\"\nmsgstr \"Hazır Ayarı Kaydet...\"\n\n#: res/xrc/OutfitStudio.xrc:22 res/xrc/Project.xrc:5\nmsgid \"New Project\"\nmsgstr \"Yeni Proje\"\n\n#: res/xrc/OutfitStudio.xrc:23\nmsgid \"\"\n\"Create a new project by selecting a reference body slider set, and outfit \"\n\"model files.\"\nmsgstr \"\"\n\"Örnek bir vücut kaydırıcısı setini ve kıyafet modeli dosyasını seçerek yeni \"\n\"bir proje oluştur.\"\n\n#: res/xrc/OutfitStudio.xrc:28\nmsgid \"Load Project\"\nmsgstr \"Projeyi Yükle\"\n\n#: res/xrc/OutfitStudio.xrc:29\nmsgid \"Load a previously created slider set for editing.\"\nmsgstr \"Düzenlemek için önceden oluşturulmuş bir kaydırıcı yükle.\"\n\n#: res/xrc/OutfitStudio.xrc:34\nmsgid \"Undo\"\nmsgstr \"Geri Al\"\n\n#: res/xrc/OutfitStudio.xrc:35\nmsgid \"Undo a previous action.\"\nmsgstr \"Önceki eylemi geri al.\"\n\n#: res/xrc/OutfitStudio.xrc:41\nmsgid \"Redo\"\nmsgstr \"Yinele\"\n\n#: res/xrc/OutfitStudio.xrc:49 res/xrc/OutfitStudio.xrc:2119\nmsgid \"Select\"\nmsgstr \"Seç\"\n\n#: res/xrc/OutfitStudio.xrc:50 res/xrc/OutfitStudio.xrc:2120\nmsgid \"Navigate and select meshes (or vertices in vertex mode).\"\nmsgstr \"Kafesler arasında gezin ve seç (veya uç tepe noktalarında).\"\n\n#: res/xrc/OutfitStudio.xrc:57 res/xrc/OutfitStudio.xrc:2124\n#: src/program/NormalsGenDialog.cpp:291\nmsgid \"Mask\"\nmsgstr \"Maske\"\n\n#: res/xrc/OutfitStudio.xrc:58 res/xrc/OutfitStudio.xrc:2125\nmsgid \"\"\n\"Mask vertices to prevent them from being transformed.\\n\"\n\"Hold down the ALT key to remove masking.\"\nmsgstr \"\"\n\"Değiştirilmelerini önlemek için Uç tepe noktası maskeleri.\\n\"\n\"Maskelemeyi kaldırmak için ALT tuşuna basılı tut.\"\n\n#: res/xrc/OutfitStudio.xrc:64 res/xrc/OutfitStudio.xrc:2129\nmsgid \"Inflate\"\nmsgstr \"Büyült\"\n\n#: res/xrc/OutfitStudio.xrc:65 res/xrc/OutfitStudio.xrc:2130\nmsgid \"Increase mesh volume in an area.\"\nmsgstr \"Bir alandaki kafes yoğunluğunu artırır.\"\n\n#: res/xrc/OutfitStudio.xrc:71 res/xrc/OutfitStudio.xrc:2135\nmsgid \"Deflate\"\nmsgstr \"İncelt\"\n\n#: res/xrc/OutfitStudio.xrc:72 res/xrc/OutfitStudio.xrc:2136\nmsgid \"Decrease mesh volume in an area.\"\nmsgstr \"Bir alandaki kafes yoğunluğunu artırır.\"\n\n#: res/xrc/OutfitStudio.xrc:79 res/xrc/OutfitStudio.xrc:2141\nmsgid \"Move vertices over a plane parallel to the view.\"\nmsgstr \"Tepe noktalarını, görünüme paralel bir düzlemin üzerine getirir.\"\n\n#: res/xrc/OutfitStudio.xrc:85 res/xrc/OutfitStudio.xrc:2145\nmsgid \"Smooth\"\nmsgstr \"Düzgünleştir\"\n\n#: res/xrc/OutfitStudio.xrc:86 res/xrc/OutfitStudio.xrc:2146\nmsgid \"Smooth an area of a mesh.\"\nmsgstr \"Düzgünleştir.\"\n\n#: res/xrc/OutfitStudio.xrc:92 res/xrc/OutfitStudio.xrc:2150\nmsgid \"Undiff\"\nmsgstr \"Farkı Sil\"\n\n#: res/xrc/OutfitStudio.xrc:93 res/xrc/OutfitStudio.xrc:2151\nmsgid \"Undiff an area of a slider.\"\nmsgstr \"Kaydırıcının bir alanındaki farkını kaldır.\"\n\n#: res/xrc/OutfitStudio.xrc:99 res/xrc/OutfitStudio.xrc:2155\nmsgid \"Weight Paint\"\nmsgstr \"Ağırlık Boyaması\"\n\n#: res/xrc/OutfitStudio.xrc:100\nmsgid \"\"\n\"Apply animation weight values for currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"Seçili olan kemik için animasyon ağırlık değerleri uygula.\\n\"\n\"Ağırlığı azaltmak için ALT tuşuna basılı tut.\"\n\n#: res/xrc/OutfitStudio.xrc:107 res/xrc/OutfitStudio.xrc:2161\nmsgid \"Color Paint\"\nmsgstr \"Boyama Rengi\"\n\n#: res/xrc/OutfitStudio.xrc:108 res/xrc/OutfitStudio.xrc:2162\nmsgid \"\"\n\"Apply vertex colors.\\n\"\n\"Hold down the ALT key to remove colors.\"\nmsgstr \"\"\n\"Uç Renkleri kabul et.\\n\"\n\"Rengi kaldırmak için ALT tuşuna basılı tut.\"\n\n#: res/xrc/OutfitStudio.xrc:115 res/xrc/OutfitStudio.xrc:2167\nmsgid \"Alpha Paint\"\nmsgstr \"Alfa Boyama\"\n\n#: res/xrc/OutfitStudio.xrc:116 res/xrc/OutfitStudio.xrc:2168\nmsgid \"\"\n\"Apply vertex alpha.\\n\"\n\"Hold down the ALT key to remove alpha.\"\nmsgstr \"\"\n\"Uç Alfayı kabul et.\\n\"\n\"Alfayı kaldırmak için ALT tuşunu basılı tut.\"\n\n#: res/xrc/OutfitStudio.xrc:123 res/xrc/OutfitStudio.xrc:2173\nmsgid \"Collapse Vertex\"\nmsgstr \"Uç Noktaları Daralt\"\n\n#: res/xrc/OutfitStudio.xrc:124 res/xrc/OutfitStudio.xrc:2174\nmsgid \"\"\n\"Deletes vertices with no more than three connections, without creating a \"\n\"hole.\"\nmsgstr \"\"\n\"Bir delik oluşturmadan, en fazla üç bağlantıya sahip olan köşe noktalarını \"\n\"siler.\"\n\n#: res/xrc/OutfitStudio.xrc:130 res/xrc/OutfitStudio.xrc:2178\nmsgid \"Flip Edge\"\nmsgstr \"Kenarı Çevir\"\n\n#: res/xrc/OutfitStudio.xrc:131 res/xrc/OutfitStudio.xrc:2179\nmsgid \"Flips mesh edges so that the opposite pair of vertices is connected.\"\nmsgstr \"Kafes kenarlarını ters köşelere bağlanacak şekilde çevirir.\"\n\n#: res/xrc/OutfitStudio.xrc:137 res/xrc/OutfitStudio.xrc:2183\nmsgid \"Split Edge\"\nmsgstr \"Bölünmüş Kenar\"\n\n#: res/xrc/OutfitStudio.xrc:138 res/xrc/OutfitStudio.xrc:2184\nmsgid \"Splits a mesh edge in two with a new vertex.\"\nmsgstr \"Mesh dosyasının kenarını yeni bir tepe noktası ile ikiye böler.\"\n\n#: res/xrc/OutfitStudio.xrc:144 res/xrc/OutfitStudio.xrc:2188\nmsgid \"Move Vertex\"\nmsgstr \"Tepe Noktasını Taşı\"\n\n#: res/xrc/OutfitStudio.xrc:145 res/xrc/OutfitStudio.xrc:2189\nmsgid \"Moves a vertex.\"\nmsgstr \"Bir köşeyi hareket ettirir.\"\n\n#: res/xrc/OutfitStudio.xrc:155\nmsgid \"Field of View\"\nmsgstr \"Görüş Alanı\"\n\n#: res/xrc/OutfitStudio.xrc:159\nmsgid \"Field of View: 65\"\nmsgstr \"Görüş Alanı: 65\"\n\n#: res/xrc/OutfitStudio.xrc:164\nmsgid \"Brush Settings\"\nmsgstr \"Fırçalama Ayarları\"\n\n#: res/xrc/OutfitStudio.xrc:169\nmsgid \"Open Discord invite link.\"\nmsgstr \"Discord Site bağlantısını aç.\"\n\n#: res/xrc/OutfitStudio.xrc:174\nmsgid \"Open GitHub link.\"\nmsgstr \"GitHub Site bağlantısını aç.\"\n\n#: res/xrc/OutfitStudio.xrc:179\nmsgid \"Open PayPal link.\"\nmsgstr \"PayPal Site bağlantısını aç.\"\n\n#: res/xrc/OutfitStudio.xrc:200\nmsgid \"Transform\"\nmsgstr \"Dönüştür\"\n\n#: res/xrc/OutfitStudio.xrc:201 res/xrc/OutfitStudio.xrc:2195\nmsgid \"Shows a transform tool to manipulate shapes and vertices with.\"\nmsgstr \"\"\n\"Kalıpları ve uç tepe noktalarını işlemek için bir dönüştürme aracı gösterir.\"\n\n#: res/xrc/OutfitStudio.xrc:207\nmsgid \"Pivot\"\nmsgstr \"Eksen\"\n\n#: res/xrc/OutfitStudio.xrc:208 res/xrc/OutfitStudio.xrc:2200\nmsgid \"\"\n\"Shows a pivot that can be moved and makes it the center of mesh operations \"\n\"like rotation and scale.\"\nmsgstr \"\"\n\"Hareket ettirilebilen bir dönüşü gösterir ve döndürme ve ölçekleme gibi \"\n\"işlemlerin merkezi eksenini sağlar.\"\n\n#: res/xrc/OutfitStudio.xrc:214\nmsgid \"Vertex Edit\"\nmsgstr \"Tepe Noktasını Düzenle\"\n\n#: res/xrc/OutfitStudio.xrc:215\nmsgid \"\"\n\"Lets you select vertices to add to or remove from the mask.\\n\"\n\"Click on a vertex to select/unmask it.\\n\"\n\"Hold down CTRL to unselect/mask it.\"\nmsgstr \"\"\n\"Maskeye eklemek veya çıkarmak için tepe noktalarını seçmeni sağlar.\\n\"\n\"Tepe noktalarını kaldırmak/maskelemek için basılı tut.\\n\"\n\"Seçimi kaldırmak/maskelemek için CTRL tuşuna bas.\"\n\n#: res/xrc/OutfitStudio.xrc:222\nmsgid \"View Front\"\nmsgstr \"Ön Görünüm\"\n\n#: res/xrc/OutfitStudio.xrc:223\nmsgid \"Change camera view to the front.\"\nmsgstr \"Kamera görünümünü önden görecek şekilde değiştirir.\"\n\n#: res/xrc/OutfitStudio.xrc:227\nmsgid \"View Back\"\nmsgstr \"Arka Görünüm\"\n\n#: res/xrc/OutfitStudio.xrc:228\nmsgid \"Change camera view to the back.\"\nmsgstr \"Kamera görünümünü arkadan görecek şekilde değiştirir.\"\n\n#: res/xrc/OutfitStudio.xrc:232\nmsgid \"View Left\"\nmsgstr \"Soldan Görünüm\"\n\n#: res/xrc/OutfitStudio.xrc:233\nmsgid \"Change camera view to the left.\"\nmsgstr \"Kamera görünümünü soldan görecek şekilde değiştirir.\"\n\n#: res/xrc/OutfitStudio.xrc:237\nmsgid \"View Right\"\nmsgstr \"Sağdan Görünüm\"\n\n#: res/xrc/OutfitStudio.xrc:238\nmsgid \"Change camera view to the right.\"\nmsgstr \"Kamera görünümünü sağdan görecek şekilde değiştirir.\"\n\n#: res/xrc/OutfitStudio.xrc:242\nmsgid \"Perspective View\"\nmsgstr \"Derin Görünüm\"\n\n#: res/xrc/OutfitStudio.xrc:243\nmsgid \"Toggle perspective view.\"\nmsgstr \"Kamera görünümünü derinlemesine görecek şekilde değiştirir.\"\n\n#: res/xrc/OutfitStudio.xrc:249\nmsgid \"Show Nodes\"\nmsgstr \"Düğümleri Göster\"\n\n#: res/xrc/OutfitStudio.xrc:250\nmsgid \"Toggle rendering of nodes.\"\nmsgstr \"Düğümleri, Bezeleri görüntüler.\"\n\n#: res/xrc/OutfitStudio.xrc:255\nmsgid \"Show Bones\"\nmsgstr \"İskeleti Göster\"\n\n#: res/xrc/OutfitStudio.xrc:256\nmsgid \"Toggle rendering of bones.\"\nmsgstr \"Kemik İskelet yapısını görüntüler.\"\n\n#: res/xrc/OutfitStudio.xrc:261\nmsgid \"Show Floor\"\nmsgstr \"Zemini Göster\"\n\n#: res/xrc/OutfitStudio.xrc:262\nmsgid \"Toggle rendering of the floor grid.\"\nmsgstr \"Zemin ızgarasını görüntüler.\"\n\n#: res/xrc/OutfitStudio.xrc:268\nmsgid \"X Mirror\"\nmsgstr \"Yansıtma X\"\n\n#: res/xrc/OutfitStudio.xrc:269 res/xrc/OutfitStudio.xrc:1775\nmsgid \"Mirror edits across the X axis.\"\nmsgstr \"X ekseni boyunca yansıtma düzenlemeleri.\"\n\n#: res/xrc/OutfitStudio.xrc:276 res/xrc/OutfitStudio.xrc:1781\nmsgid \"Edit Connected Only\\tC\"\nmsgstr \"Sadece Bağlantıyı Düzenle\\tC\"\n\n#: res/xrc/OutfitStudio.xrc:277\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius.\"\nmsgstr \"\"\n\"Fırça yarıçapı içindeki boyamanın altındakilere bağlı olan yalnızca köşe \"\n\"noktalarını düzenle.\"\n\n#: res/xrc/OutfitStudio.xrc:283 res/xrc/OutfitStudio.xrc:1788\nmsgid \"Merge Vertex\"\nmsgstr \"Tepe Noktasını Düzenle\"\n\n#: res/xrc/OutfitStudio.xrc:284 res/xrc/OutfitStudio.xrc:1789\nmsgid \"Merges two vertices and fills any gaps.\"\nmsgstr \"İki köşeyi birleştirir ve boşlukları doldurur.\"\n\n#: res/xrc/OutfitStudio.xrc:290 res/xrc/OutfitStudio.xrc:1795\nmsgid \"Weld Vertex\"\nmsgstr \"Köşe Kaynaşımı\"\n\n#: res/xrc/OutfitStudio.xrc:291 res/xrc/OutfitStudio.xrc:1796\nmsgid \"Welds two vertices while keeping the texture coordinates (UV) distinct.\"\nmsgstr \"\"\n\"Doku koordinatlarını (UV) farklı tutarken iki köşeyi birbirine kaynaştırır.\"\n\n#: res/xrc/OutfitStudio.xrc:297 res/xrc/OutfitStudio.xrc:1802\nmsgid \"Restrict To Surface\"\nmsgstr \"Yüzey Alanıyla Kısıtla\"\n\n#: res/xrc/OutfitStudio.xrc:298 res/xrc/OutfitStudio.xrc:1803\nmsgid \"Restricts motion to a mesh surface.\"\nmsgstr \"Hareketi tek bir ağ yüzeyiyle sınırlar.\"\n\n#: res/xrc/OutfitStudio.xrc:304 res/xrc/OutfitStudio.xrc:1809\nmsgid \"Restrict To Plane\"\nmsgstr \"Düzlem Alanıyla Sınırla\"\n\n#: res/xrc/OutfitStudio.xrc:305 res/xrc/OutfitStudio.xrc:1810\nmsgid \"Restricts motion to parallel to the surface.\"\nmsgstr \"Hareketi yüzeye paralel olarak kısıtlar.\"\n\n#: res/xrc/OutfitStudio.xrc:311 res/xrc/OutfitStudio.xrc:1816\nmsgid \"Restrict To Normal\"\nmsgstr \"Normal Alanı Kısıtla\"\n\n#: res/xrc/OutfitStudio.xrc:312 res/xrc/OutfitStudio.xrc:1817\nmsgid \"Restricts motion to perpendicular to the surface.\"\nmsgstr \"Hareketi yüzeye dik olarak sınırlar.\"\n\n#: res/xrc/OutfitStudio.xrc:375\nmsgid \"Meshes\"\nmsgstr \"Kafesler\"\n\n#: res/xrc/OutfitStudio.xrc:399 res/xrc/OutfitStudio.xrc:2510\n#: res/xrc/OutfitStudio.xrc:2536\nmsgid \"Segments\"\nmsgstr \"Parçalar\"\n\n#: res/xrc/OutfitStudio.xrc:411 res/xrc/OutfitStudio.xrc:2543\n#: res/xrc/OutfitStudio.xrc:2554\nmsgid \"Partitions\"\nmsgstr \"Bölümler\"\n\n#: res/xrc/OutfitStudio.xrc:423\nmsgid \"Colors\"\nmsgstr \"Renkler\"\n\n#: res/xrc/OutfitStudio.xrc:435\nmsgid \"Lights\"\nmsgstr \"Işıklar\"\n\n#: res/xrc/OutfitStudio.xrc:475\nmsgid \"Total Bones: 0\"\nmsgstr \"Toplam İskelet: 0\"\n\n#: res/xrc/OutfitStudio.xrc:485\nmsgid \"Shape Selection Bones: 0\"\nmsgstr \"İskelet Modeli Seçimi: 0\"\n\n#: res/xrc/OutfitStudio.xrc:515\nmsgid \"Brush Color\"\nmsgstr \"Fırça Rengi\"\n\n#: res/xrc/OutfitStudio.xrc:524\nmsgid \"Color of the brush.\"\nmsgstr \"Fırçanın rengi.\"\n\n#: res/xrc/OutfitStudio.xrc:546\nmsgid \"Clamp Max Value\"\nmsgstr \"Max Küme Değeri\"\n\n#: res/xrc/OutfitStudio.xrc:589 src/program/OutfitStudio.cpp:3062\n#: src/program/OutfitStudio.cpp:6647\nmsgid \"Edit Alpha\"\nmsgstr \"Alfa Düzenleme\"\n\n#: res/xrc/OutfitStudio.xrc:635 res/xrc/OutfitStudio.xrc:1039\n#: res/xrc/OutfitStudio.xrc:1140 src/program/OutfitStudio.cpp:6362\n#: src/program/OutfitStudio.cpp:10632\nmsgid \"Reset\"\nmsgstr \"Sıfırla\"\n\n#: res/xrc/OutfitStudio.xrc:648\nmsgid \"Ambient\"\nmsgstr \"Çevre\"\n\n#: res/xrc/OutfitStudio.xrc:673\nmsgid \"Frontal\"\nmsgstr \"Önden\"\n\n#: res/xrc/OutfitStudio.xrc:698\nmsgid \"Directional 1\"\nmsgstr \"Yön 1\"\n\n#: res/xrc/OutfitStudio.xrc:723\nmsgid \"Directional 2\"\nmsgstr \"Yön 2\"\n\n#: res/xrc/OutfitStudio.xrc:748\nmsgid \"Directional 3\"\nmsgstr \"Yön 3\"\n\n#: res/xrc/OutfitStudio.xrc:916\nmsgid \"Slot\"\nmsgstr \"Yuva\"\n\n#: res/xrc/OutfitStudio.xrc:991 src/program/OutfitStudio.cpp:5472\nmsgid \"SSF File\"\nmsgstr \"SSF Dosyası\"\n\n#: res/xrc/OutfitStudio.xrc:1011\nmsgid \"Set\"\nmsgstr \"Ayarla\"\n\n#: res/xrc/OutfitStudio.xrc:1029 res/xrc/OutfitStudio.xrc:1130\n#: src/program/OutfitStudio.cpp:6362\nmsgid \"Apply\"\nmsgstr \"Uygula\"\n\n#: res/xrc/OutfitStudio.xrc:1158\nmsgid \"De-/Select Sliders\"\nmsgstr \"De-/Kaydırıcıları Seç\"\n\n#: res/xrc/OutfitStudio.xrc:1177\nmsgid \"Fixed Weight Brush\"\nmsgstr \"Ağırlık Fırçalaması Düzeltme\"\n\n#: res/xrc/OutfitStudio.xrc:1188\nmsgid \"Normalize Weights\"\nmsgstr \"Ağırlıkları Normalleştir\"\n\n#: res/xrc/OutfitStudio.xrc:1205\nmsgid \"X-Mirror Bone\"\nmsgstr \"X-Yansıtma İskelet\"\n\n#: res/xrc/OutfitStudio.xrc:1230\nmsgid \"Masks\"\nmsgstr \"Maskeler\"\n\n#: res/xrc/OutfitStudio.xrc:1275 res/xrc/OutfitStudio.xrc:1336\n#: res/xrc/OutfitStudio.xrc:2476\nmsgid \"Delete\"\nmsgstr \"Sil\"\n\n#: res/xrc/OutfitStudio.xrc:1291\nmsgid \"Posing\"\nmsgstr \"Hareket\"\n\n#: res/xrc/OutfitStudio.xrc:1352\nmsgid \"Show Pose\"\nmsgstr \"Hareketi Göster\"\n\n#: res/xrc/OutfitStudio.xrc:1370\nmsgid \"Reset Bone\"\nmsgstr \"İskeleti Sıfırla\"\n\n#: res/xrc/OutfitStudio.xrc:1390\nmsgid \"Rotation X\"\nmsgstr \"Döndür X Konumu\"\n\n#: res/xrc/OutfitStudio.xrc:1418\nmsgid \"Rotation Y\"\nmsgstr \"Döndür Y Konumu\"\n\n#: res/xrc/OutfitStudio.xrc:1446\nmsgid \"Rotation Z\"\nmsgstr \"Döndür Z Konumu\"\n\n#: res/xrc/OutfitStudio.xrc:1474\nmsgid \"Offset X\"\nmsgstr \"Dengele X Konumu\"\n\n#: res/xrc/OutfitStudio.xrc:1502\nmsgid \"Offset Y\"\nmsgstr \"Dengele Y Konumu\"\n\n#: res/xrc/OutfitStudio.xrc:1530\nmsgid \"Offset Z\"\nmsgstr \"Dengele Z Konumu\"\n\n#: res/xrc/OutfitStudio.xrc:1592\nmsgid \"Reset All\"\nmsgstr \"Tümünü Sıfırla\"\n\n#: res/xrc/OutfitStudio.xrc:1600\nmsgid \"Apply to Mesh\"\nmsgstr \"Mesh Dosyasına Uygula\"\n\n#: res/xrc/OutfitStudio.xrc:1642 res/xrc/Settings.xrc:371\n#: src/program/NormalsGenDialog.cpp:284\nmsgid \"File\"\nmsgstr \"Dosya\"\n\n#: res/xrc/OutfitStudio.xrc:1644\nmsgid \"New Project...\\tCtrl+N\"\nmsgstr \"Yeni Proje...\\tCtrl+N\"\n\n#: res/xrc/OutfitStudio.xrc:1645\nmsgid \"Create a new outfit project.\"\nmsgstr \"Yeni bir kıyafet projesi oluştur.\"\n\n#: res/xrc/OutfitStudio.xrc:1648\nmsgid \"Load Project..\\tCtrl+O\"\nmsgstr \"Hazır Proje Yükle..\\tCtrl+O\"\n\n#: res/xrc/OutfitStudio.xrc:1649\nmsgid \"Load a project.\"\nmsgstr \"Önceki Projeyi yükle.\"\n\n#: res/xrc/OutfitStudio.xrc:1652\nmsgid \"Add Project..\\tCtrl+Shift+O\"\nmsgstr \"Proje Ekle..\\tCtrl+Shift+O\"\n\n#: res/xrc/OutfitStudio.xrc:1653\nmsgid \"Add a project without replacing the current one.\"\nmsgstr \"Geçerli olanı değiştirmeden yeni bir proje ekle.\"\n\n#: res/xrc/OutfitStudio.xrc:1656\nmsgid \"Unload Project...\\tCtrl+W\"\nmsgstr \"Projeyi Kaldır...\\tCtrl+W\"\n\n#: res/xrc/OutfitStudio.xrc:1657\nmsgid \"Unloads the project and creates an empty new one.\"\nmsgstr \"Projeyi kaldırır ve yeni bir boş proje oluşturur.\"\n\n#: res/xrc/OutfitStudio.xrc:1660\nmsgid \"Recent Projects...\"\nmsgstr \"Son Projeler...\"\n\n#: res/xrc/OutfitStudio.xrc:1665\nmsgid \"Load Reference...\"\nmsgstr \"Örnekten Yükle...\"\n\n#: res/xrc/OutfitStudio.xrc:1666\nmsgid \"\"\n\"Load a new reference slider set, replacing any current reference objects.\"\nmsgstr \"\"\n\"Mevcut referans nesnelerini değiştirerek yeni bir örnekleme kaydırıcı setini \"\n\"yükle.\"\n\n#: res/xrc/OutfitStudio.xrc:1669\nmsgid \"Load Outfit...\"\nmsgstr \"Kıyafeti Yükle...\"\n\n#: res/xrc/OutfitStudio.xrc:1670\nmsgid \"\"\n\"Load a NIF file as the working outfit, replacing any current outfit objects.\"\nmsgstr \"\"\n\"Herhangi bir mevcut kıyafet nesnesini değiştirerek, çalışma kıyafeti \"\n\"şeklinde NIF dosyası olarak yükle.\"\n\n#: res/xrc/OutfitStudio.xrc:1674\nmsgid \"Convert / Replace Reference...\\tCtrl+Shift+R\"\nmsgstr \"Örnek Kalıbı Değiştir/Dönüştür...\\tCtrl+Shift+R\"\n\n#: res/xrc/OutfitStudio.xrc:1675\nmsgid \"Convert to or replace an outfit's body/reference\"\nmsgstr \"Bir kıyafeti bedenine göre beden/örnek olarak dönüştür veya değiştir\"\n\n#: res/xrc/OutfitStudio.xrc:1679\nmsgid \"Save Project\\tCtrl+S\"\nmsgstr \"Projeyi Kaydet\\tCtrl+S\"\n\n#: res/xrc/OutfitStudio.xrc:1680\nmsgid \"Save the project.\"\nmsgstr \"Çalışmanı Kaydet.\"\n\n#: res/xrc/OutfitStudio.xrc:1684\nmsgid \"Save Project As...\\tCtrl+Shift+S\"\nmsgstr \"Projeyi Farklı Kaydet...\\tCtrl+Shift+S\"\n\n#: res/xrc/OutfitStudio.xrc:1685\nmsgid \"Save the project under a new name.\"\nmsgstr \"Projeyi yeni bir isim vererek kaydet.\"\n\n#: res/xrc/OutfitStudio.xrc:1689 src/program/OutfitStudio.cpp:7222\n#: src/program/OutfitStudio.cpp:7333\nmsgid \"Import\"\nmsgstr \"Yerleştir\"\n\n#: res/xrc/OutfitStudio.xrc:1691\nmsgid \"From NIF...\"\nmsgstr \"NIF olarak...\"\n\n#: res/xrc/OutfitStudio.xrc:1692\nmsgid \"Choose a NIF file to import into the project.\"\nmsgstr \"Projeye yerleştirmek için bir NIF dosyasını seç.\"\n\n#: res/xrc/OutfitStudio.xrc:1695\nmsgid \"From OBJ...\"\nmsgstr \"OBJ olarak...\"\n\n#: res/xrc/OutfitStudio.xrc:1696\nmsgid \"Import an OBJ file as a new shape in the outfit.\"\nmsgstr \"Bir OBJ dosyasını kıyafette yeni bir kalıp olarak içe aktar.\"\n\n#: res/xrc/OutfitStudio.xrc:1699\nmsgid \"From FBX...\"\nmsgstr \"FBX olarak...\"\n\n#: res/xrc/OutfitStudio.xrc:1700\nmsgid \"Import an FBX file as a new shape in the outfit.\"\nmsgstr \"Bir FBX dosyasını kıyafette yeni bir kalıp olarak içe aktar.\"\n\n#: res/xrc/OutfitStudio.xrc:1703\nmsgid \"From TRI (Head)...\"\nmsgstr \"TRI Dosyası Olarak (Kafa)...\"\n\n#: res/xrc/OutfitStudio.xrc:1704\nmsgid \"Import shape and morphs from a head TRI file.\"\nmsgstr \"TRI morphs dosyası verilerini TRI dosyası olarak çıkarır.\"\n\n#: res/xrc/OutfitStudio.xrc:1707\nmsgid \"Import Data\"\nmsgstr \"Data Yerleştir\"\n\n#: res/xrc/OutfitStudio.xrc:1709\nmsgid \"Import BSClothExtraData From HKX\"\nmsgstr \"BSClothExtraData Dosyasına HKX Dosyasından Yerleştir\"\n\n#: res/xrc/OutfitStudio.xrc:1710\nmsgid \"\"\n\"Choose an HKX file to import as a BSClothExtraData block into the project.\"\nmsgstr \"\"\n\"Projeye BSClothExtraData bloğu olarak almak için bir HKX dosyasını seç.\"\n\n#: res/xrc/OutfitStudio.xrc:1715 res/xrc/OutfitStudio.xrc:1843\n#: res/xrc/OutfitStudio.xrc:2313\nmsgid \"Export\"\nmsgstr \"Çıkart\"\n\n#: res/xrc/OutfitStudio.xrc:1717\nmsgid \"To NIF...\\tCtrl+E\"\nmsgstr \"NIF olarak...\\tCtrl+E\"\n\n#: res/xrc/OutfitStudio.xrc:1718\nmsgid \"Save the current project as a NIF file (without reference)\"\nmsgstr \"Mevcut projeyi bir NIF dosyası olarak kaydet (referans olmadan)\"\n\n#: res/xrc/OutfitStudio.xrc:1721\nmsgid \"To NIF With Reference...\\tCtrl+Alt+E\"\nmsgstr \"Referans ile NIF'e aktar...\\tCtrl+Alt+E\"\n\n#: res/xrc/OutfitStudio.xrc:1722\nmsgid \"Save the current project as a NIF file (including reference)\"\nmsgstr \"Mevcut projeyi bir NIF dosyası olarak kaydet (referans dahil olarak)\"\n\n#: res/xrc/OutfitStudio.xrc:1725 res/xrc/OutfitStudio.xrc:1849\n#: res/xrc/OutfitStudio.xrc:2319\nmsgid \"To OBJ...\"\nmsgstr \"OBJ olarak...\"\n\n#: res/xrc/OutfitStudio.xrc:1726\nmsgid \"Export the current project as an OBJ file.\"\nmsgstr \"Seçilen modeli bir OBJ kalıbı olarak dışa aktar.\"\n\n#: res/xrc/OutfitStudio.xrc:1729 res/xrc/OutfitStudio.xrc:1853\n#: res/xrc/OutfitStudio.xrc:2323\nmsgid \"To FBX...\"\nmsgstr \"FBX olarak...\"\n\n#: res/xrc/OutfitStudio.xrc:1730\nmsgid \"Export the current project as an FBX file.\"\nmsgstr \"Mevcut projeyi bir FBX dosyası olarak dışa aktar.\"\n\n#: res/xrc/OutfitStudio.xrc:1733 res/xrc/OutfitStudio.xrc:1857\n#: res/xrc/OutfitStudio.xrc:2327\nmsgid \"To TRI (Head)...\"\nmsgstr \"TRI olarak (Kafa)...\"\n\n#: res/xrc/OutfitStudio.xrc:1734 res/xrc/OutfitStudio.xrc:1858\n#: res/xrc/OutfitStudio.xrc:2328\nmsgid \"Export head morphs to a TRI file.\"\nmsgstr \"TRI morphs dosyası verilerini TRI dosyası olarak çıkarır.\"\n\n#: res/xrc/OutfitStudio.xrc:1737\nmsgid \"Export Data\"\nmsgstr \"Verileri Dışa Aktar\"\n\n#: res/xrc/OutfitStudio.xrc:1739\nmsgid \"Export BSClothExtraData As HKX\"\nmsgstr \"BSClothExtraData dosyasını HKX olarak çıkart\"\n\n#: res/xrc/OutfitStudio.xrc:1740\nmsgid \"\"\n\"Save one of the currently loaded BSClothExtraData blocks to an HKX file.\"\nmsgstr \"\"\n\"Şu anda yüklü olan BSClothExtraData bloklarından birini HKX dosyasına kaydet.\"\n\n#: res/xrc/OutfitStudio.xrc:1745\nmsgid \"Make Conversion Reference\"\nmsgstr \"Dönüşüm Referansı Oluştur\"\n\n#: res/xrc/OutfitStudio.xrc:1746\nmsgid \"\"\n\"Using the current slider settings for the reference shape, create a new \"\n\"reference that will morph from the current shape back to the base shape.\"\nmsgstr \"\"\n\"Referans şekli için mevcut kaydırıcı ayarlarını kullanarak, mevcut şekilden \"\n\"taban şekline dönüşecek yeni bir referans oluştur.\"\n\n#: res/xrc/OutfitStudio.xrc:1750 res/xrc/Project.xrc:947\nmsgid \"Pack Projects...\"\nmsgstr \"Paket Projeler...\"\n\n#: res/xrc/OutfitStudio.xrc:1751\nmsgid \"Pack one or more projects into a folder or archive for sharing.\"\nmsgstr \"\"\n\"Bir veya daha fazla projeyi paylaşmak üzere bir klasöre veya arşive paketle.\"\n\n#: res/xrc/OutfitStudio.xrc:1758\nmsgid \"Exit\\tAlt+F4\"\nmsgstr \"Kapat\\tAlt+F4\"\n\n#: res/xrc/OutfitStudio.xrc:1759\nmsgid \"Exit Outfit Studio.\"\nmsgstr \"Kapat Outfit Studio.\"\n\n#: res/xrc/OutfitStudio.xrc:1774\nmsgid \"X Mirror\\tX\"\nmsgstr \"Yansıtma X\\tX\"\n\n#: res/xrc/OutfitStudio.xrc:1782\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius\"\nmsgstr \"\"\n\"Fırça yarıçapı içindeki boyamanın altındakilere bağlı olan yalnızca köşe \"\n\"noktalarını düzenle\"\n\n#: res/xrc/OutfitStudio.xrc:1824\nmsgid \"Recalculate Normals\\tR\"\nmsgstr \"Yeniden Hesaplama Normali\\tR\"\n\n#: res/xrc/OutfitStudio.xrc:1825\nmsgid \"Recalculate normals on active mesh\"\nmsgstr \"Aktif kafeste normal değerleri yeniden hesapla\"\n\n#: res/xrc/OutfitStudio.xrc:1828\nmsgid \"Reset Transforms\"\nmsgstr \"Dönüşümü Sıfırla\"\n\n#: res/xrc/OutfitStudio.xrc:1829\nmsgid \"Resets the shape and skin transforms.\"\nmsgstr \"Kalıpları ve cilt dönüşümlerini sıfırlar.\"\n\n#: res/xrc/OutfitStudio.xrc:1832 src/program/OutfitStudio.cpp:10232\nmsgid \"Delete Unreferenced Nodes\"\nmsgstr \"Örneklenmeyen Düğümleri Sil\"\n\n#: res/xrc/OutfitStudio.xrc:1833\nmsgid \"Deletes all nodes from the project that aren't used in any other block.\"\nmsgstr \"Başka bir blokta kullanılmayan tüm düğümleri projeden siler.\"\n\n#: res/xrc/OutfitStudio.xrc:1836\nmsgid \"Remove Skinning\"\nmsgstr \"Kaplamayı Kaldır\"\n\n#: res/xrc/OutfitStudio.xrc:1837\nmsgid \"Removes skinning of all shapes and all unused nodes.\"\nmsgstr \"Tüm kalıpların ve kullanılmayan tüm düğümlerin kaplamasını kaldırır.\"\n\n#: res/xrc/OutfitStudio.xrc:1841 res/xrc/OutfitStudio.xrc:2311\nmsgid \"Shape\"\nmsgstr \"Model\"\n\n#: res/xrc/OutfitStudio.xrc:1845 res/xrc/OutfitStudio.xrc:2315\nmsgid \"To NIF...\"\nmsgstr \"NIF olarak...\"\n\n#: res/xrc/OutfitStudio.xrc:1846 res/xrc/OutfitStudio.xrc:2316\nmsgid \"Export only the selected shapes to a NIF file.\"\nmsgstr \"Bir NIF dosyasını kıyafette yeni bir kalıp olarak içe aktar.\"\n\n#: res/xrc/OutfitStudio.xrc:1850 res/xrc/OutfitStudio.xrc:2320\nmsgid \"Export only the selected shapes to an OBJ file.\"\nmsgstr \"\"\n\"Geçerli kaydırıcının verilerini BodySlide OBJ dosyası olarak kaydederek dışa \"\n\"aktarır.\"\n\n#: res/xrc/OutfitStudio.xrc:1854 res/xrc/OutfitStudio.xrc:2324\nmsgid \"Export only the selected shapes to an FBX file.\"\nmsgstr \"Seçilen modeli bir FBX kalıbı olarak dışa aktar.\"\n\n#: res/xrc/OutfitStudio.xrc:1862 res/xrc/OutfitStudio.xrc:2332\n#: res/xrc/Slider.xrc:200\nmsgid \"UV\"\nmsgstr \"UV\"\n\n#: res/xrc/OutfitStudio.xrc:1864 res/xrc/OutfitStudio.xrc:2334\nmsgid \"Edit...\"\nmsgstr \"Düzenle...\"\n\n#: res/xrc/OutfitStudio.xrc:1865 res/xrc/OutfitStudio.xrc:2335\nmsgid \"Edit the texture coordinates.\"\nmsgstr \"Doku (texture) koordinatlarını düzenle.\"\n\n#: res/xrc/OutfitStudio.xrc:1868 res/xrc/OutfitStudio.xrc:2338\nmsgid \"Invert X\"\nmsgstr \"X Yöne Çevir\"\n\n#: res/xrc/OutfitStudio.xrc:1869 res/xrc/OutfitStudio.xrc:2339\nmsgid \"Inverts the X-axis of the texture coordinates.\"\nmsgstr \"Textures doku dosyalarını X-ekseni tarafına doğru çevir.\"\n\n#: res/xrc/OutfitStudio.xrc:1872 res/xrc/OutfitStudio.xrc:2342\nmsgid \"Invert Y\"\nmsgstr \"Y Yöne Çevir\"\n\n#: res/xrc/OutfitStudio.xrc:1873 res/xrc/OutfitStudio.xrc:2343\nmsgid \"Inverts the Y-axis of the texture coordinates.\"\nmsgstr \"Textures doku dosyalarını Y-ekseni tarafına doğru çevir.\"\n\n#: res/xrc/OutfitStudio.xrc:1877 res/xrc/OutfitStudio.xrc:2347\nmsgid \"Mirror\"\nmsgstr \"Yansıt\"\n\n#: res/xrc/OutfitStudio.xrc:1880 res/xrc/OutfitStudio.xrc:2350\nmsgid \"Mirror the selected shapes on the X-axis.\"\nmsgstr \"Seçilen modelleri X-eksenine doğru yansıt.\"\n\n#: res/xrc/OutfitStudio.xrc:1884 res/xrc/OutfitStudio.xrc:2354\nmsgid \"Mirror the selected shapes on the Y-axis.\"\nmsgstr \"Seçilen modelleri Y-eksenine doğru yansıt.\"\n\n#: res/xrc/OutfitStudio.xrc:1888 res/xrc/OutfitStudio.xrc:2358\nmsgid \"Mirror the selected shapes on the Z-axis.\"\nmsgstr \"Seçilen modelleri Z-eksenine doğru yansıt.\"\n\n#: res/xrc/OutfitStudio.xrc:1892 res/xrc/OutfitStudio.xrc:2362\nmsgid \"Delete Vertices...\\tShift+Del\"\nmsgstr \"Köşeleri Sil...\\tShift+Del\"\n\n#: res/xrc/OutfitStudio.xrc:1893 res/xrc/OutfitStudio.xrc:2363\nmsgid \"Deletes all unmasked vertices of the currently selected shapes.\"\nmsgstr \"Seçili modellerin tüm maskelenmemiş köşelerini siler.\"\n\n#: res/xrc/OutfitStudio.xrc:1896 res/xrc/OutfitStudio.xrc:2366\nmsgid \"Separate Vertices...\\tShift+S\"\nmsgstr \"Ayrışmış Köşeler...\\tShift+S\"\n\n#: res/xrc/OutfitStudio.xrc:1897 res/xrc/OutfitStudio.xrc:2367\nmsgid \"Separate the current shape into two by using the mask.\"\nmsgstr \"Maskeyi kullanarak mevcut modeli ikiye ayır.\"\n\n#: res/xrc/OutfitStudio.xrc:1900 res/xrc/OutfitStudio.xrc:2370\nmsgid \"Merge Geometry...\"\nmsgstr \"Geometriyi Birleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:1901 res/xrc/OutfitStudio.xrc:2371\nmsgid \"Copies vertices and triangles from one shape to another.\"\nmsgstr \"Köşeleri ve üçgenleri bir şekilden diğerine kopyalar.\"\n\n#: res/xrc/OutfitStudio.xrc:1904 res/xrc/OutfitStudio.xrc:2374\nmsgid \"Duplicate...\"\nmsgstr \"Tekrarla...\"\n\n#: res/xrc/OutfitStudio.xrc:1905 res/xrc/OutfitStudio.xrc:2375\nmsgid \"Duplicate the current shape.\"\nmsgstr \"Geçerli modeli tekrarla.\"\n\n#: res/xrc/OutfitStudio.xrc:1908 res/xrc/OutfitStudio.xrc:2378\nmsgid \"Refine Mesh\"\nmsgstr \"Ağ Düzeltme\"\n\n#: res/xrc/OutfitStudio.xrc:1909 res/xrc/OutfitStudio.xrc:2379\nmsgid \"Splits all edges between unmasked vertices\"\nmsgstr \"Maskelenmemiş köşeler arasında tüm kenarları böler\"\n\n#: res/xrc/OutfitStudio.xrc:1912 res/xrc/OutfitStudio.xrc:2382\nmsgid \"Rename...\\tF2\"\nmsgstr \"Ad Değiştir...\\tF2\"\n\n#: res/xrc/OutfitStudio.xrc:1913 res/xrc/OutfitStudio.xrc:2383\nmsgid \"Change the name of the current shape.\"\nmsgstr \"Geçerli modelin adını değiştir.\"\n\n#: res/xrc/OutfitStudio.xrc:1916 res/xrc/OutfitStudio.xrc:2386\nmsgid \"Set Reference\"\nmsgstr \"Örnek Kurulumu\"\n\n#: res/xrc/OutfitStudio.xrc:1917 res/xrc/OutfitStudio.xrc:2387\nmsgid \"Turn the shape into the reference shape of the project.\"\nmsgstr \"Dönüştürülen projeyi örnek model olarak kaydet.\"\n\n#: res/xrc/OutfitStudio.xrc:1921 res/xrc/OutfitStudio.xrc:2391\nmsgid \"Move...\"\nmsgstr \"Hareket...\"\n\n#: res/xrc/OutfitStudio.xrc:1922 res/xrc/OutfitStudio.xrc:2392\nmsgid \"\"\n\"Apply an offset adjustment to the mesh vertices. This permanently moves \"\n\"vertices.\"\nmsgstr \"\"\n\"Kafes köşelerine bir dengeleme ayarı uygula. Bu kalıcı olarak köşe \"\n\"noktalarını düzenleyecek.\"\n\n#: res/xrc/OutfitStudio.xrc:1925 res/xrc/OutfitStudio.xrc:2395\nmsgid \"Scale...\"\nmsgstr \"Derece...\"\n\n#: res/xrc/OutfitStudio.xrc:1926 res/xrc/OutfitStudio.xrc:2396\nmsgid \"Apply a scale adjustment to the shape. This permanently moves vertices.\"\nmsgstr \"\"\n\"Modele bir ölçek derecesi ayarını uygula. Bu kalıcı olarak köşe noktalarını \"\n\"düzenleyecek.\"\n\n#: res/xrc/OutfitStudio.xrc:1929 res/xrc/OutfitStudio.xrc:2399\nmsgid \"Rotate...\"\nmsgstr \"Dönüş...\"\n\n#: res/xrc/OutfitStudio.xrc:1930 res/xrc/OutfitStudio.xrc:2400\nmsgid \"Apply a rotation to the mesh vertices. This permanently moves vertices.\"\nmsgstr \"\"\n\"Modele bir dönüş derecesi ayarını uygula. Bu kalıcı olarak köşe noktalarını \"\n\"düzenleyecek.\"\n\n#: res/xrc/OutfitStudio.xrc:1933\nmsgid \"Smooth Seam Normals\"\nmsgstr \"Pürüzsüz Dikiş Standartı\"\n\n#: res/xrc/OutfitStudio.xrc:1934\nmsgid \"\"\n\"Smooths edges of seams (usually found at texture borders), disable if this \"\n\"causes odd normals on the shape.\"\nmsgstr \"\"\n\"Dikişlerin kenarlarını pürüzsüzleştirir (genellikle doku sınırlarında \"\n\"bulunur), bu durum model üzerindeki tuhaf şekillere neden oluyorsa devre \"\n\"dışı bırakabilirsin.\"\n\n#: res/xrc/OutfitStudio.xrc:1939\nmsgid \"Lock Normals\"\nmsgstr \"Standart Kilidi\"\n\n#: res/xrc/OutfitStudio.xrc:1940\nmsgid \"\"\n\"Locks the mesh normals. Enable if you want to keep custom normals intact.\"\nmsgstr \"\"\n\"Kafes kenarlarını kilitler. Özel yapılandırmayı bozmak istemiyorsan bunu \"\n\"etkinleştir.\"\n\n#: res/xrc/OutfitStudio.xrc:1947 res/xrc/OutfitStudio.xrc:2405\nmsgid \"Copies all bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\"Tüm beden ağırlıklarını referans aldığı modelden mevcut modele kopyalar.\"\n\n#: res/xrc/OutfitStudio.xrc:1950 res/xrc/OutfitStudio.xrc:2408\nmsgid \"Copy Selected Weights\"\nmsgstr \"Seçilen Ağırlıkları Kopyala\"\n\n#: res/xrc/OutfitStudio.xrc:1951 res/xrc/OutfitStudio.xrc:2409\nmsgid \"\"\n\"Copies selected bone weights from the reference shape to the current shape.\"\nmsgstr \"\"\n\"Tercihe göre seçilen beden ağırlıklarını referans aldığı modelden mevcut \"\n\"modele kopyalar.\"\n\n#: res/xrc/OutfitStudio.xrc:1954 res/xrc/OutfitStudio.xrc:2412\nmsgid \"Transfer Selected Weights\"\nmsgstr \"Seçilen Ağırlıkları Aktar\"\n\n#: res/xrc/OutfitStudio.xrc:1955 res/xrc/OutfitStudio.xrc:2413\nmsgid \"\"\n\"Transfers selected weights from the reference shape to the current shape. \"\n\"Requires same vertex count and order.\"\nmsgstr \"\"\n\"Referans modelinden seçilen şekil ağırlıklarını aktarır. Aynı köşegen \"\n\"açıları sayısını ve kodlamasını gerektirir.\"\n\n#: res/xrc/OutfitStudio.xrc:1958 res/xrc/OutfitStudio.xrc:2416\n#: res/xrc/OutfitStudio.xrc:2491\nmsgid \"Mask Weighted Vertices\"\nmsgstr \"Kafes Ağırlıklarını Maskele\"\n\n#: res/xrc/OutfitStudio.xrc:1959 res/xrc/OutfitStudio.xrc:2417\nmsgid \"\"\n\"Masks vertices with bone weights, so you can manually assign weights to \"\n\"unweighted vertices.\"\nmsgstr \"\"\n\"Kemik ağırlıklarına sahip köşeleri maskeleyerek ağırlık atamasını sıfırlar, \"\n\"böylece istediğin değerleri ağırlıksız köşelere elle atayabilirsin.\"\n\n#: res/xrc/OutfitStudio.xrc:1962\nmsgid \"Check For Bad Bones...\"\nmsgstr \"Hatalı İskelet Kontrolü...\"\n\n#: res/xrc/OutfitStudio.xrc:1963 res/xrc/OutfitStudio.xrc:2421\nmsgid \"\"\n\"Looks for bones with inconsistencies in their transforms.  If any are found, \"\n\"a dialog is opened to give options for fixing them.\"\nmsgstr \"\"\n\"Dönüşümlerinde tutarsızlık yapan iskelet yapılarını arar. Hatalı iskelet \"\n\"bulunursa, bunu düzeltmek için seçenekler sunan bir iletişim kutusu açılır.\"\n\n#: res/xrc/OutfitStudio.xrc:1967 res/xrc/OutfitStudio.xrc:2425\nmsgid \"Copy Partitions/Segments...\"\nmsgstr \"Kopyala Bölümler/Parçalar...\"\n\n#: res/xrc/OutfitStudio.xrc:1968 res/xrc/OutfitStudio.xrc:2426\nmsgid \"\"\n\"Copies partitions/segments and all triangle assignments from the reference \"\n\"shape to the current shape.\"\nmsgstr \"\"\n\"Bölümleri/parçaları ve tüm üçgen atamalarını referans alınan örnek kalıptan \"\n\"geçerli kalıba kopyalar.\"\n\n#: res/xrc/OutfitStudio.xrc:1972 res/xrc/OutfitStudio.xrc:2430\nmsgid \"Mask Symmetric Vertices...\"\nmsgstr \"Simetrik Köşeleri Maskele...\"\n\n#: res/xrc/OutfitStudio.xrc:1973 res/xrc/OutfitStudio.xrc:2431\nmsgid \"\"\n\"Masks unmasked vertices that have a mirrored vertex with identical data.\"\nmsgstr \"\"\n\"Aynı verilere sahip tepe noktalarını maskelenmemiş olan tepe noktalarına \"\n\"maskeler.\"\n\n#: res/xrc/OutfitStudio.xrc:1976 res/xrc/OutfitStudio.xrc:2434\nmsgid \"Symmetrize Vertices...\"\nmsgstr \"Tepe Noktalarını Simetrileştir...\"\n\n#: res/xrc/OutfitStudio.xrc:1977 res/xrc/OutfitStudio.xrc:2435\nmsgid \"Changes vertex data to be identical to mirrored vertices.\"\nmsgstr \"\"\n\"Tepe noktası verilerini yansıtılmış köşelerle aynı olacak şekilde değiştirir.\"\n\n#: res/xrc/OutfitStudio.xrc:1980 res/xrc/OutfitStudio.xrc:2438\nmsgid \"Mask Symmetric Triangles\"\nmsgstr \"Üçgenleri Simetrik Maskele\"\n\n#: res/xrc/OutfitStudio.xrc:1981 res/xrc/OutfitStudio.xrc:2439\nmsgid \"Masks triangles that can be matched to a mirrored triangle.\"\nmsgstr \"Yansıtılmış bir üçgenle eşleşen tüm üçgenleri maskeler.\"\n\n#: res/xrc/OutfitStudio.xrc:1985 res/xrc/OutfitStudio.xrc:2443\nmsgid \"Delete\\tDel\"\nmsgstr \"Sil\\tDel\"\n\n#: res/xrc/OutfitStudio.xrc:1986 res/xrc/OutfitStudio.xrc:2444\nmsgid \"Removes the currently selected shape from the outfit.\"\nmsgstr \"Mevcut kıyafetlerden seçili kalıbı kaldırır.\"\n\n#: res/xrc/OutfitStudio.xrc:1989 res/xrc/OutfitStudio.xrc:2447\nmsgid \"Properties...\"\nmsgstr \"Özellikler...\"\n\n#: res/xrc/OutfitStudio.xrc:1990 res/xrc/OutfitStudio.xrc:2448\nmsgid \"\"\n\"Opens the properties dialog for shader, texture and more settings of the \"\n\"selected shape.\"\nmsgstr \"\"\n\"Gölgelendirici, doku ve seçilen kalıbın daha fazla ayarları için özellikler \"\n\"iletişim kutusunu açar.\"\n\n#: res/xrc/OutfitStudio.xrc:1994\nmsgid \"Slider\"\nmsgstr \"Kaydırıcı\"\n\n#: res/xrc/OutfitStudio.xrc:1996\nmsgid \"Conform Selected\\tCtrl+C\"\nmsgstr \"Seçimi Uydur\\tCtrl+C\"\n\n#: res/xrc/OutfitStudio.xrc:1997\nmsgid \"Conform selected outfit shape to all checked sliders.\"\nmsgstr \"\"\n\"Seçilen kaydırıcılara tercih edilen kıyafet kalıbını uygun hale getirir.\"\n\n#: res/xrc/OutfitStudio.xrc:2000\nmsgid \"Conform All\\tCtrl+Shift+C\"\nmsgstr \"Tümünü Uydur\\tCtrl+Shift+C\"\n\n#: res/xrc/OutfitStudio.xrc:2001\nmsgid \"Conform all outfit shapes to all checked sliders.\"\nmsgstr \"Tüm kaydırıcılara seçilen kıyafet kalıbını uygun hale getirir.\"\n\n#: res/xrc/OutfitStudio.xrc:2005\nmsgid \"Set Base Shape\"\nmsgstr \"Temel Kalıbı Ayarla\"\n\n#: res/xrc/OutfitStudio.xrc:2006\nmsgid \"Set the current outfit shape as the base shape and clear slider data.\"\nmsgstr \"\"\n\"Mevcut kıyafet kalıbını ana şablon olarak ayarla ve kaydırıcı verilerini \"\n\"temizle.\"\n\n#: res/xrc/OutfitStudio.xrc:2011\nmsgid \"\"\n\"Load and preview a slider preset. Inverted sliders will have inverted values.\"\nmsgstr \"\"\n\"Hazır kaydırıcı ayarını yükle ve ön izlemeye al. Ters kaydırıcılar, ters \"\n\"değerlere sahip olacaktır.\"\n\n#: res/xrc/OutfitStudio.xrc:2015\nmsgid \"\"\n\"Save a slider preset with the current values. Inverted sliders will have \"\n\"inverted values.\"\nmsgstr \"\"\n\"Hazır kaydırıcı ayarını mevcut değerleri ile kaydet. Ters kaydırıcılar, ters \"\n\"değerlere sahip olacaktır.\"\n\n#: res/xrc/OutfitStudio.xrc:2019\nmsgid \"New Slider\"\nmsgstr \"Yeni Kaydırıcı Gurup\"\n\n#: res/xrc/OutfitStudio.xrc:2020\nmsgid \"Create a new shape transformation slider.\"\nmsgstr \"Yeni bir kalıp dönüştürme kaydırıcısı oluştur.\"\n\n#: res/xrc/OutfitStudio.xrc:2023\nmsgid \"Coalesce sliders\"\nmsgstr \"Birleşik Kaydırıcılar\"\n\n#: res/xrc/OutfitStudio.xrc:2024\nmsgid \"\"\n\"Create a new shape transformation slider based on the current slider values\"\nmsgstr \"Mevcut kaydırıcı değerlerini uygulayarak yeni bir kalıp oluştur\"\n\n#: res/xrc/OutfitStudio.xrc:2027\nmsgid \"New Zap Slider\"\nmsgstr \"Yeni Zap Kaydırıcısı\"\n\n#: res/xrc/OutfitStudio.xrc:2028\nmsgid \"Create a new Zap slider based on unmasked vertices\"\nmsgstr \"Değer atanmayan köşelere yeni bir Zap kaydırıcısı oluştur\"\n\n#: res/xrc/OutfitStudio.xrc:2032\nmsgid \"Import OSD...\"\nmsgstr \"OSD Dosyası Yerleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:2033\nmsgid \"Imports OSD file and creates sliders for shapes with a matching name.\"\nmsgstr \"\"\n\"OSD dosyasını içe aktarır ve eşleşen ada sahip kalıplar için bir kaydırıcı \"\n\"oluşturur.\"\n\n#: res/xrc/OutfitStudio.xrc:2036\nmsgid \"Export OSD...\"\nmsgstr \"OSD olarak Çıkar...\"\n\n#: res/xrc/OutfitStudio.xrc:2037\nmsgid \"Exports all currently loaded slider data to an OSD file.\"\nmsgstr \"Yüklü olan tüm kaydırıcı verilerini bir OSD dosyası olarak aktarır.\"\n\n#: res/xrc/OutfitStudio.xrc:2040\nmsgid \"Import TRI Morphs...\"\nmsgstr \"TRI Morphs Dosyası olarak yerleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:2041\nmsgid \"\"\n\"Imports TRI morphs from a TRI file and creates sliders for shapes with a \"\n\"matching name.\"\nmsgstr \"\"\n\"Bir TRI morphs dosyasından verileri TRI dosyası olarak içe aktarır ve \"\n\"eşleşen ada sahip kalıplar için kaydırıcı oluşturur.\"\n\n#: res/xrc/OutfitStudio.xrc:2044\nmsgid \"Export TRI Morphs...\"\nmsgstr \"TRI Morphs Dosyası olarak Çıkar...\"\n\n#: res/xrc/OutfitStudio.xrc:2045\nmsgid \"Exports TRI morphs to a TRI file.\"\nmsgstr \"TRI morphs dosyası verilerini TRI dosyası olarak çıkarır.\"\n\n#: res/xrc/OutfitStudio.xrc:2048\nmsgid \"Export to OBJs...\"\nmsgstr \"OBJ Dosyası olarak Çıkar...\"\n\n#: res/xrc/OutfitStudio.xrc:2049\nmsgid \"Export all sliders to an OBJ file per slider.\"\nmsgstr \"Tüm kaydırıcıları farklı bir OBJ dosyası olarak kaydeder.\"\n\n#: res/xrc/OutfitStudio.xrc:2053\nmsgid \"Import Slider Data\"\nmsgstr \"Kaydırıcı Verisini Al\"\n\n#: res/xrc/OutfitStudio.xrc:2055\nmsgid \"Import NIF...\"\nmsgstr \"NIF Dosyası Yerleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:2056\nmsgid \"Import a NIF file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\"Bir NIF dosyasını içe aktarır ve geçerli kalıbın kaydırıcı verilerinin \"\n\"üzerine yazar.\"\n\n#: res/xrc/OutfitStudio.xrc:2059\nmsgid \"Import BSD...\"\nmsgstr \"BSD Dosyası Yerleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:2060\nmsgid \"\"\n\"Import a BodySlide BSD file and overwrites the current shape's slider data.\"\nmsgstr \"\"\n\"BodySlide BSD dosyasını içe aktarır ve geçerli kalıbın kaydırıcı verilerini \"\n\"üzerine yazar.\"\n\n#: res/xrc/OutfitStudio.xrc:2063\nmsgid \"Import OBJ...\"\nmsgstr \"OBJ Dosyası Yerleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:2064\nmsgid \"\"\n\"Import an OBJ file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"\"\n\"Geçerli kalıbın tepe noktalarıyla eşleşen bir OBJ dosyasını içe aktarır ve \"\n\"kaydırıcı verileri farkını hesaplar.\"\n\n#: res/xrc/OutfitStudio.xrc:2067\nmsgid \"Import FBX...\"\nmsgstr \"FBX Dosyası Yerleştir...\"\n\n#: res/xrc/OutfitStudio.xrc:2068\nmsgid \"\"\n\"Import an FBX file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"\"\n\"Geçerli kalıbın tepe noktalarıyla eşleşen bir FBX dosyasını içe aktarır ve \"\n\"kaydırıcı verileri farkını hesaplar.\"\n\n#: res/xrc/OutfitStudio.xrc:2073\nmsgid \"Export Slider Data\"\nmsgstr \"Kaydırıcı Verisini Çıkart\"\n\n#: res/xrc/OutfitStudio.xrc:2075\nmsgid \"Export NIF...\"\nmsgstr \"NIF olarak çıkart...\"\n\n#: res/xrc/OutfitStudio.xrc:2076\nmsgid \"Exports the current slider's data as a NIF file.\"\nmsgstr \"\"\n\"Geçerli kaydırıcının tüm verilerini bir NIF dosyası olarak dışa aktarır.\"\n\n#: res/xrc/OutfitStudio.xrc:2079\nmsgid \"Export BSD...\"\nmsgstr \"BSD olarak Çıkart...\"\n\n#: res/xrc/OutfitStudio.xrc:2080\nmsgid \"Exports the current slider's data as a BodySlide BSD file.\"\nmsgstr \"\"\n\"Geçerli kaydırıcının verilerini BodySlide BSD dosyası olarak kaydederek dışa \"\n\"aktarır.\"\n\n#: res/xrc/OutfitStudio.xrc:2083\nmsgid \"Export OBJ...\"\nmsgstr \"OBJ olarak Çıkart...\"\n\n#: res/xrc/OutfitStudio.xrc:2084\nmsgid \"Exports the current slider's data as an OBJ file.\"\nmsgstr \"\"\n\"Geçerli kaydırıcının verilerini BodySlide OBJ dosyası olarak kaydederek dışa \"\n\"aktarır.\"\n\n#: res/xrc/OutfitStudio.xrc:2090\nmsgid \"Negate Slider\"\nmsgstr \"Kaydırıcıyı İptal Et\"\n\n#: res/xrc/OutfitStudio.xrc:2091\nmsgid \"Negates the current slider, reversing it's effect\"\nmsgstr \"Geçerli kaydırıcıyı iptal eder, etkilerini geri alır\"\n\n#: res/xrc/OutfitStudio.xrc:2095\nmsgid \"Mask Affected Vertices\"\nmsgstr \"Uç Etki Maskesi\"\n\n#: res/xrc/OutfitStudio.xrc:2096\nmsgid \"Masks the vertices the slider is affecting for all selected shapes.\"\nmsgstr \"\"\n\"Kaydırma çubuğu ile seçilen tüm kalıpların etkilendiği tepe noktalarını \"\n\"maskeler.\"\n\n#: res/xrc/OutfitStudio.xrc:2100\nmsgid \"Clear Slider Data\"\nmsgstr \"Kaydırıcı Verilerini Temizle\"\n\n#: res/xrc/OutfitStudio.xrc:2101\nmsgid \"\"\n\"Erases the slider data without removing the slider itself. (Cannot be undone)\"\nmsgstr \"\"\n\"Kaydırıcının kendiliğinden kaldırmadığı kaydırıcı verilerini siler. (Geri \"\n\"alınamaz)\"\n\n#: res/xrc/OutfitStudio.xrc:2104\nmsgid \"Delete Slider\"\nmsgstr \"Kaydırıcıyı Sil\"\n\n#: res/xrc/OutfitStudio.xrc:2105\nmsgid \"Delete the active slider from the project. (Cannot be undone)\"\nmsgstr \"Etkin kaydırıcıyı projeden siler. (Geri Alınamaz)\"\n\n#: res/xrc/OutfitStudio.xrc:2109\nmsgid \"Properties...\\tTab\"\nmsgstr \"Özellikler...\\tTab\"\n\n#: res/xrc/OutfitStudio.xrc:2110 src/ui/wxSliderPanel.cpp:69\nmsgid \"Display and edit the active slider's properties.\"\nmsgstr \"Aktif kaydırıcının özelliklerini görüntüler ve düzenler.\"\n\n#: res/xrc/OutfitStudio.xrc:2115\nmsgid \"Tool\"\nmsgstr \"Araçlar\"\n\n#: res/xrc/OutfitStudio.xrc:2117\nmsgid \"Current Tool\"\nmsgstr \"Mevcut Araçlar\"\n\n#: res/xrc/OutfitStudio.xrc:2156\nmsgid \"\"\n\"Apply animation weight values for the currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"Seçili olan iskelet için animasyon ağırlık değerlerini uygular.\\n\"\n\"Ağırlığı düşürmek için ALT tuşuna basılı tut.\"\n\n#: res/xrc/OutfitStudio.xrc:2194\nmsgid \"Transform\\tF\"\nmsgstr \"Dönüştür\\tF\"\n\n#: res/xrc/OutfitStudio.xrc:2199\nmsgid \"Pivot\\tP\"\nmsgstr \"Eksen\\tP\"\n\n#: res/xrc/OutfitStudio.xrc:2204\nmsgid \"Vertex Edit\\tQ\"\nmsgstr \"Tepe Noktasını Düzenle\\tQ\"\n\n#: res/xrc/OutfitStudio.xrc:2205\nmsgid \"\"\n\"Shows vertex points and lets you mask/unmask them.\\n\"\n\"Without any brush active, click on a vertex to unmask it.\\n\"\n\"Hold down CTRL to mask it.\"\nmsgstr \"\"\n\"Köşe noktalarını gösterir ve bunları maskelemeni/maskeyi kaldırmanı sağlar.\\n\"\n\"Herhangi bir fırça etkin değilken, maskesini kaldırmak için bir tepe \"\n\"noktasına tıklayın.\\n\"\n\"Gizlemek için CTRL tuşunu basılı tutun.\"\n\n#: res/xrc/OutfitStudio.xrc:2210\nmsgid \"Increase Brush Size\\tShift++\"\nmsgstr \"Fırça Çapını Büyült\\tShift++\"\n\n#: res/xrc/OutfitStudio.xrc:2211\nmsgid \"Increase brush diameter\"\nmsgstr \"Fırça çapını büyült\"\n\n#: res/xrc/OutfitStudio.xrc:2214\nmsgid \"Decrease Brush Size\\tShift+-\"\nmsgstr \"Fırça Çapını Küçült\\tShift+-\"\n\n#: res/xrc/OutfitStudio.xrc:2215\nmsgid \"Decrease brush diameter\"\nmsgstr \"Fırça çapını küçült\"\n\n#: res/xrc/OutfitStudio.xrc:2218\nmsgid \"Increase Brush Strength\\tCtrl++\"\nmsgstr \"Fırça Kuvvetini Arttır\\tCtrl++\"\n\n#: res/xrc/OutfitStudio.xrc:2219\nmsgid \"Increase brush strength\"\nmsgstr \"Fırça kuvvetini arttır\"\n\n#: res/xrc/OutfitStudio.xrc:2222\nmsgid \"Decrease Brush Strength\\tCtrl+-\"\nmsgstr \"Fırça Kuvvetini Azalt\\tCtrl+-\"\n\n#: res/xrc/OutfitStudio.xrc:2223\nmsgid \"Decrease brush strength\"\nmsgstr \"Fırça kuvvetini azalt\"\n\n#: res/xrc/OutfitStudio.xrc:2227\nmsgid \"Mask Less\\tA\"\nmsgstr \"Maskeyi Küçült\\tA\"\n\n#: res/xrc/OutfitStudio.xrc:2228\nmsgid \"Mask Less\"\nmsgstr \"Maskeyi Küçült\"\n\n#: res/xrc/OutfitStudio.xrc:2231\nmsgid \"Mask More\\tD\"\nmsgstr \"Maske Daha Fazla\\tD\"\n\n#: res/xrc/OutfitStudio.xrc:2232\nmsgid \"Mask More\"\nmsgstr \"Maske Daha Fazlası\"\n\n#: res/xrc/OutfitStudio.xrc:2236\nmsgid \"Invert Mask\\tCtrl+I\"\nmsgstr \"Maskeyi Ters Çevir\\tCtrl+I\"\n\n#: res/xrc/OutfitStudio.xrc:2237\nmsgid \"Invert Mask\"\nmsgstr \"Maskeyi Ters Çevir\"\n\n#: res/xrc/OutfitStudio.xrc:2240\nmsgid \"Clear Mask\\tCtrl+A\"\nmsgstr \"Maskeyi Temizle\\tCtrl+A\"\n\n#: res/xrc/OutfitStudio.xrc:2241\nmsgid \"Clear Mask\"\nmsgstr \"Maskeyi Temizle\"\n\n#: res/xrc/OutfitStudio.xrc:2245\nmsgid \"View\"\nmsgstr \"Gösterim\"\n\n#: res/xrc/OutfitStudio.xrc:2247\nmsgid \"Front\\tShift+1\"\nmsgstr \"Önden Görünüm\\tShift+1\"\n\n#: res/xrc/OutfitStudio.xrc:2250\nmsgid \"Back\\tShift+2\"\nmsgstr \"Arkadan Görünüm\\tShift+2\"\n\n#: res/xrc/OutfitStudio.xrc:2253\nmsgid \"Left\\tShift+3\"\nmsgstr \"Soldan Görünüm\\tShift+3\"\n\n#: res/xrc/OutfitStudio.xrc:2256\nmsgid \"Right\\tShift+4\"\nmsgstr \"Sağdan Görünüm\\tShift+4\"\n\n#: res/xrc/OutfitStudio.xrc:2259\nmsgid \"Perspective\\tShift+5\"\nmsgstr \"Derin Görünüm\\tShift+5\"\n\n#: res/xrc/OutfitStudio.xrc:2264\nmsgid \"Toggle Rotation Center\\tShift+R\"\nmsgstr \"Döndürme Komutu\\tShift+R\"\n\n#: res/xrc/OutfitStudio.xrc:2265\nmsgid \"Switch between the different rotation center modes.\"\nmsgstr \"Farklı dönüş merkezleri arasında geçiş yap.\"\n\n#: res/xrc/OutfitStudio.xrc:2268\nmsgid \"Show Nodes\\tShift+N\"\nmsgstr \"Düğümleri Göster\\tShift+N\"\n\n#: res/xrc/OutfitStudio.xrc:2272\nmsgid \"Show Bones\\tShift+B\"\nmsgstr \"İskeletleri Göster\\tShift+B\"\n\n#: res/xrc/OutfitStudio.xrc:2276\nmsgid \"Show Floor\\tG\"\nmsgstr \"Zemini Göster\\tG\"\n\n#: res/xrc/OutfitStudio.xrc:2281\nmsgid \"Toggle Visibility\\tE\"\nmsgstr \"Hayalet Modunda\\tE\"\n\n#: res/xrc/OutfitStudio.xrc:2282\nmsgid \"Switch between the different visibility modes for the selected shapes.\"\nmsgstr \"Kalıplar için farklı görünürlülük seçenekleri arasında geçiş yap.\"\n\n#: res/xrc/OutfitStudio.xrc:2285\nmsgid \"Show Wireframe\\tW\"\nmsgstr \"Tel Çerçeveyi Göster\\tW\"\n\n#: res/xrc/OutfitStudio.xrc:2286\nmsgid \"Show wireframe on all models.\"\nmsgstr \"Tüm modelleri tel bir kafes içerisinde gösterir.\"\n\n#: res/xrc/OutfitStudio.xrc:2290\nmsgid \"Enable Lighting\\tL\"\nmsgstr \"Aydınlatma Açık\\tL\"\n\n#: res/xrc/OutfitStudio.xrc:2291\nmsgid \"Turn on or off lighting.\"\nmsgstr \"Aydınlatmayı açar ve kapatır.\"\n\n#: res/xrc/OutfitStudio.xrc:2296\nmsgid \"Enable Textures\\tT\"\nmsgstr \"Dokuları Etkinleştir\\tT\"\n\n#: res/xrc/OutfitStudio.xrc:2297\nmsgid \"Display texture maps on models.\"\nmsgstr \"Tüm modellerin doku (texture) haritalarını gösterir.\"\n\n#: res/xrc/OutfitStudio.xrc:2302\nmsgid \"Enable Vertex Colors\"\nmsgstr \"Köşe Renklerini Etkinleştir\"\n\n#: res/xrc/OutfitStudio.xrc:2303\nmsgid \"Display vertex colors on models.\"\nmsgstr \"Modellemelerde köşe renklerini görüntüle.\"\n\n#: res/xrc/OutfitStudio.xrc:2420\nmsgid \"Check For Bad Bones\"\nmsgstr \"Hatalı İskeletleri Tara\"\n\n#: res/xrc/OutfitStudio.xrc:2454\nmsgid \"Bad Bone\"\nmsgstr \"Hatalı İskelet\"\n\n#: res/xrc/OutfitStudio.xrc:2456\nmsgid \"Set Skin Transform From Node\"\nmsgstr \"Düğümden Dış Görünümü Ayarla\"\n\n#: res/xrc/OutfitStudio.xrc:2457\nmsgid \"Fixes the bad bone by calculating a new skin-to-bone transform.\"\nmsgstr \"\"\n\"Yeni bir deri kaplaması ile iskelet dönüşümünü hesaplayarak bozuk iskeleti \"\n\"düzeltir.\"\n\n#: res/xrc/OutfitStudio.xrc:2460\nmsgid \"Set Node Transform From Skin\"\nmsgstr \"Düğüm Dönüşümü İçin Deri Kaplama\"\n\n#: res/xrc/OutfitStudio.xrc:2461\nmsgid \"\"\n\"Fixes the bad custom bone by calculating a new bone-to-global transform.\"\nmsgstr \"\"\n\"Yeni bir iskeletten küresel dönüşümü hesaplayarak hatalı iskeleti düzeltir.\"\n\n#: res/xrc/OutfitStudio.xrc:2465 res/xrc/OutfitStudio.xrc:2498\n#: res/xrc/ShapeProperties.xrc:263 res/xrc/ShapeProperties.xrc:421\n#: res/xrc/ShapeProperties.xrc:590\nmsgid \"Add\"\nmsgstr \"Yükle\"\n\n#: res/xrc/OutfitStudio.xrc:2467 res/xrc/OutfitStudio.xrc:2500\nmsgid \"From Skeleton...\"\nmsgstr \"İskelet Yapısı Hakkında...\"\n\n#: res/xrc/OutfitStudio.xrc:2468 res/xrc/OutfitStudio.xrc:2501\nmsgid \"Choose a bone from the reference skeleton to add to the project.\"\nmsgstr \"Projeye eklemek için örnek iskeletten bir kemik yapısını seç.\"\n\n#: res/xrc/OutfitStudio.xrc:2471 res/xrc/OutfitStudio.xrc:2504\nmsgid \"Custom Bone...\"\nmsgstr \"Kemik Yapısı Hakkında...\"\n\n#: res/xrc/OutfitStudio.xrc:2472 res/xrc/OutfitStudio.xrc:2505\nmsgid \"Add a custom bone to the project.\"\nmsgstr \"Projene bir kemik yapısı ekle.\"\n\n#: res/xrc/OutfitStudio.xrc:2478\nmsgid \"From Project\"\nmsgstr \"Proje Hakkında\"\n\n#: res/xrc/OutfitStudio.xrc:2479\nmsgid \"Delete bone(s) from all shapes of the project.\"\nmsgstr \"Kemik (iskelet yapısını) ve projenin tüm kalıplarını Sil.\"\n\n#: res/xrc/OutfitStudio.xrc:2482\nmsgid \"From Selected Shapes\"\nmsgstr \"Seçilen Kalıplar Hakkında\"\n\n#: res/xrc/OutfitStudio.xrc:2483\nmsgid \"Delete bone(s) from only the selected shapes.\"\nmsgstr \"Kemik (iskelet yapısını) ve projede uyguladığın bu kalıbı Sil.\"\n\n#: res/xrc/OutfitStudio.xrc:2487\nmsgid \"Edit Bone...\"\nmsgstr \"İskeleti Düzenle...\"\n\n#: res/xrc/OutfitStudio.xrc:2488\nmsgid \"Edit a custom bone or view a standard bone.\"\nmsgstr \"\"\n\"Özel bir kemik yapısını düzenleyin veya standart bir kemik yapısını \"\n\"görüntüleyin.\"\n\n#: res/xrc/OutfitStudio.xrc:2492\nmsgid \"Masks vertices with weights for the selected bones.\"\nmsgstr \"Köşeleri seçilen kemikler için ağırlık değerlerini maskeler.\"\n\n#: res/xrc/OutfitStudio.xrc:2512 res/xrc/OutfitStudio.xrc:2538\nmsgid \"Add Segment...\"\nmsgstr \"Bölümsel Ekleme...\"\n\n#: res/xrc/OutfitStudio.xrc:2513 res/xrc/OutfitStudio.xrc:2539\nmsgid \"Choose a segment to add to the shape.\"\nmsgstr \"Kalıba eklemek için iskeletin bir bölümünü seç.\"\n\n#: res/xrc/OutfitStudio.xrc:2516 res/xrc/OutfitStudio.xrc:2527\nmsgid \"Add Sub Segment...\"\nmsgstr \"Alt Bölüm Eklemesi...\"\n\n#: res/xrc/OutfitStudio.xrc:2517 res/xrc/OutfitStudio.xrc:2528\nmsgid \"Add a new sub segment to the currently selected segment.\"\nmsgstr \"Kalıba eklemek için iskeletin alt katmanını seç.\"\n\n#: res/xrc/OutfitStudio.xrc:2520\nmsgid \"Delete Segment...\"\nmsgstr \"Ana Bölümü Sil...\"\n\n#: res/xrc/OutfitStudio.xrc:2521\nmsgid \"Delete segment and all of its sub segments from the shape.\"\nmsgstr \"Bölümleri ve tüm alt segmentlerini kalıptan sil.\"\n\n#: res/xrc/OutfitStudio.xrc:2525\nmsgid \"Sub Segments\"\nmsgstr \"Alt Bölümler\"\n\n#: res/xrc/OutfitStudio.xrc:2531\nmsgid \"Delete Sub Segment...\"\nmsgstr \"Alt Bölümleri Sil...\"\n\n#: res/xrc/OutfitStudio.xrc:2532\nmsgid \"Delete the selected sub segment.\"\nmsgstr \"Seçili tüm alt bölümleri sil.\"\n\n#: res/xrc/OutfitStudio.xrc:2545 res/xrc/OutfitStudio.xrc:2556\nmsgid \"Add Partition...\"\nmsgstr \"Bölüm Ekle...\"\n\n#: res/xrc/OutfitStudio.xrc:2546 res/xrc/OutfitStudio.xrc:2557\nmsgid \"Adds a new partition to the shape.\"\nmsgstr \"Kalıba yeni bir bölüm ekler.\"\n\n#: res/xrc/OutfitStudio.xrc:2549\nmsgid \"Delete Partition...\"\nmsgstr \"Bölümü Sil...\"\n\n#: res/xrc/OutfitStudio.xrc:2550\nmsgid \"Deletes the partition from the shape.\"\nmsgstr \"Kalıba eklenen yeni bölümü siler.\"\n\n#: res/xrc/Project.xrc:16\nmsgid \"\"\n\"Welcome to the New Project wizard!\\n\"\n\"\\n\"\n\"First, please choose a reference. Typically, this is a body (such as CBBE) \"\n\"or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"Yeni Proje Sihirbazına hoş geldin!\\n\"\n\"\\n\"\n\"Öncelikle, bir örnekten seçimini yapmalısın. Tipik olarak, bu bir beden \"\n\"olabilir (CBBE gibi) veya bir dönüştürme seti olabilir  (Vanilla'dan \"\n\"CBBE'ye) gibi, ve onlar kalıpları ile birlikte açılır.\"\n\n#: res/xrc/Project.xrc:32 res/xrc/Project.xrc:578\nmsgid \"Reference\"\nmsgstr \"Örnekler\"\n\n#: res/xrc/Project.xrc:50 res/xrc/Project.xrc:596\nmsgid \"From Template\"\nmsgstr \"Şablondan\"\n\n#: res/xrc/Project.xrc:69 res/xrc/Project.xrc:210 res/xrc/Project.xrc:272\n#: res/xrc/Project.xrc:615 res/xrc/Project.xrc:826 res/xrc/Project.xrc:898\nmsgid \"From File\"\nmsgstr \"Dosyadan\"\n\n#: res/xrc/Project.xrc:79 res/xrc/Project.xrc:625\nmsgid \"Select a project or NIF file\"\nmsgstr \"Çalışmak için Bir NIF dosyası seç\"\n\n#: res/xrc/Project.xrc:106 res/xrc/Project.xrc:652\nmsgid \"Slider Set:\"\nmsgstr \"Kaydırıcı Seti:\"\n\n#: res/xrc/Project.xrc:124 res/xrc/Project.xrc:670\nmsgid \"Shape:\"\nmsgstr \"Kalıp:\"\n\n#: res/xrc/Project.xrc:146 res/xrc/Project.xrc:692\nmsgid \"Clear Reference\"\nmsgstr \"Örneği Temizle\"\n\n#: res/xrc/Project.xrc:162\nmsgid \"Next, select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\"Sonrasında, çalışmak için bir kıyafeti/kafesi seç ve bunun için yeni bir \"\n\"isim gir.\"\n\n#: res/xrc/Project.xrc:177 res/xrc/Project.xrc:319 res/xrc/Project.xrc:793\nmsgid \"Display Name\"\nmsgstr \"İsmi Görüntüle\"\n\n#: res/xrc/Project.xrc:197 res/xrc/Project.xrc:813\nmsgid \"Outfit/Mesh\"\nmsgstr \"Kıyafet/Kafes\"\n\n#: res/xrc/Project.xrc:220 res/xrc/Project.xrc:836\nmsgid \"Select a file to load as an outfit/mesh\"\nmsgstr \"Bir kıyafeti/kafesi (meshes dosyaları) yüklemek için bir dosyadan seç\"\n\n#: res/xrc/Project.xrc:232 res/xrc/Project.xrc:848\nmsgid \"Clear Outfit\"\nmsgstr \"Kıyafeti Temizle\"\n\n#: res/xrc/Project.xrc:250 res/xrc/Project.xrc:876\nmsgid \"Textures\"\nmsgstr \"Dokular\"\n\n#: res/xrc/Project.xrc:257 res/xrc/Project.xrc:883\nmsgid \"Automatically search for textures\"\nmsgstr \"Otomatik olarak Doku ara\"\n\n#: res/xrc/Project.xrc:282 res/xrc/Project.xrc:908\nmsgid \"Select a texture file\"\nmsgstr \"Doku dosyasını seç\"\n\n#: res/xrc/Project.xrc:297\nmsgid \"Save Project As...\"\nmsgstr \"Projeyi Farklı Kaydet...\"\n\n#: res/xrc/Project.xrc:328\nmsgid \"The name of the outfit and slider set, as it will appear in BodySlide.\"\nmsgstr \"BodySlide menülerinde görünecek şekilde kıyafet ve beden adını gir.\"\n\n#: res/xrc/Project.xrc:337\nmsgid \"Copies the current display name to the project text fields below.\"\nmsgstr \"Geçerli olan adı aşağıdaki proje metin alanlarına kopyalar.\"\n\n#: res/xrc/Project.xrc:338\nmsgid \"To Project\"\nmsgstr \"Proje İçin\"\n\n#: res/xrc/Project.xrc:354\nmsgid \"Output File Name\"\nmsgstr \"Dosya Çıkış Adı\"\n\n#: res/xrc/Project.xrc:363\nmsgid \"\"\n\"The name of the outfit file that will end up in the game data path when \"\n\"BodySlide builds it. Should not include _1 or _0 in the name, e.g: \"\n\"lovelydress\"\nmsgstr \"\"\n\"BodySlide onu oluşturduğunda oyun veri yolunda kopyalanacak olan kıyafet \"\n\"dosyasının adı. Adında _1 veya _0 bulunmamalıdır, örn. sevgigeceliği\"\n\n#: res/xrc/Project.xrc:389\nmsgid \"Output Data Path\"\nmsgstr \"Çıkış Veri Yolu\"\n\n#: res/xrc/Project.xrc:398\nmsgid \"\"\n\"The location in the game's data path where BodySlide-built outfit files will \"\n\"be placed, e.g: meshes\\\\clothes\\\\lovelydress\"\nmsgstr \"\"\n\"BodySlide tarafından oluşturulan kıyafet dosyalarının yerleştirileceği \"\n\"oyunun veri klasörü konumu, örn .: meshes\\\\clothes\\\\sevgigeceliği\"\n\n#: res/xrc/Project.xrc:410\nmsgid \"\"\n\"If this is enabled, BodySlide creates a low and high weight model when it \"\n\"generates the final outfit.\"\nmsgstr \"\"\n\"Bu etkinleştirilirse, BodySlide son kıyafeti oluşturduğunda düşük ve yüksek \"\n\"ağırlıkta oluşuna göre bir örnek modeli oluşturur.\"\n\n#: res/xrc/Project.xrc:411\nmsgid \"Low/High Weight Output\"\nmsgstr \"Düşük/Yüksek Ağırlık Çıkışı\"\n\n#: res/xrc/Project.xrc:419\nmsgid \"\"\n\"If this is enabled, only one output file will be created (useful for single-\"\n\"weighted things like hair).\"\nmsgstr \"\"\n\"Bu etkinleştirilirse, yalnızca bir çıktı dosyası oluşturulur (saç ve kaş \"\n\"gibi tekil ağırlıklı şeyler için yararlıdır).\"\n\n#: res/xrc/Project.xrc:420\nmsgid \"Single Weight Output\"\nmsgstr \"Tekil Ağırlık Çıkışı\"\n\n#: res/xrc/Project.xrc:431\nmsgid \"Project\"\nmsgstr \"Proje\"\n\n#: res/xrc/Project.xrc:443\nmsgid \"Slider Set File\"\nmsgstr \"Kaydırıcı Ayar Dosyası\"\n\n#: res/xrc/Project.xrc:453\nmsgid \"The .osp slider set project file\"\nmsgstr \".osp slider (kaydırıcı) ayarlanmış proje dosyası\"\n\n#: res/xrc/Project.xrc:454\nmsgid \"Select slider set .osp file name\"\nmsgstr \"Kaydırıcı .osp dosyası adını Seç\"\n\n#: res/xrc/Project.xrc:472\nmsgid \"Shape Data Folder\"\nmsgstr \"Kalıp Veri Klasörü\"\n\n#: res/xrc/Project.xrc:482\nmsgid \"\"\n\"The folder where all the slider data will go, as well as the base outfit NIF \"\n\"file.\"\nmsgstr \"\"\n\"Tüm kaydırıcı verilerinin yanı sıra temel donanım olan NIF dosyasının da yer \"\n\"alacağı klasör.\"\n\n#: res/xrc/Project.xrc:483\nmsgid \"Select slider data folder\"\nmsgstr \"Kaydırıcı veri klasörünü seç\"\n\n#: res/xrc/Project.xrc:500\nmsgid \"Shape Data File\"\nmsgstr \"Kalıp Veri Dosyası\"\n\n#: res/xrc/Project.xrc:510\nmsgid \"The name of the output's base NIF file.\"\nmsgstr \"Oluşturulan temel NIF dosyasının adı.\"\n\n#: res/xrc/Project.xrc:511\nmsgid \"Select output NIF file name\"\nmsgstr \"Oluşturulan NIF dosyası adını Seç\"\n\n#: res/xrc/Project.xrc:523\nmsgid \"\"\n\"Outfits require the reference body to be a part of the output file. Disable \"\n\"this if you've already copied the reference over or you don't want it \"\n\"included.\"\nmsgstr \"\"\n\"Kıyafetler örnek gövdenin çıktı dosyasının bir parçası olmasını gerektirir. \"\n\"Örneği daha önce kopyaladıysan veya verilerini içermesini istemiyorsan bunu \"\n\"devre dışı bırak.\"\n\n#: res/xrc/Project.xrc:524\nmsgid \"Copy reference shape into output\"\nmsgstr \"Örnek kalıbı çıktıya kopyala\"\n\n#: res/xrc/Project.xrc:543 res/xrc/SavePreset.xrc:78\nmsgid \"&Save\"\nmsgstr \"&Kaydet\"\n\n#: res/xrc/Project.xrc:559\nmsgid \"Load Reference\"\nmsgstr \"Örnekten Yükle\"\n\n#: res/xrc/Project.xrc:568\nmsgid \"\"\n\"Please choose a reference. Typically, this is a body (such as CBBE) or a \"\n\"conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"Lütfen öncelikle, bir örnekten seçimini yap. Genellikle, bu bir beden \"\n\"olabilir (CBBE gibi) veya bir dönüştürme seti olabilir  (Vanilla'dan \"\n\"CBBE'ye) gibi, ve onlar kalıpları ile birlikte açılırlar.\"\n\n#: res/xrc/Project.xrc:704\nmsgid \"Merge\"\nmsgstr \"Birleşik\"\n\n#: res/xrc/Project.xrc:721\nmsgid \"Zaps\"\nmsgstr \"Zap'lar\"\n\n#: res/xrc/Project.xrc:722\nmsgid \"Merge existing zaps with new sliders\"\nmsgstr \"Mevcut zapları yeni kaydırıcılarla birleştir\"\n\n#: res/xrc/Project.xrc:732\nmsgid \"Merge new sliders with existing sliders\"\nmsgstr \"Yeni kaydırıcıları mevcut kalıplarla birleştir\"\n\n#: res/xrc/Project.xrc:769\nmsgid \"Load Outfit\"\nmsgstr \"Kıyafeti Yükle\"\n\n#: res/xrc/Project.xrc:778\nmsgid \"\"\n\"Please select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"\"\n\"Lütfen üzerinde çalışmak için bir kıyafet/kafes örgüsünü seç ve yeni bir \"\n\"isim ataması yap.\"\n\n#: res/xrc/Project.xrc:857\nmsgid \"Keep other shapes\"\nmsgstr \"Diğer Kalıpları Koru\"\n\n#: res/xrc/Project.xrc:981\nmsgid \"Group file (optional):\"\nmsgstr \"Grup dosyası (isteğe bağlı):\"\n\n#: res/xrc/Project.xrc:990\nmsgid \"Group file to pack (optional).\"\nmsgstr \"Grup paket dosyası (isteğe bağlı).\"\n\n#: res/xrc/Project.xrc:1007\nmsgid \"Merged file name:\"\nmsgstr \"Birleştirilmiş dosya adı:\"\n\n#: res/xrc/Project.xrc:1015\nmsgid \"File name to use for the merged project file.\"\nmsgstr \"Birleştirilmiş proje dosyası için kullanılacak dosya ismidir.\"\n\n#: res/xrc/Project.xrc:1041\nmsgid \"Pack Folder...\"\nmsgstr \"Dosyaları Paketle...\"\n\n#: res/xrc/Project.xrc:1050\nmsgid \"Pack Archive...\"\nmsgstr \"Arşivleri Paketle...\"\n\n#: res/xrc/Project.xrc:1067 src/program/OutfitStudio.cpp:3728\n#: src/program/OutfitStudio.cpp:6362 src/program/OutfitStudio.cpp:7222\n#: src/program/OutfitStudio.cpp:7333 src/program/OutfitStudio.cpp:10632\nmsgid \"Cancel\"\nmsgstr \"İptal\"\n\n#: res/xrc/SavePreset.xrc:6\nmsgid \"Enter preset name...\"\nmsgstr \"Hazır Ayarlardan seç...\"\n\n#: res/xrc/SavePreset.xrc:15\nmsgid \"Please enter a name for the new preset:\"\nmsgstr \"Lütfen yeni hazır ayar için bir isim yaz:\"\n\n#: res/xrc/SavePreset.xrc:38\nmsgid \"Select groups to assign to the new preset:\"\nmsgstr \"Yeni hazır ayarı atayacağın grupları seç:\"\n\n#: res/xrc/Settings.xrc:15\nmsgid \"Game\"\nmsgstr \"Oyun\"\n\n#: res/xrc/Settings.xrc:28 src/program/OutfitProject.cpp:5128\nmsgid \"Target Game\"\nmsgstr \"Hedef Oyun\"\n\n#: res/xrc/Settings.xrc:37\nmsgid \"Choose the target game you want to use the program for here.\"\nmsgstr \"Programı kullanmak istediğin hedef oyununu seç.\"\n\n#: res/xrc/Settings.xrc:66\nmsgid \"Game Data Path\"\nmsgstr \"Oyun Veri Yolu\"\n\n#: res/xrc/Settings.xrc:76\nmsgid \"Select the data path of the game...\"\nmsgstr \"Oyunun yüklü olduğu klasör konumunu seç...\"\n\n#: res/xrc/Settings.xrc:78\nmsgid \"Data path to load textures from.\"\nmsgstr \"Doku (textures) dosyalarından yüklemek ve oluşturmak için veri yolu.\"\n\n#: res/xrc/Settings.xrc:90\nmsgid \"Advanced\"\nmsgstr \"Gelişmiş Seçenekler\"\n\n#: res/xrc/Settings.xrc:107\nmsgid \"Output Path\"\nmsgstr \"Çıkış Veri Yolu\"\n\n#: res/xrc/Settings.xrc:117\nmsgid \"Select the output path...\"\nmsgstr \"Oyunun çıktı klasörü konumunu seç...\"\n\n#: res/xrc/Settings.xrc:119\nmsgid \"\"\n\"Data path to build files to. If empty, Game Data Path will be used instead.\"\nmsgstr \"\"\n\"Dosyaların oluşturulacağı veri klasörü. Eğer seçenek boş olarak \"\n\"işaretlenirse, bunun yerine orijinal Oyun Veri Yolu kullanılacak.\"\n\n#: res/xrc/Settings.xrc:136\nmsgid \"Project Path\"\nmsgstr \"Proje Klasörü\"\n\n#: res/xrc/Settings.xrc:146\nmsgid \"Select the project path...\"\nmsgstr \"Projeler için klasör yolunu seç...\"\n\n#: res/xrc/Settings.xrc:148\nmsgid \"\"\n\"Project path where files related to BodySlide are loaded from. If empty, \"\n\"executable directory will be used instead.\"\nmsgstr \"\"\n\"BodySlide ile ilgili dosyaların yüklendiği proje klasörüdür. Boşsa, bunun \"\n\"yerine yürütülebilir dizin kullanılacaktır.\"\n\n#: res/xrc/Settings.xrc:164\nmsgid \"\"\n\"With this turned on, BodySlide receives a new checkbox \\\"Force Body Normals\"\n\"\\\". Using it when building adds normal and tangent data to the body meshes \"\n\"(including bodies within outfits) for Skyrim. Use this only if you have a \"\n\"tangent space body mod.\"\nmsgstr \"\"\n\"Bu etkinleştirildiğinde, BodySlide yeni bir \\\"Force Body Normals\\\" Normal \"\n\"Beden Yapısı için onay kutusu alır. İnşa ederken kullanmak, Skyrim için \"\n\"gövde ağlarına (kıyafetlerdeki gövdeler dahil) normal ve yan verileri ekler. \"\n\"Bunu yalnızca ikincil bir beden modunuz varsa kullanın.\"\n\n#: res/xrc/Settings.xrc:165\nmsgid \"Show 'Force Body Normals'\"\nmsgstr \"Göster 'Normal Beden Yapısı'\"\n\n#: res/xrc/Settings.xrc:183\nmsgid \"General\"\nmsgstr \"Genel\"\n\n#: res/xrc/Settings.xrc:195\nmsgid \"\"\n\"Enables/disables the dialog for choosing which set to build during a batch \"\n\"build if overrides happen.\"\nmsgstr \"\"\n\"Geçersiz kılma gerçekleştiğinde hangi setin oluşturulacağını seçmek için \"\n\"iletişim kutusunu etkinleştirir/devre dışı bırakır.\"\n\n#: res/xrc/Settings.xrc:196\nmsgid \"Override Warning\"\nmsgstr \"Uyarıları Geçersiz Kıl\"\n\n#: res/xrc/Settings.xrc:205\nmsgid \"\"\n\"Enables/disables scanning BSAs in the game data folder for textures to load.\"\nmsgstr \"\"\n\"Yüklenecek dokular için oyun veri klasöründeki BSA dosyalarını taramayı \"\n\"etkinleştirir/devre dışı bırakır.\"\n\n#: res/xrc/Settings.xrc:206\nmsgid \"BSA Textures\"\nmsgstr \"BSA Doku Dosyaları\"\n\n#: res/xrc/Settings.xrc:223\nmsgid \"\"\n\"Enables/disables panning the camera with the left mouse button in Outfit \"\n\"Studio.\"\nmsgstr \"\"\n\"Outfit Studio'da kamerayı farenin sol tuşuyla çevirmeyi etkinleştirir/devre \"\n\"dışı bırakır.\"\n\n#: res/xrc/Settings.xrc:224\nmsgid \"Left Mouse Pan\"\nmsgstr \"Sol Fare Tuşu\"\n\n#: res/xrc/Settings.xrc:233\nmsgid \"\"\n\"Enables/disables opening the brush settings near the mouse cursor when \"\n\"hitting the 'space' key.\"\nmsgstr \"\"\n\"'Boşluk-Space' tuşuna basıldığında fare imlecinin yanında fırça ayarlarının \"\n\"açılmasını etkinleştirir/devre dışı bırakır.\"\n\n#: res/xrc/Settings.xrc:234\nmsgid \"Brush Settings Near Cursor\"\nmsgstr \"İmleç Yakınında Fırça Ayarları\"\n\n#: res/xrc/Settings.xrc:252\nmsgid \"Language\"\nmsgstr \"Dil Seçimi\"\n\n#: res/xrc/Settings.xrc:261\nmsgid \"Use the selected language for the program.\"\nmsgstr \"\"\n\"Programı Türkçe olarak kullanabilmek için dil ayarlarından Türkçe'yi seç..\"\n\n#: res/xrc/Settings.xrc:276\nmsgid \"Rendering\"\nmsgstr \"Kaplamalar\"\n\n#: res/xrc/Settings.xrc:289\nmsgid \"Background Color\"\nmsgstr \"Arkaplan Rengi\"\n\n#: res/xrc/Settings.xrc:298\nmsgid \"Background color of the renderer.\"\nmsgstr \"Arkaplan rengini düzenler.\"\n\n#: res/xrc/Settings.xrc:316\nmsgid \"Wireframe Color\"\nmsgstr \"Tel Kafesi Rengi\"\n\n#: res/xrc/Settings.xrc:325\nmsgid \"Wireframe color of the renderer.\"\nmsgstr \"Oluşturulan yeni tel kafesi için renk belirle.\"\n\n#: res/xrc/Settings.xrc:340\nmsgid \"Data Files\"\nmsgstr \"Veri Dosyaları\"\n\n#: res/xrc/Settings.xrc:358\nmsgid \"Reference Skeleton\"\nmsgstr \"Örnek İskelet\"\n\n#: res/xrc/Settings.xrc:381\nmsgid \"Select a reference skeleton .nif file...\"\nmsgstr \"Referans-Örnek iskeleti için .nif dosyasını seç...\"\n\n#: res/xrc/Settings.xrc:384\nmsgid \"The reference skeleton file for Outfit Studio.\"\nmsgstr \"Outfit Studio için referans iskelet dosyası.\"\n\n#: res/xrc/Settings.xrc:401\nmsgid \"Root Node\"\nmsgstr \"Temel Kodlama\"\n\n#: res/xrc/Settings.xrc:410\nmsgid \"\"\n\"The root node name of the reference skeleton. Can differ from game to game.\"\nmsgstr \"\"\n\"Referans iskeletin temel kod adı. Oyundan oyuna farklılık gösterebilir.\"\n\n#: res/xrc/Setup.xrc:5\nmsgid \"Setup\"\nmsgstr \"Kurulum\"\n\n#: res/xrc/Setup.xrc:15\nmsgid \"\"\n\"Please select the data folder and your target game.\\n\"\n\"You can only choose one game at a time, but it is possible to change the \"\n\"selection in the settings.\"\nmsgstr \"\"\n\"Lütfen data-veri klasörünü ve hedef oyununu seç.\\n\"\n\"Tek seferde yalnızca bir oyun seçebilirsin, ancak oyun seçimini ayar \"\n\"menüsünden değiştirmek mümkündür.\"\n\n#: res/xrc/Setup.xrc:44 res/xrc/Setup.xrc:73 res/xrc/Setup.xrc:102\n#: res/xrc/Setup.xrc:131 res/xrc/Setup.xrc:160 res/xrc/Setup.xrc:189\n#: res/xrc/Setup.xrc:218 res/xrc/Setup.xrc:247\nmsgid \"Game not found! Select the data folder manually...\"\nmsgstr \"\"\n\"Oyun bulunamadı! Oyunun Data-Veri klasör dizinini kendin belirtmelisin...\"\n\n#: res/xrc/Setup.xrc:45 res/xrc/Setup.xrc:74 res/xrc/Setup.xrc:103\n#: res/xrc/Setup.xrc:132 res/xrc/Setup.xrc:161 res/xrc/Setup.xrc:190\n#: res/xrc/Setup.xrc:219 res/xrc/Setup.xrc:248\nmsgid \"Select a folder\"\nmsgstr \"Klasör Konumunu Seç\"\n\n#: res/xrc/Setup.xrc:55 res/xrc/Setup.xrc:84 res/xrc/Setup.xrc:113\n#: res/xrc/Setup.xrc:142 res/xrc/Setup.xrc:171 res/xrc/Setup.xrc:200\n#: res/xrc/Setup.xrc:229 res/xrc/Setup.xrc:258\nmsgid \"Choose Game\"\nmsgstr \"Oyun Seç\"\n\n#: res/xrc/ShapeProperties.xrc:5\nmsgid \"Shape Properties\"\nmsgstr \"Kalıp Özellikleri\"\n\n#: res/xrc/ShapeProperties.xrc:16\nmsgid \"Shader\"\nmsgstr \"Ön Bellek\"\n\n#: res/xrc/ShapeProperties.xrc:31 res/xrc/ShapeProperties.xrc:608\n#: res/xrc/Skeleton.xrc:68\nmsgid \"Name\"\nmsgstr \"İsim\"\n\n#: res/xrc/ShapeProperties.xrc:102\nmsgid \"Specular Color\"\nmsgstr \"Yansıtıcı Renk\"\n\n#: res/xrc/ShapeProperties.xrc:120\nmsgid \"Specular Strength\"\nmsgstr \"Yansıtıcı Kuvvet\"\n\n#: res/xrc/ShapeProperties.xrc:139\nmsgid \"Specular Power\"\nmsgstr \"Yansıtıcı Güç\"\n\n#: res/xrc/ShapeProperties.xrc:179\nmsgid \"Emissive Color\"\nmsgstr \"Yayıcı Renk\"\n\n#: res/xrc/ShapeProperties.xrc:197\nmsgid \"Emissive Multiple\"\nmsgstr \"Yayıcı Katman\"\n\n#: res/xrc/ShapeProperties.xrc:216\nmsgid \"Alpha\"\nmsgstr \"Alfa\"\n\n#: res/xrc/ShapeProperties.xrc:235\nmsgid \"Vertex Colors\"\nmsgstr \"Uç Renkler\"\n\n#: res/xrc/ShapeProperties.xrc:272 res/xrc/ShapeProperties.xrc:430\nmsgid \"Remove\"\nmsgstr \"Sil\"\n\n#: res/xrc/ShapeProperties.xrc:281\nmsgid \"Textures...\"\nmsgstr \"Dokular...\"\n\n#: res/xrc/ShapeProperties.xrc:293\nmsgid \"Transparency\"\nmsgstr \"Şeffaflık\"\n\n#: res/xrc/ShapeProperties.xrc:316\nmsgid \"Threshold\"\nmsgstr \"Eşik Değeri\"\n\n#: res/xrc/ShapeProperties.xrc:356\nmsgid \"Vertex Alpha\"\nmsgstr \"Uç Alfa\"\n\n#: res/xrc/ShapeProperties.xrc:374\nmsgid \"Alpha Test\"\nmsgstr \"Alfa Testi\"\n\n#: res/xrc/ShapeProperties.xrc:392\nmsgid \"Alpha Blend\"\nmsgstr \"Alfa Karışımı\"\n\n#: res/xrc/ShapeProperties.xrc:443\nmsgid \"Copy from shape...\"\nmsgstr \"Kalıptan kopyala...\"\n\n#: res/xrc/ShapeProperties.xrc:451\nmsgid \"Geometry\"\nmsgstr \"Geometri\"\n\n#: res/xrc/ShapeProperties.xrc:471\nmsgid \"Full Precision\"\nmsgstr \"Tam Hassasiyet\"\n\n#: res/xrc/ShapeProperties.xrc:489\nmsgid \"Sub Index\"\nmsgstr \"Alt Endeks\"\n\n#: res/xrc/ShapeProperties.xrc:507\nmsgid \"Skinned\"\nmsgstr \"Deri-Cilt\"\n\n#: res/xrc/ShapeProperties.xrc:524\nmsgid \"Dynamic\"\nmsgstr \"Dinamik\"\n\n#: res/xrc/ShapeProperties.xrc:569\nmsgid \"Extra Data\"\nmsgstr \"Ekstra Veri\"\n\n#: res/xrc/ShapeProperties.xrc:617\nmsgid \"Value\"\nmsgstr \"Değer\"\n\n#: res/xrc/ShapeProperties.xrc:627\nmsgid \"Coordinates\"\nmsgstr \"Koordinat\"\n\n#: res/xrc/ShapeProperties.xrc:636\nmsgid \"Transform from shape to global coordinates:\"\nmsgstr \"Kalıptan küresel koordinatlara dönüştür:\"\n\n#: res/xrc/ShapeProperties.xrc:699 res/xrc/Skeleton.xrc:142\nmsgid \"Rotation\"\nmsgstr \"Dönüş Hareketleri\"\n\n#: res/xrc/Skeleton.xrc:6\nmsgid \"Select a bone to add\"\nmsgstr \"Eklenecek kemik yapısını seç\"\n\n#: res/xrc/Skeleton.xrc:15\nmsgid \"Bones in the current reference skeleton:\"\nmsgstr \"Örnek iskeletteki kemik yapısı:\"\n\n#: res/xrc/Skeleton.xrc:53\nmsgid \"Add Custom Bone\"\nmsgstr \"Özel Kemik Yapısı Ekle\"\n\n#: res/xrc/Skeleton.xrc:93\nmsgid \"Parent\"\nmsgstr \"Temel\"\n\n#: res/xrc/Slider.xrc:6\nmsgid \"Select a slider preset\"\nmsgstr \"Bir kaydırıcı hazır ayar seç\"\n\n#: res/xrc/Slider.xrc:15\nmsgid \"Choose a preset:\"\nmsgstr \"Hazır ayarı seç:\"\n\n#: res/xrc/Slider.xrc:40\nmsgid \"Low weight\"\nmsgstr \"Düsük ağırlık\"\n\n#: res/xrc/Slider.xrc:49\nmsgid \"High weight\"\nmsgstr \"Yüksek ağırlık\"\n\n#: res/xrc/Slider.xrc:81\nmsgid \"Slider Properties\"\nmsgstr \"Kaydırıcı Özellikleri\"\n\n#: res/xrc/Slider.xrc:91\nmsgid \"Slider Name\"\nmsgstr \"Kaydırıcı Adı\"\n\n#: res/xrc/Slider.xrc:108\nmsgid \"Default Values\"\nmsgstr \"Varsayılan Değerler\"\n\n#: res/xrc/Slider.xrc:114\nmsgid \"Low\"\nmsgstr \"Düsük\"\n\n#: res/xrc/Slider.xrc:131\nmsgid \"High\"\nmsgstr \"Yüksek\"\n\n#: res/xrc/Slider.xrc:148\nmsgid \"Zapped\"\nmsgstr \"Komuta Et\"\n\n#: res/xrc/Slider.xrc:173\nmsgid \"Invert\"\nmsgstr \"Ters Çevir\"\n\n#: res/xrc/Slider.xrc:182\nmsgid \"Hidden\"\nmsgstr \"Gizli\"\n\n#: res/xrc/Slider.xrc:191\nmsgid \"Zap\"\nmsgstr \"Zap\"\n\n#: res/xrc/Slider.xrc:211\nmsgid \"Toggle Zaps:\"\nmsgstr \"Aç/Kapa Zap:\"\n\n#: res/xrc/SliderDataImport.xrc:6\nmsgid \"Slider Data Import Options...\"\nmsgstr \"Kaydırıcı Veri İçe Aktarma Seçenekleri...\"\n\n#: res/xrc/SliderDataImport.xrc:21\nmsgid \"Select the shapes that slider data will be imported for:\"\nmsgstr \"Kaydırıcı verilerin içe aktarılacağı kalıpları seç:\"\n\n#: res/xrc/SliderDataImport.xrc:52\nmsgid \"Select the sliders to be imported\"\nmsgstr \"İçe aktarılacak kaydırıcıları seç\"\n\n#: src/components/Anim.cpp:570\nmsgid \"\"\n\"Bone information incomplete. Exported data will not contain correct bone \"\n\"entries! Be sure to load a reference NIF prior to export.\"\nmsgstr \"\"\n\"Kemik yapısı bilgisi eksik. Dışa aktarılan veriler doğru kemik girişlerini \"\n\"içermeyecektir! Kaydetmeden önce örnek bir NIF dosyasını yüklediğinden emin \"\n\"olmalısın.\"\n\n#: src/components/Anim.cpp:571\nmsgid \"Export Warning\"\nmsgstr \"Dışa Aktarma Tehlikesi\"\n\n#: src/components/Anim.cpp:689\n#, c-format\nmsgid \"Failed to load skeleton '%s'!\"\nmsgstr \"İskelet yüklemesi başarısız '%s'!\"\n\n#: src/components/Anim.cpp:697\n#, c-format\nmsgid \"Root '%s' not found in skeleton '%s'!\"\nmsgstr \"Temel '%s' iskelet bulunamadı '%s'!\"\n\n#: src/program/BodySlideApp.cpp:184 src/program/OutfitStudio.cpp:417\nmsgid \"\"\n\"No read/write permission for game data path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the game data \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"Oyun veri yolu için okuma/yazma izni yok!\\n\"\n\"\\n\"\n\"Lütfen programı yönetici modunda yeniden başlatın ve ayarlardaki oyun veri \"\n\"yolunun doğru olduğundan emin olun.\"\n\n#: src/program/BodySlideApp.cpp:185 src/program/BodySlideApp.cpp:195\n#: src/program/BodySlideApp.cpp:1436 src/program/OutfitStudio.cpp:418\n#: src/program/OutfitStudio.cpp:428 src/program/OutfitStudio.cpp:652\n#: src/program/OutfitStudio.cpp:659\nmsgid \"Warning\"\nmsgstr \"Uyarı\"\n\n#: src/program/BodySlideApp.cpp:194 src/program/OutfitStudio.cpp:427\nmsgid \"\"\n\"No read/write permission for project path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the project \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"Oyun veri yolu için okuma/yazma izni yok!\\n\"\n\"\\n\"\n\"Lütfen programı yönetici modunda yeniden başlatın ve ayarlardaki oyun veri \"\n\"yolunun doğru olduğundan emin olun.\"\n\n#: src/program/BodySlideApp.cpp:267 src/program/OutfitStudio.cpp:514\n#, c-format\nmsgid \"Unexpected exception has occurred: %s, the program will terminate.\"\nmsgstr \"Beklenmeyen bir hata oluştu: %s, program kapatılacak.\"\n\n#: src/program/BodySlideApp.cpp:267 src/program/OutfitStudio.cpp:514\nmsgid \"Unexpected exception\"\nmsgstr \"Beklenmeyen Hata\"\n\n#: src/program/BodySlideApp.cpp:290 src/program/OutfitStudio.cpp:534\n#, c-format\nmsgid \"Unhandled exception has occurred: %s, the program will terminate.\"\nmsgstr \"İşlenmeyen özel durum oluştu: %s, program kapatılacak.\"\n\n#: src/program/BodySlideApp.cpp:290 src/program/OutfitStudio.cpp:534\nmsgid \"Unhandled exception\"\nmsgstr \"İşlenme Hatası\"\n\n#: src/program/BodySlideApp.cpp:301 src/program/OutfitStudio.cpp:542\nmsgid \"Fatal exception has occurred, the program will terminate.\"\nmsgstr \"Tehlikeli bir hata oluştu, program kapatılacak.\"\n\n#: src/program/BodySlideApp.cpp:301 src/program/OutfitStudio.cpp:542\nmsgid \"Fatal exception\"\nmsgstr \"Tehlikeli Hata\"\n\n#: src/program/BodySlideApp.cpp:923\nmsgid \"Failed to launch Outfit Studio executable!\"\nmsgstr \"Outfit Studio yürütülebilir sürümü başlatılamadı!\"\n\n#: src/program/BodySlideApp.cpp:923 src/program/BodySlideApp.cpp:1457\n#: src/program/BodySlideApp.cpp:1751 src/program/BodySlideApp.cpp:2813\n#: src/program/BodySlideApp.cpp:2820 src/program/BodySlideApp.cpp:3554\n#: src/program/OutfitStudio.cpp:975 src/program/OutfitStudio.cpp:981\n#: src/program/OutfitStudio.cpp:1473 src/program/OutfitStudio.cpp:1484\n#: src/program/OutfitStudio.cpp:1520 src/program/OutfitStudio.cpp:1531\n#: src/program/OutfitStudio.cpp:1541 src/program/OutfitStudio.cpp:1550\n#: src/program/OutfitStudio.cpp:1561 src/program/OutfitStudio.cpp:1572\n#: src/program/OutfitStudio.cpp:1584 src/program/OutfitStudio.cpp:1623\n#: src/program/OutfitStudio.cpp:1631 src/program/OutfitStudio.cpp:1638\n#: src/program/OutfitStudio.cpp:1674 src/program/OutfitStudio.cpp:1682\n#: src/program/OutfitStudio.cpp:1689 src/program/OutfitStudio.cpp:1699\n#: src/program/OutfitStudio.cpp:1708 src/program/OutfitStudio.cpp:1716\n#: src/program/OutfitStudio.cpp:1723 src/program/OutfitStudio.cpp:1734\n#: src/program/OutfitStudio.cpp:1743 src/program/OutfitStudio.cpp:1750\n#: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2044\n#: src/program/OutfitStudio.cpp:2059 src/program/OutfitStudio.cpp:2144\n#: src/program/OutfitStudio.cpp:2153 src/program/OutfitStudio.cpp:2161\n#: src/program/OutfitStudio.cpp:2175 src/program/OutfitStudio.cpp:2184\n#: src/program/OutfitStudio.cpp:2190 src/program/OutfitStudio.cpp:2222\n#: src/program/OutfitStudio.cpp:3627 src/program/OutfitStudio.cpp:3634\n#: src/program/OutfitStudio.cpp:4281 src/program/OutfitStudio.cpp:4300\n#: src/program/OutfitStudio.cpp:4366 src/program/OutfitStudio.cpp:4402\n#: src/program/OutfitStudio.cpp:4421 src/program/OutfitStudio.cpp:4491\n#: src/program/OutfitStudio.cpp:4527 src/program/OutfitStudio.cpp:4546\n#: src/program/OutfitStudio.cpp:4571 src/program/OutfitStudio.cpp:4622\n#: src/program/OutfitStudio.cpp:4627 src/program/OutfitStudio.cpp:4641\n#: src/program/OutfitStudio.cpp:4648 src/program/OutfitStudio.cpp:4653\n#: src/program/OutfitStudio.cpp:4664 src/program/OutfitStudio.cpp:7033\n#: src/program/OutfitStudio.cpp:7091 src/program/OutfitStudio.cpp:7097\n#: src/program/OutfitStudio.cpp:7101 src/program/OutfitStudio.cpp:7112\n#: src/program/OutfitStudio.cpp:7122 src/program/OutfitStudio.cpp:7126\n#: src/program/OutfitStudio.cpp:7143 src/program/OutfitStudio.cpp:7147\n#: src/program/OutfitStudio.cpp:7158 src/program/OutfitStudio.cpp:7168\n#: src/program/OutfitStudio.cpp:7181 src/program/OutfitStudio.cpp:7296\n#: src/program/OutfitStudio.cpp:7309 src/program/OutfitStudio.cpp:7412\n#: src/program/OutfitStudio.cpp:7416 src/program/OutfitStudio.cpp:7427\n#: src/program/OutfitStudio.cpp:7437 src/program/OutfitStudio.cpp:7441\n#: src/program/OutfitStudio.cpp:7464 src/program/OutfitStudio.cpp:7473\n#: src/program/OutfitStudio.cpp:7477 src/program/OutfitStudio.cpp:7506\n#: src/program/OutfitStudio.cpp:7510 src/program/OutfitStudio.cpp:7533\n#: src/program/OutfitStudio.cpp:7542 src/program/OutfitStudio.cpp:7553\n#: src/program/OutfitStudio.cpp:7560 src/program/OutfitStudio.cpp:7571\n#: src/program/OutfitStudio.cpp:7578 src/program/OutfitStudio.cpp:7602\n#: src/program/OutfitStudio.cpp:7653 src/program/OutfitStudio.cpp:7715\n#: src/program/OutfitStudio.cpp:7719 src/program/OutfitStudio.cpp:7732\n#: src/program/OutfitStudio.cpp:7736 src/program/OutfitStudio.cpp:7947\n#: src/program/OutfitStudio.cpp:8114 src/program/OutfitStudio.cpp:8131\n#: src/program/OutfitStudio.cpp:8151 src/program/OutfitStudio.cpp:8175\n#: src/program/OutfitStudio.cpp:8209 src/program/OutfitStudio.cpp:8361\n#: src/program/OutfitStudio.cpp:8550 src/program/OutfitStudio.cpp:8700\n#: src/program/OutfitStudio.cpp:8755 src/program/OutfitStudio.cpp:8969\n#: src/program/OutfitStudio.cpp:8979 src/program/OutfitStudio.cpp:9020\n#: src/program/OutfitStudio.cpp:9025 src/program/OutfitStudio.cpp:9034\n#: src/program/OutfitStudio.cpp:9056 src/program/OutfitStudio.cpp:9220\n#: src/program/OutfitStudio.cpp:9228 src/program/OutfitStudio.cpp:9528\n#: src/program/OutfitStudio.cpp:9533 src/program/OutfitStudio.cpp:9619\n#: src/program/OutfitStudio.cpp:9624 src/program/OutfitStudio.cpp:9712\n#: src/program/OutfitStudio.cpp:9718 src/program/OutfitStudio.cpp:9723\n#: src/program/OutfitStudio.cpp:9730 src/program/OutfitStudio.cpp:9757\n#: src/program/OutfitStudio.cpp:9798 src/program/OutfitStudio.cpp:9845\n#: src/program/OutfitStudio.cpp:9850 src/program/OutfitStudio.cpp:9884\n#: src/program/OutfitStudio.cpp:10096 src/program/OutfitStudio.cpp:10142\n#: src/program/OutfitStudio.cpp:10245 src/program/OutfitStudio.cpp:10388\n#: src/program/OutfitStudio.cpp:11741 src/program/OutfitStudio.cpp:12061\n#: src/program/OutfitStudio.cpp:12098 src/program/OutfitStudio.cpp:12103\n#: src/program/OutfitStudio.cpp:12115 src/program/OutfitStudio.cpp:13426\nmsgid \"Error\"\nmsgstr \"Hata\"\n\n#: src/program/BodySlideApp.cpp:1436 src/program/OutfitStudio.cpp:659\nmsgid \"\"\n\"Failed to find game install path registry key or GameDataPath in the config.\"\nmsgstr \"\"\n\"Yapılandırmada oyun yükleme yolu kayıt defteri anahtarı veya GameDataPath \"\n\"bulunamadı.\"\n\n#: src/program/BodySlideApp.cpp:1664 src/program/OutfitStudio.cpp:887\n#, c-format\nmsgid \"System language '%d' is wrong.\"\nmsgstr \"Sistem dili '%d' yanlış.\"\n\n#: src/program/BodySlideApp.cpp:1673 src/program/OutfitStudio.cpp:896\n#, c-format\nmsgid \"\"\n\"The system language '%d' is not supported by your system. Try installing \"\n\"support for this language.\"\nmsgstr \"\"\n\"Sistem dili '%d' sisteminiz tarafından desteklenmiyor. Bu dil için destek \"\n\"alarak yüklemeyi deneyin.\"\n\n#: src/program/BodySlideApp.cpp:1751\nmsgid \"Failed to create group file.\"\nmsgstr \"Grup dosyası oluşturulamadı.\"\n\n#: src/program/BodySlideApp.cpp:1765\nmsgid \"\"\n\"That group already exists in the specified file, do you wish to overwrite \"\n\"the group?\"\nmsgstr \"\"\n\"Bu grup adında bir dosya zaten mevcut, grubun üzerine yazmak ister misin?\"\n\n#: src/program/BodySlideApp.cpp:1765\nmsgid \"Group already exists\"\nmsgstr \"Grup zaten mevcut\"\n\n#: src/program/BodySlideApp.cpp:1922\nmsgid \"\"\n\"WARNING: Game data path not configured. Would you like to show BodySlide \"\n\"where it is?\"\nmsgstr \"\"\n\"UYARI: Oyun veri yolu yapılandırılmamış. BodySlide yükleme klasörünü elle \"\n\"belirlemek ister misin?\"\n\n#: src/program/BodySlideApp.cpp:1923 src/program/BodySlideApp.cpp:2224\n#: src/program/BodySlideApp.cpp:2229\nmsgid \"Game not found\"\nmsgstr \"Oyun bulunamadı\"\n\n#: src/program/BodySlideApp.cpp:1931\nmsgid \"Please choose a directory to set as your Data path\"\nmsgstr \"Lütfen Veri yolu olarak ayarlamak için bir klasör dizini seç\"\n\n#: src/program/BodySlideApp.cpp:1949\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folder, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"UYARI: Bu, çıkış dosyalarını kopyalanan klasöründen siler, potansiyel olarak \"\n\"çökmelere neden olabilir.\\n\"\n\"\\n\"\n\"Devam etmek istediğine emin misin?\"\n\n#: src/program/BodySlideApp.cpp:1950\nmsgid \"Clean Build\"\nmsgstr \"Kurulumu Temizle\"\n\n#: src/program/BodySlideApp.cpp:1958\nmsgid \"Removed the following files:\\n\"\nmsgstr \"Dosyalar siliniyor:\\n\"\n\n#: src/program/BodySlideApp.cpp:1970 src/program/BodySlideApp.cpp:1983\nmsgid \" (no action)\\n\"\nmsgstr \" (eylem yok)\\n\"\n\n#: src/program/BodySlideApp.cpp:1974 src/program/BodySlideApp.cpp:1986\n#: src/program/BodySlideApp.cpp:2195\nmsgid \"Process Successful\"\nmsgstr \"İşlem Başarıyla Sonuçlandı\"\n\n#: src/program/BodySlideApp.cpp:2082\n#, c-format\nmsgid \"\"\n\"Failed to write TRI file to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"TRI dosyası belirtilen konuma yazılamadı\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/BodySlideApp.cpp:2082 src/program/BodySlideApp.cpp:2138\n#: src/program/BodySlideApp.cpp:2173\nmsgid \"Unable to process\"\nmsgstr \"İşlenemiyor\"\n\n#: src/program/BodySlideApp.cpp:2138 src/program/BodySlideApp.cpp:2173\n#, c-format\nmsgid \"\"\n\"Failed to build set to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Bu ayar seti belirtilen konuma yazdırılamadı\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/BodySlideApp.cpp:2140 src/program/BodySlideApp.cpp:2175\nmsgid \"Choose alternate file name\"\nmsgstr \"Alternatif dosya adını seç\"\n\n#: src/program/BodySlideApp.cpp:2187\nmsgid \"Successfully processed the following files:\\n\"\nmsgstr \"Dosyalar başarıyla işlendi:\\n\"\n\n#: src/program/BodySlideApp.cpp:2209\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folders, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"UYARI: Bu, işleme dosyalarını çıkış klasörlerinden siler, potansiyele dayalı \"\n\"çökmelere neden olabilir.\\n\"\n\"\\n\"\n\"Devam etmek istediğine emin misin?\"\n\n#: src/program/BodySlideApp.cpp:2210\nmsgid \"Clean Batch Build\"\nmsgstr \"Toplu Yapı Temizliği\"\n\n#: src/program/BodySlideApp.cpp:2224\nmsgid \"\"\n\"WARNING: Game data path not configured. Files can't be removed that way.\"\nmsgstr \"\"\n\"UYARI: Oyun veri yolu yapılandırılmamış. Dosyalar bu şekilde silinemez.\"\n\n#: src/program/BodySlideApp.cpp:2228\nmsgid \"\"\n\"WARNING: Game data path not configured. Continue saving files to the working \"\n\"directory?\"\nmsgstr \"\"\n\"UYARI: Oyun veri yolu yapılandırılmamış. Dosyaları çalışma dizinine kaydetme \"\n\"işlemine devam edilsin mi?\"\n\n#: src/program/BodySlideApp.cpp:2363\nmsgid \"Processing Outfits\"\nmsgstr \"Kıyafet işlenmesi\"\n\n#: src/program/BodySlideApp.cpp:2363 src/program/OutfitStudio.h:1052\nmsgid \"Starting...\"\nmsgstr \"Başlatılıyor...\"\n\n#: src/program/BodySlideApp.cpp:2375\n#, c-format\nmsgid \"Processing '%s' (%d of %d)...\"\nmsgstr \"İşleniyor '%s' (%d of %d)...\"\n\n#: src/program/BodySlideApp.cpp:2383\nmsgid \"No recorded outfit name source\"\nmsgstr \"Kayıtlı bir kıyafet adı kaynağı yok\"\n\n#: src/program/BodySlideApp.cpp:2394\nmsgid \"Unable to get slider set from file: \"\nmsgstr \"Kaydırıcı dosyadan alınamadı: \"\n\n#: src/program/BodySlideApp.cpp:2399\nmsgid \"Unable to open slider set file: \"\nmsgstr \"Kaydırıcı ayar dosyası açılamıyor: \"\n\n#: src/program/BodySlideApp.cpp:2434\nmsgid \"Unable to load input nif: \"\nmsgstr \"Nif giriş kodlaması yüklenemedi: \"\n\n#: src/program/BodySlideApp.cpp:2581\nmsgid \"Unable to create destination directory: \"\nmsgstr \"Hedef dizin oluşturulamadı: \"\n\n#: src/program/BodySlideApp.cpp:2648 src/program/BodySlideApp.cpp:2656\n#: src/program/BodySlideApp.cpp:2667\nmsgid \"Unable to save nif file: \"\nmsgstr \"Nif dosyası kaydedilemiyor: \"\n\n#: src/program/BodySlideApp.cpp:2741 src/program/BodySlideApp.cpp:3790\nmsgid \"The following sets failed\"\nmsgstr \"Takipçi ayarları başarısız\"\n\n#: src/program/BodySlideApp.cpp:2741 src/program/BodySlideApp.cpp:3790\nmsgid \"Failed\"\nmsgstr \"Başarısız\"\n\n#: src/program/BodySlideApp.cpp:2813\nmsgid \"Failed to load BodySlide.xrc file!\"\nmsgstr \"Bodyslide.xrc dosyası yüklenemedi!\"\n\n#: src/program/BodySlideApp.cpp:2820\nmsgid \"Failed to load BodySlide frame!\"\nmsgstr \"BodySlide ana çerçevesi yüklenemedi!\"\n\n#: src/program/BodySlideApp.cpp:2853\nmsgid \"Group Filter\"\nmsgstr \"Gurup Filtresi\"\n\n#: src/program/BodySlideApp.cpp:2854\nmsgid \"Filter by group\"\nmsgstr \"Gruplara göre filtrele\"\n\n#: src/program/BodySlideApp.cpp:2860\nmsgid \"Outfit Filter\"\nmsgstr \"Kıyafet Filtresi\"\n\n#: src/program/BodySlideApp.cpp:2861\nmsgid \"Filter by outfit\"\nmsgstr \"Kıyafetlere göre filtrele\"\n\n#: src/program/BodySlideApp.cpp:3450\nmsgid \"Choose groups to filter outfit list\"\nmsgstr \"Kıyafet listesini filtrelemek için grupları seç\"\n\n#: src/program/BodySlideApp.cpp:3450\nmsgid \"Choose Groups\"\nmsgstr \"Gurupları Seç\"\n\n#: src/program/BodySlideApp.cpp:3469\nmsgid \"Choose or create group file\"\nmsgstr \"Grup dosyası seç veya oluştur\"\n\n#: src/program/BodySlideApp.cpp:3482\nmsgid \"What would you like the new group to be called?\"\nmsgstr \"Yeni grubun da aranmasını istiyor musun?\"\n\n#: src/program/BodySlideApp.cpp:3482\nmsgid \"New Group Name\"\nmsgstr \"Yeni Gurup İsmi\"\n\n#: src/program/BodySlideApp.cpp:3523\nmsgid \"Do you really wish to delete the selected project?\"\nmsgstr \"Seçilen projeyi silmeyi gerçekten istiyor musun?\"\n\n#: src/program/BodySlideApp.cpp:3523\nmsgid \"Delete Project\"\nmsgstr \"Projeyi Sil\"\n\n#: src/program/BodySlideApp.cpp:3532\nmsgid \"Do you really wish to delete the selected preset?\"\nmsgstr \"Bu hazır ayarı silmeyi gerçekten istiyor musun?\"\n\n#: src/program/BodySlideApp.cpp:3532\nmsgid \"Delete Preset\"\nmsgstr \"Hazır Ayarı Sil\"\n\n#: src/program/BodySlideApp.cpp:3554 src/program/OutfitStudio.cpp:7091\n#, c-format\nmsgid \"Failed to save preset (%d)!\"\nmsgstr \"Hazır ayar kaydedilemedi (%d)!\"\n\n#: src/program/BodySlideApp.cpp:3582\n#, c-format\nmsgid \"Failed to save preset as '%s' (%d)!\"\nmsgstr \"Hazır ayar olarak kaydedilemedi '%s' (%d)!\"\n\n#: src/program/BodySlideApp.cpp:3765\nmsgid \"Choose a folder to contain the saved files\"\nmsgstr \"Kaydedilen dosyaların için bir klasör seç\"\n\n#: src/program/BodySlideApp.cpp:3780\nmsgid \"All sets processed successfully!\"\nmsgstr \"Tüm guruplar başarıyla ayarlandı!\"\n\n#: src/program/BodySlideApp.cpp:3780\nmsgid \"Complete\"\nmsgstr \"Tamamlandı\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:121\nmsgid \"Starting conversion...\"\nmsgstr \"Dönüşüm başlatılıyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:139\nmsgid \"Updating Project Output Settings\"\nmsgstr \"Proje Çıktı Ayarları Güncelleniyor\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:178\nmsgid \"Deleting Shapes...\"\nmsgstr \"Kalıplar Siliniyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:199\nmsgid \"Loading conversion reference...\"\nmsgstr \"Dönüşüm referansı yükleniyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:209\n#: src/program/ConvertBodyReferenceDialog.cpp:253\nmsgid \"Conforming outfit parts...\"\nmsgstr \"Kıyafet Dönüşümleri güncelleniyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:216\nmsgid \"Updating conversion Slider...\"\nmsgstr \"Kaydırıcı Dönüşümleri güncelleniyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:220\nmsgid \"Setting the base shape and removing the conversion reference\"\nmsgstr \"Temel kalıp ayarlama ve dönüştürme referansını temizleme\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:227\nmsgid \"Skipping conversion reference...\"\nmsgstr \"Dönüşüm örnekleri atlanıyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:232\nmsgid \"Loading new reference...\"\nmsgstr \"Yeni örnek yükleniyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:246\nmsgid \"Copying bones...\"\nmsgstr \"Kemikler kopyalanıyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:260\nmsgid \"Adding Bones...\"\nmsgstr \"Kemikler Yükleniyor...\"\n\n#: src/program/ConvertBodyReferenceDialog.cpp:289\nmsgid \"Conversion finished.\"\nmsgstr \"Dönüşüm tamamlandı.\"\n\n#: src/program/EditUV.cpp:497 src/program/OutfitStudio.cpp:10876\nmsgid \"Outfit Studio: OpenGL context is not OK.\"\nmsgstr \"Outfit Studio: OpenGL içeriği mevcut değil.\"\n\n#: src/program/EditUV.cpp:497 src/program/OutfitStudio.cpp:10876\n#: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:34\n#: src/render/GLSurface.cpp:2116 src/render/GLSurface.cpp:2133\nmsgid \"OpenGL Error\"\nmsgstr \"OpenGL Hatası\"\n\n#: src/program/FBXImportDialog.cpp:158 src/program/ObjImportDialog.cpp:165\n#: src/program/OutfitStudio.cpp:9020 src/program/OutfitStudio.cpp:12098\nmsgid \"The shape has reached the vertex count limit.\"\nmsgstr \"Bu kalıp, uç tepe sayısı sınırına ulaştı.\"\n\n#: src/program/FBXImportDialog.cpp:162 src/program/ObjImportDialog.cpp:169\n#: src/program/OutfitStudio.cpp:9025 src/program/OutfitStudio.cpp:12103\nmsgid \"The shape has reached the triangle count limit.\"\nmsgstr \"Bu kalıp, üçgensel sayı sınırına ulaştı.\"\n\n#: src/program/GroupManager.cpp:143\nmsgid \"Please enter a new unique name for the group.\"\nmsgstr \"Lütfen grup için yeni bir isim belirle.\"\n\n#: src/program/GroupManager.cpp:143\nmsgid \"Rename Group\"\nmsgstr \"Grubu Yeniden Adlandır\"\n\n#: src/program/GroupManager.cpp:323\nmsgid \"Save changes to group file?\"\nmsgstr \"oplu değişiklikler bir gurup dosyası adında kaydedilsin mi?\"\n\n#: src/program/GroupManager.cpp:323\nmsgid \"Save Changes\"\nmsgstr \"Değişiklikleri Kaydet\"\n\n#: src/program/NormalsGenDialog.cpp:90\nmsgid \"Enter a name for the new layer.\"\nmsgstr \"Yeni katman için bir isim belirle.\"\n\n#: src/program/NormalsGenDialog.cpp:90\nmsgid \"Name new layer\"\nmsgstr \"Yeni Katman İsmi\"\n\n#: src/program/NormalsGenDialog.cpp:205\nmsgid \"Choose a normals generator preset file...\"\nmsgstr \"Genel standart ayarlamalarını hazır ayar olarak seç..\"\n\n#: src/program/NormalsGenDialog.cpp:222\nmsgid \"Save normals generator preset to...\"\nmsgstr \"Genel standart ayarlamalarını hazır ayar olarak kaydet...\"\n\n#: src/program/NormalsGenDialog.cpp:240\nmsgid \"Layer\"\nmsgstr \"Katmanlar\"\n\n#: src/program/NormalsGenDialog.cpp:263\nmsgid \"Background File\"\nmsgstr \"Arkaplan Dosyası\"\n\n#: src/program/NormalsGenDialog.cpp:264\nmsgid \"File source for this layer.\"\nmsgstr \"Bu katmanın dosya kaynağı.\"\n\n#: src/program/NormalsGenDialog.cpp:265\nmsgid \"Color\"\nmsgstr \"Renkler\"\n\n#: src/program/NormalsGenDialog.cpp:266\nmsgid \"Solid background color (if file is not set).\"\nmsgstr \"Koyu arka plan rengi (eğer dosya ayarlanmamışsa).\"\n\n#: src/program/NormalsGenDialog.cpp:267\nmsgid \"Resolution\"\nmsgstr \"Çözünürlük\"\n\n#: src/program/NormalsGenDialog.cpp:269\nmsgid \"\"\n\"Output texture dimensions. By default all images will be scaled to fit this \"\n\"size.\"\nmsgstr \"\"\n\"Doku boyutları çıktısıdır. Varsayılan olarak, tüm resimler bu boyuta uyacak \"\n\"şekilde ölçeklendirilecektir.\"\n\n#: src/program/NormalsGenDialog.cpp:286\nmsgid \"\"\n\"File containing normals data to combine. Note this file should fit the mesh \"\n\"UVs.\"\nmsgstr \"\"\n\"Birleştirilecek normal veri dosyalarını içeren kalıp. Bu dosyaların örgü \"\n\"UV'lerine uyması gerektiğini unutmamalısın.\"\n\n#: src/program/NormalsGenDialog.cpp:288\nmsgid \"Is Tangent Space?\"\nmsgstr \"Teğet Uzay mı olsun?\"\n\n#: src/program/NormalsGenDialog.cpp:289\nmsgid \"\"\n\"True if the normals data in the layer file is in tangent space, false if \"\n\"they are in model space (msn).\"\nmsgstr \"\"\n\"Eğer katman dosyasındaki normal değerler verisi teğet uzayda yer almıyorsa, \"\n\"model uzayda (msn) yanlış görüntülenir.\"\n\n#: src/program/NormalsGenDialog.cpp:292\nmsgid \"A greyscale image used to mask updates to destination image.\"\nmsgstr \"\"\n\"Hedef resme güncellemeleri maskelemek için kullanılan gri tonlamalı bir \"\n\"resim.\"\n\n#: src/program/NormalsGenDialog.cpp:294\nmsgid \"X Offset\"\nmsgstr \"X Dengesi\"\n\n#: src/program/NormalsGenDialog.cpp:295 src/program/NormalsGenDialog.cpp:298\nmsgid \"Offset to apply to image position.\"\nmsgstr \"Görüntü pozisyonuna uygulamak için dengeleme.\"\n\n#: src/program/NormalsGenDialog.cpp:297\nmsgid \"Y Offset\"\nmsgstr \"Y Dengesi\"\n\n#: src/program/NormalsGenDialog.cpp:301\nmsgid \"If true, scale image to match background resolution.\"\nmsgstr \"\"\n\"Eğer bunu kabul ediyorsan, resmi arka plan çözünürlüğüne uyacak şekilde \"\n\"yeniden ölçeklendirmelisin.\"\n\n#: src/program/OutfitProject.cpp:51\nmsgid \"Checking destination...\"\nmsgstr \"Hedef kontrol ediliyor...\"\n\n#: src/program/OutfitProject.cpp:106\nmsgid \"Adding reference shapes...\"\nmsgstr \"Örnek kalıplar ekleniyor...\"\n\n#: src/program/OutfitProject.cpp:124 src/program/OutfitProject.cpp:2176\nmsgid \"Adding outfit shapes...\"\nmsgstr \"Kıyafet kalıpları ekleniyor...\"\n\n#: src/program/OutfitProject.cpp:181\nmsgid \"Calculating slider data...\"\nmsgstr \"Kaydırıcı verileri hesaplanıyor...\"\n\n#: src/program/OutfitProject.cpp:189\nmsgid \"Creating slider set file...\"\nmsgstr \"Kaydırıcı gurup dosyası oluşturuluyor...\"\n\n#: src/program/OutfitProject.cpp:196\nmsgid \"Failed to open or create slider set file: \"\nmsgstr \"Kaydırıcı grubu dosyası açılamadı veya oluşturulamadı: \"\n\n#: src/program/OutfitProject.cpp:203\nmsgid \"Saving slider set file...\"\nmsgstr \"Kaydırıcı gurup dosyası kaydediliyor...\"\n\n#: src/program/OutfitProject.cpp:206\nmsgid \"Failed to write to slider set file: \"\nmsgstr \"Kaydırıcı grubu dosyasına yazdırılamadı: \"\n\n#: src/program/OutfitProject.cpp:210\nmsgid \"Saving NIF file...\"\nmsgstr \"NIF dosyası olarak Kaydediliyor..\"\n\n#: src/program/OutfitProject.cpp:240\nmsgid \"Failed to write base .nif file: \"\nmsgstr \"Temel .nif dosyası olarak yazdırması Başarısız: \"\n\n#: src/program/OutfitProject.cpp:246 src/program/OutfitProject.cpp:1641\n#: src/program/OutfitProject.cpp:1671 src/program/OutfitStudio.cpp:3490\nmsgid \"Finished\"\nmsgstr \"Tamamlandı\"\n\n#: src/program/OutfitProject.cpp:1535 src/program/OutfitProject.cpp:1627\nmsgid \"Gathering bones...\"\nmsgstr \"Kemikler toplanılıyor...\"\n\n#: src/program/OutfitProject.cpp:1563\nmsgid \"Initializing proximity data...\"\nmsgstr \"Uyumluluk veri tabanı başlatılıyor...\"\n\n#: src/program/OutfitProject.cpp:1609 src/program/OutfitStudio.cpp:9552\nmsgid \"Copying bone weights...\"\nmsgstr \"Kemik ağırlıkları kopyalanıyor...\"\n\n#: src/program/OutfitProject.cpp:1647 src/program/OutfitStudio.cpp:9743\nmsgid \"Transferring bone weights...\"\nmsgstr \"Kemik ağırlıkları aktarılıyor...\"\n\n#: src/program/OutfitProject.cpp:1892\nmsgid \"Template source entries are invalid.\"\nmsgstr \"Şablon kaynak girişleri geçersiz.\"\n\n#: src/program/OutfitProject.cpp:1892 src/program/OutfitProject.cpp:1922\n#: src/program/OutfitProject.cpp:1927 src/program/OutfitProject.cpp:1972\n#: src/program/OutfitProject.cpp:1994 src/program/OutfitProject.cpp:2001\n#: src/program/OutfitProject.cpp:2011 src/program/OutfitProject.cpp:2023\nmsgid \"Reference Error\"\nmsgstr \"Örnekleme Hatası\"\n\n#: src/program/OutfitProject.cpp:1919 src/program/OutfitProject.cpp:1991\n#: src/program/OutfitProject.cpp:4593\n#, c-format\nmsgid \"\"\n\"NIF version not supported!\\n\"\n\"\\n\"\n\"File: %s\\n\"\n\"%s\"\nmsgstr \"\"\n\"NIF sürümü desteklenmiyor!\\n\"\n\"\\n\"\n\"Dosya: %s\\n\"\n\"%s\"\n\n#: src/program/OutfitProject.cpp:1927 src/program/OutfitProject.cpp:2001\n#, c-format\nmsgid \"Could not load reference NIF file '%s'!\"\nmsgstr \"Örnek NIF dosyası yüklenemedi '%s'!\"\n\n#: src/program/OutfitProject.cpp:1972\n#, c-format\nmsgid \"Could not load slider set file '%s'!\"\nmsgstr \"Kaydırıcı grup dosyası yüklenemedi '%s'!\"\n\n#: src/program/OutfitProject.cpp:2011\n#, c-format\nmsgid \"Reference NIF file '%s' does not contain any shapes.\"\nmsgstr \"Örnek NIF dosyası '%s' herhangi bir kalıbı içermiyor.\"\n\n#: src/program/OutfitProject.cpp:2023\n#, c-format\nmsgid \"Shape '%s' not found in reference NIF file '%s'!\"\nmsgstr \"Kalıp '%s' örnek olan NIF dosyasında bulunamadı '%s'!\"\n\n#: src/program/OutfitProject.cpp:2075\nmsgid \"Loading slider set...\"\nmsgstr \"Kaydırıcı grup yükleniyor...\"\n\n#: src/program/OutfitProject.cpp:2082 src/program/OutfitProject.cpp:2166\nmsgid \"Retrieving sliders...\"\nmsgstr \"Kaydırıcılar alınıyor...\"\n\n#: src/program/OutfitProject.cpp:2092\nmsgid \"Loading outfit shapes...\"\nmsgstr \"Kıyafet kalıpları yükleniyor...\"\n\n#: src/program/OutfitProject.cpp:2135 src/program/OutfitProject.cpp:2232\nmsgid \"Updating slider data...\"\nmsgstr \"Kaydırıcı verileri güncelleniyor...\"\n\n#: src/program/OutfitProject.cpp:2158\nmsgid \"Adding slider set...\"\nmsgstr \"Kaydırıcı seti eklendi...\"\n\n#: src/program/OutfitProject.cpp:2225\nmsgid \"\"\n\"The following shapes were renamed and won't have slider data attached. \"\n\"Rename the duplicates yourself beforehand.\"\nmsgstr \"\"\n\"Aşağıdaki kalıplar yeniden adlandırıldı ama kaydırıcı verileri eklenmedi. \"\n\"Kopyasını almadan önce yeniden adlandırmalısın.\"\n\n#: src/program/OutfitProject.cpp:2227\nmsgid \"Renamed Shapes\"\nmsgstr \"Yeniden Adlandırılan Kalıplar\"\n\n#: src/program/OutfitProject.cpp:4596 src/program/OutfitProject.cpp:4601\nmsgid \"NIF Error\"\nmsgstr \"NIF Hatası\"\n\n#: src/program/OutfitProject.cpp:4601\n#, c-format\nmsgid \"Could not load NIF file '%s'!\"\nmsgstr \"NIF dosyası yüklenemedi '%s'!\"\n\n#: src/program/OutfitProject.cpp:4733\nmsgid \"\"\n\"There was cloth physics data loaded at some point (BSClothExtraData). Please \"\n\"choose all the origins to use in the output.\"\nmsgstr \"\"\n\"Bir noktada (BSClothExtraData) için yüklenen kumaş fizik verileri olmalıydı. \"\n\"Lütfen çıktıda kullanılacak tüm kaynakları seçtiğinden emin ol.\"\n\n#: src/program/OutfitProject.cpp:4734\nmsgid \"Choose cloth data\"\nmsgstr \"Kumaş verilerini seç\"\n\n#: src/program/OutfitProject.cpp:4802\nmsgid \"\"\n\"No reference has been loaded.  For correct bone transforms, you might need \"\n\"to load a reference before importing OBJ files.\"\nmsgstr \"\"\n\"Hiçbir Örnek yüklenmedi. Doğru kemik dönüşümleri için OBJ dosyalarını içe \"\n\"aktarmadan önce bir örnek kalıp yüklemeniz gerekebilir.\"\n\n#: src/program/OutfitProject.cpp:4810\n#, c-format\nmsgid \"Could not load OBJ file '%s'!\"\nmsgstr \"OBJ dosyası yüklenemedi '%s'!\"\n\n#: src/program/OutfitProject.cpp:4810 src/program/OutfitProject.cpp:4834\n#: src/program/OutfitProject.cpp:4896 src/program/OutfitProject.cpp:5062\nmsgid \"OBJ Error\"\nmsgstr \"OBJ Hatası\"\n\n#: src/program/OutfitProject.cpp:4816 src/program/OutfitProject.cpp:4981\nmsgid \"\"\n\"The reference shape has a skin coordinate system that is different from the \"\n\"global coordinate system.  Would you like to copy the reference's global-to-\"\n\"skin transform to the imported shapes?\"\nmsgstr \"\"\n\"Örnek kalıp, genel koordinat sisteminden farklı bir dış yüzey koordinat \"\n\"sistemine sahiptir. Örneğin global-tene dönüşümünü içe aktarılan kalıplara \"\n\"kopyalamak ister misin?\"\n\n#: src/program/OutfitProject.cpp:4818 src/program/OutfitProject.cpp:4983\nmsgid \"Copy skin coordinates\"\nmsgstr \"Deri-Ten koordinatlarını kopyala\"\n\n#: src/program/OutfitProject.cpp:4834\n#, c-format\nmsgid \"Could not copy data from OBJ file '%s'!\"\nmsgstr \"OBJ dosyasındaki veri kopyalanamadı '%s'!\"\n\n#: src/program/OutfitProject.cpp:4851\nmsgid \"\"\n\"The vertex count of the selected .obj file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"Seçilen .obj dosyasının tepe noktası sayısı geçerli olarak seçilen kıyafet \"\n\"kalıbıyla eşleşiyor. Mevcut kalıbı güncellemek ister misin? (yeni bir Kalıp \"\n\"oluşturmak için Hayır'a tıkla)\"\n\n#: src/program/OutfitProject.cpp:4853 src/program/OutfitProject.cpp:5009\nmsgid \"Merge or New\"\nmsgstr \"Birleştir ya da Yeniden\"\n\n#: src/program/OutfitProject.cpp:4857 src/program/OutfitProject.cpp:5013\nmsgid \"Update Vertex Positions?\"\nmsgstr \"Köşe Konumlarının Güncellemesi?\"\n\n#: src/program/OutfitProject.cpp:4857 src/program/OutfitProject.cpp:5013\nmsgid \"Vertex Position Update\"\nmsgstr \"Köşe Konumlarını Güncelleme\"\n\n#: src/program/OutfitProject.cpp:4862 src/program/OutfitProject.cpp:5018\nmsgid \"Update Texture Coordinates?\"\nmsgstr \"Texture-Doku Konumlarının Güncellemesi?\"\n\n#: src/program/OutfitProject.cpp:4862 src/program/OutfitProject.cpp:5018\nmsgid \"UV Update\"\nmsgstr \"UV Güncelleme\"\n\n#: src/program/OutfitProject.cpp:4868 src/program/OutfitProject.cpp:5024\nmsgid \"Update Normals?\"\nmsgstr \"Normal Veriler Güncellensin mi?\"\n\n#: src/program/OutfitProject.cpp:4868 src/program/OutfitProject.cpp:5024\nmsgid \"Normals Update\"\nmsgstr \"Normal Verileri Güncelle\"\n\n#: src/program/OutfitProject.cpp:4878 src/program/OutfitProject.cpp:5040\nmsgid \"Please specify a name for the new shape\"\nmsgstr \"Lütfen yeni kalıp için yeni bir isim belirle\"\n\n#: src/program/OutfitProject.cpp:4878 src/program/OutfitProject.cpp:5040\nmsgid \"New Shape Name\"\nmsgstr \"Yeni Kalıp Adı\"\n\n#: src/program/OutfitProject.cpp:4889 src/program/OutfitProject.cpp:5055\n#, c-format\nmsgid \"\"\n\"The vertex or triangle limit for '%s' was exceeded.\\n\"\n\"Remaining data was dropped.\\n\"\n\"\\n\"\n\"Vertices (current/max): %zu/%zu\\n\"\n\"Triangles (current/max): %zu/%zu\"\nmsgstr \"\"\n\"Tepe noktası veya üçgen sınırı aşılan '%s' .\\n\"\n\"Kalan veriler atıldı.\\n\"\n\"\\n\"\n\"Tepe Noktaları (mevcut/max): %zu/%zu\\n\"\n\"Üçgen Noktalar (mevcut/max): %zu/%zu\"\n\n#: src/program/OutfitProject.cpp:4969\nmsgid \"\"\n\"No reference has been loaded.  For correct bone transforms, you might need \"\n\"to load a reference before importing FBX files.\"\nmsgstr \"\"\n\"Hiçbir örnek yüklenmedi. Doğru kemik dönüşümleri için FBX dosyalarını içe \"\n\"aktarmadan önce bir örnek yüklemeniz gerekebilir.\"\n\n#: src/program/OutfitProject.cpp:5007\nmsgid \"\"\n\"The vertex count of the selected .fbx file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"Seçili .fbx dosyasının tepe noktası sayısı geçerli olarak seçilen kıyafet \"\n\"kalıbıyla eşleşiyor. Mevcut şekli güncellemek ister misin? (yeni bir Kalıp \"\n\"oluşturmak istiyorsan Hayır'a tıkla)\"\n\n#: src/program/OutfitProject.cpp:5031\nmsgid \"Update Animation Weighting?\"\nmsgstr \"Animasyon Ağırlığını Güncelle?\"\n\n#: src/program/OutfitProject.cpp:5031\nmsgid \"Animation Weight Update\"\nmsgstr \"Animasyon Ağırlık Güncellemesi\"\n\n#: src/program/OutfitProject.cpp:5128\nmsgid \"Would you like Skyrim NIFs to be optimized for SSE during this session?\"\nmsgstr \"\"\n\"Geçerli Skyrim NIF dosyalarının Skyrim SE için optimize edilmesini ister \"\n\"misin?\"\n\n#: src/program/OutfitProject.cpp:5145\nmsgid \"\"\n\"File format doesn't match the current game. Use FBX export, then start a new \"\n\"project and import the FBX file there.\"\nmsgstr \"\"\n\"Dosya formatı mevcut oyunla eşleşmiyor. FBX dışa aktarımını kullan, ardından \"\n\"yeni bir proje başlat ve FBX dosyasını oraya aktar.\"\n\n#: src/program/OutfitProject.cpp:5146\nmsgid \"Version\"\nmsgstr \"Sürüm\"\n\n#: src/program/OutfitProject.cpp:5252\nmsgid \"No Bad Bones Found.\"\nmsgstr \"Hatalı İskelet Bulunamadı.\"\n\n#: src/program/OutfitProject.cpp:5252\nmsgid \"No Bad Bones\"\nmsgstr \"Hatalı İskelet Yok\"\n\n#: src/program/OutfitProject.cpp:5367\nmsgid \"Bad Bones\"\nmsgstr \"Hatalı İskeletler\"\n\n#: src/program/OutfitProject.cpp:5388\nmsgid \"Error in rotation\"\nmsgstr \"Dönüşüm Hatası\"\n\n#: src/program/OutfitProject.cpp:5389\nmsgid \"Error in translation\"\nmsgstr \"Çevirim Hatası\"\n\n#: src/program/OutfitProject.cpp:5390\nmsgid \"Error in scale\"\nmsgstr \"Ölçekleme Hatası\"\n\n#: src/program/OutfitProject.cpp:5417\n#, c-format\nmsgid \"Bad standard bones for shape \\\"%s\\\"\"\nmsgstr \"Kalıp için hatalı iskelet \\\"%s\\\"\"\n\n#: src/program/OutfitProject.cpp:5420\n#, c-format\nmsgid \"\"\n\"%zu bones in shape \\\"%s\\\" had inconsistencies between their NIF skin \"\n\"transforms and the standard skeleton:\\n\"\nmsgstr \"\"\n\"%zu iskeletindeki \\\"%s\\\" kalıbında NIF dış görünüm dönüşümleri ile standart \"\n\"iskelet arasında tutarsızlıklar vardı:\\n\"\n\n#: src/program/OutfitProject.cpp:5435\nmsgid \"Update skin (recommended)\"\nmsgstr \"Deri-Ten Güncelle (önerilen ayar)\"\n\n#: src/program/OutfitProject.cpp:5443 src/program/OutfitProject.cpp:5507\n#: src/program/OutfitProject.cpp:5530\nmsgid \"Details\"\nmsgstr \"Detaylar\"\n\n#: src/program/OutfitProject.cpp:5443\nmsgid \"Bone\"\nmsgstr \"İskelet\"\n\n#: src/program/OutfitProject.cpp:5448 src/program/OutfitProject.cpp:5544\nmsgid \"Do nothing\"\nmsgstr \"Bunu Uygulama\"\n\n#: src/program/OutfitProject.cpp:5460\n#, c-format\nmsgid \"Bad Custom Bone \\\"%s\\\"\"\nmsgstr \"Hatalı Özel İskelet \\\"%s\\\"\"\n\n#: src/program/OutfitProject.cpp:5463\n#, c-format\nmsgid \"\"\n\"Custom bone \\\"%s\\\" had inconsistent NIF node and skin transforms for the \"\n\"following shapes:\\n\"\n\"\\\"\"\nmsgstr \"\"\n\"Özel İskelet \\\"%s\\\" geçerli NIF dosyası içerisinde hatalı ve bozuk kemikler \"\n\"içeriyordu:\\n\"\n\"\\\"\"\n\n#: src/program/OutfitProject.cpp:5483\nmsgid \"Trust node and skins \\\"\"\nmsgstr \"Doğru Düğüm ve Deriler \\\"\"\n\n#: src/program/OutfitProject.cpp:5485\nmsgid \"Trust node and skin \\\"\"\nmsgstr \"Doğru Düğüm ve Deri \\\"\"\n\n#: src/program/OutfitProject.cpp:5493\nmsgid \"\\\", and update other skins (recommended)\"\nmsgstr \"\\\", ve diğer deri-tenler güncellendi (önerilen)\"\n\n#: src/program/OutfitProject.cpp:5496\nmsgid \"Trust node, and update skins\"\nmsgstr \"Doğru Düğüm, ve Deri-Ten güncellemesi\"\n\n#: src/program/OutfitProject.cpp:5498\nmsgid \"Trust node, and update skin\"\nmsgstr \"Doğru Düğüm, ve Deri-Ten güncellemesi\"\n\n#: src/program/OutfitProject.cpp:5507\nmsgid \"Skin\"\nmsgstr \"Deri-Ten\"\n\n#: src/program/OutfitProject.cpp:5516\nmsgid \"Trust skin \\\"\"\nmsgstr \"Doğru Deri-Ten \\\"\"\n\n#: src/program/OutfitProject.cpp:5518\nmsgid \"\\\", and update node\"\nmsgstr \"\\\", ve güncellenen Düğüm\"\n\n#: src/program/OutfitProject.cpp:5520\nmsgid \"\\\", and update node and other skins\"\nmsgstr \"\\\", ve güncellenen Düğün ve Deriler\"\n\n#: src/program/OutfitProject.cpp:5530\nmsgid \"With\"\nmsgstr \"Birlikte\"\n\n#: src/program/OutfitProject.cpp:5531\nmsgid \"Node\"\nmsgstr \"Düğüm\"\n\n#: src/program/OutfitProject.cpp:5557\nmsgid \"Fix nothing\"\nmsgstr \"Düzeltme Yapma\"\n\n#: src/program/OutfitStudio.cpp:443 src/program/OutfitStudio.cpp:444\n#: src/program/OutfitStudio.cpp:13371 src/program/OutfitStudio.cpp:13372\nmsgid \"Adding NIF file...\"\nmsgstr \"NIF dosyası Ekleniyor...\"\n\n#: src/program/OutfitStudio.cpp:448 src/program/OutfitStudio.cpp:459\n#: src/program/OutfitStudio.cpp:470 src/program/OutfitStudio.cpp:4209\n#: src/program/OutfitStudio.cpp:13376 src/program/OutfitStudio.cpp:13387\n#: src/program/OutfitStudio.cpp:13398\nmsgid \"Refreshing GUI...\"\nmsgstr \"GUI canlandırılıyor...\"\n\n#: src/program/OutfitStudio.cpp:455 src/program/OutfitStudio.cpp:13383\nmsgid \"Adding OBJ file...\"\nmsgstr \"OBJ dosyası Ekleniyor...\"\n\n#: src/program/OutfitStudio.cpp:465 src/program/OutfitStudio.cpp:466\n#: src/program/OutfitStudio.cpp:13393 src/program/OutfitStudio.cpp:13394\nmsgid \"Adding FBX file...\"\nmsgstr \"FBX dosyası Ekleniyor...\"\n\n#: src/program/OutfitStudio.cpp:652\nmsgid \"\"\n\"Failed to find game install path registry value or GameDataPath in the \"\n\"config.\"\nmsgstr \"\"\n\"Yapılandırmada oyun yükleme yolu kayıt defteri değeri veya GameDataPath \"\n\"bulunamadı.\"\n\n#: src/program/OutfitStudio.cpp:975\nmsgid \"Failed to load OutfitStudio.xrc file!\"\nmsgstr \"Başarısız.. OutfitStudio.xrc Dosyası yüklenemedi!\"\n\n#: src/program/OutfitStudio.cpp:981\nmsgid \"Failed to load Outfit Studio frame!\"\nmsgstr \"Outfit Studio ana çerçevesi yüklenemedi!\"\n\n#: src/program/OutfitStudio.cpp:999 src/program/OutfitStudio.cpp:3754\n#: src/program/OutfitStudio.h:1082\nmsgid \"Ready!\"\nmsgstr \"Hazır!\"\n\n#: src/program/OutfitStudio.cpp:1447 src/program/OutfitStudio.cpp:1452\nmsgid \"Packing projects to folder...\"\nmsgstr \"Projeler klasöre paketleniyor...\"\n\n#: src/program/OutfitStudio.cpp:1473 src/program/OutfitStudio.cpp:1520\n#: src/program/OutfitStudio.cpp:1623\n#, c-format\nmsgid \"Failed to open input file '%s'!\"\nmsgstr \"Başarısız  '%s'! Açılamayan girdi dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1484\n#, c-format\nmsgid \"Failed to copy input file '%s'!\"\nmsgstr \"aşarısız  '%s'! Kopyalanamayan girdi dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1531\n#, c-format\nmsgid \"Failed to copy data file '%s'!\"\nmsgstr \"Başarısız  '%s'! Kopyalanamayan veri dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1541 src/program/OutfitStudio.cpp:1699\n#, c-format\nmsgid \"Failed to save merged project file '%s'!\"\nmsgstr \"Başarısız  '%s'! Kaydedilemeyen birleştirilmiş proje dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1550 src/program/OutfitStudio.cpp:1708\n#, c-format\nmsgid \"Failed to open project file '%s'!\"\nmsgstr \"Başarısız  '%s'! Açılamayan proje dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1561\n#, c-format\nmsgid \"Failed to copy merged project file '%s'!\"\nmsgstr \"Başarısız  '%s'! Kopyalanamayan birleştirilmiş proje dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1572 src/program/OutfitStudio.cpp:1734\n#, c-format\nmsgid \"Failed to open group file '%s'!\"\nmsgstr \"Başarısız  '%s'! Açılamayan grup dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1584\n#, c-format\nmsgid \"Failed to copy group file '%s'!\"\nmsgstr \"Başarısız  '%s'! Kopyalanamayan grup dosyası!\"\n\n#: src/program/OutfitStudio.cpp:1590 src/program/OutfitStudio.cpp:1756\nmsgid \"Packing finished.\"\nmsgstr \"Paketleme tamamlandı.\"\n\n#: src/program/OutfitStudio.cpp:1594 src/program/OutfitStudio.cpp:1599\nmsgid \"Packing projects to archive...\"\nmsgstr \"Arşivler klasöre paketleniyor...\"\n\n#: src/program/OutfitStudio.cpp:1631 src/program/OutfitStudio.cpp:1682\n#: src/program/OutfitStudio.cpp:1716 src/program/OutfitStudio.cpp:1743\nmsgid \"Failed to put new entry into archive!\"\nmsgstr \"Başarısız.. Yeni girdi arşive eklenemedi!\"\n\n#: src/program/OutfitStudio.cpp:1638 src/program/OutfitStudio.cpp:1689\n#: src/program/OutfitStudio.cpp:1723 src/program/OutfitStudio.cpp:1750\nmsgid \"Failed to copy file contents to archive!\"\nmsgstr \"Başarısız.. Dosya içeriği arşive kopyalanamadı!\"\n\n#: src/program/OutfitStudio.cpp:1674\n#, c-format\nmsgid \"Failed to open data file '%s'!\"\nmsgstr \"Başarısız  '%s'! Açılamayan veri dosyası!\"\n\n#: src/program/OutfitStudio.cpp:2012 src/program/OutfitStudio.cpp:2059\n#: src/program/OutfitStudio.cpp:3627 src/program/OutfitStudio.cpp:3634\n#: src/program/OutfitStudio.cpp:4622 src/program/OutfitStudio.cpp:4648\n#: src/program/OutfitStudio.cpp:7168 src/program/OutfitStudio.cpp:7296\n#: src/program/OutfitStudio.cpp:7542 src/program/OutfitStudio.cpp:7560\n#: src/program/OutfitStudio.cpp:7578\nmsgid \"There are no valid shapes loaded!\"\nmsgstr \"Başarısız  '%s'! Açılamayan veri dosyası!\"\n\n#: src/program/OutfitStudio.cpp:2020 src/program/OutfitStudio.cpp:2198\n#, c-format\nmsgid \"Saving project '%s'...\"\nmsgstr \"Proje kaydediliyor '%s'...\"\n\n#: src/program/OutfitStudio.cpp:2045 src/program/OutfitStudio.cpp:2223\nmsgid \"Saving failed.\"\nmsgstr \"Kayıt başarısız oldu.\"\n\n#: src/program/OutfitStudio.cpp:2050 src/program/OutfitStudio.cpp:2218\nmsgid \"Saved.\"\nmsgstr \"Kaydediliyor.\"\n\n#: src/program/OutfitStudio.cpp:2144\nmsgid \"Invalid or no slider set file specified! Please try again.\"\nmsgstr \"\"\n\"Geçersiz set veya hiç kaydırıcı ayar dosyası belirtilmemiş! Lütfen tekrar \"\n\"dene.\"\n\n#: src/program/OutfitStudio.cpp:2153\nmsgid \"No outfit name specified! Please try again.\"\nmsgstr \"Belirtilen bir kıyafet ismi yok! Lütfen tekrar dene.\"\n\n#: src/program/OutfitStudio.cpp:2161\nmsgid \"No data folder specified! Please try again.\"\nmsgstr \"Belirtilen bir data veri klasörü yok! Lütfen tekrar dene.\"\n\n#: src/program/OutfitStudio.cpp:2175\nmsgid \"\"\n\"An invalid or no base outfit .nif file name specified! Please try again.\"\nmsgstr \"\"\n\"Geçersiz veya temelsiz bir kıyafet .nif dosya adı belirtildi! Lütfen tekrar \"\n\"dene.\"\n\n#: src/program/OutfitStudio.cpp:2184\nmsgid \"No game file path specified! Please try again.\"\nmsgstr \"Oyun dosyası yolu belirtilmemiş! Lütfen tekrar dene.\"\n\n#: src/program/OutfitStudio.cpp:2190\nmsgid \"No game file name specified! Please try again.\"\nmsgstr \"Oyun dosya adı belirtilmemiş! Lütfen tekrar dene.\"\n\n#: src/program/OutfitStudio.cpp:2235\n#, c-format\nmsgid \"Failed to open '%s' as a slider set file!\"\nmsgstr \"u dosya '%s' bir kaydırıcı seti olarak açılamadı!\"\n\n#: src/program/OutfitStudio.cpp:2235 src/program/OutfitStudio.cpp:2299\nmsgid \"Slider Set Error\"\nmsgstr \"Kaydırıcı Seti Hatası\"\n\n#: src/program/OutfitStudio.cpp:2254\nmsgid \"Please choose an outfit to load\"\nmsgstr \"Lütfen yüklemek için bir kıyafet seç\"\n\n#: src/program/OutfitStudio.cpp:2254\nmsgid \"Load a slider set\"\nmsgstr \"Bir kaydırıcı seti yükle\"\n\n#: src/program/OutfitStudio.cpp:2265\nmsgid \"Loading project...\"\nmsgstr \"Proje yükleniyor...\"\n\n#: src/program/OutfitStudio.cpp:2285\nmsgid \"Loading outfit data...\"\nmsgstr \"Kıyafet verileri yükleniyor...\"\n\n#: src/program/OutfitStudio.cpp:2299\n#, c-format\nmsgid \"Failed to create project '%s' from file '%s' (%d)!\"\nmsgstr \"'%s' dosyasından '%s' (%d) Proje oluşturulamadı!\"\n\n#: src/program/OutfitStudio.cpp:2313\n#, c-format\nmsgid \"Loading reference shape '%s'...\"\nmsgstr \"Örnek kalıp yükleniyor '%s'...\"\n\n#: src/program/OutfitStudio.cpp:2327\nmsgid \"Loading textures...\"\nmsgstr \"Textures Data Yükleniyor...\"\n\n#: src/program/OutfitStudio.cpp:2332 src/program/OutfitStudio.cpp:3472\n#: src/program/OutfitStudio.cpp:3717\nmsgid \"Creating outfit...\"\nmsgstr \"Kıyafet oluşturma...\"\n\n#: src/program/OutfitStudio.cpp:2336 src/program/OutfitStudio.cpp:3482\n#: src/program/OutfitStudio.cpp:3617\n#, c-format\nmsgid \"Creating %zu slider(s)...\"\nmsgstr \"Kaydırıcı(lar) %zu oluşturuluyor...\"\n\n#: src/program/OutfitStudio.cpp:2355\nmsgid \"Creating sliders...\"\nmsgstr \"Kaydırıcılar oluşturuluyor...\"\n\n#: src/program/OutfitStudio.cpp:2358\nmsgid \"Clearing old sliders...\"\nmsgstr \"Eski kaydırıcılar temizleniyor...\"\n\n#: src/program/OutfitStudio.cpp:2369\nmsgid \"Loading slider: \"\nmsgstr \"Yüklenen kaydırıcı: \"\n\n#: src/program/OutfitStudio.cpp:2429 src/program/OutfitStudio.cpp:7699\nmsgid \"Enter a name for the new slider:\"\nmsgstr \"Kaydırıcı için yeni bir isim girin:\"\n\n#: src/program/OutfitStudio.cpp:2429 src/program/OutfitStudio.cpp:7699\nmsgid \"Create New Slider\"\nmsgstr \"Yeni Kaydırıcı Oluştur\"\n\n#: src/program/OutfitStudio.cpp:2555\n#, c-format\nmsgid \"Total Bones: %zu\"\nmsgstr \"Toplam İskelet: %zu\"\n\n#: src/program/OutfitStudio.cpp:2570\n#, c-format\nmsgid \"Shape Selection Bones: %zu\"\nmsgstr \"Kalıp İçin Seçilen İskeletler: %zu\"\n\n#: src/program/OutfitStudio.cpp:3072\nmsgid \"Edit Color\"\nmsgstr \"Renk Düzenleme\"\n\n#: src/program/OutfitStudio.cpp:3234\nmsgid \"\"\n\"You are trying to edit a slider's morph with that slider set to zero.  Do \"\n\"you wish to set the slider to one now?\"\nmsgstr \"\"\n\"Bu kaydırıcı sıfıra ayarlıyken bir kaydırıcının (morps) dönüşümünü \"\n\"düzenlemeye çalışıyorsunuz. Kaydırıcıyı şimdi bir değerine ayarlamak ister \"\n\"misiniz?\"\n\n#: src/program/OutfitStudio.cpp:3251\nmsgid \"\"\n\"You can only use the undiff brush while editing a slider. Note, use the \"\n\"pencil button next to a slider to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"Bir kaydırıcıyı düzenlerken yalnızca yayma fırçasıyla çalışabilirsin. Bu \"\n\"kaydırıcının dönüşümünü düzenlemeyi etkinleştirmek için kaydırıcının \"\n\"yanındaki kalem düğmesini kullanabilirsin.\"\n\n#: src/program/OutfitStudio.cpp:3262\nmsgid \"\"\n\"You can only edit the base shape when all sliders are zero. Do you wish to \"\n\"set all sliders to zero now?  Note, use the pencil button next to a slider \"\n\"to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"Yalnızca tüm kaydırıcılar sıfır olduğunda temel şekli düzenleyebilirsin. \"\n\"Şimdi tüm kaydırıcıları sıfırlamak istiyor musun? Not: Bu kaydırıcının morph \"\n\"düzenlenmesini sağlamak için kaydırıcının yanındaki kalem düğmesini \"\n\"kullanmalısın.\"\n\n#: src/program/OutfitStudio.cpp:3338\n#, c-format\nmsgid \"You have unsaved changes to '%s'. Would you like to save them now?\"\nmsgstr \"\"\n\"'%s' Üzerinde kaydedilmemiş değişikliklerin var. Onları şimdi kurtarmak \"\n\"ister misin?\"\n\n#: src/program/OutfitStudio.cpp:3339\nmsgid \"Unsaved Changes\"\nmsgstr \"Kaydedilmemiş Değişiklikler\"\n\n#: src/program/OutfitStudio.cpp:3394\n#, c-format\nmsgid \"Creating project '%s'...\"\nmsgstr \"Proje oluşturuluyor '%s'...\"\n\n#: src/program/OutfitStudio.cpp:3411 src/program/OutfitStudio.cpp:3555\nmsgid \"Loading reference...\"\nmsgstr \"Örnek yükleniyor...\"\n\n#: src/program/OutfitStudio.cpp:3451 src/program/OutfitStudio.cpp:3675\n#: src/program/OutfitStudio.cpp:3684\nmsgid \"Loading outfit...\"\nmsgstr \"Kıyafet yükleniyor...\"\n\n#: src/program/OutfitStudio.cpp:3497\nmsgid \"Select a slider set to load\"\nmsgstr \"Yüklemek için bir kaydırıcı seç\"\n\n#: src/program/OutfitStudio.cpp:3514\nmsgid \"Select a slider set to add\"\nmsgstr \"Eklenecek kaydırıcıyı seç\"\n\n#: src/program/OutfitStudio.cpp:3531 src/program/OutfitStudio.cpp:3639\n#: src/program/OutfitStudio.cpp:8705 src/program/OutfitStudio.cpp:8760\n#: src/program/OutfitStudio.cpp:8851 src/program/OutfitStudio.cpp:8974\nmsgid \"\"\n\"You're currently editing slider data, please exit the slider's edit mode \"\n\"(pencil button) and try again.\"\nmsgstr \"\"\n\"Şu anda kaydırıcı verilerini düzenliyorsun, lütfen kaydırıcının düzenleme \"\n\"modundan çık (kalem butonuyla) ve tekrar dene.\"\n\n#: src/program/OutfitStudio.cpp:3561\nmsgid \"Loading reference set...\"\nmsgstr \"Örnek set yükleniyor...\"\n\n#: src/program/OutfitStudio.cpp:3613\nmsgid \"Creating reference...\"\nmsgstr \"Örnek oluşturuluyor...\"\n\n#: src/program/OutfitStudio.cpp:3727\nmsgid \"Unload the project? All unsaved changes will be lost\"\nmsgstr \"\"\n\"Projeyi gerçekten kaldırmayı istiyor musun? Kaydedilmemiş tüm değişiklikler \"\n\"silinecek.\"\n\n#: src/program/OutfitStudio.cpp:3727\nmsgid \"Unload Project\"\nmsgstr \"Projeyi Kaldır\"\n\n#: src/program/OutfitStudio.cpp:3728\nmsgid \"Unload\"\nmsgstr \"Kaldır\"\n\n#: src/program/OutfitStudio.cpp:4196\nmsgid \"Import NIF file\"\nmsgstr \"NIF dosyası Yerleştir\"\n\n#: src/program/OutfitStudio.cpp:4203 src/program/OutfitStudio.cpp:4204\nmsgid \"Importing NIF file...\"\nmsgstr \"NIF dosyası yerleştiriliyor...\"\n\n#: src/program/OutfitStudio.cpp:4225\nmsgid \"Export outfit NIF\"\nmsgstr \"Kıyafet çıktısı NIF olarak\"\n\n#: src/program/OutfitStudio.cpp:4243\n#, c-format\nmsgid \"Failed to save NIF file '%s'!\"\nmsgstr \"NIF dosyası olarak kaydedilemedi '%s'!\"\n\n#: src/program/OutfitStudio.cpp:4243 src/program/OutfitStudio.cpp:4275\n#: src/program/OutfitStudio.cpp:4360 src/program/OutfitStudio.cpp:4485\n#: src/program/OutfitStudio.cpp:4710\nmsgid \"Export Error\"\nmsgstr \"Dışa Aktarma Hatası\"\n\n#: src/program/OutfitStudio.cpp:4259\nmsgid \"Export project NIF\"\nmsgstr \"Proje NIF dosyasını dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4275\n#, c-format\nmsgid \"Failed to save NIF file '%s' with reference!\"\nmsgstr \"NIF dosyası '%s' örnek dosya olarak kaydedilemedi!\"\n\n#: src/program/OutfitStudio.cpp:4281 src/program/OutfitStudio.cpp:4366\n#: src/program/OutfitStudio.cpp:4491 src/program/OutfitStudio.cpp:4627\n#: src/program/OutfitStudio.cpp:4653 src/program/OutfitStudio.cpp:7097\n#: src/program/OutfitStudio.cpp:7122 src/program/OutfitStudio.cpp:7143\n#: src/program/OutfitStudio.cpp:7412 src/program/OutfitStudio.cpp:7437\n#: src/program/OutfitStudio.cpp:7473 src/program/OutfitStudio.cpp:7506\n#: src/program/OutfitStudio.cpp:7602 src/program/OutfitStudio.cpp:7653\n#: src/program/OutfitStudio.cpp:7715 src/program/OutfitStudio.cpp:7732\n#: src/program/OutfitStudio.cpp:8114 src/program/OutfitStudio.cpp:8131\n#: src/program/OutfitStudio.cpp:8151 src/program/OutfitStudio.cpp:8175\n#: src/program/OutfitStudio.cpp:8209 src/program/OutfitStudio.cpp:8361\n#: src/program/OutfitStudio.cpp:8550 src/program/OutfitStudio.cpp:8700\n#: src/program/OutfitStudio.cpp:8755 src/program/OutfitStudio.cpp:8969\n#: src/program/OutfitStudio.cpp:9056 src/program/OutfitStudio.cpp:9528\n#: src/program/OutfitStudio.cpp:9619 src/program/OutfitStudio.cpp:9712\n#: src/program/OutfitStudio.cpp:9757 src/program/OutfitStudio.cpp:9798\n#: src/program/OutfitStudio.cpp:9845 src/program/OutfitStudio.cpp:10096\n#: src/program/OutfitStudio.cpp:10142 src/program/OutfitStudio.cpp:10245\n#: src/program/OutfitStudio.cpp:10388 src/program/OutfitStudio.cpp:13426\nmsgid \"There is no shape selected!\"\nmsgstr \"Seçili bir kalıp yok!\"\n\n#: src/program/OutfitStudio.cpp:4288\nmsgid \"Export selected shapes to NIF\"\nmsgstr \"Seçilen modeli bir NIF kalıbı olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4300\nmsgid \"Failed to export selected shapes to NIF file!\"\nmsgstr \"Seçilen model bir NIF kalıbı olarak dışa aktarılamadı!\"\n\n#: src/program/OutfitStudio.cpp:4305\nmsgid \"Import .obj file for new shape\"\nmsgstr \"eni kalıp içerisine .obj dosyasını yerleştir\"\n\n#: src/program/OutfitStudio.cpp:4343\nmsgid \"\"\n\"Some of the shapes have coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the OBJ?  (This is not recommended.)\"\nmsgstr \"\"\n\"Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat \"\n\"sistemlerine sahiptir. Geometri, OBJ'de genel koordinatlara dönüştürülsün \"\n\"mü? (Bu tavsiye edilmez.)\"\n\n#: src/program/OutfitStudio.cpp:4345 src/program/OutfitStudio.cpp:4380\n#: src/program/OutfitStudio.cpp:4470 src/program/OutfitStudio.cpp:4505\nmsgid \"Transform to global\"\nmsgstr \"Küresel Dönüşüm\"\n\n#: src/program/OutfitStudio.cpp:4352\nmsgid \"Export project as an .obj file\"\nmsgstr \"Projeyi bir .obj dosyası olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4360 src/program/OutfitStudio.cpp:4402\n#: src/program/OutfitStudio.cpp:4421 src/program/OutfitStudio.cpp:7533\nmsgid \"Failed to export OBJ file!\"\nmsgstr \"OBJ dosyası çıkartımı başarısız!\"\n\n#: src/program/OutfitStudio.cpp:4378\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the OBJ?\"\nmsgstr \"\"\n\"Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat \"\n\"sistemlerine sahiptir. Geometri, OBJ'de genel koordinatlara dönüştürülsün mü?\"\n\n#: src/program/OutfitStudio.cpp:4389\nmsgid \"Export selected shapes as an .obj file\"\nmsgstr \"Seçilen kalıpları bir .obj dosyası olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4406\nmsgid \"Export shape as an .obj file\"\nmsgstr \"Kalıbı bir .obj dosyası olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4427\nmsgid \"Import .fbx file for new shape\"\nmsgstr \"Yeni kalıp içerisine .fbx dosyasını yerleştir\"\n\n#: src/program/OutfitStudio.cpp:4468\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the FBX?  (This is not recommended.)\"\nmsgstr \"\"\n\"Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat \"\n\"sistemlerine sahiptir. Geometri, FBX genel koordinatlara dönüştürülsün mü? \"\n\"(Bu tavsiye edilmez.)\"\n\n#: src/program/OutfitStudio.cpp:4477\nmsgid \"Export project as an .fbx file\"\nmsgstr \"Projeyi bir .fbx dosyası olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4485 src/program/OutfitStudio.cpp:4527\n#: src/program/OutfitStudio.cpp:4546\nmsgid \"Failed to export FBX file!\"\nmsgstr \"FBX dosyası çıkartımı başarısız!\"\n\n#: src/program/OutfitStudio.cpp:4503\nmsgid \"\"\n\"Some of the shapes have skin coordinate systems that are not the same as the \"\n\"global coordinate system.  Should the geometry be transformed to global \"\n\"coordinates in the FBX?\"\nmsgstr \"\"\n\"Kalıplardan bazıları, küresel koordinat sistemiyle aynı olmayan koordinat \"\n\"sistemlerine sahiptir. Geometri, FBX genel koordinatlara dönüştürülsün mü?\"\n\n#: src/program/OutfitStudio.cpp:4514\nmsgid \"Export selected shapes as an .fbx file\"\nmsgstr \"Seçilen kalıpları .fbx dosyası olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4531\nmsgid \"Export shape as an .fbx file\"\nmsgstr \"Kalıbı bir .fbx dosyası olarak dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:4552 src/program/OutfitStudio.cpp:7300\nmsgid \"Import .tri morphs\"\nmsgstr \".tri morphs dosyası yerleştir\"\n\n#: src/program/OutfitStudio.cpp:4571 src/program/OutfitStudio.cpp:7309\nmsgid \"Failed to load TRI file!\"\nmsgstr \"TRI dosyası yerleştirilemedi!\"\n\n#: src/program/OutfitStudio.cpp:4577 src/program/OutfitStudio.cpp:8157\nmsgid \"Please enter a new unique name for the shape.\"\nmsgstr \"Lütfen kalıp için yeni bir isim girin.\"\n\n#: src/program/OutfitStudio.cpp:4577 src/program/OutfitStudio.cpp:8157\nmsgid \"Rename Shape\"\nmsgstr \"Kalıbı Yeniden Adlandır\"\n\n#: src/program/OutfitStudio.cpp:4631 src/program/OutfitStudio.cpp:4657\n#: src/program/OutfitStudio.cpp:7564\nmsgid \"Export .tri morphs\"\nmsgstr \".tri morphs Olarak Çıkart\"\n\n#: src/program/OutfitStudio.cpp:4641 src/program/OutfitStudio.cpp:4664\n#: src/program/OutfitStudio.cpp:7571\nmsgid \"Failed to export TRI file!\"\nmsgstr \"TRI dosyası olarak dışa çıkartma başarısız!\"\n\n#: src/program/OutfitStudio.cpp:4669\nmsgid \"Import physics data to project\"\nmsgstr \"Projeye fizik data dosyasını yerleştir\"\n\n#: src/program/OutfitStudio.cpp:4676\n#, c-format\nmsgid \"Failed to import physics data file '%s'!\"\nmsgstr \"Fizik dosyası yüklemesi başarısız '%s'!\"\n\n#: src/program/OutfitStudio.cpp:4676\nmsgid \"Import Error\"\nmsgstr \"Yerleştirme Hatası\"\n\n#: src/program/OutfitStudio.cpp:4688\nmsgid \"There is no physics data loaded!\"\nmsgstr \"Yüklenen dosyada herhangi bir fizik bilgisi yok!\"\n\n#: src/program/OutfitStudio.cpp:4688 src/program/OutfitStudio.cpp:6384\n#: src/program/OutfitStudio.cpp:7084\nmsgid \"Info\"\nmsgstr \"Bilgi\"\n\n#: src/program/OutfitStudio.cpp:4696\nmsgid \"Please choose the physics data source you want to export.\"\nmsgstr \"Lütfen yerleştirmek istediğin fizik veri kaynağını seç.\"\n\n#: src/program/OutfitStudio.cpp:4696\nmsgid \"Choose physics data\"\nmsgstr \"Fizik verilerini seç\"\n\n#: src/program/OutfitStudio.cpp:4704\nmsgid \"Export physics data\"\nmsgstr \"Fizik verilerini yerleştir\"\n\n#: src/program/OutfitStudio.cpp:4710\n#, c-format\nmsgid \"Failed to save physics data file '%s'!\"\nmsgstr \"Fizik veri dosyaları yerleştirmesi başarısız '%s'!\"\n\n#: src/program/OutfitStudio.cpp:4717\nmsgid \"This function requires at least one slider position to be non-zero.\"\nmsgstr \"\"\n\"Bu işlev değeri sıfır olmayan bir en az bir tane kaydırma konumu gerektirir.\"\n\n#: src/program/OutfitStudio.cpp:4729\nmsgid \"\"\n\"Create a conversion slider for the current slider settings with the \"\n\"following name: \"\nmsgstr \"\"\n\"Geçerli kaydırıcı ayarları için aşağıda aynı adla bir dönüşüm kaydırıcısını \"\n\"oluştur: \"\n\n#: src/program/OutfitStudio.cpp:4729\nmsgid \"Create New Conversion Slider\"\nmsgstr \"Yeni Dönüşüm Kaydırıcısı Oluştur\"\n\n#: src/program/OutfitStudio.cpp:5472\nmsgid \"Please enter an SSF file path.\"\nmsgstr \"Lütfen bir SSF dosya yolu gir.\"\n\n#: src/program/OutfitStudio.cpp:6229\n#, c-format\nmsgid \"Field of View: %d\"\nmsgstr \"Görüş Alanı: %d\"\n\n#: src/program/OutfitStudio.cpp:6359\nmsgid \"Your changes were not applied yet. Do you want to apply or reset them?\"\nmsgstr \"\"\n\"Yaptığınız değişiklikler henüz uygulanmadı. Bunları uygulamak mı yoksa \"\n\"sıfırlamak mı istiyorsunuz?\"\n\n#: src/program/OutfitStudio.cpp:6360\nmsgid \"Pending Changes\"\nmsgstr \"Bekleyen Değişiklikler\"\n\n#: src/program/OutfitStudio.cpp:6384\nmsgid \"\"\n\"You must have exactly one mesh selected in order to edit partitions or \"\n\"segments.\"\nmsgstr \"\"\n\"Bölümleri veya segmentleri tam olarak düzenlemek için bir mesh dosyası \"\n\"seçmelisin.\"\n\n#: src/program/OutfitStudio.cpp:7033\nmsgid \"There are no sliders loaded!\"\nmsgstr \"Yüklenen bir kaydırıcı yok!\"\n\n#: src/program/OutfitStudio.cpp:7084\nmsgid \"No changes were made to the sliders, so no preset was saved!\"\nmsgstr \"\"\n\"Kaydırıcılara herhangi bir değişiklik yapılmadı, bu nedenle hiçbir hazır \"\n\"ayar kaydedilmedi!\"\n\n#: src/program/OutfitStudio.cpp:7101 src/program/OutfitStudio.cpp:7126\n#: src/program/OutfitStudio.cpp:7147 src/program/OutfitStudio.cpp:7416\nmsgid \"There is no slider in edit mode to import data to!\"\nmsgstr \"Verileri içe aktarmak için düzenleme modunda hiç kaydırıcı yok!\"\n\n#: src/program/OutfitStudio.cpp:7105\nmsgid \"Import .nif file for slider calculation\"\nmsgstr \"Kaydırıcı hesaplaması için .nif dosyasını içe aktar\"\n\n#: src/program/OutfitStudio.cpp:7112\nmsgid \"No mesh found in the .nif file that matches currently selected shape!\"\nmsgstr \".nif dosyasında şu anda seçili kalıba uyan ağ yapısı bulunamadı!\"\n\n#: src/program/OutfitStudio.cpp:7130\nmsgid \"Import .bsd slider data\"\nmsgstr \".bsd Kaydırıcı Dosyası Yerleştir\"\n\n#: src/program/OutfitStudio.cpp:7151\nmsgid \"Import .obj file for slider calculation\"\nmsgstr \".obj kaydırıcı hesaplama dosyası yerleştir\"\n\n#: src/program/OutfitStudio.cpp:7158 src/program/OutfitStudio.cpp:7427\nmsgid \"Vertex count of .obj file mesh does not match currently selected shape!\"\nmsgstr \".obj dosya kafesinin köşe sayısı şu an seçili olan kalıpla eşleşmiyor!\"\n\n#: src/program/OutfitStudio.cpp:7172\nmsgid \"Import .osd file\"\nmsgstr \".osd Dosyasını Yerleştir\"\n\n#: src/program/OutfitStudio.cpp:7181\nmsgid \"Failed to import OSD file!\"\nmsgstr \"OSD Dosyası yerleştirmesi başarısız!\"\n\n#: src/program/OutfitStudio.cpp:7221 src/program/OutfitStudio.cpp:7332\nmsgid \"This will delete all loaded sliders. Are you sure?\"\nmsgstr \"Bu işlem, tüm yüklü kaydırıcıları siler. Emin misin?\"\n\n#: src/program/OutfitStudio.cpp:7221 src/program/OutfitStudio.cpp:7291\nmsgid \"OSD Import\"\nmsgstr \"OSD Yerleştir\"\n\n#: src/program/OutfitStudio.cpp:7291 src/program/OutfitStudio.cpp:7407\n#, c-format\nmsgid \"\"\n\"Added morphs for the following shapes:\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"Aşağıdaki kalıplara morphs dosyası eklendi:\\n\"\n\"\\n\"\n\"%s\"\n\n#: src/program/OutfitStudio.cpp:7332 src/program/OutfitStudio.cpp:7407\nmsgid \"TRI Import\"\nmsgstr \"TRI Yerleştir\"\n\n#: src/program/OutfitStudio.cpp:7420\nmsgid \"Import .fbx file for slider calculation\"\nmsgstr \".fbx kaydırıcı hesaplama dosyası yerleştir\"\n\n#: src/program/OutfitStudio.cpp:7441 src/program/OutfitStudio.cpp:7477\n#: src/program/OutfitStudio.cpp:7510\nmsgid \"There is no slider in edit mode to export data from!\"\nmsgstr \"Verileri dışa aktarmak için düzenleme modunda hiç kaydırıcı yok!\"\n\n#: src/program/OutfitStudio.cpp:7446\nmsgid \"Export .nif slider data to directory\"\nmsgstr \".nif kaydırıcı verilerini dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:7457\nmsgid \"Export .nif slider data\"\nmsgstr \".nif kaydırıcı verilerini Çıkart\"\n\n#: src/program/OutfitStudio.cpp:7464\nmsgid \"Failed to export NIF file!\"\nmsgstr \"NIF dosyası Dışa Aktarılamadı!\"\n\n#: src/program/OutfitStudio.cpp:7482\nmsgid \"Export .bsd slider data to directory\"\nmsgstr \".bsd kaydırıcı verilerini dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:7493\nmsgid \"Export .bsd slider data\"\nmsgstr \".bsd kaydırıcı verilerini Çıkart\"\n\n#: src/program/OutfitStudio.cpp:7515 src/program/OutfitStudio.cpp:7582\nmsgid \"Export .obj slider data to directory\"\nmsgstr \".obj kaydırıcı verilerini dışa aktar\"\n\n#: src/program/OutfitStudio.cpp:7526\nmsgid \"Export .obj slider data\"\nmsgstr \".obj kaydırıcı verilerini Çıkart\"\n\n#: src/program/OutfitStudio.cpp:7546\nmsgid \"Export .osd file\"\nmsgstr \".osd Olarak Çıkart\"\n\n#: src/program/OutfitStudio.cpp:7553\nmsgid \"Failed to export OSD file!\"\nmsgstr \"OSD dosyası dışa çıkartma başarısız!\"\n\n#: src/program/OutfitStudio.cpp:7608\nmsgid \"\"\n\"Are you sure you wish to clear the unmasked slider data for the selected \"\n\"shapes?  This action cannot be undone.\"\nmsgstr \"\"\n\"Maskelememiş kaydırıcı verilerini silmek istediğinden emin misin ? Bu işlem \"\n\"geri alınamaz.\"\n\n#: src/program/OutfitStudio.cpp:7609 src/program/OutfitStudio.cpp:7614\nmsgid \"Confirm data erase\"\nmsgstr \"Veri silme işlemini onayla\"\n\n#: src/program/OutfitStudio.cpp:7612\n#, c-format\nmsgid \"\"\n\"Are you sure you wish to clear the unmasked slider data for the shape '%s'?  \"\n\"This action cannot be undone.\"\nmsgstr \"\"\n\"'%s' kalıbı için maskelenmemiş kaydırıcı verilerini silmek istediğinden emin \"\n\"misin? Bu işlem geri alınamaz.\"\n\n#: src/program/OutfitStudio.cpp:7667\nmsgid \"Enter a name for the new zap:\"\nmsgstr \"Yeni zap için bir isim gir:\"\n\n#: src/program/OutfitStudio.cpp:7667\nmsgid \"Create New Zap\"\nmsgstr \"Yeni Zap Olustur\"\n\n#: src/program/OutfitStudio.cpp:7719\nmsgid \"There is no slider in edit mode to negate!\"\nmsgstr \"Düzenleme modunda düzenleme yapmak için bir kaydırıcı yok!\"\n\n#: src/program/OutfitStudio.cpp:7736\nmsgid \"There is no slider in edit mode to create a mask from!\"\nmsgstr \"Maske oluşturmak için düzenleme modunda bir kaydırıcı yok!\"\n\n#: src/program/OutfitStudio.cpp:7746\nmsgid \"Are you sure you wish to delete the selected slider(s)?\"\nmsgstr \"Seçilen kaydırıcı(ları) silmek istediğinden emin misin?\"\n\n#: src/program/OutfitStudio.cpp:7747\nmsgid \"Confirm slider delete\"\nmsgstr \"Kaydırıcıyı silmeyi onayla\"\n\n#: src/program/OutfitStudio.cpp:7947\nmsgid \"There is no slider in edit mode to show properties for!\"\nmsgstr \"Özellikleri göstermek için düzenleme modunda kaydırıcı yok!\"\n\n#: src/program/OutfitStudio.cpp:7960 src/program/OutfitStudio.cpp:8004\nmsgid \"Conforming: \"\nmsgstr \"Uyum sağlanıyor: \"\n\n#: src/program/OutfitStudio.cpp:7991\nmsgid \"Conforming shapes...\"\nmsgstr \"Kalıplara uygulanıyor...\"\n\n#: src/program/OutfitStudio.cpp:8015\nmsgid \"All shapes conformed.\"\nmsgstr \"Tüm kalıplar uyumlu.\"\n\n#: src/program/OutfitStudio.cpp:8729\nmsgid \"Are you sure you wish to delete parts of the selected shapes?\"\nmsgstr \"Seçili kalıp parçalarını silmek istediğinden emin misin?\"\n\n#: src/program/OutfitStudio.cpp:8729 src/program/OutfitStudio.cpp:9060\nmsgid \"Confirm Delete\"\nmsgstr \"Silmeyi Onayla\"\n\n#: src/program/OutfitStudio.cpp:8771\nmsgid \"Please enter a unique name for the new separated shape.\"\nmsgstr \"Lütfen yeni ayrıştırılmış modelin için yeni bir isim gir.\"\n\n#: src/program/OutfitStudio.cpp:8771\nmsgid \"Separate Vertices...\"\nmsgstr \"Ayrışmış Köşeler...\"\n\n#: src/program/OutfitStudio.cpp:8821\nmsgid \"No errors found!\"\nmsgstr \"Hata bulunmadı!\"\n\n#: src/program/OutfitStudio.cpp:8827\nmsgid \"Errors:\"\nmsgstr \"Hatalar:\"\n\n#: src/program/OutfitStudio.cpp:8829\nmsgid \"Target must be different from source.\"\nmsgstr \"Hedef kaynaktan farklı olmalıdır.\"\n\n#: src/program/OutfitStudio.cpp:8831\nmsgid \"\"\n\"Partitions do not match. Make sure the amount of partitions and their slots \"\n\"match up.\"\nmsgstr \"\"\n\"Bölümler eşleşmiyor. Bölümlerin miktarının ve yuvalarının eşleştiğinden emin \"\n\"ol.\"\n\n#: src/program/OutfitStudio.cpp:8833\nmsgid \"\"\n\"Segments do not match. Make sure the amount of segments, sub segments and \"\n\"their info as well as the segmentation file match.\"\nmsgstr \"\"\n\"Segmentler eşleşmiyor. Segmentlerin, alt segmentlerin ve bilgilerinin yanı \"\n\"sıra segmentasyon dosyasının eşleştiğinden emin ol.\"\n\n#: src/program/OutfitStudio.cpp:8835\nmsgid \"Resulting shape would have too many vertices.\"\nmsgstr \"Ortaya çıkan kalıbta çok fazla tepe noktası oluşur.\"\n\n#: src/program/OutfitStudio.cpp:8837\nmsgid \"Resulting shape would have too many triangles.\"\nmsgstr \"Ortaya çıkan kalıbta çok fazla üçgen köşe oluşur.\"\n\n#: src/program/OutfitStudio.cpp:8839\nmsgid \"\"\n\"Shaders do not match. Make sure both shapes either have or don't have a \"\n\"shader and their shader type matches.\"\nmsgstr \"\"\n\"Shader eşleşmiyor. Her iki kalıbın da gölgelendiricisi olduğundan ve \"\n\"gölgelendirici türünün eşleştiğinden emin ol.\"\n\n#: src/program/OutfitStudio.cpp:8841\nmsgid \"\"\n\"Base texture doesn't match. Make sure both shapes have the same base/diffuse \"\n\"texture path.\"\nmsgstr \"\"\n\"Temel texture-doku eşleşmiyor. Her iki şeklin de aynı temel/gerçek doku \"\n\"yoluna sahip olduğundan emin ol.\"\n\n#: src/program/OutfitStudio.cpp:8843\nmsgid \"\"\n\"Alpha property mismatch. Make sure both shapes either have or don't have an \"\n\"alpha property and their flags + threshold match.\"\nmsgstr \"\"\n\"Alfa uyuşmazlığı. Her iki kalıbın da alfa özelliğine sahip olduğundan ve \"\n\"ortak bayrak + ortak eşik değerlerine sahip olduğundan emin ol.\"\n\n#: src/program/OutfitStudio.cpp:8930\nmsgid \"\"\n\"You can only copy shapes into an outfit, and there is no outfit in the \"\n\"current project. Load one first!\"\nmsgstr \"\"\n\"Kalıpları yalnızca bir kıyafete kopyalayabilirsin ve mevcut projende \"\n\"kıyafetin yok. Önce bir tane yüklemelisin!\"\n\n#: src/program/OutfitStudio.cpp:8937\nmsgid \"Please enter a unique name for the duplicated shape.\"\nmsgstr \"Lütfen çoğaltılmış kalıp için yeni bir isim gir.\"\n\n#: src/program/OutfitStudio.cpp:8937\nmsgid \"Duplicate Shape\"\nmsgstr \"Kalıbı Çoğalt\"\n\n#: src/program/OutfitStudio.cpp:8979\nmsgid \"There is more than one shape selected.\"\nmsgstr \"Birden fazla kalıp seçili.\"\n\n#: src/program/OutfitStudio.cpp:9034\nmsgid \"\"\n\"An edge has multiple triangles of the same orientation.  Correct the \"\n\"orientations before splitting.\"\nmsgstr \"\"\n\"Bir kenar, aynı yönelimde birden çok üçgene sahiptir. Bölmeden önce \"\n\"oryantasyonlarını düzeltmelisin.\"\n\n#: src/program/OutfitStudio.cpp:9060\nmsgid \"\"\n\"Are you sure you wish to delete the selected shapes?  This action cannot be \"\n\"undone.\"\nmsgstr \"\"\n\"Seçilen kalıpları silmek istediğinden emin misin? Bu işlem geri alınamaz.\"\n\n#: src/program/OutfitStudio.cpp:9220\nmsgid \"No bone name was entered!\"\nmsgstr \"Kemik adı girilmedi!\"\n\n#: src/program/OutfitStudio.cpp:9228\n#, c-format\nmsgid \"Bone '%s' already exists in the project!\"\nmsgstr \"Bu kemik '%s' projende zaten mevcut!\"\n\n#: src/program/OutfitStudio.cpp:9358\nmsgid \"\"\n\"The following shapes have unweighted vertices, which can cause issues. The \"\n\"affected vertices have been put under a mask. Do you want to save anyway?\"\nmsgstr \"\"\n\"Aşağıdaki kalıplar sorunlara neden olabilecek, ağırlıksız köşelere sahip. \"\n\"Etkilenen köşeler bir maskenin altına yerleştirildi. Yine de kaydetmek ister \"\n\"misin?\"\n\n#: src/program/OutfitStudio.cpp:9361\nmsgid \"Unweighted Vertices\"\nmsgstr \"Ağırlıksız Tepe Noktaları\"\n\n#: src/program/OutfitStudio.cpp:9533 src/program/OutfitStudio.cpp:9624\n#: src/program/OutfitStudio.cpp:9718 src/program/OutfitStudio.cpp:9850\nmsgid \"There is no reference shape!\"\nmsgstr \"Seçili bir örnek kalıbı yok!\"\n\n#: src/program/OutfitStudio.cpp:9542 src/program/OutfitStudio.cpp:9692\nmsgid \"\"\n\"Sorry, you can't copy weights from the reference shape to itself. Skipping \"\n\"this shape.\"\nmsgstr \"\"\n\"Üzgünüm, referans şekillerindeki ağırlıkları istediğin gibi kopyalayamazsın. \"\n\"Bu kalıbı atlamalısın.\"\n\n#: src/program/OutfitStudio.cpp:9542 src/program/OutfitStudio.cpp:9692\nmsgid \"Can't copy weights\"\nmsgstr \"Ağırlıklar kopyalanamaz\"\n\n#: src/program/OutfitStudio.cpp:9662\nmsgid \"Copying selected bone weights...\"\nmsgstr \"Seçilen kemik ağırlıklarını kopyalar...\"\n\n#: src/program/OutfitStudio.cpp:9723\nmsgid \"Sorry, you can't copy weights from the reference shape to itself.\"\nmsgstr \"\"\n\"Üzgünüm, referans şekillerindeki ağırlıkları istediğin gibi kopyalayamazsın.\"\n\n#: src/program/OutfitStudio.cpp:9730\nmsgid \"The vertex count of the reference and chosen shape is not the same!\"\nmsgstr \"Örneğin ve seçilen modelin köşe sayısı aynı değildir!\"\n\n#: src/program/OutfitStudio.cpp:9859\nmsgid \"\"\n\"Sorry, you can't copy partitions/segments from the reference shape to \"\n\"itself. Skipping this shape.\"\nmsgstr \"\"\n\"Üzgünüm, referans şekillerindeki bölüm/segmentleri istediğin gibi \"\n\"kopyalayamazsın. Bu kalıbı atlamalısın.\"\n\n#: src/program/OutfitStudio.cpp:9859\nmsgid \"Can't copy segments/partitions\"\nmsgstr \"Segment/Bölümler kopyalanamaz\"\n\n#: src/program/OutfitStudio.cpp:9864\nmsgid \"\"\n\"Triangles will be assigned to the partition/segment of the nearest triangle \"\n\"in the reference.  Existing partitions/segments are cleared.  This action \"\n\"can't be undone.\"\nmsgstr \"\"\n\"Üçgen noktaları, referanstaki en yakın üçgenin bölümüne/sekmentine \"\n\"atanacaktır. Mevcut bölüm/segmentler temizlenir. Bu işlem geri alınamaz.\"\n\n#: src/program/OutfitStudio.cpp:9864\nmsgid \"Copy Partitions/Segments\"\nmsgstr \"Bölüm/Segmentleri Kopyala\"\n\n#: src/program/OutfitStudio.cpp:9873\nmsgid \"Copying segments/partitions...\"\nmsgstr \"Segmentler ve Bölümler kopyalanıyor...\"\n\n#: src/program/OutfitStudio.cpp:9884\n#, c-format\nmsgid \"\"\n\"The partitions/segments could not be copied for '%s' because %d triangles \"\n\"could not be matched.\"\nmsgstr \"\"\n\"Bölüm/segmentler '%s' için %d üçgen tepeleri eşleştirilemediğinden \"\n\"kopyalanamadı.\"\n\n#: src/program/OutfitStudio.cpp:9935\nmsgid \" sliders\"\nmsgstr \" kaydırıcılar\"\n\n#: src/program/OutfitStudio.cpp:9937\nmsgid \" bones\"\nmsgstr \" kemikler\"\n\n#: src/program/OutfitStudio.cpp:10073\nmsgid \"Symmetrize Vertices\"\nmsgstr \"tepe Noktalarını Simetrikleştir\"\n\n#: src/program/OutfitStudio.cpp:10075\nmsgid \"\"\n\"Eliminates the selected asymmetries from unmasked vertices by adjusting \"\n\"vertex data to be consistent with mirror vertices.\"\nmsgstr \"\"\n\"Tepe noktası verilerini ayna tepe noktalarıyla tutarlı olacak şekilde \"\n\"ayarlayarak, maskelenmemiş tepe noktalarından seçilen asimetrileri ortadan \"\n\"kaldırır.\"\n\n#: src/program/OutfitStudio.cpp:10077\nmsgid \"\"\n\"  (Hint: To choose which non-selected bones are adjusted during weight \"\n\"normalization, unlock them in the bones list in the Bones tab.)\"\nmsgstr \"\"\n\"  (İpucu: Ağırlık normalleştirmesi sırasında hangi kemiklerin ayarlanacağını \"\n\"seçmek için İskeletler sekmesindeki kemikler listesinden bunların kilidini \"\n\"açmalısın.)\"\n\n#: src/program/OutfitStudio.cpp:10081\nmsgid \"Vertices that will be symmetrized:\"\nmsgstr \"Simetri yapılacak tepe noktaları:\"\n\n#: src/program/OutfitStudio.cpp:10082\nmsgid \"&Symmetrize\"\nmsgstr \"&Simetri\"\n\n#: src/program/OutfitStudio.cpp:10231\n#, c-format\nmsgid \"%d unreferenced nodes were deleted.\"\nmsgstr \"%d kullanılmayan bezecikler silindi.\"\n\n#: src/program/OutfitStudio.cpp:10446\nmsgid \"Please enter a new unique name for the mask.\"\nmsgstr \"Lütfen maske için yeni bir isim belirleyin.\"\n\n#: src/program/OutfitStudio.cpp:10446\nmsgid \"New Mask\"\nmsgstr \"Yeni Maske\"\n\n#: src/program/OutfitStudio.cpp:10631\nmsgid \"Reset all bone poses?\"\nmsgstr \"Tüm iskelet hareketleri sıfırlansın mı?\"\n\n#: src/program/OutfitStudio.cpp:10631\nmsgid \"Reset Pose\"\nmsgstr \"Hareketleri Sıfırla\"\n\n#: src/program/OutfitStudio.cpp:10782\nmsgid \"Please enter a new unique name for the pose.\"\nmsgstr \"Lütfen yeni duruş hareketi için bir isim belirle.\"\n\n#: src/program/OutfitStudio.cpp:10782\nmsgid \"New Pose\"\nmsgstr \"Yeni Hareket\"\n\n#: src/program/OutfitStudio.cpp:10833\n#, c-format\nmsgid \"Are you sure you wish to delete the pose '%s'?\"\nmsgstr \"'%s' hareketini silmek istediğinden emin misin?\"\n\n#: src/program/OutfitStudio.cpp:10834\nmsgid \"Confirm pose delete\"\nmsgstr \"Hareketi silmeyi onayla\"\n\n#: src/program/OutfitStudio.cpp:11741\nmsgid \"The vertex picked has more than three connections.\"\nmsgstr \"Seçilen uç tepe noktasının üçten fazla bağlantısı var.\"\n\n#: src/program/OutfitStudio.cpp:11976\nmsgid \"\"\n\"Neither the selected nor target vertices are on the mesh boundary.  It is \"\n\"recommended that you only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\"Ne seçim ne de hedef köşeler ağ sınırında değil. Yalnızca sınır köşelerini \"\n\"kaynaklaman veya birleştirmen önerilir. Devam edecek misin?\"\n\n#: src/program/OutfitStudio.cpp:11977\nmsgid \"\"\n\"The selected vertex is not on the mesh boundary.  It is recommended that you \"\n\"only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\"Seçilen tepe noktası ağ sınırında değil. Yalnızca sınır köşelerini \"\n\"kaynaklaman veya birleştirmen önerilir. Devam edecek misin?\"\n\n#: src/program/OutfitStudio.cpp:11978\nmsgid \"\"\n\"The target vertex is not on the mesh boundary.  It is recommended that you \"\n\"only weld or merge boundary vertices.  Continue?\"\nmsgstr \"\"\n\"Hedef tepe noktası ağ sınırında değil. Yalnızca sınır köşelerini kaynaklaman \"\n\"veya birleştirmen önerilir. Devam edecek misin?\"\n\n#: src/program/OutfitStudio.cpp:11979\nmsgid \"Weld/Merge Non-Boundary Vertices\"\nmsgstr \"Sınır Dışı Köşeleri Kaynakla/Birleştir\"\n\n#: src/program/OutfitStudio.cpp:12061\nmsgid \"The edge picked is on the surface boundary.  Pick an interior edge.\"\nmsgstr \"Alınan kenar yüzey sınırında. Bir iç kenar seçmelisin.\"\n\n#: src/program/OutfitStudio.cpp:12115\nmsgid \"\"\n\"The edge picked has multiple triangles of the same orientation.  Correct the \"\n\"orientations before splitting.\"\nmsgstr \"\"\n\"Seçilen kenar, aynı yönelimde birden çok üçgene sahip. Bölmeden önce \"\n\"yönlerini düzeltmelisin.\"\n\n#: src/program/OutfitStudio.cpp:13437 src/program/OutfitStudio.cpp:13438\nmsgid \"Loading slider file...\"\nmsgstr \"Kaydırıcı dosyası yükleniyor...\"\n\n#: src/program/PreviewWindow.cpp:39\nmsgid \"Show the Normal Map Generator dialog.\"\nmsgstr \"Normal Harita Üreticisi konuşmasını göster.\"\n\n#: src/program/PreviewWindow.cpp:66 src/render/GLDialog.cpp:34\nmsgid \"Preview failed: OpenGL context is not OK.\"\nmsgstr \"Ön izleme başarısız: OpenGL içeriği Mevcut değil.\"\n\n#: src/program/ShapeProperties.cpp:96\nmsgid \"Material\"\nmsgstr \"Malzeme\"\n\n#: src/program/ShapeProperties.cpp:266\nmsgid \"Choose material file\"\nmsgstr \"Malzeme dosyasını seç\"\n\n#: src/program/ShapeProperties.cpp:512\nmsgid \"Please choose a shape to copy from\"\nmsgstr \"Lütfen kopyalamak için bir kalıp seçimi yap\"\n\n#: src/program/ShapeProperties.cpp:512\nmsgid \"Choose shape\"\nmsgstr \"Kalıp seçimi\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:123\nmsgid \"Size\"\nmsgstr \"Boyut\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:127\nmsgid \"Shortcut: 'S' + mouse wheel\"\nmsgstr \"Kısayol Tuşu: 'S' + Fare Tekerleği\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:136\nmsgid \"Strength\"\nmsgstr \"Kuvvet\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:148\nmsgid \"Focus\"\nmsgstr \"Odak\"\n\n#: src/ui/wxBrushSettingsPopup.cpp:160\nmsgid \"Spacing\"\nmsgstr \"Aralık\"\n\n#: src/ui/wxSliderPanel.cpp:63\nmsgid \"Turn on edit mode for this slider.\"\nmsgstr \"Bu kaydırıcı için düzenleme modunu aç.\"\n\n#: src/ui/wxSliderPanel.cpp:75\nmsgid \"Weaken slider data by 1%.\"\nmsgstr \"Kaydırıcı verilerini 1% azalt.\"\n\n#: src/ui/wxSliderPanel.cpp:82\nmsgid \"Strengthen slider data by 1%.\"\nmsgstr \"Kaydırıcı verilerini %1 oranında güçlendir.\"\n"
  },
  {
    "path": "lang/uk/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/uk/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/vi/BodySlide.mo",
    "content": ""
  },
  {
    "path": "lang/vi/BodySlide.po",
    "content": ""
  },
  {
    "path": "lang/xrctext.cpp",
    "content": "#line 5 \"res/xrc/About.xrc\"\n_(\"About\");\n#line 145 \"res/xrc/About.xrc\"\n_(\"Close\");\n#line 6 \"res/xrc/Actions.xrc\"\n_(\"Apply a vertex position\");\n#line 15 \"res/xrc/Actions.xrc\"\n_(\"This permanently moves a single vertex straight to the given location.\");\n#line 93 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 100 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 110 \"res/xrc/Actions.xrc\"\n_(\"Move Shape\");\n#line 254 \"res/xrc/Actions.xrc\"\n_(\"Mirror Axis\");\n#line 302 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 309 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 320 \"res/xrc/Actions.xrc\"\n_(\"Scale Shape\");\n#line 329 \"res/xrc/Actions.xrc\"\n_(\"Scaling will adjust the size of a mesh. This permanently affects vertices.\");\n#line 461 \"res/xrc/Actions.xrc\"\n_(\"Origin\");\n#line 472 \"res/xrc/Actions.xrc\"\n_(\"Zero (0, 0, 0)\");\n#line 473 \"res/xrc/Actions.xrc\"\n_(\"Center of selected shapes(s)\");\n#line 484 \"res/xrc/Actions.xrc\"\n_(\"Uniform (XYZ)\");\n#line 499 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 506 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 517 \"res/xrc/Actions.xrc\"\n_(\"Rotate Shape\");\n#line 667 \"res/xrc/Actions.xrc\"\n_(\"Origin\");\n#line 678 \"res/xrc/Actions.xrc\"\n_(\"Zero (0, 0, 0)\");\n#line 679 \"res/xrc/Actions.xrc\"\n_(\"Center of selected shapes(s)\");\n#line 694 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 701 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 712 \"res/xrc/Actions.xrc\"\n_(\"Inflate Shape\");\n#line 721 \"res/xrc/Actions.xrc\"\n_(\"Inflate/deflate a mesh along its normals. This permanently affects vertices.\");\n#line 847 \"res/xrc/Actions.xrc\"\n_(\"Uniform (XYZ)\");\n#line 862 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 869 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 880 \"res/xrc/Actions.xrc\"\n_(\"Mirror Shape\");\n#line 924 \"res/xrc/Actions.xrc\"\n_(\"Swap bones on X axis (L/R)\");\n#line 938 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 945 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 956 \"res/xrc/Actions.xrc\"\n_(\"Smooth Seams\");\n#line 1014 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 1021 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 1032 \"res/xrc/Actions.xrc\"\n_(\"Set Shape Textures\");\n#line 1062 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 1069 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 1079 \"res/xrc/Actions.xrc\"\n_(\"Conforming...\");\n#line 1088 \"res/xrc/Actions.xrc\"\n_(\"Each vertex of the reference will copy its slider data to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become conformed and work well. Often, the default values are sufficient.\");\n#line 1108 \"res/xrc/Actions.xrc\"\n_(\"Search Radius\");\n#line 1137 \"res/xrc/Actions.xrc\"\n_(\"Max Vertex Targets\");\n#line 1166 \"res/xrc/Actions.xrc\"\n_(\"No Target Limit\");\n#line 1189 \"res/xrc/Actions.xrc\"\n_(\"No Squeeze\");\n#line 1212 \"res/xrc/Actions.xrc\"\n_(\"Solid Mode\");\n#line 1235 \"res/xrc/Actions.xrc\"\n_(\"Axis\");\n#line 1285 \"res/xrc/Actions.xrc\"\n_(\"Preset\");\n#line 1301 \"res/xrc/Actions.xrc\"\n_(\"Default\");\n#line 1310 \"res/xrc/Actions.xrc\"\n_(\"Even Movement\");\n#line 1319 \"res/xrc/Actions.xrc\"\n_(\"Solid Object\");\n#line 1341 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 1348 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 1358 \"res/xrc/Actions.xrc\"\n_(\"Merge Geometry\");\n#line 1367 \"res/xrc/Actions.xrc\"\n_(\"This function copies vertices and triangles from one shape to another.  Partitions/segments of source and target shapes must match.  It is the user's responsibility to check that all other shape and shader properties are compatible, or merging will likely have side effects.\");\n#line 1382 \"res/xrc/Actions.xrc\"\n_(\"Source\");\n#line 1400 \"res/xrc/Actions.xrc\"\n_(\"Target\");\n#line 1429 \"res/xrc/Actions.xrc\"\n_(\"Delete source shape\");\n#line 1442 \"res/xrc/Actions.xrc\"\n_(\"&OK\");\n#line 1449 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 1459 \"res/xrc/Actions.xrc\"\n_(\"Mask symmetric vertices\");\n#line 1468 \"res/xrc/Actions.xrc\"\n_(\"Masks all vertices that do not have any of the selected asymmetries.\");\n#line 1494 \"res/xrc/Actions.xrc\"\n_(\"Vertices currently unmasked:\");\n#line 1522 \"res/xrc/Actions.xrc\"\n_(\"Unmatched Vertices:\");\n#line 1544 \"res/xrc/Actions.xrc\"\n_(\"Vertex Data Asymmetries\");\n#line 1577 \"res/xrc/Actions.xrc\"\n_(\"Type\");\n#line 1586 \"res/xrc/Actions.xrc\"\n_(\"Average\");\n#line 1595 \"res/xrc/Actions.xrc\"\n_(\"Count\");\n#line 1613 \"res/xrc/Actions.xrc\"\n_(\"Position\");\n#line 1681 \"res/xrc/Actions.xrc\"\n_(\"Sliders\");\n#line 1728 \"res/xrc/Actions.xrc\"\n_(\"Bones\");\n#line 1747 \"res/xrc/Actions.xrc\"\n_(\"Vertices that will still be unmasked:\");\n#line 1773 \"res/xrc/Actions.xrc\"\n_(\"&Mask\");\n#line 1780 \"res/xrc/Actions.xrc\"\n_(\"&Cancel\");\n#line 5 \"res/xrc/Automation.xrc\"\n_(\"Automation Script\");\n#line 22 \"res/xrc/Automation.xrc\"\n_(\"Automation:\");\n#line 30 \"res/xrc/Automation.xrc\"\n_(\"Select an automation to load, or type a name for a new one\");\n#line 31 \"res/xrc/Automation.xrc\"\n_(\"Automation name...\");\n#line 39 \"res/xrc/Automation.xrc\"\n_(\"Save\");\n#line 40 \"res/xrc/Automation.xrc\"\n_(\"Save the automation script\");\n#line 48 \"res/xrc/Automation.xrc\"\n_(\"Delete\");\n#line 49 \"res/xrc/Automation.xrc\"\n_(\"Delete the current automation script\");\n#line 57 \"res/xrc/Automation.xrc\"\n_(\"Open Folder\");\n#line 58 \"res/xrc/Automation.xrc\"\n_(\"Open the Automations folder in file explorer\");\n#line 99 \"res/xrc/Automation.xrc\"\n_(\"Step Settings\");\n#line 114 \"res/xrc/Automation.xrc\"\n_(\"Type:\");\n#line 121 \"res/xrc/Automation.xrc\"\n_(\"Bones: Add Custom Bone\");\n#line 122 \"res/xrc/Automation.xrc\"\n_(\"Bones: Copy Bone Weights\");\n#line 123 \"res/xrc/Automation.xrc\"\n_(\"Bones: Delete Bones\");\n#line 124 \"res/xrc/Automation.xrc\"\n_(\"Bones: Edit Custom Bone\");\n#line 125 \"res/xrc/Automation.xrc\"\n_(\"Bones: Remove Skinning\");\n#line 126 \"res/xrc/Automation.xrc\"\n_(\"Export: File\");\n#line 127 \"res/xrc/Automation.xrc\"\n_(\"Export: Save Project\");\n#line 128 \"res/xrc/Automation.xrc\"\n_(\"Import: File\");\n#line 129 \"res/xrc/Automation.xrc\"\n_(\"Import: Slider Data\");\n#line 130 \"res/xrc/Automation.xrc\"\n_(\"Project: Add Project\");\n#line 131 \"res/xrc/Automation.xrc\"\n_(\"Project: Clear Project\");\n#line 132 \"res/xrc/Automation.xrc\"\n_(\"Project: Clear Reference\");\n#line 133 \"res/xrc/Automation.xrc\"\n_(\"Project: Load Reference\");\n#line 134 \"res/xrc/Automation.xrc\"\n_(\"Project: Set Base Shape\");\n#line 135 \"res/xrc/Automation.xrc\"\n_(\"Project: Set Reference Shape\");\n#line 136 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Apply Pose\");\n#line 137 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Delete Shape\");\n#line 138 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Duplicate Shape\");\n#line 139 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Fix Clipping\");\n#line 140 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Invert UVs\");\n#line 141 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Mirror Shape\");\n#line 142 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Refine Mesh\");\n#line 143 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Rename Shape\");\n#line 144 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Reset Transforms\");\n#line 145 \"res/xrc/Automation.xrc\"\n_(\"Shapes: Transform Shape\");\n#line 146 \"res/xrc/Automation.xrc\"\n_(\"Sliders: Conform Sliders\");\n#line 147 \"res/xrc/Automation.xrc\"\n_(\"Sliders: Delete Slider\");\n#line 148 \"res/xrc/Automation.xrc\"\n_(\"Sliders: Set Slider Values\");\n#line 149 \"res/xrc/Automation.xrc\"\n_(\"Sliders: Set Slider Properties\");\n#line 150 \"res/xrc/Automation.xrc\"\n_(\"Masks: Load Mask\");\n#line 151 \"res/xrc/Automation.xrc\"\n_(\"Nodes: Remove Unused Nodes\");\n#line 159 \"res/xrc/Automation.xrc\"\n_(\"Active:\");\n#line 165 \"res/xrc/Automation.xrc\"\n_(\"Execute this step\");\n#line 173 \"res/xrc/Automation.xrc\"\n_(\"Target Shapes:\");\n#line 185 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of shape names. Leave empty to target all shapes.\");\n#line 186 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated shape list\");\n#line 192 \"res/xrc/Automation.xrc\"\n_(\"Regex\");\n#line 193 \"res/xrc/Automation.xrc\"\n_(\"Use regex matching for target shape names\");\n#line 202 \"res/xrc/Automation.xrc\"\n_(\"Note:\");\n#line 210 \"res/xrc/Automation.xrc\"\n_(\"A note to describe what this step does and how to configure it.\");\n#line 211 \"res/xrc/Automation.xrc\"\n_(\"Description of this step...\");\n#line 232 \"res/xrc/Automation.xrc\"\n_(\"Add Custom Bone\");\n#line 246 \"res/xrc/Automation.xrc\"\n_(\"Bone Name:\");\n#line 252 \"res/xrc/Automation.xrc\"\n_(\"Bone name\");\n#line 259 \"res/xrc/Automation.xrc\"\n_(\"Parent Bone:\");\n#line 265 \"res/xrc/Automation.xrc\"\n_(\"Name of the parent bone (leave empty for no parent)\");\n#line 266 \"res/xrc/Automation.xrc\"\n_(\"Parent bone name\");\n#line 273 \"res/xrc/Automation.xrc\"\n_(\"Translation:\");\n#line 314 \"res/xrc/Automation.xrc\"\n_(\"Rotation:\");\n#line 362 \"res/xrc/Automation.xrc\"\n_(\"Copy Bone Weights\");\n#line 376 \"res/xrc/Automation.xrc\"\n_(\"Proximity Radius:\");\n#line 390 \"res/xrc/Automation.xrc\"\n_(\"Max Results:\");\n#line 404 \"res/xrc/Automation.xrc\"\n_(\"Bone List:\");\n#line 410 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of bone names. Leave empty to copy all bones.\");\n#line 411 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated bone list\");\n#line 425 \"res/xrc/Automation.xrc\"\n_(\"Delete Bones\");\n#line 439 \"res/xrc/Automation.xrc\"\n_(\"Bone Names:\");\n#line 445 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of bone names to delete\");\n#line 446 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated bone list\");\n#line 453 \"res/xrc/Automation.xrc\"\n_(\"Mode:\");\n#line 459 \"res/xrc/Automation.xrc\"\n_(\"Delete bone entirely from project\");\n#line 461 \"res/xrc/Automation.xrc\"\n_(\"If checked, deletes the bone from all shapes and the NIF. If unchecked, only removes bone weights from target shapes.\");\n#line 475 \"res/xrc/Automation.xrc\"\n_(\"Edit Bone\");\n#line 489 \"res/xrc/Automation.xrc\"\n_(\"Bone Name:\");\n#line 495 \"res/xrc/Automation.xrc\"\n_(\"Name of the custom bone to edit\");\n#line 496 \"res/xrc/Automation.xrc\"\n_(\"Bone name\");\n#line 503 \"res/xrc/Automation.xrc\"\n_(\"Parent Bone:\");\n#line 509 \"res/xrc/Automation.xrc\"\n_(\"Name of the parent bone (leave empty for no parent)\");\n#line 510 \"res/xrc/Automation.xrc\"\n_(\"Parent bone name\");\n#line 517 \"res/xrc/Automation.xrc\"\n_(\"Translation:\");\n#line 558 \"res/xrc/Automation.xrc\"\n_(\"Rotation:\");\n#line 606 \"res/xrc/Automation.xrc\"\n_(\"Remove Skinning\");\n#line 612 \"res/xrc/Automation.xrc\"\n_(\"Removes skinning from target shapes (or all shapes if Target Meshes is empty).\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tThis deletes all bone weights and skinning data from the shapes.\");\n#line 626 \"res/xrc/Automation.xrc\"\n_(\"Export File\");\n#line 640 \"res/xrc/Automation.xrc\"\n_(\"Export File Path:\");\n#line 650 \"res/xrc/Automation.xrc\"\n_(\"Select export file path\");\n#line 658 \"res/xrc/Automation.xrc\"\n_(\"Select export folder\");\n#line 668 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 677 \"res/xrc/Automation.xrc\"\n_(\"Use original file path from batch operation\");\n#line 682 \"res/xrc/Automation.xrc\"\n_(\"Export with reference shape (.nif only)\");\n#line 692 \"res/xrc/Automation.xrc\"\n_(\"Filename Prefix:\");\n#line 698 \"res/xrc/Automation.xrc\"\n_(\"Prefix to add before the filename. Supports {{PLACEHOLDER}} variables.\");\n#line 699 \"res/xrc/Automation.xrc\"\n_(\"e.g. prefix_\");\n#line 706 \"res/xrc/Automation.xrc\"\n_(\"Filename Suffix:\");\n#line 712 \"res/xrc/Automation.xrc\"\n_(\"Suffix to add after the filename before the extension. Supports {{PLACEHOLDER}} variables.\");\n#line 713 \"res/xrc/Automation.xrc\"\n_(\"e.g. &suffix\");\n#line 727 \"res/xrc/Automation.xrc\"\n_(\"Save Project\");\n#line 733 \"res/xrc/Automation.xrc\"\n_(\"Use original project from batch\");\n#line 750 \"res/xrc/Automation.xrc\"\n_(\"Display Name:\");\n#line 756 \"res/xrc/Automation.xrc\"\n_(\"Name shown in BodySlide (supports {{PLACEHOLDER}} variables)\");\n#line 757 \"res/xrc/Automation.xrc\"\n_(\"Display name\");\n#line 764 \"res/xrc/Automation.xrc\"\n_(\"Output File Name:\");\n#line 770 \"res/xrc/Automation.xrc\"\n_(\"Base filename for the output NIF (supports {{PLACEHOLDER}} variables)\");\n#line 771 \"res/xrc/Automation.xrc\"\n_(\"Output filename\");\n#line 778 \"res/xrc/Automation.xrc\"\n_(\"Output Data Path:\");\n#line 784 \"res/xrc/Automation.xrc\"\n_(\"Game data path for output (supports {{PLACEHOLDER}} variables)\");\n#line 792 \"res/xrc/Automation.xrc\"\n_(\"Slider Set File:\");\n#line 798 \"res/xrc/Automation.xrc\"\n_(\"Slider set project file (.osp) (supports {{PLACEHOLDER}} variables)\");\n#line 806 \"res/xrc/Automation.xrc\"\n_(\"Shape Data Folder:\");\n#line 812 \"res/xrc/Automation.xrc\"\n_(\"Folder for slider data files (supports {{PLACEHOLDER}} variables)\");\n#line 820 \"res/xrc/Automation.xrc\"\n_(\"Shape Data File:\");\n#line 826 \"res/xrc/Automation.xrc\"\n_(\"Base NIF filename (supports {{PLACEHOLDER}} variables)\");\n#line 834 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 843 \"res/xrc/Automation.xrc\"\n_(\"Generate low/high weight outputs\");\n#line 849 \"res/xrc/Automation.xrc\"\n_(\"Copy reference to output\");\n#line 873 \"res/xrc/Automation.xrc\"\n_(\"Replace (from):\");\n#line 879 \"res/xrc/Automation.xrc\"\n_(\"Text to find and replace in original project fields (batch only)\");\n#line 880 \"res/xrc/Automation.xrc\"\n_(\"Find text\");\n#line 887 \"res/xrc/Automation.xrc\"\n_(\"Replace (to):\");\n#line 893 \"res/xrc/Automation.xrc\"\n_(\"Replacement text for matching text in original project fields (batch only)\");\n#line 894 \"res/xrc/Automation.xrc\"\n_(\"Replace with\");\n#line 901 \"res/xrc/Automation.xrc\"\n_(\"Suffix:\");\n#line 907 \"res/xrc/Automation.xrc\"\n_(\"Suffix to append to Display Name, Shape Data Folder, and Shape Data File name (batch only)\");\n#line 908 \"res/xrc/Automation.xrc\"\n_(\"e.g. &modified\");\n#line 924 \"res/xrc/Automation.xrc\"\n_(\"Copy reference based on loaded project\");\n#line 925 \"res/xrc/Automation.xrc\"\n_(\"If the loaded project had a reference shape, include it in the output. Otherwise, exclude it. Overrides the option above. (batch only)\");\n#line 933 \"res/xrc/Automation.xrc\"\n_(\"Only treat these shape names as the reference (comma-separated). Leave empty to use any reference shape.\");\n#line 934 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated shape list\");\n#line 948 \"res/xrc/Automation.xrc\"\n_(\"Import File\");\n#line 962 \"res/xrc/Automation.xrc\"\n_(\"Mode:\");\n#line 968 \"res/xrc/Automation.xrc\"\n_(\"Import all files from folder\");\n#line 975 \"res/xrc/Automation.xrc\"\n_(\"File:\");\n#line 981 \"res/xrc/Automation.xrc\"\n_(\"Select file to import\");\n#line 990 \"res/xrc/Automation.xrc\"\n_(\"Folder:\");\n#line 996 \"res/xrc/Automation.xrc\"\n_(\"Select folder to import from\");\n#line 1011 \"res/xrc/Automation.xrc\"\n_(\"Import Slider Data\");\n#line 1025 \"res/xrc/Automation.xrc\"\n_(\"Mode:\");\n#line 1031 \"res/xrc/Automation.xrc\"\n_(\"Import all files from folder (ShapeName#SliderName.ext)\");\n#line 1038 \"res/xrc/Automation.xrc\"\n_(\"Slider Data File:\");\n#line 1044 \"res/xrc/Automation.xrc\"\n_(\"Select slider data file\");\n#line 1053 \"res/xrc/Automation.xrc\"\n_(\"Folder:\");\n#line 1059 \"res/xrc/Automation.xrc\"\n_(\"Select folder with slider data files\");\n#line 1067 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 1073 \"res/xrc/Automation.xrc\"\n_(\"Merge into existing sliders\");\n#line 1080 \"res/xrc/Automation.xrc\"\n_(\"Slider Names:\");\n#line 1086 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of slider names. Leave empty to import all sliders.\");\n#line 1087 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated slider list\");\n#line 1101 \"res/xrc/Automation.xrc\"\n_(\"Add Project\");\n#line 1115 \"res/xrc/Automation.xrc\"\n_(\"Source File:\");\n#line 1121 \"res/xrc/Automation.xrc\"\n_(\"Select project file\");\n#line 1130 \"res/xrc/Automation.xrc\"\n_(\"Slider Set:\");\n#line 1136 \"res/xrc/Automation.xrc\"\n_(\"Name of the slider set to add\");\n#line 1143 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 1152 \"res/xrc/Automation.xrc\"\n_(\"Append new sliders\");\n#line 1169 \"res/xrc/Automation.xrc\"\n_(\"Clear Project\");\n#line 1175 \"res/xrc/Automation.xrc\"\n_(\"Clears the current project (removes all shapes, sliders, and references).\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tNo additional parameters needed.\");\n#line 1189 \"res/xrc/Automation.xrc\"\n_(\"Clear Reference\");\n#line 1195 \"res/xrc/Automation.xrc\"\n_(\"Removes the current reference/base shape from the project. Slider data for the reference is moved to the morpher.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tNo additional parameters needed.\");\n#line 1209 \"res/xrc/Automation.xrc\"\n_(\"Load Reference\");\n#line 1223 \"res/xrc/Automation.xrc\"\n_(\"Template:\");\n#line 1229 \"res/xrc/Automation.xrc\"\n_(\"Select a reference template to auto-fill the fields below\");\n#line 1236 \"res/xrc/Automation.xrc\"\n_(\"Source File:\");\n#line 1242 \"res/xrc/Automation.xrc\"\n_(\"Select reference file\");\n#line 1251 \"res/xrc/Automation.xrc\"\n_(\"Slider Set:\");\n#line 1257 \"res/xrc/Automation.xrc\"\n_(\"Name of the slider set within the source file\");\n#line 1264 \"res/xrc/Automation.xrc\"\n_(\"Shape:\");\n#line 1270 \"res/xrc/Automation.xrc\"\n_(\"Name of the reference shape\");\n#line 1277 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 1286 \"res/xrc/Automation.xrc\"\n_(\"Load all shapes\");\n#line 1292 \"res/xrc/Automation.xrc\"\n_(\"Merge sliders\");\n#line 1298 \"res/xrc/Automation.xrc\"\n_(\"Merge zaps\");\n#line 1304 \"res/xrc/Automation.xrc\"\n_(\"Append new sliders\");\n#line 1321 \"res/xrc/Automation.xrc\"\n_(\"Set Base Shape\");\n#line 1327 \"res/xrc/Automation.xrc\"\n_(\"Bakes the current slider values into the base geometry of all shapes and zeros all sliders.\\n\\nEquivalent to \\\"Slider -> Set Base Shape\\\" in the menu.\");\n#line 1342 \"res/xrc/Automation.xrc\"\n_(\"Set Reference Shape\");\n#line 1356 \"res/xrc/Automation.xrc\"\n_(\"Shape Name:\");\n#line 1362 \"res/xrc/Automation.xrc\"\n_(\"Name of the shape to set as reference (highlighted green).\");\n#line 1363 \"res/xrc/Automation.xrc\"\n_(\"Shape name\");\n#line 1373 \"res/xrc/Automation.xrc\"\n_(\"Unset Reference\");\n#line 1374 \"res/xrc/Automation.xrc\"\n_(\"Unset the reference shape instead of setting one. Morph data will be moved.\");\n#line 1388 \"res/xrc/Automation.xrc\"\n_(\"Apply Pose\");\n#line 1402 \"res/xrc/Automation.xrc\"\n_(\"Pose Name:\");\n#line 1408 \"res/xrc/Automation.xrc\"\n_(\"Name of the pose from PoseData to apply to meshes\");\n#line 1409 \"res/xrc/Automation.xrc\"\n_(\"Pose name\");\n#line 1423 \"res/xrc/Automation.xrc\"\n_(\"Delete Shape\");\n#line 1429 \"res/xrc/Automation.xrc\"\n_(\"Deletes the shapes specified in the Target Meshes field above.\\n\\nIf Target Meshes is empty, all non-reference shapes are deleted. Use Regex mode for pattern matching.\");\n#line 1444 \"res/xrc/Automation.xrc\"\n_(\"Duplicate Shape\");\n#line 1458 \"res/xrc/Automation.xrc\"\n_(\"New Name:\");\n#line 1464 \"res/xrc/Automation.xrc\"\n_(\"Name for the duplicated shape. Supports {{PLACEHOLDER}} variables.\");\n#line 1465 \"res/xrc/Automation.xrc\"\n_(\"New shape name\");\n#line 1479 \"res/xrc/Automation.xrc\"\n_(\"Fix Clipping\");\n#line 1493 \"res/xrc/Automation.xrc\"\n_(\"Mode:\");\n#line 1500 \"res/xrc/Automation.xrc\"\n_(\"Shapes\");\n#line 1501 \"res/xrc/Automation.xrc\"\n_(\"Sliders\");\n#line 1504 \"res/xrc/Automation.xrc\"\n_(\"Shapes: fix base geometry of target shapes. Sliders: fix clipping for each slider individually.\");\n#line 1511 \"res/xrc/Automation.xrc\"\n_(\"Strength (0 - 100):\");\n#line 1518 \"res/xrc/Automation.xrc\"\n_(\"Clipping fix strength between 0 and 100.\");\n#line 1526 \"res/xrc/Automation.xrc\"\n_(\"Slider Names:\");\n#line 1532 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of slider names to fix clipping for (Sliders mode only). Leave empty to process all non-zap/non-UV sliders.\");\n#line 1533 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated slider list\");\n#line 1547 \"res/xrc/Automation.xrc\"\n_(\"Invert UVs\");\n#line 1556 \"res/xrc/Automation.xrc\"\n_(\"Invert U\");\n#line 1563 \"res/xrc/Automation.xrc\"\n_(\"Invert V\");\n#line 1577 \"res/xrc/Automation.xrc\"\n_(\"Mirror Shape\");\n#line 1586 \"res/xrc/Automation.xrc\"\n_(\"Mirror X\");\n#line 1594 \"res/xrc/Automation.xrc\"\n_(\"Mirror Y\");\n#line 1601 \"res/xrc/Automation.xrc\"\n_(\"Mirror Z\");\n#line 1608 \"res/xrc/Automation.xrc\"\n_(\"Swap bones left/right (X axis)\");\n#line 1622 \"res/xrc/Automation.xrc\"\n_(\"Refine Mesh\");\n#line 1628 \"res/xrc/Automation.xrc\"\n_(\"Subdivides/refines meshes by splitting edges.\\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t\\tAll unmasked vertices are refined. Use the Target Meshes field above to select which shapes to refine.\");\n#line 1642 \"res/xrc/Automation.xrc\"\n_(\"Rename Shape\");\n#line 1656 \"res/xrc/Automation.xrc\"\n_(\"Old Name:\");\n#line 1662 \"res/xrc/Automation.xrc\"\n_(\"Current name of the shape (supports {{PLACEHOLDER}} variables)\");\n#line 1663 \"res/xrc/Automation.xrc\"\n_(\"Current shape name\");\n#line 1670 \"res/xrc/Automation.xrc\"\n_(\"New Name:\");\n#line 1676 \"res/xrc/Automation.xrc\"\n_(\"New name for the shape (supports {{PLACEHOLDER}} variables)\");\n#line 1677 \"res/xrc/Automation.xrc\"\n_(\"New shape name\");\n#line 1691 \"res/xrc/Automation.xrc\"\n_(\"Reset Transforms\");\n#line 1697 \"res/xrc/Automation.xrc\"\n_(\"Resets global-to-skin transforms for all skinned meshes. No additional parameters needed.\");\n#line 1710 \"res/xrc/Automation.xrc\"\n_(\"Transform Shape\");\n#line 1724 \"res/xrc/Automation.xrc\"\n_(\"Move:\");\n#line 1731 \"res/xrc/Automation.xrc\"\n_(\"Move X\");\n#line 1739 \"res/xrc/Automation.xrc\"\n_(\"Move Y\");\n#line 1747 \"res/xrc/Automation.xrc\"\n_(\"Move Z\");\n#line 1755 \"res/xrc/Automation.xrc\"\n_(\"Rotate (Ã‚Â°):\");\n#line 1762 \"res/xrc/Automation.xrc\"\n_(\"Rotate X (degrees)\");\n#line 1770 \"res/xrc/Automation.xrc\"\n_(\"Rotate Y (degrees)\");\n#line 1778 \"res/xrc/Automation.xrc\"\n_(\"Rotate Z (degrees)\");\n#line 1786 \"res/xrc/Automation.xrc\"\n_(\"Scale:\");\n#line 1793 \"res/xrc/Automation.xrc\"\n_(\"Scale X\");\n#line 1801 \"res/xrc/Automation.xrc\"\n_(\"Scale Y\");\n#line 1809 \"res/xrc/Automation.xrc\"\n_(\"Scale Z\");\n#line 1817 \"res/xrc/Automation.xrc\"\n_(\"Inflate:\");\n#line 1824 \"res/xrc/Automation.xrc\"\n_(\"Inflate X (along normals)\");\n#line 1832 \"res/xrc/Automation.xrc\"\n_(\"Inflate Y (along normals)\");\n#line 1840 \"res/xrc/Automation.xrc\"\n_(\"Inflate Z (along normals)\");\n#line 1855 \"res/xrc/Automation.xrc\"\n_(\"Conform Sliders\");\n#line 1869 \"res/xrc/Automation.xrc\"\n_(\"Proximity Radius:\");\n#line 1883 \"res/xrc/Automation.xrc\"\n_(\"Max Results:\");\n#line 1897 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 1906 \"res/xrc/Automation.xrc\"\n_(\"No squeeze\");\n#line 1911 \"res/xrc/Automation.xrc\"\n_(\"Solid mode\");\n#line 1920 \"res/xrc/Automation.xrc\"\n_(\"Axes:\");\n#line 1931 \"res/xrc/Automation.xrc\"\n_(\"X\");\n#line 1939 \"res/xrc/Automation.xrc\"\n_(\"Y\");\n#line 1945 \"res/xrc/Automation.xrc\"\n_(\"Z\");\n#line 1955 \"res/xrc/Automation.xrc\"\n_(\"Slider Names:\");\n#line 1961 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of slider names to conform. Leave empty to conform all visible sliders.\");\n#line 1962 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated slider list\");\n#line 1976 \"res/xrc/Automation.xrc\"\n_(\"Delete Slider\");\n#line 1990 \"res/xrc/Automation.xrc\"\n_(\"Slider Name:\");\n#line 1996 \"res/xrc/Automation.xrc\"\n_(\"Name of the slider to delete. If regex is checked, matches slider names by pattern.\");\n#line 1997 \"res/xrc/Automation.xrc\"\n_(\"Slider name or pattern\");\n#line 2004 \"res/xrc/Automation.xrc\"\n_(\"Regex:\");\n#line 2010 \"res/xrc/Automation.xrc\"\n_(\"Match slider names by regex pattern\");\n#line 2024 \"res/xrc/Automation.xrc\"\n_(\"Set Slider Values\");\n#line 2038 \"res/xrc/Automation.xrc\"\n_(\"Slider Names:\");\n#line 2044 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of slider names. Leave empty to set all visible sliders.\");\n#line 2045 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated slider list\");\n#line 2052 \"res/xrc/Automation.xrc\"\n_(\"Value (0 - 100):\");\n#line 2059 \"res/xrc/Automation.xrc\"\n_(\"Slider value between 0 and 100 (percentage)\");\n#line 2074 \"res/xrc/Automation.xrc\"\n_(\"Set Slider Properties\");\n#line 2088 \"res/xrc/Automation.xrc\"\n_(\"Slider Names:\");\n#line 2094 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated list of slider names. Leave empty to apply to all sliders.\");\n#line 2095 \"res/xrc/Automation.xrc\"\n_(\"Comma-separated slider list\");\n#line 2102 \"res/xrc/Automation.xrc\"\n_(\"Zap:\");\n#line 2109 \"res/xrc/Automation.xrc\"\n_(\"No change\");\n#line 2110 \"res/xrc/Automation.xrc\"\n_(\"No\");\n#line 2111 \"res/xrc/Automation.xrc\"\n_(\"Yes\");\n#line 2113 \"res/xrc/Automation.xrc\"\n_(\"Set the zap flag on matching sliders.\");\n#line 2120 \"res/xrc/Automation.xrc\"\n_(\"Hidden:\");\n#line 2127 \"res/xrc/Automation.xrc\"\n_(\"No change\");\n#line 2128 \"res/xrc/Automation.xrc\"\n_(\"No\");\n#line 2129 \"res/xrc/Automation.xrc\"\n_(\"Yes\");\n#line 2131 \"res/xrc/Automation.xrc\"\n_(\"Set the hidden flag on matching sliders.\");\n#line 2138 \"res/xrc/Automation.xrc\"\n_(\"Default Zapped:\");\n#line 2145 \"res/xrc/Automation.xrc\"\n_(\"No change\");\n#line 2146 \"res/xrc/Automation.xrc\"\n_(\"Not zapped\");\n#line 2147 \"res/xrc/Automation.xrc\"\n_(\"Zapped\");\n#line 2149 \"res/xrc/Automation.xrc\"\n_(\"Whether matching zap sliders are zapped by default.\");\n#line 2155 \"res/xrc/Automation.xrc\"\n_(\"Default (Small):\");\n#line 2161 \"res/xrc/Automation.xrc\"\n_(\"Default small value (0-100). Leave empty for no change.\");\n#line 2169 \"res/xrc/Automation.xrc\"\n_(\"Default (Big):\");\n#line 2175 \"res/xrc/Automation.xrc\"\n_(\"Default big value (0-100). Leave empty for no change.\");\n#line 2190 \"res/xrc/Automation.xrc\"\n_(\"Load Mask\");\n#line 2204 \"res/xrc/Automation.xrc\"\n_(\"Mask File:\");\n#line 2210 \"res/xrc/Automation.xrc\"\n_(\"Select a mask XML file\");\n#line 2219 \"res/xrc/Automation.xrc\"\n_(\"Mask Name:\");\n#line 2225 \"res/xrc/Automation.xrc\"\n_(\"Select a mask entry from the loaded mask file.\");\n#line 2239 \"res/xrc/Automation.xrc\"\n_(\"Remove Unused Nodes\");\n#line 2245 \"res/xrc/Automation.xrc\"\n_(\"Removes all unreferenced nodes from the NIF.\");\n#line 2265 \"res/xrc/Automation.xrc\"\n_(\"Placeholder Variables\");\n#line 2274 \"res/xrc/Automation.xrc\"\n_(\"Define {{KEY}} = Value pairs. These are substituted in all text fields before execution.\");\n#line 2291 \"res/xrc/Automation.xrc\"\n_(\"Key:\");\n#line 2297 \"res/xrc/Automation.xrc\"\n_(\"Value:\");\n#line 2304 \"res/xrc/Automation.xrc\"\n_(\"KEY\");\n#line 2310 \"res/xrc/Automation.xrc\"\n_(\"Value\");\n#line 2323 \"res/xrc/Automation.xrc\"\n_(\"+ Add\");\n#line 2331 \"res/xrc/Automation.xrc\"\n_(\"- Remove\");\n#line 2348 \"res/xrc/Automation.xrc\"\n_(\"Batch Operation\");\n#line 2358 \"res/xrc/Automation.xrc\"\n_(\"Mode\");\n#line 2361 \"res/xrc/Automation.xrc\"\n_(\"None (run on current project)\");\n#line 2362 \"res/xrc/Automation.xrc\"\n_(\"Folder scan (repeat on files in folder)\");\n#line 2363 \"res/xrc/Automation.xrc\"\n_(\"Slider sets (repeat on installed slider sets)\");\n#line 2377 \"res/xrc/Automation.xrc\"\n_(\"Folder Scan Settings\");\n#line 2390 \"res/xrc/Automation.xrc\"\n_(\"Folder:\");\n#line 2396 \"res/xrc/Automation.xrc\"\n_(\"Select folder to scan\");\n#line 2404 \"res/xrc/Automation.xrc\"\n_(\"Extension:\");\n#line 2411 \"res/xrc/Automation.xrc\"\n_(\"File extension to scan for (e.g. .nif, .obj)\");\n#line 2419 \"res/xrc/Automation.xrc\"\n_(\"Options:\");\n#line 2425 \"res/xrc/Automation.xrc\"\n_(\"Include subdirectories\");\n#line 2432 \"res/xrc/Automation.xrc\"\n_(\"File Filter:\");\n#line 2444 \"res/xrc/Automation.xrc\"\n_(\"Filter file/folder names (substring or regex)\");\n#line 2445 \"res/xrc/Automation.xrc\"\n_(\"Filter pattern...\");\n#line 2451 \"res/xrc/Automation.xrc\"\n_(\"Regex\");\n#line 2470 \"res/xrc/Automation.xrc\"\n_(\"Slider Set Settings\");\n#line 2483 \"res/xrc/Automation.xrc\"\n_(\"Filter:\");\n#line 2495 \"res/xrc/Automation.xrc\"\n_(\"Filter slider set names (substring or regex). Leave empty for all.\");\n#line 2496 \"res/xrc/Automation.xrc\"\n_(\"Filter pattern...\");\n#line 2502 \"res/xrc/Automation.xrc\"\n_(\"Regex\");\n#line 2526 \"res/xrc/Automation.xrc\"\n_(\"Output Log\");\n#line 2543 \"res/xrc/Automation.xrc\"\n_(\"Execute\");\n#line 2544 \"res/xrc/Automation.xrc\"\n_(\"Execute all active steps in order\");\n#line 2554 \"res/xrc/Automation.xrc\"\n_(\"Close\");\n#line 6 \"res/xrc/BatchBuild.xrc\"\n_(\"Batch Build\");\n#line 21 \"res/xrc/BatchBuild.xrc\"\n_(\"Select the slider sets for the batch build process. Use the group and outfit filters to show the outfits you want!\");\n#line 50 \"res/xrc/BatchBuild.xrc\"\n_(\"&Build\");\n#line 57 \"res/xrc/BatchBuild.xrc\"\n_(\"&Cancel\");\n#line 67 \"res/xrc/BatchBuild.xrc\"\n_(\"Choose output set\");\n#line 78 \"res/xrc/BatchBuild.xrc\"\n_(\"The following sets will override the same files.\\nPlease decide which one to use and select it in the list below.\");\n#line 88 \"res/xrc/BatchBuild.xrc\"\n_(\"Type and hit enter to choose output...\");\n#line 114 \"res/xrc/BatchBuild.xrc\"\n_(\"&Preview\");\n#line 115 \"res/xrc/BatchBuild.xrc\"\n_(\"Open a preview window showing the conflicting outfits for the selected group\");\n#line 127 \"res/xrc/BatchBuild.xrc\"\n_(\"&OK\");\n#line 135 \"res/xrc/BatchBuild.xrc\"\n_(\"&Cancel\");\n#line 7 \"res/xrc/BodySlide.xrc\"\n_(\"BodySlide\");\n#line 28 \"res/xrc/BodySlide.xrc\"\n_(\"Outfit/Body\");\n#line 44 \"res/xrc/BodySlide.xrc\"\n_(\"Select an outfit to modify\");\n#line 58 \"res/xrc/BodySlide.xrc\"\n_(\"Deletes a project from its project file\");\n#line 74 \"res/xrc/BodySlide.xrc\"\n_(\"Opens the current project in Outfit Studio\");\n#line 97 \"res/xrc/BodySlide.xrc\"\n_(\"Preset\");\n#line 113 \"res/xrc/BodySlide.xrc\"\n_(\"Choose from a list of slider settings presets\");\n#line 127 \"res/xrc/BodySlide.xrc\"\n_(\"Deletes a preset from its preset file\");\n#line 142 \"res/xrc/BodySlide.xrc\"\n_(\"Saves the new slider values to the currently selected preset\");\n#line 143 \"res/xrc/BodySlide.xrc\"\n_(\"Save\");\n#line 153 \"res/xrc/BodySlide.xrc\"\n_(\"Save the current slider settings as a new preset\");\n#line 154 \"res/xrc/BodySlide.xrc\"\n_(\"Save As...\");\n#line 165 \"res/xrc/BodySlide.xrc\"\n_(\"Opens the group manager where you can edit existing or create new groups\");\n#line 166 \"res/xrc/BodySlide.xrc\"\n_(\"Group Manager\");\n#line 240 \"res/xrc/BodySlide.xrc\"\n_(\"Single Weight\");\n#line 267 \"res/xrc/BodySlide.xrc\"\n_(\"Low Weight\");\n#line 284 \"res/xrc/BodySlide.xrc\"\n_(\"High Weight\");\n#line 325 \"res/xrc/BodySlide.xrc\"\n_(\"Copy the low weight slider values to the high weight section.\");\n#line 342 \"res/xrc/BodySlide.xrc\"\n_(\"Default outfit choice in Batch Build\");\n#line 353 \"res/xrc/BodySlide.xrc\"\n_(\"Output Path (which the game would use for this outfit)\");\n#line 365 \"res/xrc/BodySlide.xrc\"\n_(\"(right-click to view alternatives)\");\n#line 385 \"res/xrc/BodySlide.xrc\"\n_(\"Build multiple outfits using the currently active slider values.\\n\\nHold CTRL = Build to custom directory\\nHold ALT = Delete from output directory\");\n#line 386 \"res/xrc/BodySlide.xrc\"\n_(\"Batch Build...\");\n#line 401 \"res/xrc/BodySlide.xrc\"\n_(\"Build Morphs\");\n#line 402 \"res/xrc/BodySlide.xrc\"\n_(\"Builds a morphs (.tri) file alongside the meshes for accessing the sliders in-game. Requires other mods to make use of the morph data.\");\n#line 412 \"res/xrc/BodySlide.xrc\"\n_(\"Force Body Normals\");\n#line 413 \"res/xrc/BodySlide.xrc\"\n_(\"Adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod.\");\n#line 432 \"res/xrc/BodySlide.xrc\"\n_(\"Fix Clipping\");\n#line 442 \"res/xrc/BodySlide.xrc\"\n_(\"Controls how far outfit vertices are pushed away from the body surface.\");\n#line 460 \"res/xrc/BodySlide.xrc\"\n_(\"Show a preview window for this outfit.\");\n#line 461 \"res/xrc/BodySlide.xrc\"\n_(\"Preview\");\n#line 479 \"res/xrc/BodySlide.xrc\"\n_(\"Creates the currently selected outfit/body.\\n\\nHold CTRL = Build to working directory\\nHold ALT = Delete from output directory\");\n#line 480 \"res/xrc/BodySlide.xrc\"\n_(\"Build\");\n#line 492 \"res/xrc/BodySlide.xrc\"\n_(\"Copy the high weight slider values to the low weight section.\");\n#line 510 \"res/xrc/BodySlide.xrc\"\n_(\"About\");\n#line 519 \"res/xrc/BodySlide.xrc\"\n_(\"Open settings dialog.\");\n#line 520 \"res/xrc/BodySlide.xrc\"\n_(\"Settings\");\n#line 529 \"res/xrc/BodySlide.xrc\"\n_(\"Open Outfit Studio, a full-featured tool for creating and converting outfits.\");\n#line 530 \"res/xrc/BodySlide.xrc\"\n_(\"Outfit Studio\");\n#line 540 \"res/xrc/BodySlide.xrc\"\n_(\"Filter Options\");\n#line 542 \"res/xrc/BodySlide.xrc\"\n_(\"Choose groups...\");\n#line 543 \"res/xrc/BodySlide.xrc\"\n_(\"Choose groups to display in the Outfit menu\");\n#line 547 \"res/xrc/BodySlide.xrc\"\n_(\"Refresh Groups\");\n#line 548 \"res/xrc/BodySlide.xrc\"\n_(\"Refresh group information\");\n#line 552 \"res/xrc/BodySlide.xrc\"\n_(\"Filter Options\");\n#line 554 \"res/xrc/BodySlide.xrc\"\n_(\"Refresh Outfits\");\n#line 555 \"res/xrc/BodySlide.xrc\"\n_(\"Reloads outfit list\");\n#line 559 \"res/xrc/BodySlide.xrc\"\n_(\"Regular Expressions\");\n#line 560 \"res/xrc/BodySlide.xrc\"\n_(\"Allow the use of regular expressions (regex) for filtering.\");\n#line 564 \"res/xrc/BodySlide.xrc\"\n_(\"Has Zap Options\");\n#line 565 \"res/xrc/BodySlide.xrc\"\n_(\"Show only outfits that have zap options.\");\n#line 570 \"res/xrc/BodySlide.xrc\"\n_(\"Browse outfit folder...\");\n#line 571 \"res/xrc/BodySlide.xrc\"\n_(\"Browses to the shape data folder of the current outfit in the file explorer.\");\n#line 574 \"res/xrc/BodySlide.xrc\"\n_(\"Save Outfit list as group...\");\n#line 575 \"res/xrc/BodySlide.xrc\"\n_(\"Save the current filtered outfit list as a group\");\n#line 580 \"res/xrc/BodySlide.xrc\"\n_(\"Select None\");\n#line 583 \"res/xrc/BodySlide.xrc\"\n_(\"Select All\");\n#line 586 \"res/xrc/BodySlide.xrc\"\n_(\"Invert Selection\");\n#line 6 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Convert / Replace Body Reference\");\n#line 16 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"This wizard aids in the conversion to another body/reference..\");\n#line 25 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Reference Bodies\");\n#line 36 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Select a conversion reference (or 'None' to skip converting):\");\n#line 58 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Conversion Body Reference\");\n#line 78 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Select a body reference to convert to:\");\n#line 100 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"New Body Reference\");\n#line 130 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Options\");\n#line 136 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Merge Sliders\");\n#line 145 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Merge Zaps\");\n#line 165 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Conform Sliders\");\n#line 174 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Skip conform popup (use default settings)\");\n#line 183 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Copy Bone Weights\");\n#line 192 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Skip bone weights popup (use default settings)\");\n#line 203 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Delete reference after completion\");\n#line 219 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"This wizard aids in the conversion to another body/reference..\");\n#line 228 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Rename Project (optional)\");\n#line 239 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Specify text to be removed from the project name (comma-delimited):\");\n#line 260 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Remove from project name\");\n#line 277 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Specify any text to be prepended to project name:\");\n#line 298 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Prepend to project name\");\n#line 315 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"NOTE: Game file output path is unaffected by this\");\n#line 326 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Extras (optional)\");\n#line 337 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Remove the following shapes before conversion (comma-delimited):\");\n#line 359 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Shapes to delete\");\n#line 375 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Add the following bones after conversion (comma-delimited):\");\n#line 396 \"res/xrc/ConvertBodyReference.xrc\"\n_(\"Bones to add\");\n#line 5 \"res/xrc/EditUV.xrc\"\n_(\"Edit UV\");\n#line 32 \"res/xrc/EditUV.xrc\"\n_(\"&OK\");\n#line 39 \"res/xrc/EditUV.xrc\"\n_(\"&Cancel\");\n#line 52 \"res/xrc/EditUV.xrc\"\n_(\"Box Selection\");\n#line 53 \"res/xrc/EditUV.xrc\"\n_(\"Box Selection\\nShortcut: 1\");\n#line 60 \"res/xrc/EditUV.xrc\"\n_(\"Vertex Selection\");\n#line 61 \"res/xrc/EditUV.xrc\"\n_(\"Vertex Selection\\nShortcut: 2\");\n#line 67 \"res/xrc/EditUV.xrc\"\n_(\"Move\");\n#line 68 \"res/xrc/EditUV.xrc\"\n_(\"Move\\nShortcut: 3\");\n#line 74 \"res/xrc/EditUV.xrc\"\n_(\"Scale\");\n#line 75 \"res/xrc/EditUV.xrc\"\n_(\"Scale\\nShortcut: 4\");\n#line 81 \"res/xrc/EditUV.xrc\"\n_(\"Rotate\");\n#line 82 \"res/xrc/EditUV.xrc\"\n_(\"Rotate\\nShortcut: 5\");\n#line 88 \"res/xrc/EditUV.xrc\"\n_(\"Show Seam Edges\");\n#line 89 \"res/xrc/EditUV.xrc\"\n_(\"Show Seam Edges\");\n#line 97 \"res/xrc/EditUV.xrc\"\n_(\"Menu\");\n#line 99 \"res/xrc/EditUV.xrc\"\n_(\"File\");\n#line 101 \"res/xrc/EditUV.xrc\"\n_(\"Export UV Template...\\tCtrl+E\");\n#line 102 \"res/xrc/EditUV.xrc\"\n_(\"Export the UV layout as an image file.\");\n#line 106 \"res/xrc/EditUV.xrc\"\n_(\"Edit\");\n#line 108 \"res/xrc/EditUV.xrc\"\n_(\"Undo\\tCtrl+Z\");\n#line 109 \"res/xrc/EditUV.xrc\"\n_(\"Undo the previous action.\");\n#line 112 \"res/xrc/EditUV.xrc\"\n_(\"Redo\\tCtrl+Y\");\n#line 113 \"res/xrc/EditUV.xrc\"\n_(\"Redo the next undone action.\");\n#line 117 \"res/xrc/EditUV.xrc\"\n_(\"Select All\\tCtrl+A\");\n#line 118 \"res/xrc/EditUV.xrc\"\n_(\"Select All\");\n#line 121 \"res/xrc/EditUV.xrc\"\n_(\"Invert Selection\\tCtrl+I\");\n#line 122 \"res/xrc/EditUV.xrc\"\n_(\"Invert Selection\");\n#line 125 \"res/xrc/EditUV.xrc\"\n_(\"Select Less\\tA\");\n#line 126 \"res/xrc/EditUV.xrc\"\n_(\"Select less adjacent points in the selected islands.\");\n#line 129 \"res/xrc/EditUV.xrc\"\n_(\"Select More\\tD\");\n#line 130 \"res/xrc/EditUV.xrc\"\n_(\"Select more adjacent points in the selected islands.\");\n#line 134 \"res/xrc/EditUV.xrc\"\n_(\"Mask Selection\");\n#line 135 \"res/xrc/EditUV.xrc\"\n_(\"Create a mask from the current UV selection for the mesh in the main viewport.\");\n#line 139 \"res/xrc/EditUV.xrc\"\n_(\"Translate...\\tT\");\n#line 140 \"res/xrc/EditUV.xrc\"\n_(\"Show a dialog to translate the current selection.\");\n#line 143 \"res/xrc/EditUV.xrc\"\n_(\"Rotate...\\tR\");\n#line 144 \"res/xrc/EditUV.xrc\"\n_(\"Show a dialog to rotate the current selection.\");\n#line 147 \"res/xrc/EditUV.xrc\"\n_(\"Scale...\\tS\");\n#line 148 \"res/xrc/EditUV.xrc\"\n_(\"Show a dialog to scale the current selection.\");\n#line 155 \"res/xrc/EditUV.xrc\"\n_(\"Translate\");\n#line 258 \"res/xrc/EditUV.xrc\"\n_(\"&OK\");\n#line 265 \"res/xrc/EditUV.xrc\"\n_(\"&Cancel\");\n#line 275 \"res/xrc/EditUV.xrc\"\n_(\"Rotate\");\n#line 296 \"res/xrc/EditUV.xrc\"\n_(\"Angle\");\n#line 333 \"res/xrc/EditUV.xrc\"\n_(\"&OK\");\n#line 340 \"res/xrc/EditUV.xrc\"\n_(\"&Cancel\");\n#line 350 \"res/xrc/EditUV.xrc\"\n_(\"Scale\");\n#line 439 \"res/xrc/EditUV.xrc\"\n_(\"Uniform (UV)\");\n#line 454 \"res/xrc/EditUV.xrc\"\n_(\"&OK\");\n#line 461 \"res/xrc/EditUV.xrc\"\n_(\"&Cancel\");\n#line 470 \"res/xrc/EditUV.xrc\"\n_(\"Export UV Template\");\n#line 487 \"res/xrc/EditUV.xrc\"\n_(\"Resolution\");\n#line 507 \"res/xrc/EditUV.xrc\"\n_(\"Wire Color\");\n#line 520 \"res/xrc/EditUV.xrc\"\n_(\"Background Color\");\n#line 535 \"res/xrc/EditUV.xrc\"\n_(\"Transparent Background\");\n#line 545 \"res/xrc/EditUV.xrc\"\n_(\"Include Texture\");\n#line 553 \"res/xrc/EditUV.xrc\"\n_(\"Wrap Mode\");\n#line 561 \"res/xrc/EditUV.xrc\"\n_(\"Wrap\");\n#line 562 \"res/xrc/EditUV.xrc\"\n_(\"Clamp\");\n#line 573 \"res/xrc/EditUV.xrc\"\n_(\"Anti-Aliasing\");\n#line 588 \"res/xrc/EditUV.xrc\"\n_(\"&OK\");\n#line 595 \"res/xrc/EditUV.xrc\"\n_(\"&Cancel\");\n#line 7 \"res/xrc/GroupManager.xrc\"\n_(\"Group Manager\");\n#line 17 \"res/xrc/GroupManager.xrc\"\n_(\"Choose a group and add or remove members by selecting them in the lists.\");\n#line 33 \"res/xrc/GroupManager.xrc\"\n_(\"Select a group XML file\");\n#line 44 \"res/xrc/GroupManager.xrc\"\n_(\"Save\");\n#line 53 \"res/xrc/GroupManager.xrc\"\n_(\"Save As...\");\n#line 71 \"res/xrc/GroupManager.xrc\"\n_(\"Groups\");\n#line 101 \"res/xrc/GroupManager.xrc\"\n_(\"Add Group\");\n#line 110 \"res/xrc/GroupManager.xrc\"\n_(\"Remove Group\");\n#line 122 \"res/xrc/GroupManager.xrc\"\n_(\"Members\");\n#line 137 \"res/xrc/GroupManager.xrc\"\n_(\"Remove >>\");\n#line 151 \"res/xrc/GroupManager.xrc\"\n_(\"Outfits\");\n#line 172 \"res/xrc/GroupManager.xrc\"\n_(\"<< Add\");\n#line 189 \"res/xrc/GroupManager.xrc\"\n_(\"Close\");\n#line 5 \"res/xrc/ImportDialog.xrc\"\n_(\"Import Options...\");\n#line 53 \"res/xrc/ImportDialog.xrc\"\n_(\"Invert U\");\n#line 62 \"res/xrc/ImportDialog.xrc\"\n_(\"Invert V\");\n#line 71 \"res/xrc/ImportDialog.xrc\"\n_(\"Scale\");\n#line 89 \"res/xrc/ImportDialog.xrc\"\n_(\"Rotate (X)\");\n#line 98 \"res/xrc/ImportDialog.xrc\"\n_(\"Choose X rotation.\");\n#line 113 \"res/xrc/ImportDialog.xrc\"\n_(\"Rotate (Y)\");\n#line 122 \"res/xrc/ImportDialog.xrc\"\n_(\"Choose Y rotation.\");\n#line 137 \"res/xrc/ImportDialog.xrc\"\n_(\"Rotate (Z)\");\n#line 146 \"res/xrc/ImportDialog.xrc\"\n_(\"Choose Z rotation.\");\n#line 174 \"res/xrc/ImportDialog.xrc\"\n_(\"&OK\");\n#line 181 \"res/xrc/ImportDialog.xrc\"\n_(\"&Cancel\");\n#line 6 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Normal Map Generator\");\n#line 21 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Layers\");\n#line 37 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Load or save preset layer settings.\");\n#line 61 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Add a new layer after the current one in the layer list.\");\n#line 62 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Add Layer\");\n#line 71 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Move selected layer up one position.\");\n#line 72 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Move Up\");\n#line 87 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Delete the selected layer.\");\n#line 88 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Delete Layer\");\n#line 108 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Options\");\n#line 114 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Save a copy of an existing normal map if one already exists. File is saved in the original directory.\");\n#line 115 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Backup destination file\");\n#line 124 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Compress output file using BC7 compression. This can make saving the file take a VERY long time!\");\n#line 125 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Compress output \");\n#line 134 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Use the file name specified in the background layer to save the normal map.\");\n#line 135 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Save to background layer file\");\n#line 145 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Choose an output file...\");\n#line 149 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Location to save normal map to.\");\n#line 165 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Display current settings on mesh in preview window.\");\n#line 166 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Preview\");\n#line 181 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Generate and save the normal map file.\");\n#line 182 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Generate\");\n#line 191 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Preset\");\n#line 193 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Load Preset...\");\n#line 197 \"res/xrc/NormalsGenDlg.xrc\"\n_(\"Save Preset...\");\n#line 7 \"res/xrc/OutfitStudio.xrc\"\n_(\"Outfit Studio\");\n#line 22 \"res/xrc/OutfitStudio.xrc\"\n_(\"New Project\");\n#line 23 \"res/xrc/OutfitStudio.xrc\"\n_(\"Create a new project by selecting a reference body slider set, and outfit model files.\");\n#line 28 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load Project\");\n#line 29 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load a previously created slider set for editing.\");\n#line 34 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undo\");\n#line 35 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undo a previous action.\");\n#line 41 \"res/xrc/OutfitStudio.xrc\"\n_(\"Redo\");\n#line 42 \"res/xrc/OutfitStudio.xrc\"\n_(\"Redo the next undone action.\");\n#line 49 \"res/xrc/OutfitStudio.xrc\"\n_(\"Select\");\n#line 50 \"res/xrc/OutfitStudio.xrc\"\n_(\"Navigate and select meshes (or vertices in vertex mode).\");\n#line 57 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask\");\n#line 58 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask vertices to prevent them from being transformed.\\nHold down the ALT key to remove masking.\");\n#line 64 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inflate\");\n#line 65 \"res/xrc/OutfitStudio.xrc\"\n_(\"Increase mesh volume in an area.\");\n#line 71 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deflate\");\n#line 72 \"res/xrc/OutfitStudio.xrc\"\n_(\"Decrease mesh volume in an area.\");\n#line 78 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move\");\n#line 79 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move vertices over a plane parallel to the view.\");\n#line 85 \"res/xrc/OutfitStudio.xrc\"\n_(\"Smooth\");\n#line 86 \"res/xrc/OutfitStudio.xrc\"\n_(\"Smooth an area of a mesh.\");\n#line 92 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undiff\");\n#line 93 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undiff an area of a slider.\");\n#line 99 \"res/xrc/OutfitStudio.xrc\"\n_(\"Weight Paint\");\n#line 100 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply animation weight values for currently selected bone.\\nHold down the ALT key to weaken the weighting.\");\n#line 107 \"res/xrc/OutfitStudio.xrc\"\n_(\"Color Paint\");\n#line 108 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply vertex colors.\\nHold down the ALT key to remove colors.\");\n#line 115 \"res/xrc/OutfitStudio.xrc\"\n_(\"Alpha Paint\");\n#line 116 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply vertex alpha.\\nHold down the ALT key to remove alpha.\");\n#line 123 \"res/xrc/OutfitStudio.xrc\"\n_(\"Collapse Vertex\");\n#line 124 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deletes vertices with no more than three connections, without creating a hole.\");\n#line 130 \"res/xrc/OutfitStudio.xrc\"\n_(\"Flip Edge\");\n#line 131 \"res/xrc/OutfitStudio.xrc\"\n_(\"Flips mesh edges so that the opposite pair of vertices is connected.\");\n#line 137 \"res/xrc/OutfitStudio.xrc\"\n_(\"Split Edge\");\n#line 138 \"res/xrc/OutfitStudio.xrc\"\n_(\"Splits a mesh edge in two with a new vertex.\");\n#line 144 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move Vertex\");\n#line 145 \"res/xrc/OutfitStudio.xrc\"\n_(\"Moves a vertex.\");\n#line 152 \"res/xrc/OutfitStudio.xrc\"\n_(\"Depth Clip\");\n#line 154 \"res/xrc/OutfitStudio.xrc\"\n_(\"Simulates lower depth buffer precision to help with depth-related clipping\");\n#line 161 \"res/xrc/OutfitStudio.xrc\"\n_(\"Field of View\");\n#line 165 \"res/xrc/OutfitStudio.xrc\"\n_(\"Field of View: 65\");\n#line 170 \"res/xrc/OutfitStudio.xrc\"\n_(\"Brush Settings\");\n#line 175 \"res/xrc/OutfitStudio.xrc\"\n_(\"Open Discord invite link.\");\n#line 180 \"res/xrc/OutfitStudio.xrc\"\n_(\"Open GitHub link.\");\n#line 185 \"res/xrc/OutfitStudio.xrc\"\n_(\"Open PayPal link.\");\n#line 206 \"res/xrc/OutfitStudio.xrc\"\n_(\"Transform\");\n#line 207 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shows a transform tool to manipulate shapes and vertices with.\");\n#line 213 \"res/xrc/OutfitStudio.xrc\"\n_(\"Pivot\");\n#line 214 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale.\");\n#line 220 \"res/xrc/OutfitStudio.xrc\"\n_(\"Vertex Edit\");\n#line 221 \"res/xrc/OutfitStudio.xrc\"\n_(\"Lets you select vertices to add to or remove from the mask.\\nClick on a vertex to select/unmask it.\\nHold down CTRL to unselect/mask it.\");\n#line 228 \"res/xrc/OutfitStudio.xrc\"\n_(\"View Front\");\n#line 229 \"res/xrc/OutfitStudio.xrc\"\n_(\"Change camera view to the front.\");\n#line 233 \"res/xrc/OutfitStudio.xrc\"\n_(\"View Back\");\n#line 234 \"res/xrc/OutfitStudio.xrc\"\n_(\"Change camera view to the back.\");\n#line 238 \"res/xrc/OutfitStudio.xrc\"\n_(\"View Left\");\n#line 239 \"res/xrc/OutfitStudio.xrc\"\n_(\"Change camera view to the left.\");\n#line 243 \"res/xrc/OutfitStudio.xrc\"\n_(\"View Right\");\n#line 244 \"res/xrc/OutfitStudio.xrc\"\n_(\"Change camera view to the right.\");\n#line 248 \"res/xrc/OutfitStudio.xrc\"\n_(\"Perspective View\");\n#line 249 \"res/xrc/OutfitStudio.xrc\"\n_(\"Toggle perspective view.\");\n#line 255 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Nodes\");\n#line 256 \"res/xrc/OutfitStudio.xrc\"\n_(\"Toggle rendering of nodes.\");\n#line 261 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Bones\");\n#line 262 \"res/xrc/OutfitStudio.xrc\"\n_(\"Toggle rendering of bones.\");\n#line 267 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Floor\");\n#line 268 \"res/xrc/OutfitStudio.xrc\"\n_(\"Toggle rendering of the floor grid.\");\n#line 274 \"res/xrc/OutfitStudio.xrc\"\n_(\"X Mirror\");\n#line 275 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mirror edits across the X axis.\");\n#line 282 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit Connected Only\\tC\");\n#line 283 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit only vertices that are connected to the ones under the brush within the brush radius.\");\n#line 289 \"res/xrc/OutfitStudio.xrc\"\n_(\"Merge Vertex\");\n#line 290 \"res/xrc/OutfitStudio.xrc\"\n_(\"Merges two vertices and fills any gaps.\");\n#line 296 \"res/xrc/OutfitStudio.xrc\"\n_(\"Weld Vertex\");\n#line 297 \"res/xrc/OutfitStudio.xrc\"\n_(\"Welds two vertices while keeping the texture coordinates (UV) distinct.\");\n#line 303 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restrict To Surface\");\n#line 304 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restricts motion to a mesh surface.\");\n#line 310 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restrict To Plane\");\n#line 311 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restricts motion to parallel to the surface.\");\n#line 317 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restrict To Normal\");\n#line 318 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restricts motion to perpendicular to the surface.\");\n#line 381 \"res/xrc/OutfitStudio.xrc\"\n_(\"Meshes\");\n#line 393 \"res/xrc/OutfitStudio.xrc\"\n_(\"Bones\");\n#line 405 \"res/xrc/OutfitStudio.xrc\"\n_(\"Segments\");\n#line 417 \"res/xrc/OutfitStudio.xrc\"\n_(\"Partitions\");\n#line 429 \"res/xrc/OutfitStudio.xrc\"\n_(\"Colors\");\n#line 441 \"res/xrc/OutfitStudio.xrc\"\n_(\"Lights\");\n#line 481 \"res/xrc/OutfitStudio.xrc\"\n_(\"Total Bones: 0\");\n#line 491 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shape Selection Bones: 0\");\n#line 521 \"res/xrc/OutfitStudio.xrc\"\n_(\"Brush Color\");\n#line 530 \"res/xrc/OutfitStudio.xrc\"\n_(\"Color of the brush.\");\n#line 552 \"res/xrc/OutfitStudio.xrc\"\n_(\"Clamp Max Value\");\n#line 595 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit Alpha\");\n#line 604 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask matching color\");\n#line 650 \"res/xrc/OutfitStudio.xrc\"\n_(\"Reset\");\n#line 663 \"res/xrc/OutfitStudio.xrc\"\n_(\"Ambient\");\n#line 688 \"res/xrc/OutfitStudio.xrc\"\n_(\"Frontal\");\n#line 713 \"res/xrc/OutfitStudio.xrc\"\n_(\"Directional 1\");\n#line 738 \"res/xrc/OutfitStudio.xrc\"\n_(\"Directional 2\");\n#line 763 \"res/xrc/OutfitStudio.xrc\"\n_(\"Directional 3\");\n#line 808 \"res/xrc/OutfitStudio.xrc\"\n_(\"Type\");\n#line 931 \"res/xrc/OutfitStudio.xrc\"\n_(\"Slot\");\n#line 1006 \"res/xrc/OutfitStudio.xrc\"\n_(\"SSF File\");\n#line 1026 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set\");\n#line 1044 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply\");\n#line 1054 \"res/xrc/OutfitStudio.xrc\"\n_(\"Reset\");\n#line 1072 \"res/xrc/OutfitStudio.xrc\"\n_(\"Type\");\n#line 1145 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply\");\n#line 1155 \"res/xrc/OutfitStudio.xrc\"\n_(\"Reset\");\n#line 1173 \"res/xrc/OutfitStudio.xrc\"\n_(\"De-/Select Sliders\");\n#line 1192 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fixed Weight Brush\");\n#line 1203 \"res/xrc/OutfitStudio.xrc\"\n_(\"Normalize Weights\");\n#line 1220 \"res/xrc/OutfitStudio.xrc\"\n_(\"X-Mirror Bone\");\n#line 1245 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks\");\n#line 1272 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save\");\n#line 1281 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete\");\n#line 1297 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export...\");\n#line 1306 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import...\");\n#line 1322 \"res/xrc/OutfitStudio.xrc\"\n_(\"Posing\");\n#line 1349 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save\");\n#line 1358 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save As...\");\n#line 1367 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete\");\n#line 1383 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Pose\");\n#line 1401 \"res/xrc/OutfitStudio.xrc\"\n_(\"Reset Bone\");\n#line 1421 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rotation X\");\n#line 1449 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rotation Y\");\n#line 1477 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rotation Z\");\n#line 1505 \"res/xrc/OutfitStudio.xrc\"\n_(\"Offset X\");\n#line 1533 \"res/xrc/OutfitStudio.xrc\"\n_(\"Offset Y\");\n#line 1561 \"res/xrc/OutfitStudio.xrc\"\n_(\"Offset Z\");\n#line 1590 \"res/xrc/OutfitStudio.xrc\"\n_(\"Scale\");\n#line 1623 \"res/xrc/OutfitStudio.xrc\"\n_(\"Reset All\");\n#line 1631 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply to Mesh\");\n#line 1659 \"res/xrc/OutfitStudio.xrc\"\n_(\"Notes\");\n#line 1696 \"res/xrc/OutfitStudio.xrc\"\n_(\"Menu\");\n#line 1698 \"res/xrc/OutfitStudio.xrc\"\n_(\"File\");\n#line 1700 \"res/xrc/OutfitStudio.xrc\"\n_(\"New Project...\\tCtrl+N\");\n#line 1701 \"res/xrc/OutfitStudio.xrc\"\n_(\"Create a new outfit project.\");\n#line 1704 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load Project..\\tCtrl+O\");\n#line 1705 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load a project.\");\n#line 1708 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Project..\\tCtrl+Shift+O\");\n#line 1709 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add a project without replacing the current one.\");\n#line 1712 \"res/xrc/OutfitStudio.xrc\"\n_(\"Unload Project...\\tCtrl+W\");\n#line 1713 \"res/xrc/OutfitStudio.xrc\"\n_(\"Unloads the project and creates an empty new one.\");\n#line 1716 \"res/xrc/OutfitStudio.xrc\"\n_(\"Recent Projects...\");\n#line 1721 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load Reference...\");\n#line 1722 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load a new reference slider set, replacing any current reference objects.\");\n#line 1725 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load Outfit...\");\n#line 1726 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load a NIF file as the working outfit, replacing any current outfit objects.\");\n#line 1730 \"res/xrc/OutfitStudio.xrc\"\n_(\"Convert / Replace Reference...\\tCtrl+Shift+R\");\n#line 1731 \"res/xrc/OutfitStudio.xrc\"\n_(\"Convert to or replace an outfit's body/reference\");\n#line 1734 \"res/xrc/OutfitStudio.xrc\"\n_(\"Open Automation...\\tCtrl+Shift+A\");\n#line 1735 \"res/xrc/OutfitStudio.xrc\"\n_(\"Open the automation dialog to create, load and execute automation scripts.\");\n#line 1739 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save Project\\tCtrl+S\");\n#line 1740 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save the project.\");\n#line 1744 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save Project As...\\tCtrl+Shift+S\");\n#line 1745 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save the project under a new name.\");\n#line 1749 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import\");\n#line 1751 \"res/xrc/OutfitStudio.xrc\"\n_(\"From NIF...\");\n#line 1752 \"res/xrc/OutfitStudio.xrc\"\n_(\"Choose a NIF file to import into the project.\");\n#line 1755 \"res/xrc/OutfitStudio.xrc\"\n_(\"From OBJ...\");\n#line 1756 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import an OBJ file as a new shape in the outfit.\");\n#line 1759 \"res/xrc/OutfitStudio.xrc\"\n_(\"From FBX...\");\n#line 1760 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import an FBX file as a new shape in the outfit.\");\n#line 1763 \"res/xrc/OutfitStudio.xrc\"\n_(\"From TRI (Head)...\");\n#line 1764 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import shape and morphs from a head TRI file.\");\n#line 1767 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import Data\");\n#line 1769 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import BSClothExtraData From HKX\");\n#line 1770 \"res/xrc/OutfitStudio.xrc\"\n_(\"Choose an HKX file to import as a BSClothExtraData block into the project.\");\n#line 1775 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export\");\n#line 1777 \"res/xrc/OutfitStudio.xrc\"\n_(\"To NIF...\\tCtrl+E\");\n#line 1778 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save the current project as a NIF file (without reference)\");\n#line 1781 \"res/xrc/OutfitStudio.xrc\"\n_(\"To NIF With Reference...\\tCtrl+Alt+E\");\n#line 1782 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save the current project as a NIF file (including reference)\");\n#line 1785 \"res/xrc/OutfitStudio.xrc\"\n_(\"To OBJ...\");\n#line 1786 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export the current project as an OBJ file.\");\n#line 1789 \"res/xrc/OutfitStudio.xrc\"\n_(\"To FBX...\");\n#line 1790 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export the current project as an FBX file.\");\n#line 1793 \"res/xrc/OutfitStudio.xrc\"\n_(\"To TRI (Head)...\");\n#line 1794 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export head morphs to a TRI file.\");\n#line 1797 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export Data\");\n#line 1799 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export BSClothExtraData As HKX\");\n#line 1800 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save one of the currently loaded BSClothExtraData blocks to an HKX file.\");\n#line 1805 \"res/xrc/OutfitStudio.xrc\"\n_(\"Make Conversion Reference\");\n#line 1806 \"res/xrc/OutfitStudio.xrc\"\n_(\"Using the current slider settings for the reference shape, create a new reference that will morph from the current shape back to the base shape.\");\n#line 1810 \"res/xrc/OutfitStudio.xrc\"\n_(\"Pack Projects...\");\n#line 1811 \"res/xrc/OutfitStudio.xrc\"\n_(\"Pack one or more projects into a folder or archive for sharing.\");\n#line 1814 \"res/xrc/OutfitStudio.xrc\"\n_(\"Settings\");\n#line 1815 \"res/xrc/OutfitStudio.xrc\"\n_(\"Open settings dialog.\");\n#line 1818 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exit\\tAlt+F4\");\n#line 1819 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exit Outfit Studio.\");\n#line 1823 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit\");\n#line 1825 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undo\\tCtrl+Z\");\n#line 1826 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undo the previous action.\");\n#line 1829 \"res/xrc/OutfitStudio.xrc\"\n_(\"Redo\\tCtrl+Y\");\n#line 1830 \"res/xrc/OutfitStudio.xrc\"\n_(\"Redo the next undone action.\");\n#line 1834 \"res/xrc/OutfitStudio.xrc\"\n_(\"X Mirror\\tX\");\n#line 1835 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mirror edits across the X axis.\");\n#line 1841 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit Connected Only\\tC\");\n#line 1842 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit only vertices that are connected to the ones under the brush within the brush radius\");\n#line 1848 \"res/xrc/OutfitStudio.xrc\"\n_(\"Merge Vertex\");\n#line 1849 \"res/xrc/OutfitStudio.xrc\"\n_(\"Merges two vertices and fills any gaps.\");\n#line 1855 \"res/xrc/OutfitStudio.xrc\"\n_(\"Weld Vertex\");\n#line 1856 \"res/xrc/OutfitStudio.xrc\"\n_(\"Welds two vertices while keeping the texture coordinates (UV) distinct.\");\n#line 1862 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restrict To Surface\");\n#line 1863 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restricts motion to a mesh surface.\");\n#line 1869 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restrict To Plane\");\n#line 1870 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restricts motion to parallel to the surface.\");\n#line 1876 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restrict To Normal\");\n#line 1877 \"res/xrc/OutfitStudio.xrc\"\n_(\"Restricts motion to perpendicular to the surface.\");\n#line 1884 \"res/xrc/OutfitStudio.xrc\"\n_(\"Recalculate Normals\");\n#line 1885 \"res/xrc/OutfitStudio.xrc\"\n_(\"Recalculate normals on active mesh\");\n#line 1888 \"res/xrc/OutfitStudio.xrc\"\n_(\"Disable Normals Calculation\");\n#line 1889 \"res/xrc/OutfitStudio.xrc\"\n_(\"Turn off all automatic recalculation of normals on all meshes. Only applies to Outfit Studio.\");\n#line 1894 \"res/xrc/OutfitStudio.xrc\"\n_(\"Reset Transforms\");\n#line 1895 \"res/xrc/OutfitStudio.xrc\"\n_(\"Resets the shape and skin transforms.\");\n#line 1898 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Unreferenced Nodes\");\n#line 1899 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deletes all nodes from the project that aren't used in any other block.\");\n#line 1902 \"res/xrc/OutfitStudio.xrc\"\n_(\"Remove Skinning\");\n#line 1903 \"res/xrc/OutfitStudio.xrc\"\n_(\"Removes skinning of all shapes and all unused nodes.\");\n#line 1907 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shape\");\n#line 1909 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export\");\n#line 1911 \"res/xrc/OutfitStudio.xrc\"\n_(\"To NIF...\");\n#line 1912 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export only the selected shapes to a NIF file.\");\n#line 1915 \"res/xrc/OutfitStudio.xrc\"\n_(\"To OBJ...\");\n#line 1916 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export only the selected shapes to an OBJ file.\");\n#line 1919 \"res/xrc/OutfitStudio.xrc\"\n_(\"To FBX...\");\n#line 1920 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export only the selected shapes to an FBX file.\");\n#line 1923 \"res/xrc/OutfitStudio.xrc\"\n_(\"To TRI (Head)...\");\n#line 1924 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export head morphs to a TRI file.\");\n#line 1928 \"res/xrc/OutfitStudio.xrc\"\n_(\"UV\");\n#line 1930 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit...\");\n#line 1931 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit the texture coordinates.\");\n#line 1934 \"res/xrc/OutfitStudio.xrc\"\n_(\"Invert X (Mirror)\");\n#line 1935 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inverts the X-axis to mirror the texture coordinates.\");\n#line 1938 \"res/xrc/OutfitStudio.xrc\"\n_(\"Invert Y (Flip)\");\n#line 1939 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inverts the Y-axis to flip the texture coordinates.\");\n#line 1943 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Vertices...\\tShift+Del\");\n#line 1944 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deletes all unmasked vertices of the currently selected shapes.\");\n#line 1947 \"res/xrc/OutfitStudio.xrc\"\n_(\"Separate Vertices...\\tShift+S\");\n#line 1948 \"res/xrc/OutfitStudio.xrc\"\n_(\"Separate the current shape into two by using the mask.\");\n#line 1951 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mirror Shape...\");\n#line 1952 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mirror the selected shapes on any axis.\");\n#line 1955 \"res/xrc/OutfitStudio.xrc\"\n_(\"Merge Geometry...\");\n#line 1956 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copies vertices and triangles from one shape to another.\");\n#line 1959 \"res/xrc/OutfitStudio.xrc\"\n_(\"Duplicate...\");\n#line 1960 \"res/xrc/OutfitStudio.xrc\"\n_(\"Duplicate the current shape.\");\n#line 1963 \"res/xrc/OutfitStudio.xrc\"\n_(\"Refine Mesh\");\n#line 1964 \"res/xrc/OutfitStudio.xrc\"\n_(\"Splits all edges between unmasked vertices\");\n#line 1967 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rename...\\tF2\");\n#line 1968 \"res/xrc/OutfitStudio.xrc\"\n_(\"Change the name of the current shape.\");\n#line 1971 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set Reference\");\n#line 1972 \"res/xrc/OutfitStudio.xrc\"\n_(\"Turn the shape into the reference shape of the project.\");\n#line 1976 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move...\");\n#line 1977 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply an offset adjustment to the mesh vertices. This permanently moves vertices.\");\n#line 1980 \"res/xrc/OutfitStudio.xrc\"\n_(\"Scale...\");\n#line 1981 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply a scale adjustment to the shape. This permanently moves vertices.\");\n#line 1984 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rotate...\");\n#line 1985 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply a rotation to the mesh vertices. This permanently moves vertices.\");\n#line 1988 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inflate...\");\n#line 1989 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inflates/deflates a shape along its normals. This permanently moves vertices.\");\n#line 1992 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fix Clipping...\");\n#line 1993 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fixes clipping of outfit vertices that penetrate the reference shape.\");\n#line 1997 \"res/xrc/OutfitStudio.xrc\"\n_(\"Normals\");\n#line 1999 \"res/xrc/OutfitStudio.xrc\"\n_(\"Smooth Seam Normals\");\n#line 2000 \"res/xrc/OutfitStudio.xrc\"\n_(\"Smooths edges of seams (usually found at texture borders), disable if this causes odd normals on the shape.\");\n#line 2005 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit Smoothing Angle...\");\n#line 2006 \"res/xrc/OutfitStudio.xrc\"\n_(\"Angle, in degrees, that controls the threshold at which normal seams are smoothed.\");\n#line 2009 \"res/xrc/OutfitStudio.xrc\"\n_(\"Lock Normals\");\n#line 2010 \"res/xrc/OutfitStudio.xrc\"\n_(\"Locks the mesh normals. Enable if you want to keep custom normals intact.\");\n#line 2017 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copy Bone Weights\");\n#line 2018 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copies all bone weights from the reference shape to the current shape.\");\n#line 2021 \"res/xrc/OutfitStudio.xrc\"\n_(\"Transfer Selected Weights\");\n#line 2022 \"res/xrc/OutfitStudio.xrc\"\n_(\"Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order.\");\n#line 2025 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Weighted Vertices\");\n#line 2026 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks vertices with bone weights, so you can manually assign weights to unweighted vertices.\");\n#line 2029 \"res/xrc/OutfitStudio.xrc\"\n_(\"Check For Bad Bones...\");\n#line 2030 \"res/xrc/OutfitStudio.xrc\"\n_(\"Looks for bones with inconsistencies in their transforms.  If any are found, a dialog is opened to give options for fixing them.\");\n#line 2034 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copy Partitions/Segments...\");\n#line 2035 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copies partitions/segments and all triangle assignments from the reference shape to the current shape.\");\n#line 2039 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Symmetric Vertices...\");\n#line 2040 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks unmasked vertices that have a mirrored vertex with identical data.\");\n#line 2043 \"res/xrc/OutfitStudio.xrc\"\n_(\"Symmetrize Vertices...\");\n#line 2044 \"res/xrc/OutfitStudio.xrc\"\n_(\"Changes vertex data to be identical to mirrored vertices.\");\n#line 2047 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Symmetric Triangles\");\n#line 2048 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks triangles that can be matched to a mirrored triangle.\");\n#line 2052 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete\\tDel\");\n#line 2053 \"res/xrc/OutfitStudio.xrc\"\n_(\"Removes the currently selected shape from the outfit.\");\n#line 2059 \"res/xrc/OutfitStudio.xrc\"\n_(\"Properties...\");\n#line 2060 \"res/xrc/OutfitStudio.xrc\"\n_(\"Opens the properties dialog for shader, texture and more settings of the selected shape.\");\n#line 2064 \"res/xrc/OutfitStudio.xrc\"\n_(\"Slider\");\n#line 2066 \"res/xrc/OutfitStudio.xrc\"\n_(\"Conform Selected\\tCtrl+C\");\n#line 2067 \"res/xrc/OutfitStudio.xrc\"\n_(\"Conform selected outfit shape to all checked sliders.\");\n#line 2070 \"res/xrc/OutfitStudio.xrc\"\n_(\"Conform All\\tCtrl+Shift+C\");\n#line 2071 \"res/xrc/OutfitStudio.xrc\"\n_(\"Conform all outfit shapes to all checked sliders.\");\n#line 2074 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fix Clipping...\");\n#line 2075 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fixes clipping of outfit vertices that penetrate the reference shape for the active slider.\");\n#line 2079 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set Base Shape\");\n#line 2080 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set the current outfit shape as the base shape and clear slider data.\");\n#line 2084 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load Preset...\");\n#line 2085 \"res/xrc/OutfitStudio.xrc\"\n_(\"Load and preview a slider preset. Inverted sliders will have inverted values.\");\n#line 2088 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save Preset...\");\n#line 2089 \"res/xrc/OutfitStudio.xrc\"\n_(\"Save a slider preset with the current values. Inverted sliders will have inverted values.\");\n#line 2093 \"res/xrc/OutfitStudio.xrc\"\n_(\"New Slider\");\n#line 2094 \"res/xrc/OutfitStudio.xrc\"\n_(\"Create a new shape transformation slider.\");\n#line 2097 \"res/xrc/OutfitStudio.xrc\"\n_(\"Coalesce sliders\");\n#line 2098 \"res/xrc/OutfitStudio.xrc\"\n_(\"Create a new shape transformation slider based on the current slider values\");\n#line 2101 \"res/xrc/OutfitStudio.xrc\"\n_(\"New Zap Slider\");\n#line 2102 \"res/xrc/OutfitStudio.xrc\"\n_(\"Create a new Zap slider based on unmasked vertices\");\n#line 2106 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import\");\n#line 2108 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import OSD...\");\n#line 2109 \"res/xrc/OutfitStudio.xrc\"\n_(\"Imports OSD file and creates sliders for shapes with a matching name.\");\n#line 2112 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import TRI Morphs...\");\n#line 2113 \"res/xrc/OutfitStudio.xrc\"\n_(\"Imports TRI morphs from a TRI file and creates sliders for shapes with a matching name.\");\n#line 2116 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import Starfield morphs...\");\n#line 2117 \"res/xrc/OutfitStudio.xrc\"\n_(\"Imports Starfield morph.dat file and creates sliders for shapes with a matching name.\");\n#line 2121 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import to active slider\");\n#line 2123 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import NIF...\");\n#line 2124 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import a NIF file and overwrites the current shape's slider data.\");\n#line 2127 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import BSD...\");\n#line 2128 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import a BodySlide BSD file and overwrites the current shape's slider data.\");\n#line 2131 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import OBJ...\");\n#line 2132 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference.\");\n#line 2135 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import FBX...\");\n#line 2136 \"res/xrc/OutfitStudio.xrc\"\n_(\"Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference.\");\n#line 2142 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export\");\n#line 2144 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export OSD...\");\n#line 2145 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exports all currently loaded slider data to an OSD file.\");\n#line 2148 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export TRI Morphs...\");\n#line 2149 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exports TRI morphs to a TRI file.\");\n#line 2152 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export Starfield morphs...\");\n#line 2153 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exports Starfield morph.dat file.\");\n#line 2156 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export to OBJs...\");\n#line 2157 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export all sliders to an OBJ file per slider.\");\n#line 2161 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export active slider\");\n#line 2163 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export NIF...\");\n#line 2164 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exports the current slider's data as a NIF file.\");\n#line 2167 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export BSD...\");\n#line 2168 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exports the current slider's data as a BodySlide BSD file.\");\n#line 2171 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export OBJ...\");\n#line 2172 \"res/xrc/OutfitStudio.xrc\"\n_(\"Exports the current slider's data as an OBJ file.\");\n#line 2179 \"res/xrc/OutfitStudio.xrc\"\n_(\"Clone Slider\");\n#line 2180 \"res/xrc/OutfitStudio.xrc\"\n_(\"Clones the current slider.\");\n#line 2184 \"res/xrc/OutfitStudio.xrc\"\n_(\"Negate Slider\");\n#line 2185 \"res/xrc/OutfitStudio.xrc\"\n_(\"Negates the current slider, reversing it's effect\");\n#line 2189 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Affected Vertices\");\n#line 2190 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks the vertices the slider is affecting for all selected shapes.\");\n#line 2194 \"res/xrc/OutfitStudio.xrc\"\n_(\"Clear Slider Data\");\n#line 2195 \"res/xrc/OutfitStudio.xrc\"\n_(\"Erases the slider data without removing the slider itself. (Cannot be undone)\");\n#line 2198 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Slider\\tCtrl+Del\");\n#line 2199 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete the active slider from the project. (Cannot be undone)\");\n#line 2203 \"res/xrc/OutfitStudio.xrc\"\n_(\"Properties...\\tTab\");\n#line 2204 \"res/xrc/OutfitStudio.xrc\"\n_(\"Display and edit the active slider's properties.\");\n#line 2209 \"res/xrc/OutfitStudio.xrc\"\n_(\"Tool\");\n#line 2211 \"res/xrc/OutfitStudio.xrc\"\n_(\"Current Tool\");\n#line 2213 \"res/xrc/OutfitStudio.xrc\"\n_(\"Select\");\n#line 2214 \"res/xrc/OutfitStudio.xrc\"\n_(\"Navigate and select meshes (or vertices in vertex mode).\");\n#line 2218 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask\");\n#line 2219 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask vertices to prevent them from being transformed.\\nHold down the ALT key to remove masking.\");\n#line 2223 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inflate\");\n#line 2224 \"res/xrc/OutfitStudio.xrc\"\n_(\"Increase mesh volume in an area.\");\n#line 2229 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deflate\");\n#line 2230 \"res/xrc/OutfitStudio.xrc\"\n_(\"Decrease mesh volume in an area.\");\n#line 2234 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move\");\n#line 2235 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move vertices over a plane parallel to the view.\");\n#line 2239 \"res/xrc/OutfitStudio.xrc\"\n_(\"Smooth\");\n#line 2240 \"res/xrc/OutfitStudio.xrc\"\n_(\"Smooth an area of a mesh.\");\n#line 2244 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undiff\");\n#line 2245 \"res/xrc/OutfitStudio.xrc\"\n_(\"Undiff an area of a slider.\");\n#line 2249 \"res/xrc/OutfitStudio.xrc\"\n_(\"Weight Paint\");\n#line 2250 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply animation weight values for the currently selected bone.\\nHold down the ALT key to weaken the weighting.\");\n#line 2255 \"res/xrc/OutfitStudio.xrc\"\n_(\"Color Paint\");\n#line 2256 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply vertex colors.\\nHold down the ALT key to remove colors.\");\n#line 2261 \"res/xrc/OutfitStudio.xrc\"\n_(\"Alpha Paint\");\n#line 2262 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply vertex alpha.\\nHold down the ALT key to remove alpha.\");\n#line 2267 \"res/xrc/OutfitStudio.xrc\"\n_(\"Collapse Vertex\");\n#line 2268 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deletes vertices with no more than three connections, without creating a hole.\");\n#line 2272 \"res/xrc/OutfitStudio.xrc\"\n_(\"Flip Edge\");\n#line 2273 \"res/xrc/OutfitStudio.xrc\"\n_(\"Flips mesh edges so that the opposite pair of vertices is connected.\");\n#line 2277 \"res/xrc/OutfitStudio.xrc\"\n_(\"Split Edge\");\n#line 2278 \"res/xrc/OutfitStudio.xrc\"\n_(\"Splits a mesh edge in two with a new vertex.\");\n#line 2282 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move Vertex\");\n#line 2283 \"res/xrc/OutfitStudio.xrc\"\n_(\"Moves a vertex.\");\n#line 2288 \"res/xrc/OutfitStudio.xrc\"\n_(\"Transform\\tF\");\n#line 2289 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shows a transform tool to manipulate shapes and vertices with.\");\n#line 2293 \"res/xrc/OutfitStudio.xrc\"\n_(\"Pivot\\tP\");\n#line 2294 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale.\");\n#line 2298 \"res/xrc/OutfitStudio.xrc\"\n_(\"Vertex Edit\\tQ\");\n#line 2299 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shows vertex points and lets you mask/unmask them.\\nWithout any brush active, click on a vertex to unmask it.\\nHold down CTRL to mask it.\");\n#line 2304 \"res/xrc/OutfitStudio.xrc\"\n_(\"Increase Brush Size\\tShift++\");\n#line 2305 \"res/xrc/OutfitStudio.xrc\"\n_(\"Increase brush diameter\");\n#line 2308 \"res/xrc/OutfitStudio.xrc\"\n_(\"Decrease Brush Size\\tShift+-\");\n#line 2309 \"res/xrc/OutfitStudio.xrc\"\n_(\"Decrease brush diameter\");\n#line 2312 \"res/xrc/OutfitStudio.xrc\"\n_(\"Increase Brush Strength\\tCtrl++\");\n#line 2313 \"res/xrc/OutfitStudio.xrc\"\n_(\"Increase brush strength\");\n#line 2316 \"res/xrc/OutfitStudio.xrc\"\n_(\"Decrease Brush Strength\\tCtrl+-\");\n#line 2317 \"res/xrc/OutfitStudio.xrc\"\n_(\"Decrease brush strength\");\n#line 2321 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Less\\tA\");\n#line 2322 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Less\");\n#line 2325 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask More\\tD\");\n#line 2326 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask More\");\n#line 2330 \"res/xrc/OutfitStudio.xrc\"\n_(\"Invert Mask\\tCtrl+I\");\n#line 2331 \"res/xrc/OutfitStudio.xrc\"\n_(\"Invert Mask\");\n#line 2334 \"res/xrc/OutfitStudio.xrc\"\n_(\"Clear Mask\\tCtrl+A\");\n#line 2335 \"res/xrc/OutfitStudio.xrc\"\n_(\"Clear Mask\");\n#line 2339 \"res/xrc/OutfitStudio.xrc\"\n_(\"View\");\n#line 2341 \"res/xrc/OutfitStudio.xrc\"\n_(\"Front\\tShift+1\");\n#line 2344 \"res/xrc/OutfitStudio.xrc\"\n_(\"Back\\tShift+2\");\n#line 2347 \"res/xrc/OutfitStudio.xrc\"\n_(\"Left\\tShift+3\");\n#line 2350 \"res/xrc/OutfitStudio.xrc\"\n_(\"Right\\tShift+4\");\n#line 2353 \"res/xrc/OutfitStudio.xrc\"\n_(\"Perspective\\tShift+5\");\n#line 2358 \"res/xrc/OutfitStudio.xrc\"\n_(\"Toggle Rotation Center\\tShift+R\");\n#line 2359 \"res/xrc/OutfitStudio.xrc\"\n_(\"Switch between the different rotation center modes.\");\n#line 2362 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Nodes\\tShift+N\");\n#line 2366 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Bones\\tShift+B\");\n#line 2370 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Floor\\tG\");\n#line 2375 \"res/xrc/OutfitStudio.xrc\"\n_(\"Toggle Visibility\\tE\");\n#line 2376 \"res/xrc/OutfitStudio.xrc\"\n_(\"Switch between the different visibility modes for the selected shapes.\");\n#line 2379 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show Wireframe\\tW\");\n#line 2380 \"res/xrc/OutfitStudio.xrc\"\n_(\"Show wireframe on all models.\");\n#line 2384 \"res/xrc/OutfitStudio.xrc\"\n_(\"Enable Lighting\\tL\");\n#line 2385 \"res/xrc/OutfitStudio.xrc\"\n_(\"Turn on or off lighting.\");\n#line 2390 \"res/xrc/OutfitStudio.xrc\"\n_(\"Enable Textures\\tT\");\n#line 2391 \"res/xrc/OutfitStudio.xrc\"\n_(\"Display texture maps on models.\");\n#line 2396 \"res/xrc/OutfitStudio.xrc\"\n_(\"Enable Vertex Colors\");\n#line 2397 \"res/xrc/OutfitStudio.xrc\"\n_(\"Display vertex colors on models.\");\n#line 2405 \"res/xrc/OutfitStudio.xrc\"\n_(\"Shape\");\n#line 2407 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export\");\n#line 2409 \"res/xrc/OutfitStudio.xrc\"\n_(\"To NIF...\");\n#line 2410 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export only the selected shapes to a NIF file.\");\n#line 2413 \"res/xrc/OutfitStudio.xrc\"\n_(\"To OBJ...\");\n#line 2414 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export only the selected shapes to an OBJ file.\");\n#line 2417 \"res/xrc/OutfitStudio.xrc\"\n_(\"To FBX...\");\n#line 2418 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export only the selected shapes to an FBX file.\");\n#line 2421 \"res/xrc/OutfitStudio.xrc\"\n_(\"To TRI (Head)...\");\n#line 2422 \"res/xrc/OutfitStudio.xrc\"\n_(\"Export head morphs to a TRI file.\");\n#line 2426 \"res/xrc/OutfitStudio.xrc\"\n_(\"UV\");\n#line 2428 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit...\");\n#line 2429 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit the texture coordinates.\");\n#line 2432 \"res/xrc/OutfitStudio.xrc\"\n_(\"Invert X\");\n#line 2433 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inverts the X-axis of the texture coordinates.\");\n#line 2436 \"res/xrc/OutfitStudio.xrc\"\n_(\"Invert Y\");\n#line 2437 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inverts the Y-axis of the texture coordinates.\");\n#line 2441 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Vertices...\\tShift+Del\");\n#line 2442 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deletes all unmasked vertices of the currently selected shapes.\");\n#line 2445 \"res/xrc/OutfitStudio.xrc\"\n_(\"Separate Vertices...\\tShift+S\");\n#line 2446 \"res/xrc/OutfitStudio.xrc\"\n_(\"Separate the current shape into two by using the mask.\");\n#line 2449 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mirror Shape...\");\n#line 2450 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mirror the selected shapes on any axis.\");\n#line 2453 \"res/xrc/OutfitStudio.xrc\"\n_(\"Merge Geometry...\");\n#line 2454 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copies vertices and triangles from one shape to another.\");\n#line 2457 \"res/xrc/OutfitStudio.xrc\"\n_(\"Duplicate...\");\n#line 2458 \"res/xrc/OutfitStudio.xrc\"\n_(\"Duplicate the current shape.\");\n#line 2461 \"res/xrc/OutfitStudio.xrc\"\n_(\"Refine Mesh\");\n#line 2462 \"res/xrc/OutfitStudio.xrc\"\n_(\"Splits all edges between unmasked vertices\");\n#line 2465 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rename...\\tF2\");\n#line 2466 \"res/xrc/OutfitStudio.xrc\"\n_(\"Change the name of the current shape.\");\n#line 2469 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set Reference\");\n#line 2470 \"res/xrc/OutfitStudio.xrc\"\n_(\"Turn the shape into the reference shape of the project.\");\n#line 2474 \"res/xrc/OutfitStudio.xrc\"\n_(\"Move...\");\n#line 2475 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply an offset adjustment to the mesh vertices. This permanently moves vertices.\");\n#line 2478 \"res/xrc/OutfitStudio.xrc\"\n_(\"Scale...\");\n#line 2479 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply a scale adjustment to the shape. This permanently moves vertices.\");\n#line 2482 \"res/xrc/OutfitStudio.xrc\"\n_(\"Rotate...\");\n#line 2483 \"res/xrc/OutfitStudio.xrc\"\n_(\"Apply a rotation to the mesh vertices. This permanently moves vertices.\");\n#line 2486 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inflate...\");\n#line 2487 \"res/xrc/OutfitStudio.xrc\"\n_(\"Inflates/deflates a shape along its normals. This permanently moves vertices.\");\n#line 2490 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fix Clipping...\");\n#line 2491 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fixes clipping of outfit vertices that penetrate the reference shape.\");\n#line 2495 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copy Bone Weights\");\n#line 2496 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copies all bone weights from the reference shape to the current shape.\");\n#line 2499 \"res/xrc/OutfitStudio.xrc\"\n_(\"Transfer Selected Weights\");\n#line 2500 \"res/xrc/OutfitStudio.xrc\"\n_(\"Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order.\");\n#line 2503 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Weighted Vertices\");\n#line 2504 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks vertices with bone weights, so you can manually assign weights to unweighted vertices.\");\n#line 2507 \"res/xrc/OutfitStudio.xrc\"\n_(\"Check For Bad Bones\");\n#line 2508 \"res/xrc/OutfitStudio.xrc\"\n_(\"Looks for bones with inconsistencies in their transforms.  If any are found, a dialog is opened to give options for fixing them.\");\n#line 2512 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copy Partitions/Segments...\");\n#line 2513 \"res/xrc/OutfitStudio.xrc\"\n_(\"Copies partitions/segments and all triangle assignments from the reference shape to the current shape.\");\n#line 2517 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Symmetric Vertices...\");\n#line 2518 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks unmasked vertices that have a mirrored vertex with identical data.\");\n#line 2521 \"res/xrc/OutfitStudio.xrc\"\n_(\"Symmetrize Vertices...\");\n#line 2522 \"res/xrc/OutfitStudio.xrc\"\n_(\"Changes vertex data to be identical to mirrored vertices.\");\n#line 2525 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Symmetric Triangles\");\n#line 2526 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks triangles that can be matched to a mirrored triangle.\");\n#line 2530 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete\\tDel\");\n#line 2531 \"res/xrc/OutfitStudio.xrc\"\n_(\"Removes the currently selected shape from the outfit.\");\n#line 2534 \"res/xrc/OutfitStudio.xrc\"\n_(\"Properties...\");\n#line 2535 \"res/xrc/OutfitStudio.xrc\"\n_(\"Opens the properties dialog for shader, texture and more settings of the selected shape.\");\n#line 2539 \"res/xrc/OutfitStudio.xrc\"\n_(\"Bones\");\n#line 2541 \"res/xrc/OutfitStudio.xrc\"\n_(\"Bad Bone\");\n#line 2543 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set Skin Transform From Node\");\n#line 2544 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fixes the bad bone by calculating a new skin-to-bone transform.\");\n#line 2547 \"res/xrc/OutfitStudio.xrc\"\n_(\"Set Node Transform From Skin\");\n#line 2548 \"res/xrc/OutfitStudio.xrc\"\n_(\"Fixes the bad custom bone by calculating a new bone-to-global transform.\");\n#line 2552 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add\");\n#line 2554 \"res/xrc/OutfitStudio.xrc\"\n_(\"From Skeleton...\");\n#line 2555 \"res/xrc/OutfitStudio.xrc\"\n_(\"Choose a bone from the reference skeleton to add to the project.\");\n#line 2558 \"res/xrc/OutfitStudio.xrc\"\n_(\"Custom Bone...\");\n#line 2559 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add a custom bone to the project.\");\n#line 2563 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete\");\n#line 2565 \"res/xrc/OutfitStudio.xrc\"\n_(\"From Project\");\n#line 2566 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete bone(s) from all shapes of the project.\");\n#line 2569 \"res/xrc/OutfitStudio.xrc\"\n_(\"From Selected Shapes\");\n#line 2570 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete bone(s) from only the selected shapes.\");\n#line 2574 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit Bone...\");\n#line 2575 \"res/xrc/OutfitStudio.xrc\"\n_(\"Edit a custom bone or view a standard bone.\");\n#line 2578 \"res/xrc/OutfitStudio.xrc\"\n_(\"Mask Weighted Vertices\");\n#line 2579 \"res/xrc/OutfitStudio.xrc\"\n_(\"Masks vertices with weights for the selected bones.\");\n#line 2583 \"res/xrc/OutfitStudio.xrc\"\n_(\"Bones\");\n#line 2585 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add\");\n#line 2587 \"res/xrc/OutfitStudio.xrc\"\n_(\"From Skeleton...\");\n#line 2588 \"res/xrc/OutfitStudio.xrc\"\n_(\"Choose a bone from the reference skeleton to add to the project.\");\n#line 2591 \"res/xrc/OutfitStudio.xrc\"\n_(\"Custom Bone...\");\n#line 2592 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add a custom bone to the project.\");\n#line 2597 \"res/xrc/OutfitStudio.xrc\"\n_(\"Segments\");\n#line 2599 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Segment...\");\n#line 2600 \"res/xrc/OutfitStudio.xrc\"\n_(\"Choose a segment to add to the shape.\");\n#line 2603 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Sub Segment...\");\n#line 2604 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add a new sub segment to the currently selected segment.\");\n#line 2607 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Segment...\");\n#line 2608 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete segment and all of its sub segments from the shape.\");\n#line 2612 \"res/xrc/OutfitStudio.xrc\"\n_(\"Sub Segments\");\n#line 2614 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Sub Segment...\");\n#line 2615 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add a new sub segment to the currently selected segment.\");\n#line 2618 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Sub Segment...\");\n#line 2619 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete the selected sub segment.\");\n#line 2623 \"res/xrc/OutfitStudio.xrc\"\n_(\"Segments\");\n#line 2625 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Segment...\");\n#line 2626 \"res/xrc/OutfitStudio.xrc\"\n_(\"Choose a segment to add to the shape.\");\n#line 2630 \"res/xrc/OutfitStudio.xrc\"\n_(\"Partitions\");\n#line 2632 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Partition...\");\n#line 2633 \"res/xrc/OutfitStudio.xrc\"\n_(\"Adds a new partition to the shape.\");\n#line 2636 \"res/xrc/OutfitStudio.xrc\"\n_(\"Delete Partition...\");\n#line 2637 \"res/xrc/OutfitStudio.xrc\"\n_(\"Deletes the partition from the shape.\");\n#line 2641 \"res/xrc/OutfitStudio.xrc\"\n_(\"Partitions\");\n#line 2643 \"res/xrc/OutfitStudio.xrc\"\n_(\"Add Partition...\");\n#line 2644 \"res/xrc/OutfitStudio.xrc\"\n_(\"Adds a new partition to the shape.\");\n#line 5 \"res/xrc/Project.xrc\"\n_(\"New Project\");\n#line 16 \"res/xrc/Project.xrc\"\n_(\"Welcome to the New Project wizard!\\n\\nFirst, please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\");\n#line 32 \"res/xrc/Project.xrc\"\n_(\"Reference\");\n#line 50 \"res/xrc/Project.xrc\"\n_(\"From Template\");\n#line 69 \"res/xrc/Project.xrc\"\n_(\"From File\");\n#line 79 \"res/xrc/Project.xrc\"\n_(\"Select a project or NIF file\");\n#line 106 \"res/xrc/Project.xrc\"\n_(\"Slider Set:\");\n#line 124 \"res/xrc/Project.xrc\"\n_(\"Shape:\");\n#line 146 \"res/xrc/Project.xrc\"\n_(\"Clear Reference\");\n#line 162 \"res/xrc/Project.xrc\"\n_(\"Next, select an outfit/mesh to work on and enter a display name for it.\");\n#line 177 \"res/xrc/Project.xrc\"\n_(\"Display Name\");\n#line 197 \"res/xrc/Project.xrc\"\n_(\"Outfit/Mesh\");\n#line 210 \"res/xrc/Project.xrc\"\n_(\"From File\");\n#line 220 \"res/xrc/Project.xrc\"\n_(\"Select a file to load as an outfit/mesh\");\n#line 232 \"res/xrc/Project.xrc\"\n_(\"Clear Outfit\");\n#line 250 \"res/xrc/Project.xrc\"\n_(\"Textures\");\n#line 257 \"res/xrc/Project.xrc\"\n_(\"Automatically search for textures\");\n#line 272 \"res/xrc/Project.xrc\"\n_(\"From File\");\n#line 282 \"res/xrc/Project.xrc\"\n_(\"Select a texture file\");\n#line 297 \"res/xrc/Project.xrc\"\n_(\"Save Project As...\");\n#line 319 \"res/xrc/Project.xrc\"\n_(\"Display Name\");\n#line 328 \"res/xrc/Project.xrc\"\n_(\"The name of the outfit and slider set, as it will appear in BodySlide.\");\n#line 337 \"res/xrc/Project.xrc\"\n_(\"Copies the current display name to the project text fields below.\");\n#line 338 \"res/xrc/Project.xrc\"\n_(\"To Project\");\n#line 354 \"res/xrc/Project.xrc\"\n_(\"Output File Name\");\n#line 363 \"res/xrc/Project.xrc\"\n_(\"The name of the outfit file that will end up in the game data path when BodySlide builds it. Should not include _1 or _0 in the name, e.g: lovelydress\");\n#line 389 \"res/xrc/Project.xrc\"\n_(\"Output Data Path\");\n#line 398 \"res/xrc/Project.xrc\"\n_(\"The location in the game's data path where BodySlide-built outfit files will be placed, e.g: meshes\\\\clothes\\\\lovelydress\");\n#line 410 \"res/xrc/Project.xrc\"\n_(\"If this is enabled, BodySlide creates a low and high weight model when it generates the final outfit.\");\n#line 411 \"res/xrc/Project.xrc\"\n_(\"Low/High Weight Output\");\n#line 419 \"res/xrc/Project.xrc\"\n_(\"If this is enabled, only one output file will be created (useful for single-weighted things like hair).\");\n#line 420 \"res/xrc/Project.xrc\"\n_(\"Single Weight Output\");\n#line 431 \"res/xrc/Project.xrc\"\n_(\"Project\");\n#line 443 \"res/xrc/Project.xrc\"\n_(\"Slider Set File\");\n#line 453 \"res/xrc/Project.xrc\"\n_(\"The .osp slider set project file\");\n#line 454 \"res/xrc/Project.xrc\"\n_(\"Select slider set .osp file name\");\n#line 472 \"res/xrc/Project.xrc\"\n_(\"Shape Data Folder\");\n#line 482 \"res/xrc/Project.xrc\"\n_(\"The folder where all the slider data will go, as well as the base outfit NIF file.\");\n#line 483 \"res/xrc/Project.xrc\"\n_(\"Select slider data folder\");\n#line 500 \"res/xrc/Project.xrc\"\n_(\"Shape Data File\");\n#line 510 \"res/xrc/Project.xrc\"\n_(\"The name of the output's base NIF file.\");\n#line 511 \"res/xrc/Project.xrc\"\n_(\"Select output NIF file name\");\n#line 523 \"res/xrc/Project.xrc\"\n_(\"Outfits require the reference body to be a part of the output file. Disable this if you've already copied the reference over or you don't want it included.\");\n#line 524 \"res/xrc/Project.xrc\"\n_(\"Copy reference shape into output\");\n#line 533 \"res/xrc/Project.xrc\"\n_(\"Prevents the building of morph .tri files in BodySlide for this project.\");\n#line 534 \"res/xrc/Project.xrc\"\n_(\"Prevent morph file building in BodySlide\");\n#line 543 \"res/xrc/Project.xrc\"\n_(\"Prevents the removal of fully zapped shapes when building in BodySlide. Useful when the shape order and count matters, like for retextures using texture sets.\");\n#line 544 \"res/xrc/Project.xrc\"\n_(\"Prevent removal of fully zapped shapes in BodySlide\");\n#line 563 \"res/xrc/Project.xrc\"\n_(\"&Save\");\n#line 570 \"res/xrc/Project.xrc\"\n_(\"&Cancel\");\n#line 579 \"res/xrc/Project.xrc\"\n_(\"Load Reference\");\n#line 588 \"res/xrc/Project.xrc\"\n_(\"Please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\");\n#line 598 \"res/xrc/Project.xrc\"\n_(\"Reference\");\n#line 616 \"res/xrc/Project.xrc\"\n_(\"From Template\");\n#line 635 \"res/xrc/Project.xrc\"\n_(\"From File\");\n#line 645 \"res/xrc/Project.xrc\"\n_(\"Select a project or NIF file\");\n#line 672 \"res/xrc/Project.xrc\"\n_(\"Slider Set:\");\n#line 690 \"res/xrc/Project.xrc\"\n_(\"Shape:\");\n#line 712 \"res/xrc/Project.xrc\"\n_(\"Clear Reference\");\n#line 724 \"res/xrc/Project.xrc\"\n_(\"Merge\");\n#line 736 \"res/xrc/Project.xrc\"\n_(\"Zaps\");\n#line 737 \"res/xrc/Project.xrc\"\n_(\"Merge existing zaps with new sliders\");\n#line 746 \"res/xrc/Project.xrc\"\n_(\"Sliders\");\n#line 747 \"res/xrc/Project.xrc\"\n_(\"Merge new sliders with existing sliders\");\n#line 756 \"res/xrc/Project.xrc\"\n_(\"Append new sliders\");\n#line 757 \"res/xrc/Project.xrc\"\n_(\"Append new sliders that aren't in the project at the end of the list (or don't)\");\n#line 778 \"res/xrc/Project.xrc\"\n_(\"&OK\");\n#line 785 \"res/xrc/Project.xrc\"\n_(\"&Cancel\");\n#line 794 \"res/xrc/Project.xrc\"\n_(\"Load Outfit\");\n#line 803 \"res/xrc/Project.xrc\"\n_(\"Please select an outfit/mesh to work on and enter a display name for it.\");\n#line 818 \"res/xrc/Project.xrc\"\n_(\"Display Name\");\n#line 838 \"res/xrc/Project.xrc\"\n_(\"Outfit/Mesh\");\n#line 851 \"res/xrc/Project.xrc\"\n_(\"From File\");\n#line 861 \"res/xrc/Project.xrc\"\n_(\"Select a file to load as an outfit/mesh\");\n#line 873 \"res/xrc/Project.xrc\"\n_(\"Clear Outfit\");\n#line 882 \"res/xrc/Project.xrc\"\n_(\"Keep other shapes\");\n#line 901 \"res/xrc/Project.xrc\"\n_(\"Textures\");\n#line 908 \"res/xrc/Project.xrc\"\n_(\"Automatically search for textures\");\n#line 923 \"res/xrc/Project.xrc\"\n_(\"From File\");\n#line 933 \"res/xrc/Project.xrc\"\n_(\"Select a texture file\");\n#line 955 \"res/xrc/Project.xrc\"\n_(\"&OK\");\n#line 962 \"res/xrc/Project.xrc\"\n_(\"&Cancel\");\n#line 972 \"res/xrc/Project.xrc\"\n_(\"Pack Projects...\");\n#line 1006 \"res/xrc/Project.xrc\"\n_(\"Group file (optional):\");\n#line 1015 \"res/xrc/Project.xrc\"\n_(\"Group file to pack (optional).\");\n#line 1016 \"res/xrc/Project.xrc\"\n_(\"Select a group XML file\");\n#line 1032 \"res/xrc/Project.xrc\"\n_(\"Merged file name:\");\n#line 1040 \"res/xrc/Project.xrc\"\n_(\"File name to use for the merged project file.\");\n#line 1066 \"res/xrc/Project.xrc\"\n_(\"Pack Folder...\");\n#line 1075 \"res/xrc/Project.xrc\"\n_(\"Pack Archive...\");\n#line 1084 \"res/xrc/Project.xrc\"\n_(\"Group Manager\");\n#line 1092 \"res/xrc/Project.xrc\"\n_(\"Cancel\");\n#line 1101 \"res/xrc/Project.xrc\"\n_(\"Select None\");\n#line 1104 \"res/xrc/Project.xrc\"\n_(\"Select All\");\n#line 1107 \"res/xrc/Project.xrc\"\n_(\"Invert Selection\");\n#line 6 \"res/xrc/SavePreset.xrc\"\n_(\"Enter preset name...\");\n#line 15 \"res/xrc/SavePreset.xrc\"\n_(\"Please enter a name for the new preset:\");\n#line 38 \"res/xrc/SavePreset.xrc\"\n_(\"Select groups to assign to the new preset:\");\n#line 78 \"res/xrc/SavePreset.xrc\"\n_(\"&Save\");\n#line 85 \"res/xrc/SavePreset.xrc\"\n_(\"&Cancel\");\n#line 5 \"res/xrc/Settings.xrc\"\n_(\"Settings\");\n#line 15 \"res/xrc/Settings.xrc\"\n_(\"Game\");\n#line 28 \"res/xrc/Settings.xrc\"\n_(\"Target Game\");\n#line 37 \"res/xrc/Settings.xrc\"\n_(\"Choose the target game you want to use the program for here.\");\n#line 67 \"res/xrc/Settings.xrc\"\n_(\"Game Data Path\");\n#line 77 \"res/xrc/Settings.xrc\"\n_(\"Select the data path of the game...\");\n#line 79 \"res/xrc/Settings.xrc\"\n_(\"Data path to load textures from.\");\n#line 91 \"res/xrc/Settings.xrc\"\n_(\"Advanced\");\n#line 108 \"res/xrc/Settings.xrc\"\n_(\"Output Path\");\n#line 118 \"res/xrc/Settings.xrc\"\n_(\"Select the output path...\");\n#line 120 \"res/xrc/Settings.xrc\"\n_(\"Data path to build files to. If empty, Game Data Path will be used instead.\");\n#line 137 \"res/xrc/Settings.xrc\"\n_(\"Project Path\");\n#line 147 \"res/xrc/Settings.xrc\"\n_(\"Select the project path...\");\n#line 149 \"res/xrc/Settings.xrc\"\n_(\"Project path where files related to BodySlide are loaded from. If empty, executable directory will be used instead.\");\n#line 165 \"res/xrc/Settings.xrc\"\n_(\"With this turned on, BodySlide receives a new checkbox \\\"Force Body Normals\\\". Using it when building adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod.\");\n#line 166 \"res/xrc/Settings.xrc\"\n_(\"Show 'Force Body Normals'\");\n#line 184 \"res/xrc/Settings.xrc\"\n_(\"General\");\n#line 196 \"res/xrc/Settings.xrc\"\n_(\"Enables/disables the dialog for choosing which set to build during a batch build if overrides happen.\");\n#line 197 \"res/xrc/Settings.xrc\"\n_(\"Override Warning\");\n#line 206 \"res/xrc/Settings.xrc\"\n_(\"Enables/disables scanning BSAs in the game data folder for textures to load.\");\n#line 207 \"res/xrc/Settings.xrc\"\n_(\"BSA Textures\");\n#line 224 \"res/xrc/Settings.xrc\"\n_(\"Enables/disables panning the camera with the left mouse button in Outfit Studio.\");\n#line 225 \"res/xrc/Settings.xrc\"\n_(\"Left Mouse Pan\");\n#line 234 \"res/xrc/Settings.xrc\"\n_(\"Enables/disables opening the brush settings near the mouse cursor when hitting the 'space' key.\");\n#line 235 \"res/xrc/Settings.xrc\"\n_(\"Brush Settings Near Cursor\");\n#line 244 \"res/xrc/Settings.xrc\"\n_(\"Enables/disables the undo history for the mask brush and vertex selection.\");\n#line 245 \"res/xrc/Settings.xrc\"\n_(\"Mask History\");\n#line 263 \"res/xrc/Settings.xrc\"\n_(\"Single Instance\");\n#line 272 \"res/xrc/Settings.xrc\"\n_(\"Controls behavior when opening files and another instance is already running.\");\n#line 275 \"res/xrc/Settings.xrc\"\n_(\"Ask (Message Box)\");\n#line 276 \"res/xrc/Settings.xrc\"\n_(\"Open in Existing\");\n#line 277 \"res/xrc/Settings.xrc\"\n_(\"Open in New\");\n#line 295 \"res/xrc/Settings.xrc\"\n_(\"Language\");\n#line 304 \"res/xrc/Settings.xrc\"\n_(\"Use the selected language for the program.\");\n#line 319 \"res/xrc/Settings.xrc\"\n_(\"Rendering\");\n#line 325 \"res/xrc/Settings.xrc\"\n_(\"Enables/disables the perspective view in the rendering window.\");\n#line 326 \"res/xrc/Settings.xrc\"\n_(\"Perspective View\");\n#line 341 \"res/xrc/Settings.xrc\"\n_(\"Background Color\");\n#line 350 \"res/xrc/Settings.xrc\"\n_(\"Background color of the renderer.\");\n#line 367 \"res/xrc/Settings.xrc\"\n_(\"Wireframe Color\");\n#line 376 \"res/xrc/Settings.xrc\"\n_(\"Wireframe color of the renderer.\");\n#line 393 \"res/xrc/Settings.xrc\"\n_(\"Point Color (normal/masked)\");\n#line 402 \"res/xrc/Settings.xrc\"\n_(\"Color of points in the renderer.\");\n#line 411 \"res/xrc/Settings.xrc\"\n_(\"Color of masked points in the renderer.\");\n#line 426 \"res/xrc/Settings.xrc\"\n_(\"Data Files\");\n#line 444 \"res/xrc/Settings.xrc\"\n_(\"Reference Skeleton\");\n#line 457 \"res/xrc/Settings.xrc\"\n_(\"File\");\n#line 467 \"res/xrc/Settings.xrc\"\n_(\"Select a reference skeleton .nif file...\");\n#line 470 \"res/xrc/Settings.xrc\"\n_(\"The reference skeleton file for Outfit Studio.\");\n#line 487 \"res/xrc/Settings.xrc\"\n_(\"Root Node\");\n#line 496 \"res/xrc/Settings.xrc\"\n_(\"The root node name of the reference skeleton. Can differ from game to game.\");\n#line 524 \"res/xrc/Settings.xrc\"\n_(\"&OK\");\n#line 531 \"res/xrc/Settings.xrc\"\n_(\"&Cancel\");\n#line 5 \"res/xrc/Setup.xrc\"\n_(\"Setup\");\n#line 15 \"res/xrc/Setup.xrc\"\n_(\"Please select the data folder and your target game.\\nYou can only choose one game at a time, but it is possible to change the selection in the settings.\");\n#line 44 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 45 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 55 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 73 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 74 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 84 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 102 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 103 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 113 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 131 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 132 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 142 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 160 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 161 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 171 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 189 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 190 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 200 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 218 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 219 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 229 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 247 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 248 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 258 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 276 \"res/xrc/Setup.xrc\"\n_(\"Game not found! Select the data folder manually...\");\n#line 277 \"res/xrc/Setup.xrc\"\n_(\"Select a folder\");\n#line 287 \"res/xrc/Setup.xrc\"\n_(\"Choose Game\");\n#line 302 \"res/xrc/Setup.xrc\"\n_(\"&Cancel\");\n#line 5 \"res/xrc/ShapeProperties.xrc\"\n_(\"Shape Properties\");\n#line 16 \"res/xrc/ShapeProperties.xrc\"\n_(\"Shader\");\n#line 31 \"res/xrc/ShapeProperties.xrc\"\n_(\"Name\");\n#line 84 \"res/xrc/ShapeProperties.xrc\"\n_(\"Type\");\n#line 102 \"res/xrc/ShapeProperties.xrc\"\n_(\"Specular Color\");\n#line 120 \"res/xrc/ShapeProperties.xrc\"\n_(\"Specular Strength\");\n#line 139 \"res/xrc/ShapeProperties.xrc\"\n_(\"Specular Power\");\n#line 179 \"res/xrc/ShapeProperties.xrc\"\n_(\"Emissive Color\");\n#line 197 \"res/xrc/ShapeProperties.xrc\"\n_(\"Emissive Multiple\");\n#line 216 \"res/xrc/ShapeProperties.xrc\"\n_(\"Alpha\");\n#line 235 \"res/xrc/ShapeProperties.xrc\"\n_(\"Vertex Colors\");\n#line 252 \"res/xrc/ShapeProperties.xrc\"\n_(\"Double Sided\");\n#line 280 \"res/xrc/ShapeProperties.xrc\"\n_(\"Add\");\n#line 289 \"res/xrc/ShapeProperties.xrc\"\n_(\"Remove\");\n#line 298 \"res/xrc/ShapeProperties.xrc\"\n_(\"Textures...\");\n#line 310 \"res/xrc/ShapeProperties.xrc\"\n_(\"Transparency\");\n#line 333 \"res/xrc/ShapeProperties.xrc\"\n_(\"Threshold\");\n#line 373 \"res/xrc/ShapeProperties.xrc\"\n_(\"Vertex Alpha\");\n#line 391 \"res/xrc/ShapeProperties.xrc\"\n_(\"Alpha Test\");\n#line 409 \"res/xrc/ShapeProperties.xrc\"\n_(\"Alpha Blend\");\n#line 438 \"res/xrc/ShapeProperties.xrc\"\n_(\"Add\");\n#line 447 \"res/xrc/ShapeProperties.xrc\"\n_(\"Remove\");\n#line 460 \"res/xrc/ShapeProperties.xrc\"\n_(\"Copy from shape...\");\n#line 468 \"res/xrc/ShapeProperties.xrc\"\n_(\"Geometry\");\n#line 488 \"res/xrc/ShapeProperties.xrc\"\n_(\"Full Precision\");\n#line 507 \"res/xrc/ShapeProperties.xrc\"\n_(\"Sub Index\");\n#line 526 \"res/xrc/ShapeProperties.xrc\"\n_(\"Skinned\");\n#line 544 \"res/xrc/ShapeProperties.xrc\"\n_(\"Dynamic\");\n#line 590 \"res/xrc/ShapeProperties.xrc\"\n_(\"Extra Data\");\n#line 611 \"res/xrc/ShapeProperties.xrc\"\n_(\"Add\");\n#line 620 \"res/xrc/ShapeProperties.xrc\"\n_(\"Type\");\n#line 629 \"res/xrc/ShapeProperties.xrc\"\n_(\"Name\");\n#line 638 \"res/xrc/ShapeProperties.xrc\"\n_(\"Value\");\n#line 648 \"res/xrc/ShapeProperties.xrc\"\n_(\"Coordinates\");\n#line 657 \"res/xrc/ShapeProperties.xrc\"\n_(\"Transform from shape to global coordinates:\");\n#line 672 \"res/xrc/ShapeProperties.xrc\"\n_(\"Scale\");\n#line 711 \"res/xrc/ShapeProperties.xrc\"\n_(\"Origin\");\n#line 720 \"res/xrc/ShapeProperties.xrc\"\n_(\"Rotation\");\n#line 806 \"res/xrc/ShapeProperties.xrc\"\n_(\"Recalculate geometry's coordinates so it doesn't move\");\n#line 807 \"res/xrc/ShapeProperties.xrc\"\n_(\"Transform geometry so its position in global coordinates does not change.\");\n#line 831 \"res/xrc/ShapeProperties.xrc\"\n_(\"&OK\");\n#line 838 \"res/xrc/ShapeProperties.xrc\"\n_(\"&Cancel\");\n#line 6 \"res/xrc/Skeleton.xrc\"\n_(\"Select a bone to add\");\n#line 15 \"res/xrc/Skeleton.xrc\"\n_(\"Bones in the current reference skeleton:\");\n#line 36 \"res/xrc/Skeleton.xrc\"\n_(\"&OK\");\n#line 43 \"res/xrc/Skeleton.xrc\"\n_(\"&Cancel\");\n#line 53 \"res/xrc/Skeleton.xrc\"\n_(\"Add Custom Bone\");\n#line 68 \"res/xrc/Skeleton.xrc\"\n_(\"Parent\");\n#line 94 \"res/xrc/Skeleton.xrc\"\n_(\"Name\");\n#line 133 \"res/xrc/Skeleton.xrc\"\n_(\"Origin\");\n#line 142 \"res/xrc/Skeleton.xrc\"\n_(\"Rotation\");\n#line 234 \"res/xrc/Skeleton.xrc\"\n_(\"Add Count #\");\n#line 259 \"res/xrc/Skeleton.xrc\"\n_(\"&OK\");\n#line 266 \"res/xrc/Skeleton.xrc\"\n_(\"&Cancel\");\n#line 6 \"res/xrc/Slider.xrc\"\n_(\"Select a slider preset\");\n#line 15 \"res/xrc/Slider.xrc\"\n_(\"Choose a preset:\");\n#line 40 \"res/xrc/Slider.xrc\"\n_(\"Low weight\");\n#line 49 \"res/xrc/Slider.xrc\"\n_(\"High weight\");\n#line 64 \"res/xrc/Slider.xrc\"\n_(\"&OK\");\n#line 71 \"res/xrc/Slider.xrc\"\n_(\"&Cancel\");\n#line 81 \"res/xrc/Slider.xrc\"\n_(\"Slider Properties\");\n#line 91 \"res/xrc/Slider.xrc\"\n_(\"Slider Name\");\n#line 108 \"res/xrc/Slider.xrc\"\n_(\"Default Values\");\n#line 114 \"res/xrc/Slider.xrc\"\n_(\"Low\");\n#line 131 \"res/xrc/Slider.xrc\"\n_(\"High\");\n#line 148 \"res/xrc/Slider.xrc\"\n_(\"Zapped\");\n#line 161 \"res/xrc/Slider.xrc\"\n_(\"Options\");\n#line 173 \"res/xrc/Slider.xrc\"\n_(\"Invert\");\n#line 182 \"res/xrc/Slider.xrc\"\n_(\"Hidden\");\n#line 191 \"res/xrc/Slider.xrc\"\n_(\"Zap\");\n#line 200 \"res/xrc/Slider.xrc\"\n_(\"UV\");\n#line 211 \"res/xrc/Slider.xrc\"\n_(\"Toggle Zaps:\");\n#line 238 \"res/xrc/Slider.xrc\"\n_(\"&OK\");\n#line 246 \"res/xrc/Slider.xrc\"\n_(\"&Cancel\");\n#line 6 \"res/xrc/SliderDataImport.xrc\"\n_(\"Slider Data Import Options...\");\n#line 21 \"res/xrc/SliderDataImport.xrc\"\n_(\"Select the shapes that slider data will be imported for:\");\n#line 52 \"res/xrc/SliderDataImport.xrc\"\n_(\"Select the sliders to be imported\");\n#line 77 \"res/xrc/SliderDataImport.xrc\"\n_(\"Merge Sliders\");\n#line 90 \"res/xrc/SliderDataImport.xrc\"\n_(\"&OK\");\n#line 97 \"res/xrc/SliderDataImport.xrc\"\n_(\"&Cancel\");\n#line 106 \"res/xrc/SliderDataImport.xrc\"\n_(\"Select None\");\n#line 109 \"res/xrc/SliderDataImport.xrc\"\n_(\"Select All\");\n#line 112 \"res/xrc/SliderDataImport.xrc\"\n_(\"Invert Selection\");\n#line 6 \"res/xrc/WeightCopy.xrc\"\n_(\"Copy Bone Weights\");\n#line 15 \"res/xrc/WeightCopy.xrc\"\n_(\"Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient.\");\n#line 35 \"res/xrc/WeightCopy.xrc\"\n_(\"Search Radius\");\n#line 64 \"res/xrc/WeightCopy.xrc\"\n_(\"Max Vertex Targets\");\n#line 95 \"res/xrc/WeightCopy.xrc\"\n_(\"No Target Limit\");\n#line 104 \"res/xrc/WeightCopy.xrc\"\n_(\"Bones to copy (click to preview weights):\");\n#line 127 \"res/xrc/WeightCopy.xrc\"\n_(\"Check All\");\n#line 135 \"res/xrc/WeightCopy.xrc\"\n_(\"Uncheck All\");\n#line 151 \"res/xrc/WeightCopy.xrc\"\n_(\"Pose:\");\n#line 167 \"res/xrc/WeightCopy.xrc\"\n_(\"The skin coordinate system doesn't match the reference shape's. Do you want to copy the transforms?\");\n#line 177 \"res/xrc/WeightCopy.xrc\"\n_(\"Copy skin transform from reference\");\n#line 187 \"res/xrc/WeightCopy.xrc\"\n_(\"Recalculate geometry's coordinates so it doesn't move\");\n#line 188 \"res/xrc/WeightCopy.xrc\"\n_(\"Transform geometry so its position in global coordinates does not change.\");\n#line 204 \"res/xrc/WeightCopy.xrc\"\n_(\"&Preview\");\n#line 205 \"res/xrc/WeightCopy.xrc\"\n_(\"Run the weight copy and preview the results. Click again to update the preview.\");\n#line 228 \"res/xrc/WeightCopy.xrc\"\n_(\"&OK\");\n#line 236 \"res/xrc/WeightCopy.xrc\"\n_(\"&Cancel\");\n"
  },
  {
    "path": "lang/zh/BodySlide.po",
    "content": "msgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: BodySlide_zh\\n\"\n\"POT-Creation-Date: \\n\"\n\"PO-Revision-Date: 2025-01-27 19:43+0100\\n\"\n\"Last-Translator: \\n\"\n\"Language-Team: 小莫\\n\"\n\"Language: zh\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=UTF-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"X-Generator: Poedit 3.5\\n\"\n\"X-Poedit-Basepath: .\\n\"\n\"X-Poedit-SearchPath-0: BodySlide.po\\n\"\n\nmsgid \"Outfit/Body\"\nmsgstr \"装备/身体\"\n\nmsgid \"Select an outfit to modify\"\nmsgstr \"选择一个装备来修改\"\n\nmsgid \"Preset\"\nmsgstr \"预设\"\n\nmsgid \"Choose from a list of slider settings presets\"\nmsgstr \"从一列滑块集预设中选择\"\n\nmsgid \"Saves the new slider values to the currently selected preset\"\nmsgstr \"保存新滑块值到当前被选预设\"\n\nmsgid \"Save\"\nmsgstr \"保存\"\n\nmsgid \"Save the current slider settings as a new preset\"\nmsgstr \"将当前的滑块集作为新预设保存\"\n\nmsgid \"Save As...\"\nmsgstr \"另存为...\"\n\nmsgid \"\"\n\"Opens the group manager where you can edit existing or create new groups\"\nmsgstr \"打开组管理器以编辑现有组或创建新组\"\n\nmsgid \"Group Manager\"\nmsgstr \"组管理器\"\n\nmsgid \"Opens the current project in Outfit Studio\"\nmsgstr \"在Outfit Studio中打开当前项目\"\n\nmsgid \"Single Weight\"\nmsgstr \"单重量\"\n\nmsgid \"Low Weight\"\nmsgstr \"最小重量\"\n\nmsgid \"High Weight\"\nmsgstr \"最大重量\"\n\nmsgid \"Copy the low weight slider values to the high weight section.\"\nmsgstr \"复制最小重量的滑块值到最大重量那儿去。\"\n\nmsgid \"\"\n\"Build multiple outfits using the currently active slider values.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to custom directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"使用当前预设批量建立装备。\\n\"\n\"按住CTRL = 建立到自定义目录中\\n\"\n\"按住ALT = 从输出目录中删除\"\n\nmsgid \"Batch Build...\"\nmsgstr \"批量建立...\"\n\nmsgid \"Build Morphs\"\nmsgstr \"建立变形\"\n\nmsgid \"\"\n\"Builds a morphs (.tri) file alongside the meshes for accessing the sliders \"\n\"in-game. Requires other mods to make use of the morph data.\"\nmsgstr \"\"\n\"在网格旁建立一个变形(.tri)文件以在游戏中访问滑块。需要其他mod来利用变形数据。\"\n\nmsgid \"Show a preview window for this outfit.\"\nmsgstr \"显示这件装备的预览窗口。\"\n\nmsgid \"Preview\"\nmsgstr \"预览\"\n\nmsgid \"\"\n\"Creates the currently selected outfit/body.\\n\"\n\"\\n\"\n\"Hold CTRL = Build to working directory\\n\"\n\"Hold ALT = Delete from output directory\"\nmsgstr \"\"\n\"创建当前被选装备/身体。\\n\"\n\"按住CTRL = 建立到工作目录中\\n\"\n\"按住ALT = 从输出目录中删除\"\n\nmsgid \"Build\"\nmsgstr \"建立\"\n\nmsgid \"Copy the high weight slider values to the low weight section.\"\nmsgstr \"复制最大重量滑块值到最小重量那去。\"\n\nmsgid \"About\"\nmsgstr \"关于\"\n\nmsgid \"Open settings dialog.\"\nmsgstr \"打开设置对话框。\"\n\nmsgid \"Settings\"\nmsgstr \"设置\"\n\nmsgid \"\"\n\"Open Outfit Studio, a full-featured tool for creating and converting outfits.\"\nmsgstr \"打开Outfit Studio，一个功能齐全的装备创建和转换工具。\"\n\nmsgid \"Failed to launch Outfit Studio executable!\"\nmsgstr \"无法启动Outfit Studio的可执行文件！\"\n\nmsgid \"Filter Options\"\nmsgstr \"过滤器选项\"\n\nmsgid \"Choose groups...\"\nmsgstr \"选择组...\"\n\nmsgid \"Choose groups to display in the Outfit menu\"\nmsgstr \"选择要在装备菜单中显示的组\"\n\nmsgid \"Refresh Groups\"\nmsgstr \"刷新组\"\n\nmsgid \"Refresh group information\"\nmsgstr \"刷新组信息\"\n\nmsgid \"Save Outfit list as group...\"\nmsgstr \"将装备列表作为组保存...\"\n\nmsgid \"Save the current filtered outfit list as a group\"\nmsgstr \"将当前已过滤的装备列表保存为一个组\"\n\nmsgid \"Refresh Outfits\"\nmsgstr \"刷新装备\"\n\nmsgid \"Reloads outfit list\"\nmsgstr \"重新加载装备列表\"\n\nmsgid \"Select None\"\nmsgstr \"清除选择\"\n\nmsgid \"Select All\"\nmsgstr \"选择所有\"\n\nmsgid \"Enter preset name...\"\nmsgstr \"输入预设名...\"\n\nmsgid \"Please enter a name for the new preset:\"\nmsgstr \"请为新预设输入一个名字：\"\n\nmsgid \"Select groups to assign to the new preset:\"\nmsgstr \"选择要分配新预设的组：\"\n\nmsgid \"Deletes a project from its project file\"\nmsgstr \"从项目文件中删除项目\"\n\nmsgid \"Delete Project\"\nmsgstr \"删除项目\"\n\nmsgid \"Do you really wish to delete the selected project?\"\nmsgstr \"你真的要删除被选的项目吗？\"\n\nmsgid \"Deletes a preset from its preset file\"\nmsgstr \"从预设文件中删除预设\"\n\nmsgid \"Delete Preset\"\nmsgstr \"删除预设\"\n\nmsgid \"Do you really wish to delete the selected preset?\"\nmsgstr \"你真的要删除被选的预设吗？\"\n\nmsgid \"&Save\"\nmsgstr \"&保存\"\n\nmsgid \"&OK\"\nmsgstr \"&确定\"\n\nmsgid \"&Cancel\"\nmsgstr \"&取消\"\n\nmsgid \"\"\n\"Choose a group and add or remove members by selecting them in the lists.\"\nmsgstr \"选择一个组，并通过在列表中选取来增加或移除成员。\"\n\nmsgid \"Select a group XML file\"\nmsgstr \"选择一个组的 XML 文件\"\n\nmsgid \"Save As\"\nmsgstr \"另存为\"\n\nmsgid \"Groups\"\nmsgstr \"组\"\n\nmsgid \"Add Group\"\nmsgstr \"增加组\"\n\nmsgid \"Remove Group\"\nmsgstr \"移除组\"\n\nmsgid \"Members\"\nmsgstr \"成员\"\n\nmsgid \"Remove >>\"\nmsgstr \"移除 >>\"\n\nmsgid \"Outfits\"\nmsgstr \"装备\"\n\nmsgid \"<< Add\"\nmsgstr \"<< 增加\"\n\nmsgid \"Save Changes\"\nmsgstr \"保存更改\"\n\nmsgid \"\"\n\"Do you really want to close the group manager? All unsaved changes will be \"\n\"lost.\"\nmsgstr \"你确定关闭管理器身形管理器吗?所有未保存的内容都会丢失。\"\n\nmsgid \"Batch Build\"\nmsgstr \"批量建立\"\n\nmsgid \"\"\n\"Select the slider sets for the batch build process. Use the group and outfit \"\n\"filters to show the outfits you want!\"\nmsgstr \"为批量建立选择滑块集。使用组和装备过滤器来显示你想要的装备！\"\n\nmsgid \"&Build\"\nmsgstr \"&建立\"\n\nmsgid \"Game\"\nmsgstr \"游戏\"\n\nmsgid \"Target Game\"\nmsgstr \"目标游戏\"\n\nmsgid \"Choose the target game you want to use the program for here.\"\nmsgstr \"选择你想使用此程序的目标游戏。\"\n\nmsgid \"Fallout 3\"\nmsgstr \"辐射3\"\n\nmsgid \"Fallout New Vegas\"\nmsgstr \"辐射新维加斯\"\n\nmsgid \"Skyrim\"\nmsgstr \"天际\"\n\nmsgid \"Fallout 4\"\nmsgstr \"辐射4\"\n\nmsgid \"Advanced\"\nmsgstr \"高级\"\n\nmsgid \"Game Data Path\"\nmsgstr \"游戏数据路径\"\n\nmsgid \"Select the data path of the game...\"\nmsgstr \"选择此游戏的数据路径...\"\n\nmsgid \"Data path to load textures from.\"\nmsgstr \"用来加载材质（和建立文件）的数据路径。\"\n\nmsgid \"Output Path\"\nmsgstr \"输出路径\"\n\nmsgid \"Select the output path...\"\nmsgstr \"选择输出路径......\"\n\nmsgid \"\"\n\"Data path to build files to. If empty, Game Data Path will be used instead.\"\nmsgstr \"建立文件所用的数据路径。 留空则使用游戏数据路径。\"\n\nmsgid \"General\"\nmsgstr \"常规\"\n\nmsgid \"\"\n\"Enables/disables the dialog for choosing which set to build during a batch \"\n\"build if overrides happen.\"\nmsgstr \"开启/关闭在批量建立发生覆盖时的设置选择对话框。\"\n\nmsgid \"Override Warning\"\nmsgstr \"覆盖警告\"\n\nmsgid \"\"\n\"Enables/disables scanning BSAs in the game data folder for textures to load.\"\nmsgstr \"开启/关闭扫描游戏数据目录中的BSA以获取要加载的材质。\"\n\nmsgid \"BSA Textures\"\nmsgstr \"BSA材质\"\n\nmsgid \"\"\n\"Enables/disables panning the camera with the left mouse button in Outfit \"\n\"Studio.\"\nmsgstr \"开启/关闭用鼠标左键平移Outfit Studio中的相机。\"\n\nmsgid \"Left Mouse Pan\"\nmsgstr \"鼠标左键平移\"\n\nmsgid \"Data Files\"\nmsgstr \"数据文件\"\n\nmsgid \"Reference Skeleton\"\nmsgstr \"参照骨架\"\n\nmsgid \"File\"\nmsgstr \"文件\"\n\nmsgid \"Select a reference skeleton .nif file...\"\nmsgstr \"选择一个参照骨架.nif文件...\"\n\nmsgid \"The reference skeleton file for Outfit Studio.\"\nmsgstr \"Outfit Studio的参照骨架文件。\"\n\nmsgid \"Root Node\"\nmsgstr \"根结点\"\n\nmsgid \"\"\n\"The root node name of the reference skeleton. Can differ from game to game.\"\nmsgstr \"参照骨架的根节点名称。 不同游戏之间可能不同。\"\n\nmsgid \"Close\"\nmsgstr \"关闭\"\n\nmsgid \"Brush Settings\"\nmsgstr \"笔刷设置\"\n\nmsgid \"Size\"\nmsgstr \"尺寸\"\n\nmsgid \"Strength\"\nmsgstr \"强度\"\n\nmsgid \"Focus\"\nmsgstr \"焦点\"\n\nmsgid \"Spacing\"\nmsgstr \"间距\"\n\nmsgid \"Meshes\"\nmsgstr \"网格\"\n\nmsgid \"Bones\"\nmsgstr \"骨骼\"\n\nmsgid \"Lights\"\nmsgstr \"灯光\"\n\nmsgid \"Reset\"\nmsgstr \"重置\"\n\nmsgid \"Ambient\"\nmsgstr \"环境\"\n\nmsgid \"Frontal\"\nmsgstr \"前端\"\n\nmsgid \"Directional 1\"\nmsgstr \"方向1\"\n\nmsgid \"Directional 2\"\nmsgstr \"方向2\"\n\nmsgid \"Directional 3\"\nmsgstr \"方向3\"\n\nmsgid \"De-/Select Sliders\"\nmsgstr \"取消/选定滑块\"\n\nmsgid \"Fixed Weight Brush\"\nmsgstr \"固定权重（Fixed Weight）笔刷\"\n\nmsgid \"Preview Scaling\"\nmsgstr \"预览缩放\"\n\nmsgid \"Menu\"\nmsgstr \"菜单\"\n\nmsgid \"New Project...\\tCtrl+N\"\nmsgstr \"新建项目...\\tCtrl+N\"\n\nmsgid \"Create a new outfit project.\"\nmsgstr \"创建一个新的装备项目。\"\n\nmsgid \"Load Project..\\tCtrl+O\"\nmsgstr \"加载项目..\\\\tCtrl+O\"\n\nmsgid \"Load a project.\"\nmsgstr \"加载一个项目。\"\n\nmsgid \"Add Project..\\tCtrl+Shift+O\"\nmsgstr \"添加项目... Ctrl+Shift+O\"\n\nmsgid \"Add a project without replacing the current one.\"\nmsgstr \"在不替换当前项目的情况下添加项目。\"\n\nmsgid \"Load Reference...\"\nmsgstr \"加载参照...\"\n\nmsgid \"\"\n\"Load a new reference slider set, replacing any current reference objects.\"\nmsgstr \"加载一个新的参考滑块集，取代任何当前的参考项目。\"\n\nmsgid \"Load Outfit...\"\nmsgstr \"加载服装...\"\n\nmsgid \"\"\n\"Load a NIF file as the working outfit, replacing any current outfit objects.\"\nmsgstr \"加载一个NIF文件作为工作装备，替换任何当前的装备对象。\"\n\nmsgid \"\"\n\"Disable for a different way of loading NIF files to see if that puts it into \"\n\"the right (or a better) spot.\"\nmsgstr \"\"\n\"禁用以采用不同的方式加载NIF文件，以查看是否能把它放入正确（或更好）的场景。\"\n\nmsgid \"Save Project\\tCtrl+S\"\nmsgstr \"保存项目\\tCtrl+S\"\n\nmsgid \"Save the project.\"\nmsgstr \"保存项目。\"\n\nmsgid \"Save Project As...\\tCtrl+Shift+S\"\nmsgstr \"另存项目为\\tCtrl+Shift+S\"\n\nmsgid \"Save the project under a new name.\"\nmsgstr \"以新的名称保存此项目。\"\n\nmsgid \"Import\"\nmsgstr \"导入\"\n\nmsgid \"From NIF...\"\nmsgstr \"从NIF...\"\n\nmsgid \"Choose a NIF file to import into the project.\"\nmsgstr \"选择一个NIF文件来导入到项目中。\"\n\nmsgid \"Import Data\"\nmsgstr \"导入数据\"\n\nmsgid \"Import BSClothExtraData From HKX\"\nmsgstr \"从HKX导入BSClothExtraData\"\n\nmsgid \"\"\n\"Choose an HKX file to import as a BSClothExtraData block into the project.\"\nmsgstr \"选择一个HKX文件作为BSClothExtraData块导入到项目中。\"\n\nmsgid \"Export\"\nmsgstr \"导出\"\n\nmsgid \"Save the current project as a NIF file (without reference)\"\nmsgstr \"将当前项目保存为NIF文件（不带参照）\"\n\nmsgid \"To NIF With Reference...\"\nmsgstr \"到带参照的NIF...\"\n\nmsgid \"Save the current project as a NIF file (including reference)\"\nmsgstr \"将当前项目保存为NIF文件（包含参照）\"\n\nmsgid \"Export Data\"\nmsgstr \"导出数据\"\n\nmsgid \"Export BSClothExtraData As HKX\"\nmsgstr \"导出BSClothExtraData为HKX\"\n\nmsgid \"\"\n\"Save one of the currently loaded BSClothExtraData blocks to an HKX file.\"\nmsgstr \"保存一个当前已加载的BSClothExtraData块为HKX文件。\"\n\nmsgid \"Make Conversion Reference\"\nmsgstr \"制作转换参照\"\n\nmsgid \"\"\n\"Using the current slider settings for the reference shape, create a new \"\n\"reference that will morph from the current shape back to the base shape.\"\nmsgstr \"\"\n\"在参照模型的基础上使用当前滑块集，创建一个可以从当前模型变回基础模型的新参\"\n\"照。\"\n\nmsgid \"Exit\\tAlt+F4\"\nmsgstr \"退出\\tAlt+F4\"\n\nmsgid \"Exit Outfit Studio.\"\nmsgstr \"退出Outfit Studio。\"\n\nmsgid \"Edit\"\nmsgstr \"编辑\"\n\nmsgid \"Undo\\tCtrl+Z\"\nmsgstr \"撤销\\tCtrl+Z\"\n\nmsgid \"Undo the previous action.\"\nmsgstr \"撤消上一个动作。\"\n\nmsgid \"Redo\\tCtrl+Y\"\nmsgstr \"重做\\tCtrl+Y\"\n\nmsgid \"Redo the next undone action.\"\nmsgstr \"重做下一个被撤销的操作。\"\n\nmsgid \"X Mirror\\tX\"\nmsgstr \"X镜像\\tX\"\n\nmsgid \"Mirror edits across the X axis.\"\nmsgstr \"在X轴上镜像编辑。\"\n\nmsgid \"Edit Connected Only\\tC\"\nmsgstr \"仅编辑相连的顶点\\tC\"\n\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius\"\nmsgstr \"仅编辑笔刷半径内相连的顶点\"\n\nmsgid \"Global Brush Collision\\tB\"\nmsgstr \"全局笔刷处理（Collision）\\tB\"\n\nmsgid \"\"\n\"Allows for the brushes to collide with all currently selected meshes at the \"\n\"same time\"\nmsgstr \"允许画笔在同一时间处理所有当前被选网格\"\n\nmsgid \"Recalculate Normals\\tR\"\nmsgstr \"重新计算法线\\tR\"\n\nmsgid \"Recalculate normals on active mesh\"\nmsgstr \"在激活的网格上重新计算法线\"\n\nmsgid \"View\"\nmsgstr \"视图\"\n\nmsgid \"Front\\tShift+1\"\nmsgstr \"前\\tShift+1\"\n\nmsgid \"Back\\tShift+2\"\nmsgstr \"后\\tShift+2\"\n\nmsgid \"Left\\tShift+3\"\nmsgstr \"左\\tShift+3\"\n\nmsgid \"Right\\tShift+4\"\nmsgstr \"右\\tShift+4\"\n\nmsgid \"Perspective\\tShift+5\"\nmsgstr \"透视\\tShift+5\"\n\nmsgid \"Toggle Ghost Mode\\tG\"\nmsgstr \"幽灵模式开关\\tG\"\n\nmsgid \"Show the active mesh in translucent mode.\"\nmsgstr \"以半透明模式显示被选网格。\"\n\nmsgid \"Show Wireframe\\tW\"\nmsgstr \"显示线框\\tW\"\n\nmsgid \"Show wireframe on all models.\"\nmsgstr \"显示所有模型上的线框。\"\n\nmsgid \"Enable Lighting\\tL\"\nmsgstr \"启用照明\\tL\"\n\nmsgid \"Turn on or off lighting.\"\nmsgstr \"开启或关闭照明。\"\n\nmsgid \"Enable Textures\\tT\"\nmsgstr \"启用材质\\tT\"\n\nmsgid \"Display texture maps on models.\"\nmsgstr \"显示模型上的材质贴图。\"\n\nmsgid \"Shape\"\nmsgstr \"模型\"\n\nmsgid \"From OBJ...\"\nmsgstr \"从OBJ...\"\n\nmsgid \"Import an OBJ file as a new shape in the outfit.\"\nmsgstr \"导入一个OBJ文件作为装备上的新模型。\"\n\nmsgid \"From FBX...\"\nmsgstr \"从FBX...\"\n\nmsgid \"Import an FBX file as a new shape in the outfit.\"\nmsgstr \"从FBX文件中导入一个新模型插入装备。\"\n\nmsgid \"To NIF...\"\nmsgstr \"到NIF...\"\n\nmsgid \"Export only the selected shapes to a NIF file.\"\nmsgstr \"只将被选模型导出到NIF文件。\"\n\nmsgid \"Export selected shapes to NIF\"\nmsgstr \"将被选模型导出到NIF\"\n\nmsgid \"Failed to export selected shapes to NIF file!\"\nmsgstr \"未能将被选模型导出到NIF文件！\"\n\nmsgid \"To OBJ...\"\nmsgstr \"到OBJ...\"\n\nmsgid \"Export the current project as an OBJ file.\"\nmsgstr \"将当前项目作为OBJ文件导出。\"\n\nmsgid \"To FBX...\"\nmsgstr \"到FBX...\"\n\nmsgid \"Export only the selected shapes to an FBX file.\"\nmsgstr \"仅将被选模型导出到FBX文件。\"\n\nmsgid \"UV\"\nmsgstr \"UV\"\n\nmsgid \"Invert X\"\nmsgstr \"反转X轴\"\n\nmsgid \"Inverts the X-axis of the texture coordinates.\"\nmsgstr \"反转材质坐标的X轴。\"\n\nmsgid \"Invert Y\"\nmsgstr \"反转Y轴\"\n\nmsgid \"Inverts the Y-axis of the texture coordinates.\"\nmsgstr \"反转材质坐标的Y轴。\"\n\nmsgid \"Mirror\"\nmsgstr \"镜像\"\n\nmsgid \"Mirror the selected shapes on the X-axis.\"\nmsgstr \"在X轴上镜像被选形状。\"\n\nmsgid \"Mirror the selected shapes on the Y-axis.\"\nmsgstr \"在Y轴上镜像被选形状。\"\n\nmsgid \"Mirror the selected shapes on the Z-axis.\"\nmsgstr \"在Z轴上镜像被选形状。\"\n\nmsgid \"Duplicate...\"\nmsgstr \"复制...\"\n\nmsgid \"Duplicate the current shape.\"\nmsgstr \"复制当前模型。\"\n\nmsgid \"Rename...\\tF2\"\nmsgstr \"重命名... \\tF2\"\n\nmsgid \"Change the name of the current shape.\"\nmsgstr \"更改当前模型的名称。\"\n\nmsgid \"Set Reference\"\nmsgstr \"设置参照\"\n\nmsgid \"Turn the shape into the reference shape of the project.\"\nmsgstr \"将此模型转化为项目的参照模型。\"\n\nmsgid \"Move...\"\nmsgstr \"移动...\"\n\nmsgid \"\"\n\"Apply an offset adjustment to the mesh vertices. This permanently moves \"\n\"vertices.\"\nmsgstr \"对网格顶点调偏（Apply an offset adjustment)。这将永久移动顶点。\"\n\nmsgid \"Scale...\"\nmsgstr \"缩放...\"\n\nmsgid \"Apply a scale adjustment to the shape. This permanently moves vertices.\"\nmsgstr \"对模型使用缩放调节。这将永久移动顶点。\"\n\nmsgid \"Rotate...\"\nmsgstr \"旋转...\"\n\nmsgid \"Apply a rotation to the mesh vertices. This permanently moves vertices.\"\nmsgstr \"旋转网格顶点。这将永久移动顶点。\"\n\nmsgid \"Smooth Seam Normals\"\nmsgstr \"平滑接缝法线\"\n\nmsgid \"\"\n\"Smooths edges of seams (usually found at texture borders), disable if this \"\n\"causes odd normals on the shape.\"\nmsgstr \"平滑接缝处的边缘（常见于材质边界），若引起模型法线异常请禁用此选项。\"\n\nmsgid \"Lock Normals\"\nmsgstr \"锁定法线\"\n\nmsgid \"\"\n\"Locks the mesh normals. Enable if you want to keep custom normals intact.\"\nmsgstr \"锁定网格法线。在希望自定义法线原封不动时启用。\"\n\nmsgid \"Copy Bone Weights\"\nmsgstr \"复制骨骼权重\"\n\nmsgid \"Copies all bone weights from the reference shape to the current shape.\"\nmsgstr \"将参照模型中的所有骨骼权重复制到到当前模型。\"\n\nmsgid \"Copy Selected Weights\"\nmsgstr \"复制被选权重\"\n\nmsgid \"\"\n\"Copies selected bone weights from the reference shape to the current shape.\"\nmsgstr \"从参照模型复制被选骨骼权重到当前模型。\"\n\nmsgid \"Transfer Selected Weights\"\nmsgstr \"转移被选权重\"\n\nmsgid \"\"\n\"Transfers selected weights from the reference shape to the current shape. \"\n\"Requires same vertex count and order.\"\nmsgstr \"将被选权重从参照模型转移到当前模型。需要相同的顶点数和顺序。\"\n\nmsgid \"Mask Weighted Vertices\"\nmsgstr \"遮罩权重顶点\"\n\nmsgid \"\"\n\"Masks vertices with bone weights, so you can manually assign weights to \"\n\"unweighted vertices.\"\nmsgstr \"遮罩有骨骼权重的顶点，方便手动处理无权重的顶点。\"\n\nmsgid \"Delete\\tDel\"\nmsgstr \"删除\\tDel\"\n\nmsgid \"Removes the currently selected shape from the outfit.\"\nmsgstr \"从装备中删除当前被选模型。\"\n\nmsgid \"Properties...\"\nmsgstr \"属性...\"\n\nmsgid \"\"\n\"Opens the properties dialog for shader, texture and more settings of the \"\n\"selected shape.\"\nmsgstr \"打开被选模型的着色器、材质等设置的属性对话框。\"\n\nmsgid \"Slider\"\nmsgstr \"滑块\"\n\nmsgid \"Conform Selected\\tCtrl+C\"\nmsgstr \"应用被选\\tCtrl+C\"\n\nmsgid \"Conform selected outfit shape to all checked sliders.\"\nmsgstr \"将被选滑块应用到被选装备模型中。\"\n\nmsgid \"Conform All\\tCtrl+Shift+C\"\nmsgstr \"应用所有滑块\\tCtrl+Shift+C\"\n\nmsgid \"Conform all outfit shapes to all checked sliders.\"\nmsgstr \"将所有被选滑块应用到所有装备模型中。\"\n\nmsgid \"Set Base Shape\"\nmsgstr \"设置基础模型\"\n\nmsgid \"Set the current outfit shape as the base shape and clear slider data.\"\nmsgstr \"设置当前装备模型为基础模型，并清除滑块数据。\"\n\nmsgid \"Load Preset...\"\nmsgstr \"加载预设...\"\n\nmsgid \"\"\n\"Load and preview a slider preset. Inverted sliders will have inverted values.\"\nmsgstr \"加载并预览一个滑块预设。反转滑块的值是相反的。\"\n\nmsgid \"Save Preset...\"\nmsgstr \"保存预设...\"\n\nmsgid \"\"\n\"Save a slider preset with the current values. Inverted sliders will have \"\n\"inverted values.\"\nmsgstr \"保存当前值为滑块预设。反转滑块的值是相反的。\"\n\nmsgid \"New Slider\"\nmsgstr \"新建滑块\"\n\nmsgid \"Create a new shape transformation slider.\"\nmsgstr \"创建一个新的模型转换滑块。\"\n\nmsgid \"Coalesce sliders\"\nmsgstr \"合并滑块\"\n\nmsgid \"\"\n\"Create a new shape transformation slider based on the current slider values\"\nmsgstr \"创建一个基于当前滑块值的新模型转换滑块\"\n\nmsgid \"New Zap Slider\"\nmsgstr \"新建修正滑块\"\n\nmsgid \"Create a new Zap slider based on unmasked vertices\"\nmsgstr \"创建一个基于未遮罩顶点的新修正滑块\"\n\nmsgid \"Import OSD...\"\nmsgstr \"导入OSD...\"\n\nmsgid \"Imports OSD file and creates sliders for shapes with a matching name.\"\nmsgstr \"导入OSD文件并为具有匹配名称的模型创建滑块。\"\n\nmsgid \"Export OSD...\"\nmsgstr \"导出OSD...\"\n\nmsgid \"Exports all currently loaded slider data to an OSD file.\"\nmsgstr \"将所有当前已加载的滑块数据导出到OSD文件。\"\n\nmsgid \"Import TRI Morphs...\"\nmsgstr \"导入TRI变形...\"\n\nmsgid \"\"\n\"Imports TRI morphs from a TRI file and creates sliders for shapes with a \"\n\"matching name.\"\nmsgstr \"从TRI文件中导入TRI变形，并为具有匹配名称的模型创建滑块。\"\n\nmsgid \"Export TRI Morphs...\"\nmsgstr \"导出TRI变形...\"\n\nmsgid \"Exports TRI morphs to a TRI file.\"\nmsgstr \"导出TRI变形到TRI文件。\"\n\nmsgid \"Import Slider Data\"\nmsgstr \"导入滑块数据\"\n\nmsgid \"Import BSD...\"\nmsgstr \"导入BSD...\"\n\nmsgid \"\"\n\"Import a BodySlide BSD file and overwrites the current shape's slider data.\"\nmsgstr \"导入一个bodyslide BSD文件，并覆盖当前模型的滑块数据。\"\n\nmsgid \"Import OBJ...\"\nmsgstr \"导入OBJ文件...\"\n\nmsgid \"\"\n\"Import an OBJ file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"导入一个与当前模型顶点数匹配的OBJ文件，并根据差值计算滑块数据。\"\n\nmsgid \"Import FBX...\"\nmsgstr \"导入FBX文件...\"\n\nmsgid \"\"\n\"Import an FBX file matching the current shape's vertex count, and calculate \"\n\"slider data from the difference.\"\nmsgstr \"导入一个与当前模型顶点数匹配的FBX文件，并根据差值计算滑块数据。\"\n\nmsgid \"Export Slider Data\"\nmsgstr \"导出滑块数据\"\n\nmsgid \"Export BSD...\"\nmsgstr \"导出BSD...\"\n\nmsgid \"Exports the current slider's data as a BodySlide BSD file.\"\nmsgstr \"将当前滑块数据作为BSD文件导出。\"\n\nmsgid \"Export OBJ...\"\nmsgstr \"导出OBJ...\"\n\nmsgid \"Export only the selected shapes to an OBJ file.\"\nmsgstr \"只将被选模型导出到OBJ文件。\"\n\nmsgid \"Negate Slider\"\nmsgstr \"无效化滑块\"\n\nmsgid \"Negates the current slider, reversing it's effect\"\nmsgstr \"无效化当前滑块，逆转其效果\"\n\nmsgid \"Mask Affected Vertices\"\nmsgstr \"遮罩受影响顶点\"\n\nmsgid \"Masks the vertices the slider is affecting for all selected shapes.\"\nmsgstr \"为所有被选模型遮罩受滑块影响的顶点。\"\n\nmsgid \"Clear Slider Data\"\nmsgstr \"清除滑块数据\"\n\nmsgid \"\"\n\"Erases the slider data without removing the slider itself. (Cannot be undone)\"\nmsgstr \"清除滑块数据而不删除滑块。（无法撤销）\"\n\nmsgid \"Delete Slider\"\nmsgstr \"删除滑块\"\n\nmsgid \"Delete the active slider from the project. (Cannot be undone)\"\nmsgstr \"从项目中删除被选滑块。（无法撤销）\"\n\nmsgid \"Properties...\\tTab\"\nmsgstr \"属性...\\tTab\"\n\nmsgid \"Display and edit the active slider's properties.\"\nmsgstr \"显示和编辑已激活滑块的属性。\"\n\nmsgid \"Tool\"\nmsgstr \"工具\"\n\nmsgid \"Current Tool\"\nmsgstr \"当前工具\"\n\nmsgid \"Select\\t0\"\nmsgstr \"选择\\t0\"\n\nmsgid \"Navigate and select meshes (or vertices in vertex mode).\"\nmsgstr \"导航并选择网格（或顶点模式下的顶点）。\"\n\nmsgid \"Mask\\t1\"\nmsgstr \"遮罩\\t1\"\n\nmsgid \"\"\n\"Mask vertices to prevent them from being transformed.\\n\"\n\"Hold down the ALT key to remove masking.\"\nmsgstr \"\"\n\"遮罩顶点以防误操作。\\n\"\n\"按住ALT键移除遮罩。\"\n\nmsgid \"Inflate\\t2\"\nmsgstr \"放大\\t2\"\n\nmsgid \"Increase mesh volume in an area.\"\nmsgstr \"在一个区域放大网格。\"\n\nmsgid \"Deflate\\t3\"\nmsgstr \"缩小\\t3\"\n\nmsgid \"Decrease mesh volume in an area.\"\nmsgstr \"在一个区域缩小网格。\"\n\nmsgid \"Move\\t4\"\nmsgstr \"移动\\t4\"\n\nmsgid \"Move vertices over a plane parallel to the view.\"\nmsgstr \"在平行于视图的平面上移动顶点。\"\n\nmsgid \"Smooth\\t5\"\nmsgstr \"平滑\\t5\"\n\nmsgid \"Smooth an area of a mesh.\"\nmsgstr \"平滑一个区域的网格。\"\n\nmsgid \"Weight Paint\\t6\"\nmsgstr \"权重画笔\\t6\"\n\nmsgid \"\"\n\"Apply animation weight values for the currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"对当前被选骨骼应用动画权重值。\\n\"\n\"按住ALT键减弱权重。\"\n\nmsgid \"Transform\\tF\"\nmsgstr \"变换\\tF\"\n\nmsgid \"Shows a transform tool to manipulate shapes and vertices with.\"\nmsgstr \"显示变换工具来操作模型和顶点。\"\n\nmsgid \"Pivot\\tF\"\nmsgstr \"枢轴\\tF\"\n\nmsgid \"\"\n\"Shows a pivot that can be moved and makes it the center of mesh operations \"\n\"like rotation and scale.\"\nmsgstr \"显示可以移动的轴，并使其成为网格操作（如旋转和缩放）的中心。\"\n\nmsgid \"Vertex Edit\\tQ\"\nmsgstr \"顶点编辑\\tQ\"\n\nmsgid \"\"\n\"Lets you select vertices to add to or remove from the mask.\\n\"\n\"Click on a vertex to select/unmask it.\\n\"\n\"Hold down CTRL to unselect/mask it.\"\nmsgstr \"\"\n\"允许你添加或删除遮罩中选择顶点。\\n\"\n\"点击一个顶点来选择/取消遮罩它。\\n\"\n\"按住CTRL来取消选择/遮罩它。\"\n\nmsgid \"Increase Brush Size\\tShift++\"\nmsgstr \"增加笔刷尺寸\\tShift++\"\n\nmsgid \"Increase brush diameter\"\nmsgstr \"增加笔刷直径\"\n\nmsgid \"Decrease Brush Size\\tShift+-\"\nmsgstr \"减小笔刷尺寸\\tShift+-\"\n\nmsgid \"Decrease brush diameter\"\nmsgstr \"减小笔刷直径\"\n\nmsgid \"Increase Brush Strength\\tCtrl++\"\nmsgstr \"增加笔刷强度\\tCtrl++\"\n\nmsgid \"Increase brush strength\"\nmsgstr \"增加笔刷强度\"\n\nmsgid \"Decrease Brush Strength\\tCtrl+-\"\nmsgstr \"减小笔刷强度\\tCtrl+-\"\n\nmsgid \"Decrease brush strength\"\nmsgstr \"减小笔刷强度\"\n\nmsgid \"Mask Less\\tA\"\nmsgstr \"遮罩减少\\tA\"\n\nmsgid \"Mask Less\"\nmsgstr \"遮罩减少\"\n\nmsgid \"Mask More\\tD\"\nmsgstr \"遮罩增加\\tD\"\n\nmsgid \"Mask More\"\nmsgstr \"遮罩增加\"\n\nmsgid \"Invert Mask\\tCtrl+I\"\nmsgstr \"反转遮罩\\tCtrl+I\"\n\nmsgid \"Invert Mask\"\nmsgstr \"反转遮罩\"\n\nmsgid \"Clear Mask\\tCtrl+A\"\nmsgstr \"清除遮罩\\tCtrl+A\"\n\nmsgid \"Clear Mask\"\nmsgstr \"清除遮罩\"\n\nmsgid \"Show Mask\\tM\"\nmsgstr \"显示遮罩\\tM\"\n\nmsgid \"Shade meshes to indicate areas that are currently masked.\"\nmsgstr \"为网格添加阴影来指示当前已被遮罩的区域。\"\n\nmsgid \"New Project\"\nmsgstr \"新建项目\"\n\nmsgid \"\"\n\"Create a new project by selecting a reference body slider set, and outfit \"\n\"model files.\"\nmsgstr \"\"\n\"选择一个参照滑块集和装备模型文件以新建一个项目。（Create a new project by \"\n\"selecting a reference body slider set, and outfit model files.)\"\n\nmsgid \"Load Project\"\nmsgstr \"加载项目\"\n\nmsgid \"Load a previously created slider set for editing.\"\nmsgstr \"打开一个上次创建的滑块集来编辑。\"\n\nmsgid \"Select\"\nmsgstr \"选择\"\n\nmsgid \"Mask\"\nmsgstr \"遮罩\"\n\nmsgid \"Inflate\"\nmsgstr \"放大\"\n\nmsgid \"Deflate\"\nmsgstr \"缩小\"\n\nmsgid \"Move\"\nmsgstr \"移动\"\n\nmsgid \"Smooth\"\nmsgstr \"平滑\"\n\nmsgid \"Weight Paint\"\nmsgstr \"权重画笔\"\n\nmsgid \"\"\n\"Apply animation weight values for currently selected bone.\\n\"\n\"Hold down the ALT key to weaken the weighting.\"\nmsgstr \"\"\n\"对当前被选骨骼应用动画权重值。\\n\"\n\"按住ALT键减弱权重。\"\n\nmsgid \"Transform\"\nmsgstr \"变形\"\n\nmsgid \"Pivot\"\nmsgstr \"枢轴\"\n\nmsgid \"Vertex Edit\"\nmsgstr \"顶点编辑\"\n\nmsgid \"X Mirror\"\nmsgstr \"X镜像\"\n\nmsgid \"\"\n\"Edit only vertices that are connected to the ones under the brush within the \"\n\"brush radius.\"\nmsgstr \"仅编辑笔刷半径内相连的顶点。\"\n\nmsgid \"Global Brush Collision\\tC\"\nmsgstr \"全局笔刷\\tC\"\n\nmsgid \"\"\n\"Allows for the brushes to collide with all currently selected meshes at the \"\n\"same time.\"\nmsgstr \"允许笔刷同时处理所有被选模型。\"\n\nmsgid \"View Front\"\nmsgstr \"前视图\"\n\nmsgid \"Change camera view to the front.\"\nmsgstr \"改变相机视图到前方。\"\n\nmsgid \"View Back\"\nmsgstr \"后视图\"\n\nmsgid \"Change camera view to the back.\"\nmsgstr \"改变相机视图到后方。\"\n\nmsgid \"View Left\"\nmsgstr \"左视图\"\n\nmsgid \"Change camera view to the left.\"\nmsgstr \"改变相机视图到左方。\"\n\nmsgid \"View Right\"\nmsgstr \"右视图\"\n\nmsgid \"Change camera view to the right.\"\nmsgstr \"改变相机视图到右方。\"\n\nmsgid \"Perspective View\"\nmsgstr \"透视图\"\n\nmsgid \"Toggle perspective view.\"\nmsgstr \"开关透视图。\"\n\nmsgid \"Field of View\"\nmsgstr \"视野\"\n\nmsgid \"Field of View: 65\"\nmsgstr \"视野：65\"\n\nmsgid \"Move Shape\"\nmsgstr \"移动模型\"\n\nmsgid \"CBBE to Vanilla (old)\"\nmsgstr \"CBBE到原版（过时）\"\n\nmsgid \"Scale Shape\"\nmsgstr \"缩放模型\"\n\nmsgid \"\"\n\"Scaling will adjust the size of a mesh. This permanently affects vertices.\"\nmsgstr \"缩放会调整网格的尺寸。这将永久影响顶点。\"\n\nmsgid \"Scale\"\nmsgstr \"缩放\"\n\nmsgid \"Rotate Shape\"\nmsgstr \"旋转模型\"\n\nmsgid \"Apply a vertex position\"\nmsgstr \"应用顶点位置\"\n\nmsgid \"This permanently moves a single vertex straight to the given location.\"\nmsgstr \"这会直接将顶点移动到给定的位置。\"\n\nmsgid \"\"\n\"Welcome to the New Project wizard!\\n\"\n\"\\n\"\n\"First, please choose a reference. Typically, this is a body (such as CBBE) \"\n\"or a conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"欢迎使用新项目向导！\\n\"\n\"\\n\"\n\"首先，请选择一个参照。一般来说，这是一个身形（比如CBBE）或者一个转换设置（比\"\n\"如原版到 CBBE），并且附带其滑块。\"\n\nmsgid \"Reference\"\nmsgstr \"参照\"\n\nmsgid \"From Template\"\nmsgstr \"从模板\"\n\nmsgid \"From File\"\nmsgstr \"从文件\"\n\nmsgid \"Select a project or NIF file\"\nmsgstr \"选择一个项目或NIF文件\"\n\nmsgid \"Slider Set:\"\nmsgstr \"滑块集：\"\n\nmsgid \"Shape:\"\nmsgstr \"模型：\"\n\nmsgid \"Clear Reference\"\nmsgstr \"清除参照\"\n\nmsgid \"Next, select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"然后，选择一个要处理的装备/网格，并输入它的显示名称。\"\n\nmsgid \"Display Name\"\nmsgstr \"显示名称\"\n\nmsgid \"New Outfit\"\nmsgstr \"新装备\"\n\nmsgid \"Outfit/Mesh\"\nmsgstr \"装备/网格\"\n\nmsgid \"Select a file to load as an outfit/mesh\"\nmsgstr \"选择一个文件作为装备/网格加载 。\"\n\nmsgid \"Clear Outfit\"\nmsgstr \"清除装备\"\n\nmsgid \"Textures\"\nmsgstr \"材质\"\n\nmsgid \"Automatically search for textures\"\nmsgstr \"自动搜索材质\"\n\nmsgid \"Select a texture file\"\nmsgstr \"选择一个材质文件\"\n\nmsgid \"Select a slider preset\"\nmsgstr \"选择一个滑块预设\"\n\nmsgid \"Choose a preset:\"\nmsgstr \"选择一个预设：\"\n\nmsgid \"Low weight\"\nmsgstr \"最小重量\"\n\nmsgid \"High weight\"\nmsgstr \"最大重量\"\n\nmsgid \"Set Shape Textures\"\nmsgstr \"设置模型材质\"\n\nmsgid \"Display Texture:\"\nmsgstr \"显示材质：\"\n\nmsgid \"\"\n\"Applies the current diffuse texture path to the Outfit Studio display \"\n\"texture path.\"\nmsgstr \"将当前漫反射材质的路径应用到Outfit Studio显示材质的路径。\"\n\nmsgid \"Apply Diffuse\"\nmsgstr \"应用漫反射\"\n\nmsgid \"Load Reference\"\nmsgstr \"加载参照\"\n\nmsgid \"\"\n\"Please choose a reference. Typically, this is a body (such as CBBE) or a \"\n\"conversion set (such as Vanilla To CBBE) and comes with its sliders.\"\nmsgstr \"\"\n\"请选择一个参照。一般来说，这是一个身形（比如CBBE）或者一个转换设置（比如原版\"\n\"到 CBBE），并附带其滑块。\"\n\nmsgid \"Merge new sliders with existing sliders\"\nmsgstr \"将新滑块集与现有滑块集合并\"\n\nmsgid \"Load Outfit\"\nmsgstr \"加载装备\"\n\nmsgid \"\"\n\"Please select an outfit/mesh to work on and enter a display name for it.\"\nmsgstr \"请选择一个要处理的装备/模型，并输入它的显示名称。\"\n\nmsgid \"Keep other shapes\"\nmsgstr \"保留其他模型\"\n\nmsgid \"Add\"\nmsgstr \"增加\"\n\nmsgid \"Delete\"\nmsgstr \"删除\"\n\nmsgid \"From Project\"\nmsgstr \"从项目\"\n\nmsgid \"Delete bone(s) from all shapes of the project.\"\nmsgstr \"删除项目中所有模型的骨骼。\"\n\nmsgid \"From Selected Shapes\"\nmsgstr \"从被选模型\"\n\nmsgid \"Delete bone(s) from only the selected shapes.\"\nmsgstr \"删除项目中被选模型的骨骼。\"\n\nmsgid \"From Skeleton...\"\nmsgstr \"从骨架...\"\n\nmsgid \"Choose a bone from the reference skeleton to add to the project.\"\nmsgstr \"从参照骨架中选择一个骨骼添加到项目。\"\n\nmsgid \"Custom Bone...\"\nmsgstr \"自定义骨骼...\"\n\nmsgid \"Add a custom bone to the project.\"\nmsgstr \"将一个自定义骨骼添加到项目。\"\n\nmsgid \"Select a bone to add\"\nmsgstr \"选择一个骨骼来添加\"\n\nmsgid \"Bones in the current reference skeleton:\"\nmsgstr \"当前参考骨架中的骨骼：\"\n\nmsgid \"Add Custom Bone\"\nmsgstr \"添加自定义骨骼\"\n\nmsgid \"Name\"\nmsgstr \"名字\"\n\nmsgid \"Slider Properties\"\nmsgstr \"滑块属性\"\n\nmsgid \"Slider Name\"\nmsgstr \"滑块名称\"\n\nmsgid \"Default Values\"\nmsgstr \"默认值\"\n\nmsgid \"Low\"\nmsgstr \"最小\"\n\nmsgid \"High\"\nmsgstr \"最大\"\n\nmsgid \"Zapped\"\nmsgstr \"旋转一圈（Zapped）\"\n\nmsgid \"Options\"\nmsgstr \"选项\"\n\nmsgid \"Invert\"\nmsgstr \"反转\"\n\nmsgid \"Hidden\"\nmsgstr \"隐藏\"\n\nmsgid \"Zap\"\nmsgstr \"修正\"\n\nmsgid \"Save Project As...\"\nmsgstr \"将项目保存为...\"\n\nmsgid \"The name of the outfit and slider set, as it will appear in BodySlide.\"\nmsgstr \"装备和滑块集的名称，它也会在BodySlide中显示。\"\n\nmsgid \"Copies the current display name to the project text fields below.\"\nmsgstr \"将当前显示名称复制到下面的项目文本字段。\"\n\nmsgid \"To Project\"\nmsgstr \"到项目\"\n\nmsgid \"Output File Name\"\nmsgstr \"输出文件名称\"\n\nmsgid \"\"\n\"The name of the outfit file that will end up in the game data path when \"\n\"BodySlide builds it. Should not include _1 or _0 in the name, e.g: \"\n\"lovelydress\"\nmsgstr \"\"\n\"Bodyslide建立装备时，装备文件最终会出现在游戏数据路径的名称。不要在名称里包含\"\n\"_1或_0，例如：lovelydress\"\n\nmsgid \"_0/_1.nif\"\nmsgstr \"_0/_1.nif\"\n\nmsgid \"Output Data Path\"\nmsgstr \"输出数据路径\"\n\nmsgid \"\"\n\"The location in the game's data path where BodySlide-built outfit files will \"\n\"be placed, e.g: meshes\\\\clothes\\\\lovelydress\"\nmsgstr \"\"\n\"BodySlide创建的装备文件将被放置于游戏数据路径中的位置，例如：\"\n\"meshes\\\\clothes\\\\lovelydress\"\n\nmsgid \"\"\n\"If this is enabled, BodySlide creates a low and high weight model when it \"\n\"generates the final outfit.\"\nmsgstr \"\"\n\"若启用此项，当Bodyslide生成最终装备时，将会创建最小重量和最大重量的模型文件。\"\n\nmsgid \"Low/High Weight Output\"\nmsgstr \"最小/最大重量输出\"\n\nmsgid \"\"\n\"If this is enabled, only one output file will be created (useful for single-\"\n\"weighted things like hair).\"\nmsgstr \"\"\n\"若启用此项，只会创建一个输出文件（对于像头发这样的单一权重的东西很有用）。\"\n\nmsgid \"Single Weight Output\"\nmsgstr \"单重量输出\"\n\nmsgid \"Project\"\nmsgstr \"项目\"\n\nmsgid \"Slider Set File\"\nmsgstr \"滑块集文件\"\n\nmsgid \"The .osp slider set project file\"\nmsgstr \".osp滑块集项目文件\"\n\nmsgid \"Select slider set .osp file name\"\nmsgstr \"选择滑块集.osp文件名称\"\n\nmsgid \"Shape Data Folder\"\nmsgstr \"模型数据文件夹\"\n\nmsgid \"\"\n\"The folder where all the slider data will go, as well as the base outfit NIF \"\n\"file.\"\nmsgstr \"所有滑块数据和基础装备NIF文件存放的位置。\"\n\nmsgid \"Select slider data folder\"\nmsgstr \"选择滑块数据文件夹\"\n\nmsgid \"Shape Data File\"\nmsgstr \"模型数据文件\"\n\nmsgid \"The name of the output's base NIF file.\"\nmsgstr \"输出端的NIF基础文件的名称。\"\n\nmsgid \"Select output NIF file name\"\nmsgstr \"选择输出端NIF文件名称\"\n\nmsgid \"\"\n\"Outfits require the reference body to be a part of the output file. Disable \"\n\"this if you've already copied the reference over or you don't want it \"\n\"included.\"\nmsgstr \"\"\n\"装备需要参照身体作为输出文件的一部分。若你已复制了参照或者你不希望它包含在\"\n\"内，请禁用此选项，。\"\n\nmsgid \"Copy reference shape into output\"\nmsgstr \"将参照模型复制到输出端\"\n\nmsgid \"Shape Properties\"\nmsgstr \"模型属性\"\n\nmsgid \"Material\"\nmsgstr \"材料\"\n\nmsgid \"Choose material file\"\nmsgstr \"选择材料文件\"\n\nmsgid \"Shader\"\nmsgstr \"着色器\"\n\nmsgid \"Type\"\nmsgstr \"类型\"\n\nmsgid \"Specular Color\"\nmsgstr \"高光颜色\"\n\nmsgid \"Specular Strength\"\nmsgstr \"高光大小\"\n\nmsgid \"Specular Power\"\nmsgstr \"高光强度\"\n\nmsgid \"Emissive Color\"\nmsgstr \"自发光颜色\"\n\nmsgid \"Emissive Multiple\"\nmsgstr \"自发光倍数\"\n\nmsgid \"Remove\"\nmsgstr \"移除\"\n\nmsgid \"Textures...\"\nmsgstr \"材质...\"\n\nmsgid \"Transparency\"\nmsgstr \"透明度\"\n\nmsgid \"Threshold\"\nmsgstr \"临界值\"\n\nmsgid \"Geometry\"\nmsgstr \"几何结构\"\n\nmsgid \"Full Precision\"\nmsgstr \"全精度\"\n\nmsgid \"Sub Index\"\nmsgstr \"子索引\"\n\nmsgid \"Extra Data\"\nmsgstr \"附加数据\"\n\nmsgid \"Value\"\nmsgstr \"值\"\n\nmsgid \"Segments\"\nmsgstr \"段数\"\n\nmsgid \"Apply\"\nmsgstr \"应用\"\n\nmsgid \"SSF File\"\nmsgstr \"SSF文件\"\n\nmsgid \"Partitions\"\nmsgstr \"分区\"\n\nmsgid \"Add Partition...\"\nmsgstr \"添加分区...\"\n\nmsgid \"Adds a new partition to the shape.\"\nmsgstr \"将新分区添加到模型。\"\n\nmsgid \"Delete Partition...\"\nmsgstr \"删除分区...\"\n\nmsgid \"Deletes the partition from the shape.\"\nmsgstr \"从模型中删除分区。\"\n\nmsgid \"FBX Import Options...\"\nmsgstr \"FBX导入选项...\"\n\nmsgid \"Invert U\"\nmsgstr \"反转U（轴）\"\n\nmsgid \"Invert V\"\nmsgstr \"反转V（轴）\"\n\nmsgid \"Toggle:\"\nmsgstr \"切换：\"\n\nmsgid \"Search Radius\"\nmsgstr \"搜索半径\"\n\nmsgid \"Max Vertex Targets\"\nmsgstr \"最大顶点目标\"\n\nmsgid \"\"\n\"Each vertex of the reference will copy its weights to the nearest collection \"\n\"of vertices within the given radius. Bear in mind that some geometry will \"\n\"always require manual tweaking to become weighted and work well. Often, the \"\n\"default values are sufficient.\"\nmsgstr \"\"\n\"参照中的每个顶点将会复制它的权重到给定半径内最近的顶点集合。要牢记一些几何结\"\n\"构将总是需要手动调整来权重化和更好的工作。默认值通常是足够的。\"\n\nmsgid \"\"\n\"Bone information incomplete. Exported data will not contain correct bone \"\n\"entries! Be sure to load a reference NIF prior to export.\"\nmsgstr \"\"\n\"骨骼信息不完整。导出数据将不包含正确的骨骼条目！确保在导出之前加载一个参照\"\n\"NIF。\"\n\nmsgid \"Export Warning\"\nmsgstr \"导出警告\"\n\nmsgid \"Failed to load skeleton '%s'!\"\nmsgstr \"未能加载骨架'%s'！\"\n\nmsgid \"Root '%s' not found in skeleton '%s'!\"\nmsgstr \"根'%s'未在骨架'%s'中找到！\"\n\nmsgid \"\"\n\"No read/write permission for game data path!\\n\"\n\"\\n\"\n\"Please launch the program with admin elevation and make sure the game data \"\n\"path in the settings is correct.\"\nmsgstr \"\"\n\"没有游戏数据路径的读/写权限！\\n\"\n\"\\n\"\n\"请使用管理员权限启动程序，并确保游戏数据路径的设置是正确的。\"\n\nmsgid \"Warning\"\nmsgstr \"警告\"\n\nmsgid \"Unexpected exception has occurred: %s, the program will terminate.\"\nmsgstr \"发生了意外的异常：%s，程序将终止。\"\n\nmsgid \"Unexpected exception\"\nmsgstr \"意外的异常\"\n\nmsgid \"Unhandled exception has occurred: %s, the program will terminate.\"\nmsgstr \"发生了未处理的异常：%s，程序将终止。\"\n\nmsgid \"Unhandled exception\"\nmsgstr \"未处理的异常\"\n\nmsgid \"Fatal exception has occurred, the program will terminate.\"\nmsgstr \"发生了致命的异常，程序将终止。\"\n\nmsgid \"Fatal exception\"\nmsgstr \"致命异常\"\n\nmsgid \"\"\n\"Failed to find game install path registry value or GameDataPath in the \"\n\"config.\"\nmsgstr \"未能在配置中找到游戏安装路径的注册表值或GameDataPath。\"\n\nmsgid \"\"\n\"Failed to find game install path registry key or GameDataPath in the config.\"\nmsgstr \"未能在配置中找到游戏安装路径的注册表项或游戏数据路径。\"\n\nmsgid \"System language '%d' is wrong.\"\nmsgstr \"系统语言'%d'是错误的。\"\n\nmsgid \"\"\n\"The system language '%d' is not supported by your system. Try installing \"\n\"support for this language.\"\nmsgstr \"系统语言'%d'不支持你的系统。试着为这种语言安装支持。\"\n\nmsgid \"Failed to create group file.\"\nmsgstr \"未能创建组文件。\"\n\nmsgid \"\"\n\"That group already exists in the specified file, do you wish to overwrite \"\n\"the group?\"\nmsgstr \"该组已经在指定的文件中存在，你想覆盖此组吗？\"\n\nmsgid \"Group already exists\"\nmsgstr \"组已存在\"\n\nmsgid \"\"\n\"WARNING: Game data path not configured. Would you like to show BodySlide \"\n\"where it is?\"\nmsgstr \"警告：游戏数据路径未配置。你要告诉BodySlide它在哪儿吗？\"\n\nmsgid \"Game not found\"\nmsgstr \"未发现游戏\"\n\nmsgid \"Please choose a directory to set as your Data path\"\nmsgstr \"请选择一个目录来设置为你的数据路径\"\n\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folder, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"警告：这将从输出文件夹中删除输出文件，可能会导致崩溃。\\n\"\n\"\\n\"\n\"你想要继续吗？\"\n\nmsgid \"Clean Build\"\nmsgstr \"清除建立\"\n\nmsgid \"Removed the following files:\\n\"\nmsgstr \"移除以下文件：\\n\"\n\nmsgid \" (no action)\\n\"\nmsgstr \"（无操作）\\n\"\n\nmsgid \"Process Successful\"\nmsgstr \"步骤成功\"\n\nmsgid \"\"\n\"Failed to write TRI file to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"未能将TRI文件写入以下位置\\n\"\n\"\\n\"\n\"%s\"\n\nmsgid \"Unable to process\"\nmsgstr \"无法处理\"\n\nmsgid \"\"\n\"Failed to build set to the following location\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"未能将设置建立到以下的位置\\n\"\n\"\\n\"\n\"%s\"\n\nmsgid \"Choose alternate file name\"\nmsgstr \"选择可选（alternate)文件名\"\n\nmsgid \"Successfully processed the following files:\\n\"\nmsgstr \"成功处理以下文件：\\n\"\n\nmsgid \"\"\n\"WARNING: This will delete the output files from the output folders, \"\n\"potentially causing crashes.\\n\"\n\"\\n\"\n\"Do you want to continue?\"\nmsgstr \"\"\n\"警告：这将从输出文件夹删除（各）输出文件，可能会导致崩溃。\\n\"\n\"\\n\"\n\"你想要继续吗？\"\n\nmsgid \"Clean Batch Build\"\nmsgstr \"清除批量建立\"\n\nmsgid \"\"\n\"WARNING: Game data path not configured. Files can't be removed that way.\"\nmsgstr \"警告：游戏数据路径未配置。这样文件就不能被删除。\"\n\nmsgid \"\"\n\"WARNING: Game data path not configured. Continue saving files to the working \"\n\"directory?\"\nmsgstr \"警告：游戏数据路径未配置。继续保存文件到工作目录吗？\"\n\nmsgid \"\"\n\"The following sets will override the same files.\\n\"\n\"Please decide which one to use and select it in the list below.\"\nmsgstr \"\"\n\"以下设置将覆盖相同的文件。\\n\"\n\"请决定使用哪一个，并在下面的列表中选择它。\"\n\nmsgid \"Choose output set\"\nmsgstr \"选择输出设置\"\n\nmsgid \"Processing Outfits\"\nmsgstr \"处理装备\"\n\nmsgid \"Starting...\"\nmsgstr \"正在开始...\"\n\nmsgid \"Processing '%s' (%d of %d)...\"\nmsgstr \"处理'%s'（%d的%d）中...\"\n\nmsgid \"No recorded outfit name source\"\nmsgstr \"没有记录的装备名称来源\"\n\nmsgid \"Unable to get slider set from file: \"\nmsgstr \"无法从文件得到滑块集：\"\n\nmsgid \"Unable to open slider set file: \"\nmsgstr \"无法打开滑块集文件：\"\n\nmsgid \"Unable to load input nif: \"\nmsgstr \"无法加载输入nif：\"\n\nmsgid \"Unable to create destination directory: \"\nmsgstr \"无法创建目标目录：\"\n\nmsgid \"Unable to save nif file: \"\nmsgstr \"无法保存nif文件：\"\n\nmsgid \"All group build sets processed successfully!\"\nmsgstr \"所有组建立集(group build sets)处理成功！\"\n\nmsgid \"Complete\"\nmsgstr \"完成\"\n\nmsgid \"The following sets failed\"\nmsgstr \"以下集（sets）失败\"\n\nmsgid \"Failed\"\nmsgstr \"失败\"\n\nmsgid \"Failed to load BodyslideFrame.xrc file!\"\nmsgstr \"加载BodyslideFrame.xrc文件失败！\"\n\nmsgid \"Error\"\nmsgstr \"错误\"\n\nmsgid \"Failed to load BodySlide frame!\"\nmsgstr \"加载BodySlide框架失败！\"\n\nmsgid \"Group Filter\"\nmsgstr \"组过滤器\"\n\nmsgid \"Filter by group\"\nmsgstr \"通过组来过滤\"\n\nmsgid \"Outfit Filter\"\nmsgstr \"装备过滤器\"\n\nmsgid \"Filter by outfit\"\nmsgstr \"通过装备来过滤\"\n\nmsgid \"Choose groups to filter outfit list\"\nmsgstr \"选择用于过滤装备列表的组\"\n\nmsgid \"Choose Groups\"\nmsgstr \"选择组\"\n\nmsgid \"Choose or create group file\"\nmsgstr \"选择或创建组文件\"\n\nmsgid \"What would you like the new group to be called?\"\nmsgstr \"你想要给新组取什么名称？\"\n\nmsgid \"New Group Name\"\nmsgstr \"新组名\"\n\nmsgid \"Failed to save preset (%d)!\"\nmsgstr \"未能保存预置(%d)！\"\n\nmsgid \"Failed to save preset as '%s' (%d)!\"\nmsgstr \"未能保存预设为'%s' (%d)！\"\n\nmsgid \"Choose a folder to contain the saved files\"\nmsgstr \"选择一个目录来容纳保存的文件\"\n\nmsgid \"All sets processed successfully!\"\nmsgstr \"所有集（sets）处理成功！\"\n\nmsgid \"OpenGL Error\"\nmsgstr \"OpenGL错误\"\n\nmsgid \"Checking destination...\"\nmsgstr \"检查目标中...\"\n\nmsgid \"Adding reference shapes...\"\nmsgstr \"添加参照模型.中..\"\n\nmsgid \"Adding outfit shapes...\"\nmsgstr \"添加装备模型中...\"\n\nmsgid \"Calculating slider data...\"\nmsgstr \"计算滑块数据中...\"\n\nmsgid \"Creating slider set file...\"\nmsgstr \"创建滑块集文件中...\"\n\nmsgid \"Failed to open or create slider set file: \"\nmsgstr \"未能打开或创建滑块集文件：\"\n\nmsgid \"Saving slider set file...\"\nmsgstr \"保存滑块集文件中...\"\n\nmsgid \"Failed to write to slider set file: \"\nmsgstr \"未能写入滑块集文件：\"\n\nmsgid \"Saving NIF file...\"\nmsgstr \"保存NIF文件中...\"\n\nmsgid \"Failed to write base .nif file: \"\nmsgstr \"未能写入基础.nif文件：\"\n\nmsgid \"Finished\"\nmsgstr \"已完成\"\n\nmsgid \"Could not load OBJ file '%s'!\"\nmsgstr \"无法加载OBJ文件'%s'！\"\n\nmsgid \"OBJ Error\"\nmsgstr \"OBJ错误\"\n\nmsgid \"Could not copy data from OBJ file '%s'!\"\nmsgstr \"无法从OBJ文件'%s'复制数据！\"\n\nmsgid \"\"\n\"The vertex count of the selected .obj file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"被选.obj文件的顶点数与当前被选装备模型相匹配。您想更新当前模型吗？（点击否以\"\n\"创建一个新模型）\"\n\nmsgid \"Merge or New\"\nmsgstr \"合并或新建\"\n\nmsgid \"Update Vertex Positions?\"\nmsgstr \"更新顶点位置？\"\n\nmsgid \"Vertex Position Update\"\nmsgstr \"顶点位置更新\"\n\nmsgid \"Update Texture Coordinates?\"\nmsgstr \"更新材质坐标？\"\n\nmsgid \"UV Update\"\nmsgstr \"UV更新\"\n\nmsgid \"Please specify a name for the new shape\"\nmsgstr \"请为新模型指定一个名字\"\n\nmsgid \"New Shape Name\"\nmsgstr \"新模型名称\"\n\nmsgid \"Import Data Error\"\nmsgstr \"导入数据错误\"\n\nmsgid \"Gathering bones...\"\nmsgstr \"聚集骨骼中...\"\n\nmsgid \"Initializing proximity data...\"\nmsgstr \"初始化邻近数据中...\"\n\nmsgid \"Copying bone weights...\"\nmsgstr \"复制骨骼权重中...\"\n\nmsgid \"Transferring bone weights...\"\nmsgstr \"转移骨骼权重中...\"\n\nmsgid \"Template source entries are invalid.\"\nmsgstr \"模板源条目无效。\"\n\nmsgid \"Reference Error\"\nmsgstr \"参照错误\"\n\nmsgid \"\"\n\"NIF version not supported!\\n\"\n\"\\n\"\n\"File: %s\\n\"\n\"%s\\n\"\n\"User Version: %i\\n\"\n\"User Version 2: %i\"\nmsgstr \"\"\n\"NIF版本不支持！\\n\"\n\"\\n\"\n\"文件：%s\\n\"\n\"%s\\n\"\n\"用户版本：%i\\n\"\n\"用户版本2：%i\"\n\nmsgid \"Could not load reference NIF file '%s'!\"\nmsgstr \"无法加载参照NIF文件'%s'！\"\n\nmsgid \"Could not load slider set file '%s'!\"\nmsgstr \"无法加载滑块集文件'%s'！\"\n\nmsgid \"Reference NIF file '%s' does not contain any shapes.\"\nmsgstr \"参照NIF文件'%s'没有包含任何模型。\"\n\nmsgid \"Shape '%s' not found in reference NIF file '%s'!\"\nmsgstr \"模型 '%s'未能在参照NIF文件 '%s'中找到！\"\n\nmsgid \"NIF Error\"\nmsgstr \"NIF错误\"\n\nmsgid \"Could not load NIF file '%s'!\"\nmsgstr \"无法加载NIF文件'%s'！\"\n\nmsgid \"Loading slider set...\"\nmsgstr \"加载滑块集中...\"\n\nmsgid \"Adding slider set...\"\nmsgstr \"添加滑块集中......\"\n\nmsgid \"Retrieving sliders...\"\nmsgstr \"检索（各）滑块中...\"\n\nmsgid \"Loading outfit shapes...\"\nmsgstr \"加载装备模型中...\"\n\nmsgid \"Updating slider data...\"\nmsgstr \"更新滑块数据中...\"\n\nmsgid \"\"\n\"There was cloth physics data loaded at some point (BSClothExtraData). Please \"\n\"choose all the origins to use in the output.\"\nmsgstr \"\"\n\"有布料物理数据被加载在某些点（BSClothExtraData）。请选择所有输出时要用到的\"\n\"源。\"\n\nmsgid \"Choose cloth data\"\nmsgstr \"选择布料数据\"\n\nmsgid \"\"\n\"The vertex count of the selected .fbx file matches the currently selected \"\n\"outfit shape.  Do you wish to update the current shape?  (click No to create \"\n\"a new shape)\"\nmsgstr \"\"\n\"被选.fbx文件的顶点数与当前被选装备模型相匹配。您想更新当前模型吗？（点击否以\"\n\"创建一个新模型）\"\n\nmsgid \"Update Animation Weighting?\"\nmsgstr \"更新动画权重吗？\"\n\nmsgid \"Animation Weight Update\"\nmsgstr \"动画权重更新\"\n\nmsgid \"Failed to load outfitStudio.xrc file!\"\nmsgstr \"加载outfitStudio.xrc文件失败！\"\n\nmsgid \"Failed to load Outfit Studio frame!\"\nmsgstr \"加载Outfit Studio框架失败！\"\n\nmsgid \"Ready!\"\nmsgstr \"已准备！\"\n\nmsgid \"Creating sliders...\"\nmsgstr \"创建各滑块中...\"\n\nmsgid \"Clearing old sliders...\"\nmsgstr \"清除各旧滑块中...\"\n\nmsgid \"Loading slider: \"\nmsgstr \"正在加载滑块：\"\n\nmsgid \"Turn on edit mode for this slider.\"\nmsgstr \"为此滑块打开编辑模式。\"\n\nmsgid \"Weaken slider data by 1%.\"\nmsgstr \"减弱滑块数据1%。\"\n\nmsgid \"Strengthen slider data by 1%.\"\nmsgstr \"增强滑块数据1%。\"\n\nmsgid \"Enter a name for the new slider:\"\nmsgstr \"为新滑块输入一个名称：\"\n\nmsgid \"Create New Slider\"\nmsgstr \"创建新滑块\"\n\nmsgid \"\"\n\"You can only edit the base shape when all sliders are zero. Do you wish to \"\n\"set all sliders to zero now?  Note, use the pencil button next to a slider \"\n\"to enable editing of that slider's morph.\"\nmsgstr \"\"\n\"当所有滑块为零时你只能编辑基础模型。你现在希望设置所有滑块为零吗？注意，使用\"\n\"滑块旁边的铅笔按钮来开启对该滑块变形的编辑。\"\n\nmsgid \"Creating project '%s'...\"\nmsgstr \"创建项目'%s'中...\"\n\nmsgid \"Loading reference...\"\nmsgstr \"加载参照中...\"\n\nmsgid \"Loading outfit...\"\nmsgstr \"加载装备中...\"\n\nmsgid \"Creating outfit...\"\nmsgstr \"创建装备中...\"\n\nmsgid \"Creating %zu slider(s)...\"\nmsgstr \"创建（各）%zu滑块中...\"\n\nmsgid \"Select a slider set to load\"\nmsgstr \"选择要加载的滑块集\"\n\nmsgid \"Select a slider set to add\"\nmsgstr \"选择要添加的滑块\"\n\nmsgid \"Failed to open '%s' as a slider set file!\"\nmsgstr \"未能将'%s'作为滑块集文件打开！\"\n\nmsgid \"Slider Set Error\"\nmsgstr \"滑块集错误\"\n\nmsgid \"Please choose an outfit to load\"\nmsgstr \"请选择一个要加载的装备\"\n\nmsgid \"Load a slider set\"\nmsgstr \"加载一个滑块集\"\n\nmsgid \"Loading project...\"\nmsgstr \"加载项目中...\"\n\nmsgid \"Loading outfit data...\"\nmsgstr \"加载装备数据中...\"\n\nmsgid \"Failed to create project '%s' from file '%s' (%d)!\"\nmsgstr \"未能创建项目'%s'（从文件'%s' 中）(%d)！\"\n\nmsgid \"Loading reference shape '%s'...\"\nmsgstr \"加载参照模型'%s'中...\"\n\nmsgid \"Loading textures...\"\nmsgstr \"加载材质中...\"\n\nmsgid \"\"\n\"You're currently editing slider data, please exit the slider's edit mode \"\n\"(pencil button) and try again.\"\nmsgstr \"你当前正在编辑滑块数据，请退出滑块编辑模式（铅笔按钮）并重试。\"\n\nmsgid \"Loading reference set...\"\nmsgstr \"加载参照集中...\"\n\nmsgid \"Creating reference...\"\nmsgstr \"生成参照中...\"\n\nmsgid \"There are no valid shapes loaded!\"\nmsgstr \"无有效模型被加载！\"\n\nmsgid \"\"\n\"The following shapes have unweighted vertices, which can cause issues. The \"\n\"affected vertices have been put under a mask. Do you want to save anyway?\"\nmsgstr \"\"\n\"以下模型含有未加权重的顶点，可能会导致问题。受影响的顶点已被遮罩。你确定要保\"\n\"存吗？\"\n\nmsgid \"Unweighted Vertices\"\nmsgstr \"移除顶点权重\"\n\nmsgid \"\"\n\"The following shapes were renamed and won't have slider data attached. \"\n\"Rename the duplicates yourself beforehand.\"\nmsgstr \"以下模型已重命名，并且不会附加滑块数据。请事先重命名重复项。\"\n\nmsgid \"Renamed Shapes\"\nmsgstr \"重命名模型\"\n\nmsgid \"Saving project '%s'...\"\nmsgstr \"保存项目'%s'中...\"\n\nmsgid \"Invalid or no slider set file specified! Please try again.\"\nmsgstr \"无效或没有指定的滑块集文件！请重试。\"\n\nmsgid \"No outfit name specified! Please try again.\"\nmsgstr \"没有指定的装备名！请重试。\"\n\nmsgid \"No data folder specified! Please try again.\"\nmsgstr \"没有指定的数据目录！请重试。\"\n\nmsgid \"\"\n\"An invalid or no base outfit .nif file name specified! Please try again.\"\nmsgstr \"一个无效或无基础装备.nif文件的名称被指定！请重试。\"\n\nmsgid \"No game file path specified! Please try again.\"\nmsgstr \"没有游戏文件路径被指定！请重试。\"\n\nmsgid \"No game file name specified! Please try again.\"\nmsgstr \"没有游戏文件名被指定！请重试。\"\n\nmsgid \"Import NIF file\"\nmsgstr \"导入NIF文件\"\n\nmsgid \"Importing NIF file...\"\nmsgstr \"导入NIF文件中...\"\n\nmsgid \"Refreshing GUI...\"\nmsgstr \"刷新GUI（图形用户界面）中...\"\n\nmsgid \"Finished.\"\nmsgstr \"已完成。\"\n\nmsgid \"Export outfit NIF\"\nmsgstr \"导出装备NIF\"\n\nmsgid \"Failed to save NIF file '%s'!\"\nmsgstr \"未能保存NIF文件'%s！\"\n\nmsgid \"Export Error\"\nmsgstr \"导出错误\"\n\nmsgid \"Export project NIF\"\nmsgstr \"导出项目NIF\"\n\nmsgid \"Failed to save NIF file '%s' with reference!\"\nmsgstr \"未能保存带参照的NIF文件'%s'！\"\n\nmsgid \"Import physics data to project\"\nmsgstr \"将物理数据导入到项目\"\n\nmsgid \"Failed to import physics data file '%s'!\"\nmsgstr \"未能导入物理数据文件'%s'！\"\n\nmsgid \"Import Error\"\nmsgstr \"导入错误\"\n\nmsgid \"There is no physics data loaded!\"\nmsgstr \"没有物理数据被加载！\"\n\nmsgid \"Info\"\nmsgstr \"信息\"\n\nmsgid \"Please choose the physics data source you want to export.\"\nmsgstr \"请选择你想导出的物理数据源。\"\n\nmsgid \"Choose physics data\"\nmsgstr \"选择物理数据\"\n\nmsgid \"Export physics data\"\nmsgstr \"导出物理数据\"\n\nmsgid \"Failed to save physics data file '%s'!\"\nmsgstr \"未能保存物理数据文件'%s'！\"\n\nmsgid \"This function requires at least one slider position to be non-zero.\"\nmsgstr \"此功能需要至少一个滑块不为零。\"\n\nmsgid \"\"\n\"Create a conversion slider for the current slider settings with the \"\n\"following name: \"\nmsgstr \"使用以下名称为当前滑块设置创建一个转换滑块：\"\n\nmsgid \"Create New Conversion Slider\"\nmsgstr \"创建新的转换滑块\"\n\nmsgid \"Field of View: %d\"\nmsgstr \"视野：%d\"\n\nmsgid \"There are no sliders loaded!\"\nmsgstr \"没有滑块被加载！\"\n\nmsgid \"No changes were made to the sliders, so no preset was saved!\"\nmsgstr \"滑块没有被改变，所以预设没有被保存！\"\n\nmsgid \"There is no shape selected!\"\nmsgstr \"没有被选模型！\"\n\nmsgid \"There is no reference shape!\"\nmsgstr \"没有参考模型！\"\n\nmsgid \"There is no slider in edit mode to import data to!\"\nmsgstr \"编辑模式中没有可导入数据的滑块！\"\n\nmsgid \"Import .bsd slider data\"\nmsgstr \"导入.bsd滑块数据\"\n\nmsgid \"Import .obj file for slider calculation\"\nmsgstr \"为滑块计算导入.obj文件\"\n\nmsgid \"Vertex count of .obj file mesh does not match currently selected shape!\"\nmsgstr \".obj 网格文件的顶点数量与当前被选模型不匹配！\"\n\nmsgid \"Import .tri morphs\"\nmsgstr \"导入.tri变形\"\n\nmsgid \"This will delete all loaded sliders. Are you sure?\"\nmsgstr \"这会删除所有已加载的滑块。你确定吗？\"\n\nmsgid \"TRI Import\"\nmsgstr \"TRI导入\"\n\nmsgid \"Failed to load TRI file!\"\nmsgstr \"未能加载TRI文件！\"\n\nmsgid \"\"\n\"Added morphs for the following shapes:\\n\"\n\"\\n\"\n\"%s\"\nmsgstr \"\"\n\"为以下模型添加变形数据：\\n\"\n\"\\n\"\n\"%s\"\n\nmsgid \"Import .fbx file for slider calculation\"\nmsgstr \"为滑块计算导入.fbx文件\"\n\nmsgid \"There is no slider in edit mode to export data from!\"\nmsgstr \"编辑模式中没有可导出数据的滑块！\"\n\nmsgid \"Export .bsd slider data to directory\"\nmsgstr \"导出.bsd滑块数据到目录\"\n\nmsgid \"Export .bsd slider data\"\nmsgstr \"导出.bsd滑块数据\"\n\nmsgid \"Export .obj slider data to directory\"\nmsgstr \"导出.obj滑块数据到目录\"\n\nmsgid \"Export .obj slider data\"\nmsgstr \"导出.obj滑块数据\"\n\nmsgid \"Failed to export OBJ file!\"\nmsgstr \"未能导出OBJ文件！\"\n\nmsgid \"Failed to export FBX file!\"\nmsgstr \"未能导出FBX文件！\"\n\nmsgid \"OSD Import\"\nmsgstr \"OSD导入\"\n\nmsgid \"Import .osd file\"\nmsgstr \"导入.osd文件\"\n\nmsgid \"Failed to import OSD file!\"\nmsgstr \"未能导入OSD文件！\"\n\nmsgid \"Export .osd file\"\nmsgstr \"导出.osd文件\"\n\nmsgid \"Failed to export OSD file!\"\nmsgstr \"未能导出OSD文件！\"\n\nmsgid \"Export .tri morphs\"\nmsgstr \"导出.tri变形\"\n\nmsgid \"Failed to export TRI file!\"\nmsgstr \"未能导出TRI文件！\"\n\nmsgid \"Are you sure you wish to clear the unmasked slider data \"\nmsgstr \"您确定要清除未被遮罩的滑块数据吗\"\n\nmsgid \"for the selected shapes? This cannot be undone.\"\nmsgstr \"对被选模型?这不能被撤消。\"\n\nmsgid \"Confirm data erase\"\nmsgstr \"确认数据擦除\"\n\nmsgid \"for the shape \\\"\"\nmsgstr \"为模型\\\"\"\n\nmsgid \"Enter a name for the new zap:\"\nmsgstr \"为新修正命名：\"\n\nmsgid \"Create New Zap\"\nmsgstr \"创建新修正\"\n\nmsgid \"There is no slider in edit mode to negate!\"\nmsgstr \"编辑模式中没有可无效化的滑块！\"\n\nmsgid \"There is no slider in edit mode to create a mask from!\"\nmsgstr \"编辑模式中没有可创建遮罩的滑块！\"\n\nmsgid \"Are you sure you wish to delete the selected slider(s)?\"\nmsgstr \"你确定要删除被选滑块吗(s)\"\n\nmsgid \"\\\"? This cannot be undone.\"\nmsgstr \"\\\"吗？这无法撤销。\"\n\nmsgid \"Confirm slider delete\"\nmsgstr \"确认滑块删除\"\n\nmsgid \"There is no slider in edit mode to show properties for!\"\nmsgstr \"编辑模式中没有可显示属性的滑块！\"\n\nmsgid \"Conforming all shapes...\"\nmsgstr \"整合所有模型中...\"\n\nmsgid \"Conforming: \"\nmsgstr \"正在整合：\"\n\nmsgid \"All shapes conformed.\"\nmsgstr \"所有模型已整合。\"\n\nmsgid \"Conforming...\"\nmsgstr \"整合中...\"\n\nmsgid \"Initializing data...\"\nmsgstr \"初始化数据中...\"\n\nmsgid \"Shape(s) conformed.\"\nmsgstr \"模型已整合。\"\n\nmsgid \"Import .obj file for new shape\"\nmsgstr \"为新模型导入.obj文件\"\n\nmsgid \"Export selected shapes as an .obj file\"\nmsgstr \"将被选模型导出为一个.obj文件\"\n\nmsgid \"Export shape as an .obj file\"\nmsgstr \"将模型导出为一个.obj文件\"\n\nmsgid \"Export project as an .obj file\"\nmsgstr \"将项目导出为一个.obj文件\"\n\nmsgid \"Export project as an .fbx file\"\nmsgstr \"将项目导出为一个.fbx文件\"\n\nmsgid \"Export shape as an .fbx file\"\nmsgstr \"将模型导出为一个.fbx文件\"\n\nmsgid \"Export selected shapes as an .fbx file\"\nmsgstr \"将被选模型导出为一个.fbx文件\"\n\nmsgid \"Import .fbx file for new shape\"\nmsgstr \"为新模型导入.fbx文件\"\n\nmsgid \"Please enter a new unique name for the shape.\"\nmsgstr \"请为模型输入一个独有的的新名称。\"\n\nmsgid \"Rename Shape\"\nmsgstr \"重命名模型\"\n\nmsgid \"\"\n\"Rotating slider data is currently not possible using the Rotate Shape dialog.\"\nmsgstr \"目前无法使用旋转模型对话框旋转滑块数据。\"\n\nmsgid \"Rotate\"\nmsgstr \"旋转\"\n\nmsgid \"\"\n\"You can only copy shapes into an outfit, and there is no outfit in the \"\n\"current project. Load one first!\"\nmsgstr \"你只能将模型复制进装备，且当前项目中没有装备。请先加载一个！\"\n\nmsgid \"Please enter a unique name for the duplicated shape.\"\nmsgstr \"请为复制的模型命一个独有的名。\"\n\nmsgid \"Duplicate Shape\"\nmsgstr \"复制模型\"\n\nmsgid \"\"\n\"Are you sure you wish to delete the unmasked vertices of the selected \"\n\"shapes?  This action cannot be undone.\"\nmsgstr \"确定删除未遮罩的模型吗？此操作无法撤销。\"\n\nmsgid \"\"\n\"Are you sure you wish to delete the selected shapes?  This action cannot be \"\n\"undone.\"\nmsgstr \"确定删除被选模型吗？此操作无法撤销。\"\n\nmsgid \"Confirm Delete\"\nmsgstr \"确认删除\"\n\nmsgid \"No bone name was entered!\"\nmsgstr \"没有骨骼名称被输入！\"\n\nmsgid \"Bone '%s' already exists in the project!\"\nmsgstr \"骨骼'%s'已经存在于项目中！\"\n\nmsgid \"\"\n\"Sorry, you can't copy weights from the reference shape to itself. Skipping \"\n\"this shape.\"\nmsgstr \"抱歉，你无法将参照模型的权重复制到它本身。跳过此模型。\"\n\nmsgid \"Can't copy weights\"\nmsgstr \"无法复制权重\"\n\nmsgid \"Copying selected bone weights...\"\nmsgstr \"复制被选骨骼权重中...\"\n\nmsgid \"Sorry, you can't copy weights from the reference shape to itself.\"\nmsgstr \"对不起，你无法复制参照模型的权重到它本身。 。\"\n\nmsgid \"The vertex count of the reference and chosen shape is not the same!\"\nmsgstr \"参照和被选模型的顶点数不同！\"\n\nmsgid \"Outfit Studio: OpenGL context is not OK.\"\nmsgstr \"Outfit Studio：OpenGL环境异常。\"\n\nmsgid \"Adding NIF file...\"\nmsgstr \"添加NIF文件中...\"\n\nmsgid \"Adding OBJ file...\"\nmsgstr \"添加OBJ文件中...\"\n\nmsgid \"Adding FBX file...\"\nmsgstr \"添加FBX文件中...\"\n\nmsgid \"Loading slider file...\"\nmsgstr \"加载滑块文件中...\"\n\nmsgid \"Preview failed: OpenGL context is not OK.\"\nmsgstr \"Outfit Studio：OpenGL环境异常。\"\n\nmsgid \"Version\"\nmsgstr \"版本\"\n\nmsgid \"\"\n\"Version of NIF file doesn't match current target game. To use the meshes for \"\n\"the target game, export to OBJ/FBX and reload them again.\"\nmsgstr \"\"\n\"NIF文件的版本不匹配当前目标游戏。若要为目标游戏使用此网格，请导出到OBJ/FBX并\"\n\"重新加载。\"\n\nmsgid \"Would you like Skyrim NIFs to be optimized for SSE during this session?\"\nmsgstr \"你想在本阶段将NIF文件为特别版进行优化吗？\"\n\nmsgid \"Language\"\nmsgstr \"语言\"\n\nmsgid \"Use the selected language for the program.\"\nmsgstr \"为程序使用被选语言。\"\n\nmsgid \"Rendering\"\nmsgstr \"渲染中\"\n\nmsgid \"Background Color\"\nmsgstr \"背景颜色\"\n\nmsgid \"Background color of the renderer.\"\nmsgstr \"渲染器的背景颜色。\"\n\nmsgid \"Unload Project\"\nmsgstr \"卸载项目\"\n\nmsgid \"Unload Project...\\tCtrl+W\"\nmsgstr \"卸载项目..\\tCtrl+W\"\n\nmsgid \"Unloads the project and creates an empty new one.\"\nmsgstr \"卸载此项目并新建一个空项目。\"\n\nmsgid \"\"\n\"Do you really want to unload the project? All unsaved changes will be lost.\"\nmsgstr \"你真的要卸载项目吗？所有未保存的修改将丢失。\"\n\nmsgid \"Delete Vertices...\"\nmsgstr \"删除顶点...\"\n\nmsgid \"Deletes all unmasked vertices of the currently selected shapes.\"\nmsgstr \"删除当前被选模型所有未被遮罩的顶点。\"\n\nmsgid \"Separate Vertices...\"\nmsgstr \"分离顶点...\"\n\nmsgid \"Please enter a unique name for the new separated shape.\"\nmsgstr \"请为新分离的模型命一个独有的名。\"\n\nmsgid \"Separate the current shape into two by using the mask.\"\nmsgstr \"用遮罩将当前模型分离为两个。\"\n\nmsgid \"Show the Normal Map Generator dialog.\"\nmsgstr \"显示法线贴图生成器对话框。\"\n\nmsgid \"Normal Map Generator\"\nmsgstr \"法线贴图生成器\"\n\nmsgid \"Layers\"\nmsgstr \"图层\"\n\nmsgid \"Load or save preset layer settings.\"\nmsgstr \"打开或保存预设图层设置。\"\n\nmsgid \"Choose a normals generator preset file...\"\nmsgstr \"选择一个法线生成器预设文件...\"\n\nmsgid \"Save normals generator preset to...\"\nmsgstr \"将法线生成器预设保存到...\"\n\nmsgid \"Background\"\nmsgstr \"背景\"\n\nmsgid \"Background File\"\nmsgstr \"背景文件\"\n\nmsgid \"File source for this layer.\"\nmsgstr \"此图层的文件来源。\"\n\nmsgid \"\"\n\"File containing normals data to combine. Note this file should fit the mesh \"\n\"UVs.\"\nmsgstr \"包含要合并的法线数据的文件。注意这个文件应适应网格uv。\"\n\nmsgid \"Color\"\nmsgstr \"颜色\"\n\nmsgid \"Solid background color (if file is not set).\"\nmsgstr \"纯背景色（若文件没有设置）。\"\n\nmsgid \"Resolution\"\nmsgstr \"分辨率\"\n\nmsgid \"\"\n\"Output texture dimensions. By default all images will be scaled to fit this \"\n\"size.\"\nmsgstr \"输出材质的尺寸（dimensions）。默认所有图像都会被缩放以适应此尺寸。\"\n\nmsgid \"Is Tangent Space?\"\nmsgstr \"是切空间吗？\"\n\nmsgid \"\"\n\"True if the normals data in the layer file is in tangent space, false if \"\n\"they are in model space (msn).\"\nmsgstr \"\"\n\"若图层文件中的法线数据位于切空间中则为真；若位于模型空间(msn)中则为假。\"\n\nmsgid \"A greyscale image used to mask updates to destination image.\"\nmsgstr \"一个用于屏蔽目标图像更新的灰度图像。\"\n\nmsgid \"X Offset\"\nmsgstr \"X偏移量\"\n\nmsgid \"Y Offset\"\nmsgstr \"Y偏移量\"\n\nmsgid \"Offset to apply to image position.\"\nmsgstr \"应用于图像位置的偏移。\"\n\nmsgid \"If true, scale image to match background resolution.\"\nmsgstr \"若为真，缩放图像来匹配背景分辨率。\"\n\nmsgid \"Add Layer\"\nmsgstr \"添加图层\"\n\nmsgid \"Add a new layer after the current one in the layer list.\"\nmsgstr \"添加一个新图层于图层列表中的当前图层之后。\"\n\nmsgid \"Move Up\"\nmsgstr \"上移\"\n\nmsgid \"Move selected layer up one position.\"\nmsgstr \"将被选图层向上移动一个位置。\"\n\nmsgid \"Delete Layer\"\nmsgstr \"删除图层\"\n\nmsgid \"Delete the selected layer.\"\nmsgstr \"删除被选图层。\"\n\nmsgid \"Backup destination file\"\nmsgstr \"备份目标文件\"\n\nmsgid \"\"\n\"Save a copy of an existing normal map if one already exists. File is saved \"\n\"in the original directory.\"\nmsgstr \"若文件已存在，保存现有法线贴图的副本。文件保存在原目录中。\"\n\nmsgid \"Compress output\"\nmsgstr \"压缩输出内容\"\n\nmsgid \"\"\n\"Compress output file using BC7 compression. This can make saving the file \"\n\"take a VERY long time!\"\nmsgstr \"使用BC7 compression压缩输出文件。这可能会使保存文件花费很长时间！\"\n\nmsgid \"Save to background layer file\"\nmsgstr \"保存到背景图层文件\"\n\nmsgid \"\"\n\"Use the file name specified in the background layer to save the normal map.\"\nmsgstr \"使用背景图层中指定的文件名来保存法线贴图。\"\n\nmsgid \"Location to save normal map to.\"\nmsgstr \"保存法线贴图的位置。\"\n\nmsgid \"Choose an output file...\"\nmsgstr \"选择一个输出文件...\"\n\nmsgid \"Display current settings on mesh in preview window.\"\nmsgstr \"在预览窗口中显示网格上的当前设置。\"\n\nmsgid \"Generate\"\nmsgstr \"生成\"\n\nmsgid \"Generate and save the normal map file.\"\nmsgstr \"生成并保存法线贴图文件。\"\n\nmsgid \"Colors\"\nmsgstr \"颜色\"\n\nmsgid \"Brush Color\"\nmsgstr \"笔刷颜色\"\n\nmsgid \"Color of the brush.\"\nmsgstr \"画笔颜色。\"\n\nmsgid \"Edit Color\"\nmsgstr \"编辑颜色\"\n\nmsgid \"Edit Alpha\"\nmsgstr \"编辑透明度\"\n\nmsgid \"Color Paint\"\nmsgstr \"色漆\"\n\nmsgid \"Color Paint\\t7\"\nmsgstr \"色漆\\t7\"\n\nmsgid \"\"\n\"Apply vertex colors.\\n\"\n\"Hold down the ALT key to remove colors.\"\nmsgstr \"\"\n\"应用顶点颜色\\n\"\n\"按住ALT键以删除颜色。\"\n\nmsgid \"Alpha Paint\"\nmsgstr \"绘制透明度\"\n\nmsgid \"Alpha Paint\\t8\"\nmsgstr \"绘制透明度\\\\8\"\n\nmsgid \"\"\n\"Apply vertex alpha.\\n\"\n\"Hold down the ALT key to remove alpha.\"\nmsgstr \"\"\n\"应用顶点透明度\\n\"\n\"按住ALT键以删除透明度。\"\n\nmsgid \"Vertex Colors\"\nmsgstr \"顶点颜色\"\n\nmsgid \"Vertex Alpha\"\nmsgstr \"顶点透明度\"\n\nmsgid \"Outfit Studio\"\nmsgstr \"Outfit Studio\"\n\nmsgid \"Browse\"\nmsgstr \"浏览\"\n\nmsgid \"Skyrim Special Edition\"\nmsgstr \"上古卷轴特别版\"\n\nmsgid \"Fallout 4 VR\"\nmsgstr \"辐射4 VR版\"\n\nmsgid \"Skyrim VR\"\nmsgstr \"天际 VR版\"\n"
  },
  {
    "path": "lib/DDS.h",
    "content": "//--------------------------------------------------------------------------------------\n// DDS.h\n//\n// This header defines constants and structures that are useful when parsing\n// DDS files.  DDS files were originally designed to use several structures\n// and constants that are native to DirectDraw and are defined in ddraw.h,\n// such as DDSURFACEDESC2 and DDSCAPS2.  This file defines similar\n// (compatible) constants and structures so that one can use DDS files\n// without needing to include ddraw.h.\n//\n// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n//\n// http://go.microsoft.com/fwlink/?LinkId=248926\n// http://go.microsoft.com/fwlink/?LinkId=248929\n// http://go.microsoft.com/fwlink/?LinkID=615561\n//--------------------------------------------------------------------------------------\n\n#pragma once\n\n#include <cstdint>\n\nnamespace DirectX\n{\n\n#pragma pack(push,1)\n\n    constexpr uint32_t DDS_MAGIC = 0x20534444; // \"DDS \"\n\n    struct DDS_PIXELFORMAT\n    {\n        uint32_t    size;\n        uint32_t    flags;\n        uint32_t    fourCC;\n        uint32_t    RGBBitCount;\n        uint32_t    RBitMask;\n        uint32_t    GBitMask;\n        uint32_t    BBitMask;\n        uint32_t    ABitMask;\n    };\n\n#define DDS_FOURCC      0x00000004  // DDPF_FOURCC\n#define DDS_RGB         0x00000040  // DDPF_RGB\n#define DDS_RGBA        0x00000041  // DDPF_RGB | DDPF_ALPHAPIXELS\n#define DDS_LUMINANCE   0x00020000  // DDPF_LUMINANCE\n#define DDS_LUMINANCEA  0x00020001  // DDPF_LUMINANCE | DDPF_ALPHAPIXELS\n#define DDS_ALPHAPIXELS 0x00000001  // DDPF_ALPHAPIXELS\n#define DDS_ALPHA       0x00000002  // DDPF_ALPHA\n#define DDS_PAL8        0x00000020  // DDPF_PALETTEINDEXED8\n#define DDS_PAL8A       0x00000021  // DDPF_PALETTEINDEXED8 | DDPF_ALPHAPIXELS\n#define DDS_BUMPDUDV    0x00080000  // DDPF_BUMPDUDV\n// DDS_BUMPLUMINANCE 0x00040000\n\n#ifndef MAKEFOURCC\n#define MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n                (static_cast<uint32_t>(static_cast<uint8_t>(ch0)) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch1)) << 8) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch2)) << 16) \\\n                | (static_cast<uint32_t>(static_cast<uint8_t>(ch3)) << 24))\n#endif /* MAKEFOURCC */\n\n#ifndef DDSGLOBALCONST\n#if defined(__GNUC__) && !defined(__MINGW32__)\n#define DDSGLOBALCONST extern const __attribute__((weak))\n#else\n#define DDSGLOBALCONST extern const __declspec(selectany)\n#endif\n#endif /* DDSGLOBALCONST */\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','1'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','2'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT3 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','3'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','4'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DXT5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','T','5'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC4_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','U'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC4_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','4','S'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC5_UNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','U'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_BC5_SNORM =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('B','C','5','S'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R8G8_B8G8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('R','G','B','G'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_G8R8_G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('G','R','G','B'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_YUY2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('Y','U','Y','2'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_UYVY =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X8R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X8B8G8R8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_G16R16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB,  0, 32, 0x0000ffff, 0xffff0000, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R5G6B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xf800, 0x07e0, 0x001f, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x8000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X1R5G5B5 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x0f00, 0x00f0, 0x000f, 0xf000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_X4R4G4B4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R8G8B8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 24, 0xff0000, 0x00ff00, 0x0000ff, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8R3G3B2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_R3G3B2 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A4L4 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x0f, 0, 0, 0xf0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0xff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 16, 0xffff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 16, 0x00ff, 0, 0, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8_ALT =\n    { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCEA, 0, 8, 0x00ff, 0, 0, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L8_NVTT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_L16_NVTT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0xffff, 0, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8L8_NVTT1 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 16, 0x00ff, 0, 0, 0xff00 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_ALPHA, 0, 8, 0, 0, 0, 0xff };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_V8U8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 16, 0x00ff, 0xff00, 0, 0 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_Q8W8V8U8 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 };\n\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_V16U16 =\n    { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0, 0 };\n\n// D3DFMT_A2R10G10B10/D3DFMT_A2B10G10R10 should be written using DX10 extension to avoid D3DX 10:10:10:2 reversal issue\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A2R10G10B10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 };\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_A2B10G10R10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_RGBA, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 };\n\n// We do not support the following legacy Direct3D 9 formats:\n// DDSPF_A2W10V10U10 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPDUDV, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 };\n// DDSPF_L6V5U5 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 16, 0x001f, 0x03e0, 0xfc00, 0 };\n// DDSPF_X8L8V8U8 = { sizeof(DDS_PIXELFORMAT), DDS_BUMPLUMINANCE, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0 };\n\n// This indicates the DDS_HEADER_DXT10 extension is present (the format is in dxgiFormat)\n    DDSGLOBALCONST DDS_PIXELFORMAT DDSPF_DX10 =\n    { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('D','X','1','0'), 0, 0, 0, 0, 0 };\n\n#define DDS_HEADER_FLAGS_TEXTURE        0x00001007  // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT\n#define DDS_HEADER_FLAGS_MIPMAP         0x00020000  // DDSD_MIPMAPCOUNT\n#define DDS_HEADER_FLAGS_VOLUME         0x00800000  // DDSD_DEPTH\n#define DDS_HEADER_FLAGS_PITCH          0x00000008  // DDSD_PITCH\n#define DDS_HEADER_FLAGS_LINEARSIZE     0x00080000  // DDSD_LINEARSIZE\n\n#define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT\n#define DDS_WIDTH  0x00000004 // DDSD_WIDTH\n\n#define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE\n#define DDS_SURFACE_FLAGS_MIPMAP  0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP\n#define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX\n\n#define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX\n#define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX\n#define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY\n#define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY\n#define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ\n#define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\n#define DDS_CUBEMAP_ALLFACES ( DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\\\n                               DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\\\n                               DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ )\n\n#define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP\n\n#define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME\n\n// Subset here matches D3D10_RESOURCE_DIMENSION and D3D11_RESOURCE_DIMENSION\n    enum DDS_RESOURCE_DIMENSION : uint32_t\n    {\n        DDS_DIMENSION_TEXTURE1D = 2,\n        DDS_DIMENSION_TEXTURE2D = 3,\n        DDS_DIMENSION_TEXTURE3D = 4,\n    };\n\n    // Subset here matches D3D10_RESOURCE_MISC_FLAG and D3D11_RESOURCE_MISC_FLAG\n    enum DDS_RESOURCE_MISC_FLAG : uint32_t\n    {\n        DDS_RESOURCE_MISC_TEXTURECUBE = 0x4L,\n    };\n\n    enum DDS_MISC_FLAGS2 : uint32_t\n    {\n        DDS_MISC_FLAGS2_ALPHA_MODE_MASK = 0x7L,\n    };\n\n#ifndef DDS_ALPHA_MODE_DEFINED\n#define DDS_ALPHA_MODE_DEFINED\n    enum DDS_ALPHA_MODE : uint32_t\n    {\n        DDS_ALPHA_MODE_UNKNOWN = 0,\n        DDS_ALPHA_MODE_STRAIGHT = 1,\n        DDS_ALPHA_MODE_PREMULTIPLIED = 2,\n        DDS_ALPHA_MODE_OPAQUE = 3,\n        DDS_ALPHA_MODE_CUSTOM = 4,\n    };\n#endif\n\n    struct DDS_HEADER\n    {\n        uint32_t        size;\n        uint32_t        flags;\n        uint32_t        height;\n        uint32_t        width;\n        uint32_t        pitchOrLinearSize;\n        uint32_t        depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags\n        uint32_t        mipMapCount;\n        uint32_t        reserved1[11];\n        DDS_PIXELFORMAT ddspf;\n        uint32_t        caps;\n        uint32_t        caps2;\n        uint32_t        caps3;\n        uint32_t        caps4;\n        uint32_t        reserved2;\n    };\n\n    struct DDS_HEADER_DXT10\n    {\n        DXGI_FORMAT     dxgiFormat;\n        uint32_t        resourceDimension;\n        uint32_t        miscFlag; // see D3D11_RESOURCE_MISC_FLAG\n        uint32_t        arraySize;\n        uint32_t        miscFlags2; // see DDS_MISC_FLAGS2\n    };\n\n#pragma pack(pop)\n\n    static_assert(sizeof(DDS_PIXELFORMAT) == 32, \"DDS pixel format size mismatch\");\n    static_assert(sizeof(DDS_HEADER) == 124, \"DDS Header size mismatch\");\n    static_assert(sizeof(DDS_HEADER_DXT10) == 20, \"DDS DX10 Extended Header size mismatch\");\n\n} // namespace\n"
  },
  {
    "path": "lib/FSEngine/FSBSA.cpp",
    "content": "/***** BEGIN LICENSE BLOCK *****\n\nBSD License\n\nCopyright (c) 2005-2012, NIF File Format Library and Tools\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the NIF File Format Library and Tools project may not be\n   used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n***** END LICENCE BLOCK *****/\n\n#include \"FSBSA.h\"\n#ifdef __linux__\n#include <directx/dxgiformat.h>\n#else\n#include <dxgiformat.h>\n#endif\n#include \"../DDS.h\"\n\n#include <wx/mstream.h>\n#include <wx/zstream.h>\n#include <vector>\n#include <algorithm>\n\n#include \"../LZ4F/lz4.h\"\n#include \"../LZ4F/lz4frame.h\"\n\n#ifndef MAX_PATH\n#define MAX_PATH 4096\n#endif\n\nwxUint32 BSA::BSAFile::size() const {\n\tif (sizeFlags > 0) {\n\t\t// Skyrim and earlier\n\t\treturn sizeFlags & OB_BSAFILE_SIZEMASK;\n\t}\n\n\treturn (packedLength == 0) ? unpackedLength : packedLength;\n}\n\nbool BSA::BSAFile::compressed() const {\n\treturn (sizeFlags & OB_BSAFILE_FLAG_COMPRESS) != 0;\n}\n\n//! Reads a foldername sized string (length + null-terminated string) from the BSA\nstatic bool BSAReadSizedString(wxFile &bsa, std::string &s) {\n\twxUint8 len;\n\tif (bsa.Read((char *)&len, 1) != 1)\n\t\treturn false;\n\n\tif (len <= 0) {\n\t\ts.clear();\n\t\treturn true;\n\t}\n\n\twxMemoryBuffer b(len);\n\tif (bsa.Read(b.GetData(), len) == len) {\n\t\ts = b;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\ntemplate<typename TIter>\nstatic void SequenceToLowerCase(TIter begin, TIter end) {\n\tfor (auto it = begin; it != end; ++it)\n\t\t*it |= 0x20;\n}\n\nwxMemoryBuffer gUncompress(const wxMemoryBuffer &data, wxUint32 unpackedSize = 0, int skip = 0) {\n\tif (data.GetDataLen() <= 4) {\n\t\t// Input data is truncated\n\t\treturn wxMemoryBuffer();\n\t}\n\n\twxMemoryInputStream input((char*)data.GetData() + skip, data.GetDataLen() - skip);\n\twxZlibInputStream zlibStream(input);\n\n\twxMemoryBuffer result;\n\tif (!zlibStream.CanRead())\n\t\treturn result;\n\n\tif (unpackedSize > 0) {\n\t\t// Allocate if unpacked size is known\n\t\tresult.SetBufSize(unpackedSize);\n\t\tresult.SetDataLen(unpackedSize);\n\t\tzlibStream.Read(result.GetData(), unpackedSize);\n\t}\n\telse {\n\t\twxMemoryOutputStream output;\n\t\tzlibStream.Read(output);\n\n\t\tresult.SetBufSize(output.GetLength());\n\t\tresult.SetDataLen(output.GetLength());\n\t\toutput.CopyTo(result.GetData(), result.GetDataLen());\n\t}\n\n\treturn result;\n}\n\nwxMemoryBuffer lz4fUncompress(const wxMemoryBuffer& data, wxUint32 unpackedSize = 0, int skip = 0) {\n\tif (data.GetDataLen() <= skip) {\n\t\t// Input data is truncated\n\t\treturn wxMemoryBuffer();\n\t}\n\n\t(void*)&unpackedSize; // unused\n\n\tsize_t srcSize = data.GetDataLen() - skip;\n\tsize_t dstSize = ((unsigned int*)data.GetData())[0];\n\n\twxMemoryBuffer result(dstSize);\n\n\tLZ4F_decompressionContext_t dCtx = nullptr;\n\tLZ4F_createDecompressionContext(&dCtx, LZ4F_VERSION);\n\n\tLZ4F_decompressOptions_t options = { 0 };\n\n\tLZ4F_decompress(dCtx, result.GetData(), &dstSize, (char*)data.GetData() + skip, &srcSize, &options);\n\tLZ4F_freeDecompressionContext(dCtx);\n\n\tresult.SetDataLen(dstSize);\n\treturn result;\n}\n\nwxMemoryBuffer lz4Uncompress(const wxMemoryBuffer& data, wxUint32 unpackedSize = 0) {\n\tif (data.GetDataLen() <= 0) {\n\t\t// Input data is truncated\n\t\treturn wxMemoryBuffer();\n\t}\n\n\tsize_t srcSize = data.GetDataLen();\n\tsize_t dstSize = unpackedSize;\n\n\twxMemoryBuffer result(dstSize);\n\n\tLZ4_decompress_safe_partial((char*)data.GetData(), (char*)result.GetData(), srcSize, dstSize, dstSize);\n\n\tresult.SetDataLen(dstSize);\n\treturn result;\n};\n\n\nBSA::BSA(const std::string &filename) : FSArchiveFile(), bsa(filename), bsaInfo(filename), status(\"initialized\") {\n\tbsaPath = bsaInfo.GetPathWithSep() + bsaInfo.GetFullName();\n\tbsaBase = bsaInfo.GetPath();\n\tbsaName = bsaInfo.GetFullName();\n}\n\nBSA::~BSA() {\n\tclose();\n}\n\nbool BSA::canOpen(const std::string &fn) {\n\twxFile f(fn);\n\tif (f.IsOpened()) {\n\t\twxUint32 magic, version;\n\n\t\tif (f.Read((char *)& magic, sizeof(magic)) != 4)\n\t\t\treturn false;\n\n\t\tif (magic == F4_BSAHEADER_FILEID) {\n\t\t\tif (f.Read((char *)&version, sizeof(version)) != 4)\n\t\t\t\treturn false;\n\n\t\t\treturn version == F4_BSAHEADER_VERSION || F4_BSAHEADER_VERSION2 || F4_BSAHEADER_VERSION3 || version == SF_BSAHEADER_VERSION2 || version == SF_BSAHEADER_VERSION3;\n\t\t}\n\t\telse if (magic == OB_BSAHEADER_FILEID) {\n\t\t\tif (f.Read((char *)& version, sizeof(version)) != 4)\n\t\t\t\treturn false;\n\n\t\t\treturn (version == OB_BSAHEADER_VERSION || version == F3_BSAHEADER_VERSION || version == SSE_BSAHEADER_VERSION);\n\t\t}\n\t\telse\n\t\t\treturn magic == MW_BSAHEADER_FILEID;\n\t}\n\n\treturn false;\n}\n\nbool BSA::open() {\n\twxMutexLocker lock(bsaMutex);\n\n\ttry {\n\t\tbsa.Open(bsaPath);\n\t\tif (!bsa.IsOpened())\n\t\t\tthrow std::string(\"file open\");\n\n\t\twxUint32 magic, version;\n\n\t\tbsa.Read((char*)&magic, sizeof(magic));\n\n\t\tif (magic == F4_BSAHEADER_FILEID) {\n\t\t\tbsa.Read((char*)&version, sizeof(version));\n\n\t\t\tif (version != F4_BSAHEADER_VERSION && version != F4_BSAHEADER_VERSION2 && version != F4_BSAHEADER_VERSION3 && version != SF_BSAHEADER_VERSION2\n\t\t\t\t&& version != SF_BSAHEADER_VERSION3)\n\t\t\t\tthrow std::string(\"file version\");\n\n\t\t\theaderVersion = version;\n\n\t\t\tssize_t headerSize = sizeof(ba2Header);\n\t\t\tif (version == F4_BSAHEADER_VERSION || version == F4_BSAHEADER_VERSION2 || version == F4_BSAHEADER_VERSION3)\n\t\t\t\theaderSize = 16;\n\t\t\telse if (version == SF_BSAHEADER_VERSION2)\n\t\t\t\theaderSize = 24;\n\t\t\telse if (version == SF_BSAHEADER_VERSION3)\n\t\t\t\theaderSize = 28;\n\n\t\t\tif (bsa.Read((char*)&ba2Header, headerSize) != headerSize)\n\t\t\t\tthrow std::string(\"header size\");\n\n\t\t\tnumFiles = ba2Header.numFiles;\n\t\t\tnamePrefix = false;\n\n\t\t\tfileNameSuperBuffer = std::make_unique<char[]>(numFiles * (MAX_PATH + 2) + 1);\n\t\t\tchar* superBufferPtr = fileNameSuperBuffer.get();\n\t\t\tstd::vector<wxUint32> path_sizes(numFiles * 2);\n\n\t\t\tif (bsa.Seek(ba2Header.nameTableOffset)) {\n\t\t\t\tbsa.Read(superBufferPtr, numFiles * (MAX_PATH + 2));\n\t\t\t\twxUint32 cursor = 0;\n\t\t\t\twxUint32 n = 0;\n\t\t\t\tfor (wxUint32 i = 0; i < ba2Header.numFiles; i++) {\n\t\t\t\t\twxUint16 len;\n\t\t\t\t\tlen = *(wxUint16*)(superBufferPtr + cursor);\n\t\t\t\t\tcursor += 2;\n\t\t\t\t\tpath_sizes[n++] = cursor;\n\t\t\t\t\tcursor += len;\n\t\t\t\t\tpath_sizes[n++] = cursor;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tstd::replace(superBufferPtr, superBufferPtr + numFiles * (MAX_PATH + 2), '\\\\', '/');\n\n\t\t\tstd::string h(ba2Header.type, 4);\n\t\t\tif (h == \"GNRL\") {\n\t\t\t\t// General BA2 Format\n\t\t\t\tif (bsa.Seek(headerSize + 8)) {\n\t\t\t\t\troot.files.reserve(ba2Header.numFiles);\n\n\t\t\t\t\tBA2GeneralInfo* finfo = new BA2GeneralInfo[ba2Header.numFiles];\n\t\t\t\t\tbsa.Read(finfo, 36 * numFiles);\n\n\t\t\t\t\twxUint32 n = 0;\n\t\t\t\t\tfor (wxUint32 i = 0; i < ba2Header.numFiles; i++) {\n\t\t\t\t\t\tinsertFile(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n], finfo[i].packedSize, finfo[i].unpackedSize, finfo[i].offset);\n\n\t\t\t\t\t\t/* Folders not required in this tool\n\t\t\t\t\t\tstd::string fullFile = std::string(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n]);\n\t\t\t\t\t\tstd::string file;\n\t\t\t\t\t\tstd::string folder;\n\n\t\t\t\t\t\tint folderStrIndex = fullFile.find_last_of('/');\n\t\t\t\t\t\tif (folderStrIndex >= 0) {\n\t\t\t\t\t\t\tfile = fullFile.substr(folderStrIndex + 1, path_sizes[n + 1] - path_sizes[n] - folderStrIndex + 1);\n\t\t\t\t\t\t\tfolder = fullFile.substr(0, folderStrIndex);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfile = fullFile;\n\n\t\t\t\t\t\tinsertFile(insertFolder(folder), file, finfo[i].packedSize, finfo[i].unpackedSize, finfo[i].offset);\n\t\t\t\t\t\t*/\n\n\t\t\t\t\t\tn += 2;\n\t\t\t\t\t}\n\t\t\t\t\tdelete[] finfo;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (h == \"DX10\") {\n\t\t\t\t// Texture BA2 Format\n\t\t\t\tif (bsa.Seek(headerSize + 8)) {\n\t\t\t\t\troot.files.reserve(ba2Header.numFiles);\n\n\t\t\t\t\twxUint32 n = 0;\n\t\t\t\t\tfor (wxUint32 i = 0; i < ba2Header.numFiles; i++) {\n\t\t\t\t\t\tBA2Tex tex;\n\t\t\t\t\t\tbsa.Read((char*)&tex.header, 24);\n\n\t\t\t\t\t\tstd::vector<BA2TexChunk> texChunks(tex.header.numChunks);\n\t\t\t\t\t\tbsa.Read(texChunks.data(), tex.header.numChunks * 24);\n\t\t\t\t\t\ttex.chunks = std::move(texChunks);\n\n\t\t\t\t\t\tconst BA2TexChunk& chunk = tex.chunks[0];\n\t\t\t\t\t\tinsertFile(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n], chunk.packedSize, chunk.unpackedSize, chunk.offset, &tex);\n\n\t\t\t\t\t\t/* Folders not required in this tool\n\t\t\t\t\t\tstd::string fullFile = std::string(superBufferPtr + path_sizes[n], path_sizes[n + 1] - path_sizes[n]);\n\t\t\t\t\t\tstd::string file;\n\t\t\t\t\t\tstd::string folder;\n\n\t\t\t\t\t\tint folderStrIndex = fullFile.find_last_of('/');\n\t\t\t\t\t\tif (folderStrIndex >= 0) {\n\t\t\t\t\t\t\tfile = fullFile.substr(folderStrIndex + 1, path_sizes[n + 1] - path_sizes[n] - folderStrIndex + 1);\n\t\t\t\t\t\t\tfolder = fullFile.substr(0, folderStrIndex);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tfile = fullFile;\n\n\t\t\t\t\t\tinsertFile(insertFolder(folder), file, chunk.packedSize, chunk.unpackedSize, chunk.offset, tex);\n\t\t\t\t\t\t*/\n\n\t\t\t\t\t\tn += 2;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// From NifSkope\n\t\telse if (magic == OB_BSAHEADER_FILEID) {\n\t\t\tbsa.Read((char*)&version, sizeof(version));\n\n\t\t\tif (version != OB_BSAHEADER_VERSION && version != F3_BSAHEADER_VERSION && version != SSE_BSAHEADER_VERSION)\n\t\t\t\tthrow std::string(\"file version\");\n\n\t\t\theaderVersion = version;\n\n\t\t\tOBBSAHeader header{};\n\n\t\t\tif (bsa.Read((char *)& header, sizeof(header)) != sizeof(header))\n\t\t\t\tthrow std::string(\"header size\");\n\n\t\t\tnumFiles = header.FileCount;\n\n\t\t\tif ((header.ArchiveFlags & OB_BSAARCHIVE_PATHNAMES) == 0 || (header.ArchiveFlags & OB_BSAARCHIVE_FILENAMES) == 0)\n\t\t\t\tthrow std::string(\"header flags\");\n\n\t\t\tcompressToggle = (header.ArchiveFlags & OB_BSAARCHIVE_COMPRESSFILES) != 0;\n\n\t\t\tif (version == F3_BSAHEADER_VERSION || version == SSE_BSAHEADER_VERSION)\n\t\t\t\tnamePrefix = (header.ArchiveFlags & F3_BSAARCHIVE_PREFIXFULLFILENAMES) != 0;\n\t\t\telse\n\t\t\t\tnamePrefix = false;\n\n\t\t\twxUint32 folderSize = 0;\n\t\t\tif (version != SSE_BSAHEADER_VERSION)\n\t\t\t\tfolderSize = sizeof(OBBSAFolderInfo);\n\t\t\telse\n\t\t\t\tfolderSize = sizeof(SSEBSAFolderInfo);\n\n\t\t\tif (bsa.Seek(header.FolderRecordOffset + header.FolderNameLength + header.FolderCount * (1 + folderSize) + header.FileCount * sizeof(OBBSAFileInfo)) == wxInvalidOffset)\n\t\t\t\tthrow std::string(\"file name seek\");\n\n\t\t\twxMemoryBuffer fileNames(header.FileNameLength);\n\t\t\tif (bsa.Read(fileNames.GetData(), header.FileNameLength) != (ssize_t)header.FileNameLength)\n\t\t\t\tthrow std::string(\"file name read\");\n\n\t\t\twxUint32 fileNameIndex = 0;\n\n\t\t\tif (bsa.Seek(header.FolderRecordOffset) == wxInvalidOffset)\n\t\t\t\tthrow std::string(\"folder info seek\");\n\n\t\t\tBSAFolderInfo initInfo{ 0 };\n\t\t\tstd::vector<BSAFolderInfo> folderInfos(header.FolderCount, initInfo);\n\t\t\tif (version != SSE_BSAHEADER_VERSION) {\n\t\t\t\tbool ok = true;\n\t\t\t\tfor (wxUint32 i = 0; i < header.FolderCount; i++) {\n\t\t\t\t\tok &= bsa.Read((char *)&folderInfos[i], 8) == 8;\t\t// Hash\n\t\t\t\t\tok &= bsa.Read((char *)&folderInfos[i] + 8, 4) == 4;\t// File size\n\t\t\t\t\tok &= bsa.Read((char *)&folderInfos[i] + 16, 4) == 4;\t// Offset: this is reading a uint32 into a uint64 whose memory must be zeroed\n\n\t\t\t\t\tif (!ok)\n\t\t\t\t\t\tthrow std::string(\"folder info read\");\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (bsa.Read((char *)folderInfos.data(), header.FolderCount * folderSize) != (ssize_t)(header.FolderCount * folderSize))\n\t\t\t\t\tthrow std::string(\"folder info read\");\n\t\t\t}\n\n\t\t\twxUint32 totalFileCount = 0;\n\n\t\t\tfor (const BSAFolderInfo& folderInfo : folderInfos) {\n\t\t\t\tstd::string folderName;\n\t\t\t\tif (!BSAReadSizedString(bsa, folderName))\n\t\t\t\t\tthrow std::string(\"folder name read\");\n\n\t\t\t\tBSAFolder *folder = insertFolder(folderName);\n\n\t\t\t\twxUint32 fcnt = folderInfo.fileCount;\n\t\t\t\ttotalFileCount += fcnt;\n\t\t\t\tstd::vector<OBBSAFileInfo> fileInfos(fcnt);\n\t\t\t\tif (bsa.Read((char *)fileInfos.data(), fcnt * sizeof(OBBSAFileInfo)) != (ssize_t)(fcnt * sizeof(OBBSAFileInfo)))\n\t\t\t\t\tthrow std::string(\"file info read\");\n\n\t\t\t\tfor (const OBBSAFileInfo fileInfo : fileInfos) {\n\t\t\t\t\tif (fileNameIndex >= header.FileNameLength)\n\t\t\t\t\t\tthrow std::string(\"file name size\");\n\n\t\t\t\t\tstd::string fileName = static_cast<char*>(fileNames.GetData()) + fileNameIndex;\n\t\t\t\t\tfileNameIndex += fileName.length() + 1;\n\n\t\t\t\t\tinsertFile(folder, fileName, fileInfo.sizeFlags, fileInfo.offset);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (totalFileCount != header.FileCount)\n\t\t\t\tthrow std::string(\"file count\");\n\t\t}\n\t\telse if (magic == MW_BSAHEADER_FILEID) {\n\t\t\tMWBSAHeader header{};\n\n\t\t\tif (bsa.Read((char *)& header, sizeof(header)) != sizeof(header))\n\t\t\t\tthrow std::string(\"header\");\n\n\t\t\tnumFiles = header.FileCount;\n\t\t\tcompressToggle = false;\n\t\t\tnamePrefix = false;\n\n\t\t\t// header is 12 bytes, hash table is 8 bytes per entry\n\t\t\twxUint32 dataOffset = 12 + header.HashOffset + header.FileCount * 8;\n\n\t\t\t// file size/offset table\n\t\t\tstd::vector<MWBSAFileSizeOffset> sizeOffset(header.FileCount);\n\t\t\tif (bsa.Read((char *)sizeOffset.data(), header.FileCount * sizeof(MWBSAFileSizeOffset)) != (ssize_t)(header.FileCount * sizeof(MWBSAFileSizeOffset)))\n\t\t\t\tthrow std::string(\"file size/offset\");\n\n\t\t\t// filename offset table\n\t\t\tstd::vector<wxUint32> nameOffset(header.FileCount);\n\t\t\tif (bsa.Read((char *)nameOffset.data(), header.FileCount * sizeof(wxUint32)) != (ssize_t)(header.FileCount * sizeof(wxUint32)))\n\t\t\t\tthrow std::string(\"file name offset\");\n\n\t\t\t// filenames. size is given by ( HashOffset - ( 8 * number of file/size offsets) - ( 4 * number of filenames) )\n\t\t\t// i.e. ( HashOffset - ( 12 * number of files ) )\n\t\t\twxMemoryBuffer fileNames;\n\t\t\tfileNames.SetBufSize(header.HashOffset - 12 * header.FileCount);\n\t\t\tif (bsa.Read((char *)fileNames.GetData(), header.HashOffset - 12 * header.FileCount) != (ssize_t)(header.HashOffset - 12 * header.FileCount))\n\t\t\t\tthrow std::string(\"file names\");\n\n\t\t\t// table of 8 bytes of hash values follow, but we don't need to know what they are\n\t\t\t// file data follows that, which is fetched by fileContents\n\n\t\t\tfor (wxUint32 c = 0; c < header.FileCount; c++) {\n\t\t\t\tstd::string fname = static_cast<char*>(fileNames.GetData()) + nameOffset[c];\n\t\t\t\tstd::string dname;\n\t\t\t\tint x = fname.find_last_of('\\\\');\n\t\t\t\tif (x > 0) {\n\t\t\t\t\tdname = fname.substr(0, x);\n\t\t\t\t\tfname.erase(0, x + 1);\n\t\t\t\t}\n\n\t\t\t\tinsertFile(insertFolder(dname), fname, sizeOffset[c].size, dataOffset + sizeOffset[c].offset);\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tthrow std::string(\"file magic\");\n\t}\n\tcatch (std::string e) {\n\t\tstatus = e;\n\t\treturn false;\n\t}\n\n\tstatus = \"loaded successful\";\n\n\treturn true;\n}\n\nvoid BSA::close() {\n\twxMutexLocker lock(bsaMutex);\n\n\tbsa.Close();\n\tfor (auto &it : root.children)\n\t\tdelete it.second;\n\tfor (auto &it : root.files)\n\t\tdelete it.second;\n\n\troot.children.clear();\n\troot.files.clear();\n\tfolders.clear();\n\n\tfileNameSuperBuffer.reset();\n}\n\nwxInt64 BSA::fileSize(const std::string & fn) const {\n\t// note: lazy size count (not accurate for compressed files)\n\tif (const BSAFile * file = getFile(fn)) {\n\t\tif (file->sizeFlags > 0)\n\t\t\treturn file->size();\n\n\t\twxUint64 size = file->unpackedLength;\n\n\t\tif (file->tex.chunks.size()) {\n\t\t\tfor (size_t i = 1; i < file->tex.chunks.size(); i++) {\n\t\t\t\tsize += file->tex.chunks[i].unpackedSize;\n\t\t\t}\n\t\t}\n\n\t\treturn size;\n\t}\n\treturn 0;\n}\n\nvoid BSA::addFilesOfFolders(const std::string &folderName, std::vector<std::string> &tree) const {\n\tif (const BSAFolder *folder = getFolder(folderName)) {\n\t\ttree.push_back(folderName);\n\t\tfor (auto &child : folder->children) {\n\t\t\taddFilesOfFolders(folderName + \"/\" + child.first, tree);\n\t\t}\n\t\tfor (auto &file : folder->files) {\n\t\t\ttree.push_back(folderName + \"/\" + file.first);\n\t\t}\n\t}\n}\n\nvoid BSA::fileTree(std::vector<std::string> &tree) const {\n\ttree.push_back(name());\n\tfor (auto &folder : root.children)\n\t\taddFilesOfFolders(folder.first, tree);\n}\n\nbool BSA::fileContents(const std::string &fn, wxMemoryBuffer &content) {\n\tif (const BSAFile *file = getFile(fn)) {\n\t\twxMutexLocker lock(bsaMutex);\n\t\tif (bsa.Seek(file->offset)) {\n\t\t\twxInt64 filesz = file->size();\n\t\t\tssize_t fileok = 1;\n\t\t\tif (namePrefix) {\n\t\t\t\tchar len;\n\t\t\t\tfileok = bsa.Read(&len, 1);\n\t\t\t\tfilesz -= len;\n\t\t\t\tif (fileok != wxInvalidOffset)\n\t\t\t\t\tfileok = bsa.Seek(file->offset + 1 + len);\n\t\t\t}\n\n\t\t\tif (file->tex.chunks.size() > 0) {\n\t\t\t\t// Fill DDS Header for BA2\n\t\t\t\tDirectX::DDS_HEADER ddsHeader = {};\n\t\t\t\tddsHeader.size = sizeof(ddsHeader);\n\t\t\t\tddsHeader.flags = DDS_HEADER_FLAGS_TEXTURE | DDS_HEADER_FLAGS_LINEARSIZE | DDS_HEADER_FLAGS_MIPMAP;\n\t\t\t\tddsHeader.height = file->tex.header.height;\n\t\t\t\tddsHeader.width = file->tex.header.width;\n\t\t\t\tddsHeader.mipMapCount = file->tex.header.numMips;\n\t\t\t\tddsHeader.caps = DDS_SURFACE_FLAGS_TEXTURE | DDS_SURFACE_FLAGS_MIPMAP;\n\t\t\t\tddsHeader.pitchOrLinearSize = file->tex.header.width * file->tex.header.height; // 8bpp\n\n\t\t\t\tDirectX::DDS_HEADER_DXT10 ddsHeader10 = {};\n\t\t\t\tddsHeader10.resourceDimension = DirectX::DDS_DIMENSION_TEXTURE2D;\n\t\t\t\tddsHeader10.arraySize = 1;\n\n\t\t\t\tif (file->tex.header.unk16 == 2049) {\n\t\t\t\t\tddsHeader.caps2 = DDS_CUBEMAP_ALLFACES;\n\t\t\t\t\tddsHeader10.miscFlag = DirectX::DDS_RESOURCE_MISC_TEXTURECUBE;\n\t\t\t\t\tddsHeader10.arraySize *= 6;\n\t\t\t\t}\n\n\t\t\t\tbool ok = true;\n\n\t\t\t\tswitch (file->tex.header.format) {\n\t\t\t\t\tcase DXGI_FORMAT_BC1_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC1_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_BC1_UNORM_SRGB:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_DXT1;\n\t\t\t\t\t\tddsHeader.pitchOrLinearSize /= 2; // 4bpp\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_BC2_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC2_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_BC2_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_DXT3; break;\n\n\t\t\t\t\tcase DXGI_FORMAT_BC3_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC3_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_BC3_UNORM_SRGB: ddsHeader.ddspf = DirectX::DDSPF_DXT5; break;\n\n\t\t\t\t\tcase DXGI_FORMAT_BC4_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC4_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_BC4_SNORM:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_DX10;\n\t\t\t\t\t\tddsHeader.pitchOrLinearSize /= 2; // 4bpp\n\t\t\t\t\t\tddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_BC5_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC5_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_BC5_SNORM:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_DX10;\n\t\t\t\t\t\tddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_BC6H_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC6H_UF16:\n\t\t\t\t\tcase DXGI_FORMAT_BC6H_SF16:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_DX10;\n\t\t\t\t\t\tddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_BC7_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_BC7_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_BC7_UNORM_SRGB:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_DX10;\n\t\t\t\t\t\tddsHeader10.dxgiFormat = (DXGI_FORMAT)file->tex.header.format;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_B8G8R8A8_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_B8G8R8A8_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_A8R8G8B8;\n\t\t\t\t\t\tddsHeader.pitchOrLinearSize *= 4; // 32bpp\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_R8G8B8A8_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_R8G8B8A8_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:\n\t\t\t\t\tcase DXGI_FORMAT_R8G8B8A8_UINT:\n\t\t\t\t\tcase DXGI_FORMAT_R8G8B8A8_SNORM:\n\t\t\t\t\tcase DXGI_FORMAT_R8G8B8A8_SINT:\n\t\t\t\t\t\tddsHeader.ddspf = DirectX::DDSPF_A8R8G8B8;\n\t\t\t\t\t\tddsHeader.pitchOrLinearSize *= 4; // 32bpp\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase DXGI_FORMAT_R8_TYPELESS:\n\t\t\t\t\tcase DXGI_FORMAT_R8_UNORM:\n\t\t\t\t\tcase DXGI_FORMAT_R8_UINT:\n\t\t\t\t\tcase DXGI_FORMAT_R8_SNORM:\n\t\t\t\t\tcase DXGI_FORMAT_R8_SINT: ddsHeader.ddspf = DirectX::DDSPF_L8_NVTT1; break;\n\n\t\t\t\t\tdefault: ok = false; break;\n\t\t\t\t}\n\n\t\t\t\tif (!ok)\n\t\t\t\t\treturn false;\n\n\t\t\t\t// Append DDS Header\n\t\t\t\tcontent.AppendData(&DirectX::DDS_MAGIC, 4);\n\t\t\t\tcontent.AppendData(&ddsHeader, sizeof(ddsHeader));\n\t\t\t\tif (ddsHeader10.dxgiFormat != DXGI_FORMAT_UNKNOWN)\n\t\t\t\t\tcontent.AppendData(&ddsHeader10, sizeof(ddsHeader10));\n\t\t\t}\n\n\t\t\twxMemoryBuffer chunk(filesz);\n\t\t\tchunk.SetDataLen(filesz);\n\t\t\tif (fileok != wxInvalidOffset && bsa.Read(chunk.GetData(), filesz) == filesz) {\n\t\t\t\tif (file->sizeFlags > 0) {\n\t\t\t\t\t// BSA\n\t\t\t\t\tif (file->compressed() ^ compressToggle) {\n\t\t\t\t\t\tif (headerVersion == SSE_BSAHEADER_VERSION)\n\t\t\t\t\t\t\tchunk = lz4fUncompress(chunk, 0, 4);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tchunk = gUncompress(chunk, 0, 4);\n\t\t\t\t\t}\n\n\t\t\t\t\tcontent.AppendData(chunk, chunk.GetDataLen());\n\t\t\t\t}\n\t\t\t\telse if (file->packedLength > 0 && file->tex.chunks.empty()) {\n\t\t\t\t\t// GNRL BA2 compressed\n\t\t\t\t\tchunk = gUncompress(chunk, file->unpackedLength);\n\t\t\t\t\tcontent.AppendData(chunk, chunk.GetDataLen());\n\t\t\t\t}\n\t\t\t\telse if (file->tex.chunks.empty()) {\n\t\t\t\t\t// GNRL BA2 uncompressed\n\t\t\t\t\tcontent.AppendData(chunk.GetData(), chunk.GetDataLen());\n\t\t\t\t}\n\n\t\t\t\tif (!file->tex.chunks.empty()) {\n\t\t\t\t\t// Read chunks for DX10 BA2\n\t\t\t\t\tfor (size_t i = 0; i < file->tex.chunks.size(); i++) {\n\t\t\t\t\t\tconst BA2TexChunk& chunkInfo = file->tex.chunks[i];\n\t\t\t\t\t\tif (bsa.Seek(chunkInfo.offset)) {\n\t\t\t\t\t\t\twxMemoryBuffer currentChunk;\n\n\t\t\t\t\t\t\tif (chunkInfo.packedSize > 0) {\n\t\t\t\t\t\t\t\tcurrentChunk.SetBufSize(chunkInfo.packedSize);\n\t\t\t\t\t\t\t\tcurrentChunk.SetDataLen(chunkInfo.packedSize);\n\n\t\t\t\t\t\t\t\tif (bsa.Read(currentChunk.GetData(), chunkInfo.packedSize) == (ssize_t)chunkInfo.packedSize) {\n\t\t\t\t\t\t\t\t\tif (ba2Header.compressionFlag == 3)\n\t\t\t\t\t\t\t\t\t\tcurrentChunk = lz4Uncompress(currentChunk, chunkInfo.unpackedSize);\n\t\t\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\t\t\tcurrentChunk = gUncompress(currentChunk, chunkInfo.unpackedSize);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (currentChunk.GetDataLen() != chunkInfo.unpackedSize) {\n\t\t\t\t\t\t\t\t\t// Size does not match at chunkInfo.offset\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tcurrentChunk.SetBufSize(chunkInfo.unpackedSize);\n\t\t\t\t\t\t\t\tcurrentChunk.SetDataLen(chunkInfo.unpackedSize);\n\t\t\t\t\t\t\t\tif (!(bsa.Read(currentChunk.GetData(), chunkInfo.unpackedSize) == (ssize_t)chunkInfo.unpackedSize)) {\n\t\t\t\t\t\t\t\t\t// Size does not match at chunkInfo.offset\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcontent.AppendData(currentChunk.GetData(), currentChunk.GetDataLen());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t// Seek error\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n}\n\nbool BSA::exportFile(const std::string &fn, const std::string &target) {\n\twxMemoryBuffer content;\n\tif (!fileContents(fn, content))\n\t\treturn false;\n\n\tif (content.IsEmpty())\n\t\treturn false;\n\n\twxFile file(target, wxFile::write);\n\tif (file.Error())\n\t\treturn false;\n\n\tif (file.Write(content.GetData(), content.GetDataLen()) != content.GetDataLen())\n\t\treturn false;\n\n\tfile.Close();\n\treturn true;\n}\n\nstd::string BSA::absoluteFilePath(const std::string &fn) const {\n\tif (hasFile(fn)) {\n\t\twxFileName fileInfo(fn);\n\t\treturn (fileInfo.GetPath(true) + fileInfo.GetName()).ToStdString();\n\t}\n\n\treturn std::string();\n}\n\nBSA::BSAFolder *BSA::insertFolder(std::string name) {\n\tif (name.empty())\n\t\treturn &root;\n\n\tstd::replace(name.begin(), name.end(), '\\\\', '/');\n\tSequenceToLowerCase(name.begin(), name.end());\n\n\tBSAFolder *folder = folders[name];\n\tif (!folder) {\n\t\tfolder = new BSAFolder;\n\t\tfolders[name] = folder;\n\n\t\tint p = name.find_last_of('/');\n\t\tif (p >= 0) {\n\t\t\tfolder->parent = insertFolder(name.substr(0, p));\n\t\t\tfolder->parent->children[name.substr(p + 1)] = folder;\n\t\t}\n\t\telse {\n\t\t\tfolder->parent = &root;\n\t\t\troot.children[name] = folder;\n\t\t}\n\t}\n\n\treturn folder;\n}\n\nBSA::BSAFolder* BSA::insertFolder(char* folder, int szFn) {\n\tauto loc = folders.find(std::string(folder, folder + szFn));\n\tif (loc != folders.end()) {\n\t\treturn loc->second;\n\t}\n\n\tBSAFolder* fldr = new BSAFolder();\n\tfolders[std::string(folder, folder + szFn)] = fldr;\n\n\tfor (int p = szFn - 1; p >= 0; p--) {\n\t\tif (folder[p] == '/') {\n\t\t\tfldr->parent = insertFolder(folder, p);\n\t\t\tfldr->parent->children[std::string(folder + p + 1, szFn - p - 1)] = fldr;\n\t\t\treturn fldr;\n\t\t}\n\t}\n\tfldr->parent = &root;\n\troot.children[std::string(folder, folder + szFn)] = fldr;\n\treturn fldr;\n}\n\nBSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 sizeFlags, wxUint32 offset) {\n\tSequenceToLowerCase(name.begin(), name.end());\n\n\tBSAFile *file = new BSAFile;\n\tfile->sizeFlags = sizeFlags;\n\tfile->offset = offset;\n\n\tfolder->files[name] = file;\n\treturn file;\n}\n\n/* Folders not required in this tool\nBSA::BSAFile *BSA::insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex dds) {\n\tSequenceToLowerCase(name.begin(), name.end());\n\n\tBSAFile *file = new BSAFile;\n\tfile->tex = dds;\n\tfile->packedLength = packed;\n\tfile->unpackedLength = unpacked;\n\tfile->offset = offset;\n\tfolder->files[name] = file;\n\n\treturn file;\n}\n*/\n\nBSA::BSAFile* BSA::insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex* dds) {\n\tSequenceToLowerCase(filename, filename + szFn);\n\n\t/* Folders not required in this tool\n\tint p;\n\tfor (p = szFn - 1; p >= 0; p--) {\n\t\tif (filename[p] == '/')\n\t\t\tbreak;\n\t}\n\n\tBSAFolder* folder;\n\tif (p > -1)\n\t\tfolder = insertFolder(filename, p);\n\telse\n\t\tfolder = &root;\n\t*/\n\n\tBSAFile *file = new BSAFile;\n\tif (dds)\n\t\tfile->tex = *dds;\n\n\tfile->packedLength = packed;\n\tfile->unpackedLength = unpacked;\n\tfile->offset = offset;\n\t//folder->files[filename] = file;\n\troot.files.emplace(std::string(filename, szFn), file);\n\treturn nullptr;\n}\n\nconst BSA::BSAFolder *BSA::getFolder(std::string fn) const {\n\tSequenceToLowerCase(fn.begin(), fn.end());\n\n\tif (fn.empty()) {\n\t\treturn &root;\n\t}\n\telse {\n\t\tauto it = folders.find(fn);\n\t\tif (it != folders.end()) {\n\t\t\tBSA::BSAFolder *folder = it->second;\n\t\t\tif (folder)\n\t\t\t\treturn folder;\n\t\t}\n\t}\n\n\treturn nullptr;\n}\n\nconst BSA::BSAFile *BSA::getFile(std::string fn) const {\n\tSequenceToLowerCase(fn.begin(), fn.end());\n\n\tauto earlyfile = root.files.find(fn);\n\tif (earlyfile != root.files.end()) {\n\t\treturn earlyfile->second;\n\t}\n\n\tstd::string folderName;\n\tint p = fn.find_last_of('/');\n\tif (p >= 0) {\n\t\tfolderName = fn.substr(0, p);\n\t\tfn = fn.substr(p + 1);\n\t}\n\n\t// TODO: Multiple matches occur and user has no say which version gets loaded\n\t// When it comes to the AUTO feature, should give preference to certain BSAs\n\t// or take the newest and or highest quality version.\n\tif (const BSAFolder *folder = getFolder(folderName)) {\n\t\tauto it = folder->files.find(fn);\n\t\tif (it != folder->files.end()) {\n\t\t\tBSA::BSAFile *file = it->second;\n\t\t\tif (file)\n\t\t\t\treturn file;\n\t\t}\n\t}\n\n\treturn nullptr;\n}\n\nbool BSA::hasFile(const std::string &fn) const {\n\treturn getFile(fn) != nullptr;\n}\n\nbool BSA::hasFolder(const std::string &fn) const {\n\treturn getFolder(fn) != nullptr;\n}\n\nwxDateTime BSA::fileTime(const std::string&) const {\n\twxDateTime created;\n\tbsaInfo.GetTimes(nullptr, nullptr, &created);\n\treturn created;\n}\n"
  },
  {
    "path": "lib/FSEngine/FSBSA.h",
    "content": "/***** BEGIN LICENSE BLOCK *****\n\nBSD License\n\nCopyright (c) 2005-2012, NIF File Format Library and Tools\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the NIF File Format Library and Tools project may not be\n   used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n***** END LICENCE BLOCK *****/\n\n#pragma once\n\n#include \"FSEngine.h\"\n\n#include <wx/dir.h>\n#include <wx/file.h>\n#include <wx/filename.h>\n#include <wx/thread.h>\n#include <unordered_map>\n#include <memory>\n\n\n/* Default header data */\n#define MW_BSAHEADER_FILEID  0x00000100 //!< Magic for Morrowind BSA\n#define OB_BSAHEADER_FILEID  0x00415342 //!< Magic for Oblivion BSA, the literal string \"BSA\\0\".\n#define F4_BSAHEADER_FILEID  0x58445442\t//!< Magic for Fallout 4 BA2, the literal string \"BTDX\".\n#define OB_BSAHEADER_VERSION 0x67 //!< Version number of an Oblivion BSA\n#define F3_BSAHEADER_VERSION 0x68 //!< Version number of a Fallout 3 BSA\n#define SSE_BSAHEADER_VERSION 0x69 //!< Version number of a Skyrim SE BSA\n#define F4_BSAHEADER_VERSION 0x01 //!< Version number of a Fallout 4 BA2\n#define F4_BSAHEADER_VERSION2 0x07 //!< Version number of a Fallout 4 BA2\n#define F4_BSAHEADER_VERSION3 0x08 //!< Version number of a Fallout 4 BA2\n#define SF_BSAHEADER_VERSION2 0x02 //!< Version number of a Starfield BA2\n#define SF_BSAHEADER_VERSION3 0x03 //!< Version number of a Starfield BA2\n\n/* Archive flags */\n#define OB_BSAARCHIVE_PATHNAMES           0x0001 //!< Whether the BSA has names for paths\n#define OB_BSAARCHIVE_FILENAMES           0x0002 //!< Whether the BSA has names for files\n#define OB_BSAARCHIVE_COMPRESSFILES       0x0004 //!< Whether the files are compressed\n#define F3_BSAARCHIVE_PREFIXFULLFILENAMES 0x0100 //!< Whether the name is prefixed to the data?\n\n/* File flags */\n#define OB_BSAFILE_NIF  0x0001 //!< Set when the BSA contains NIF files\n#define OB_BSAFILE_DDS  0x0002 //!< Set when the BSA contains DDS files\n#define OB_BSAFILE_XML  0x0004 //!< Set when the BSA contains XML files\n#define OB_BSAFILE_WAV  0x0008 //!< Set when the BSA contains WAV files\n#define OB_BSAFILE_MP3  0x0010 //!< Set when the BSA contains MP3 files\n#define OB_BSAFILE_TXT  0x0020 //!< Set when the BSA contains TXT files\n#define OB_BSAFILE_HTML 0x0020 //!< Set when the BSA contains HTML files\n#define OB_BSAFILE_BAT  0x0020 //!< Set when the BSA contains BAT files\n#define OB_BSAFILE_SCC  0x0020 //!< Set when the BSA contains SCC files\n#define OB_BSAFILE_SPT  0x0040 //!< Set when the BSA contains SPT files\n#define OB_BSAFILE_TEX  0x0080 //!< Set when the BSA contains TEX files\n#define OB_BSAFILE_FNT  0x0080 //!< Set when the BSA contains FNT files\n#define OB_BSAFILE_CTL  0x0100 //!< Set when the BSA contains CTL files\n\n/* Bitmasks for the size field in the header */\n#define OB_BSAFILE_SIZEMASK 0x3fffffff //!< Bit mask with OBBSAFileInfo::sizeFlags to get the size of the file\n\n/* Record flags */\n#define OB_BSAFILE_FLAG_COMPRESS 0xC0000000 //!< Bit mask with OBBSAFileInfo::sizeFlags to get the compression status\n\n//! The header of an Oblivion BSA.\n/*!\n* Follows OB_BSAHEADER_FILEID and OB_BSAHEADER_VERSION.\n*/\nstruct OBBSAHeader {\n\twxUint32 FolderRecordOffset; //!< Offset of beginning of folder records\n\twxUint32 ArchiveFlags; //!< Archive flags\n\twxUint32 FolderCount; //!< Total number of folder records ((OB/SSE)BSAFolderInfo)\n\twxUint32 FileCount; //!< Total number of file records (OBBSAFileInfo)\n\twxUint32 FolderNameLength; //!< Total length of folder names\n\twxUint32 FileNameLength; //!< Total length of file names\n\twxUint32 FileFlags; //!< File flags\n};\n\n//! Info for a file inside an Oblivion BSA\nstruct OBBSAFileInfo {\n\twxUint64 hash; //!< Hash of the filename\n\twxUint32 sizeFlags; //!< Size of the data, possibly with OB_BSAFILE_FLAG_COMPRESS set\n\twxUint32 offset; //!< Offset to raw file data\n};\n\n//! Info for a folder inside a Skyrim SE BSA\nstruct SSEBSAFolderInfo {\n\twxUint64 hash; //!< Hash of the folder name\n\twxUint32 fileCount; //!< Number of files in folder\n\twxUint32 unknown; //!< Unknown\n\twxUint64 offset; //!< Offset to name of this folder\n};\n\n//! Info for a folder inside an Oblivion BSA\nstruct OBBSAFolderInfo {\n\twxUint64 hash; //!< Hash of the folder name\n\twxUint32 fileCount; //!< Number of files in folder\n\twxUint32 offset; //!< Offset to name of this folder\n};\n\n//! Define as general folder info\ntypedef SSEBSAFolderInfo BSAFolderInfo;\n\n//! The header of a Morrowind BSA\nstruct MWBSAHeader {\n\twxUint32 HashOffset; //!< Offset of hash table minus header size (12)\n\twxUint32 FileCount; //!< Number of files in the archive\n};\n\n//! The file size and offset of an entry in a Morrowind BSA\nstruct MWBSAFileSizeOffset {\n\twxUint32 size; //!< The size of the file\n\twxUint32 offset; //!< The offset of the file\n};\n\n#pragma pack(push, 4)\nstruct BA2Header {\n\tchar type[4]{}; //!< 08 GNRL=General, DX10=Textures\n\twxUint32 numFiles = 0; //!< 0C\n\twxUint64 nameTableOffset = 0; //!< 10 - relative to start of file\n\n\twxUint32 unk1 = 0;\n\twxUint32 unk2 = 0;\n\twxUint32 compressionFlag = 0; // LZ4 if 3, ZIP otherwise\n};\n\n// 24\nstruct BA2GeneralInfo {\n\twxUint32 unk00; //!< 00 - hash?\n\tchar ext[4]; //!< 04 - extension\n\twxUint32 unk08; //!< 08 - hash?\n\twxUint32 unk0C; //!< 0C - flags? 00100100\n\twxUint64 offset; //!< 10 - relative to start of file\n\twxUint32 packedSize; //!< 18 - packed length (zlib)\n\twxUint32 unpackedSize; //!< 1C - unpacked length\n\twxUint32 unk20; //!< 20 - BAADF00D\n};\n#pragma pack(pop)\n\n// 18\nstruct BA2TexInfo {\n\twxUint32 nameHash; //!< 00\n\tchar ext[4]; //!< 04\n\twxUint32 dirHash; //!< 08\n\twxUint8 unk0C; //!< 0C\n\twxUint8 numChunks; //!< 0D\n\twxUint16 chunkHeaderSize; //!< 0E - size of one chunk header\n\twxUint16 height; //!< 10\n\twxUint16 width; //!< 12\n\twxUint8 numMips; //!<  14\n\twxUint8 format; //!< 15 - DXGI_FORMAT\n\twxUint16 unk16; //!< 16 - 0800\n};\n\n// 18\nstruct BA2TexChunk {\n\twxUint64 offset; //!< 00\n\twxUint32 packedSize; //!< 08\n\twxUint32 unpackedSize; //!< 0C\n\twxUint16 startMip; //!< 10\n\twxUint16 endMip; //!< 12\n\twxUint32 unk14; //!< 14 - BAADFOOD\n};\n\nstruct BA2Tex {\n\tBA2TexInfo header{};\n\tstd::vector<BA2TexChunk> chunks;\n};\n\n\nclass BSA final : public FSArchiveFile {\npublic:\n\t//! Constructor; creates a %BSA from the given file path.\n\tBSA(const std::string &filePath);\n\t//! Destructor; closes the file.\n\t~BSA();\n\n\t//! Opens the %BSA file\n\tbool open() override final;\n\t//! Closes the %BSA file\n\tvoid close() override final;\n\n\t//! Returns BSA::bsaPath.\n\tstd::string path() const override final { return bsaPath; }\n\t//! Returns BSA::bsaBase.\n\tstd::string base() const override final { return bsaBase; }\n\t//! Returns BSA::bsaName.\n\tstd::string name() const override final { return bsaName; }\n\n\t//! Whether the specified folder exists or not\n\tbool hasFolder(const std::string&) const override final;\n\n\t//! Whether the specified file exists or not\n\tbool hasFile(const std::string&) const override final;\n\t//! Returns the size of the file per BSAFile::size().\n\twxInt64 fileSize(const std::string&) const override final;\n\t//! Add all files of the folder to the map\n\tvoid addFilesOfFolders(const std::string&, std::vector<std::string>&) const override final;\n\t//! Returns the entire file tree of the BSA\n\tvoid fileTree(std::vector<std::string>&) const override final;\n\n\t//! Returns the contents of the specified file\n\t/*!\n\t* \\param fn The filename to get the contents for\n\t* \\param content Reference to the byte array that holds the file contents\n\t* \\return True if successful\n\t*/\n\tbool fileContents(const std::string&, wxMemoryBuffer&) override final;\n\n\t//! Writes the contents to the specified file\n\tbool exportFile(const std::string&, const std::string&) override final;\n\n\t//! See QFileInfo::created().\n\twxDateTime fileTime(const std::string&) const override final;\n\t//! See QFileInfo::absoluteFilePath().\n\tstd::string absoluteFilePath(const std::string&) const override final;\n\n\t//! Whether the given file can be opened as a %BSA or not\n\tstatic bool canOpen(const std::string&);\n\n\t//! Returns BSA::status.\n\tstd::string statusText() const { return status; }\n\n\t//! Returns BSA::numFiles.\n\twxUint64 fileCount() const { return numFiles; }\n\nprotected:\n\t//! A file inside a BSA\n\tstruct BSAFile\n\t{\n\t\t// Skyrim and earlier\n\t\twxUint32 sizeFlags = 0; //!< The size of the file in the BSA\n\n\t\t// Fallout 4\n\t\twxUint32 packedLength = 0;\n\t\twxUint32 unpackedLength = 0;\n\n\t\twxUint64 offset = 0; //!< The offset of the file in the BSA\n\n\t\t//! The size of the file inside the BSA\n\t\twxUint32 size() const;\n\n\t\t//! Whether the file is compressed inside the BSA\n\t\tbool compressed() const;\n\n\t\tBA2Tex tex;\n\t};\n\n\t//! A folder inside a BSA\n\tstruct BSAFolder\n\t{\n\t\t//! Constructor\n\t\tBSAFolder() : parent(0) {}\n\t\t//! Destructor\n\t\t~BSAFolder() {\n\t\t\tfor (auto &it : children)\n\t\t\t\tdelete it.second;\n\t\t\tfor (auto &it : files)\n\t\t\t\tdelete it.second;\n\n\t\t\tchildren.clear();\n\t\t\tfiles.clear();\n\t\t}\n\n\t\tBSAFolder *parent; //!< The parent item\n\t\tstd::unordered_map<std::string, BSAFolder*> children; //!< A map of child folders\n\t\tstd::unordered_map<std::string, BSAFile*> files; //!< A map of files inside the folder\n\t};\n\n\t//! Recursive function to generate the tree structure of folders inside a %BSA\n\tBSAFolder *insertFolder(std::string name);\n\tBSAFolder *insertFolder(char* folder, int szFn);\n\t//! Inserts a file into the structure of a %BSA\n\tBSAFile* insertFile(BSAFolder* folder, std::string name, wxUint32 sizeFlags, wxUint32 offset);\n\t/* Folders not required in this tool\n\tBSAFile *insertFile(BSAFolder *folder, std::string name, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex dds = BA2Tex());\n\t*/\n\tBSAFile *insertFile(char* filename, int szFn, wxUint32 packed, wxUint32 unpacked, wxUint64 offset, BA2Tex* dds = nullptr);\n\n\t//! Gets the specified folder, or the root folder if not found\n\tconst BSAFolder *getFolder(std::string fn) const;\n\t//! Gets the specified file, or null if not found\n\tconst BSAFile *getFile(std::string fn) const;\n\n\t//! The %BSA file\n\twxFile bsa;\n\t//! File info for the %BSA\n\twxFileName bsaInfo;\n\n\t//! Mutual exclusion handler\n\twxMutex bsaMutex;\n\n\t//! The absolute name of the file, e.g. \"d:/temp/test.bsa\"\n\tstd::string bsaPath;\n\t//! The base path of the file, e.g. \"d:/temp\"\n\tstd::string bsaBase;\n\t//! The name of the file, e.g. \"test.bsa\"\n\tstd::string bsaName;\n\n\t//! Map of folders inside a %BSA\n\tstd::unordered_map<std::string, BSAFolder*> folders;\n\t//! The root folder\n\tBSAFolder root;\n\n\t//! Error string for exception handling\n\tstd::string status;\n\n\t//! Version number from the header\n\twxUint32 headerVersion = 0;\n\n\t//! BA2 header\n\tBA2Header ba2Header;\n\n\t//! Number of files\n\twxUint64 numFiles = 0;\n\n\t//! Whether the %BSA is compressed\n\tbool compressToggle = false;\n\t//! Whether Fallout 3 names are prefixed with an extra string\n\tbool namePrefix = false;\n\n\tstd::unique_ptr<char[]> fileNameSuperBuffer;\n};\n"
  },
  {
    "path": "lib/FSEngine/FSEngine.cpp",
    "content": "/***** BEGIN LICENSE BLOCK *****\n\nBSD License\n\nCopyright (c) 2005-2012, NIF File Format Library and Tools\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the NIF File Format Library and Tools project may not be\n   used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n***** END LICENCE BLOCK *****/\n\n#include \"FSEngine.h\"\n#include \"FSBSA.h\"\n\n\n//! \\file fsengine.cpp File system engine implementations\n\nFSArchiveHandler *FSArchiveHandler::openArchive(const std::string &fn) {\n\tif (BSA::canOpen(fn)) {\n\t\tBSA *bsa = new BSA(fn);\n\t\tif (bsa->open())\n\t\t\treturn new FSArchiveHandler(bsa);\n\n\t\tdelete bsa;\n\t}\n\treturn 0;\n}\n\nFSArchiveHandler::FSArchiveHandler(FSArchiveFile *a) {\n\tarchive = a;\n\twxAtomicInc(archive->ref);\n}\n\nFSArchiveHandler::~FSArchiveHandler() {\n\tif (!wxAtomicDec(archive->ref))\n\t\tdelete archive;\n}\n"
  },
  {
    "path": "lib/FSEngine/FSEngine.h",
    "content": "/***** BEGIN LICENSE BLOCK *****\n\nBSD License\n\nCopyright (c) 2005-2012, NIF File Format Library and Tools\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the NIF File Format Library and Tools project may not be\n   used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n***** END LICENCE BLOCK *****/\n\n\n#pragma once\n\n#include <wx/datetime.h>\n#include <wx/atomic.h>\n#include <vector>\n\n\n//! Provides a way to register an FSArchiveEngine with the application.\nclass FSArchiveHandler\n{\npublic:\n\t//! Opens a BSA for the specified file\n\tstatic FSArchiveHandler *openArchive(const std::string&);\n\npublic:\n\t//! Constructor\n\tFSArchiveHandler(class FSArchiveFile *a);\n\t//! Destructor\n\t~FSArchiveHandler();\n\n\tFSArchiveFile *getArchive() { return archive; }\n\nprotected:\n\tclass FSArchiveFile *archive;\n};\n\n\n//! A file system archive\nclass FSArchiveFile\n{\npublic:\n\t//! Constructor\n\tFSArchiveFile() : ref(0) {}\n\tvirtual ~FSArchiveFile() {}\n\n\tvirtual bool open() = 0;\n\tvirtual void close() = 0;\n\n\tvirtual std::string base() const = 0;\n\tvirtual std::string name() const = 0;\n\tvirtual std::string path() const = 0;\n\n\tvirtual bool hasFolder(const std::string&) const = 0;\n\tvirtual bool hasFile(const std::string&) const = 0;\n\tvirtual wxInt64 fileSize(const std::string&) const = 0;\n\tvirtual void addFilesOfFolders(const std::string&, std::vector<std::string>&) const = 0;\n\tvirtual void fileTree(std::vector<std::string>&) const = 0;\n\tvirtual bool fileContents(const std::string&, wxMemoryBuffer&) = 0;\n\tvirtual bool exportFile(const std::string&, const std::string&) = 0;\n\tvirtual std::string absoluteFilePath(const std::string&) const = 0;\n\n\tvirtual wxDateTime fileTime(const std::string&) const = 0;\n\nprotected:\n\t//! A reference counter for an implicitly shared class\n\twxAtomicInt ref;\n\n\tfriend class FSArchiveHandler;\n};\n"
  },
  {
    "path": "lib/FSEngine/FSManager.cpp",
    "content": "/***** BEGIN LICENSE BLOCK *****\n\nBSD License\n\nCopyright (c) 2005-2012, NIF File Format Library and Tools\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the NIF File Format Library and Tools project may not be\n   used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n***** END LICENCE BLOCK *****/\n\n\n#include \"FSManager.h\"\n#include \"FSEngine.h\"\n\n#include <algorithm>\n#include <iterator>\n\n\n//! Global BSA file manager\nstatic FSManager *theFSManager = nullptr;\n\nFSManager* FSManager::get() {\n\tif (!theFSManager)\n\t\ttheFSManager = new FSManager();\n\treturn theFSManager;\n}\n\nbool FSManager::exists() {\n\treturn theFSManager != nullptr;\n}\n\nvoid FSManager::del() {\n\tif (theFSManager) {\n\t\tdelete theFSManager;\n\t\ttheFSManager = nullptr;\n\t}\n}\n\nstd::list<FSArchiveFile*> FSManager::archiveList() {\n\tstd::list<FSArchiveFile*> archives;\n\n\tstd::transform(get()->archives.begin(), get()->archives.end(), std::back_inserter(archives),\n\t\t[](std::map<std::string, FSArchiveHandler*>::value_type& val){ return val.second->getArchive(); });\n\n\treturn archives;\n}\n\nvoid FSManager::addArchives(const std::vector<std::string>& archiveList) {\n\tfor (auto &archive : archiveList) {\n\t\tif (FSArchiveHandler *a = FSArchiveHandler::openArchive(archive))\n\t\t\tget()->archives[archive] = a;\n\t}\n}\n\nFSManager::FSManager() {\n}\n\nFSManager::~FSManager() {\n\tfor (auto &it : archives)\n\t\tdelete it.second;\n\n\tarchives.clear();\n}\n"
  },
  {
    "path": "lib/FSEngine/FSManager.h",
    "content": "/***** BEGIN LICENSE BLOCK *****\n\nBSD License\n\nCopyright (c) 2005-2012, NIF File Format Library and Tools\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions\nare met:\n1. Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n3. The name of the NIF File Format Library and Tools project may not be\n   used to endorse or promote products derived from this software\n   without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n***** END LICENCE BLOCK *****/\n\n#pragma once\n\n#include <string>\n#include <vector>\n#include <map>\n#include <list>\n\n\nclass FSArchiveHandler;\nclass FSArchiveFile;\n\n//! The file system manager class.\nclass FSManager {\npublic:\n\t//! Gets the global file system manager\n\tstatic FSManager *get();\n\t//! Returns if the file manager exists already\n\tstatic bool exists();\n\t//! Deletes the global file system manager\n\tstatic void del();\n\t//! Gets the list of globally registered BSA files\n\tstatic std::list<FSArchiveFile*> archiveList();\n\t//! Adds archives to the global list\n\tstatic void addArchives(const std::vector<std::string>&);\n\nprotected:\n\t//! Constructor\n\tFSManager();\n\t//! Destructor\n\t~FSManager();\n\n\tstd::map<std::string, FSArchiveHandler*> archives;\n};\n"
  },
  {
    "path": "lib/LZ4F/lz4.c",
    "content": "/*\n   LZ4 - Fast LZ compression algorithm\n   Copyright (C) 2011-2020, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n    - LZ4 homepage : http://www.lz4.org\n    - LZ4 source repository : https://github.com/lz4/lz4\n*/\n\n/*-************************************\n*  Tuning parameters\n**************************************/\n/*\n * LZ4_HEAPMODE :\n * Select how stateless compression functions like `LZ4_compress_default()`\n * allocate memory for their hash table,\n * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()).\n */\n#ifndef LZ4_HEAPMODE\n#  define LZ4_HEAPMODE 0\n#endif\n\n/*\n * LZ4_ACCELERATION_DEFAULT :\n * Select \"acceleration\" for LZ4_compress_fast() when parameter value <= 0\n */\n#define LZ4_ACCELERATION_DEFAULT 1\n/*\n * LZ4_ACCELERATION_MAX :\n * Any \"acceleration\" value higher than this threshold\n * get treated as LZ4_ACCELERATION_MAX instead (fix #876)\n */\n#define LZ4_ACCELERATION_MAX 65537\n\n\n/*-************************************\n*  CPU Feature Detection\n**************************************/\n/* LZ4_FORCE_MEMORY_ACCESS\n * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.\n * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.\n * The below switch allow to select different access method for improved performance.\n * Method 0 (default) : use `memcpy()`. Safe and portable.\n * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).\n *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.\n * Method 2 : direct access. This method is portable but violate C standard.\n *            It can generate buggy code on targets which assembly generation depends on alignment.\n *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)\n * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details.\n * Prefer these methods in priority order (0 > 1 > 2)\n */\n#ifndef LZ4_FORCE_MEMORY_ACCESS   /* can be defined externally */\n#  if defined(__GNUC__) && \\\n  ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \\\n  || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )\n#    define LZ4_FORCE_MEMORY_ACCESS 2\n#  elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__)\n#    define LZ4_FORCE_MEMORY_ACCESS 1\n#  endif\n#endif\n\n/*\n * LZ4_FORCE_SW_BITCOUNT\n * Define this parameter if your target system or compiler does not support hardware bit count\n */\n#if defined(_MSC_VER) && defined(_WIN32_WCE)   /* Visual Studio for WinCE doesn't support Hardware bit count */\n#  undef  LZ4_FORCE_SW_BITCOUNT  /* avoid double def */\n#  define LZ4_FORCE_SW_BITCOUNT\n#endif\n\n\n\n/*-************************************\n*  Dependency\n**************************************/\n/*\n * LZ4_SRC_INCLUDED:\n * Amalgamation flag, whether lz4.c is included\n */\n#ifndef LZ4_SRC_INCLUDED\n#  define LZ4_SRC_INCLUDED 1\n#endif\n\n#ifndef LZ4_STATIC_LINKING_ONLY\n#define LZ4_STATIC_LINKING_ONLY\n#endif\n\n#ifndef LZ4_DISABLE_DEPRECATE_WARNINGS\n#define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */\n#endif\n\n#define LZ4_STATIC_LINKING_ONLY  /* LZ4_DISTANCE_MAX */\n#include \"lz4.h\"\n/* see also \"memory routines\" below */\n\n\n/*-************************************\n*  Compiler Options\n**************************************/\n#if defined(_MSC_VER) && (_MSC_VER >= 1400)  /* Visual Studio 2005+ */\n#  include <intrin.h>               /* only present in VS2005+ */\n#  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */\n#  pragma warning(disable : 6237)   /* disable: C6237: conditional expression is always 0 */\n#endif  /* _MSC_VER */\n\n#ifndef LZ4_FORCE_INLINE\n#  ifdef _MSC_VER    /* Visual Studio */\n#    define LZ4_FORCE_INLINE static __forceinline\n#  else\n#    if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */\n#      ifdef __GNUC__\n#        define LZ4_FORCE_INLINE static inline __attribute__((always_inline))\n#      else\n#        define LZ4_FORCE_INLINE static inline\n#      endif\n#    else\n#      define LZ4_FORCE_INLINE static\n#    endif /* __STDC_VERSION__ */\n#  endif  /* _MSC_VER */\n#endif /* LZ4_FORCE_INLINE */\n\n/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE\n * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8,\n * together with a simple 8-byte copy loop as a fall-back path.\n * However, this optimization hurts the decompression speed by >30%,\n * because the execution does not go to the optimized loop\n * for typical compressible data, and all of the preamble checks\n * before going to the fall-back path become useless overhead.\n * This optimization happens only with the -O3 flag, and -O2 generates\n * a simple 8-byte copy loop.\n * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8\n * functions are annotated with __attribute__((optimize(\"O2\"))),\n * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute\n * of LZ4_wildCopy8 does not affect the compression speed.\n */\n#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__)\n#  define LZ4_FORCE_O2  __attribute__((optimize(\"O2\")))\n#  undef LZ4_FORCE_INLINE\n#  define LZ4_FORCE_INLINE  static __inline __attribute__((optimize(\"O2\"),always_inline))\n#else\n#  define LZ4_FORCE_O2\n#endif\n\n#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)\n#  define expect(expr,value)    (__builtin_expect ((expr),(value)) )\n#else\n#  define expect(expr,value)    (expr)\n#endif\n\n#ifndef likely\n#define likely(expr)     expect((expr) != 0, 1)\n#endif\n#ifndef unlikely\n#define unlikely(expr)   expect((expr) != 0, 0)\n#endif\n\n/* Should the alignment test prove unreliable, for some reason,\n * it can be disabled by setting LZ4_ALIGN_TEST to 0 */\n#ifndef LZ4_ALIGN_TEST  /* can be externally provided */\n# define LZ4_ALIGN_TEST 1\n#endif\n\n\n/*-************************************\n*  Memory routines\n**************************************/\n\n/*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION :\n *  Disable relatively high-level LZ4/HC functions that use dynamic memory\n *  allocation functions (malloc(), calloc(), free()).\n *\n *  Note that this is a compile-time switch. And since it disables\n *  public/stable LZ4 v1 API functions, we don't recommend using this\n *  symbol to generate a library for distribution.\n *\n *  The following public functions are removed when this symbol is defined.\n *  - lz4   : LZ4_createStream, LZ4_freeStream,\n *            LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create (deprecated)\n *  - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC,\n *            LZ4_createHC (deprecated), LZ4_freeHC  (deprecated)\n *  - lz4frame, lz4file : All LZ4F_* functions\n */\n#if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\n#  define ALLOC(s)          lz4_error_memory_allocation_is_disabled\n#  define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled\n#  define FREEMEM(p)        lz4_error_memory_allocation_is_disabled\n#elif defined(LZ4_USER_MEMORY_FUNCTIONS)\n/* memory management functions can be customized by user project.\n * Below functions must exist somewhere in the Project\n * and be available at link time */\nvoid* LZ4_malloc(size_t s);\nvoid* LZ4_calloc(size_t n, size_t s);\nvoid  LZ4_free(void* p);\n# define ALLOC(s)          LZ4_malloc(s)\n# define ALLOC_AND_ZERO(s) LZ4_calloc(1,s)\n# define FREEMEM(p)        LZ4_free(p)\n#else\n# include <stdlib.h>   /* malloc, calloc, free */\n# define ALLOC(s)          malloc(s)\n# define ALLOC_AND_ZERO(s) calloc(1,s)\n# define FREEMEM(p)        free(p)\n#endif\n\n#if ! LZ4_FREESTANDING\n#  include <string.h>   /* memset, memcpy */\n#endif\n#if !defined(LZ4_memset)\n#  define LZ4_memset(p,v,s) memset((p),(v),(s))\n#endif\n#define MEM_INIT(p,v,s)   LZ4_memset((p),(v),(s))\n\n\n/*-************************************\n*  Common Constants\n**************************************/\n#define MINMATCH 4\n\n#define WILDCOPYLENGTH 8\n#define LASTLITERALS   5   /* see ../doc/lz4_Block_format.md#parsing-restrictions */\n#define MFLIMIT       12   /* see ../doc/lz4_Block_format.md#parsing-restrictions */\n#define MATCH_SAFEGUARD_DISTANCE  ((2*WILDCOPYLENGTH) - MINMATCH)   /* ensure it's possible to write 2 x wildcopyLength without overflowing output buffer */\n#define FASTLOOP_SAFE_DISTANCE 64\nstatic const int LZ4_minLength = (MFLIMIT+1);\n\n#define KB *(1 <<10)\n#define MB *(1 <<20)\n#define GB *(1U<<30)\n\n#define LZ4_DISTANCE_ABSOLUTE_MAX 65535\n#if (LZ4_DISTANCE_MAX > LZ4_DISTANCE_ABSOLUTE_MAX)   /* max supported by LZ4 format */\n#  error \"LZ4_DISTANCE_MAX is too big : must be <= 65535\"\n#endif\n\n#define ML_BITS  4\n#define ML_MASK  ((1U<<ML_BITS)-1)\n#define RUN_BITS (8-ML_BITS)\n#define RUN_MASK ((1U<<RUN_BITS)-1)\n\n\n/*-************************************\n*  Error detection\n**************************************/\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)\n#  include <assert.h>\n#else\n#  ifndef assert\n#    define assert(condition) ((void)0)\n#  endif\n#endif\n\n#define LZ4_STATIC_ASSERT(c)   { enum { LZ4_static_assert = 1/(int)(!!(c)) }; }   /* use after variable declarations */\n\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2)\n#  include <stdio.h>\n   static int g_debuglog_enable = 1;\n#  define DEBUGLOG(l, ...) {                          \\\n        if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \\\n            fprintf(stderr, __FILE__  \" %i: \", __LINE__); \\\n            fprintf(stderr, __VA_ARGS__);             \\\n            fprintf(stderr, \" \\n\");                   \\\n    }   }\n#else\n#  define DEBUGLOG(l, ...) {}    /* disabled */\n#endif\n\nstatic int LZ4_isAligned(const void* ptr, size_t alignment)\n{\n    return ((size_t)ptr & (alignment -1)) == 0;\n}\n\n\n/*-************************************\n*  Types\n**************************************/\n#include <limits.h>\n#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n# include <stdint.h>\n  typedef  uint8_t BYTE;\n  typedef uint16_t U16;\n  typedef uint32_t U32;\n  typedef  int32_t S32;\n  typedef uint64_t U64;\n  typedef uintptr_t uptrval;\n#else\n# if UINT_MAX != 4294967295UL\n#   error \"LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4\"\n# endif\n  typedef unsigned char       BYTE;\n  typedef unsigned short      U16;\n  typedef unsigned int        U32;\n  typedef   signed int        S32;\n  typedef unsigned long long  U64;\n  typedef size_t              uptrval;   /* generally true, except OpenVMS-64 */\n#endif\n\n#if defined(__x86_64__)\n  typedef U64    reg_t;   /* 64-bits in x32 mode */\n#else\n  typedef size_t reg_t;   /* 32-bits in x32 mode */\n#endif\n\ntypedef enum {\n    notLimited = 0,\n    limitedOutput = 1,\n    fillOutput = 2\n} limitedOutput_directive;\n\n\n/*-************************************\n*  Reading and writing into memory\n**************************************/\n\n/**\n * LZ4 relies on memcpy with a constant size being inlined. In freestanding\n * environments, the compiler can't assume the implementation of memcpy() is\n * standard compliant, so it can't apply its specialized memcpy() inlining\n * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze\n * memcpy() as if it were standard compliant, so it can inline it in freestanding\n * environments. This is needed when decompressing the Linux Kernel, for example.\n */\n#if !defined(LZ4_memcpy)\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size)\n#  else\n#    define LZ4_memcpy(dst, src, size) memcpy(dst, src, size)\n#  endif\n#endif\n\n#if !defined(LZ4_memmove)\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4_memmove __builtin_memmove\n#  else\n#    define LZ4_memmove memmove\n#  endif\n#endif\n\nstatic unsigned LZ4_isLittleEndian(void)\n{\n    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental */\n    return one.c[0];\n}\n\n\n#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2)\n/* lie to the compiler about data alignment; use with caution */\n\nstatic U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; }\nstatic U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; }\nstatic reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; }\n\nstatic void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; }\nstatic void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; }\n\n#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1)\n\n/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */\n/* currently only defined for gcc and icc */\ntypedef struct { U16 u16; } __attribute__((packed)) LZ4_unalign16;\ntypedef struct { U32 u32; } __attribute__((packed)) LZ4_unalign32;\ntypedef struct { reg_t uArch; } __attribute__((packed)) LZ4_unalignST;\n\nstatic U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign16*)ptr)->u16; }\nstatic U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign32*)ptr)->u32; }\nstatic reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalignST*)ptr)->uArch; }\n\nstatic void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign16*)memPtr)->u16 = value; }\nstatic void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign32*)memPtr)->u32 = value; }\n\n#else  /* safe and portable access using memcpy() */\n\nstatic U16 LZ4_read16(const void* memPtr)\n{\n    U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic U32 LZ4_read32(const void* memPtr)\n{\n    U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic reg_t LZ4_read_ARCH(const void* memPtr)\n{\n    reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val;\n}\n\nstatic void LZ4_write16(void* memPtr, U16 value)\n{\n    LZ4_memcpy(memPtr, &value, sizeof(value));\n}\n\nstatic void LZ4_write32(void* memPtr, U32 value)\n{\n    LZ4_memcpy(memPtr, &value, sizeof(value));\n}\n\n#endif /* LZ4_FORCE_MEMORY_ACCESS */\n\n\nstatic U16 LZ4_readLE16(const void* memPtr)\n{\n    if (LZ4_isLittleEndian()) {\n        return LZ4_read16(memPtr);\n    } else {\n        const BYTE* p = (const BYTE*)memPtr;\n        return (U16)((U16)p[0] + (p[1]<<8));\n    }\n}\n\nstatic void LZ4_writeLE16(void* memPtr, U16 value)\n{\n    if (LZ4_isLittleEndian()) {\n        LZ4_write16(memPtr, value);\n    } else {\n        BYTE* p = (BYTE*)memPtr;\n        p[0] = (BYTE) value;\n        p[1] = (BYTE)(value>>8);\n    }\n}\n\n/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */\nLZ4_FORCE_INLINE\nvoid LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd)\n{\n    BYTE* d = (BYTE*)dstPtr;\n    const BYTE* s = (const BYTE*)srcPtr;\n    BYTE* const e = (BYTE*)dstEnd;\n\n    do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d<e);\n}\n\nstatic const unsigned inc32table[8] = {0, 1, 2,  1,  0,  4, 4, 4};\nstatic const int      dec64table[8] = {0, 0, 0, -1, -4,  1, 2, 3};\n\n\n#ifndef LZ4_FAST_DEC_LOOP\n#  if defined __i386__ || defined _M_IX86 || defined __x86_64__ || defined _M_X64\n#    define LZ4_FAST_DEC_LOOP 1\n#  elif defined(__aarch64__) && defined(__APPLE__)\n#    define LZ4_FAST_DEC_LOOP 1\n#  elif defined(__aarch64__) && !defined(__clang__)\n     /* On non-Apple aarch64, we disable this optimization for clang because\n      * on certain mobile chipsets, performance is reduced with clang. For\n      * more information refer to https://github.com/lz4/lz4/pull/707 */\n#    define LZ4_FAST_DEC_LOOP 1\n#  else\n#    define LZ4_FAST_DEC_LOOP 0\n#  endif\n#endif\n\n#if LZ4_FAST_DEC_LOOP\n\nLZ4_FORCE_INLINE void\nLZ4_memcpy_using_offset_base(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)\n{\n    assert(srcPtr + offset == dstPtr);\n    if (offset < 8) {\n        LZ4_write32(dstPtr, 0);   /* silence an msan warning when offset==0 */\n        dstPtr[0] = srcPtr[0];\n        dstPtr[1] = srcPtr[1];\n        dstPtr[2] = srcPtr[2];\n        dstPtr[3] = srcPtr[3];\n        srcPtr += inc32table[offset];\n        LZ4_memcpy(dstPtr+4, srcPtr, 4);\n        srcPtr -= dec64table[offset];\n        dstPtr += 8;\n    } else {\n        LZ4_memcpy(dstPtr, srcPtr, 8);\n        dstPtr += 8;\n        srcPtr += 8;\n    }\n\n    LZ4_wildCopy8(dstPtr, srcPtr, dstEnd);\n}\n\n/* customized variant of memcpy, which can overwrite up to 32 bytes beyond dstEnd\n * this version copies two times 16 bytes (instead of one time 32 bytes)\n * because it must be compatible with offsets >= 16. */\nLZ4_FORCE_INLINE void\nLZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd)\n{\n    BYTE* d = (BYTE*)dstPtr;\n    const BYTE* s = (const BYTE*)srcPtr;\n    BYTE* const e = (BYTE*)dstEnd;\n\n    do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d<e);\n}\n\n/* LZ4_memcpy_using_offset()  presumes :\n * - dstEnd >= dstPtr + MINMATCH\n * - there is at least 8 bytes available to write after dstEnd */\nLZ4_FORCE_INLINE void\nLZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset)\n{\n    BYTE v[8];\n\n    assert(dstEnd >= dstPtr + MINMATCH);\n\n    switch(offset) {\n    case 1:\n        MEM_INIT(v, *srcPtr, 8);\n        break;\n    case 2:\n        LZ4_memcpy(v, srcPtr, 2);\n        LZ4_memcpy(&v[2], srcPtr, 2);\n#if defined(_MSC_VER) && (_MSC_VER <= 1936) /* MSVC 2022 ver 17.6 or earlier */\n#  pragma warning(push)\n#  pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */\n#endif\n        LZ4_memcpy(&v[4], v, 4);\n#if defined(_MSC_VER) && (_MSC_VER <= 1936) /* MSVC 2022 ver 17.6 or earlier */\n#  pragma warning(pop)\n#endif\n        break;\n    case 4:\n        LZ4_memcpy(v, srcPtr, 4);\n        LZ4_memcpy(&v[4], srcPtr, 4);\n        break;\n    default:\n        LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset);\n        return;\n    }\n\n    LZ4_memcpy(dstPtr, v, 8);\n    dstPtr += 8;\n    while (dstPtr < dstEnd) {\n        LZ4_memcpy(dstPtr, v, 8);\n        dstPtr += 8;\n    }\n}\n#endif\n\n\n/*-************************************\n*  Common functions\n**************************************/\nstatic unsigned LZ4_NbCommonBytes (reg_t val)\n{\n    assert(val != 0);\n    if (LZ4_isLittleEndian()) {\n        if (sizeof(val) == 8) {\n#       if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT)\n/*-*************************************************************************************************\n* ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11.\n* The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics\n* including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC.\n****************************************************************************************************/\n#         if defined(__clang__) && (__clang_major__ < 10)\n            /* Avoid undefined clang-cl intrinsics issue.\n             * See https://github.com/lz4/lz4/pull/1017 for details. */\n            return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3;\n#         else\n            /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */\n            return (unsigned)_tzcnt_u64(val) >> 3;\n#         endif\n#       elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            unsigned long r = 0;\n            _BitScanForward64(&r, (U64)val);\n            return (unsigned)r >> 3;\n#       elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                                        !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_ctzll((U64)val) >> 3;\n#       else\n            const U64 m = 0x0101010101010101ULL;\n            val ^= val - 1;\n            return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56);\n#       endif\n        } else /* 32 bits */ {\n#       if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            unsigned long r;\n            _BitScanForward(&r, (U32)val);\n            return (unsigned)r >> 3;\n#       elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                        !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_ctz((U32)val) >> 3;\n#       else\n            const U32 m = 0x01010101;\n            return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24;\n#       endif\n        }\n    } else   /* Big Endian CPU */ {\n        if (sizeof(val)==8) {\n#       if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                        !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_clzll((U64)val) >> 3;\n#       else\n#if 1\n            /* this method is probably faster,\n             * but adds a 128 bytes lookup table */\n            static const unsigned char ctz7_tab[128] = {\n                7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n                4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,\n            };\n            U64 const mask = 0x0101010101010101ULL;\n            U64 const t = (((val >> 8) - mask) | val) & mask;\n            return ctz7_tab[(t * 0x0080402010080402ULL) >> 57];\n#else\n            /* this method doesn't consume memory space like the previous one,\n             * but it contains several branches,\n             * that may end up slowing execution */\n            static const U32 by32 = sizeof(val)*4;  /* 32 on 64 bits (goal), 16 on 32 bits.\n            Just to avoid some static analyzer complaining about shift by 32 on 32-bits target.\n            Note that this code path is never triggered in 32-bits mode. */\n            unsigned r;\n            if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; }\n            if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }\n            r += (!val);\n            return r;\n#endif\n#       endif\n        } else /* 32 bits */ {\n#       if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \\\n                            ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \\\n                                        !defined(LZ4_FORCE_SW_BITCOUNT)\n            return (unsigned)__builtin_clz((U32)val) >> 3;\n#       else\n            val >>= 8;\n            val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) |\n              (val + 0x00FF0000)) >> 24;\n            return (unsigned)val ^ 3;\n#       endif\n        }\n    }\n}\n\n\n#define STEPSIZE sizeof(reg_t)\nLZ4_FORCE_INLINE\nunsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit)\n{\n    const BYTE* const pStart = pIn;\n\n    if (likely(pIn < pInLimit-(STEPSIZE-1))) {\n        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);\n        if (!diff) {\n            pIn+=STEPSIZE; pMatch+=STEPSIZE;\n        } else {\n            return LZ4_NbCommonBytes(diff);\n    }   }\n\n    while (likely(pIn < pInLimit-(STEPSIZE-1))) {\n        reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);\n        if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }\n        pIn += LZ4_NbCommonBytes(diff);\n        return (unsigned)(pIn - pStart);\n    }\n\n    if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }\n    if ((pIn<(pInLimit-1)) && (LZ4_read16(pMatch) == LZ4_read16(pIn))) { pIn+=2; pMatch+=2; }\n    if ((pIn<pInLimit) && (*pMatch == *pIn)) pIn++;\n    return (unsigned)(pIn - pStart);\n}\n\n\n#ifndef LZ4_COMMONDEFS_ONLY\n/*-************************************\n*  Local Constants\n**************************************/\nstatic const int LZ4_64Klimit = ((64 KB) + (MFLIMIT-1));\nstatic const U32 LZ4_skipTrigger = 6;  /* Increase this value ==> compression run slower on incompressible data */\n\n\n/*-************************************\n*  Local Structures and types\n**************************************/\ntypedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t;\n\n/**\n * This enum distinguishes several different modes of accessing previous\n * content in the stream.\n *\n * - noDict        : There is no preceding content.\n * - withPrefix64k : Table entries up to ctx->dictSize before the current blob\n *                   blob being compressed are valid and refer to the preceding\n *                   content (of length ctx->dictSize), which is available\n *                   contiguously preceding in memory the content currently\n *                   being compressed.\n * - usingExtDict  : Like withPrefix64k, but the preceding content is somewhere\n *                   else in memory, starting at ctx->dictionary with length\n *                   ctx->dictSize.\n * - usingDictCtx  : Everything concerning the preceding content is\n *                   in a separate context, pointed to by ctx->dictCtx.\n *                   ctx->dictionary, ctx->dictSize, and table entries\n *                   in the current context that refer to positions\n *                   preceding the beginning of the current compression are\n *                   ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx\n *                   ->dictSize describe the location and size of the preceding\n *                   content, and matches are found by looking in the ctx\n *                   ->dictCtx->hashTable.\n */\ntypedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive;\ntypedef enum { noDictIssue = 0, dictSmall } dictIssue_directive;\n\n\n/*-************************************\n*  Local Utils\n**************************************/\nint LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; }\nconst char* LZ4_versionString(void) { return LZ4_VERSION_STRING; }\nint LZ4_compressBound(int isize)  { return LZ4_COMPRESSBOUND(isize); }\nint LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); }\n\n\n/*-****************************************\n*  Internal Definitions, used only in Tests\n*******************************************/\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\nint LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize);\n\nint LZ4_decompress_safe_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int maxOutputSize,\n                                     const void* dictStart, size_t dictSize);\nint LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int targetOutputSize, int dstCapacity,\n                                     const void* dictStart, size_t dictSize);\n#if defined (__cplusplus)\n}\n#endif\n\n/*-******************************\n*  Compression functions\n********************************/\nLZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType)\n{\n    if (tableType == byU16)\n        return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));\n    else\n        return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));\n}\n\nLZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType)\n{\n    const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;\n    if (LZ4_isLittleEndian()) {\n        const U64 prime5bytes = 889523592379ULL;\n        return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));\n    } else {\n        const U64 prime8bytes = 11400714785074694791ULL;\n        return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));\n    }\n}\n\nLZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)\n{\n    if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType);\n    return LZ4_hash4(LZ4_read32(p), tableType);\n}\n\nLZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType)\n{\n    switch (tableType)\n    {\n    default: /* fallthrough */\n    case clearedTable: { /* illegal! */ assert(0); return; }\n    case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; }\n    }\n}\n\nLZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType)\n{\n    switch (tableType)\n    {\n    default: /* fallthrough */\n    case clearedTable: /* fallthrough */\n    case byPtr: { /* illegal! */ assert(0); return; }\n    case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; }\n    case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; }\n    }\n}\n\n/* LZ4_putPosition*() : only used in byPtr mode */\nLZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h,\n                                  void* tableBase, tableType_t const tableType)\n{\n    const BYTE** const hashTable = (const BYTE**)tableBase;\n    assert(tableType == byPtr); (void)tableType;\n    hashTable[h] = p;\n}\n\nLZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType)\n{\n    U32 const h = LZ4_hashPosition(p, tableType);\n    LZ4_putPositionOnHash(p, h, tableBase, tableType);\n}\n\n/* LZ4_getIndexOnHash() :\n * Index of match position registered in hash table.\n * hash position must be calculated by using base+index, or dictBase+index.\n * Assumption 1 : only valid if tableType == byU32 or byU16.\n * Assumption 2 : h is presumed valid (within limits of hash table)\n */\nLZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType)\n{\n    LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2);\n    if (tableType == byU32) {\n        const U32* const hashTable = (const U32*) tableBase;\n        assert(h < (1U << (LZ4_MEMORY_USAGE-2)));\n        return hashTable[h];\n    }\n    if (tableType == byU16) {\n        const U16* const hashTable = (const U16*) tableBase;\n        assert(h < (1U << (LZ4_MEMORY_USAGE-1)));\n        return hashTable[h];\n    }\n    assert(0); return 0;  /* forbidden case */\n}\n\nstatic const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType)\n{\n    assert(tableType == byPtr); (void)tableType;\n    { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; }\n}\n\nLZ4_FORCE_INLINE const BYTE*\nLZ4_getPosition(const BYTE* p,\n                const void* tableBase, tableType_t tableType)\n{\n    U32 const h = LZ4_hashPosition(p, tableType);\n    return LZ4_getPositionOnHash(h, tableBase, tableType);\n}\n\nLZ4_FORCE_INLINE void\nLZ4_prepareTable(LZ4_stream_t_internal* const cctx,\n           const int inputSize,\n           const tableType_t tableType) {\n    /* If the table hasn't been used, it's guaranteed to be zeroed out, and is\n     * therefore safe to use no matter what mode we're in. Otherwise, we figure\n     * out if it's safe to leave as is or whether it needs to be reset.\n     */\n    if ((tableType_t)cctx->tableType != clearedTable) {\n        assert(inputSize >= 0);\n        if ((tableType_t)cctx->tableType != tableType\n          || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU)\n          || ((tableType == byU32) && cctx->currentOffset > 1 GB)\n          || tableType == byPtr\n          || inputSize >= 4 KB)\n        {\n            DEBUGLOG(4, \"LZ4_prepareTable: Resetting table in %p\", cctx);\n            MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE);\n            cctx->currentOffset = 0;\n            cctx->tableType = (U32)clearedTable;\n        } else {\n            DEBUGLOG(4, \"LZ4_prepareTable: Re-use hash table (no reset)\");\n        }\n    }\n\n    /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back,\n     * is faster than compressing without a gap.\n     * However, compressing with currentOffset == 0 is faster still,\n     * so we preserve that case.\n     */\n    if (cctx->currentOffset != 0 && tableType == byU32) {\n        DEBUGLOG(5, \"LZ4_prepareTable: adding 64KB to currentOffset\");\n        cctx->currentOffset += 64 KB;\n    }\n\n    /* Finally, clear history */\n    cctx->dictCtx = NULL;\n    cctx->dictionary = NULL;\n    cctx->dictSize = 0;\n}\n\n/** LZ4_compress_generic() :\n *  inlined, to ensure branches are decided at compilation time.\n *  The following conditions are presumed already validated:\n *  - source != NULL\n *  - inputSize > 0\n */\nLZ4_FORCE_INLINE int LZ4_compress_generic_validated(\n                 LZ4_stream_t_internal* const cctx,\n                 const char* const source,\n                 char* const dest,\n                 const int inputSize,\n                 int*  inputConsumed, /* only written when outputDirective == fillOutput */\n                 const int maxOutputSize,\n                 const limitedOutput_directive outputDirective,\n                 const tableType_t tableType,\n                 const dict_directive dictDirective,\n                 const dictIssue_directive dictIssue,\n                 const int acceleration)\n{\n    int result;\n    const BYTE* ip = (const BYTE*)source;\n\n    U32 const startIndex = cctx->currentOffset;\n    const BYTE* base = (const BYTE*)source - startIndex;\n    const BYTE* lowLimit;\n\n    const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx;\n    const BYTE* const dictionary =\n        dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary;\n    const U32 dictSize =\n        dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize;\n    const U32 dictDelta =\n        (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0;   /* make indexes in dictCtx comparable with indexes in current context */\n\n    int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx);\n    U32 const prefixIdxLimit = startIndex - dictSize;   /* used when dictDirective == dictSmall */\n    const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary;\n    const BYTE* anchor = (const BYTE*) source;\n    const BYTE* const iend = ip + inputSize;\n    const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1;\n    const BYTE* const matchlimit = iend - LASTLITERALS;\n\n    /* the dictCtx currentOffset is indexed on the start of the dictionary,\n     * while a dictionary in the current context precedes the currentOffset */\n    const BYTE* dictBase = (dictionary == NULL) ? NULL :\n                           (dictDirective == usingDictCtx) ?\n                            dictionary + dictSize - dictCtx->currentOffset :\n                            dictionary + dictSize - startIndex;\n\n    BYTE* op = (BYTE*) dest;\n    BYTE* const olimit = op + maxOutputSize;\n\n    U32 offset = 0;\n    U32 forwardH;\n\n    DEBUGLOG(5, \"LZ4_compress_generic_validated: srcSize=%i, tableType=%u\", inputSize, tableType);\n    assert(ip != NULL);\n    if (tableType == byU16) assert(inputSize<LZ4_64Klimit);  /* Size too large (not within 64K limit) */\n    if (tableType == byPtr) assert(dictDirective==noDict);   /* only supported use case with byPtr */\n    /* If init conditions are not met, we don't have to mark stream\n     * as having dirty context, since no action was taken yet */\n    if (outputDirective == fillOutput && maxOutputSize < 1) { return 0; } /* Impossible to store anything */\n    assert(acceleration >= 1);\n\n    lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0);\n\n    /* Update context state */\n    if (dictDirective == usingDictCtx) {\n        /* Subsequent linked blocks can't use the dictionary. */\n        /* Instead, they use the block we just compressed. */\n        cctx->dictCtx = NULL;\n        cctx->dictSize = (U32)inputSize;\n    } else {\n        cctx->dictSize += (U32)inputSize;\n    }\n    cctx->currentOffset += (U32)inputSize;\n    cctx->tableType = (U32)tableType;\n\n    if (inputSize<LZ4_minLength) goto _last_literals;        /* Input too small, no compression (all literals) */\n\n    /* First Byte */\n    {   U32 const h = LZ4_hashPosition(ip, tableType);\n        if (tableType == byPtr) {\n            LZ4_putPositionOnHash(ip, h, cctx->hashTable, byPtr);\n        } else {\n            LZ4_putIndexOnHash(startIndex, h, cctx->hashTable, tableType);\n    }   }\n    ip++; forwardH = LZ4_hashPosition(ip, tableType);\n\n    /* Main Loop */\n    for ( ; ; ) {\n        const BYTE* match;\n        BYTE* token;\n        const BYTE* filledIp;\n\n        /* Find a match */\n        if (tableType == byPtr) {\n            const BYTE* forwardIp = ip;\n            int step = 1;\n            int searchMatchNb = acceleration << LZ4_skipTrigger;\n            do {\n                U32 const h = forwardH;\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;\n                assert(ip < mflimitPlusOne);\n\n                match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType);\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType);\n\n            } while ( (match+LZ4_DISTANCE_MAX < ip)\n                   || (LZ4_read32(match) != LZ4_read32(ip)) );\n\n        } else {   /* byU32, byU16 */\n\n            const BYTE* forwardIp = ip;\n            int step = 1;\n            int searchMatchNb = acceleration << LZ4_skipTrigger;\n            do {\n                U32 const h = forwardH;\n                U32 const current = (U32)(forwardIp - base);\n                U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);\n                assert(matchIndex <= current);\n                assert(forwardIp - base < (ptrdiff_t)(2 GB - 1));\n                ip = forwardIp;\n                forwardIp += step;\n                step = (searchMatchNb++ >> LZ4_skipTrigger);\n\n                if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals;\n                assert(ip < mflimitPlusOne);\n\n                if (dictDirective == usingDictCtx) {\n                    if (matchIndex < startIndex) {\n                        /* there was no match, try the dictionary */\n                        assert(tableType == byU32);\n                        matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);\n                        match = dictBase + matchIndex;\n                        matchIndex += dictDelta;   /* make dictCtx index comparable with current context */\n                        lowLimit = dictionary;\n                    } else {\n                        match = base + matchIndex;\n                        lowLimit = (const BYTE*)source;\n                    }\n                } else if (dictDirective == usingExtDict) {\n                    if (matchIndex < startIndex) {\n                        DEBUGLOG(7, \"extDict candidate: matchIndex=%5u  <  startIndex=%5u\", matchIndex, startIndex);\n                        assert(startIndex - matchIndex >= MINMATCH);\n                        assert(dictBase);\n                        match = dictBase + matchIndex;\n                        lowLimit = dictionary;\n                    } else {\n                        match = base + matchIndex;\n                        lowLimit = (const BYTE*)source;\n                    }\n                } else {   /* single continuous memory segment */\n                    match = base + matchIndex;\n                }\n                forwardH = LZ4_hashPosition(forwardIp, tableType);\n                LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);\n\n                DEBUGLOG(7, \"candidate at pos=%u  (offset=%u \\n\", matchIndex, current - matchIndex);\n                if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; }    /* match outside of valid area */\n                assert(matchIndex < current);\n                if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX))\n                  && (matchIndex+LZ4_DISTANCE_MAX < current)) {\n                    continue;\n                } /* too far */\n                assert((current - matchIndex) <= LZ4_DISTANCE_MAX);  /* match now expected within distance */\n\n                if (LZ4_read32(match) == LZ4_read32(ip)) {\n                    if (maybe_extMem) offset = current - matchIndex;\n                    break;   /* match found */\n                }\n\n            } while(1);\n        }\n\n        /* Catch up */\n        filledIp = ip;\n        while (((ip>anchor) & (match > lowLimit)) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; }\n\n        /* Encode Literals */\n        {   unsigned const litLength = (unsigned)(ip - anchor);\n            token = op++;\n            if ((outputDirective == limitedOutput) &&  /* Check output buffer overflow */\n                (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)) ) {\n                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */\n            }\n            if ((outputDirective == fillOutput) &&\n                (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) {\n                op--;\n                goto _last_literals;\n            }\n            if (litLength >= RUN_MASK) {\n                int len = (int)(litLength - RUN_MASK);\n                *token = (RUN_MASK<<ML_BITS);\n                for(; len >= 255 ; len-=255) *op++ = 255;\n                *op++ = (BYTE)len;\n            }\n            else *token = (BYTE)(litLength<<ML_BITS);\n\n            /* Copy Literals */\n            LZ4_wildCopy8(op, anchor, op+litLength);\n            op+=litLength;\n            DEBUGLOG(6, \"seq.start:%i, literals=%u, match.start:%i\",\n                        (int)(anchor-(const BYTE*)source), litLength, (int)(ip-(const BYTE*)source));\n        }\n\n_next_match:\n        /* at this stage, the following variables must be correctly set :\n         * - ip : at start of LZ operation\n         * - match : at start of previous pattern occurrence; can be within current prefix, or within extDict\n         * - offset : if maybe_ext_memSegment==1 (constant)\n         * - lowLimit : must be == dictionary to mean \"match is within extDict\"; must be == source otherwise\n         * - token and *token : position to write 4-bits for match length; higher 4-bits for literal length supposed already written\n         */\n\n        if ((outputDirective == fillOutput) &&\n            (op + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit)) {\n            /* the match was too close to the end, rewind and go to last literals */\n            op = token;\n            goto _last_literals;\n        }\n\n        /* Encode Offset */\n        if (maybe_extMem) {   /* static test */\n            DEBUGLOG(6, \"             with offset=%u  (ext if > %i)\", offset, (int)(ip - (const BYTE*)source));\n            assert(offset <= LZ4_DISTANCE_MAX && offset > 0);\n            LZ4_writeLE16(op, (U16)offset); op+=2;\n        } else  {\n            DEBUGLOG(6, \"             with offset=%u  (same segment)\", (U32)(ip - match));\n            assert(ip-match <= LZ4_DISTANCE_MAX);\n            LZ4_writeLE16(op, (U16)(ip - match)); op+=2;\n        }\n\n        /* Encode MatchLength */\n        {   unsigned matchCode;\n\n            if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx)\n              && (lowLimit==dictionary) /* match within extDict */ ) {\n                const BYTE* limit = ip + (dictEnd-match);\n                assert(dictEnd > match);\n                if (limit > matchlimit) limit = matchlimit;\n                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);\n                ip += (size_t)matchCode + MINMATCH;\n                if (ip==limit) {\n                    unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit);\n                    matchCode += more;\n                    ip += more;\n                }\n                DEBUGLOG(6, \"             with matchLength=%u starting in extDict\", matchCode+MINMATCH);\n            } else {\n                matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);\n                ip += (size_t)matchCode + MINMATCH;\n                DEBUGLOG(6, \"             with matchLength=%u\", matchCode+MINMATCH);\n            }\n\n            if ((outputDirective) &&    /* Check output buffer overflow */\n                (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) {\n                if (outputDirective == fillOutput) {\n                    /* Match description too long : reduce it */\n                    U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255;\n                    ip -= matchCode - newMatchCode;\n                    assert(newMatchCode < matchCode);\n                    matchCode = newMatchCode;\n                    if (unlikely(ip <= filledIp)) {\n                        /* We have already filled up to filledIp so if ip ends up less than filledIp\n                         * we have positions in the hash table beyond the current position. This is\n                         * a problem if we reuse the hash table. So we have to remove these positions\n                         * from the hash table.\n                         */\n                        const BYTE* ptr;\n                        DEBUGLOG(5, \"Clearing %u positions\", (U32)(filledIp - ip));\n                        for (ptr = ip; ptr <= filledIp; ++ptr) {\n                            U32 const h = LZ4_hashPosition(ptr, tableType);\n                            LZ4_clearHash(h, cctx->hashTable, tableType);\n                        }\n                    }\n                } else {\n                    assert(outputDirective == limitedOutput);\n                    return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */\n                }\n            }\n            if (matchCode >= ML_MASK) {\n                *token += ML_MASK;\n                matchCode -= ML_MASK;\n                LZ4_write32(op, 0xFFFFFFFF);\n                while (matchCode >= 4*255) {\n                    op+=4;\n                    LZ4_write32(op, 0xFFFFFFFF);\n                    matchCode -= 4*255;\n                }\n                op += matchCode / 255;\n                *op++ = (BYTE)(matchCode % 255);\n            } else\n                *token += (BYTE)(matchCode);\n        }\n        /* Ensure we have enough space for the last literals. */\n        assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit));\n\n        anchor = ip;\n\n        /* Test end of chunk */\n        if (ip >= mflimitPlusOne) break;\n\n        /* Fill table */\n        {   U32 const h = LZ4_hashPosition(ip-2, tableType);\n            if (tableType == byPtr) {\n                LZ4_putPositionOnHash(ip-2, h, cctx->hashTable, byPtr);\n            } else {\n                U32 const idx = (U32)((ip-2) - base);\n                LZ4_putIndexOnHash(idx, h, cctx->hashTable, tableType);\n        }   }\n\n        /* Test next position */\n        if (tableType == byPtr) {\n\n            match = LZ4_getPosition(ip, cctx->hashTable, tableType);\n            LZ4_putPosition(ip, cctx->hashTable, tableType);\n            if ( (match+LZ4_DISTANCE_MAX >= ip)\n              && (LZ4_read32(match) == LZ4_read32(ip)) )\n            { token=op++; *token=0; goto _next_match; }\n\n        } else {   /* byU32, byU16 */\n\n            U32 const h = LZ4_hashPosition(ip, tableType);\n            U32 const current = (U32)(ip-base);\n            U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType);\n            assert(matchIndex < current);\n            if (dictDirective == usingDictCtx) {\n                if (matchIndex < startIndex) {\n                    /* there was no match, try the dictionary */\n                    assert(tableType == byU32);\n                    matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32);\n                    match = dictBase + matchIndex;\n                    lowLimit = dictionary;   /* required for match length counter */\n                    matchIndex += dictDelta;\n                } else {\n                    match = base + matchIndex;\n                    lowLimit = (const BYTE*)source;  /* required for match length counter */\n                }\n            } else if (dictDirective==usingExtDict) {\n                if (matchIndex < startIndex) {\n                    assert(dictBase);\n                    match = dictBase + matchIndex;\n                    lowLimit = dictionary;   /* required for match length counter */\n                } else {\n                    match = base + matchIndex;\n                    lowLimit = (const BYTE*)source;   /* required for match length counter */\n                }\n            } else {   /* single memory segment */\n                match = base + matchIndex;\n            }\n            LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType);\n            assert(matchIndex < current);\n            if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1)\n              && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current))\n              && (LZ4_read32(match) == LZ4_read32(ip)) ) {\n                token=op++;\n                *token=0;\n                if (maybe_extMem) offset = current - matchIndex;\n                DEBUGLOG(6, \"seq.start:%i, literals=%u, match.start:%i\",\n                            (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source));\n                goto _next_match;\n            }\n        }\n\n        /* Prepare next loop */\n        forwardH = LZ4_hashPosition(++ip, tableType);\n\n    }\n\n_last_literals:\n    /* Encode Last Literals */\n    {   size_t lastRun = (size_t)(iend - anchor);\n        if ( (outputDirective) &&  /* Check output buffer overflow */\n            (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) {\n            if (outputDirective == fillOutput) {\n                /* adapt lastRun to fill 'dst' */\n                assert(olimit >= op);\n                lastRun  = (size_t)(olimit-op) - 1/*token*/;\n                lastRun -= (lastRun + 256 - RUN_MASK) / 256;  /*additional length tokens*/\n            } else {\n                assert(outputDirective == limitedOutput);\n                return 0;   /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */\n            }\n        }\n        DEBUGLOG(6, \"Final literal run : %i literals\", (int)lastRun);\n        if (lastRun >= RUN_MASK) {\n            size_t accumulator = lastRun - RUN_MASK;\n            *op++ = RUN_MASK << ML_BITS;\n            for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;\n            *op++ = (BYTE) accumulator;\n        } else {\n            *op++ = (BYTE)(lastRun<<ML_BITS);\n        }\n        LZ4_memcpy(op, anchor, lastRun);\n        ip = anchor + lastRun;\n        op += lastRun;\n    }\n\n    if (outputDirective == fillOutput) {\n        *inputConsumed = (int) (((const char*)ip)-source);\n    }\n    result = (int)(((char*)op) - dest);\n    assert(result > 0);\n    DEBUGLOG(5, \"LZ4_compress_generic: compressed %i bytes into %i bytes\", inputSize, result);\n    return result;\n}\n\n/** LZ4_compress_generic() :\n *  inlined, to ensure branches are decided at compilation time;\n *  takes care of src == (NULL, 0)\n *  and forward the rest to LZ4_compress_generic_validated */\nLZ4_FORCE_INLINE int LZ4_compress_generic(\n                 LZ4_stream_t_internal* const cctx,\n                 const char* const src,\n                 char* const dst,\n                 const int srcSize,\n                 int *inputConsumed, /* only written when outputDirective == fillOutput */\n                 const int dstCapacity,\n                 const limitedOutput_directive outputDirective,\n                 const tableType_t tableType,\n                 const dict_directive dictDirective,\n                 const dictIssue_directive dictIssue,\n                 const int acceleration)\n{\n    DEBUGLOG(5, \"LZ4_compress_generic: srcSize=%i, dstCapacity=%i\",\n                srcSize, dstCapacity);\n\n    if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; }  /* Unsupported srcSize, too large (or negative) */\n    if (srcSize == 0) {   /* src == NULL supported if srcSize == 0 */\n        if (outputDirective != notLimited && dstCapacity <= 0) return 0;  /* no output, can't write anything */\n        DEBUGLOG(5, \"Generating an empty block\");\n        assert(outputDirective == notLimited || dstCapacity >= 1);\n        assert(dst != NULL);\n        dst[0] = 0;\n        if (outputDirective == fillOutput) {\n            assert (inputConsumed != NULL);\n            *inputConsumed = 0;\n        }\n        return 1;\n    }\n    assert(src != NULL);\n\n    return LZ4_compress_generic_validated(cctx, src, dst, srcSize,\n                inputConsumed, /* only written into if outputDirective == fillOutput */\n                dstCapacity, outputDirective,\n                tableType, dictDirective, dictIssue, acceleration);\n}\n\n\nint LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration)\n{\n    LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse;\n    assert(ctx != NULL);\n    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;\n    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;\n    if (maxOutputSize >= LZ4_compressBound(inputSize)) {\n        if (inputSize < LZ4_64Klimit) {\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration);\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n        }\n    } else {\n        if (inputSize < LZ4_64Klimit) {\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n        }\n    }\n}\n\n/**\n * LZ4_compress_fast_extState_fastReset() :\n * A variant of LZ4_compress_fast_extState().\n *\n * Using this variant avoids an expensive initialization step. It is only safe\n * to call if the state buffer is known to be correctly initialized already\n * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of\n * \"correctly initialized\").\n */\nint LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration)\n{\n    LZ4_stream_t_internal* const ctx = &((LZ4_stream_t*)state)->internal_donotuse;\n    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;\n    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;\n    assert(ctx != NULL);\n\n    if (dstCapacity >= LZ4_compressBound(srcSize)) {\n        if (srcSize < LZ4_64Klimit) {\n            const tableType_t tableType = byU16;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            if (ctx->currentOffset) {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration);\n            } else {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n            }\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration);\n        }\n    } else {\n        if (srcSize < LZ4_64Klimit) {\n            const tableType_t tableType = byU16;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            if (ctx->currentOffset) {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration);\n            } else {\n                return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n            }\n        } else {\n            const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            LZ4_prepareTable(ctx, srcSize, tableType);\n            return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration);\n        }\n    }\n}\n\n\nint LZ4_compress_fast(const char* src, char* dest, int srcSize, int dstCapacity, int acceleration)\n{\n    int result;\n#if (LZ4_HEAPMODE)\n    LZ4_stream_t* const ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */\n    if (ctxPtr == NULL) return 0;\n#else\n    LZ4_stream_t ctx;\n    LZ4_stream_t* const ctxPtr = &ctx;\n#endif\n    result = LZ4_compress_fast_extState(ctxPtr, src, dest, srcSize, dstCapacity, acceleration);\n\n#if (LZ4_HEAPMODE)\n    FREEMEM(ctxPtr);\n#endif\n    return result;\n}\n\n\nint LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity)\n{\n    return LZ4_compress_fast(src, dst, srcSize, dstCapacity, 1);\n}\n\n\n/* Note!: This function leaves the stream in an unclean/broken state!\n * It is not safe to subsequently use the same state with a _fastReset() or\n * _continue() call without resetting it. */\nstatic int LZ4_compress_destSize_extState (LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize)\n{\n    void* const s = LZ4_initStream(state, sizeof (*state));\n    assert(s != NULL); (void)s;\n\n    if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) {  /* compression success is guaranteed */\n        return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1);\n    } else {\n        if (*srcSizePtr < LZ4_64Klimit) {\n            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, 1);\n        } else {\n            tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32;\n            return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, 1);\n    }   }\n}\n\n\nint LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize)\n{\n#if (LZ4_HEAPMODE)\n    LZ4_stream_t* const ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));   /* malloc-calloc always properly aligned */\n    if (ctx == NULL) return 0;\n#else\n    LZ4_stream_t ctxBody;\n    LZ4_stream_t* const ctx = &ctxBody;\n#endif\n\n    int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize);\n\n#if (LZ4_HEAPMODE)\n    FREEMEM(ctx);\n#endif\n    return result;\n}\n\n\n\n/*-******************************\n*  Streaming functions\n********************************/\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_stream_t* LZ4_createStream(void)\n{\n    LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t));\n    LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal));\n    DEBUGLOG(4, \"LZ4_createStream %p\", lz4s);\n    if (lz4s == NULL) return NULL;\n    LZ4_initStream(lz4s, sizeof(*lz4s));\n    return lz4s;\n}\n#endif\n\nstatic size_t LZ4_stream_t_alignment(void)\n{\n#if LZ4_ALIGN_TEST\n    typedef struct { char c; LZ4_stream_t t; } t_a;\n    return sizeof(t_a) - sizeof(LZ4_stream_t);\n#else\n    return 1;  /* effectively disabled */\n#endif\n}\n\nLZ4_stream_t* LZ4_initStream (void* buffer, size_t size)\n{\n    DEBUGLOG(5, \"LZ4_initStream\");\n    if (buffer == NULL) { return NULL; }\n    if (size < sizeof(LZ4_stream_t)) { return NULL; }\n    if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL;\n    MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal));\n    return (LZ4_stream_t*)buffer;\n}\n\n/* resetStream is now deprecated,\n * prefer initStream() which is more general */\nvoid LZ4_resetStream (LZ4_stream_t* LZ4_stream)\n{\n    DEBUGLOG(5, \"LZ4_resetStream (ctx:%p)\", LZ4_stream);\n    MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal));\n}\n\nvoid LZ4_resetStream_fast(LZ4_stream_t* ctx) {\n    LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32);\n}\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nint LZ4_freeStream (LZ4_stream_t* LZ4_stream)\n{\n    if (!LZ4_stream) return 0;   /* support free on NULL */\n    DEBUGLOG(5, \"LZ4_freeStream %p\", LZ4_stream);\n    FREEMEM(LZ4_stream);\n    return (0);\n}\n#endif\n\n\n#define HASH_UNIT sizeof(reg_t)\nint LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize)\n{\n    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;\n    const tableType_t tableType = byU32;\n    const BYTE* p = (const BYTE*)dictionary;\n    const BYTE* const dictEnd = p + dictSize;\n    U32 idx32;\n\n    DEBUGLOG(4, \"LZ4_loadDict (%i bytes from %p into %p)\", dictSize, dictionary, LZ4_dict);\n\n    /* It's necessary to reset the context,\n     * and not just continue it with prepareTable()\n     * to avoid any risk of generating overflowing matchIndex\n     * when compressing using this dictionary */\n    LZ4_resetStream(LZ4_dict);\n\n    /* We always increment the offset by 64 KB, since, if the dict is longer,\n     * we truncate it to the last 64k, and if it's shorter, we still want to\n     * advance by a whole window length so we can provide the guarantee that\n     * there are only valid offsets in the window, which allows an optimization\n     * in LZ4_compress_fast_continue() where it uses noDictIssue even when the\n     * dictionary isn't a full 64k. */\n    dict->currentOffset += 64 KB;\n\n    if (dictSize < (int)HASH_UNIT) {\n        return 0;\n    }\n\n    if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB;\n    dict->dictionary = p;\n    dict->dictSize = (U32)(dictEnd - p);\n    dict->tableType = (U32)tableType;\n    idx32 = dict->currentOffset - dict->dictSize;\n\n    while (p <= dictEnd-HASH_UNIT) {\n        U32 const h = LZ4_hashPosition(p, tableType);\n        LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType);\n        p+=3; idx32+=3;\n    }\n\n    return (int)dict->dictSize;\n}\n\nvoid LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream)\n{\n    const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL :\n        &(dictionaryStream->internal_donotuse);\n\n    DEBUGLOG(4, \"LZ4_attach_dictionary (%p, %p, size %u)\",\n             workingStream, dictionaryStream,\n             dictCtx != NULL ? dictCtx->dictSize : 0);\n\n    if (dictCtx != NULL) {\n        /* If the current offset is zero, we will never look in the\n         * external dictionary context, since there is no value a table\n         * entry can take that indicate a miss. In that case, we need\n         * to bump the offset to something non-zero.\n         */\n        if (workingStream->internal_donotuse.currentOffset == 0) {\n            workingStream->internal_donotuse.currentOffset = 64 KB;\n        }\n\n        /* Don't actually attach an empty dictionary.\n         */\n        if (dictCtx->dictSize == 0) {\n            dictCtx = NULL;\n        }\n    }\n    workingStream->internal_donotuse.dictCtx = dictCtx;\n}\n\n\nstatic void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize)\n{\n    assert(nextSize >= 0);\n    if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) {   /* potential ptrdiff_t overflow (32-bits mode) */\n        /* rescale hash table */\n        U32 const delta = LZ4_dict->currentOffset - 64 KB;\n        const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize;\n        int i;\n        DEBUGLOG(4, \"LZ4_renormDictT\");\n        for (i=0; i<LZ4_HASH_SIZE_U32; i++) {\n            if (LZ4_dict->hashTable[i] < delta) LZ4_dict->hashTable[i]=0;\n            else LZ4_dict->hashTable[i] -= delta;\n        }\n        LZ4_dict->currentOffset = 64 KB;\n        if (LZ4_dict->dictSize > 64 KB) LZ4_dict->dictSize = 64 KB;\n        LZ4_dict->dictionary = dictEnd - LZ4_dict->dictSize;\n    }\n}\n\n\nint LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream,\n                                const char* source, char* dest,\n                                int inputSize, int maxOutputSize,\n                                int acceleration)\n{\n    const tableType_t tableType = byU32;\n    LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse;\n    const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL;\n\n    DEBUGLOG(5, \"LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)\", inputSize, streamPtr->dictSize);\n\n    LZ4_renormDictT(streamPtr, inputSize);   /* fix index overflow */\n    if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT;\n    if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX;\n\n    /* invalidate tiny dictionaries */\n    if ( (streamPtr->dictSize < 4)     /* tiny dictionary : not enough for a hash */\n      && (dictEnd != source)           /* prefix mode */\n      && (inputSize > 0)               /* tolerance : don't lose history, in case next invocation would use prefix mode */\n      && (streamPtr->dictCtx == NULL)  /* usingDictCtx */\n      ) {\n        DEBUGLOG(5, \"LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small\", streamPtr->dictSize, streamPtr->dictionary);\n        /* remove dictionary existence from history, to employ faster prefix mode */\n        streamPtr->dictSize = 0;\n        streamPtr->dictionary = (const BYTE*)source;\n        dictEnd = source;\n    }\n\n    /* Check overlapping input/dictionary space */\n    {   const char* const sourceEnd = source + inputSize;\n        if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) {\n            streamPtr->dictSize = (U32)(dictEnd - sourceEnd);\n            if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB;\n            if (streamPtr->dictSize < 4) streamPtr->dictSize = 0;\n            streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize;\n        }\n    }\n\n    /* prefix mode : source data follows dictionary */\n    if (dictEnd == source) {\n        if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset))\n            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration);\n        else\n            return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration);\n    }\n\n    /* external dictionary mode */\n    {   int result;\n        if (streamPtr->dictCtx) {\n            /* We depend here on the fact that dictCtx'es (produced by\n             * LZ4_loadDict) guarantee that their tables contain no references\n             * to offsets between dictCtx->currentOffset - 64 KB and\n             * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe\n             * to use noDictIssue even when the dict isn't a full 64 KB.\n             */\n            if (inputSize > 4 KB) {\n                /* For compressing large blobs, it is faster to pay the setup\n                 * cost to copy the dictionary's tables into the active context,\n                 * so that the compression loop is only looking into one table.\n                 */\n                LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr));\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);\n            } else {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration);\n            }\n        } else {  /* small data <= 4 KB */\n            if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration);\n            } else {\n                result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration);\n            }\n        }\n        streamPtr->dictionary = (const BYTE*)source;\n        streamPtr->dictSize = (U32)inputSize;\n        return result;\n    }\n}\n\n\n/* Hidden debug function, to force-test external dictionary mode */\nint LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize)\n{\n    LZ4_stream_t_internal* const streamPtr = &LZ4_dict->internal_donotuse;\n    int result;\n\n    LZ4_renormDictT(streamPtr, srcSize);\n\n    if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) {\n        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1);\n    } else {\n        result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1);\n    }\n\n    streamPtr->dictionary = (const BYTE*)source;\n    streamPtr->dictSize = (U32)srcSize;\n\n    return result;\n}\n\n\n/*! LZ4_saveDict() :\n *  If previously compressed data block is not guaranteed to remain available at its memory location,\n *  save it into a safer place (char* safeBuffer).\n *  Note : no need to call LZ4_loadDict() afterwards, dictionary is immediately usable,\n *         one can therefore call LZ4_compress_fast_continue() right after.\n * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error.\n */\nint LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize)\n{\n    LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse;\n\n    DEBUGLOG(5, \"LZ4_saveDict : dictSize=%i, safeBuffer=%p\", dictSize, safeBuffer);\n\n    if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */\n    if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; }\n\n    if (safeBuffer == NULL) assert(dictSize == 0);\n    if (dictSize > 0) {\n        const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize;\n        assert(dict->dictionary);\n        LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize);\n    }\n\n    dict->dictionary = (const BYTE*)safeBuffer;\n    dict->dictSize = (U32)dictSize;\n\n    return dictSize;\n}\n\n\n\n/*-*******************************\n *  Decompression functions\n ********************************/\n\ntypedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;\n\n#undef MIN\n#define MIN(a,b)    ( (a) < (b) ? (a) : (b) )\n\n\n/* variant for decompress_unsafe()\n * does not know end of input\n * presumes input is well formed\n * note : will consume at least one byte */\nstatic size_t read_long_length_no_check(const BYTE** pp)\n{\n    size_t b, l = 0;\n    do { b = **pp; (*pp)++; l += b; } while (b==255);\n    DEBUGLOG(6, \"read_long_length_no_check: +length=%zu using %zu input bytes\", l, l/255 + 1)\n    return l;\n}\n\n/* core decoder variant for LZ4_decompress_fast*()\n * for legacy support only : these entry points are deprecated.\n * - Presumes input is correctly formed (no defense vs malformed inputs)\n * - Does not know input size (presume input buffer is \"large enough\")\n * - Decompress a full block (only)\n * @return : nb of bytes read from input.\n * Note : this variant is not optimized for speed, just for maintenance.\n *        the goal is to remove support of decompress_fast*() variants by v2.0\n**/\nLZ4_FORCE_INLINE int\nLZ4_decompress_unsafe_generic(\n                 const BYTE* const istart,\n                 BYTE* const ostart,\n                 int decompressedSize,\n\n                 size_t prefixSize,\n                 const BYTE* const dictStart,  /* only if dict==usingExtDict */\n                 const size_t dictSize         /* note: =0 if dictStart==NULL */\n                 )\n{\n    const BYTE* ip = istart;\n    BYTE* op = (BYTE*)ostart;\n    BYTE* const oend = ostart + decompressedSize;\n    const BYTE* const prefixStart = ostart - prefixSize;\n\n    DEBUGLOG(5, \"LZ4_decompress_unsafe_generic\");\n    if (dictStart == NULL) assert(dictSize == 0);\n\n    while (1) {\n        /* start new sequence */\n        unsigned token = *ip++;\n\n        /* literals */\n        {   size_t ll = token >> ML_BITS;\n            if (ll==15) {\n                /* long literal length */\n                ll += read_long_length_no_check(&ip);\n            }\n            if ((size_t)(oend-op) < ll) return -1; /* output buffer overflow */\n            LZ4_memmove(op, ip, ll); /* support in-place decompression */\n            op += ll;\n            ip += ll;\n            if ((size_t)(oend-op) < MFLIMIT) {\n                if (op==oend) break;  /* end of block */\n                DEBUGLOG(5, \"invalid: literals end at distance %zi from end of block\", oend-op);\n                /* incorrect end of block :\n                 * last match must start at least MFLIMIT==12 bytes before end of output block */\n                return -1;\n        }   }\n\n        /* match */\n        {   size_t ml = token & 15;\n            size_t const offset = LZ4_readLE16(ip);\n            ip+=2;\n\n            if (ml==15) {\n                /* long literal length */\n                ml += read_long_length_no_check(&ip);\n            }\n            ml += MINMATCH;\n\n            if ((size_t)(oend-op) < ml) return -1; /* output buffer overflow */\n\n            {   const BYTE* match = op - offset;\n\n                /* out of range */\n                if (offset > (size_t)(op - prefixStart) + dictSize) {\n                    DEBUGLOG(6, \"offset out of range\");\n                    return -1;\n                }\n\n                /* check special case : extDict */\n                if (offset > (size_t)(op - prefixStart)) {\n                    /* extDict scenario */\n                    const BYTE* const dictEnd = dictStart + dictSize;\n                    const BYTE* extMatch = dictEnd - (offset - (size_t)(op-prefixStart));\n                    size_t const extml = (size_t)(dictEnd - extMatch);\n                    if (extml > ml) {\n                        /* match entirely within extDict */\n                        LZ4_memmove(op, extMatch, ml);\n                        op += ml;\n                        ml = 0;\n                    } else {\n                        /* match split between extDict & prefix */\n                        LZ4_memmove(op, extMatch, extml);\n                        op += extml;\n                        ml -= extml;\n                    }\n                    match = prefixStart;\n                }\n\n                /* match copy - slow variant, supporting overlap copy */\n                {   size_t u;\n                    for (u=0; u<ml; u++) {\n                        op[u] = match[u];\n            }   }   }\n            op += ml;\n            if ((size_t)(oend-op) < LASTLITERALS) {\n                DEBUGLOG(5, \"invalid: match ends at distance %zi from end of block\", oend-op);\n                /* incorrect end of block :\n                 * last match must stop at least LASTLITERALS==5 bytes before end of output block */\n                return -1;\n            }\n        } /* match */\n    } /* main loop */\n    return (int)(ip - istart);\n}\n\n\n/* Read the variable-length literal or match length.\n *\n * @ip : input pointer\n * @ilimit : position after which if length is not decoded, the input is necessarily corrupted.\n * @initial_check - check ip >= ipmax before start of loop.  Returns initial_error if so.\n * @error (output) - error code.  Must be set to 0 before call.\n**/\ntypedef size_t Rvl_t;\nstatic const Rvl_t rvl_error = (Rvl_t)(-1);\nLZ4_FORCE_INLINE Rvl_t\nread_variable_length(const BYTE** ip, const BYTE* ilimit,\n                     int initial_check)\n{\n    Rvl_t s, length = 0;\n    assert(ip != NULL);\n    assert(*ip !=  NULL);\n    assert(ilimit != NULL);\n    if (initial_check && unlikely((*ip) >= ilimit)) {    /* read limit reached */\n        return rvl_error;\n    }\n    do {\n        s = **ip;\n        (*ip)++;\n        length += s;\n        if (unlikely((*ip) > ilimit)) {    /* read limit reached */\n            return rvl_error;\n        }\n        /* accumulator overflow detection (32-bit mode only) */\n        if ((sizeof(length)<8) && unlikely(length > ((Rvl_t)(-1)/2)) ) {\n            return rvl_error;\n        }\n    } while (s==255);\n\n    return length;\n}\n\n/*! LZ4_decompress_generic() :\n *  This generic decompression function covers all use cases.\n *  It shall be instantiated several times, using different sets of directives.\n *  Note that it is important for performance that this function really get inlined,\n *  in order to remove useless branches during compilation optimization.\n */\nLZ4_FORCE_INLINE int\nLZ4_decompress_generic(\n                 const char* const src,\n                 char* const dst,\n                 int srcSize,\n                 int outputSize,         /* If endOnInput==endOnInputSize, this value is `dstCapacity` */\n\n                 earlyEnd_directive partialDecoding,  /* full, partial */\n                 dict_directive dict,                 /* noDict, withPrefix64k, usingExtDict */\n                 const BYTE* const lowPrefix,  /* always <= dst, == dst when no prefix */\n                 const BYTE* const dictStart,  /* only if dict==usingExtDict */\n                 const size_t dictSize         /* note : = 0 if noDict */\n                 )\n{\n    if ((src == NULL) || (outputSize < 0)) { return -1; }\n\n    {   const BYTE* ip = (const BYTE*) src;\n        const BYTE* const iend = ip + srcSize;\n\n        BYTE* op = (BYTE*) dst;\n        BYTE* const oend = op + outputSize;\n        BYTE* cpy;\n\n        const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize;\n\n        const int checkOffset = (dictSize < (int)(64 KB));\n\n\n        /* Set up the \"end\" pointers for the shortcut. */\n        const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/;\n        const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/;\n\n        const BYTE* match;\n        size_t offset;\n        unsigned token;\n        size_t length;\n\n\n        DEBUGLOG(5, \"LZ4_decompress_generic (srcSize:%i, dstSize:%i)\", srcSize, outputSize);\n\n        /* Special cases */\n        assert(lowPrefix <= op);\n        if (unlikely(outputSize==0)) {\n            /* Empty output buffer */\n            if (partialDecoding) return 0;\n            return ((srcSize==1) && (*ip==0)) ? 0 : -1;\n        }\n        if (unlikely(srcSize==0)) { return -1; }\n\n    /* LZ4_FAST_DEC_LOOP:\n     * designed for modern OoO performance cpus,\n     * where copying reliably 32-bytes is preferable to an unpredictable branch.\n     * note : fast loop may show a regression for some client arm chips. */\n#if LZ4_FAST_DEC_LOOP\n        if ((oend - op) < FASTLOOP_SAFE_DISTANCE) {\n            DEBUGLOG(6, \"skip fast decode loop\");\n            goto safe_decode;\n        }\n\n        /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */\n        DEBUGLOG(6, \"using fast decode loop\");\n        while (1) {\n            /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */\n            assert(oend - op >= FASTLOOP_SAFE_DISTANCE);\n            assert(ip < iend);\n            token = *ip++;\n            length = token >> ML_BITS;  /* literal length */\n\n            /* decode literal length */\n            if (length == RUN_MASK) {\n                size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1);\n                if (addl == rvl_error) {\n                    DEBUGLOG(6, \"error reading long literal length\");\n                    goto _output_error;\n                }\n                length += addl;\n                if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */\n                if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */\n\n                /* copy literals */\n                LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);\n                if ((op+length>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; }\n                LZ4_wildCopy32(op, ip, op+length);\n                ip += length; op += length;\n            } else if (ip <= iend-(16 + 1/*max lit + offset + nextToken*/)) {\n                /* We don't need to check oend, since we check it once for each loop below */\n                DEBUGLOG(7, \"copy %u bytes in a 16-bytes stripe\", (unsigned)length);\n                /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */\n                LZ4_memcpy(op, ip, 16);\n                ip += length; op += length;\n            } else {\n                goto safe_literal_copy;\n            }\n\n            /* get offset */\n            offset = LZ4_readLE16(ip); ip+=2;\n            DEBUGLOG(6, \" offset = %zu\", offset);\n            match = op - offset;\n            assert(match <= op);  /* overflow check */\n\n            /* get matchlength */\n            length = token & ML_MASK;\n\n            if (length == ML_MASK) {\n                size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);\n                if (addl == rvl_error) {\n                    DEBUGLOG(6, \"error reading long match length\");\n                    goto _output_error;\n                }\n                length += addl;\n                length += MINMATCH;\n                if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */\n                if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) {\n                    DEBUGLOG(6, \"Error : offset outside buffers\");\n                    goto _output_error;\n                }\n                if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {\n                    goto safe_match_copy;\n                }\n            } else {\n                length += MINMATCH;\n                if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) {\n                    goto safe_match_copy;\n                }\n\n                /* Fastpath check: skip LZ4_wildCopy32 when true */\n                if ((dict == withPrefix64k) || (match >= lowPrefix)) {\n                    if (offset >= 8) {\n                        assert(match >= lowPrefix);\n                        assert(match <= op);\n                        assert(op + 18 <= oend);\n\n                        LZ4_memcpy(op, match, 8);\n                        LZ4_memcpy(op+8, match+8, 8);\n                        LZ4_memcpy(op+16, match+16, 2);\n                        op += length;\n                        continue;\n            }   }   }\n\n            if ( checkOffset && (unlikely(match + dictSize < lowPrefix)) ) {\n                DEBUGLOG(6, \"Error : pos=%zi, offset=%zi => outside buffers\", op-lowPrefix, op-match);\n                goto _output_error;\n            }\n            /* match starting within external dictionary */\n            if ((dict==usingExtDict) && (match < lowPrefix)) {\n                assert(dictEnd != NULL);\n                if (unlikely(op+length > oend-LASTLITERALS)) {\n                    if (partialDecoding) {\n                        DEBUGLOG(7, \"partialDecoding: dictionary match, close to dstEnd\");\n                        length = MIN(length, (size_t)(oend-op));\n                    } else {\n                        DEBUGLOG(6, \"end-of-block condition violated\")\n                        goto _output_error;\n                }   }\n\n                if (length <= (size_t)(lowPrefix-match)) {\n                    /* match fits entirely within external dictionary : just copy */\n                    LZ4_memmove(op, dictEnd - (lowPrefix-match), length);\n                    op += length;\n                } else {\n                    /* match stretches into both external dictionary and current block */\n                    size_t const copySize = (size_t)(lowPrefix - match);\n                    size_t const restSize = length - copySize;\n                    LZ4_memcpy(op, dictEnd - copySize, copySize);\n                    op += copySize;\n                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */\n                        BYTE* const endOfMatch = op + restSize;\n                        const BYTE* copyFrom = lowPrefix;\n                        while (op < endOfMatch) { *op++ = *copyFrom++; }\n                    } else {\n                        LZ4_memcpy(op, lowPrefix, restSize);\n                        op += restSize;\n                }   }\n                continue;\n            }\n\n            /* copy match within block */\n            cpy = op + length;\n\n            assert((op <= oend) && (oend-op >= 32));\n            if (unlikely(offset<16)) {\n                LZ4_memcpy_using_offset(op, match, cpy, offset);\n            } else {\n                LZ4_wildCopy32(op, match, cpy);\n            }\n\n            op = cpy;   /* wildcopy correction */\n        }\n    safe_decode:\n#endif\n\n        /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */\n        DEBUGLOG(6, \"using safe decode loop\");\n        while (1) {\n            assert(ip < iend);\n            token = *ip++;\n            length = token >> ML_BITS;  /* literal length */\n\n            /* A two-stage shortcut for the most common case:\n             * 1) If the literal length is 0..14, and there is enough space,\n             * enter the shortcut and copy 16 bytes on behalf of the literals\n             * (in the fast mode, only 8 bytes can be safely copied this way).\n             * 2) Further if the match length is 4..18, copy 18 bytes in a similar\n             * manner; but we ensure that there's enough space in the output for\n             * those 18 bytes earlier, upon entering the shortcut (in other words,\n             * there is a combined check for both stages).\n             */\n            if ( (length != RUN_MASK)\n                /* strictly \"less than\" on input, to re-enter the loop with at least one byte */\n              && likely((ip < shortiend) & (op <= shortoend)) ) {\n                /* Copy the literals */\n                LZ4_memcpy(op, ip, 16);\n                op += length; ip += length;\n\n                /* The second stage: prepare for match copying, decode full info.\n                 * If it doesn't work out, the info won't be wasted. */\n                length = token & ML_MASK; /* match length */\n                offset = LZ4_readLE16(ip); ip += 2;\n                match = op - offset;\n                assert(match <= op); /* check overflow */\n\n                /* Do not deal with overlapping matches. */\n                if ( (length != ML_MASK)\n                  && (offset >= 8)\n                  && (dict==withPrefix64k || match >= lowPrefix) ) {\n                    /* Copy the match. */\n                    LZ4_memcpy(op + 0, match + 0, 8);\n                    LZ4_memcpy(op + 8, match + 8, 8);\n                    LZ4_memcpy(op +16, match +16, 2);\n                    op += length + MINMATCH;\n                    /* Both stages worked, load the next token. */\n                    continue;\n                }\n\n                /* The second stage didn't work out, but the info is ready.\n                 * Propel it right to the point of match copying. */\n                goto _copy_match;\n            }\n\n            /* decode literal length */\n            if (length == RUN_MASK) {\n                size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1);\n                if (addl == rvl_error) { goto _output_error; }\n                length += addl;\n                if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */\n                if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */\n            }\n\n#if LZ4_FAST_DEC_LOOP\n        safe_literal_copy:\n#endif\n            /* copy literals */\n            cpy = op+length;\n\n            LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH);\n            if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) {\n                /* We've either hit the input parsing restriction or the output parsing restriction.\n                 * In the normal scenario, decoding a full block, it must be the last sequence,\n                 * otherwise it's an error (invalid input or dimensions).\n                 * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow.\n                 */\n                if (partialDecoding) {\n                    /* Since we are partial decoding we may be in this block because of the output parsing\n                     * restriction, which is not valid since the output buffer is allowed to be undersized.\n                     */\n                    DEBUGLOG(7, \"partialDecoding: copying literals, close to input or output end\")\n                    DEBUGLOG(7, \"partialDecoding: literal length = %u\", (unsigned)length);\n                    DEBUGLOG(7, \"partialDecoding: remaining space in dstBuffer : %i\", (int)(oend - op));\n                    DEBUGLOG(7, \"partialDecoding: remaining space in srcBuffer : %i\", (int)(iend - ip));\n                    /* Finishing in the middle of a literals segment,\n                     * due to lack of input.\n                     */\n                    if (ip+length > iend) {\n                        length = (size_t)(iend-ip);\n                        cpy = op + length;\n                    }\n                    /* Finishing in the middle of a literals segment,\n                     * due to lack of output space.\n                     */\n                    if (cpy > oend) {\n                        cpy = oend;\n                        assert(op<=oend);\n                        length = (size_t)(oend-op);\n                    }\n                } else {\n                     /* We must be on the last sequence (or invalid) because of the parsing limitations\n                      * so check that we exactly consume the input and don't overrun the output buffer.\n                      */\n                    if ((ip+length != iend) || (cpy > oend)) {\n                        DEBUGLOG(6, \"should have been last run of literals\")\n                        DEBUGLOG(6, \"ip(%p) + length(%i) = %p != iend (%p)\", ip, (int)length, ip+length, iend);\n                        DEBUGLOG(6, \"or cpy(%p) > oend(%p)\", cpy, oend);\n                        goto _output_error;\n                    }\n                }\n                LZ4_memmove(op, ip, length);  /* supports overlapping memory regions, for in-place decompression scenarios */\n                ip += length;\n                op += length;\n                /* Necessarily EOF when !partialDecoding.\n                 * When partialDecoding, it is EOF if we've either\n                 * filled the output buffer or\n                 * can't proceed with reading an offset for following match.\n                 */\n                if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) {\n                    break;\n                }\n            } else {\n                LZ4_wildCopy8(op, ip, cpy);   /* can overwrite up to 8 bytes beyond cpy */\n                ip += length; op = cpy;\n            }\n\n            /* get offset */\n            offset = LZ4_readLE16(ip); ip+=2;\n            match = op - offset;\n\n            /* get matchlength */\n            length = token & ML_MASK;\n\n    _copy_match:\n            if (length == ML_MASK) {\n                size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0);\n                if (addl == rvl_error) { goto _output_error; }\n                length += addl;\n                if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error;   /* overflow detection */\n            }\n            length += MINMATCH;\n\n#if LZ4_FAST_DEC_LOOP\n        safe_match_copy:\n#endif\n            if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error;   /* Error : offset outside buffers */\n            /* match starting within external dictionary */\n            if ((dict==usingExtDict) && (match < lowPrefix)) {\n                assert(dictEnd != NULL);\n                if (unlikely(op+length > oend-LASTLITERALS)) {\n                    if (partialDecoding) length = MIN(length, (size_t)(oend-op));\n                    else goto _output_error;   /* doesn't respect parsing restriction */\n                }\n\n                if (length <= (size_t)(lowPrefix-match)) {\n                    /* match fits entirely within external dictionary : just copy */\n                    LZ4_memmove(op, dictEnd - (lowPrefix-match), length);\n                    op += length;\n                } else {\n                    /* match stretches into both external dictionary and current block */\n                    size_t const copySize = (size_t)(lowPrefix - match);\n                    size_t const restSize = length - copySize;\n                    LZ4_memcpy(op, dictEnd - copySize, copySize);\n                    op += copySize;\n                    if (restSize > (size_t)(op - lowPrefix)) {  /* overlap copy */\n                        BYTE* const endOfMatch = op + restSize;\n                        const BYTE* copyFrom = lowPrefix;\n                        while (op < endOfMatch) *op++ = *copyFrom++;\n                    } else {\n                        LZ4_memcpy(op, lowPrefix, restSize);\n                        op += restSize;\n                }   }\n                continue;\n            }\n            assert(match >= lowPrefix);\n\n            /* copy match within block */\n            cpy = op + length;\n\n            /* partialDecoding : may end anywhere within the block */\n            assert(op<=oend);\n            if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {\n                size_t const mlen = MIN(length, (size_t)(oend-op));\n                const BYTE* const matchEnd = match + mlen;\n                BYTE* const copyEnd = op + mlen;\n                if (matchEnd > op) {   /* overlap copy */\n                    while (op < copyEnd) { *op++ = *match++; }\n                } else {\n                    LZ4_memcpy(op, match, mlen);\n                }\n                op = copyEnd;\n                if (op == oend) { break; }\n                continue;\n            }\n\n            if (unlikely(offset<8)) {\n                LZ4_write32(op, 0);   /* silence msan warning when offset==0 */\n                op[0] = match[0];\n                op[1] = match[1];\n                op[2] = match[2];\n                op[3] = match[3];\n                match += inc32table[offset];\n                LZ4_memcpy(op+4, match, 4);\n                match -= dec64table[offset];\n            } else {\n                LZ4_memcpy(op, match, 8);\n                match += 8;\n            }\n            op += 8;\n\n            if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) {\n                BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1);\n                if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */\n                if (op < oCopyLimit) {\n                    LZ4_wildCopy8(op, match, oCopyLimit);\n                    match += oCopyLimit - op;\n                    op = oCopyLimit;\n                }\n                while (op < cpy) { *op++ = *match++; }\n            } else {\n                LZ4_memcpy(op, match, 8);\n                if (length > 16)  { LZ4_wildCopy8(op+8, match+8, cpy); }\n            }\n            op = cpy;   /* wildcopy correction */\n        }\n\n        /* end of decoding */\n        DEBUGLOG(5, \"decoded %i bytes\", (int) (((char*)op)-dst));\n        return (int) (((char*)op)-dst);     /* Nb of output bytes decoded */\n\n        /* Overflow error detected */\n    _output_error:\n        return (int) (-(((const char*)ip)-src))-1;\n    }\n}\n\n\n/*===== Instantiate the API decoding functions. =====*/\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize,\n                                  decode_full_block, noDict,\n                                  (BYTE*)dest, NULL, 0);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe_partial(const char* src, char* dst, int compressedSize, int targetOutputSize, int dstCapacity)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,\n                                  partial_decode,\n                                  noDict, (BYTE*)dst, NULL, 0);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_fast(const char* source, char* dest, int originalSize)\n{\n    DEBUGLOG(5, \"LZ4_decompress_fast\");\n    return LZ4_decompress_unsafe_generic(\n                (const BYTE*)source, (BYTE*)dest, originalSize,\n                0, NULL, 0);\n}\n\n/*===== Instantiate a few more decoding cases, used more than once. =====*/\n\nLZ4_FORCE_O2 /* Exported, an obsolete API function. */\nint LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, withPrefix64k,\n                                  (BYTE*)dest - 64 KB, NULL, 0);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_safe_partial_withPrefix64k(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,\n                                  partial_decode, withPrefix64k,\n                                  (BYTE*)dest - 64 KB, NULL, 0);\n}\n\n/* Another obsolete API function, paired with the previous one. */\nint LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize)\n{\n    return LZ4_decompress_unsafe_generic(\n                (const BYTE*)source, (BYTE*)dest, originalSize,\n                64 KB, NULL, 0);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_safe_withSmallPrefix(const char* source, char* dest, int compressedSize, int maxOutputSize,\n                                               size_t prefixSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, noDict,\n                                  (BYTE*)dest-prefixSize, NULL, 0);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_safe_partial_withSmallPrefix(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity,\n                                               size_t prefixSize)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,\n                                  partial_decode, noDict,\n                                  (BYTE*)dest-prefixSize, NULL, 0);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int maxOutputSize,\n                                     const void* dictStart, size_t dictSize)\n{\n    DEBUGLOG(5, \"LZ4_decompress_safe_forceExtDict\");\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, usingExtDict,\n                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);\n}\n\nLZ4_FORCE_O2\nint LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest,\n                                     int compressedSize, int targetOutputSize, int dstCapacity,\n                                     const void* dictStart, size_t dictSize)\n{\n    dstCapacity = MIN(targetOutputSize, dstCapacity);\n    return LZ4_decompress_generic(source, dest, compressedSize, dstCapacity,\n                                  partial_decode, usingExtDict,\n                                  (BYTE*)dest, (const BYTE*)dictStart, dictSize);\n}\n\nLZ4_FORCE_O2\nstatic int LZ4_decompress_fast_extDict(const char* source, char* dest, int originalSize,\n                                       const void* dictStart, size_t dictSize)\n{\n    return LZ4_decompress_unsafe_generic(\n                (const BYTE*)source, (BYTE*)dest, originalSize,\n                0, (const BYTE*)dictStart, dictSize);\n}\n\n/* The \"double dictionary\" mode, for use with e.g. ring buffers: the first part\n * of the dictionary is passed as prefix, and the second via dictStart + dictSize.\n * These routines are used only once, in LZ4_decompress_*_continue().\n */\nLZ4_FORCE_INLINE\nint LZ4_decompress_safe_doubleDict(const char* source, char* dest, int compressedSize, int maxOutputSize,\n                                   size_t prefixSize, const void* dictStart, size_t dictSize)\n{\n    return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize,\n                                  decode_full_block, usingExtDict,\n                                  (BYTE*)dest-prefixSize, (const BYTE*)dictStart, dictSize);\n}\n\n/*===== streaming decompression functions =====*/\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_streamDecode_t* LZ4_createStreamDecode(void)\n{\n    LZ4_STATIC_ASSERT(sizeof(LZ4_streamDecode_t) >= sizeof(LZ4_streamDecode_t_internal));\n    return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t));\n}\n\nint LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream)\n{\n    if (LZ4_stream == NULL) { return 0; }  /* support free on NULL */\n    FREEMEM(LZ4_stream);\n    return 0;\n}\n#endif\n\n/*! LZ4_setStreamDecode() :\n *  Use this function to instruct where to find the dictionary.\n *  This function is not necessary if previous data is still available where it was decoded.\n *  Loading a size of 0 is allowed (same effect as no dictionary).\n * @return : 1 if OK, 0 if error\n */\nint LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    lz4sd->prefixSize = (size_t)dictSize;\n    if (dictSize) {\n        assert(dictionary != NULL);\n        lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize;\n    } else {\n        lz4sd->prefixEnd = (const BYTE*) dictionary;\n    }\n    lz4sd->externalDict = NULL;\n    lz4sd->extDictSize  = 0;\n    return 1;\n}\n\n/*! LZ4_decoderRingBufferSize() :\n *  when setting a ring buffer for streaming decompression (optional scenario),\n *  provides the minimum size of this ring buffer\n *  to be compatible with any source respecting maxBlockSize condition.\n *  Note : in a ring buffer scenario,\n *  blocks are presumed decompressed next to each other.\n *  When not enough space remains for next block (remainingSize < maxBlockSize),\n *  decoding resumes from beginning of ring buffer.\n * @return : minimum ring buffer size,\n *           or 0 if there is an error (invalid maxBlockSize).\n */\nint LZ4_decoderRingBufferSize(int maxBlockSize)\n{\n    if (maxBlockSize < 0) return 0;\n    if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0;\n    if (maxBlockSize < 16) maxBlockSize = 16;\n    return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize);\n}\n\n/*\n*_continue() :\n    These decoding functions allow decompression of multiple blocks in \"streaming\" mode.\n    Previously decoded blocks must still be available at the memory position where they were decoded.\n    If it's not possible, save the relevant part of decoded data into a safe buffer,\n    and indicate where it stands using LZ4_setStreamDecode()\n*/\nLZ4_FORCE_O2\nint LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)\n{\n    LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse;\n    int result;\n\n    if (lz4sd->prefixSize == 0) {\n        /* The first call, no dictionary yet. */\n        assert(lz4sd->extDictSize == 0);\n        result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)result;\n        lz4sd->prefixEnd = (BYTE*)dest + result;\n    } else if (lz4sd->prefixEnd == (BYTE*)dest) {\n        /* They're rolling the current segment. */\n        if (lz4sd->prefixSize >= 64 KB - 1)\n            result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);\n        else if (lz4sd->extDictSize == 0)\n            result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize,\n                                                         lz4sd->prefixSize);\n        else\n            result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize,\n                                                    lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize += (size_t)result;\n        lz4sd->prefixEnd  += result;\n    } else {\n        /* The buffer wraps around, or they're switching to another buffer. */\n        lz4sd->extDictSize = lz4sd->prefixSize;\n        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;\n        result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize,\n                                                  lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)result;\n        lz4sd->prefixEnd  = (BYTE*)dest + result;\n    }\n\n    return result;\n}\n\nLZ4_FORCE_O2 int\nLZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode,\n                        const char* source, char* dest, int originalSize)\n{\n    LZ4_streamDecode_t_internal* const lz4sd =\n        (assert(LZ4_streamDecode!=NULL), &LZ4_streamDecode->internal_donotuse);\n    int result;\n\n    DEBUGLOG(5, \"LZ4_decompress_fast_continue (toDecodeSize=%i)\", originalSize);\n    assert(originalSize >= 0);\n\n    if (lz4sd->prefixSize == 0) {\n        DEBUGLOG(5, \"first invocation : no prefix nor extDict\");\n        assert(lz4sd->extDictSize == 0);\n        result = LZ4_decompress_fast(source, dest, originalSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)originalSize;\n        lz4sd->prefixEnd = (BYTE*)dest + originalSize;\n    } else if (lz4sd->prefixEnd == (BYTE*)dest) {\n        DEBUGLOG(5, \"continue using existing prefix\");\n        result = LZ4_decompress_unsafe_generic(\n                        (const BYTE*)source, (BYTE*)dest, originalSize,\n                        lz4sd->prefixSize,\n                        lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize += (size_t)originalSize;\n        lz4sd->prefixEnd  += originalSize;\n    } else {\n        DEBUGLOG(5, \"prefix becomes extDict\");\n        lz4sd->extDictSize = lz4sd->prefixSize;\n        lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize;\n        result = LZ4_decompress_fast_extDict(source, dest, originalSize,\n                                             lz4sd->externalDict, lz4sd->extDictSize);\n        if (result <= 0) return result;\n        lz4sd->prefixSize = (size_t)originalSize;\n        lz4sd->prefixEnd  = (BYTE*)dest + originalSize;\n    }\n\n    return result;\n}\n\n\n/*\nAdvanced decoding functions :\n*_usingDict() :\n    These decoding functions work the same as \"_continue\" ones,\n    the dictionary must be explicitly provided within parameters\n*/\n\nint LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)\n{\n    if (dictSize==0)\n        return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize);\n    if (dictStart+dictSize == dest) {\n        if (dictSize >= 64 KB - 1) {\n            return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize);\n        }\n        assert(dictSize >= 0);\n        return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize);\n    }\n    assert(dictSize >= 0);\n    return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize);\n}\n\nint LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize)\n{\n    if (dictSize==0)\n        return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity);\n    if (dictStart+dictSize == dest) {\n        if (dictSize >= 64 KB - 1) {\n            return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity);\n        }\n        assert(dictSize >= 0);\n        return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize);\n    }\n    assert(dictSize >= 0);\n    return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize);\n}\n\nint LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize)\n{\n    if (dictSize==0 || dictStart+dictSize == dest)\n        return LZ4_decompress_unsafe_generic(\n                        (const BYTE*)source, (BYTE*)dest, originalSize,\n                        (size_t)dictSize, NULL, 0);\n    assert(dictSize >= 0);\n    return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize);\n}\n\n\n/*=*************************************************\n*  Obsolete Functions\n***************************************************/\n/* obsolete compression functions */\nint LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)\n{\n    return LZ4_compress_default(source, dest, inputSize, maxOutputSize);\n}\nint LZ4_compress(const char* src, char* dest, int srcSize)\n{\n    return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize));\n}\nint LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize)\n{\n    return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1);\n}\nint LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize)\n{\n    return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1);\n}\nint LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity)\n{\n    return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1);\n}\nint LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize)\n{\n    return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1);\n}\n\n/*\nThese decompression functions are deprecated and should no longer be used.\nThey are only provided here for compatibility with older user programs.\n- LZ4_uncompress is totally equivalent to LZ4_decompress_fast\n- LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe\n*/\nint LZ4_uncompress (const char* source, char* dest, int outputSize)\n{\n    return LZ4_decompress_fast(source, dest, outputSize);\n}\nint LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize)\n{\n    return LZ4_decompress_safe(source, dest, isize, maxOutputSize);\n}\n\n/* Obsolete Streaming functions */\n\nint LZ4_sizeofStreamState(void) { return sizeof(LZ4_stream_t); }\n\nint LZ4_resetStreamState(void* state, char* inputBuffer)\n{\n    (void)inputBuffer;\n    LZ4_resetStream((LZ4_stream_t*)state);\n    return 0;\n}\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nvoid* LZ4_create (char* inputBuffer)\n{\n    (void)inputBuffer;\n    return LZ4_createStream();\n}\n#endif\n\nchar* LZ4_slideInputBuffer (void* state)\n{\n    /* avoid const char * -> char * conversion warning */\n    return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary;\n}\n\n#endif   /* LZ4_COMMONDEFS_ONLY */\n"
  },
  {
    "path": "lib/LZ4F/lz4.h",
    "content": "/*\n *  LZ4 - Fast LZ compression algorithm\n *  Header File\n *  Copyright (C) 2011-2020, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n    - LZ4 homepage : http://www.lz4.org\n    - LZ4 source repository : https://github.com/lz4/lz4\n*/\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n#ifndef LZ4_H_2983827168210\n#define LZ4_H_2983827168210\n\n/* --- Dependency --- */\n#include <stddef.h>   /* size_t */\n\n\n/**\n  Introduction\n\n  LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core,\n  scalable with multi-cores CPU. It features an extremely fast decoder, with speed in\n  multiple GB/s per core, typically reaching RAM speed limits on multi-core systems.\n\n  The LZ4 compression library provides in-memory compression and decompression functions.\n  It gives full buffer control to user.\n  Compression can be done in:\n    - a single step (described as Simple Functions)\n    - a single step, reusing a context (described in Advanced Functions)\n    - unbounded multiple steps (described as Streaming compression)\n\n  lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md).\n  Decompressing such a compressed block requires additional metadata.\n  Exact metadata depends on exact decompression function.\n  For the typical case of LZ4_decompress_safe(),\n  metadata includes block's compressed size, and maximum bound of decompressed size.\n  Each application is free to encode and pass such metadata in whichever way it wants.\n\n  lz4.h only handle blocks, it can not generate Frames.\n\n  Blocks are different from Frames (doc/lz4_Frame_format.md).\n  Frames bundle both blocks and metadata in a specified manner.\n  Embedding metadata is required for compressed data to be self-contained and portable.\n  Frame format is delivered through a companion API, declared in lz4frame.h.\n  The `lz4` CLI can only manage frames.\n*/\n\n/*^***************************************************************\n*  Export parameters\n*****************************************************************/\n/*\n*  LZ4_DLL_EXPORT :\n*  Enable exporting of functions when building a Windows DLL\n*  LZ4LIB_VISIBILITY :\n*  Control library symbols visibility.\n*/\n#ifndef LZ4LIB_VISIBILITY\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4LIB_VISIBILITY __attribute__ ((visibility (\"default\")))\n#  else\n#    define LZ4LIB_VISIBILITY\n#  endif\n#endif\n#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)\n#  define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY\n#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)\n#  define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/\n#else\n#  define LZ4LIB_API LZ4LIB_VISIBILITY\n#endif\n\n/*! LZ4_FREESTANDING :\n *  When this macro is set to 1, it enables \"freestanding mode\" that is\n *  suitable for typical freestanding environment which doesn't support\n *  standard C library.\n *\n *  - LZ4_FREESTANDING is a compile-time switch.\n *  - It requires the following macros to be defined:\n *    LZ4_memcpy, LZ4_memmove, LZ4_memset.\n *  - It only enables LZ4/HC functions which don't use heap.\n *    All LZ4F_* functions are not supported.\n *  - See tests/freestanding.c to check its basic setup.\n */\n#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1)\n#  define LZ4_HEAPMODE 0\n#  define LZ4HC_HEAPMODE 0\n#  define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1\n#  if !defined(LZ4_memcpy)\n#    error \"LZ4_FREESTANDING requires macro 'LZ4_memcpy'.\"\n#  endif\n#  if !defined(LZ4_memset)\n#    error \"LZ4_FREESTANDING requires macro 'LZ4_memset'.\"\n#  endif\n#  if !defined(LZ4_memmove)\n#    error \"LZ4_FREESTANDING requires macro 'LZ4_memmove'.\"\n#  endif\n#elif ! defined(LZ4_FREESTANDING)\n#  define LZ4_FREESTANDING 0\n#endif\n\n\n/*------   Version   ------*/\n#define LZ4_VERSION_MAJOR    1    /* for breaking interface changes  */\n#define LZ4_VERSION_MINOR    9    /* for new (non-breaking) interface capabilities */\n#define LZ4_VERSION_RELEASE  4    /* for tweaks, bug-fixes, or development */\n\n#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)\n\n#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE\n#define LZ4_QUOTE(str) #str\n#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)\n#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)  /* requires v1.7.3+ */\n\nLZ4LIB_API int LZ4_versionNumber (void);  /**< library version number; useful to check dll version; requires v1.3.0+ */\nLZ4LIB_API const char* LZ4_versionString (void);   /**< library version string; useful to check dll version; requires v1.7.5+ */\n\n\n/*-************************************\n*  Tuning parameter\n**************************************/\n#define LZ4_MEMORY_USAGE_MIN 10\n#define LZ4_MEMORY_USAGE_DEFAULT 14\n#define LZ4_MEMORY_USAGE_MAX 20\n\n/*!\n * LZ4_MEMORY_USAGE :\n * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; )\n * Increasing memory usage improves compression ratio, at the cost of speed.\n * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality.\n * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache\n */\n#ifndef LZ4_MEMORY_USAGE\n# define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT\n#endif\n\n#if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN)\n#  error \"LZ4_MEMORY_USAGE is too small !\"\n#endif\n\n#if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX)\n#  error \"LZ4_MEMORY_USAGE is too large !\"\n#endif\n\n/*-************************************\n*  Simple Functions\n**************************************/\n/*! LZ4_compress_default() :\n *  Compresses 'srcSize' bytes from buffer 'src'\n *  into already allocated 'dst' buffer of size 'dstCapacity'.\n *  Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize).\n *  It also runs faster, so it's a recommended setting.\n *  If the function cannot compress 'src' into a more limited 'dst' budget,\n *  compression stops *immediately*, and the function result is zero.\n *  In which case, 'dst' content is undefined (invalid).\n *      srcSize : max supported value is LZ4_MAX_INPUT_SIZE.\n *      dstCapacity : size of buffer 'dst' (which must be already allocated)\n *     @return  : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity)\n *                or 0 if compression fails\n * Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer).\n */\nLZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity);\n\n/*! LZ4_decompress_safe() :\n * @compressedSize : is the exact complete size of the compressed block.\n * @dstCapacity : is the size of destination buffer (which must be already allocated),\n *                is an upper bound of decompressed size.\n * @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity)\n *           If destination buffer is not large enough, decoding will stop and output an error code (negative value).\n *           If the source stream is detected malformed, the function will stop decoding and return a negative result.\n * Note 1 : This function is protected against malicious data packets :\n *          it will never writes outside 'dst' buffer, nor read outside 'source' buffer,\n *          even if the compressed block is maliciously modified to order the decoder to do these actions.\n *          In such case, the decoder stops immediately, and considers the compressed block malformed.\n * Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them.\n *          The implementation is free to send / store / derive this information in whichever way is most beneficial.\n *          If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead.\n */\nLZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity);\n\n\n/*-************************************\n*  Advanced Functions\n**************************************/\n#define LZ4_MAX_INPUT_SIZE        0x7E000000   /* 2 113 929 216 bytes */\n#define LZ4_COMPRESSBOUND(isize)  ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)\n\n/*! LZ4_compressBound() :\n    Provides the maximum size that LZ4 compression may output in a \"worst case\" scenario (input data not compressible)\n    This function is primarily useful for memory allocation purposes (destination buffer size).\n    Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example).\n    Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize)\n        inputSize  : max supported value is LZ4_MAX_INPUT_SIZE\n        return : maximum output size in a \"worst case\" scenario\n              or 0, if input size is incorrect (too large or negative)\n*/\nLZ4LIB_API int LZ4_compressBound(int inputSize);\n\n/*! LZ4_compress_fast() :\n    Same as LZ4_compress_default(), but allows selection of \"acceleration\" factor.\n    The larger the acceleration value, the faster the algorithm, but also the lesser the compression.\n    It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed.\n    An acceleration value of \"1\" is the same as regular LZ4_compress_default()\n    Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c).\n    Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c).\n*/\nLZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n\n/*! LZ4_compress_fast_extState() :\n *  Same as LZ4_compress_fast(), using an externally allocated memory space for its state.\n *  Use LZ4_sizeofState() to know how much memory must be allocated,\n *  and allocate it on 8-bytes boundaries (using `malloc()` typically).\n *  Then, provide this buffer as `void* state` to compression function.\n */\nLZ4LIB_API int LZ4_sizeofState(void);\nLZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n\n/*! LZ4_compress_destSize() :\n *  Reverse the logic : compresses as much data as possible from 'src' buffer\n *  into already allocated buffer 'dst', of size >= 'targetDestSize'.\n *  This function either compresses the entire 'src' content into 'dst' if it's large enough,\n *  or fill 'dst' buffer completely with as much data as possible from 'src'.\n *  note: acceleration parameter is fixed to \"default\".\n *\n * *srcSizePtr : will be modified to indicate how many bytes where read from 'src' to fill 'dst'.\n *               New value is necessarily <= input value.\n * @return : Nb bytes written into 'dst' (necessarily <= targetDestSize)\n *           or 0 if compression fails.\n *\n * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed in v1.9.2+):\n *        the produced compressed content could, in specific circumstances,\n *        require to be decompressed into a destination buffer larger\n *        by at least 1 byte than the content to decompress.\n *        If an application uses `LZ4_compress_destSize()`,\n *        it's highly recommended to update liblz4 to v1.9.2 or better.\n *        If this can't be done or ensured,\n *        the receiving decompression function should provide\n *        a dstCapacity which is > decompressedSize, by at least 1 byte.\n *        See https://github.com/lz4/lz4/issues/859 for details\n */\nLZ4LIB_API int LZ4_compress_destSize (const char* src, char* dst, int* srcSizePtr, int targetDstSize);\n\n\n/*! LZ4_decompress_safe_partial() :\n *  Decompress an LZ4 compressed block, of size 'srcSize' at position 'src',\n *  into destination buffer 'dst' of size 'dstCapacity'.\n *  Up to 'targetOutputSize' bytes will be decoded.\n *  The function stops decoding on reaching this objective.\n *  This can be useful to boost performance\n *  whenever only the beginning of a block is required.\n *\n * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize)\n *           If source stream is detected malformed, function returns a negative result.\n *\n *  Note 1 : @return can be < targetOutputSize, if compressed block contains less data.\n *\n *  Note 2 : targetOutputSize must be <= dstCapacity\n *\n *  Note 3 : this function effectively stops decoding on reaching targetOutputSize,\n *           so dstCapacity is kind of redundant.\n *           This is because in older versions of this function,\n *           decoding operation would still write complete sequences.\n *           Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize,\n *           it could write more bytes, though only up to dstCapacity.\n *           Some \"margin\" used to be required for this operation to work properly.\n *           Thankfully, this is no longer necessary.\n *           The function nonetheless keeps the same signature, in an effort to preserve API compatibility.\n *\n *  Note 4 : If srcSize is the exact size of the block,\n *           then targetOutputSize can be any value,\n *           including larger than the block's decompressed size.\n *           The function will, at most, generate block's decompressed size.\n *\n *  Note 5 : If srcSize is _larger_ than block's compressed size,\n *           then targetOutputSize **MUST** be <= block's decompressed size.\n *           Otherwise, *silent corruption will occur*.\n */\nLZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity);\n\n\n/*-*********************************************\n*  Streaming Compression Functions\n***********************************************/\ntypedef union LZ4_stream_u LZ4_stream_t;  /* incomplete type (defined later) */\n\n/**\n Note about RC_INVOKED\n\n - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is part of MSVC/Visual Studio).\n   https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros\n\n - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars)\n   and reports warning \"RC4011: identifier truncated\".\n\n - To eliminate the warning, we surround long preprocessor symbol with\n   \"#if !defined(RC_INVOKED) ... #endif\" block that means\n   \"skip this block when rc.exe is trying to read it\".\n*/\n#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4LIB_API LZ4_stream_t* LZ4_createStream(void);\nLZ4LIB_API int           LZ4_freeStream (LZ4_stream_t* streamPtr);\n#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */\n#endif\n\n/*! LZ4_resetStream_fast() : v1.9.0+\n *  Use this to prepare an LZ4_stream_t for a new chain of dependent blocks\n *  (e.g., LZ4_compress_fast_continue()).\n *\n *  An LZ4_stream_t must be initialized once before usage.\n *  This is automatically done when created by LZ4_createStream().\n *  However, should the LZ4_stream_t be simply declared on stack (for example),\n *  it's necessary to initialize it first, using LZ4_initStream().\n *\n *  After init, start any new stream with LZ4_resetStream_fast().\n *  A same LZ4_stream_t can be re-used multiple times consecutively\n *  and compress multiple streams,\n *  provided that it starts each new stream with LZ4_resetStream_fast().\n *\n *  LZ4_resetStream_fast() is much faster than LZ4_initStream(),\n *  but is not compatible with memory regions containing garbage data.\n *\n *  Note: it's only useful to call LZ4_resetStream_fast()\n *        in the context of streaming compression.\n *        The *extState* functions perform their own resets.\n *        Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive.\n */\nLZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr);\n\n/*! LZ4_loadDict() :\n *  Use this function to reference a static dictionary into LZ4_stream_t.\n *  The dictionary must remain available during compression.\n *  LZ4_loadDict() triggers a reset, so any previous data will be forgotten.\n *  The same dictionary will have to be loaded on decompression side for successful decoding.\n *  Dictionary are useful for better compression of small data (KB range).\n *  While LZ4 accept any input as dictionary,\n *  results are generally better when using Zstandard's Dictionary Builder.\n *  Loading a size of 0 is allowed, and is the same as reset.\n * @return : loaded dictionary size, in bytes (necessarily <= 64 KB)\n */\nLZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize);\n\n/*! LZ4_compress_fast_continue() :\n *  Compress 'src' content using data from previously compressed blocks, for better compression ratio.\n * 'dst' buffer must be already allocated.\n *  If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster.\n *\n * @return : size of compressed block\n *           or 0 if there is an error (typically, cannot fit into 'dst').\n *\n *  Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block.\n *           Each block has precise boundaries.\n *           Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata.\n *           It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together.\n *\n *  Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory !\n *\n *  Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB.\n *           Make sure that buffers are separated, by at least one byte.\n *           This construction ensures that each block only depends on previous block.\n *\n *  Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB.\n *\n *  Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed.\n */\nLZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n/*! LZ4_saveDict() :\n *  If last 64KB data cannot be guaranteed to remain available at its current memory location,\n *  save it into a safer place (char* safeBuffer).\n *  This is schematically equivalent to a memcpy() followed by LZ4_loadDict(),\n *  but is much faster, because LZ4_saveDict() doesn't need to rebuild tables.\n * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error.\n */\nLZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize);\n\n\n/*-**********************************************\n*  Streaming Decompression Functions\n*  Bufferless synchronous API\n************************************************/\ntypedef union LZ4_streamDecode_u LZ4_streamDecode_t;   /* tracking context */\n\n/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() :\n *  creation / destruction of streaming decompression tracking context.\n *  A tracking context can be re-used multiple times.\n */\n#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void);\nLZ4LIB_API int                 LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream);\n#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */\n#endif\n\n/*! LZ4_setStreamDecode() :\n *  An LZ4_streamDecode_t context can be allocated once and re-used multiple times.\n *  Use this function to start decompression of a new stream of blocks.\n *  A dictionary can optionally be set. Use NULL or size 0 for a reset order.\n *  Dictionary is presumed stable : it must remain accessible and unmodified during next decompression.\n * @return : 1 if OK, 0 if error\n */\nLZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize);\n\n/*! LZ4_decoderRingBufferSize() : v1.8.2+\n *  Note : in a ring buffer scenario (optional),\n *  blocks are presumed decompressed next to each other\n *  up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize),\n *  at which stage it resumes from beginning of ring buffer.\n *  When setting such a ring buffer for streaming decompression,\n *  provides the minimum size of this ring buffer\n *  to be compatible with any source respecting maxBlockSize condition.\n * @return : minimum ring buffer size,\n *           or 0 if there is an error (invalid maxBlockSize).\n */\nLZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize);\n#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize))  /* for static allocation; maxBlockSize presumed valid */\n\n/*! LZ4_decompress_safe_continue() :\n *  This decoding function allows decompression of consecutive blocks in \"streaming\" mode.\n *  The difference with the usual independent blocks is that\n *  new blocks are allowed to find references into former blocks.\n *  A block is an unsplittable entity, and must be presented entirely to the decompression function.\n *  LZ4_decompress_safe_continue() only accepts one block at a time.\n *  It's modeled after `LZ4_decompress_safe()` and behaves similarly.\n *\n * @LZ4_streamDecode : decompression state, tracking the position in memory of past data\n * @compressedSize : exact complete size of one compressed block.\n * @dstCapacity : size of destination buffer (which must be already allocated),\n *                must be an upper bound of decompressed size.\n * @return : number of bytes decompressed into destination buffer (necessarily <= dstCapacity)\n *           If destination buffer is not large enough, decoding will stop and output an error code (negative value).\n *           If the source stream is detected malformed, the function will stop decoding and return a negative result.\n *\n *  The last 64KB of previously decoded data *must* remain available and unmodified\n *  at the memory position where they were previously decoded.\n *  If less than 64KB of data has been decoded, all the data must be present.\n *\n *  Special : if decompression side sets a ring buffer, it must respect one of the following conditions :\n *  - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize).\n *    maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes.\n *    In which case, encoding and decoding buffers do not need to be synchronized.\n *    Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize.\n *  - Synchronized mode :\n *    Decompression buffer size is _exactly_ the same as compression buffer size,\n *    and follows exactly same update rule (block boundaries at same positions),\n *    and decoding function is provided with exact decompressed size of each block (exception for last block of the stream),\n *    _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB).\n *  - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes.\n *    In which case, encoding and decoding buffers do not need to be synchronized,\n *    and encoding ring buffer can have any size, including small ones ( < 64 KB).\n *\n *  Whenever these conditions are not possible,\n *  save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression,\n *  then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block.\n*/\nLZ4LIB_API int\nLZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode,\n                        const char* src, char* dst,\n                        int srcSize, int dstCapacity);\n\n\n/*! LZ4_decompress_safe_usingDict() :\n *  Works the same as\n *  a combination of LZ4_setStreamDecode() followed by LZ4_decompress_safe_continue()\n *  However, it's stateless: it doesn't need any LZ4_streamDecode_t state.\n *  Dictionary is presumed stable : it must remain accessible and unmodified during decompression.\n *  Performance tip : Decompression speed can be substantially increased\n *                    when dst == dictStart + dictSize.\n */\nLZ4LIB_API int\nLZ4_decompress_safe_usingDict(const char* src, char* dst,\n                              int srcSize, int dstCapacity,\n                              const char* dictStart, int dictSize);\n\n/*! LZ4_decompress_safe_partial_usingDict() :\n *  Behaves the same as LZ4_decompress_safe_partial()\n *  with the added ability to specify a memory segment for past data.\n *  Performance tip : Decompression speed can be substantially increased\n *                    when dst == dictStart + dictSize.\n */\nLZ4LIB_API int\nLZ4_decompress_safe_partial_usingDict(const char* src, char* dst,\n                                      int compressedSize,\n                                      int targetOutputSize, int maxOutputSize,\n                                      const char* dictStart, int dictSize);\n\n#endif /* LZ4_H_2983827168210 */\n\n\n/*^*************************************\n * !!!!!!   STATIC LINKING ONLY   !!!!!!\n ***************************************/\n\n/*-****************************************************************************\n * Experimental section\n *\n * Symbols declared in this section must be considered unstable. Their\n * signatures or semantics may change, or they may be removed altogether in the\n * future. They are therefore only safe to depend on when the caller is\n * statically linked against the library.\n *\n * To protect against unsafe usage, not only are the declarations guarded,\n * the definitions are hidden by default\n * when building LZ4 as a shared/dynamic library.\n *\n * In order to access these declarations,\n * define LZ4_STATIC_LINKING_ONLY in your application\n * before including LZ4's headers.\n *\n * In order to make their implementations accessible dynamically, you must\n * define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library.\n ******************************************************************************/\n\n#ifdef LZ4_STATIC_LINKING_ONLY\n\n#ifndef LZ4_STATIC_3504398509\n#define LZ4_STATIC_3504398509\n\n#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS\n#define LZ4LIB_STATIC_API LZ4LIB_API\n#else\n#define LZ4LIB_STATIC_API\n#endif\n\n\n/*! LZ4_compress_fast_extState_fastReset() :\n *  A variant of LZ4_compress_fast_extState().\n *\n *  Using this variant avoids an expensive initialization step.\n *  It is only safe to call if the state buffer is known to be correctly initialized already\n *  (see above comment on LZ4_resetStream_fast() for a definition of \"correctly initialized\").\n *  From a high level, the difference is that\n *  this function initializes the provided state with a call to something like LZ4_resetStream_fast()\n *  while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream().\n */\nLZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration);\n\n/*! LZ4_attach_dictionary() :\n *  This is an experimental API that allows\n *  efficient use of a static dictionary many times.\n *\n *  Rather than re-loading the dictionary buffer into a working context before\n *  each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a\n *  working LZ4_stream_t, this function introduces a no-copy setup mechanism,\n *  in which the working stream references the dictionary stream in-place.\n *\n *  Several assumptions are made about the state of the dictionary stream.\n *  Currently, only streams which have been prepared by LZ4_loadDict() should\n *  be expected to work.\n *\n *  Alternatively, the provided dictionaryStream may be NULL,\n *  in which case any existing dictionary stream is unset.\n *\n *  If a dictionary is provided, it replaces any pre-existing stream history.\n *  The dictionary contents are the only history that can be referenced and\n *  logically immediately precede the data compressed in the first subsequent\n *  compression call.\n *\n *  The dictionary will only remain attached to the working stream through the\n *  first compression call, at the end of which it is cleared. The dictionary\n *  stream (and source buffer) must remain in-place / accessible / unchanged\n *  through the completion of the first compression call on the stream.\n */\nLZ4LIB_STATIC_API void\nLZ4_attach_dictionary(LZ4_stream_t* workingStream,\n                const LZ4_stream_t* dictionaryStream);\n\n\n/*! In-place compression and decompression\n *\n * It's possible to have input and output sharing the same buffer,\n * for highly constrained memory environments.\n * In both cases, it requires input to lay at the end of the buffer,\n * and decompression to start at beginning of the buffer.\n * Buffer size must feature some margin, hence be larger than final size.\n *\n * |<------------------------buffer--------------------------------->|\n *                             |<-----------compressed data--------->|\n * |<-----------decompressed size------------------>|\n *                                                  |<----margin---->|\n *\n * This technique is more useful for decompression,\n * since decompressed size is typically larger,\n * and margin is short.\n *\n * In-place decompression will work inside any buffer\n * which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize).\n * This presumes that decompressedSize > compressedSize.\n * Otherwise, it means compression actually expanded data,\n * and it would be more efficient to store such data with a flag indicating it's not compressed.\n * This can happen when data is not compressible (already compressed, or encrypted).\n *\n * For in-place compression, margin is larger, as it must be able to cope with both\n * history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX,\n * and data expansion, which can happen when input is not compressible.\n * As a consequence, buffer size requirements are much higher,\n * and memory savings offered by in-place compression are more limited.\n *\n * There are ways to limit this cost for compression :\n * - Reduce history size, by modifying LZ4_DISTANCE_MAX.\n *   Note that it is a compile-time constant, so all compressions will apply this limit.\n *   Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX,\n *   so it's a reasonable trick when inputs are known to be small.\n * - Require the compressor to deliver a \"maximum compressed size\".\n *   This is the `dstCapacity` parameter in `LZ4_compress*()`.\n *   When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail,\n *   in which case, the return code will be 0 (zero).\n *   The caller must be ready for these cases to happen,\n *   and typically design a backup scheme to send data uncompressed.\n * The combination of both techniques can significantly reduce\n * the amount of margin required for in-place compression.\n *\n * In-place compression can work in any buffer\n * which size is >= (maxCompressedSize)\n * with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success.\n * LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX,\n * so it's possible to reduce memory requirements by playing with them.\n */\n\n#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize)          (((compressedSize) >> 8) + 32)\n#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize)   ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize))  /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */\n\n#ifndef LZ4_DISTANCE_MAX   /* history window size; can be user-defined at compile time */\n#  define LZ4_DISTANCE_MAX 65535   /* set to maximum value by default */\n#endif\n\n#define LZ4_COMPRESS_INPLACE_MARGIN                           (LZ4_DISTANCE_MAX + 32)   /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */\n#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize)   ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN)  /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */\n\n#endif   /* LZ4_STATIC_3504398509 */\n#endif   /* LZ4_STATIC_LINKING_ONLY */\n\n\n\n#ifndef LZ4_H_98237428734687\n#define LZ4_H_98237428734687\n\n/*-************************************************************\n *  Private Definitions\n **************************************************************\n * Do not use these definitions directly.\n * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`.\n * Accessing members will expose user code to API and/or ABI break in future versions of the library.\n **************************************************************/\n#define LZ4_HASHLOG   (LZ4_MEMORY_USAGE-2)\n#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)\n#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG)       /* required as macro for static allocation */\n\n#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n# include <stdint.h>\n  typedef  int8_t  LZ4_i8;\n  typedef uint8_t  LZ4_byte;\n  typedef uint16_t LZ4_u16;\n  typedef uint32_t LZ4_u32;\n#else\n  typedef   signed char  LZ4_i8;\n  typedef unsigned char  LZ4_byte;\n  typedef unsigned short LZ4_u16;\n  typedef unsigned int   LZ4_u32;\n#endif\n\n/*! LZ4_stream_t :\n *  Never ever use below internal definitions directly !\n *  These definitions are not API/ABI safe, and may change in future versions.\n *  If you need static allocation, declare or allocate an LZ4_stream_t object.\n**/\n\ntypedef struct LZ4_stream_t_internal LZ4_stream_t_internal;\nstruct LZ4_stream_t_internal {\n    LZ4_u32 hashTable[LZ4_HASH_SIZE_U32];\n    const LZ4_byte* dictionary;\n    const LZ4_stream_t_internal* dictCtx;\n    LZ4_u32 currentOffset;\n    LZ4_u32 tableType;\n    LZ4_u32 dictSize;\n    /* Implicit padding to ensure structure is aligned */\n};\n\n#define LZ4_STREAM_MINSIZE  ((1UL << LZ4_MEMORY_USAGE) + 32)  /* static size, for inter-version compatibility */\nunion LZ4_stream_u {\n    char minStateSize[LZ4_STREAM_MINSIZE];\n    LZ4_stream_t_internal internal_donotuse;\n}; /* previously typedef'd to LZ4_stream_t */\n\n\n/*! LZ4_initStream() : v1.9.0+\n *  An LZ4_stream_t structure must be initialized at least once.\n *  This is automatically done when invoking LZ4_createStream(),\n *  but it's not when the structure is simply declared on stack (for example).\n *\n *  Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t.\n *  It can also initialize any arbitrary buffer of sufficient size,\n *  and will @return a pointer of proper type upon initialization.\n *\n *  Note : initialization fails if size and alignment conditions are not respected.\n *         In which case, the function will @return NULL.\n *  Note2: An LZ4_stream_t structure guarantees correct alignment and size.\n *  Note3: Before v1.9.0, use LZ4_resetStream() instead\n**/\nLZ4LIB_API LZ4_stream_t* LZ4_initStream (void* buffer, size_t size);\n\n\n/*! LZ4_streamDecode_t :\n *  Never ever use below internal definitions directly !\n *  These definitions are not API/ABI safe, and may change in future versions.\n *  If you need static allocation, declare or allocate an LZ4_streamDecode_t object.\n**/\ntypedef struct {\n    const LZ4_byte* externalDict;\n    const LZ4_byte* prefixEnd;\n    size_t extDictSize;\n    size_t prefixSize;\n} LZ4_streamDecode_t_internal;\n\n#define LZ4_STREAMDECODE_MINSIZE 32\nunion LZ4_streamDecode_u {\n    char minStateSize[LZ4_STREAMDECODE_MINSIZE];\n    LZ4_streamDecode_t_internal internal_donotuse;\n} ;   /* previously typedef'd to LZ4_streamDecode_t */\n\n\n\n/*-************************************\n*  Obsolete Functions\n**************************************/\n\n/*! Deprecation warnings\n *\n *  Deprecated functions make the compiler generate a warning when invoked.\n *  This is meant to invite users to update their source code.\n *  Should deprecation warnings be a problem, it is generally possible to disable them,\n *  typically with -Wno-deprecated-declarations for gcc\n *  or _CRT_SECURE_NO_WARNINGS in Visual.\n *\n *  Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS\n *  before including the header file.\n */\n#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS\n#  define LZ4_DEPRECATED(message)   /* disable deprecation warnings */\n#else\n#  if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */\n#    define LZ4_DEPRECATED(message) [[deprecated(message)]]\n#  elif defined(_MSC_VER)\n#    define LZ4_DEPRECATED(message) __declspec(deprecated(message))\n#  elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45))\n#    define LZ4_DEPRECATED(message) __attribute__((deprecated(message)))\n#  elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31)\n#    define LZ4_DEPRECATED(message) __attribute__((deprecated))\n#  else\n#    pragma message(\"WARNING: LZ4_DEPRECATED needs custom implementation for this compiler\")\n#    define LZ4_DEPRECATED(message)   /* disabled */\n#  endif\n#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */\n\n/*! Obsolete compression functions (since v1.7.3) */\nLZ4_DEPRECATED(\"use LZ4_compress_default() instead\")       LZ4LIB_API int LZ4_compress               (const char* src, char* dest, int srcSize);\nLZ4_DEPRECATED(\"use LZ4_compress_default() instead\")       LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_extState() instead\") LZ4LIB_API int LZ4_compress_withState               (void* state, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_extState() instead\") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_continue() instead\") LZ4LIB_API int LZ4_compress_continue                (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_fast_continue() instead\") LZ4LIB_API int LZ4_compress_limitedOutput_continue  (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize);\n\n/*! Obsolete decompression functions (since v1.8.0) */\nLZ4_DEPRECATED(\"use LZ4_decompress_fast() instead\") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize);\nLZ4_DEPRECATED(\"use LZ4_decompress_safe() instead\") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize);\n\n/* Obsolete streaming functions (since v1.7.0)\n * degraded functionality; do not use!\n *\n * In order to perform streaming compression, these functions depended on data\n * that is no longer tracked in the state. They have been preserved as well as\n * possible: using them will still produce a correct output. However, they don't\n * actually retain any history between compression calls. The compression ratio\n * achieved will therefore be no better than compressing each chunk\n * independently.\n */\nLZ4_DEPRECATED(\"Use LZ4_createStream() instead\") LZ4LIB_API void* LZ4_create (char* inputBuffer);\nLZ4_DEPRECATED(\"Use LZ4_createStream() instead\") LZ4LIB_API int   LZ4_sizeofStreamState(void);\nLZ4_DEPRECATED(\"Use LZ4_resetStream() instead\")  LZ4LIB_API int   LZ4_resetStreamState(void* state, char* inputBuffer);\nLZ4_DEPRECATED(\"Use LZ4_saveDict() instead\")     LZ4LIB_API char* LZ4_slideInputBuffer (void* state);\n\n/*! Obsolete streaming decoding functions (since v1.7.0) */\nLZ4_DEPRECATED(\"use LZ4_decompress_safe_usingDict() instead\") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize);\nLZ4_DEPRECATED(\"use LZ4_decompress_fast_usingDict() instead\") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize);\n\n/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) :\n *  These functions used to be faster than LZ4_decompress_safe(),\n *  but this is no longer the case. They are now slower.\n *  This is because LZ4_decompress_fast() doesn't know the input size,\n *  and therefore must progress more cautiously into the input buffer to not read beyond the end of block.\n *  On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability.\n *  As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated.\n *\n *  The last remaining LZ4_decompress_fast() specificity is that\n *  it can decompress a block without knowing its compressed size.\n *  Such functionality can be achieved in a more secure manner\n *  by employing LZ4_decompress_safe_partial().\n *\n *  Parameters:\n *  originalSize : is the uncompressed size to regenerate.\n *                 `dst` must be already allocated, its size must be >= 'originalSize' bytes.\n * @return : number of bytes read from source buffer (== compressed size).\n *           The function expects to finish at block's end exactly.\n *           If the source stream is detected malformed, the function stops decoding and returns a negative result.\n *  note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer.\n *         However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds.\n *         Also, since match offsets are not validated, match reads from 'src' may underflow too.\n *         These issues never happen if input (compressed) data is correct.\n *         But they may happen if input data is invalid (error or intentional tampering).\n *         As a consequence, use these functions in trusted environments with trusted data **only**.\n */\nLZ4_DEPRECATED(\"This function is deprecated and unsafe. Consider using LZ4_decompress_safe() instead\")\nLZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize);\nLZ4_DEPRECATED(\"This function is deprecated and unsafe. Consider using LZ4_decompress_safe_continue() instead\")\nLZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize);\nLZ4_DEPRECATED(\"This function is deprecated and unsafe. Consider using LZ4_decompress_safe_usingDict() instead\")\nLZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize);\n\n/*! LZ4_resetStream() :\n *  An LZ4_stream_t structure must be initialized at least once.\n *  This is done with LZ4_initStream(), or LZ4_resetStream().\n *  Consider switching to LZ4_initStream(),\n *  invoking LZ4_resetStream() will trigger deprecation warnings in the future.\n */\nLZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr);\n\n\n#endif /* LZ4_H_98237428734687 */\n\n\n#if defined (__cplusplus)\n}\n#endif\n"
  },
  {
    "path": "lib/LZ4F/lz4file.c",
    "content": "/*\n * LZ4 file library\n * Copyright (C) 2022, Xiaomi Inc.\n *\n * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright\n *   notice, this list of conditions and the following disclaimer.\n * - Redistributions in binary form must reproduce the above\n *   copyright notice, this list of conditions and the following disclaimer\n *   in the documentation and/or other materials provided with the\n *   distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * You can contact the author at :\n * - LZ4 homepage : http://www.lz4.org\n * - LZ4 source repository : https://github.com/lz4/lz4\n */\n#include <stdlib.h>\n#include <string.h>\n#include \"lz4.h\"\n#include \"lz4file.h\"\n\nstruct LZ4_readFile_s {\n  LZ4F_dctx* dctxPtr;\n  FILE* fp;\n  LZ4_byte* srcBuf;\n  size_t srcBufNext;\n  size_t srcBufSize;\n  size_t srcBufMaxSize;\n};\n\nstruct LZ4_writeFile_s {\n  LZ4F_cctx* cctxPtr;\n  FILE* fp;\n  LZ4_byte* dstBuf;\n  size_t maxWriteSize;\n  size_t dstBufMaxSize;\n  LZ4F_errorCode_t errCode;\n};\n\nLZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)\n{\n  char buf[LZ4F_HEADER_SIZE_MAX];\n  size_t consumedSize;\n  LZ4F_errorCode_t ret;\n  LZ4F_frameInfo_t info;\n\n  if (fp == NULL || lz4fRead == NULL) {\n    return -LZ4F_ERROR_GENERIC;\n  }\n\n  *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));\n  if (*lz4fRead == NULL) {\n    return -LZ4F_ERROR_allocation_failed;\n  }\n\n  ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion());\n  if (LZ4F_isError(ret)) {\n    free(*lz4fRead);\n    return ret;\n  }\n\n  (*lz4fRead)->fp = fp;\n  consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp);\n  if (consumedSize != sizeof(buf)) {\n    LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);\n    free(*lz4fRead);\n    return -LZ4F_ERROR_GENERIC;\n  }\n\n  ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize);\n  if (LZ4F_isError(ret)) {\n      LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);\n      free(*lz4fRead);\n      return ret;\n    }\n\n  switch (info.blockSizeID) {\n    case LZ4F_default :\n    case LZ4F_max64KB :\n      (*lz4fRead)->srcBufMaxSize = 64 * 1024;\n      break;\n    case LZ4F_max256KB:\n      (*lz4fRead)->srcBufMaxSize = 256 * 1024;\n      break;\n    case LZ4F_max1MB:\n      (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024;\n      break;\n    case LZ4F_max4MB:\n      (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024;\n      break;\n    default:\n      LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);\n      free(*lz4fRead);\n      return -LZ4F_ERROR_maxBlockSize_invalid;\n  }\n\n  (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize);\n  if ((*lz4fRead)->srcBuf == NULL) {\n    LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);\n    free(lz4fRead);\n    return -LZ4F_ERROR_allocation_failed;\n  }\n\n  (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize;\n  memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize);\n\n  return ret;\n}\n\nsize_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)\n{\n  LZ4_byte* p = (LZ4_byte*)buf;\n  size_t next = 0;\n\n  if (lz4fRead == NULL || buf == NULL)\n    return -LZ4F_ERROR_GENERIC;\n\n  while (next < size) {\n    size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext;\n    size_t dstsize = size - next;\n    size_t ret;\n\n    if (srcsize == 0) {\n      ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);\n      if (ret > 0) {\n        lz4fRead->srcBufSize = ret;\n        srcsize = lz4fRead->srcBufSize;\n        lz4fRead->srcBufNext = 0;\n      }\n      else if (ret == 0) {\n        break;\n      }\n      else {\n        return -LZ4F_ERROR_GENERIC;\n      }\n    }\n\n    ret = LZ4F_decompress(lz4fRead->dctxPtr,\n                          p, &dstsize,\n                          lz4fRead->srcBuf + lz4fRead->srcBufNext,\n                          &srcsize,\n                          NULL);\n    if (LZ4F_isError(ret)) {\n        return ret;\n    }\n\n    lz4fRead->srcBufNext += srcsize;\n    next += dstsize;\n    p += dstsize;\n  }\n\n  return next;\n}\n\nLZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)\n{\n  if (lz4fRead == NULL)\n    return -LZ4F_ERROR_GENERIC;\n  LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);\n  free(lz4fRead->srcBuf);\n  free(lz4fRead);\n  return LZ4F_OK_NoError;\n}\n\nLZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)\n{\n  LZ4_byte buf[LZ4F_HEADER_SIZE_MAX];\n  size_t ret;\n\n  if (fp == NULL || lz4fWrite == NULL)\n    return -LZ4F_ERROR_GENERIC;\n\n  *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t));\n  if (*lz4fWrite == NULL) {\n    return -LZ4F_ERROR_allocation_failed;\n  }\n  if (prefsPtr != NULL) {\n    switch (prefsPtr->frameInfo.blockSizeID) {\n      case LZ4F_default :\n      case LZ4F_max64KB :\n        (*lz4fWrite)->maxWriteSize = 64 * 1024;\n        break;\n      case LZ4F_max256KB:\n        (*lz4fWrite)->maxWriteSize = 256 * 1024;\n        break;\n      case LZ4F_max1MB:\n        (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024;\n        break;\n      case LZ4F_max4MB:\n        (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024;\n        break;\n      default:\n        free(lz4fWrite);\n        return -LZ4F_ERROR_maxBlockSize_invalid;\n      }\n    } else {\n      (*lz4fWrite)->maxWriteSize = 64 * 1024;\n    }\n\n  (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr);\n  (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize);\n  if ((*lz4fWrite)->dstBuf == NULL) {\n    free(*lz4fWrite);\n    return -LZ4F_ERROR_allocation_failed;\n  }\n\n  ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion());\n  if (LZ4F_isError(ret)) {\n      free((*lz4fWrite)->dstBuf);\n      free(*lz4fWrite);\n      return ret;\n  }\n\n  ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr);\n  if (LZ4F_isError(ret)) {\n      LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);\n      free((*lz4fWrite)->dstBuf);\n      free(*lz4fWrite);\n      return ret;\n  }\n\n  if (ret != fwrite(buf, 1, ret, fp)) {\n    LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);\n    free((*lz4fWrite)->dstBuf);\n    free(*lz4fWrite);\n    return -LZ4F_ERROR_GENERIC;\n  }\n\n  (*lz4fWrite)->fp = fp;\n  (*lz4fWrite)->errCode = LZ4F_OK_NoError;\n  return LZ4F_OK_NoError;\n}\n\nsize_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size)\n{\n  const LZ4_byte* p = (const LZ4_byte*)buf;\n  size_t remain = size;\n  size_t chunk;\n  size_t ret;\n\n  if (lz4fWrite == NULL || buf == NULL)\n    return -LZ4F_ERROR_GENERIC;\n  while (remain) {\n    if (remain > lz4fWrite->maxWriteSize)\n      chunk = lz4fWrite->maxWriteSize;\n    else\n      chunk = remain;\n\n    ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr,\n                              lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,\n                              p, chunk,\n                              NULL);\n    if (LZ4F_isError(ret)) {\n      lz4fWrite->errCode = ret;\n      return ret;\n    }\n\n    if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {\n      lz4fWrite->errCode = -LZ4F_ERROR_GENERIC;\n      return -LZ4F_ERROR_GENERIC;\n    }\n\n    p += chunk;\n    remain -= chunk;\n  }\n\n  return size;\n}\n\nLZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)\n{\n  LZ4F_errorCode_t ret = LZ4F_OK_NoError;\n\n  if (lz4fWrite == NULL)\n    return -LZ4F_ERROR_GENERIC;\n\n  if (lz4fWrite->errCode == LZ4F_OK_NoError) {\n    ret =  LZ4F_compressEnd(lz4fWrite->cctxPtr,\n                            lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,\n                            NULL);\n    if (LZ4F_isError(ret)) {\n      goto out;\n    }\n\n    if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {\n      ret = -LZ4F_ERROR_GENERIC;\n    }\n  }\n\nout:\n  LZ4F_freeCompressionContext(lz4fWrite->cctxPtr);\n  free(lz4fWrite->dstBuf);\n  free(lz4fWrite);\n  return ret;\n}\n"
  },
  {
    "path": "lib/LZ4F/lz4file.h",
    "content": "/*\n   LZ4 file library\n   Header File\n   Copyright (C) 2022, Xiaomi Inc.\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n   - LZ4 source repository : https://github.com/lz4/lz4\n   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n#ifndef LZ4FILE_H\n#define LZ4FILE_H\n\n#include <stdio.h>\n#include \"lz4frame_static.h\"\n\ntypedef struct LZ4_readFile_s LZ4_readFile_t;\ntypedef struct LZ4_writeFile_s LZ4_writeFile_t;\n\n/*! LZ4F_readOpen() :\n * Set read lz4file handle.\n * `lz4f` will set a lz4file handle.\n * `fp` must be the return value of the lz4 file opened by fopen.\n */\nLZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp);\n\n/*! LZ4F_read() :\n * Read lz4file content to buffer.\n * `lz4f` must use LZ4_readOpen to set first.\n * `buf` read data buffer.\n * `size` read data buffer size.\n */\nLZ4FLIB_STATIC_API size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size);\n\n/*! LZ4F_readClose() :\n * Close lz4file handle.\n * `lz4f` must use LZ4_readOpen to set first.\n */\nLZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead);\n\n/*! LZ4F_writeOpen() :\n * Set write lz4file handle.\n * `lz4f` will set a lz4file handle.\n * `fp` must be the return value of the lz4 file opened by fopen.\n */\nLZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr);\n\n/*! LZ4F_write() :\n * Write buffer to lz4file.\n * `lz4f` must use LZ4F_writeOpen to set first.\n * `buf` write data buffer.\n * `size` write data buffer size.\n */\nLZ4FLIB_STATIC_API size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size);\n\n/*! LZ4F_writeClose() :\n * Close lz4file handle.\n * `lz4f` must use LZ4F_writeOpen to set first.\n */\nLZ4FLIB_STATIC_API LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite);\n\n#endif /* LZ4FILE_H */\n\n#if defined (__cplusplus)\n}\n#endif\n"
  },
  {
    "path": "lib/LZ4F/lz4frame.c",
    "content": "/*\n * LZ4 auto-framing library\n * Copyright (C) 2011-2016, Yann Collet.\n *\n * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n *\n * Redistribution and use in source and binary forms, with or without\n * modification, are permitted provided that the following conditions are\n * met:\n *\n * - Redistributions of source code must retain the above copyright\n *   notice, this list of conditions and the following disclaimer.\n * - Redistributions in binary form must reproduce the above\n *   copyright notice, this list of conditions and the following disclaimer\n *   in the documentation and/or other materials provided with the\n *   distribution.\n *\n * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n * \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n *\n * You can contact the author at :\n * - LZ4 homepage : http://www.lz4.org\n * - LZ4 source repository : https://github.com/lz4/lz4\n */\n\n/* LZ4F is a stand-alone API to create LZ4-compressed Frames\n * in full conformance with specification v1.6.1 .\n * This library rely upon memory management capabilities (malloc, free)\n * provided either by <stdlib.h>,\n * or redirected towards another library of user's choice\n * (see Memory Routines below).\n */\n\n\n/*-************************************\n*  Compiler Options\n**************************************/\n#ifdef _MSC_VER    /* Visual Studio */\n#  pragma warning(disable : 4127)   /* disable: C4127: conditional expression is constant */\n#endif\n\n\n/*-************************************\n*  Tuning parameters\n**************************************/\n/*\n * LZ4F_HEAPMODE :\n * Control how LZ4F_compressFrame allocates the Compression State,\n * either on stack (0:default, fastest), or in memory heap (1:requires malloc()).\n */\n#ifndef LZ4F_HEAPMODE\n#  define LZ4F_HEAPMODE 0\n#endif\n\n\n/*-************************************\n*  Library declarations\n**************************************/\n#define LZ4F_STATIC_LINKING_ONLY\n#include \"lz4frame.h\"\n#define LZ4_STATIC_LINKING_ONLY\n#include \"lz4.h\"\n#define LZ4_HC_STATIC_LINKING_ONLY\n#include \"lz4hc.h\"\n#define XXH_STATIC_LINKING_ONLY\n#include \"xxhash.h\"\n\n\n/*-************************************\n*  Memory routines\n**************************************/\n/*\n * User may redirect invocations of\n * malloc(), calloc() and free()\n * towards another library or solution of their choice\n * by modifying below section.\n**/\n\n#include <string.h>   /* memset, memcpy, memmove */\n#ifndef LZ4_SRC_INCLUDED  /* avoid redefinition when sources are coalesced */\n#  define MEM_INIT(p,v,s)   memset((p),(v),(s))\n#endif\n\n#ifndef LZ4_SRC_INCLUDED   /* avoid redefinition when sources are coalesced */\n#  include <stdlib.h>   /* malloc, calloc, free */\n#  define ALLOC(s)          malloc(s)\n#  define ALLOC_AND_ZERO(s) calloc(1,(s))\n#  define FREEMEM(p)        free(p)\n#endif\n\nstatic void* LZ4F_calloc(size_t s, LZ4F_CustomMem cmem)\n{\n    /* custom calloc defined : use it */\n    if (cmem.customCalloc != NULL) {\n        return cmem.customCalloc(cmem.opaqueState, s);\n    }\n    /* nothing defined : use default <stdlib.h>'s calloc() */\n    if (cmem.customAlloc == NULL) {\n        return ALLOC_AND_ZERO(s);\n    }\n    /* only custom alloc defined : use it, and combine it with memset() */\n    {   void* const p = cmem.customAlloc(cmem.opaqueState, s);\n        if (p != NULL) MEM_INIT(p, 0, s);\n        return p;\n}   }\n\nstatic void* LZ4F_malloc(size_t s, LZ4F_CustomMem cmem)\n{\n    /* custom malloc defined : use it */\n    if (cmem.customAlloc != NULL) {\n        return cmem.customAlloc(cmem.opaqueState, s);\n    }\n    /* nothing defined : use default <stdlib.h>'s malloc() */\n    return ALLOC(s);\n}\n\nstatic void LZ4F_free(void* p, LZ4F_CustomMem cmem)\n{\n    /* custom malloc defined : use it */\n    if (cmem.customFree != NULL) {\n        cmem.customFree(cmem.opaqueState, p);\n        return;\n    }\n    /* nothing defined : use default <stdlib.h>'s free() */\n    FREEMEM(p);\n}\n\n\n/*-************************************\n*  Debug\n**************************************/\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=1)\n#  include <assert.h>\n#else\n#  ifndef assert\n#    define assert(condition) ((void)0)\n#  endif\n#endif\n\n#define LZ4F_STATIC_ASSERT(c)    { enum { LZ4F_static_assert = 1/(int)(!!(c)) }; }   /* use only *after* variable declarations */\n\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) && !defined(DEBUGLOG)\n#  include <stdio.h>\nstatic int g_debuglog_enable = 1;\n#  define DEBUGLOG(l, ...) {                                  \\\n                if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) {  \\\n                    fprintf(stderr, __FILE__ \": \");           \\\n                    fprintf(stderr, __VA_ARGS__);             \\\n                    fprintf(stderr, \" \\n\");                   \\\n            }   }\n#else\n#  define DEBUGLOG(l, ...)      {}    /* disabled */\n#endif\n\n\n/*-************************************\n*  Basic Types\n**************************************/\n#if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n# include <stdint.h>\n  typedef  uint8_t BYTE;\n  typedef uint16_t U16;\n  typedef uint32_t U32;\n  typedef  int32_t S32;\n  typedef uint64_t U64;\n#else\n  typedef unsigned char       BYTE;\n  typedef unsigned short      U16;\n  typedef unsigned int        U32;\n  typedef   signed int        S32;\n  typedef unsigned long long  U64;\n#endif\n\n\n/* unoptimized version; solves endianness & alignment issues */\nstatic U32 LZ4F_readLE32 (const void* src)\n{\n    const BYTE* const srcPtr = (const BYTE*)src;\n    U32 value32 = srcPtr[0];\n    value32 += ((U32)srcPtr[1])<< 8;\n    value32 += ((U32)srcPtr[2])<<16;\n    value32 += ((U32)srcPtr[3])<<24;\n    return value32;\n}\n\nstatic void LZ4F_writeLE32 (void* dst, U32 value32)\n{\n    BYTE* const dstPtr = (BYTE*)dst;\n    dstPtr[0] = (BYTE)value32;\n    dstPtr[1] = (BYTE)(value32 >> 8);\n    dstPtr[2] = (BYTE)(value32 >> 16);\n    dstPtr[3] = (BYTE)(value32 >> 24);\n}\n\nstatic U64 LZ4F_readLE64 (const void* src)\n{\n    const BYTE* const srcPtr = (const BYTE*)src;\n    U64 value64 = srcPtr[0];\n    value64 += ((U64)srcPtr[1]<<8);\n    value64 += ((U64)srcPtr[2]<<16);\n    value64 += ((U64)srcPtr[3]<<24);\n    value64 += ((U64)srcPtr[4]<<32);\n    value64 += ((U64)srcPtr[5]<<40);\n    value64 += ((U64)srcPtr[6]<<48);\n    value64 += ((U64)srcPtr[7]<<56);\n    return value64;\n}\n\nstatic void LZ4F_writeLE64 (void* dst, U64 value64)\n{\n    BYTE* const dstPtr = (BYTE*)dst;\n    dstPtr[0] = (BYTE)value64;\n    dstPtr[1] = (BYTE)(value64 >> 8);\n    dstPtr[2] = (BYTE)(value64 >> 16);\n    dstPtr[3] = (BYTE)(value64 >> 24);\n    dstPtr[4] = (BYTE)(value64 >> 32);\n    dstPtr[5] = (BYTE)(value64 >> 40);\n    dstPtr[6] = (BYTE)(value64 >> 48);\n    dstPtr[7] = (BYTE)(value64 >> 56);\n}\n\n\n/*-************************************\n*  Constants\n**************************************/\n#ifndef LZ4_SRC_INCLUDED   /* avoid double definition */\n#  define KB *(1<<10)\n#  define MB *(1<<20)\n#  define GB *(1<<30)\n#endif\n\n#define _1BIT  0x01\n#define _2BITS 0x03\n#define _3BITS 0x07\n#define _4BITS 0x0F\n#define _8BITS 0xFF\n\n#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U\n#define LZ4F_BLOCKSIZEID_DEFAULT LZ4F_max64KB\n\nstatic const size_t minFHSize = LZ4F_HEADER_SIZE_MIN;   /*  7 */\nstatic const size_t maxFHSize = LZ4F_HEADER_SIZE_MAX;   /* 19 */\nstatic const size_t BHSize = LZ4F_BLOCK_HEADER_SIZE;  /* block header : size, and compress flag */\nstatic const size_t BFSize = LZ4F_BLOCK_CHECKSUM_SIZE;  /* block footer : checksum (optional) */\n\n\n/*-************************************\n*  Structures and local types\n**************************************/\n\ntypedef enum { LZ4B_COMPRESSED, LZ4B_UNCOMPRESSED} LZ4F_blockCompression_t;\n\ntypedef struct LZ4F_cctx_s\n{\n    LZ4F_CustomMem cmem;\n    LZ4F_preferences_t prefs;\n    U32    version;\n    U32    cStage;     /* 0 : compression uninitialized ; 1 : initialized, can compress */\n    const LZ4F_CDict* cdict;\n    size_t maxBlockSize;\n    size_t maxBufferSize;\n    BYTE*  tmpBuff;    /* internal buffer, for streaming */\n    BYTE*  tmpIn;      /* starting position of data compress within internal buffer (>= tmpBuff) */\n    size_t tmpInSize;  /* amount of data to compress after tmpIn */\n    U64    totalInSize;\n    XXH32_state_t xxh;\n    void*  lz4CtxPtr;\n    U16    lz4CtxAlloc; /* sized for: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */\n    U16    lz4CtxState; /* in use as: 0 = none, 1 = lz4 ctx, 2 = lz4hc ctx */\n    LZ4F_blockCompression_t  blockCompression;\n} LZ4F_cctx_t;\n\n\n/*-************************************\n*  Error management\n**************************************/\n#define LZ4F_GENERATE_STRING(STRING) #STRING,\nstatic const char* LZ4F_errorStrings[] = { LZ4F_LIST_ERRORS(LZ4F_GENERATE_STRING) };\n\n\nunsigned LZ4F_isError(LZ4F_errorCode_t code)\n{\n    return (code > (LZ4F_errorCode_t)(-LZ4F_ERROR_maxCode));\n}\n\nconst char* LZ4F_getErrorName(LZ4F_errorCode_t code)\n{\n    static const char* codeError = \"Unspecified error code\";\n    if (LZ4F_isError(code)) return LZ4F_errorStrings[-(int)(code)];\n    return codeError;\n}\n\nLZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult)\n{\n    if (!LZ4F_isError(functionResult)) return LZ4F_OK_NoError;\n    return (LZ4F_errorCodes)(-(ptrdiff_t)functionResult);\n}\n\nstatic LZ4F_errorCode_t LZ4F_returnErrorCode(LZ4F_errorCodes code)\n{\n    /* A compilation error here means sizeof(ptrdiff_t) is not large enough */\n    LZ4F_STATIC_ASSERT(sizeof(ptrdiff_t) >= sizeof(size_t));\n    return (LZ4F_errorCode_t)-(ptrdiff_t)code;\n}\n\n#define RETURN_ERROR(e) return LZ4F_returnErrorCode(LZ4F_ERROR_ ## e)\n\n#define RETURN_ERROR_IF(c,e) do { if (c) RETURN_ERROR(e); } while (0)\n\n#define FORWARD_IF_ERROR(r) do { if (LZ4F_isError(r)) return (r); } while (0)\n\nunsigned LZ4F_getVersion(void) { return LZ4F_VERSION; }\n\nint LZ4F_compressionLevel_max(void) { return LZ4HC_CLEVEL_MAX; }\n\nsize_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID)\n{\n    static const size_t blockSizes[4] = { 64 KB, 256 KB, 1 MB, 4 MB };\n\n    if (blockSizeID == 0) blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;\n    if (blockSizeID < LZ4F_max64KB || blockSizeID > LZ4F_max4MB)\n        RETURN_ERROR(maxBlockSize_invalid);\n    {   int const blockSizeIdx = (int)blockSizeID - (int)LZ4F_max64KB;\n        return blockSizes[blockSizeIdx];\n}   }\n\n/*-************************************\n*  Private functions\n**************************************/\n#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )\n\nstatic BYTE LZ4F_headerChecksum (const void* header, size_t length)\n{\n    U32 const xxh = XXH32(header, length, 0);\n    return (BYTE)(xxh >> 8);\n}\n\n\n/*-************************************\n*  Simple-pass compression functions\n**************************************/\nstatic LZ4F_blockSizeID_t LZ4F_optimalBSID(const LZ4F_blockSizeID_t requestedBSID,\n                                           const size_t srcSize)\n{\n    LZ4F_blockSizeID_t proposedBSID = LZ4F_max64KB;\n    size_t maxBlockSize = 64 KB;\n    while (requestedBSID > proposedBSID) {\n        if (srcSize <= maxBlockSize)\n            return proposedBSID;\n        proposedBSID = (LZ4F_blockSizeID_t)((int)proposedBSID + 1);\n        maxBlockSize <<= 2;\n    }\n    return requestedBSID;\n}\n\n/*! LZ4F_compressBound_internal() :\n *  Provides dstCapacity given a srcSize to guarantee operation success in worst case situations.\n *  prefsPtr is optional : if NULL is provided, preferences will be set to cover worst case scenario.\n * @return is always the same for a srcSize and prefsPtr, so it can be relied upon to size reusable buffers.\n *  When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() operations.\n */\nstatic size_t LZ4F_compressBound_internal(size_t srcSize,\n                                    const LZ4F_preferences_t* preferencesPtr,\n                                          size_t alreadyBuffered)\n{\n    LZ4F_preferences_t prefsNull = LZ4F_INIT_PREFERENCES;\n    prefsNull.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;   /* worst case */\n    prefsNull.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;   /* worst case */\n    {   const LZ4F_preferences_t* const prefsPtr = (preferencesPtr==NULL) ? &prefsNull : preferencesPtr;\n        U32 const flush = prefsPtr->autoFlush | (srcSize==0);\n        LZ4F_blockSizeID_t const blockID = prefsPtr->frameInfo.blockSizeID;\n        size_t const blockSize = LZ4F_getBlockSize(blockID);\n        size_t const maxBuffered = blockSize - 1;\n        size_t const bufferedSize = MIN(alreadyBuffered, maxBuffered);\n        size_t const maxSrcSize = srcSize + bufferedSize;\n        unsigned const nbFullBlocks = (unsigned)(maxSrcSize / blockSize);\n        size_t const partialBlockSize = maxSrcSize & (blockSize-1);\n        size_t const lastBlockSize = flush ? partialBlockSize : 0;\n        unsigned const nbBlocks = nbFullBlocks + (lastBlockSize>0);\n\n        size_t const blockCRCSize = BFSize * prefsPtr->frameInfo.blockChecksumFlag;\n        size_t const frameEnd = BHSize + (prefsPtr->frameInfo.contentChecksumFlag*BFSize);\n\n        return ((BHSize + blockCRCSize) * nbBlocks) +\n               (blockSize * nbFullBlocks) + lastBlockSize + frameEnd;\n    }\n}\n\nsize_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)\n{\n    LZ4F_preferences_t prefs;\n    size_t const headerSize = maxFHSize;      /* max header size, including optional fields */\n\n    if (preferencesPtr!=NULL) prefs = *preferencesPtr;\n    else MEM_INIT(&prefs, 0, sizeof(prefs));\n    prefs.autoFlush = 1;\n\n    return headerSize + LZ4F_compressBound_internal(srcSize, &prefs, 0);;\n}\n\n\n/*! LZ4F_compressFrame_usingCDict() :\n *  Compress srcBuffer using a dictionary, in a single step.\n *  cdict can be NULL, in which case, no dictionary is used.\n *  dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).\n *  The LZ4F_preferences_t structure is optional : you may provide NULL as argument,\n *  however, it's the only way to provide a dictID, so it's not recommended.\n * @return : number of bytes written into dstBuffer,\n *           or an error code if it fails (can be tested using LZ4F_isError())\n */\nsize_t LZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,\n                                     void* dstBuffer, size_t dstCapacity,\n                               const void* srcBuffer, size_t srcSize,\n                               const LZ4F_CDict* cdict,\n                               const LZ4F_preferences_t* preferencesPtr)\n{\n    LZ4F_preferences_t prefs;\n    LZ4F_compressOptions_t options;\n    BYTE* const dstStart = (BYTE*) dstBuffer;\n    BYTE* dstPtr = dstStart;\n    BYTE* const dstEnd = dstStart + dstCapacity;\n\n    if (preferencesPtr!=NULL)\n        prefs = *preferencesPtr;\n    else\n        MEM_INIT(&prefs, 0, sizeof(prefs));\n    if (prefs.frameInfo.contentSize != 0)\n        prefs.frameInfo.contentSize = (U64)srcSize;   /* auto-correct content size if selected (!=0) */\n\n    prefs.frameInfo.blockSizeID = LZ4F_optimalBSID(prefs.frameInfo.blockSizeID, srcSize);\n    prefs.autoFlush = 1;\n    if (srcSize <= LZ4F_getBlockSize(prefs.frameInfo.blockSizeID))\n        prefs.frameInfo.blockMode = LZ4F_blockIndependent;   /* only one block => no need for inter-block link */\n\n    MEM_INIT(&options, 0, sizeof(options));\n    options.stableSrc = 1;\n\n    RETURN_ERROR_IF(dstCapacity < LZ4F_compressFrameBound(srcSize, &prefs), dstMaxSize_tooSmall);\n\n    { size_t const headerSize = LZ4F_compressBegin_usingCDict(cctx, dstBuffer, dstCapacity, cdict, &prefs);  /* write header */\n      FORWARD_IF_ERROR(headerSize);\n      dstPtr += headerSize;   /* header size */ }\n\n    assert(dstEnd >= dstPtr);\n    { size_t const cSize = LZ4F_compressUpdate(cctx, dstPtr, (size_t)(dstEnd-dstPtr), srcBuffer, srcSize, &options);\n      FORWARD_IF_ERROR(cSize);\n      dstPtr += cSize; }\n\n    assert(dstEnd >= dstPtr);\n    { size_t const tailSize = LZ4F_compressEnd(cctx, dstPtr, (size_t)(dstEnd-dstPtr), &options);   /* flush last block, and generate suffix */\n      FORWARD_IF_ERROR(tailSize);\n      dstPtr += tailSize; }\n\n    assert(dstEnd >= dstStart);\n    return (size_t)(dstPtr - dstStart);\n}\n\n\n/*! LZ4F_compressFrame() :\n *  Compress an entire srcBuffer into a valid LZ4 frame, in a single step.\n *  dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).\n *  The LZ4F_preferences_t structure is optional : you can provide NULL as argument. All preferences will be set to default.\n * @return : number of bytes written into dstBuffer.\n *           or an error code if it fails (can be tested using LZ4F_isError())\n */\nsize_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,\n                    const void* srcBuffer, size_t srcSize,\n                    const LZ4F_preferences_t* preferencesPtr)\n{\n    size_t result;\n#if (LZ4F_HEAPMODE)\n    LZ4F_cctx_t* cctxPtr;\n    result = LZ4F_createCompressionContext(&cctxPtr, LZ4F_VERSION);\n    FORWARD_IF_ERROR(result);\n#else\n    LZ4F_cctx_t cctx;\n    LZ4_stream_t lz4ctx;\n    LZ4F_cctx_t* const cctxPtr = &cctx;\n\n    MEM_INIT(&cctx, 0, sizeof(cctx));\n    cctx.version = LZ4F_VERSION;\n    cctx.maxBufferSize = 5 MB;   /* mess with real buffer size to prevent dynamic allocation; works only because autoflush==1 & stableSrc==1 */\n    if ( preferencesPtr == NULL\n      || preferencesPtr->compressionLevel < LZ4HC_CLEVEL_MIN ) {\n        LZ4_initStream(&lz4ctx, sizeof(lz4ctx));\n        cctxPtr->lz4CtxPtr = &lz4ctx;\n        cctxPtr->lz4CtxAlloc = 1;\n        cctxPtr->lz4CtxState = 1;\n    }\n#endif\n    DEBUGLOG(4, \"LZ4F_compressFrame\");\n\n    result = LZ4F_compressFrame_usingCDict(cctxPtr, dstBuffer, dstCapacity,\n                                           srcBuffer, srcSize,\n                                           NULL, preferencesPtr);\n\n#if (LZ4F_HEAPMODE)\n    LZ4F_freeCompressionContext(cctxPtr);\n#else\n    if ( preferencesPtr != NULL\n      && preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN ) {\n        LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);\n    }\n#endif\n    return result;\n}\n\n\n/*-***************************************************\n*   Dictionary compression\n*****************************************************/\n\nstruct LZ4F_CDict_s {\n    LZ4F_CustomMem cmem;\n    void* dictContent;\n    LZ4_stream_t* fastCtx;\n    LZ4_streamHC_t* HCCtx;\n}; /* typedef'd to LZ4F_CDict within lz4frame_static.h */\n\nLZ4F_CDict*\nLZ4F_createCDict_advanced(LZ4F_CustomMem cmem, const void* dictBuffer, size_t dictSize)\n{\n    const char* dictStart = (const char*)dictBuffer;\n    LZ4F_CDict* const cdict = (LZ4F_CDict*)LZ4F_malloc(sizeof(*cdict), cmem);\n    DEBUGLOG(4, \"LZ4F_createCDict_advanced\");\n    if (!cdict) return NULL;\n    cdict->cmem = cmem;\n    if (dictSize > 64 KB) {\n        dictStart += dictSize - 64 KB;\n        dictSize = 64 KB;\n    }\n    cdict->dictContent = LZ4F_malloc(dictSize, cmem);\n    cdict->fastCtx = (LZ4_stream_t*)LZ4F_malloc(sizeof(LZ4_stream_t), cmem);\n    if (cdict->fastCtx)\n        LZ4_initStream(cdict->fastCtx, sizeof(LZ4_stream_t));\n    cdict->HCCtx = (LZ4_streamHC_t*)LZ4F_malloc(sizeof(LZ4_streamHC_t), cmem);\n    if (cdict->HCCtx)\n        LZ4_initStream(cdict->HCCtx, sizeof(LZ4_streamHC_t));\n    if (!cdict->dictContent || !cdict->fastCtx || !cdict->HCCtx) {\n        LZ4F_freeCDict(cdict);\n        return NULL;\n    }\n    memcpy(cdict->dictContent, dictStart, dictSize);\n    LZ4_loadDict (cdict->fastCtx, (const char*)cdict->dictContent, (int)dictSize);\n    LZ4_setCompressionLevel(cdict->HCCtx, LZ4HC_CLEVEL_DEFAULT);\n    LZ4_loadDictHC(cdict->HCCtx, (const char*)cdict->dictContent, (int)dictSize);\n    return cdict;\n}\n\n/*! LZ4F_createCDict() :\n *  When compressing multiple messages / blocks with the same dictionary, it's recommended to load it just once.\n *  LZ4F_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.\n *  LZ4F_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.\n * @dictBuffer can be released after LZ4F_CDict creation, since its content is copied within CDict\n * @return : digested dictionary for compression, or NULL if failed */\nLZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize)\n{\n    DEBUGLOG(4, \"LZ4F_createCDict\");\n    return LZ4F_createCDict_advanced(LZ4F_defaultCMem, dictBuffer, dictSize);\n}\n\nvoid LZ4F_freeCDict(LZ4F_CDict* cdict)\n{\n    if (cdict==NULL) return;  /* support free on NULL */\n    LZ4F_free(cdict->dictContent, cdict->cmem);\n    LZ4F_free(cdict->fastCtx, cdict->cmem);\n    LZ4F_free(cdict->HCCtx, cdict->cmem);\n    LZ4F_free(cdict, cdict->cmem);\n}\n\n\n/*-*********************************\n*  Advanced compression functions\n***********************************/\n\nLZ4F_cctx*\nLZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version)\n{\n    LZ4F_cctx* const cctxPtr =\n        (LZ4F_cctx*)LZ4F_calloc(sizeof(LZ4F_cctx), customMem);\n    if (cctxPtr==NULL) return NULL;\n\n    cctxPtr->cmem = customMem;\n    cctxPtr->version = version;\n    cctxPtr->cStage = 0;   /* Uninitialized. Next stage : init cctx */\n\n    return cctxPtr;\n}\n\n/*! LZ4F_createCompressionContext() :\n *  The first thing to do is to create a compressionContext object, which will be used in all compression operations.\n *  This is achieved using LZ4F_createCompressionContext(), which takes as argument a version and an LZ4F_preferences_t structure.\n *  The version provided MUST be LZ4F_VERSION. It is intended to track potential incompatible differences between different binaries.\n *  The function will provide a pointer to an allocated LZ4F_compressionContext_t object.\n *  If the result LZ4F_errorCode_t is not OK_NoError, there was an error during context creation.\n *  Object can release its memory using LZ4F_freeCompressionContext();\n**/\nLZ4F_errorCode_t\nLZ4F_createCompressionContext(LZ4F_cctx** LZ4F_compressionContextPtr, unsigned version)\n{\n    assert(LZ4F_compressionContextPtr != NULL); /* considered a violation of narrow contract */\n    /* in case it nonetheless happen in production */\n    RETURN_ERROR_IF(LZ4F_compressionContextPtr == NULL, parameter_null);\n\n    *LZ4F_compressionContextPtr = LZ4F_createCompressionContext_advanced(LZ4F_defaultCMem, version);\n    RETURN_ERROR_IF(*LZ4F_compressionContextPtr==NULL, allocation_failed);\n    return LZ4F_OK_NoError;\n}\n\n\nLZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctxPtr)\n{\n    if (cctxPtr != NULL) {  /* support free on NULL */\n       LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);  /* note: LZ4_streamHC_t and LZ4_stream_t are simple POD types */\n       LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem);\n       LZ4F_free(cctxPtr, cctxPtr->cmem);\n    }\n    return LZ4F_OK_NoError;\n}\n\n\n/**\n * This function prepares the internal LZ4(HC) stream for a new compression,\n * resetting the context and attaching the dictionary, if there is one.\n *\n * It needs to be called at the beginning of each independent compression\n * stream (i.e., at the beginning of a frame in blockLinked mode, or at the\n * beginning of each block in blockIndependent mode).\n */\nstatic void LZ4F_initStream(void* ctx,\n                            const LZ4F_CDict* cdict,\n                            int level,\n                            LZ4F_blockMode_t blockMode) {\n    if (level < LZ4HC_CLEVEL_MIN) {\n        if (cdict != NULL || blockMode == LZ4F_blockLinked) {\n            /* In these cases, we will call LZ4_compress_fast_continue(),\n             * which needs an already reset context. Otherwise, we'll call a\n             * one-shot API. The non-continued APIs internally perform their own\n             * resets at the beginning of their calls, where they know what\n             * tableType they need the context to be in. So in that case this\n             * would be misguided / wasted work. */\n            LZ4_resetStream_fast((LZ4_stream_t*)ctx);\n        }\n        LZ4_attach_dictionary((LZ4_stream_t *)ctx, cdict ? cdict->fastCtx : NULL);\n    } else {\n        LZ4_resetStreamHC_fast((LZ4_streamHC_t*)ctx, level);\n        LZ4_attach_HC_dictionary((LZ4_streamHC_t *)ctx, cdict ? cdict->HCCtx : NULL);\n    }\n}\n\nstatic int ctxTypeID_to_size(int ctxTypeID) {\n    switch(ctxTypeID) {\n    case 1:\n        return LZ4_sizeofState();\n    case 2:\n        return LZ4_sizeofStateHC();\n    default:\n        return 0;\n    }\n}\n\n/*! LZ4F_compressBegin_usingCDict() :\n *  init streaming compression AND writes frame header into @dstBuffer.\n * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.\n * @return : number of bytes written into @dstBuffer for the header\n *           or an error code (can be tested using LZ4F_isError())\n */\nsize_t LZ4F_compressBegin_usingCDict(LZ4F_cctx* cctxPtr,\n                          void* dstBuffer, size_t dstCapacity,\n                          const LZ4F_CDict* cdict,\n                          const LZ4F_preferences_t* preferencesPtr)\n{\n    LZ4F_preferences_t const prefNull = LZ4F_INIT_PREFERENCES;\n    BYTE* const dstStart = (BYTE*)dstBuffer;\n    BYTE* dstPtr = dstStart;\n\n    RETURN_ERROR_IF(dstCapacity < maxFHSize, dstMaxSize_tooSmall);\n    if (preferencesPtr == NULL) preferencesPtr = &prefNull;\n    cctxPtr->prefs = *preferencesPtr;\n\n    /* cctx Management */\n    {   U16 const ctxTypeID = (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) ? 1 : 2;\n        int requiredSize = ctxTypeID_to_size(ctxTypeID);\n        int allocatedSize = ctxTypeID_to_size(cctxPtr->lz4CtxAlloc);\n        if (allocatedSize < requiredSize) {\n            /* not enough space allocated */\n            LZ4F_free(cctxPtr->lz4CtxPtr, cctxPtr->cmem);\n            if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {\n                /* must take ownership of memory allocation,\n                 * in order to respect custom allocator contract */\n                cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_stream_t), cctxPtr->cmem);\n                if (cctxPtr->lz4CtxPtr)\n                    LZ4_initStream(cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t));\n            } else {\n                cctxPtr->lz4CtxPtr = LZ4F_malloc(sizeof(LZ4_streamHC_t), cctxPtr->cmem);\n                if (cctxPtr->lz4CtxPtr)\n                    LZ4_initStreamHC(cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));\n            }\n            RETURN_ERROR_IF(cctxPtr->lz4CtxPtr == NULL, allocation_failed);\n            cctxPtr->lz4CtxAlloc = ctxTypeID;\n            cctxPtr->lz4CtxState = ctxTypeID;\n        } else if (cctxPtr->lz4CtxState != ctxTypeID) {\n            /* otherwise, a sufficient buffer is already allocated,\n             * but we need to reset it to the correct context type */\n            if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN) {\n                LZ4_initStream((LZ4_stream_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_stream_t));\n            } else {\n                LZ4_initStreamHC((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, sizeof(LZ4_streamHC_t));\n                LZ4_setCompressionLevel((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel);\n            }\n            cctxPtr->lz4CtxState = ctxTypeID;\n    }   }\n\n    /* Buffer Management */\n    if (cctxPtr->prefs.frameInfo.blockSizeID == 0)\n        cctxPtr->prefs.frameInfo.blockSizeID = LZ4F_BLOCKSIZEID_DEFAULT;\n    cctxPtr->maxBlockSize = LZ4F_getBlockSize(cctxPtr->prefs.frameInfo.blockSizeID);\n\n    {   size_t const requiredBuffSize = preferencesPtr->autoFlush ?\n                ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 64 KB : 0) :  /* only needs past data up to window size */\n                cctxPtr->maxBlockSize + ((cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) ? 128 KB : 0);\n\n        if (cctxPtr->maxBufferSize < requiredBuffSize) {\n            cctxPtr->maxBufferSize = 0;\n            LZ4F_free(cctxPtr->tmpBuff, cctxPtr->cmem);\n            cctxPtr->tmpBuff = (BYTE*)LZ4F_malloc(requiredBuffSize, cctxPtr->cmem);\n            RETURN_ERROR_IF(cctxPtr->tmpBuff == NULL, allocation_failed);\n            cctxPtr->maxBufferSize = requiredBuffSize;\n    }   }\n    cctxPtr->tmpIn = cctxPtr->tmpBuff;\n    cctxPtr->tmpInSize = 0;\n    (void)XXH32_reset(&(cctxPtr->xxh), 0);\n\n    /* context init */\n    cctxPtr->cdict = cdict;\n    if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked) {\n        /* frame init only for blockLinked : blockIndependent will be init at each block */\n        LZ4F_initStream(cctxPtr->lz4CtxPtr, cdict, cctxPtr->prefs.compressionLevel, LZ4F_blockLinked);\n    }\n    if (preferencesPtr->compressionLevel >= LZ4HC_CLEVEL_MIN) {\n        LZ4_favorDecompressionSpeed((LZ4_streamHC_t*)cctxPtr->lz4CtxPtr, (int)preferencesPtr->favorDecSpeed);\n    }\n\n    /* Magic Number */\n    LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER);\n    dstPtr += 4;\n    {   BYTE* const headerStart = dstPtr;\n\n        /* FLG Byte */\n        *dstPtr++ = (BYTE)(((1 & _2BITS) << 6)    /* Version('01') */\n            + ((cctxPtr->prefs.frameInfo.blockMode & _1BIT ) << 5)\n            + ((cctxPtr->prefs.frameInfo.blockChecksumFlag & _1BIT ) << 4)\n            + ((unsigned)(cctxPtr->prefs.frameInfo.contentSize > 0) << 3)\n            + ((cctxPtr->prefs.frameInfo.contentChecksumFlag & _1BIT ) << 2)\n            +  (cctxPtr->prefs.frameInfo.dictID > 0) );\n        /* BD Byte */\n        *dstPtr++ = (BYTE)((cctxPtr->prefs.frameInfo.blockSizeID & _3BITS) << 4);\n        /* Optional Frame content size field */\n        if (cctxPtr->prefs.frameInfo.contentSize) {\n            LZ4F_writeLE64(dstPtr, cctxPtr->prefs.frameInfo.contentSize);\n            dstPtr += 8;\n            cctxPtr->totalInSize = 0;\n        }\n        /* Optional dictionary ID field */\n        if (cctxPtr->prefs.frameInfo.dictID) {\n            LZ4F_writeLE32(dstPtr, cctxPtr->prefs.frameInfo.dictID);\n            dstPtr += 4;\n        }\n        /* Header CRC Byte */\n        *dstPtr = LZ4F_headerChecksum(headerStart, (size_t)(dstPtr - headerStart));\n        dstPtr++;\n    }\n\n    cctxPtr->cStage = 1;   /* header written, now request input data block */\n    return (size_t)(dstPtr - dstStart);\n}\n\n\n/*! LZ4F_compressBegin() :\n *  init streaming compression AND writes frame header into @dstBuffer.\n * @dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.\n * @preferencesPtr can be NULL, in which case default parameters are selected.\n * @return : number of bytes written into dstBuffer for the header\n *        or an error code (can be tested using LZ4F_isError())\n */\nsize_t LZ4F_compressBegin(LZ4F_cctx* cctxPtr,\n                          void* dstBuffer, size_t dstCapacity,\n                          const LZ4F_preferences_t* preferencesPtr)\n{\n    return LZ4F_compressBegin_usingCDict(cctxPtr, dstBuffer, dstCapacity,\n                                         NULL, preferencesPtr);\n}\n\n\n/*  LZ4F_compressBound() :\n * @return minimum capacity of dstBuffer for a given srcSize to handle worst case scenario.\n *  LZ4F_preferences_t structure is optional : if NULL, preferences will be set to cover worst case scenario.\n *  This function cannot fail.\n */\nsize_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr)\n{\n    if (preferencesPtr && preferencesPtr->autoFlush) {\n        return LZ4F_compressBound_internal(srcSize, preferencesPtr, 0);\n    }\n    return LZ4F_compressBound_internal(srcSize, preferencesPtr, (size_t)-1);\n}\n\n\ntypedef int (*compressFunc_t)(void* ctx, const char* src, char* dst, int srcSize, int dstSize, int level, const LZ4F_CDict* cdict);\n\n\n/*! LZ4F_makeBlock():\n *  compress a single block, add header and optional checksum.\n *  assumption : dst buffer capacity is >= BHSize + srcSize + crcSize\n */\nstatic size_t LZ4F_makeBlock(void* dst,\n                       const void* src, size_t srcSize,\n                             compressFunc_t compress, void* lz4ctx, int level,\n                       const LZ4F_CDict* cdict,\n                             LZ4F_blockChecksum_t crcFlag)\n{\n    BYTE* const cSizePtr = (BYTE*)dst;\n    U32 cSize;\n    assert(compress != NULL);\n    cSize = (U32)compress(lz4ctx, (const char*)src, (char*)(cSizePtr+BHSize),\n                          (int)(srcSize), (int)(srcSize-1),\n                          level, cdict);\n\n    if (cSize == 0 || cSize >= srcSize) {\n        cSize = (U32)srcSize;\n        LZ4F_writeLE32(cSizePtr, cSize | LZ4F_BLOCKUNCOMPRESSED_FLAG);\n        memcpy(cSizePtr+BHSize, src, srcSize);\n    } else {\n        LZ4F_writeLE32(cSizePtr, cSize);\n    }\n    if (crcFlag) {\n        U32 const crc32 = XXH32(cSizePtr+BHSize, cSize, 0);  /* checksum of compressed data */\n        LZ4F_writeLE32(cSizePtr+BHSize+cSize, crc32);\n    }\n    return BHSize + cSize + ((U32)crcFlag)*BFSize;\n}\n\n\nstatic int LZ4F_compressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)\n{\n    int const acceleration = (level < 0) ? -level + 1 : 1;\n    DEBUGLOG(5, \"LZ4F_compressBlock (srcSize=%i)\", srcSize);\n    LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent);\n    if (cdict) {\n        return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);\n    } else {\n        return LZ4_compress_fast_extState_fastReset(ctx, src, dst, srcSize, dstCapacity, acceleration);\n    }\n}\n\nstatic int LZ4F_compressBlock_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)\n{\n    int const acceleration = (level < 0) ? -level + 1 : 1;\n    (void)cdict; /* init once at beginning of frame */\n    DEBUGLOG(5, \"LZ4F_compressBlock_continue (srcSize=%i)\", srcSize);\n    return LZ4_compress_fast_continue((LZ4_stream_t*)ctx, src, dst, srcSize, dstCapacity, acceleration);\n}\n\nstatic int LZ4F_compressBlockHC(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)\n{\n    LZ4F_initStream(ctx, cdict, level, LZ4F_blockIndependent);\n    if (cdict) {\n        return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity);\n    }\n    return LZ4_compress_HC_extStateHC_fastReset(ctx, src, dst, srcSize, dstCapacity, level);\n}\n\nstatic int LZ4F_compressBlockHC_continue(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)\n{\n    (void)level; (void)cdict; /* init once at beginning of frame */\n    return LZ4_compress_HC_continue((LZ4_streamHC_t*)ctx, src, dst, srcSize, dstCapacity);\n}\n\nstatic int LZ4F_doNotCompressBlock(void* ctx, const char* src, char* dst, int srcSize, int dstCapacity, int level, const LZ4F_CDict* cdict)\n{\n    (void)ctx; (void)src; (void)dst; (void)srcSize; (void)dstCapacity; (void)level; (void)cdict;\n    return 0;\n}\n\nstatic compressFunc_t LZ4F_selectCompression(LZ4F_blockMode_t blockMode, int level, LZ4F_blockCompression_t  compressMode)\n{\n    if (compressMode == LZ4B_UNCOMPRESSED) return LZ4F_doNotCompressBlock;\n    if (level < LZ4HC_CLEVEL_MIN) {\n        if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlock;\n        return LZ4F_compressBlock_continue;\n    }\n    if (blockMode == LZ4F_blockIndependent) return LZ4F_compressBlockHC;\n    return LZ4F_compressBlockHC_continue;\n}\n\n/* Save history (up to 64KB) into @tmpBuff */\nstatic int LZ4F_localSaveDict(LZ4F_cctx_t* cctxPtr)\n{\n    if (cctxPtr->prefs.compressionLevel < LZ4HC_CLEVEL_MIN)\n        return LZ4_saveDict ((LZ4_stream_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);\n    return LZ4_saveDictHC ((LZ4_streamHC_t*)(cctxPtr->lz4CtxPtr), (char*)(cctxPtr->tmpBuff), 64 KB);\n}\n\ntypedef enum { notDone, fromTmpBuffer, fromSrcBuffer } LZ4F_lastBlockStatus;\n\nstatic const LZ4F_compressOptions_t k_cOptionsNull = { 0, { 0, 0, 0 } };\n\n\n /*! LZ4F_compressUpdateImpl() :\n *  LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.\n *  When successful, the function always entirely consumes @srcBuffer.\n *  src data is either buffered or compressed into @dstBuffer.\n *  If the block compression does not match the compression of the previous block, the old data is flushed\n *  and operations continue with the new compression mode.\n * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr) when block compression is turned on.\n * @compressOptionsPtr is optional : provide NULL to mean \"default\".\n * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered.\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n *  After an error, the state is left in a UB state, and must be re-initialized.\n */\nstatic size_t LZ4F_compressUpdateImpl(LZ4F_cctx* cctxPtr,\n                     void* dstBuffer, size_t dstCapacity,\n                     const void* srcBuffer, size_t srcSize,\n                     const LZ4F_compressOptions_t* compressOptionsPtr,\n                     LZ4F_blockCompression_t blockCompression)\n  {\n    size_t const blockSize = cctxPtr->maxBlockSize;\n    const BYTE* srcPtr = (const BYTE*)srcBuffer;\n    const BYTE* const srcEnd = srcPtr + srcSize;\n    BYTE* const dstStart = (BYTE*)dstBuffer;\n    BYTE* dstPtr = dstStart;\n    LZ4F_lastBlockStatus lastBlockCompressed = notDone;\n    compressFunc_t const compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, blockCompression);\n    size_t bytesWritten;\n    DEBUGLOG(4, \"LZ4F_compressUpdate (srcSize=%zu)\", srcSize);\n\n    RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized);   /* state must be initialized and waiting for next block */\n    if (dstCapacity < LZ4F_compressBound_internal(srcSize, &(cctxPtr->prefs), cctxPtr->tmpInSize))\n        RETURN_ERROR(dstMaxSize_tooSmall);\n\n    if (blockCompression == LZ4B_UNCOMPRESSED && dstCapacity < srcSize)\n        RETURN_ERROR(dstMaxSize_tooSmall);\n\n    /* flush currently written block, to continue with new block compression */\n    if (cctxPtr->blockCompression != blockCompression) {\n        bytesWritten = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr);\n        dstPtr += bytesWritten;\n        cctxPtr->blockCompression = blockCompression;\n    }\n\n    if (compressOptionsPtr == NULL) compressOptionsPtr = &k_cOptionsNull;\n\n    /* complete tmp buffer */\n    if (cctxPtr->tmpInSize > 0) {   /* some data already within tmp buffer */\n        size_t const sizeToCopy = blockSize - cctxPtr->tmpInSize;\n        assert(blockSize > cctxPtr->tmpInSize);\n        if (sizeToCopy > srcSize) {\n            /* add src to tmpIn buffer */\n            memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, srcSize);\n            srcPtr = srcEnd;\n            cctxPtr->tmpInSize += srcSize;\n            /* still needs some CRC */\n        } else {\n            /* complete tmpIn block and then compress it */\n            lastBlockCompressed = fromTmpBuffer;\n            memcpy(cctxPtr->tmpIn + cctxPtr->tmpInSize, srcBuffer, sizeToCopy);\n            srcPtr += sizeToCopy;\n\n            dstPtr += LZ4F_makeBlock(dstPtr,\n                                     cctxPtr->tmpIn, blockSize,\n                                     compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,\n                                     cctxPtr->cdict,\n                                     cctxPtr->prefs.frameInfo.blockChecksumFlag);\n            if (cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) cctxPtr->tmpIn += blockSize;\n            cctxPtr->tmpInSize = 0;\n    }   }\n\n    while ((size_t)(srcEnd - srcPtr) >= blockSize) {\n        /* compress full blocks */\n        lastBlockCompressed = fromSrcBuffer;\n        dstPtr += LZ4F_makeBlock(dstPtr,\n                                 srcPtr, blockSize,\n                                 compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,\n                                 cctxPtr->cdict,\n                                 cctxPtr->prefs.frameInfo.blockChecksumFlag);\n        srcPtr += blockSize;\n    }\n\n    if ((cctxPtr->prefs.autoFlush) && (srcPtr < srcEnd)) {\n        /* autoFlush : remaining input (< blockSize) is compressed */\n        lastBlockCompressed = fromSrcBuffer;\n        dstPtr += LZ4F_makeBlock(dstPtr,\n                                 srcPtr, (size_t)(srcEnd - srcPtr),\n                                 compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,\n                                 cctxPtr->cdict,\n                                 cctxPtr->prefs.frameInfo.blockChecksumFlag);\n        srcPtr = srcEnd;\n    }\n\n    /* preserve dictionary within @tmpBuff whenever necessary */\n    if ((cctxPtr->prefs.frameInfo.blockMode==LZ4F_blockLinked) && (lastBlockCompressed==fromSrcBuffer)) {\n        /* linked blocks are only supported in compressed mode, see LZ4F_uncompressedUpdate */\n        assert(blockCompression == LZ4B_COMPRESSED);\n        if (compressOptionsPtr->stableSrc) {\n            cctxPtr->tmpIn = cctxPtr->tmpBuff;  /* src is stable : dictionary remains in src across invocations */\n        } else {\n            int const realDictSize = LZ4F_localSaveDict(cctxPtr);\n            assert(0 <= realDictSize && realDictSize <= 64 KB);\n            cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;\n        }\n    }\n\n    /* keep tmpIn within limits */\n    if (!(cctxPtr->prefs.autoFlush)  /* no autoflush : there may be some data left within internal buffer */\n      && (cctxPtr->tmpIn + blockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize) )  /* not enough room to store next block */\n    {\n        /* only preserve 64KB within internal buffer. Ensures there is enough room for next block.\n         * note: this situation necessarily implies lastBlockCompressed==fromTmpBuffer */\n        int const realDictSize = LZ4F_localSaveDict(cctxPtr);\n        cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;\n        assert((cctxPtr->tmpIn + blockSize) <= (cctxPtr->tmpBuff + cctxPtr->maxBufferSize));\n    }\n\n    /* some input data left, necessarily < blockSize */\n    if (srcPtr < srcEnd) {\n        /* fill tmp buffer */\n        size_t const sizeToCopy = (size_t)(srcEnd - srcPtr);\n        memcpy(cctxPtr->tmpIn, srcPtr, sizeToCopy);\n        cctxPtr->tmpInSize = sizeToCopy;\n    }\n\n    if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled)\n        (void)XXH32_update(&(cctxPtr->xxh), srcBuffer, srcSize);\n\n    cctxPtr->totalInSize += srcSize;\n    return (size_t)(dstPtr - dstStart);\n}\n\n/*! LZ4F_compressUpdate() :\n *  LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.\n *  When successful, the function always entirely consumes @srcBuffer.\n *  src data is either buffered or compressed into @dstBuffer.\n *  If previously an uncompressed block was written, buffered data is flushed\n *  before appending compressed data is continued.\n * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr).\n * @compressOptionsPtr is optional : provide NULL to mean \"default\".\n * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered.\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n *  After an error, the state is left in a UB state, and must be re-initialized.\n */\nsize_t LZ4F_compressUpdate(LZ4F_cctx* cctxPtr,\n                           void* dstBuffer, size_t dstCapacity,\n                     const void* srcBuffer, size_t srcSize,\n                     const LZ4F_compressOptions_t* compressOptionsPtr)\n{\n     return LZ4F_compressUpdateImpl(cctxPtr,\n                                   dstBuffer, dstCapacity,\n                                   srcBuffer, srcSize,\n                                   compressOptionsPtr, LZ4B_COMPRESSED);\n}\n\n/*! LZ4F_compressUpdate() :\n *  LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.\n *  When successful, the function always entirely consumes @srcBuffer.\n *  src data is either buffered or compressed into @dstBuffer.\n *  If previously an uncompressed block was written, buffered data is flushed\n *  before appending compressed data is continued.\n *  This is only supported when LZ4F_blockIndependent is used\n * @dstCapacity MUST be >= LZ4F_compressBound(srcSize, preferencesPtr).\n * @compressOptionsPtr is optional : provide NULL to mean \"default\".\n * @return : the number of bytes written into dstBuffer. It can be zero, meaning input data was just buffered.\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n *  After an error, the state is left in a UB state, and must be re-initialized.\n */\nsize_t LZ4F_uncompressedUpdate(LZ4F_cctx* cctxPtr,\n                               void* dstBuffer, size_t dstCapacity,\n                         const void* srcBuffer, size_t srcSize,\n                         const LZ4F_compressOptions_t* compressOptionsPtr) {\n    return LZ4F_compressUpdateImpl(cctxPtr,\n                                   dstBuffer, dstCapacity,\n                                   srcBuffer, srcSize,\n                                   compressOptionsPtr, LZ4B_UNCOMPRESSED);\n}\n\n\n/*! LZ4F_flush() :\n *  When compressed data must be sent immediately, without waiting for a block to be filled,\n *  invoke LZ4_flush(), which will immediately compress any remaining data stored within LZ4F_cctx.\n *  The result of the function is the number of bytes written into dstBuffer.\n *  It can be zero, this means there was no data left within LZ4F_cctx.\n *  The function outputs an error code if it fails (can be tested using LZ4F_isError())\n *  LZ4F_compressOptions_t* is optional. NULL is a valid argument.\n */\nsize_t LZ4F_flush(LZ4F_cctx* cctxPtr,\n                  void* dstBuffer, size_t dstCapacity,\n            const LZ4F_compressOptions_t* compressOptionsPtr)\n{\n    BYTE* const dstStart = (BYTE*)dstBuffer;\n    BYTE* dstPtr = dstStart;\n    compressFunc_t compress;\n\n    if (cctxPtr->tmpInSize == 0) return 0;   /* nothing to flush */\n    RETURN_ERROR_IF(cctxPtr->cStage != 1, compressionState_uninitialized);\n    RETURN_ERROR_IF(dstCapacity < (cctxPtr->tmpInSize + BHSize + BFSize), dstMaxSize_tooSmall);\n    (void)compressOptionsPtr;   /* not useful (yet) */\n\n    /* select compression function */\n    compress = LZ4F_selectCompression(cctxPtr->prefs.frameInfo.blockMode, cctxPtr->prefs.compressionLevel, cctxPtr->blockCompression);\n\n    /* compress tmp buffer */\n    dstPtr += LZ4F_makeBlock(dstPtr,\n                             cctxPtr->tmpIn, cctxPtr->tmpInSize,\n                             compress, cctxPtr->lz4CtxPtr, cctxPtr->prefs.compressionLevel,\n                             cctxPtr->cdict,\n                             cctxPtr->prefs.frameInfo.blockChecksumFlag);\n    assert(((void)\"flush overflows dstBuffer!\", (size_t)(dstPtr - dstStart) <= dstCapacity));\n\n    if (cctxPtr->prefs.frameInfo.blockMode == LZ4F_blockLinked)\n        cctxPtr->tmpIn += cctxPtr->tmpInSize;\n    cctxPtr->tmpInSize = 0;\n\n    /* keep tmpIn within limits */\n    if ((cctxPtr->tmpIn + cctxPtr->maxBlockSize) > (cctxPtr->tmpBuff + cctxPtr->maxBufferSize)) {  /* necessarily LZ4F_blockLinked */\n        int const realDictSize = LZ4F_localSaveDict(cctxPtr);\n        cctxPtr->tmpIn = cctxPtr->tmpBuff + realDictSize;\n    }\n\n    return (size_t)(dstPtr - dstStart);\n}\n\n\n/*! LZ4F_compressEnd() :\n *  When you want to properly finish the compressed frame, just call LZ4F_compressEnd().\n *  It will flush whatever data remained within compressionContext (like LZ4_flush())\n *  but also properly finalize the frame, with an endMark and an (optional) checksum.\n *  LZ4F_compressOptions_t structure is optional : you can provide NULL as argument.\n * @return: the number of bytes written into dstBuffer (necessarily >= 4 (endMark size))\n *       or an error code if it fails (can be tested using LZ4F_isError())\n *  The context can then be used again to compress a new frame, starting with LZ4F_compressBegin().\n */\nsize_t LZ4F_compressEnd(LZ4F_cctx* cctxPtr,\n                        void* dstBuffer, size_t dstCapacity,\n                  const LZ4F_compressOptions_t* compressOptionsPtr)\n{\n    BYTE* const dstStart = (BYTE*)dstBuffer;\n    BYTE* dstPtr = dstStart;\n\n    size_t const flushSize = LZ4F_flush(cctxPtr, dstBuffer, dstCapacity, compressOptionsPtr);\n    DEBUGLOG(5,\"LZ4F_compressEnd: dstCapacity=%u\", (unsigned)dstCapacity);\n    FORWARD_IF_ERROR(flushSize);\n    dstPtr += flushSize;\n\n    assert(flushSize <= dstCapacity);\n    dstCapacity -= flushSize;\n\n    RETURN_ERROR_IF(dstCapacity < 4, dstMaxSize_tooSmall);\n    LZ4F_writeLE32(dstPtr, 0);\n    dstPtr += 4;   /* endMark */\n\n    if (cctxPtr->prefs.frameInfo.contentChecksumFlag == LZ4F_contentChecksumEnabled) {\n        U32 const xxh = XXH32_digest(&(cctxPtr->xxh));\n        RETURN_ERROR_IF(dstCapacity < 8, dstMaxSize_tooSmall);\n        DEBUGLOG(5,\"Writing 32-bit content checksum\");\n        LZ4F_writeLE32(dstPtr, xxh);\n        dstPtr+=4;   /* content Checksum */\n    }\n\n    cctxPtr->cStage = 0;   /* state is now re-usable (with identical preferences) */\n\n    if (cctxPtr->prefs.frameInfo.contentSize) {\n        if (cctxPtr->prefs.frameInfo.contentSize != cctxPtr->totalInSize)\n            RETURN_ERROR(frameSize_wrong);\n    }\n\n    return (size_t)(dstPtr - dstStart);\n}\n\n\n/*-***************************************************\n*   Frame Decompression\n*****************************************************/\n\ntypedef enum {\n    dstage_getFrameHeader=0, dstage_storeFrameHeader,\n    dstage_init,\n    dstage_getBlockHeader, dstage_storeBlockHeader,\n    dstage_copyDirect, dstage_getBlockChecksum,\n    dstage_getCBlock, dstage_storeCBlock,\n    dstage_flushOut,\n    dstage_getSuffix, dstage_storeSuffix,\n    dstage_getSFrameSize, dstage_storeSFrameSize,\n    dstage_skipSkippable\n} dStage_t;\n\nstruct LZ4F_dctx_s {\n    LZ4F_CustomMem cmem;\n    LZ4F_frameInfo_t frameInfo;\n    U32    version;\n    dStage_t dStage;\n    U64    frameRemainingSize;\n    size_t maxBlockSize;\n    size_t maxBufferSize;\n    BYTE*  tmpIn;\n    size_t tmpInSize;\n    size_t tmpInTarget;\n    BYTE*  tmpOutBuffer;\n    const BYTE* dict;\n    size_t dictSize;\n    BYTE*  tmpOut;\n    size_t tmpOutSize;\n    size_t tmpOutStart;\n    XXH32_state_t xxh;\n    XXH32_state_t blockChecksum;\n    int    skipChecksum;\n    BYTE   header[LZ4F_HEADER_SIZE_MAX];\n};  /* typedef'd to LZ4F_dctx in lz4frame.h */\n\n\nLZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version)\n{\n    LZ4F_dctx* const dctx = (LZ4F_dctx*)LZ4F_calloc(sizeof(LZ4F_dctx), customMem);\n    if (dctx == NULL) return NULL;\n\n    dctx->cmem = customMem;\n    dctx->version = version;\n    return dctx;\n}\n\n/*! LZ4F_createDecompressionContext() :\n *  Create a decompressionContext object, which will track all decompression operations.\n *  Provides a pointer to a fully allocated and initialized LZ4F_decompressionContext object.\n *  Object can later be released using LZ4F_freeDecompressionContext().\n * @return : if != 0, there was an error during context creation.\n */\nLZ4F_errorCode_t\nLZ4F_createDecompressionContext(LZ4F_dctx** LZ4F_decompressionContextPtr, unsigned versionNumber)\n{\n    assert(LZ4F_decompressionContextPtr != NULL);  /* violation of narrow contract */\n    RETURN_ERROR_IF(LZ4F_decompressionContextPtr == NULL, parameter_null);  /* in case it nonetheless happen in production */\n\n    *LZ4F_decompressionContextPtr = LZ4F_createDecompressionContext_advanced(LZ4F_defaultCMem, versionNumber);\n    if (*LZ4F_decompressionContextPtr == NULL) {  /* failed allocation */\n        RETURN_ERROR(allocation_failed);\n    }\n    return LZ4F_OK_NoError;\n}\n\nLZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx)\n{\n    LZ4F_errorCode_t result = LZ4F_OK_NoError;\n    if (dctx != NULL) {   /* can accept NULL input, like free() */\n      result = (LZ4F_errorCode_t)dctx->dStage;\n      LZ4F_free(dctx->tmpIn, dctx->cmem);\n      LZ4F_free(dctx->tmpOutBuffer, dctx->cmem);\n      LZ4F_free(dctx, dctx->cmem);\n    }\n    return result;\n}\n\n\n/*==---   Streaming Decompression operations   ---==*/\n\nvoid LZ4F_resetDecompressionContext(LZ4F_dctx* dctx)\n{\n    dctx->dStage = dstage_getFrameHeader;\n    dctx->dict = NULL;\n    dctx->dictSize = 0;\n    dctx->skipChecksum = 0;\n}\n\n\n/*! LZ4F_decodeHeader() :\n *  input   : `src` points at the **beginning of the frame**\n *  output  : set internal values of dctx, such as\n *            dctx->frameInfo and dctx->dStage.\n *            Also allocates internal buffers.\n *  @return : nb Bytes read from src (necessarily <= srcSize)\n *            or an error code (testable with LZ4F_isError())\n */\nstatic size_t LZ4F_decodeHeader(LZ4F_dctx* dctx, const void* src, size_t srcSize)\n{\n    unsigned blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictIDFlag, blockSizeID;\n    size_t frameHeaderSize;\n    const BYTE* srcPtr = (const BYTE*)src;\n\n    DEBUGLOG(5, \"LZ4F_decodeHeader\");\n    /* need to decode header to get frameInfo */\n    RETURN_ERROR_IF(srcSize < minFHSize, frameHeader_incomplete);   /* minimal frame header size */\n    MEM_INIT(&(dctx->frameInfo), 0, sizeof(dctx->frameInfo));\n\n    /* special case : skippable frames */\n    if ((LZ4F_readLE32(srcPtr) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START) {\n        dctx->frameInfo.frameType = LZ4F_skippableFrame;\n        if (src == (void*)(dctx->header)) {\n            dctx->tmpInSize = srcSize;\n            dctx->tmpInTarget = 8;\n            dctx->dStage = dstage_storeSFrameSize;\n            return srcSize;\n        } else {\n            dctx->dStage = dstage_getSFrameSize;\n            return 4;\n    }   }\n\n    /* control magic number */\n#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION\n    if (LZ4F_readLE32(srcPtr) != LZ4F_MAGICNUMBER) {\n        DEBUGLOG(4, \"frame header error : unknown magic number\");\n        RETURN_ERROR(frameType_unknown);\n    }\n#endif\n    dctx->frameInfo.frameType = LZ4F_frame;\n\n    /* Flags */\n    {   U32 const FLG = srcPtr[4];\n        U32 const version = (FLG>>6) & _2BITS;\n        blockChecksumFlag = (FLG>>4) & _1BIT;\n        blockMode = (FLG>>5) & _1BIT;\n        contentSizeFlag = (FLG>>3) & _1BIT;\n        contentChecksumFlag = (FLG>>2) & _1BIT;\n        dictIDFlag = FLG & _1BIT;\n        /* validate */\n        if (((FLG>>1)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set); /* Reserved bit */\n        if (version != 1) RETURN_ERROR(headerVersion_wrong);       /* Version Number, only supported value */\n    }\n\n    /* Frame Header Size */\n    frameHeaderSize = minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);\n\n    if (srcSize < frameHeaderSize) {\n        /* not enough input to fully decode frame header */\n        if (srcPtr != dctx->header)\n            memcpy(dctx->header, srcPtr, srcSize);\n        dctx->tmpInSize = srcSize;\n        dctx->tmpInTarget = frameHeaderSize;\n        dctx->dStage = dstage_storeFrameHeader;\n        return srcSize;\n    }\n\n    {   U32 const BD = srcPtr[5];\n        blockSizeID = (BD>>4) & _3BITS;\n        /* validate */\n        if (((BD>>7)&_1BIT) != 0) RETURN_ERROR(reservedFlag_set);   /* Reserved bit */\n        if (blockSizeID < 4) RETURN_ERROR(maxBlockSize_invalid);    /* 4-7 only supported values for the time being */\n        if (((BD>>0)&_4BITS) != 0) RETURN_ERROR(reservedFlag_set);  /* Reserved bits */\n    }\n\n    /* check header */\n    assert(frameHeaderSize > 5);\n#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION\n    {   BYTE const HC = LZ4F_headerChecksum(srcPtr+4, frameHeaderSize-5);\n        RETURN_ERROR_IF(HC != srcPtr[frameHeaderSize-1], headerChecksum_invalid);\n    }\n#endif\n\n    /* save */\n    dctx->frameInfo.blockMode = (LZ4F_blockMode_t)blockMode;\n    dctx->frameInfo.blockChecksumFlag = (LZ4F_blockChecksum_t)blockChecksumFlag;\n    dctx->frameInfo.contentChecksumFlag = (LZ4F_contentChecksum_t)contentChecksumFlag;\n    dctx->frameInfo.blockSizeID = (LZ4F_blockSizeID_t)blockSizeID;\n    dctx->maxBlockSize = LZ4F_getBlockSize((LZ4F_blockSizeID_t)blockSizeID);\n    if (contentSizeFlag)\n        dctx->frameRemainingSize = dctx->frameInfo.contentSize = LZ4F_readLE64(srcPtr+6);\n    if (dictIDFlag)\n        dctx->frameInfo.dictID = LZ4F_readLE32(srcPtr + frameHeaderSize - 5);\n\n    dctx->dStage = dstage_init;\n\n    return frameHeaderSize;\n}\n\n\n/*! LZ4F_headerSize() :\n * @return : size of frame header\n *           or an error code, which can be tested using LZ4F_isError()\n */\nsize_t LZ4F_headerSize(const void* src, size_t srcSize)\n{\n    RETURN_ERROR_IF(src == NULL, srcPtr_wrong);\n\n    /* minimal srcSize to determine header size */\n    if (srcSize < LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH)\n        RETURN_ERROR(frameHeader_incomplete);\n\n    /* special case : skippable frames */\n    if ((LZ4F_readLE32(src) & 0xFFFFFFF0U) == LZ4F_MAGIC_SKIPPABLE_START)\n        return 8;\n\n    /* control magic number */\n#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION\n    if (LZ4F_readLE32(src) != LZ4F_MAGICNUMBER)\n        RETURN_ERROR(frameType_unknown);\n#endif\n\n    /* Frame Header Size */\n    {   BYTE const FLG = ((const BYTE*)src)[4];\n        U32 const contentSizeFlag = (FLG>>3) & _1BIT;\n        U32 const dictIDFlag = FLG & _1BIT;\n        return minFHSize + (contentSizeFlag?8:0) + (dictIDFlag?4:0);\n    }\n}\n\n/*! LZ4F_getFrameInfo() :\n *  This function extracts frame parameters (max blockSize, frame checksum, etc.).\n *  Usage is optional. Objective is to provide relevant information for allocation purposes.\n *  This function works in 2 situations :\n *   - At the beginning of a new frame, in which case it will decode this information from `srcBuffer`, and start the decoding process.\n *     Amount of input data provided must be large enough to successfully decode the frame header.\n *     A header size is variable, but is guaranteed to be <= LZ4F_HEADER_SIZE_MAX bytes. It's possible to provide more input data than this minimum.\n *   - After decoding has been started. In which case, no input is read, frame parameters are extracted from dctx.\n *  The number of bytes consumed from srcBuffer will be updated within *srcSizePtr (necessarily <= original value).\n *  Decompression must resume from (srcBuffer + *srcSizePtr).\n * @return : an hint about how many srcSize bytes LZ4F_decompress() expects for next call,\n *           or an error code which can be tested using LZ4F_isError()\n *  note 1 : in case of error, dctx is not modified. Decoding operations can resume from where they stopped.\n *  note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.\n */\nLZ4F_errorCode_t LZ4F_getFrameInfo(LZ4F_dctx* dctx,\n                                   LZ4F_frameInfo_t* frameInfoPtr,\n                             const void* srcBuffer, size_t* srcSizePtr)\n{\n    LZ4F_STATIC_ASSERT(dstage_getFrameHeader < dstage_storeFrameHeader);\n    if (dctx->dStage > dstage_storeFrameHeader) {\n        /* frameInfo already decoded */\n        size_t o=0, i=0;\n        *srcSizePtr = 0;\n        *frameInfoPtr = dctx->frameInfo;\n        /* returns : recommended nb of bytes for LZ4F_decompress() */\n        return LZ4F_decompress(dctx, NULL, &o, NULL, &i, NULL);\n    } else {\n        if (dctx->dStage == dstage_storeFrameHeader) {\n            /* frame decoding already started, in the middle of header => automatic fail */\n            *srcSizePtr = 0;\n            RETURN_ERROR(frameDecoding_alreadyStarted);\n        } else {\n            size_t const hSize = LZ4F_headerSize(srcBuffer, *srcSizePtr);\n            if (LZ4F_isError(hSize)) { *srcSizePtr=0; return hSize; }\n            if (*srcSizePtr < hSize) {\n                *srcSizePtr=0;\n                RETURN_ERROR(frameHeader_incomplete);\n            }\n\n            {   size_t decodeResult = LZ4F_decodeHeader(dctx, srcBuffer, hSize);\n                if (LZ4F_isError(decodeResult)) {\n                    *srcSizePtr = 0;\n                } else {\n                    *srcSizePtr = decodeResult;\n                    decodeResult = BHSize;   /* block header size */\n                }\n                *frameInfoPtr = dctx->frameInfo;\n                return decodeResult;\n    }   }   }\n}\n\n\n/* LZ4F_updateDict() :\n * only used for LZ4F_blockLinked mode\n * Condition : @dstPtr != NULL\n */\nstatic void LZ4F_updateDict(LZ4F_dctx* dctx,\n                      const BYTE* dstPtr, size_t dstSize, const BYTE* dstBufferStart,\n                      unsigned withinTmp)\n{\n    assert(dstPtr != NULL);\n    if (dctx->dictSize==0) dctx->dict = (const BYTE*)dstPtr;  /* will lead to prefix mode */\n    assert(dctx->dict != NULL);\n\n    if (dctx->dict + dctx->dictSize == dstPtr) {  /* prefix mode, everything within dstBuffer */\n        dctx->dictSize += dstSize;\n        return;\n    }\n\n    assert(dstPtr >= dstBufferStart);\n    if ((size_t)(dstPtr - dstBufferStart) + dstSize >= 64 KB) {  /* history in dstBuffer becomes large enough to become dictionary */\n        dctx->dict = (const BYTE*)dstBufferStart;\n        dctx->dictSize = (size_t)(dstPtr - dstBufferStart) + dstSize;\n        return;\n    }\n\n    assert(dstSize < 64 KB);   /* if dstSize >= 64 KB, dictionary would be set into dstBuffer directly */\n\n    /* dstBuffer does not contain whole useful history (64 KB), so it must be saved within tmpOutBuffer */\n    assert(dctx->tmpOutBuffer != NULL);\n\n    if (withinTmp && (dctx->dict == dctx->tmpOutBuffer)) {   /* continue history within tmpOutBuffer */\n        /* withinTmp expectation : content of [dstPtr,dstSize] is same as [dict+dictSize,dstSize], so we just extend it */\n        assert(dctx->dict + dctx->dictSize == dctx->tmpOut + dctx->tmpOutStart);\n        dctx->dictSize += dstSize;\n        return;\n    }\n\n    if (withinTmp) { /* copy relevant dict portion in front of tmpOut within tmpOutBuffer */\n        size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer);\n        size_t copySize = 64 KB - dctx->tmpOutSize;\n        const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart;\n        if (dctx->tmpOutSize > 64 KB) copySize = 0;\n        if (copySize > preserveSize) copySize = preserveSize;\n\n        memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);\n\n        dctx->dict = dctx->tmpOutBuffer;\n        dctx->dictSize = preserveSize + dctx->tmpOutStart + dstSize;\n        return;\n    }\n\n    if (dctx->dict == dctx->tmpOutBuffer) {    /* copy dst into tmp to complete dict */\n        if (dctx->dictSize + dstSize > dctx->maxBufferSize) {  /* tmp buffer not large enough */\n            size_t const preserveSize = 64 KB - dstSize;\n            memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize);\n            dctx->dictSize = preserveSize;\n        }\n        memcpy(dctx->tmpOutBuffer + dctx->dictSize, dstPtr, dstSize);\n        dctx->dictSize += dstSize;\n        return;\n    }\n\n    /* join dict & dest into tmp */\n    {   size_t preserveSize = 64 KB - dstSize;\n        if (preserveSize > dctx->dictSize) preserveSize = dctx->dictSize;\n        memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - preserveSize, preserveSize);\n        memcpy(dctx->tmpOutBuffer + preserveSize, dstPtr, dstSize);\n        dctx->dict = dctx->tmpOutBuffer;\n        dctx->dictSize = preserveSize + dstSize;\n    }\n}\n\n\n/*! LZ4F_decompress() :\n *  Call this function repetitively to regenerate compressed data in srcBuffer.\n *  The function will attempt to decode up to *srcSizePtr bytes from srcBuffer\n *  into dstBuffer of capacity *dstSizePtr.\n *\n *  The number of bytes regenerated into dstBuffer will be provided within *dstSizePtr (necessarily <= original value).\n *\n *  The number of bytes effectively read from srcBuffer will be provided within *srcSizePtr (necessarily <= original value).\n *  If number of bytes read is < number of bytes provided, then decompression operation is not complete.\n *  Remaining data will have to be presented again in a subsequent invocation.\n *\n *  The function result is an hint of the better srcSize to use for next call to LZ4F_decompress.\n *  Schematically, it's the size of the current (or remaining) compressed block + header of next block.\n *  Respecting the hint provides a small boost to performance, since it allows less buffer shuffling.\n *  Note that this is just a hint, and it's always possible to any srcSize value.\n *  When a frame is fully decoded, @return will be 0.\n *  If decompression failed, @return is an error code which can be tested using LZ4F_isError().\n */\nsize_t LZ4F_decompress(LZ4F_dctx* dctx,\n                       void* dstBuffer, size_t* dstSizePtr,\n                       const void* srcBuffer, size_t* srcSizePtr,\n                       const LZ4F_decompressOptions_t* decompressOptionsPtr)\n{\n    LZ4F_decompressOptions_t optionsNull;\n    const BYTE* const srcStart = (const BYTE*)srcBuffer;\n    const BYTE* const srcEnd = srcStart + *srcSizePtr;\n    const BYTE* srcPtr = srcStart;\n    BYTE* const dstStart = (BYTE*)dstBuffer;\n    BYTE* const dstEnd = dstStart ? dstStart + *dstSizePtr : NULL;\n    BYTE* dstPtr = dstStart;\n    const BYTE* selectedIn = NULL;\n    unsigned doAnotherStage = 1;\n    size_t nextSrcSizeHint = 1;\n\n\n    DEBUGLOG(5, \"LZ4F_decompress : %p,%u => %p,%u\",\n            srcBuffer, (unsigned)*srcSizePtr, dstBuffer, (unsigned)*dstSizePtr);\n    if (dstBuffer == NULL) assert(*dstSizePtr == 0);\n    MEM_INIT(&optionsNull, 0, sizeof(optionsNull));\n    if (decompressOptionsPtr==NULL) decompressOptionsPtr = &optionsNull;\n    *srcSizePtr = 0;\n    *dstSizePtr = 0;\n    assert(dctx != NULL);\n    dctx->skipChecksum |= (decompressOptionsPtr->skipChecksums != 0); /* once set, disable for the remainder of the frame */\n\n    /* behaves as a state machine */\n\n    while (doAnotherStage) {\n\n        switch(dctx->dStage)\n        {\n\n        case dstage_getFrameHeader:\n            DEBUGLOG(6, \"dstage_getFrameHeader\");\n            if ((size_t)(srcEnd-srcPtr) >= maxFHSize) {  /* enough to decode - shortcut */\n                size_t const hSize = LZ4F_decodeHeader(dctx, srcPtr, (size_t)(srcEnd-srcPtr));  /* will update dStage appropriately */\n                FORWARD_IF_ERROR(hSize);\n                srcPtr += hSize;\n                break;\n            }\n            dctx->tmpInSize = 0;\n            if (srcEnd-srcPtr == 0) return minFHSize;   /* 0-size input */\n            dctx->tmpInTarget = minFHSize;   /* minimum size to decode header */\n            dctx->dStage = dstage_storeFrameHeader;\n            /* fall-through */\n\n        case dstage_storeFrameHeader:\n            DEBUGLOG(6, \"dstage_storeFrameHeader\");\n            {   size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize, (size_t)(srcEnd - srcPtr));\n                memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);\n                dctx->tmpInSize += sizeToCopy;\n                srcPtr += sizeToCopy;\n            }\n            if (dctx->tmpInSize < dctx->tmpInTarget) {\n                nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize) + BHSize;   /* rest of header + nextBlockHeader */\n                doAnotherStage = 0;   /* not enough src data, ask for some more */\n                break;\n            }\n            FORWARD_IF_ERROR( LZ4F_decodeHeader(dctx, dctx->header, dctx->tmpInTarget) ); /* will update dStage appropriately */\n            break;\n\n        case dstage_init:\n            DEBUGLOG(6, \"dstage_init\");\n            if (dctx->frameInfo.contentChecksumFlag) (void)XXH32_reset(&(dctx->xxh), 0);\n            /* internal buffers allocation */\n            {   size_t const bufferNeeded = dctx->maxBlockSize\n                    + ((dctx->frameInfo.blockMode==LZ4F_blockLinked) ? 128 KB : 0);\n                if (bufferNeeded > dctx->maxBufferSize) {   /* tmp buffers too small */\n                    dctx->maxBufferSize = 0;   /* ensure allocation will be re-attempted on next entry*/\n                    LZ4F_free(dctx->tmpIn, dctx->cmem);\n                    dctx->tmpIn = (BYTE*)LZ4F_malloc(dctx->maxBlockSize + BFSize /* block checksum */, dctx->cmem);\n                    RETURN_ERROR_IF(dctx->tmpIn == NULL, allocation_failed);\n                    LZ4F_free(dctx->tmpOutBuffer, dctx->cmem);\n                    dctx->tmpOutBuffer= (BYTE*)LZ4F_malloc(bufferNeeded, dctx->cmem);\n                    RETURN_ERROR_IF(dctx->tmpOutBuffer== NULL, allocation_failed);\n                    dctx->maxBufferSize = bufferNeeded;\n            }   }\n            dctx->tmpInSize = 0;\n            dctx->tmpInTarget = 0;\n            dctx->tmpOut = dctx->tmpOutBuffer;\n            dctx->tmpOutStart = 0;\n            dctx->tmpOutSize = 0;\n\n            dctx->dStage = dstage_getBlockHeader;\n            /* fall-through */\n\n        case dstage_getBlockHeader:\n            if ((size_t)(srcEnd - srcPtr) >= BHSize) {\n                selectedIn = srcPtr;\n                srcPtr += BHSize;\n            } else {\n                /* not enough input to read cBlockSize field */\n                dctx->tmpInSize = 0;\n                dctx->dStage = dstage_storeBlockHeader;\n            }\n\n            if (dctx->dStage == dstage_storeBlockHeader)   /* can be skipped */\n        case dstage_storeBlockHeader:\n            {   size_t const remainingInput = (size_t)(srcEnd - srcPtr);\n                size_t const wantedData = BHSize - dctx->tmpInSize;\n                size_t const sizeToCopy = MIN(wantedData, remainingInput);\n                memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);\n                srcPtr += sizeToCopy;\n                dctx->tmpInSize += sizeToCopy;\n\n                if (dctx->tmpInSize < BHSize) {   /* not enough input for cBlockSize */\n                    nextSrcSizeHint = BHSize - dctx->tmpInSize;\n                    doAnotherStage  = 0;\n                    break;\n                }\n                selectedIn = dctx->tmpIn;\n            }   /* if (dctx->dStage == dstage_storeBlockHeader) */\n\n        /* decode block header */\n            {   U32 const blockHeader = LZ4F_readLE32(selectedIn);\n                size_t const nextCBlockSize = blockHeader & 0x7FFFFFFFU;\n                size_t const crcSize = dctx->frameInfo.blockChecksumFlag * BFSize;\n                if (blockHeader==0) {  /* frameEnd signal, no more block */\n                    DEBUGLOG(5, \"end of frame\");\n                    dctx->dStage = dstage_getSuffix;\n                    break;\n                }\n                if (nextCBlockSize > dctx->maxBlockSize) {\n                    RETURN_ERROR(maxBlockSize_invalid);\n                }\n                if (blockHeader & LZ4F_BLOCKUNCOMPRESSED_FLAG) {\n                    /* next block is uncompressed */\n                    dctx->tmpInTarget = nextCBlockSize;\n                    DEBUGLOG(5, \"next block is uncompressed (size %u)\", (U32)nextCBlockSize);\n                    if (dctx->frameInfo.blockChecksumFlag) {\n                        (void)XXH32_reset(&dctx->blockChecksum, 0);\n                    }\n                    dctx->dStage = dstage_copyDirect;\n                    break;\n                }\n                /* next block is a compressed block */\n                dctx->tmpInTarget = nextCBlockSize + crcSize;\n                dctx->dStage = dstage_getCBlock;\n                if (dstPtr==dstEnd || srcPtr==srcEnd) {\n                    nextSrcSizeHint = BHSize + nextCBlockSize + crcSize;\n                    doAnotherStage = 0;\n                }\n                break;\n            }\n\n        case dstage_copyDirect:   /* uncompressed block */\n            DEBUGLOG(6, \"dstage_copyDirect\");\n            {   size_t sizeToCopy;\n                if (dstPtr == NULL) {\n                    sizeToCopy = 0;\n                } else {\n                    size_t const minBuffSize = MIN((size_t)(srcEnd-srcPtr), (size_t)(dstEnd-dstPtr));\n                    sizeToCopy = MIN(dctx->tmpInTarget, minBuffSize);\n                    memcpy(dstPtr, srcPtr, sizeToCopy);\n                    if (!dctx->skipChecksum) {\n                        if (dctx->frameInfo.blockChecksumFlag) {\n                            (void)XXH32_update(&dctx->blockChecksum, srcPtr, sizeToCopy);\n                        }\n                        if (dctx->frameInfo.contentChecksumFlag)\n                            (void)XXH32_update(&dctx->xxh, srcPtr, sizeToCopy);\n                    }\n                    if (dctx->frameInfo.contentSize)\n                        dctx->frameRemainingSize -= sizeToCopy;\n\n                    /* history management (linked blocks only)*/\n                    if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {\n                        LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 0);\n                    }\n                    srcPtr += sizeToCopy;\n                    dstPtr += sizeToCopy;\n                }\n                if (sizeToCopy == dctx->tmpInTarget) {   /* all done */\n                    if (dctx->frameInfo.blockChecksumFlag) {\n                        dctx->tmpInSize = 0;\n                        dctx->dStage = dstage_getBlockChecksum;\n                    } else\n                        dctx->dStage = dstage_getBlockHeader;  /* new block */\n                    break;\n                }\n                dctx->tmpInTarget -= sizeToCopy;  /* need to copy more */\n            }\n            nextSrcSizeHint = dctx->tmpInTarget +\n                            +(dctx->frameInfo.blockChecksumFlag ? BFSize : 0)\n                            + BHSize /* next header size */;\n            doAnotherStage = 0;\n            break;\n\n        /* check block checksum for recently transferred uncompressed block */\n        case dstage_getBlockChecksum:\n            DEBUGLOG(6, \"dstage_getBlockChecksum\");\n            {   const void* crcSrc;\n                if ((srcEnd-srcPtr >= 4) && (dctx->tmpInSize==0)) {\n                    crcSrc = srcPtr;\n                    srcPtr += 4;\n                } else {\n                    size_t const stillToCopy = 4 - dctx->tmpInSize;\n                    size_t const sizeToCopy = MIN(stillToCopy, (size_t)(srcEnd-srcPtr));\n                    memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);\n                    dctx->tmpInSize += sizeToCopy;\n                    srcPtr += sizeToCopy;\n                    if (dctx->tmpInSize < 4) {  /* all input consumed */\n                        doAnotherStage = 0;\n                        break;\n                    }\n                    crcSrc = dctx->header;\n                }\n                if (!dctx->skipChecksum) {\n                    U32 const readCRC = LZ4F_readLE32(crcSrc);\n                    U32 const calcCRC = XXH32_digest(&dctx->blockChecksum);\n#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION\n                    DEBUGLOG(6, \"compare block checksum\");\n                    if (readCRC != calcCRC) {\n                        DEBUGLOG(4, \"incorrect block checksum: %08X != %08X\",\n                                readCRC, calcCRC);\n                        RETURN_ERROR(blockChecksum_invalid);\n                    }\n#else\n                    (void)readCRC;\n                    (void)calcCRC;\n#endif\n            }   }\n            dctx->dStage = dstage_getBlockHeader;  /* new block */\n            break;\n\n        case dstage_getCBlock:\n            DEBUGLOG(6, \"dstage_getCBlock\");\n            if ((size_t)(srcEnd-srcPtr) < dctx->tmpInTarget) {\n                dctx->tmpInSize = 0;\n                dctx->dStage = dstage_storeCBlock;\n                break;\n            }\n            /* input large enough to read full block directly */\n            selectedIn = srcPtr;\n            srcPtr += dctx->tmpInTarget;\n\n            if (0)  /* always jump over next block */\n        case dstage_storeCBlock:\n            {   size_t const wantedData = dctx->tmpInTarget - dctx->tmpInSize;\n                size_t const inputLeft = (size_t)(srcEnd-srcPtr);\n                size_t const sizeToCopy = MIN(wantedData, inputLeft);\n                memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);\n                dctx->tmpInSize += sizeToCopy;\n                srcPtr += sizeToCopy;\n                if (dctx->tmpInSize < dctx->tmpInTarget) { /* need more input */\n                    nextSrcSizeHint = (dctx->tmpInTarget - dctx->tmpInSize)\n                                    + (dctx->frameInfo.blockChecksumFlag ? BFSize : 0)\n                                    + BHSize /* next header size */;\n                    doAnotherStage = 0;\n                    break;\n                }\n                selectedIn = dctx->tmpIn;\n            }\n\n            /* At this stage, input is large enough to decode a block */\n\n            /* First, decode and control block checksum if it exists */\n            if (dctx->frameInfo.blockChecksumFlag) {\n                assert(dctx->tmpInTarget >= 4);\n                dctx->tmpInTarget -= 4;\n                assert(selectedIn != NULL);  /* selectedIn is defined at this stage (either srcPtr, or dctx->tmpIn) */\n                {   U32 const readBlockCrc = LZ4F_readLE32(selectedIn + dctx->tmpInTarget);\n                    U32 const calcBlockCrc = XXH32(selectedIn, dctx->tmpInTarget, 0);\n#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION\n                    RETURN_ERROR_IF(readBlockCrc != calcBlockCrc, blockChecksum_invalid);\n#else\n                    (void)readBlockCrc;\n                    (void)calcBlockCrc;\n#endif\n            }   }\n\n            /* decode directly into destination buffer if there is enough room */\n            if ( ((size_t)(dstEnd-dstPtr) >= dctx->maxBlockSize)\n                 /* unless the dictionary is stored in tmpOut:\n                  * in which case it's faster to decode within tmpOut\n                  * to benefit from prefix speedup */\n              && !(dctx->dict!= NULL && (const BYTE*)dctx->dict + dctx->dictSize == dctx->tmpOut) )\n            {\n                const char* dict = (const char*)dctx->dict;\n                size_t dictSize = dctx->dictSize;\n                int decodedSize;\n                assert(dstPtr != NULL);\n                if (dict && dictSize > 1 GB) {\n                    /* overflow control : dctx->dictSize is an int, avoid truncation / sign issues */\n                    dict += dictSize - 64 KB;\n                    dictSize = 64 KB;\n                }\n                decodedSize = LZ4_decompress_safe_usingDict(\n                        (const char*)selectedIn, (char*)dstPtr,\n                        (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,\n                        dict, (int)dictSize);\n                RETURN_ERROR_IF(decodedSize < 0, decompressionFailed);\n                if ((dctx->frameInfo.contentChecksumFlag) && (!dctx->skipChecksum))\n                    XXH32_update(&(dctx->xxh), dstPtr, (size_t)decodedSize);\n                if (dctx->frameInfo.contentSize)\n                    dctx->frameRemainingSize -= (size_t)decodedSize;\n\n                /* dictionary management */\n                if (dctx->frameInfo.blockMode==LZ4F_blockLinked) {\n                    LZ4F_updateDict(dctx, dstPtr, (size_t)decodedSize, dstStart, 0);\n                }\n\n                dstPtr += decodedSize;\n                dctx->dStage = dstage_getBlockHeader;  /* end of block, let's get another one */\n                break;\n            }\n\n            /* not enough place into dst : decode into tmpOut */\n\n            /* manage dictionary */\n            if (dctx->frameInfo.blockMode == LZ4F_blockLinked) {\n                if (dctx->dict == dctx->tmpOutBuffer) {\n                    /* truncate dictionary to 64 KB if too big */\n                    if (dctx->dictSize > 128 KB) {\n                        memcpy(dctx->tmpOutBuffer, dctx->dict + dctx->dictSize - 64 KB, 64 KB);\n                        dctx->dictSize = 64 KB;\n                    }\n                    dctx->tmpOut = dctx->tmpOutBuffer + dctx->dictSize;\n                } else {  /* dict not within tmpOut */\n                    size_t const reservedDictSpace = MIN(dctx->dictSize, 64 KB);\n                    dctx->tmpOut = dctx->tmpOutBuffer + reservedDictSpace;\n            }   }\n\n            /* Decode block into tmpOut */\n            {   const char* dict = (const char*)dctx->dict;\n                size_t dictSize = dctx->dictSize;\n                int decodedSize;\n                if (dict && dictSize > 1 GB) {\n                    /* the dictSize param is an int, avoid truncation / sign issues */\n                    dict += dictSize - 64 KB;\n                    dictSize = 64 KB;\n                }\n                decodedSize = LZ4_decompress_safe_usingDict(\n                        (const char*)selectedIn, (char*)dctx->tmpOut,\n                        (int)dctx->tmpInTarget, (int)dctx->maxBlockSize,\n                        dict, (int)dictSize);\n                RETURN_ERROR_IF(decodedSize < 0, decompressionFailed);\n                if (dctx->frameInfo.contentChecksumFlag && !dctx->skipChecksum)\n                    XXH32_update(&(dctx->xxh), dctx->tmpOut, (size_t)decodedSize);\n                if (dctx->frameInfo.contentSize)\n                    dctx->frameRemainingSize -= (size_t)decodedSize;\n                dctx->tmpOutSize = (size_t)decodedSize;\n                dctx->tmpOutStart = 0;\n                dctx->dStage = dstage_flushOut;\n            }\n            /* fall-through */\n\n        case dstage_flushOut:  /* flush decoded data from tmpOut to dstBuffer */\n            DEBUGLOG(6, \"dstage_flushOut\");\n            if (dstPtr != NULL) {\n                size_t const sizeToCopy = MIN(dctx->tmpOutSize - dctx->tmpOutStart, (size_t)(dstEnd-dstPtr));\n                memcpy(dstPtr, dctx->tmpOut + dctx->tmpOutStart, sizeToCopy);\n\n                /* dictionary management */\n                if (dctx->frameInfo.blockMode == LZ4F_blockLinked)\n                    LZ4F_updateDict(dctx, dstPtr, sizeToCopy, dstStart, 1 /*withinTmp*/);\n\n                dctx->tmpOutStart += sizeToCopy;\n                dstPtr += sizeToCopy;\n            }\n            if (dctx->tmpOutStart == dctx->tmpOutSize) { /* all flushed */\n                dctx->dStage = dstage_getBlockHeader;  /* get next block */\n                break;\n            }\n            /* could not flush everything : stop there, just request a block header */\n            doAnotherStage = 0;\n            nextSrcSizeHint = BHSize;\n            break;\n\n        case dstage_getSuffix:\n            RETURN_ERROR_IF(dctx->frameRemainingSize, frameSize_wrong);   /* incorrect frame size decoded */\n            if (!dctx->frameInfo.contentChecksumFlag) {  /* no checksum, frame is completed */\n                nextSrcSizeHint = 0;\n                LZ4F_resetDecompressionContext(dctx);\n                doAnotherStage = 0;\n                break;\n            }\n            if ((srcEnd - srcPtr) < 4) {  /* not enough size for entire CRC */\n                dctx->tmpInSize = 0;\n                dctx->dStage = dstage_storeSuffix;\n            } else {\n                selectedIn = srcPtr;\n                srcPtr += 4;\n            }\n\n            if (dctx->dStage == dstage_storeSuffix)   /* can be skipped */\n        case dstage_storeSuffix:\n            {   size_t const remainingInput = (size_t)(srcEnd - srcPtr);\n                size_t const wantedData = 4 - dctx->tmpInSize;\n                size_t const sizeToCopy = MIN(wantedData, remainingInput);\n                memcpy(dctx->tmpIn + dctx->tmpInSize, srcPtr, sizeToCopy);\n                srcPtr += sizeToCopy;\n                dctx->tmpInSize += sizeToCopy;\n                if (dctx->tmpInSize < 4) { /* not enough input to read complete suffix */\n                    nextSrcSizeHint = 4 - dctx->tmpInSize;\n                    doAnotherStage=0;\n                    break;\n                }\n                selectedIn = dctx->tmpIn;\n            }   /* if (dctx->dStage == dstage_storeSuffix) */\n\n        /* case dstage_checkSuffix: */   /* no direct entry, avoid initialization risks */\n            if (!dctx->skipChecksum) {\n                U32 const readCRC = LZ4F_readLE32(selectedIn);\n                U32 const resultCRC = XXH32_digest(&(dctx->xxh));\n#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION\n                RETURN_ERROR_IF(readCRC != resultCRC, contentChecksum_invalid);\n#else\n                (void)readCRC;\n                (void)resultCRC;\n#endif\n            }\n            nextSrcSizeHint = 0;\n            LZ4F_resetDecompressionContext(dctx);\n            doAnotherStage = 0;\n            break;\n\n        case dstage_getSFrameSize:\n            if ((srcEnd - srcPtr) >= 4) {\n                selectedIn = srcPtr;\n                srcPtr += 4;\n            } else {\n                /* not enough input to read cBlockSize field */\n                dctx->tmpInSize = 4;\n                dctx->tmpInTarget = 8;\n                dctx->dStage = dstage_storeSFrameSize;\n            }\n\n            if (dctx->dStage == dstage_storeSFrameSize)\n        case dstage_storeSFrameSize:\n            {   size_t const sizeToCopy = MIN(dctx->tmpInTarget - dctx->tmpInSize,\n                                             (size_t)(srcEnd - srcPtr) );\n                memcpy(dctx->header + dctx->tmpInSize, srcPtr, sizeToCopy);\n                srcPtr += sizeToCopy;\n                dctx->tmpInSize += sizeToCopy;\n                if (dctx->tmpInSize < dctx->tmpInTarget) {\n                    /* not enough input to get full sBlockSize; wait for more */\n                    nextSrcSizeHint = dctx->tmpInTarget - dctx->tmpInSize;\n                    doAnotherStage = 0;\n                    break;\n                }\n                selectedIn = dctx->header + 4;\n            }   /* if (dctx->dStage == dstage_storeSFrameSize) */\n\n        /* case dstage_decodeSFrameSize: */   /* no direct entry */\n            {   size_t const SFrameSize = LZ4F_readLE32(selectedIn);\n                dctx->frameInfo.contentSize = SFrameSize;\n                dctx->tmpInTarget = SFrameSize;\n                dctx->dStage = dstage_skipSkippable;\n                break;\n            }\n\n        case dstage_skipSkippable:\n            {   size_t const skipSize = MIN(dctx->tmpInTarget, (size_t)(srcEnd-srcPtr));\n                srcPtr += skipSize;\n                dctx->tmpInTarget -= skipSize;\n                doAnotherStage = 0;\n                nextSrcSizeHint = dctx->tmpInTarget;\n                if (nextSrcSizeHint) break;  /* still more to skip */\n                /* frame fully skipped : prepare context for a new frame */\n                LZ4F_resetDecompressionContext(dctx);\n                break;\n            }\n        }   /* switch (dctx->dStage) */\n    }   /* while (doAnotherStage) */\n\n    /* preserve history within tmpOut whenever necessary */\n    LZ4F_STATIC_ASSERT((unsigned)dstage_init == 2);\n    if ( (dctx->frameInfo.blockMode==LZ4F_blockLinked)  /* next block will use up to 64KB from previous ones */\n      && (dctx->dict != dctx->tmpOutBuffer)             /* dictionary is not already within tmp */\n      && (dctx->dict != NULL)                           /* dictionary exists */\n      && (!decompressOptionsPtr->stableDst)             /* cannot rely on dst data to remain there for next call */\n      && ((unsigned)(dctx->dStage)-2 < (unsigned)(dstage_getSuffix)-2) )  /* valid stages : [init ... getSuffix[ */\n    {\n        if (dctx->dStage == dstage_flushOut) {\n            size_t const preserveSize = (size_t)(dctx->tmpOut - dctx->tmpOutBuffer);\n            size_t copySize = 64 KB - dctx->tmpOutSize;\n            const BYTE* oldDictEnd = dctx->dict + dctx->dictSize - dctx->tmpOutStart;\n            if (dctx->tmpOutSize > 64 KB) copySize = 0;\n            if (copySize > preserveSize) copySize = preserveSize;\n            assert(dctx->tmpOutBuffer != NULL);\n\n            memcpy(dctx->tmpOutBuffer + preserveSize - copySize, oldDictEnd - copySize, copySize);\n\n            dctx->dict = dctx->tmpOutBuffer;\n            dctx->dictSize = preserveSize + dctx->tmpOutStart;\n        } else {\n            const BYTE* const oldDictEnd = dctx->dict + dctx->dictSize;\n            size_t const newDictSize = MIN(dctx->dictSize, 64 KB);\n\n            memcpy(dctx->tmpOutBuffer, oldDictEnd - newDictSize, newDictSize);\n\n            dctx->dict = dctx->tmpOutBuffer;\n            dctx->dictSize = newDictSize;\n            dctx->tmpOut = dctx->tmpOutBuffer + newDictSize;\n        }\n    }\n\n    *srcSizePtr = (size_t)(srcPtr - srcStart);\n    *dstSizePtr = (size_t)(dstPtr - dstStart);\n    return nextSrcSizeHint;\n}\n\n/*! LZ4F_decompress_usingDict() :\n *  Same as LZ4F_decompress(), using a predefined dictionary.\n *  Dictionary is used \"in place\", without any preprocessing.\n *  It must remain accessible throughout the entire frame decoding.\n */\nsize_t LZ4F_decompress_usingDict(LZ4F_dctx* dctx,\n                       void* dstBuffer, size_t* dstSizePtr,\n                       const void* srcBuffer, size_t* srcSizePtr,\n                       const void* dict, size_t dictSize,\n                       const LZ4F_decompressOptions_t* decompressOptionsPtr)\n{\n    if (dctx->dStage <= dstage_init) {\n        dctx->dict = (const BYTE*)dict;\n        dctx->dictSize = dictSize;\n    }\n    return LZ4F_decompress(dctx, dstBuffer, dstSizePtr,\n                           srcBuffer, srcSizePtr,\n                           decompressOptionsPtr);\n}\n"
  },
  {
    "path": "lib/LZ4F/lz4frame.h",
    "content": "/*\n   LZ4F - LZ4-Frame library\n   Header File\n   Copyright (C) 2011-2020, Yann Collet.\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n   - LZ4 source repository : https://github.com/lz4/lz4\n   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n\n/* LZ4F is a stand-alone API able to create and decode LZ4 frames\n * conformant with specification v1.6.1 in doc/lz4_Frame_format.md .\n * Generated frames are compatible with `lz4` CLI.\n *\n * LZ4F also offers streaming capabilities.\n *\n * lz4.h is not required when using lz4frame.h,\n * except to extract common constants such as LZ4_VERSION_NUMBER.\n * */\n\n#ifndef LZ4F_H_09782039843\n#define LZ4F_H_09782039843\n\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n/* ---   Dependency   --- */\n#include <stddef.h>   /* size_t */\n\n\n/**\n * Introduction\n *\n * lz4frame.h implements LZ4 frame specification: see doc/lz4_Frame_format.md .\n * LZ4 Frames are compatible with `lz4` CLI,\n * and designed to be interoperable with any system.\n**/\n\n/*-***************************************************************\n *  Compiler specifics\n *****************************************************************/\n/*  LZ4_DLL_EXPORT :\n *  Enable exporting of functions when building a Windows DLL\n *  LZ4FLIB_VISIBILITY :\n *  Control library symbols visibility.\n */\n#ifndef LZ4FLIB_VISIBILITY\n#  if defined(__GNUC__) && (__GNUC__ >= 4)\n#    define LZ4FLIB_VISIBILITY __attribute__ ((visibility (\"default\")))\n#  else\n#    define LZ4FLIB_VISIBILITY\n#  endif\n#endif\n#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1)\n#  define LZ4FLIB_API __declspec(dllexport) LZ4FLIB_VISIBILITY\n#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1)\n#  define LZ4FLIB_API __declspec(dllimport) LZ4FLIB_VISIBILITY\n#else\n#  define LZ4FLIB_API LZ4FLIB_VISIBILITY\n#endif\n\n#ifdef LZ4F_DISABLE_DEPRECATE_WARNINGS\n#  define LZ4F_DEPRECATE(x) x\n#else\n#  if defined(_MSC_VER)\n#    define LZ4F_DEPRECATE(x) x   /* __declspec(deprecated) x - only works with C++ */\n#  elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 6))\n#    define LZ4F_DEPRECATE(x) x __attribute__((deprecated))\n#  else\n#    define LZ4F_DEPRECATE(x) x   /* no deprecation warning for this compiler */\n#  endif\n#endif\n\n\n/*-************************************\n *  Error management\n **************************************/\ntypedef size_t LZ4F_errorCode_t;\n\nLZ4FLIB_API unsigned    LZ4F_isError(LZ4F_errorCode_t code);   /**< tells when a function result is an error code */\nLZ4FLIB_API const char* LZ4F_getErrorName(LZ4F_errorCode_t code);   /**< return error code string; for debugging */\n\n\n/*-************************************\n *  Frame compression types\n ************************************* */\n/* #define LZ4F_ENABLE_OBSOLETE_ENUMS   // uncomment to enable obsolete enums */\n#ifdef LZ4F_ENABLE_OBSOLETE_ENUMS\n#  define LZ4F_OBSOLETE_ENUM(x) , LZ4F_DEPRECATE(x) = LZ4F_##x\n#else\n#  define LZ4F_OBSOLETE_ENUM(x)\n#endif\n\n/* The larger the block size, the (slightly) better the compression ratio,\n * though there are diminishing returns.\n * Larger blocks also increase memory usage on both compression and decompression sides.\n */\ntypedef enum {\n    LZ4F_default=0,\n    LZ4F_max64KB=4,\n    LZ4F_max256KB=5,\n    LZ4F_max1MB=6,\n    LZ4F_max4MB=7\n    LZ4F_OBSOLETE_ENUM(max64KB)\n    LZ4F_OBSOLETE_ENUM(max256KB)\n    LZ4F_OBSOLETE_ENUM(max1MB)\n    LZ4F_OBSOLETE_ENUM(max4MB)\n} LZ4F_blockSizeID_t;\n\n/* Linked blocks sharply reduce inefficiencies when using small blocks,\n * they compress better.\n * However, some LZ4 decoders are only compatible with independent blocks */\ntypedef enum {\n    LZ4F_blockLinked=0,\n    LZ4F_blockIndependent\n    LZ4F_OBSOLETE_ENUM(blockLinked)\n    LZ4F_OBSOLETE_ENUM(blockIndependent)\n} LZ4F_blockMode_t;\n\ntypedef enum {\n    LZ4F_noContentChecksum=0,\n    LZ4F_contentChecksumEnabled\n    LZ4F_OBSOLETE_ENUM(noContentChecksum)\n    LZ4F_OBSOLETE_ENUM(contentChecksumEnabled)\n} LZ4F_contentChecksum_t;\n\ntypedef enum {\n    LZ4F_noBlockChecksum=0,\n    LZ4F_blockChecksumEnabled\n} LZ4F_blockChecksum_t;\n\ntypedef enum {\n    LZ4F_frame=0,\n    LZ4F_skippableFrame\n    LZ4F_OBSOLETE_ENUM(skippableFrame)\n} LZ4F_frameType_t;\n\n#ifdef LZ4F_ENABLE_OBSOLETE_ENUMS\ntypedef LZ4F_blockSizeID_t blockSizeID_t;\ntypedef LZ4F_blockMode_t blockMode_t;\ntypedef LZ4F_frameType_t frameType_t;\ntypedef LZ4F_contentChecksum_t contentChecksum_t;\n#endif\n\n/*! LZ4F_frameInfo_t :\n *  makes it possible to set or read frame parameters.\n *  Structure must be first init to 0, using memset() or LZ4F_INIT_FRAMEINFO,\n *  setting all parameters to default.\n *  It's then possible to update selectively some parameters */\ntypedef struct {\n  LZ4F_blockSizeID_t     blockSizeID;         /* max64KB, max256KB, max1MB, max4MB; 0 == default */\n  LZ4F_blockMode_t       blockMode;           /* LZ4F_blockLinked, LZ4F_blockIndependent; 0 == default */\n  LZ4F_contentChecksum_t contentChecksumFlag; /* 1: frame terminated with 32-bit checksum of decompressed data; 0: disabled (default) */\n  LZ4F_frameType_t       frameType;           /* read-only field : LZ4F_frame or LZ4F_skippableFrame */\n  unsigned long long     contentSize;         /* Size of uncompressed content ; 0 == unknown */\n  unsigned               dictID;              /* Dictionary ID, sent by compressor to help decoder select correct dictionary; 0 == no dictID provided */\n  LZ4F_blockChecksum_t   blockChecksumFlag;   /* 1: each block followed by a checksum of block's compressed data; 0: disabled (default) */\n} LZ4F_frameInfo_t;\n\n#define LZ4F_INIT_FRAMEINFO   { LZ4F_default, LZ4F_blockLinked, LZ4F_noContentChecksum, LZ4F_frame, 0ULL, 0U, LZ4F_noBlockChecksum }    /* v1.8.3+ */\n\n/*! LZ4F_preferences_t :\n *  makes it possible to supply advanced compression instructions to streaming interface.\n *  Structure must be first init to 0, using memset() or LZ4F_INIT_PREFERENCES,\n *  setting all parameters to default.\n *  All reserved fields must be set to zero. */\ntypedef struct {\n  LZ4F_frameInfo_t frameInfo;\n  int      compressionLevel;    /* 0: default (fast mode); values > LZ4HC_CLEVEL_MAX count as LZ4HC_CLEVEL_MAX; values < 0 trigger \"fast acceleration\" */\n  unsigned autoFlush;           /* 1: always flush; reduces usage of internal buffers */\n  unsigned favorDecSpeed;       /* 1: parser favors decompression speed vs compression ratio. Only works for high compression modes (>= LZ4HC_CLEVEL_OPT_MIN) */  /* v1.8.2+ */\n  unsigned reserved[3];         /* must be zero for forward compatibility */\n} LZ4F_preferences_t;\n\n#define LZ4F_INIT_PREFERENCES   { LZ4F_INIT_FRAMEINFO, 0, 0u, 0u, { 0u, 0u, 0u } }    /* v1.8.3+ */\n\n\n/*-*********************************\n*  Simple compression function\n***********************************/\n\nLZ4FLIB_API int LZ4F_compressionLevel_max(void);   /* v1.8.0+ */\n\n/*! LZ4F_compressFrameBound() :\n *  Returns the maximum possible compressed size with LZ4F_compressFrame() given srcSize and preferences.\n * `preferencesPtr` is optional. It can be replaced by NULL, in which case, the function will assume default preferences.\n *  Note : this result is only usable with LZ4F_compressFrame().\n *         It may also be relevant to LZ4F_compressUpdate() _only if_ no flush() operation is ever performed.\n */\nLZ4FLIB_API size_t LZ4F_compressFrameBound(size_t srcSize, const LZ4F_preferences_t* preferencesPtr);\n\n/*! LZ4F_compressFrame() :\n *  Compress srcBuffer content into an LZ4-compressed frame.\n *  It's a one shot operation, all input content is consumed, and all output is generated.\n *\n *  Note : it's a stateless operation (no LZ4F_cctx state needed).\n *  In order to reduce load on the allocator, LZ4F_compressFrame(), by default,\n *  uses the stack to allocate space for the compression state and some table.\n *  If this usage of the stack is too much for your application,\n *  consider compiling `lz4frame.c` with compile-time macro LZ4F_HEAPMODE set to 1 instead.\n *  All state allocations will use the Heap.\n *  It also means each invocation of LZ4F_compressFrame() will trigger several internal alloc/free invocations.\n *\n * @dstCapacity MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).\n * @preferencesPtr is optional : one can provide NULL, in which case all preferences are set to default.\n * @return : number of bytes written into dstBuffer.\n *           or an error code if it fails (can be tested using LZ4F_isError())\n */\nLZ4FLIB_API size_t LZ4F_compressFrame(void* dstBuffer, size_t dstCapacity,\n                                const void* srcBuffer, size_t srcSize,\n                                const LZ4F_preferences_t* preferencesPtr);\n\n\n/*-***********************************\n*  Advanced compression functions\n*************************************/\ntypedef struct LZ4F_cctx_s LZ4F_cctx;   /* incomplete type */\ntypedef LZ4F_cctx* LZ4F_compressionContext_t;  /* for compatibility with older APIs, prefer using LZ4F_cctx */\n\ntypedef struct {\n  unsigned stableSrc;    /* 1 == src content will remain present on future calls to LZ4F_compress(); skip copying src content within tmp buffer */\n  unsigned reserved[3];\n} LZ4F_compressOptions_t;\n\n/*---   Resource Management   ---*/\n\n#define LZ4F_VERSION 100    /* This number can be used to check for an incompatible API breaking change */\nLZ4FLIB_API unsigned LZ4F_getVersion(void);\n\n/*! LZ4F_createCompressionContext() :\n *  The first thing to do is to create a compressionContext object,\n *  which will keep track of operation state during streaming compression.\n *  This is achieved using LZ4F_createCompressionContext(), which takes as argument a version,\n *  and a pointer to LZ4F_cctx*, to write the resulting pointer into.\n *  @version provided MUST be LZ4F_VERSION. It is intended to track potential version mismatch, notably when using DLL.\n *  The function provides a pointer to a fully allocated LZ4F_cctx object.\n *  @cctxPtr MUST be != NULL.\n *  If @return != zero, context creation failed.\n *  A created compression context can be employed multiple times for consecutive streaming operations.\n *  Once all streaming compression jobs are completed,\n *  the state object can be released using LZ4F_freeCompressionContext().\n *  Note1 : LZ4F_freeCompressionContext() is always successful. Its return value can be ignored.\n *  Note2 : LZ4F_freeCompressionContext() works fine with NULL input pointers (do nothing).\n**/\nLZ4FLIB_API LZ4F_errorCode_t LZ4F_createCompressionContext(LZ4F_cctx** cctxPtr, unsigned version);\nLZ4FLIB_API LZ4F_errorCode_t LZ4F_freeCompressionContext(LZ4F_cctx* cctx);\n\n\n/*----    Compression    ----*/\n\n#define LZ4F_HEADER_SIZE_MIN  7   /* LZ4 Frame header size can vary, depending on selected parameters */\n#define LZ4F_HEADER_SIZE_MAX 19\n\n/* Size in bytes of a block header in little-endian format. Highest bit indicates if block data is uncompressed */\n#define LZ4F_BLOCK_HEADER_SIZE 4\n\n/* Size in bytes of a block checksum footer in little-endian format. */\n#define LZ4F_BLOCK_CHECKSUM_SIZE 4\n\n/* Size in bytes of the content checksum. */\n#define LZ4F_CONTENT_CHECKSUM_SIZE 4\n\n/*! LZ4F_compressBegin() :\n *  will write the frame header into dstBuffer.\n *  dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.\n * `prefsPtr` is optional : NULL can be provided to set all preferences to default.\n * @return : number of bytes written into dstBuffer for the header\n *           or an error code (which can be tested using LZ4F_isError())\n */\nLZ4FLIB_API size_t LZ4F_compressBegin(LZ4F_cctx* cctx,\n                                      void* dstBuffer, size_t dstCapacity,\n                                      const LZ4F_preferences_t* prefsPtr);\n\n/*! LZ4F_compressBound() :\n *  Provides minimum dstCapacity required to guarantee success of\n *  LZ4F_compressUpdate(), given a srcSize and preferences, for a worst case scenario.\n *  When srcSize==0, LZ4F_compressBound() provides an upper bound for LZ4F_flush() and LZ4F_compressEnd() instead.\n *  Note that the result is only valid for a single invocation of LZ4F_compressUpdate().\n *  When invoking LZ4F_compressUpdate() multiple times,\n *  if the output buffer is gradually filled up instead of emptied and re-used from its start,\n *  one must check if there is enough remaining capacity before each invocation, using LZ4F_compressBound().\n * @return is always the same for a srcSize and prefsPtr.\n *  prefsPtr is optional : when NULL is provided, preferences will be set to cover worst case scenario.\n *  tech details :\n * @return if automatic flushing is not enabled, includes the possibility that internal buffer might already be filled by up to (blockSize-1) bytes.\n *  It also includes frame footer (ending + checksum), since it might be generated by LZ4F_compressEnd().\n * @return doesn't include frame header, as it was already generated by LZ4F_compressBegin().\n */\nLZ4FLIB_API size_t LZ4F_compressBound(size_t srcSize, const LZ4F_preferences_t* prefsPtr);\n\n/*! LZ4F_compressUpdate() :\n *  LZ4F_compressUpdate() can be called repetitively to compress as much data as necessary.\n *  Important rule: dstCapacity MUST be large enough to ensure operation success even in worst case situations.\n *  This value is provided by LZ4F_compressBound().\n *  If this condition is not respected, LZ4F_compress() will fail (result is an errorCode).\n *  After an error, the state is left in a UB state, and must be re-initialized or freed.\n *  If previously an uncompressed block was written, buffered data is flushed\n *  before appending compressed data is continued.\n * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default.\n * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered).\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n */\nLZ4FLIB_API size_t LZ4F_compressUpdate(LZ4F_cctx* cctx,\n                                       void* dstBuffer, size_t dstCapacity,\n                                 const void* srcBuffer, size_t srcSize,\n                                 const LZ4F_compressOptions_t* cOptPtr);\n\n/*! LZ4F_flush() :\n *  When data must be generated and sent immediately, without waiting for a block to be completely filled,\n *  it's possible to call LZ4_flush(). It will immediately compress any data buffered within cctx.\n * `dstCapacity` must be large enough to ensure the operation will be successful.\n * `cOptPtr` is optional : it's possible to provide NULL, all options will be set to default.\n * @return : nb of bytes written into dstBuffer (can be zero, when there is no data stored within cctx)\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n *  Note : LZ4F_flush() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr).\n */\nLZ4FLIB_API size_t LZ4F_flush(LZ4F_cctx* cctx,\n                              void* dstBuffer, size_t dstCapacity,\n                        const LZ4F_compressOptions_t* cOptPtr);\n\n/*! LZ4F_compressEnd() :\n *  To properly finish an LZ4 frame, invoke LZ4F_compressEnd().\n *  It will flush whatever data remained within `cctx` (like LZ4_flush())\n *  and properly finalize the frame, with an endMark and a checksum.\n * `cOptPtr` is optional : NULL can be provided, in which case all options will be set to default.\n * @return : nb of bytes written into dstBuffer, necessarily >= 4 (endMark),\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n *  Note : LZ4F_compressEnd() is guaranteed to be successful when dstCapacity >= LZ4F_compressBound(0, prefsPtr).\n *  A successful call to LZ4F_compressEnd() makes `cctx` available again for another compression task.\n */\nLZ4FLIB_API size_t LZ4F_compressEnd(LZ4F_cctx* cctx,\n                                    void* dstBuffer, size_t dstCapacity,\n                              const LZ4F_compressOptions_t* cOptPtr);\n\n\n/*-*********************************\n*  Decompression functions\n***********************************/\ntypedef struct LZ4F_dctx_s LZ4F_dctx;   /* incomplete type */\ntypedef LZ4F_dctx* LZ4F_decompressionContext_t;   /* compatibility with previous API versions */\n\ntypedef struct {\n  unsigned stableDst;     /* pledges that last 64KB decompressed data will remain available unmodified between invocations.\n                           * This optimization skips storage operations in tmp buffers. */\n  unsigned skipChecksums; /* disable checksum calculation and verification, even when one is present in frame, to save CPU time.\n                           * Setting this option to 1 once disables all checksums for the rest of the frame. */\n  unsigned reserved1;     /* must be set to zero for forward compatibility */\n  unsigned reserved0;     /* idem */\n} LZ4F_decompressOptions_t;\n\n\n/* Resource management */\n\n/*! LZ4F_createDecompressionContext() :\n *  Create an LZ4F_dctx object, to track all decompression operations.\n *  @version provided MUST be LZ4F_VERSION.\n *  @dctxPtr MUST be valid.\n *  The function fills @dctxPtr with the value of a pointer to an allocated and initialized LZ4F_dctx object.\n *  The @return is an errorCode, which can be tested using LZ4F_isError().\n *  dctx memory can be released using LZ4F_freeDecompressionContext();\n *  Result of LZ4F_freeDecompressionContext() indicates current state of decompressionContext when being released.\n *  That is, it should be == 0 if decompression has been completed fully and correctly.\n */\nLZ4FLIB_API LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_dctx** dctxPtr, unsigned version);\nLZ4FLIB_API LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_dctx* dctx);\n\n\n/*-***********************************\n*  Streaming decompression functions\n*************************************/\n\n#define LZ4F_MAGICNUMBER 0x184D2204U\n#define LZ4F_MAGIC_SKIPPABLE_START 0x184D2A50U\n#define LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH 5\n\n/*! LZ4F_headerSize() : v1.9.0+\n *  Provide the header size of a frame starting at `src`.\n * `srcSize` must be >= LZ4F_MIN_SIZE_TO_KNOW_HEADER_LENGTH,\n *  which is enough to decode the header length.\n * @return : size of frame header\n *           or an error code, which can be tested using LZ4F_isError()\n *  note : Frame header size is variable, but is guaranteed to be\n *         >= LZ4F_HEADER_SIZE_MIN bytes, and <= LZ4F_HEADER_SIZE_MAX bytes.\n */\nLZ4FLIB_API size_t LZ4F_headerSize(const void* src, size_t srcSize);\n\n/*! LZ4F_getFrameInfo() :\n *  This function extracts frame parameters (max blockSize, dictID, etc.).\n *  Its usage is optional: user can also invoke LZ4F_decompress() directly.\n *\n *  Extracted information will fill an existing LZ4F_frameInfo_t structure.\n *  This can be useful for allocation and dictionary identification purposes.\n *\n *  LZ4F_getFrameInfo() can work in the following situations :\n *\n *  1) At the beginning of a new frame, before any invocation of LZ4F_decompress().\n *     It will decode header from `srcBuffer`,\n *     consuming the header and starting the decoding process.\n *\n *     Input size must be large enough to contain the full frame header.\n *     Frame header size can be known beforehand by LZ4F_headerSize().\n *     Frame header size is variable, but is guaranteed to be >= LZ4F_HEADER_SIZE_MIN bytes,\n *     and not more than <= LZ4F_HEADER_SIZE_MAX bytes.\n *     Hence, blindly providing LZ4F_HEADER_SIZE_MAX bytes or more will always work.\n *     It's allowed to provide more input data than the header size,\n *     LZ4F_getFrameInfo() will only consume the header.\n *\n *     If input size is not large enough,\n *     aka if it's smaller than header size,\n *     function will fail and return an error code.\n *\n *  2) After decoding has been started,\n *     it's possible to invoke LZ4F_getFrameInfo() anytime\n *     to extract already decoded frame parameters stored within dctx.\n *\n *     Note that, if decoding has barely started,\n *     and not yet read enough information to decode the header,\n *     LZ4F_getFrameInfo() will fail.\n *\n *  The number of bytes consumed from srcBuffer will be updated in *srcSizePtr (necessarily <= original value).\n *  LZ4F_getFrameInfo() only consumes bytes when decoding has not yet started,\n *  and when decoding the header has been successful.\n *  Decompression must then resume from (srcBuffer + *srcSizePtr).\n *\n * @return : a hint about how many srcSize bytes LZ4F_decompress() expects for next call,\n *           or an error code which can be tested using LZ4F_isError().\n *  note 1 : in case of error, dctx is not modified. Decoding operation can resume from beginning safely.\n *  note 2 : frame parameters are *copied into* an already allocated LZ4F_frameInfo_t structure.\n */\nLZ4FLIB_API size_t\nLZ4F_getFrameInfo(LZ4F_dctx* dctx,\n                  LZ4F_frameInfo_t* frameInfoPtr,\n            const void* srcBuffer, size_t* srcSizePtr);\n\n/*! LZ4F_decompress() :\n *  Call this function repetitively to regenerate data compressed in `srcBuffer`.\n *\n *  The function requires a valid dctx state.\n *  It will read up to *srcSizePtr bytes from srcBuffer,\n *  and decompress data into dstBuffer, of capacity *dstSizePtr.\n *\n *  The nb of bytes consumed from srcBuffer will be written into *srcSizePtr (necessarily <= original value).\n *  The nb of bytes decompressed into dstBuffer will be written into *dstSizePtr (necessarily <= original value).\n *\n *  The function does not necessarily read all input bytes, so always check value in *srcSizePtr.\n *  Unconsumed source data must be presented again in subsequent invocations.\n *\n * `dstBuffer` can freely change between each consecutive function invocation.\n * `dstBuffer` content will be overwritten.\n *\n *  Note: if `LZ4F_getFrameInfo()` is called before `LZ4F_decompress()`, srcBuffer must be updated to reflect\n *  the number of bytes consumed after reading the frame header. Failure to update srcBuffer before calling\n *  `LZ4F_decompress()` will cause decompression failure or, even worse, successful but incorrect decompression.\n *  See the `LZ4F_getFrameInfo()` docs for details.\n *\n * @return : an hint of how many `srcSize` bytes LZ4F_decompress() expects for next call.\n *  Schematically, it's the size of the current (or remaining) compressed block + header of next block.\n *  Respecting the hint provides some small speed benefit, because it skips intermediate buffers.\n *  This is just a hint though, it's always possible to provide any srcSize.\n *\n *  When a frame is fully decoded, @return will be 0 (no more data expected).\n *  When provided with more bytes than necessary to decode a frame,\n *  LZ4F_decompress() will stop reading exactly at end of current frame, and @return 0.\n *\n *  If decompression failed, @return is an error code, which can be tested using LZ4F_isError().\n *  After a decompression error, the `dctx` context is not resumable.\n *  Use LZ4F_resetDecompressionContext() to return to clean state.\n *\n *  After a frame is fully decoded, dctx can be used again to decompress another frame.\n */\nLZ4FLIB_API size_t\nLZ4F_decompress(LZ4F_dctx* dctx,\n                void* dstBuffer, size_t* dstSizePtr,\n          const void* srcBuffer, size_t* srcSizePtr,\n          const LZ4F_decompressOptions_t* dOptPtr);\n\n\n/*! LZ4F_resetDecompressionContext() : added in v1.8.0\n *  In case of an error, the context is left in \"undefined\" state.\n *  In which case, it's necessary to reset it, before re-using it.\n *  This method can also be used to abruptly stop any unfinished decompression,\n *  and start a new one using same context resources. */\nLZ4FLIB_API void LZ4F_resetDecompressionContext(LZ4F_dctx* dctx);   /* always successful */\n\n\n\n#if defined (__cplusplus)\n}\n#endif\n\n#endif  /* LZ4F_H_09782039843 */\n\n#if defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843)\n#define LZ4F_H_STATIC_09782039843\n\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n/* These declarations are not stable and may change in the future.\n * They are therefore only safe to depend on\n * when the caller is statically linked against the library.\n * To access their declarations, define LZ4F_STATIC_LINKING_ONLY.\n *\n * By default, these symbols aren't published into shared/dynamic libraries.\n * You can override this behavior and force them to be published\n * by defining LZ4F_PUBLISH_STATIC_FUNCTIONS.\n * Use at your own risk.\n */\n#ifdef LZ4F_PUBLISH_STATIC_FUNCTIONS\n# define LZ4FLIB_STATIC_API LZ4FLIB_API\n#else\n# define LZ4FLIB_STATIC_API\n#endif\n\n\n/* ---   Error List   --- */\n#define LZ4F_LIST_ERRORS(ITEM) \\\n        ITEM(OK_NoError) \\\n        ITEM(ERROR_GENERIC) \\\n        ITEM(ERROR_maxBlockSize_invalid) \\\n        ITEM(ERROR_blockMode_invalid) \\\n        ITEM(ERROR_contentChecksumFlag_invalid) \\\n        ITEM(ERROR_compressionLevel_invalid) \\\n        ITEM(ERROR_headerVersion_wrong) \\\n        ITEM(ERROR_blockChecksum_invalid) \\\n        ITEM(ERROR_reservedFlag_set) \\\n        ITEM(ERROR_allocation_failed) \\\n        ITEM(ERROR_srcSize_tooLarge) \\\n        ITEM(ERROR_dstMaxSize_tooSmall) \\\n        ITEM(ERROR_frameHeader_incomplete) \\\n        ITEM(ERROR_frameType_unknown) \\\n        ITEM(ERROR_frameSize_wrong) \\\n        ITEM(ERROR_srcPtr_wrong) \\\n        ITEM(ERROR_decompressionFailed) \\\n        ITEM(ERROR_headerChecksum_invalid) \\\n        ITEM(ERROR_contentChecksum_invalid) \\\n        ITEM(ERROR_frameDecoding_alreadyStarted) \\\n        ITEM(ERROR_compressionState_uninitialized) \\\n        ITEM(ERROR_parameter_null) \\\n        ITEM(ERROR_maxCode)\n\n#define LZ4F_GENERATE_ENUM(ENUM) LZ4F_##ENUM,\n\n/* enum list is exposed, to handle specific errors */\ntypedef enum { LZ4F_LIST_ERRORS(LZ4F_GENERATE_ENUM)\n              _LZ4F_dummy_error_enum_for_c89_never_used } LZ4F_errorCodes;\n\nLZ4FLIB_STATIC_API LZ4F_errorCodes LZ4F_getErrorCode(size_t functionResult);\n\n\n/*! LZ4F_getBlockSize() :\n *  Return, in scalar format (size_t),\n *  the maximum block size associated with blockSizeID.\n**/\nLZ4FLIB_STATIC_API size_t LZ4F_getBlockSize(LZ4F_blockSizeID_t blockSizeID);\n\n/*! LZ4F_uncompressedUpdate() :\n *  LZ4F_uncompressedUpdate() can be called repetitively to add as much data uncompressed data as necessary.\n *  Important rule: dstCapacity MUST be large enough to store the entire source buffer as\n *  no compression is done for this operation\n *  If this condition is not respected, LZ4F_uncompressedUpdate() will fail (result is an errorCode).\n *  After an error, the state is left in a UB state, and must be re-initialized or freed.\n *  If previously a compressed block was written, buffered data is flushed\n *  before appending uncompressed data is continued.\n *  This is only supported when LZ4F_blockIndependent is used\n * `cOptPtr` is optional : NULL can be provided, in which case all options are set to default.\n * @return : number of bytes written into `dstBuffer` (it can be zero, meaning input data was just buffered).\n *           or an error code if it fails (which can be tested using LZ4F_isError())\n */\nLZ4FLIB_STATIC_API size_t\nLZ4F_uncompressedUpdate(LZ4F_cctx* cctx,\n                        void* dstBuffer, size_t dstCapacity,\n                  const void* srcBuffer, size_t srcSize,\n                  const LZ4F_compressOptions_t* cOptPtr);\n\n/**********************************\n *  Bulk processing dictionary API\n *********************************/\n\n/* A Dictionary is useful for the compression of small messages (KB range).\n * It dramatically improves compression efficiency.\n *\n * LZ4 can ingest any input as dictionary, though only the last 64 KB are useful.\n * Best results are generally achieved by using Zstandard's Dictionary Builder\n * to generate a high-quality dictionary from a set of samples.\n *\n * Loading a dictionary has a cost, since it involves construction of tables.\n * The Bulk processing dictionary API makes it possible to share this cost\n * over an arbitrary number of compression jobs, even concurrently,\n * markedly improving compression latency for these cases.\n *\n * The same dictionary will have to be used on the decompression side\n * for decoding to be successful.\n * To help identify the correct dictionary at decoding stage,\n * the frame header allows optional embedding of a dictID field.\n */\ntypedef struct LZ4F_CDict_s LZ4F_CDict;\n\n/*! LZ4_createCDict() :\n *  When compressing multiple messages / blocks using the same dictionary, it's recommended to load it just once.\n *  LZ4_createCDict() will create a digested dictionary, ready to start future compression operations without startup delay.\n *  LZ4_CDict can be created once and shared by multiple threads concurrently, since its usage is read-only.\n * `dictBuffer` can be released after LZ4_CDict creation, since its content is copied within CDict */\nLZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict(const void* dictBuffer, size_t dictSize);\nLZ4FLIB_STATIC_API void        LZ4F_freeCDict(LZ4F_CDict* CDict);\n\n\n/*! LZ4_compressFrame_usingCDict() :\n *  Compress an entire srcBuffer into a valid LZ4 frame using a digested Dictionary.\n *  cctx must point to a context created by LZ4F_createCompressionContext().\n *  If cdict==NULL, compress without a dictionary.\n *  dstBuffer MUST be >= LZ4F_compressFrameBound(srcSize, preferencesPtr).\n *  If this condition is not respected, function will fail (@return an errorCode).\n *  The LZ4F_preferences_t structure is optional : you may provide NULL as argument,\n *  but it's not recommended, as it's the only way to provide dictID in the frame header.\n * @return : number of bytes written into dstBuffer.\n *           or an error code if it fails (can be tested using LZ4F_isError()) */\nLZ4FLIB_STATIC_API size_t\nLZ4F_compressFrame_usingCDict(LZ4F_cctx* cctx,\n                              void* dst, size_t dstCapacity,\n                        const void* src, size_t srcSize,\n                        const LZ4F_CDict* cdict,\n                        const LZ4F_preferences_t* preferencesPtr);\n\n\n/*! LZ4F_compressBegin_usingCDict() :\n *  Inits streaming dictionary compression, and writes the frame header into dstBuffer.\n *  dstCapacity must be >= LZ4F_HEADER_SIZE_MAX bytes.\n * `prefsPtr` is optional : you may provide NULL as argument,\n *  however, it's the only way to provide dictID in the frame header.\n * @return : number of bytes written into dstBuffer for the header,\n *           or an error code (which can be tested using LZ4F_isError()) */\nLZ4FLIB_STATIC_API size_t\nLZ4F_compressBegin_usingCDict(LZ4F_cctx* cctx,\n                              void* dstBuffer, size_t dstCapacity,\n                        const LZ4F_CDict* cdict,\n                        const LZ4F_preferences_t* prefsPtr);\n\n\n/*! LZ4F_decompress_usingDict() :\n *  Same as LZ4F_decompress(), using a predefined dictionary.\n *  Dictionary is used \"in place\", without any preprocessing.\n**  It must remain accessible throughout the entire frame decoding. */\nLZ4FLIB_STATIC_API size_t\nLZ4F_decompress_usingDict(LZ4F_dctx* dctxPtr,\n                          void* dstBuffer, size_t* dstSizePtr,\n                    const void* srcBuffer, size_t* srcSizePtr,\n                    const void* dict, size_t dictSize,\n                    const LZ4F_decompressOptions_t* decompressOptionsPtr);\n\n\n/*! Custom memory allocation : v1.9.4+\n *  These prototypes make it possible to pass custom allocation/free functions.\n *  LZ4F_customMem is provided at state creation time, using LZ4F_create*_advanced() listed below.\n *  All allocation/free operations will be completed using these custom variants instead of regular <stdlib.h> ones.\n */\ntypedef void* (*LZ4F_AllocFunction) (void* opaqueState, size_t size);\ntypedef void* (*LZ4F_CallocFunction) (void* opaqueState, size_t size);\ntypedef void  (*LZ4F_FreeFunction) (void* opaqueState, void* address);\ntypedef struct {\n    LZ4F_AllocFunction customAlloc;\n    LZ4F_CallocFunction customCalloc; /* optional; when not defined, uses customAlloc + memset */\n    LZ4F_FreeFunction customFree;\n    void* opaqueState;\n} LZ4F_CustomMem;\nstatic\n#ifdef __GNUC__\n__attribute__((__unused__))\n#endif\nLZ4F_CustomMem const LZ4F_defaultCMem = { NULL, NULL, NULL, NULL };  /**< this constant defers to stdlib's functions */\n\nLZ4FLIB_STATIC_API LZ4F_cctx* LZ4F_createCompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version);\nLZ4FLIB_STATIC_API LZ4F_dctx* LZ4F_createDecompressionContext_advanced(LZ4F_CustomMem customMem, unsigned version);\nLZ4FLIB_STATIC_API LZ4F_CDict* LZ4F_createCDict_advanced(LZ4F_CustomMem customMem, const void* dictBuffer, size_t dictSize);\n\n\n#if defined (__cplusplus)\n}\n#endif\n\n#endif  /* defined(LZ4F_STATIC_LINKING_ONLY) && !defined(LZ4F_H_STATIC_09782039843) */\n"
  },
  {
    "path": "lib/LZ4F/lz4frame_static.h",
    "content": "/*\n   LZ4 auto-framing library\n   Header File for static linking only\n   Copyright (C) 2011-2020, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n   - LZ4 source repository : https://github.com/lz4/lz4\n   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n\n#ifndef LZ4FRAME_STATIC_H_0398209384\n#define LZ4FRAME_STATIC_H_0398209384\n\n/* The declarations that formerly were made here have been merged into\n * lz4frame.h, protected by the LZ4F_STATIC_LINKING_ONLY macro. Going forward,\n * it is recommended to simply include that header directly.\n */\n\n#define LZ4F_STATIC_LINKING_ONLY\n#include \"lz4frame.h\"\n\n#endif /* LZ4FRAME_STATIC_H_0398209384 */\n"
  },
  {
    "path": "lib/LZ4F/lz4hc.c",
    "content": "/*\n    LZ4 HC - High Compression Mode of LZ4\n    Copyright (C) 2011-2020, Yann Collet.\n\n    BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n    Redistribution and use in source and binary forms, with or without\n    modification, are permitted provided that the following conditions are\n    met:\n\n    * Redistributions of source code must retain the above copyright\n    notice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\n    copyright notice, this list of conditions and the following disclaimer\n    in the documentation and/or other materials provided with the\n    distribution.\n\n    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n    \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n    You can contact the author at :\n       - LZ4 source repository : https://github.com/lz4/lz4\n       - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */\n\n\n/* *************************************\n*  Tuning Parameter\n***************************************/\n\n/*! HEAPMODE :\n *  Select how stateless HC compression functions like `LZ4_compress_HC()`\n *  allocate memory for their workspace:\n *  in stack (0:fastest), or in heap (1:default, requires malloc()).\n *  Since workspace is rather large, heap mode is recommended.\n**/\n#ifndef LZ4HC_HEAPMODE\n#  define LZ4HC_HEAPMODE 1\n#endif\n\n\n/*===    Dependency    ===*/\n#define LZ4_HC_STATIC_LINKING_ONLY\n#include \"lz4hc.h\"\n\n\n/*===   Common definitions   ===*/\n#if defined(__GNUC__)\n#  pragma GCC diagnostic ignored \"-Wunused-function\"\n#endif\n#if defined (__clang__)\n#  pragma clang diagnostic ignored \"-Wunused-function\"\n#endif\n\n#define LZ4_COMMONDEFS_ONLY\n#ifndef LZ4_SRC_INCLUDED\n#include \"lz4.c\"   /* LZ4_count, constants, mem */\n#endif\n\n\n/*===   Enums   ===*/\ntypedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;\n\n\n/*===   Constants   ===*/\n#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)\n#define LZ4_OPT_NUM   (1<<12)\n\n\n/*===   Macros   ===*/\n#define MIN(a,b)   ( (a) < (b) ? (a) : (b) )\n#define MAX(a,b)   ( (a) > (b) ? (a) : (b) )\n#define HASH_FUNCTION(i)         (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))\n#define DELTANEXTMAXD(p)         chainTable[(p) & LZ4HC_MAXD_MASK]    /* flexible, LZ4HC_MAXD dependent */\n#define DELTANEXTU16(table, pos) table[(U16)(pos)]   /* faster */\n/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */\n#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor\n\n#define LZ4HC_HASHSIZE 4\nstatic U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }\n\n\n/**************************************\n*  HC Compression\n**************************************/\nstatic void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)\n{\n    MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable));\n    MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));\n}\n\nstatic void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)\n{\n    size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart);\n    size_t newStartingOffset = bufferSize + hc4->dictLimit;\n    DEBUGLOG(5, \"LZ4HC_init_internal\");\n    assert(newStartingOffset >= bufferSize);  /* check overflow */\n    if (newStartingOffset > 1 GB) {\n        LZ4HC_clearTables(hc4);\n        newStartingOffset = 0;\n    }\n    newStartingOffset += 64 KB;\n    hc4->nextToUpdate = (U32)newStartingOffset;\n    hc4->prefixStart = start;\n    hc4->end = start;\n    hc4->dictStart = start;\n    hc4->dictLimit = (U32)newStartingOffset;\n    hc4->lowLimit = (U32)newStartingOffset;\n}\n\n\n/* Update chains up to ip (excluded) */\nLZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)\n{\n    U16* const chainTable = hc4->chainTable;\n    U32* const hashTable  = hc4->hashTable;\n    const BYTE* const prefixPtr = hc4->prefixStart;\n    U32 const prefixIdx = hc4->dictLimit;\n    U32 const target = (U32)(ip - prefixPtr) + prefixIdx;\n    U32 idx = hc4->nextToUpdate;\n    assert(ip >= prefixPtr);\n    assert(target >= prefixIdx);\n\n    while (idx < target) {\n        U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx);\n        size_t delta = idx - hashTable[h];\n        if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;\n        DELTANEXTU16(chainTable, idx) = (U16)delta;\n        hashTable[h] = idx;\n        idx++;\n    }\n\n    hc4->nextToUpdate = target;\n}\n\n/** LZ4HC_countBack() :\n * @return : negative value, nb of common bytes before ip/match */\nLZ4_FORCE_INLINE\nint LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,\n                    const BYTE* const iMin, const BYTE* const mMin)\n{\n    int back = 0;\n    int const min = (int)MAX(iMin - ip, mMin - match);\n    assert(min <= 0);\n    assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));\n    assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));\n    while ( (back > min)\n         && (ip[back-1] == match[back-1]) )\n            back--;\n    return back;\n}\n\n#if defined(_MSC_VER)\n#  define LZ4HC_rotl32(x,r) _rotl(x,r)\n#else\n#  define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))\n#endif\n\n\nstatic U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)\n{\n    size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;\n    if (bitsToRotate == 0) return pattern;\n    return LZ4HC_rotl32(pattern, (int)bitsToRotate);\n}\n\n/* LZ4HC_countPattern() :\n * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */\nstatic unsigned\nLZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)\n{\n    const BYTE* const iStart = ip;\n    reg_t const pattern = (sizeof(pattern)==8) ?\n        (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32;\n\n    while (likely(ip < iEnd-(sizeof(pattern)-1))) {\n        reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;\n        if (!diff) { ip+=sizeof(pattern); continue; }\n        ip += LZ4_NbCommonBytes(diff);\n        return (unsigned)(ip - iStart);\n    }\n\n    if (LZ4_isLittleEndian()) {\n        reg_t patternByte = pattern;\n        while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {\n            ip++; patternByte >>= 8;\n        }\n    } else {  /* big endian */\n        U32 bitOffset = (sizeof(pattern)*8) - 8;\n        while (ip < iEnd) {\n            BYTE const byte = (BYTE)(pattern >> bitOffset);\n            if (*ip != byte) break;\n            ip ++; bitOffset -= 8;\n    }   }\n\n    return (unsigned)(ip - iStart);\n}\n\n/* LZ4HC_reverseCountPattern() :\n * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)\n * read using natural platform endianness */\nstatic unsigned\nLZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)\n{\n    const BYTE* const iStart = ip;\n\n    while (likely(ip >= iLow+4)) {\n        if (LZ4_read32(ip-4) != pattern) break;\n        ip -= 4;\n    }\n    {   const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */\n        while (likely(ip>iLow)) {\n            if (ip[-1] != *bytePtr) break;\n            ip--; bytePtr--;\n    }   }\n    return (unsigned)(iStart - ip);\n}\n\n/* LZ4HC_protectDictEnd() :\n * Checks if the match is in the last 3 bytes of the dictionary, so reading the\n * 4 byte MINMATCH would overflow.\n * @returns true if the match index is okay.\n */\nstatic int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)\n{\n    return ((U32)((dictLimit - 1) - matchIndex) >= 3);\n}\n\ntypedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;\ntypedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;\n\ntypedef struct {\n    int off;\n    int len;\n} LZ4HC_match_t;\n\nLZ4_FORCE_INLINE LZ4HC_match_t\nLZ4HC_InsertAndGetWiderMatch (\n        LZ4HC_CCtx_internal* const hc4,\n        const BYTE* const ip,\n        const BYTE* const iLowLimit, const BYTE* const iHighLimit,\n        int longest,\n        const BYTE** startpos,\n        const int maxNbAttempts,\n        const int patternAnalysis, const int chainSwap,\n        const dictCtx_directive dict,\n        const HCfavor_e favorDecSpeed)\n{\n    U16* const chainTable = hc4->chainTable;\n    U32* const hashTable = hc4->hashTable;\n    const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;\n    const BYTE* const prefixPtr = hc4->prefixStart;\n    const U32 prefixIdx = hc4->dictLimit;\n    const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx;\n    const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex);\n    const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;\n    const BYTE* const dictStart = hc4->dictStart;\n    const U32 dictIdx = hc4->lowLimit;\n    const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx;\n    int const lookBackLength = (int)(ip-iLowLimit);\n    int nbAttempts = maxNbAttempts;\n    U32 matchChainPos = 0;\n    U32 const pattern = LZ4_read32(ip);\n    U32 matchIndex;\n    repeat_state_e repeat = rep_untested;\n    size_t srcPatternLength = 0;\n    int offset = 0;\n\n    DEBUGLOG(7, \"LZ4HC_InsertAndGetWiderMatch\");\n    assert(startpos != NULL);\n    *startpos = ip;  /* in case there is no solution */\n    /* First Match */\n    LZ4HC_Insert(hc4, ip);  /* insert all prior positions up to ip (excluded) */\n    matchIndex = hashTable[LZ4HC_hashPtr(ip)];\n    DEBUGLOG(7, \"First candidate match for pos %u found at index %u / %u (lowestMatchIndex)\",\n                ipIndex, matchIndex, lowestMatchIndex);\n\n    while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) {\n        int matchLength=0;\n        nbAttempts--;\n        assert(matchIndex < ipIndex);\n        if (favorDecSpeed && (ipIndex - matchIndex < 8)) {\n            /* do nothing:\n             * favorDecSpeed intentionally skips matches with offset < 8 */\n        } else if (matchIndex >= prefixIdx) {   /* within current Prefix */\n            const BYTE* const matchPtr = prefixPtr + (matchIndex - prefixIdx);\n            assert(matchPtr < ip);\n            assert(longest >= 1);\n            if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {\n                if (LZ4_read32(matchPtr) == pattern) {\n                    int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0;\n                    matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);\n                    matchLength -= back;\n                    if (matchLength > longest) {\n                        longest = matchLength;\n                        offset = (int)(ipIndex - matchIndex);\n                        *startpos = ip + back;\n                        DEBUGLOG(7, \"Found match of len=%i within prefix, offset=%i, back=%i\", longest, offset, -back);\n            }   }   }\n        } else {   /* lowestMatchIndex <= matchIndex < dictLimit : within Ext Dict */\n            const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx);\n            assert(matchIndex >= dictIdx);\n            if ( likely(matchIndex <= prefixIdx - 4)\n              && (LZ4_read32(matchPtr) == pattern) ) {\n                int back = 0;\n                const BYTE* vLimit = ip + (prefixIdx - matchIndex);\n                if (vLimit > iHighLimit) vLimit = iHighLimit;\n                matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;\n                if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))\n                    matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit);\n                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;\n                matchLength -= back;\n                if (matchLength > longest) {\n                    longest = matchLength;\n                    offset = (int)(ipIndex - matchIndex);\n                    *startpos = ip + back;\n                    DEBUGLOG(7, \"Found match of len=%i within dict, offset=%i, back=%i\", longest, offset, -back);\n        }   }   }\n\n        if (chainSwap && matchLength==longest) {   /* better match => select a better chain */\n            assert(lookBackLength==0);   /* search forward only */\n            if (matchIndex + (U32)longest <= ipIndex) {\n                int const kTrigger = 4;\n                U32 distanceToNextMatch = 1;\n                int const end = longest - MINMATCH + 1;\n                int step = 1;\n                int accel = 1 << kTrigger;\n                int pos;\n                for (pos = 0; pos < end; pos += step) {\n                    U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);\n                    step = (accel++ >> kTrigger);\n                    if (candidateDist > distanceToNextMatch) {\n                        distanceToNextMatch = candidateDist;\n                        matchChainPos = (U32)pos;\n                        accel = 1 << kTrigger;\n                }   }\n                if (distanceToNextMatch > 1) {\n                    if (distanceToNextMatch > matchIndex) break;   /* avoid overflow */\n                    matchIndex -= distanceToNextMatch;\n                    continue;\n        }   }   }\n\n        {   U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);\n            if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {\n                U32 const matchCandidateIdx = matchIndex-1;\n                /* may be a repeated pattern */\n                if (repeat == rep_untested) {\n                    if ( ((pattern & 0xFFFF) == (pattern >> 16))\n                      &  ((pattern & 0xFF)   == (pattern >> 24)) ) {\n                        DEBUGLOG(7, \"Repeat pattern detected, char %02X\", pattern >> 24);\n                        repeat = rep_confirmed;\n                        srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);\n                    } else {\n                        repeat = rep_not;\n                }   }\n                if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)\n                  && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) {\n                    const int extDict = matchCandidateIdx < prefixIdx;\n                    const BYTE* const matchPtr = extDict ? dictStart + (matchCandidateIdx - dictIdx) : prefixPtr + (matchCandidateIdx - prefixIdx);\n                    if (LZ4_read32(matchPtr) == pattern) {  /* good candidate */\n                        const BYTE* const iLimit = extDict ? dictEnd : iHighLimit;\n                        size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);\n                        if (extDict && matchPtr + forwardPatternLength == iLimit) {\n                            U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);\n                            forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern);\n                        }\n                        {   const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr;\n                            size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);\n                            size_t currentSegmentLength;\n                            if (!extDict\n                              && matchPtr - backLength == prefixPtr\n                              && dictIdx < prefixIdx) {\n                                U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);\n                                backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern);\n                            }\n                            /* Limit backLength not go further than lowestMatchIndex */\n                            backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);\n                            assert(matchCandidateIdx - backLength >= lowestMatchIndex);\n                            currentSegmentLength = backLength + forwardPatternLength;\n                            /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */\n                            if ( (currentSegmentLength >= srcPatternLength)   /* current pattern segment large enough to contain full srcPatternLength */\n                              && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */\n                                U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength;  /* best position, full pattern, might be followed by more match */\n                                if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex))\n                                    matchIndex = newMatchIndex;\n                                else {\n                                    /* Can only happen if started in the prefix */\n                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);\n                                    matchIndex = prefixIdx;\n                                }\n                            } else {\n                                U32 const newMatchIndex = matchCandidateIdx - (U32)backLength;   /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */\n                                if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) {\n                                    assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict);\n                                    matchIndex = prefixIdx;\n                                } else {\n                                    matchIndex = newMatchIndex;\n                                    if (lookBackLength==0) {  /* no back possible */\n                                        size_t const maxML = MIN(currentSegmentLength, srcPatternLength);\n                                        if ((size_t)longest < maxML) {\n                                            assert(prefixPtr - prefixIdx + matchIndex != ip);\n                                            if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break;\n                                            assert(maxML < 2 GB);\n                                            longest = (int)maxML;\n                                            offset = (int)(ipIndex - matchIndex);\n                                            *startpos = ip;\n                                            DEBUGLOG(7, \"Found repeat pattern match of len=%i, offset=%i\", longest, offset);\n                                        }\n                                        {   U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);\n                                            if (distToNextPattern > matchIndex) break;  /* avoid overflow */\n                                            matchIndex -= distToNextPattern;\n                        }   }   }   }   }\n                        continue;\n                }   }\n        }   }   /* PA optimization */\n\n        /* follow current chain */\n        matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);\n\n    }  /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */\n\n    if ( dict == usingDictCtxHc\n      && nbAttempts > 0\n      && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {\n        size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit;\n        U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];\n        assert(dictEndOffset <= 1 GB);\n        matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;\n        if (dictMatchIndex>0) DEBUGLOG(7, \"dictEndOffset = %zu, dictMatchIndex = %u => relative matchIndex = %i\", dictEndOffset, dictMatchIndex, (int)dictMatchIndex - (int)dictEndOffset);\n        while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {\n            const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex;\n\n            if (LZ4_read32(matchPtr) == pattern) {\n                int mlt;\n                int back = 0;\n                const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);\n                if (vLimit > iHighLimit) vLimit = iHighLimit;\n                mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;\n                back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0;\n                mlt -= back;\n                if (mlt > longest) {\n                    longest = mlt;\n                    offset = (int)(ipIndex - matchIndex);\n                    *startpos = ip + back;\n                    DEBUGLOG(7, \"found match of length %i within extDictCtx\", longest);\n            }   }\n\n            {   U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);\n                dictMatchIndex -= nextOffset;\n                matchIndex -= nextOffset;\n    }   }   }\n\n    {   LZ4HC_match_t md;\n        assert(longest >= 0);\n        md.len = longest;\n        md.off = offset;\n        return md;\n    }\n}\n\nLZ4_FORCE_INLINE LZ4HC_match_t\nLZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4,   /* Index table will be updated */\n                       const BYTE* const ip, const BYTE* const iLimit,\n                       const int maxNbAttempts,\n                       const int patternAnalysis,\n                       const dictCtx_directive dict)\n{\n    const BYTE* uselessPtr = ip;\n    DEBUGLOG(7, \"LZ4HC_InsertAndFindBestMatch\");\n    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),\n     * but this won't be the case here, as we define iLowLimit==ip,\n     * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */\n    return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);\n}\n\n/* LZ4HC_encodeSequence() :\n * @return : 0 if ok,\n *           1 if buffer issue detected */\nLZ4_FORCE_INLINE int LZ4HC_encodeSequence (\n    const BYTE** _ip,\n    BYTE** _op,\n    const BYTE** _anchor,\n    int matchLength,\n    int offset,\n    limitedOutput_directive limit,\n    BYTE* oend)\n{\n#define ip      (*_ip)\n#define op      (*_op)\n#define anchor  (*_anchor)\n\n    size_t length;\n    BYTE* const token = op++;\n\n#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)\n    static const BYTE* start = NULL;\n    static U32 totalCost = 0;\n    U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start);\n    U32 const ll = (U32)(ip - anchor);\n    U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;\n    U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;\n    U32 const cost = 1 + llAdd + ll + 2 + mlAdd;\n    if (start==NULL) start = anchor;  /* only works for single segment */\n    /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */\n    DEBUGLOG(6, \"pos:%7u -- literals:%4u, match:%4i, offset:%5i, cost:%4u + %5u\",\n                pos,\n                (U32)(ip - anchor), matchLength, offset,\n                cost, totalCost);\n    totalCost += cost;\n#endif\n\n    /* Encode Literal length */\n    length = (size_t)(ip - anchor);\n    LZ4_STATIC_ASSERT(notLimited == 0);\n    /* Check output limit */\n    if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {\n        DEBUGLOG(6, \"Not enough room to write %i literals (%i bytes remaining)\",\n                (int)length, (int)(oend - op));\n        return 1;\n    }\n    if (length >= RUN_MASK) {\n        size_t len = length - RUN_MASK;\n        *token = (RUN_MASK << ML_BITS);\n        for(; len >= 255 ; len -= 255) *op++ = 255;\n        *op++ = (BYTE)len;\n    } else {\n        *token = (BYTE)(length << ML_BITS);\n    }\n\n    /* Copy Literals */\n    LZ4_wildCopy8(op, anchor, op + length);\n    op += length;\n\n    /* Encode Offset */\n    assert(offset <= LZ4_DISTANCE_MAX );\n    assert(offset > 0);\n    LZ4_writeLE16(op, (U16)(offset)); op += 2;\n\n    /* Encode MatchLength */\n    assert(matchLength >= MINMATCH);\n    length = (size_t)matchLength - MINMATCH;\n    if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) {\n        DEBUGLOG(6, \"Not enough room to write match length\");\n        return 1;   /* Check output limit */\n    }\n    if (length >= ML_MASK) {\n        *token += ML_MASK;\n        length -= ML_MASK;\n        for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; }\n        if (length >= 255) { length -= 255; *op++ = 255; }\n        *op++ = (BYTE)length;\n    } else {\n        *token += (BYTE)(length);\n    }\n\n    /* Prepare next loop */\n    ip += matchLength;\n    anchor = ip;\n\n    return 0;\n}\n#undef ip\n#undef op\n#undef anchor\n\nLZ4_FORCE_INLINE int LZ4HC_compress_hashChain (\n    LZ4HC_CCtx_internal* const ctx,\n    const char* const source,\n    char* const dest,\n    int* srcSizePtr,\n    int const maxOutputSize,\n    int maxNbAttempts,\n    const limitedOutput_directive limit,\n    const dictCtx_directive dict\n    )\n{\n    const int inputSize = *srcSizePtr;\n    const int patternAnalysis = (maxNbAttempts > 128);   /* levels 9+ */\n\n    const BYTE* ip = (const BYTE*) source;\n    const BYTE* anchor = ip;\n    const BYTE* const iend = ip + inputSize;\n    const BYTE* const mflimit = iend - MFLIMIT;\n    const BYTE* const matchlimit = (iend - LASTLITERALS);\n\n    BYTE* optr = (BYTE*) dest;\n    BYTE* op = (BYTE*) dest;\n    BYTE* oend = op + maxOutputSize;\n\n    const BYTE* start0;\n    const BYTE* start2 = NULL;\n    const BYTE* start3 = NULL;\n    LZ4HC_match_t m0, m1, m2, m3;\n    const LZ4HC_match_t nomatch = {0, 0};\n\n    /* init */\n    DEBUGLOG(5, \"LZ4HC_compress_hashChain (dict?=>%i)\", dict);\n    *srcSizePtr = 0;\n    if (limit == fillOutput) oend -= LASTLITERALS;                  /* Hack for support LZ4 format restriction */\n    if (inputSize < LZ4_minLength) goto _last_literals;             /* Input too small, no compression (all literals) */\n\n    /* Main Loop */\n    while (ip <= mflimit) {\n        m1 = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, maxNbAttempts, patternAnalysis, dict);\n        if (m1.len<MINMATCH) { ip++; continue; }\n\n        /* saved, in case we would skip too much */\n        start0 = ip; m0 = m1;\n\n_Search2:\n        DEBUGLOG(7, \"_Search2 (currently found match of size %i)\", m1.len);\n        if (ip+m1.len <= mflimit) {\n            m2 = LZ4HC_InsertAndGetWiderMatch(ctx,\n                            ip + m1.len - 2, ip + 0, matchlimit, m1.len, &start2,\n                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);\n        } else {\n            m2 = nomatch;  /* do not search further */\n        }\n\n        if (m2.len <= m1.len) { /* No better match => encode ML1 immediately */\n            optr = op;\n            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow;\n            continue;\n        }\n\n        if (start0 < ip) {   /* first match was skipped at least once */\n            if (start2 < ip + m0.len) {  /* squeezing ML1 between ML0(original ML1) and ML2 */\n                ip = start0; m1 = m0;  /* restore initial Match1 */\n        }   }\n\n        /* Here, start0==ip */\n        if ((start2 - ip) < 3) {  /* First Match too small : removed */\n            ip = start2;\n            m1 = m2;\n            goto _Search2;\n        }\n\n_Search3:\n        if ((start2 - ip) < OPTIMAL_ML) {\n            int correction;\n            int new_ml = m1.len;\n            if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;\n            if (ip+new_ml > start2 + m2.len - MINMATCH)\n                new_ml = (int)(start2 - ip) + m2.len - MINMATCH;\n            correction = new_ml - (int)(start2 - ip);\n            if (correction > 0) {\n                start2 += correction;\n                m2.len -= correction;\n            }\n        }\n\n        if (start2 + m2.len <= mflimit) {\n            m3 = LZ4HC_InsertAndGetWiderMatch(ctx,\n                            start2 + m2.len - 3, start2, matchlimit, m2.len, &start3,\n                            maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);\n        } else {\n            m3 = nomatch;  /* do not search further */\n        }\n\n        if (m3.len <= m2.len) {  /* No better match => encode ML1 and ML2 */\n            /* ip & ref are known; Now for ml */\n            if (start2 < ip+m1.len) m1.len = (int)(start2 - ip);\n            /* Now, encode 2 sequences */\n            optr = op;\n            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend))\n                goto _dest_overflow;\n            ip = start2;\n            optr = op;\n            if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m2.len, m2.off, limit, oend)) {\n                m1 = m2;\n                goto _dest_overflow;\n            }\n            continue;\n        }\n\n        if (start3 < ip+m1.len+3) {  /* Not enough space for match 2 : remove it */\n            if (start3 >= (ip+m1.len)) {  /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */\n                if (start2 < ip+m1.len) {\n                    int correction = (int)(ip+m1.len - start2);\n                    start2 += correction;\n                    m2.len -= correction;\n                    if (m2.len < MINMATCH) {\n                        start2 = start3;\n                        m2 = m3;\n                    }\n                }\n\n                optr = op;\n                if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow;\n                ip  = start3;\n                m1 = m3;\n\n                start0 = start2;\n                m0 = m2;\n                goto _Search2;\n            }\n\n            start2 = start3;\n            m2 = m3;\n            goto _Search3;\n        }\n\n        /*\n        * OK, now we have 3 ascending matches;\n        * let's write the first one ML1.\n        * ip & ref are known; Now decide ml.\n        */\n        if (start2 < ip+m1.len) {\n            if ((start2 - ip) < OPTIMAL_ML) {\n                int correction;\n                if (m1.len > OPTIMAL_ML) m1.len = OPTIMAL_ML;\n                if (ip + m1.len > start2 + m2.len - MINMATCH)\n                    m1.len = (int)(start2 - ip) + m2.len - MINMATCH;\n                correction = m1.len - (int)(start2 - ip);\n                if (correction > 0) {\n                    start2 += correction;\n                    m2.len -= correction;\n                }\n            } else {\n                m1.len = (int)(start2 - ip);\n            }\n        }\n        optr = op;\n        if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, limit, oend)) goto _dest_overflow;\n\n        /* ML2 becomes ML1 */\n        ip = start2; m1 = m2;\n\n        /* ML3 becomes ML2 */\n        start2 = start3; m2 = m3;\n\n        /* let's find a new ML3 */\n        goto _Search3;\n    }\n\n_last_literals:\n    /* Encode Last Literals */\n    {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */\n        size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;\n        size_t const totalSize = 1 + llAdd + lastRunSize;\n        if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */\n        if (limit && (op + totalSize > oend)) {\n            if (limit == limitedOutput) return 0;\n            /* adapt lastRunSize to fill 'dest' */\n            lastRunSize  = (size_t)(oend - op) - 1 /*token*/;\n            llAdd = (lastRunSize + 256 - RUN_MASK) / 256;\n            lastRunSize -= llAdd;\n        }\n        DEBUGLOG(6, \"Final literal run : %i literals\", (int)lastRunSize);\n        ip = anchor + lastRunSize;  /* can be != iend if limit==fillOutput */\n\n        if (lastRunSize >= RUN_MASK) {\n            size_t accumulator = lastRunSize - RUN_MASK;\n            *op++ = (RUN_MASK << ML_BITS);\n            for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;\n            *op++ = (BYTE) accumulator;\n        } else {\n            *op++ = (BYTE)(lastRunSize << ML_BITS);\n        }\n        LZ4_memcpy(op, anchor, lastRunSize);\n        op += lastRunSize;\n    }\n\n    /* End */\n    *srcSizePtr = (int) (((const char*)ip) - source);\n    return (int) (((char*)op)-dest);\n\n_dest_overflow:\n    if (limit == fillOutput) {\n        /* Assumption : ip, anchor, ml and ref must be set correctly */\n        size_t const ll = (size_t)(ip - anchor);\n        size_t const ll_addbytes = (ll + 240) / 255;\n        size_t const ll_totalCost = 1 + ll_addbytes + ll;\n        BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */\n        DEBUGLOG(6, \"Last sequence overflowing\");\n        op = optr;  /* restore correct out pointer */\n        if (op + ll_totalCost <= maxLitPos) {\n            /* ll validated; now adjust match length */\n            size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));\n            size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);\n            assert(maxMlSize < INT_MAX); assert(m1.len >= 0);\n            if ((size_t)m1.len > maxMlSize) m1.len = (int)maxMlSize;\n            if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + m1.len >= MFLIMIT) {\n                LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), m1.len, m1.off, notLimited, oend);\n        }   }\n        goto _last_literals;\n    }\n    /* compression failed */\n    return 0;\n}\n\n\nstatic int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,\n    const char* const source, char* dst,\n    int* srcSizePtr, int dstCapacity,\n    int const nbSearches, size_t sufficient_len,\n    const limitedOutput_directive limit, int const fullUpdate,\n    const dictCtx_directive dict,\n    const HCfavor_e favorDecSpeed);\n\n\nLZ4_FORCE_INLINE int\nLZ4HC_compress_generic_internal (\n            LZ4HC_CCtx_internal* const ctx,\n            const char* const src,\n            char* const dst,\n            int* const srcSizePtr,\n            int const dstCapacity,\n            int cLevel,\n            const limitedOutput_directive limit,\n            const dictCtx_directive dict\n            )\n{\n    typedef enum { lz4hc, lz4opt } lz4hc_strat_e;\n    typedef struct {\n        lz4hc_strat_e strat;\n        int nbSearches;\n        U32 targetLength;\n    } cParams_t;\n    static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {\n        { lz4hc,     2, 16 },  /* 0, unused */\n        { lz4hc,     2, 16 },  /* 1, unused */\n        { lz4hc,     2, 16 },  /* 2, unused */\n        { lz4hc,     4, 16 },  /* 3 */\n        { lz4hc,     8, 16 },  /* 4 */\n        { lz4hc,    16, 16 },  /* 5 */\n        { lz4hc,    32, 16 },  /* 6 */\n        { lz4hc,    64, 16 },  /* 7 */\n        { lz4hc,   128, 16 },  /* 8 */\n        { lz4hc,   256, 16 },  /* 9 */\n        { lz4opt,   96, 64 },  /*10==LZ4HC_CLEVEL_OPT_MIN*/\n        { lz4opt,  512,128 },  /*11 */\n        { lz4opt,16384,LZ4_OPT_NUM },  /* 12==LZ4HC_CLEVEL_MAX */\n    };\n\n    DEBUGLOG(5, \"LZ4HC_compress_generic_internal(src=%p, srcSize=%d)\",\n                src, *srcSizePtr);\n\n    if (limit == fillOutput && dstCapacity < 1) return 0;   /* Impossible to store anything */\n    if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0;    /* Unsupported input size (too large or negative) */\n\n    ctx->end += *srcSizePtr;\n    if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT;   /* note : convention is different from lz4frame, maybe something to review */\n    cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);\n    {   cParams_t const cParam = clTable[cLevel];\n        HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;\n        int result;\n\n        if (cParam.strat == lz4hc) {\n            result = LZ4HC_compress_hashChain(ctx,\n                                src, dst, srcSizePtr, dstCapacity,\n                                cParam.nbSearches, limit, dict);\n        } else {\n            assert(cParam.strat == lz4opt);\n            result = LZ4HC_compress_optimal(ctx,\n                                src, dst, srcSizePtr, dstCapacity,\n                                cParam.nbSearches, cParam.targetLength, limit,\n                                cLevel == LZ4HC_CLEVEL_MAX,   /* ultra mode */\n                                dict, favor);\n        }\n        if (result <= 0) ctx->dirty = 1;\n        return result;\n    }\n}\n\nstatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);\n\nstatic int\nLZ4HC_compress_generic_noDictCtx (\n        LZ4HC_CCtx_internal* const ctx,\n        const char* const src,\n        char* const dst,\n        int* const srcSizePtr,\n        int const dstCapacity,\n        int cLevel,\n        limitedOutput_directive limit\n        )\n{\n    assert(ctx->dictCtx == NULL);\n    return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);\n}\n\nstatic int\nLZ4HC_compress_generic_dictCtx (\n        LZ4HC_CCtx_internal* const ctx,\n        const char* const src,\n        char* const dst,\n        int* const srcSizePtr,\n        int const dstCapacity,\n        int cLevel,\n        limitedOutput_directive limit\n        )\n{\n    const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit);\n    assert(ctx->dictCtx != NULL);\n    if (position >= 64 KB) {\n        ctx->dictCtx = NULL;\n        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    } else if (position == 0 && *srcSizePtr > 4 KB) {\n        LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));\n        LZ4HC_setExternalDict(ctx, (const BYTE *)src);\n        ctx->compressionLevel = (short)cLevel;\n        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    } else {\n        return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);\n    }\n}\n\nstatic int\nLZ4HC_compress_generic (\n        LZ4HC_CCtx_internal* const ctx,\n        const char* const src,\n        char* const dst,\n        int* const srcSizePtr,\n        int const dstCapacity,\n        int cLevel,\n        limitedOutput_directive limit\n        )\n{\n    if (ctx->dictCtx == NULL) {\n        return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    } else {\n        return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);\n    }\n}\n\n\nint LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }\n\nstatic size_t LZ4_streamHC_t_alignment(void)\n{\n#if LZ4_ALIGN_TEST\n    typedef struct { char c; LZ4_streamHC_t t; } t_a;\n    return sizeof(t_a) - sizeof(LZ4_streamHC_t);\n#else\n    return 1;  /* effectively disabled */\n#endif\n}\n\n/* state is presumed correctly initialized,\n * in which case its size and alignment have already been validate */\nint LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)\n{\n    LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;\n    if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0;\n    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);\n    LZ4HC_init_internal (ctx, (const BYTE*)src);\n    if (dstCapacity < LZ4_compressBound(srcSize))\n        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);\n    else\n        return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);\n}\n\nint LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)\n{\n    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));\n    if (ctx==NULL) return 0;   /* init failure */\n    return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);\n}\n\nint LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)\n{\n    int cSize;\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));\n    if (statePtr==NULL) return 0;\n#else\n    LZ4_streamHC_t state;\n    LZ4_streamHC_t* const statePtr = &state;\n#endif\n    DEBUGLOG(5, \"LZ4_compress_HC\")\n    cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    FREEMEM(statePtr);\n#endif\n    return cSize;\n}\n\n/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */\nint LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)\n{\n    LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));\n    if (ctx==NULL) return 0;   /* init failure */\n    LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);\n    LZ4_setCompressionLevel(ctx, cLevel);\n    return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);\n}\n\n\n\n/**************************************\n*  Streaming Functions\n**************************************/\n/* allocation */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_streamHC_t* LZ4_createStreamHC(void)\n{\n    LZ4_streamHC_t* const state =\n        (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t));\n    if (state == NULL) return NULL;\n    LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT);\n    return state;\n}\n\nint LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)\n{\n    DEBUGLOG(4, \"LZ4_freeStreamHC(%p)\", LZ4_streamHCPtr);\n    if (!LZ4_streamHCPtr) return 0;  /* support free on NULL */\n    FREEMEM(LZ4_streamHCPtr);\n    return 0;\n}\n#endif\n\n\nLZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)\n{\n    LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;\n    DEBUGLOG(4, \"LZ4_initStreamHC(%p, %u)\", buffer, (unsigned)size);\n    /* check conditions */\n    if (buffer == NULL) return NULL;\n    if (size < sizeof(LZ4_streamHC_t)) return NULL;\n    if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL;\n    /* init */\n    { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse);\n      MEM_INIT(hcstate, 0, sizeof(*hcstate)); }\n    LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);\n    return LZ4_streamHCPtr;\n}\n\n/* just a stub */\nvoid LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)\n{\n    LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));\n    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);\n}\n\nvoid LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)\n{\n    LZ4HC_CCtx_internal* const s = &LZ4_streamHCPtr->internal_donotuse;\n    DEBUGLOG(5, \"LZ4_resetStreamHC_fast(%p, %d)\", LZ4_streamHCPtr, compressionLevel);\n    if (s->dirty) {\n        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));\n    } else {\n        assert(s->end >= s->prefixStart);\n        s->dictLimit += (U32)(s->end - s->prefixStart);\n        s->prefixStart = NULL;\n        s->end = NULL;\n        s->dictCtx = NULL;\n    }\n    LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);\n}\n\nvoid LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)\n{\n    DEBUGLOG(5, \"LZ4_setCompressionLevel(%p, %d)\", LZ4_streamHCPtr, compressionLevel);\n    if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;\n    if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;\n    LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;\n}\n\nvoid LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)\n{\n    LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);\n}\n\n/* LZ4_loadDictHC() :\n * LZ4_streamHCPtr is presumed properly initialized */\nint LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,\n              const char* dictionary, int dictSize)\n{\n    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;\n    DEBUGLOG(4, \"LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)\", LZ4_streamHCPtr, dictionary, dictSize);\n    assert(LZ4_streamHCPtr != NULL);\n    if (dictSize > 64 KB) {\n        dictionary += (size_t)dictSize - 64 KB;\n        dictSize = 64 KB;\n    }\n    /* need a full initialization, there are bad side-effects when using resetFast() */\n    {   int const cLevel = ctxPtr->compressionLevel;\n        LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));\n        LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);\n    }\n    LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);\n    ctxPtr->end = (const BYTE*)dictionary + dictSize;\n    if (dictSize >= LZ4HC_HASHSIZE) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);\n    return dictSize;\n}\n\nvoid LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {\n    working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;\n}\n\n/* compression */\n\nstatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)\n{\n    DEBUGLOG(4, \"LZ4HC_setExternalDict(%p, %p)\", ctxPtr, newBlock);\n    if (ctxPtr->end >= ctxPtr->prefixStart + 4)\n        LZ4HC_Insert (ctxPtr, ctxPtr->end-3);   /* Referencing remaining dictionary content */\n\n    /* Only one memory segment for extDict, so any previous extDict is lost at this stage */\n    ctxPtr->lowLimit  = ctxPtr->dictLimit;\n    ctxPtr->dictStart  = ctxPtr->prefixStart;\n    ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart);\n    ctxPtr->prefixStart = newBlock;\n    ctxPtr->end  = newBlock;\n    ctxPtr->nextToUpdate = ctxPtr->dictLimit;   /* match referencing will resume from there */\n\n    /* cannot reference an extDict and a dictCtx at the same time */\n    ctxPtr->dictCtx = NULL;\n}\n\nstatic int\nLZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,\n                                 const char* src, char* dst,\n                                 int* srcSizePtr, int dstCapacity,\n                                 limitedOutput_directive limit)\n{\n    LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;\n    DEBUGLOG(5, \"LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)\",\n                LZ4_streamHCPtr, src, *srcSizePtr, limit);\n    assert(ctxPtr != NULL);\n    /* auto-init if forgotten */\n    if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);\n\n    /* Check overflow */\n    if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) {\n        size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart);\n        if (dictSize > 64 KB) dictSize = 64 KB;\n        LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);\n    }\n\n    /* Check if blocks follow each other */\n    if ((const BYTE*)src != ctxPtr->end)\n        LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);\n\n    /* Check overlapping input/dictionary space */\n    {   const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;\n        const BYTE* const dictBegin = ctxPtr->dictStart;\n        const BYTE* const dictEnd   = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit);\n        if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {\n            if (sourceEnd > dictEnd) sourceEnd = dictEnd;\n            ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart);\n            ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart);\n            /* invalidate dictionary is it's too small */\n            if (ctxPtr->dictLimit - ctxPtr->lowLimit < LZ4HC_HASHSIZE) {\n                ctxPtr->lowLimit = ctxPtr->dictLimit;\n                ctxPtr->dictStart = ctxPtr->prefixStart;\n    }   }   }\n\n    return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);\n}\n\nint LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)\n{\n    DEBUGLOG(5, \"LZ4_compress_HC_continue\");\n    if (dstCapacity < LZ4_compressBound(srcSize))\n        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);\n    else\n        return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);\n}\n\nint LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)\n{\n    return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);\n}\n\n\n\n/* LZ4_saveDictHC :\n * save history content\n * into a user-provided buffer\n * which is then used to continue compression\n */\nint LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)\n{\n    LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;\n    int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart);\n    DEBUGLOG(5, \"LZ4_saveDictHC(%p, %p, %d)\", LZ4_streamHCPtr, safeBuffer, dictSize);\n    assert(prefixSize >= 0);\n    if (dictSize > 64 KB) dictSize = 64 KB;\n    if (dictSize < 4) dictSize = 0;\n    if (dictSize > prefixSize) dictSize = prefixSize;\n    if (safeBuffer == NULL) assert(dictSize == 0);\n    if (dictSize > 0)\n        LZ4_memmove(safeBuffer, streamPtr->end - dictSize, (size_t)dictSize);\n    {   U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit;\n        streamPtr->end = (safeBuffer == NULL) ? NULL : (const BYTE*)safeBuffer + dictSize;\n        streamPtr->prefixStart = (const BYTE*)safeBuffer;\n        streamPtr->dictLimit = endIndex - (U32)dictSize;\n        streamPtr->lowLimit = endIndex - (U32)dictSize;\n        streamPtr->dictStart = streamPtr->prefixStart;\n        if (streamPtr->nextToUpdate < streamPtr->dictLimit)\n            streamPtr->nextToUpdate = streamPtr->dictLimit;\n    }\n    return dictSize;\n}\n\n\n/***************************************************\n*  Deprecated Functions\n***************************************************/\n\n/* These functions currently generate deprecation warnings */\n\n/* Wrappers for deprecated compression functions */\nint LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }\nint LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }\nint LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }\nint LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }\nint LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); }\nint LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); }\nint LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }\nint LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); }\nint LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); }\nint LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); }\n\n\n/* Deprecated streaming functions */\nint LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); }\n\n/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)\n * @return : 0 on success, !=0 if error */\nint LZ4_resetStreamStateHC(void* state, char* inputBuffer)\n{\n    LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));\n    if (hc4 == NULL) return 1;   /* init failed */\n    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);\n    return 0;\n}\n\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nvoid* LZ4_createHC (const char* inputBuffer)\n{\n    LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();\n    if (hc4 == NULL) return NULL;   /* not enough memory */\n    LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);\n    return hc4;\n}\n\nint LZ4_freeHC (void* LZ4HC_Data)\n{\n    if (!LZ4HC_Data) return 0;  /* support free on NULL */\n    FREEMEM(LZ4HC_Data);\n    return 0;\n}\n#endif\n\nint LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)\n{\n    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);\n}\n\nint LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)\n{\n    return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);\n}\n\nchar* LZ4_slideInputBufferHC(void* LZ4HC_Data)\n{\n    LZ4HC_CCtx_internal* const s = &((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse;\n    const BYTE* const bufferStart = s->prefixStart - s->dictLimit + s->lowLimit;\n    LZ4_resetStreamHC_fast((LZ4_streamHC_t*)LZ4HC_Data, s->compressionLevel);\n    /* ugly conversion trick, required to evade (const char*) -> (char*) cast-qual warning :( */\n    return (char*)(uptrval)bufferStart;\n}\n\n\n/* ================================================\n *  LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])\n * ===============================================*/\ntypedef struct {\n    int price;\n    int off;\n    int mlen;\n    int litlen;\n} LZ4HC_optimal_t;\n\n/* price in bytes */\nLZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)\n{\n    int price = litlen;\n    assert(litlen >= 0);\n    if (litlen >= (int)RUN_MASK)\n        price += 1 + ((litlen-(int)RUN_MASK) / 255);\n    return price;\n}\n\n\n/* requires mlen >= MINMATCH */\nLZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)\n{\n    int price = 1 + 2 ; /* token + 16-bit offset */\n    assert(litlen >= 0);\n    assert(mlen >= MINMATCH);\n\n    price += LZ4HC_literalsPrice(litlen);\n\n    if (mlen >= (int)(ML_MASK+MINMATCH))\n        price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);\n\n    return price;\n}\n\n\n\nLZ4_FORCE_INLINE LZ4HC_match_t\nLZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,\n                      const BYTE* ip, const BYTE* const iHighLimit,\n                      int minLen, int nbSearches,\n                      const dictCtx_directive dict,\n                      const HCfavor_e favorDecSpeed)\n{\n    LZ4HC_match_t const match0 = { 0 , 0 };\n    /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),\n     * but this won't be the case here, as we define iLowLimit==ip,\n    ** so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */\n    LZ4HC_match_t md = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);\n    if (md.len <= minLen) return match0;\n    if (favorDecSpeed) {\n        if ((md.len>18) & (md.len<=36)) md.len=18;   /* favor shortcut */\n    }\n    return md;\n}\n\n\nstatic int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,\n                                    const char* const source,\n                                    char* dst,\n                                    int* srcSizePtr,\n                                    int dstCapacity,\n                                    int const nbSearches,\n                                    size_t sufficient_len,\n                                    const limitedOutput_directive limit,\n                                    int const fullUpdate,\n                                    const dictCtx_directive dict,\n                                    const HCfavor_e favorDecSpeed)\n{\n    int retval = 0;\n#define TRAILING_LITERALS 3\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS));\n#else\n    LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS];   /* ~64 KB, which is a bit large for stack... */\n#endif\n\n    const BYTE* ip = (const BYTE*) source;\n    const BYTE* anchor = ip;\n    const BYTE* const iend = ip + *srcSizePtr;\n    const BYTE* const mflimit = iend - MFLIMIT;\n    const BYTE* const matchlimit = iend - LASTLITERALS;\n    BYTE* op = (BYTE*) dst;\n    BYTE* opSaved = (BYTE*) dst;\n    BYTE* oend = op + dstCapacity;\n    int ovml = MINMATCH;  /* overflow - last sequence */\n    int ovoff = 0;\n\n    /* init */\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n    if (opt == NULL) goto _return_label;\n#endif\n    DEBUGLOG(5, \"LZ4HC_compress_optimal(dst=%p, dstCapa=%u)\", dst, (unsigned)dstCapacity);\n    *srcSizePtr = 0;\n    if (limit == fillOutput) oend -= LASTLITERALS;   /* Hack for support LZ4 format restriction */\n    if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;\n\n    /* Main Loop */\n    while (ip <= mflimit) {\n         int const llen = (int)(ip - anchor);\n         int best_mlen, best_off;\n         int cur, last_match_pos = 0;\n\n         LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);\n         if (firstMatch.len==0) { ip++; continue; }\n\n         if ((size_t)firstMatch.len > sufficient_len) {\n             /* good enough solution : immediate encoding */\n             int const firstML = firstMatch.len;\n             opSaved = op;\n             if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, firstMatch.off, limit, oend) ) {  /* updates ip, op and anchor */\n                 ovml = firstML;\n                 ovoff = firstMatch.off;\n                 goto _dest_overflow;\n             }\n             continue;\n         }\n\n         /* set prices for first positions (literals) */\n         {   int rPos;\n             for (rPos = 0 ; rPos < MINMATCH ; rPos++) {\n                 int const cost = LZ4HC_literalsPrice(llen + rPos);\n                 opt[rPos].mlen = 1;\n                 opt[rPos].off = 0;\n                 opt[rPos].litlen = llen + rPos;\n                 opt[rPos].price = cost;\n                 DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i) -- initial setup\",\n                             rPos, cost, opt[rPos].litlen);\n         }   }\n         /* set prices using initial match */\n         {   int mlen = MINMATCH;\n             int const matchML = firstMatch.len;   /* necessarily < sufficient_len < LZ4_OPT_NUM */\n             int const offset = firstMatch.off;\n             assert(matchML < LZ4_OPT_NUM);\n             for ( ; mlen <= matchML ; mlen++) {\n                 int const cost = LZ4HC_sequencePrice(llen, mlen);\n                 opt[mlen].mlen = mlen;\n                 opt[mlen].off = offset;\n                 opt[mlen].litlen = llen;\n                 opt[mlen].price = cost;\n                 DEBUGLOG(7, \"rPos:%3i => price:%3i (matchlen=%i) -- initial setup\",\n                             mlen, cost, mlen);\n         }   }\n         last_match_pos = firstMatch.len;\n         {   int addLit;\n             for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {\n                 opt[last_match_pos+addLit].mlen = 1; /* literal */\n                 opt[last_match_pos+addLit].off = 0;\n                 opt[last_match_pos+addLit].litlen = addLit;\n                 opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);\n                 DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i) -- initial setup\",\n                             last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);\n         }   }\n\n         /* check further positions */\n         for (cur = 1; cur < last_match_pos; cur++) {\n             const BYTE* const curPtr = ip + cur;\n             LZ4HC_match_t newMatch;\n\n             if (curPtr > mflimit) break;\n             DEBUGLOG(7, \"rPos:%u[%u] vs [%u]%u\",\n                     cur, opt[cur].price, opt[cur+1].price, cur+1);\n             if (fullUpdate) {\n                 /* not useful to search here if next position has same (or lower) cost */\n                 if ( (opt[cur+1].price <= opt[cur].price)\n                   /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */\n                   && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )\n                     continue;\n             } else {\n                 /* not useful to search here if next position has same (or lower) cost */\n                 if (opt[cur+1].price <= opt[cur].price) continue;\n             }\n\n             DEBUGLOG(7, \"search at rPos:%u\", cur);\n             if (fullUpdate)\n                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);\n             else\n                 /* only test matches of minimum length; slightly faster, but misses a few bytes */\n                 newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);\n             if (!newMatch.len) continue;\n\n             if ( ((size_t)newMatch.len > sufficient_len)\n               || (newMatch.len + cur >= LZ4_OPT_NUM) ) {\n                 /* immediate encoding */\n                 best_mlen = newMatch.len;\n                 best_off = newMatch.off;\n                 last_match_pos = cur + 1;\n                 goto encode;\n             }\n\n             /* before match : set price with literals at beginning */\n             {   int const baseLitlen = opt[cur].litlen;\n                 int litlen;\n                 for (litlen = 1; litlen < MINMATCH; litlen++) {\n                     int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);\n                     int const pos = cur + litlen;\n                     if (price < opt[pos].price) {\n                         opt[pos].mlen = 1; /* literal */\n                         opt[pos].off = 0;\n                         opt[pos].litlen = baseLitlen+litlen;\n                         opt[pos].price = price;\n                         DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i)\",\n                                     pos, price, opt[pos].litlen);\n             }   }   }\n\n             /* set prices using match at position = cur */\n             {   int const matchML = newMatch.len;\n                 int ml = MINMATCH;\n\n                 assert(cur + newMatch.len < LZ4_OPT_NUM);\n                 for ( ; ml <= matchML ; ml++) {\n                     int const pos = cur + ml;\n                     int const offset = newMatch.off;\n                     int price;\n                     int ll;\n                     DEBUGLOG(7, \"testing price rPos %i (last_match_pos=%i)\",\n                                 pos, last_match_pos);\n                     if (opt[cur].mlen == 1) {\n                         ll = opt[cur].litlen;\n                         price = ((cur > ll) ? opt[cur - ll].price : 0)\n                               + LZ4HC_sequencePrice(ll, ml);\n                     } else {\n                         ll = 0;\n                         price = opt[cur].price + LZ4HC_sequencePrice(0, ml);\n                     }\n\n                    assert((U32)favorDecSpeed <= 1);\n                     if (pos > last_match_pos+TRAILING_LITERALS\n                      || price <= opt[pos].price - (int)favorDecSpeed) {\n                         DEBUGLOG(7, \"rPos:%3i => price:%3i (matchlen=%i)\",\n                                     pos, price, ml);\n                         assert(pos < LZ4_OPT_NUM);\n                         if ( (ml == matchML)  /* last pos of last match */\n                           && (last_match_pos < pos) )\n                             last_match_pos = pos;\n                         opt[pos].mlen = ml;\n                         opt[pos].off = offset;\n                         opt[pos].litlen = ll;\n                         opt[pos].price = price;\n             }   }   }\n             /* complete following positions with literals */\n             {   int addLit;\n                 for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {\n                     opt[last_match_pos+addLit].mlen = 1; /* literal */\n                     opt[last_match_pos+addLit].off = 0;\n                     opt[last_match_pos+addLit].litlen = addLit;\n                     opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);\n                     DEBUGLOG(7, \"rPos:%3i => price:%3i (litlen=%i)\", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);\n             }   }\n         }  /* for (cur = 1; cur <= last_match_pos; cur++) */\n\n         assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);\n         best_mlen = opt[last_match_pos].mlen;\n         best_off = opt[last_match_pos].off;\n         cur = last_match_pos - best_mlen;\n\nencode: /* cur, last_match_pos, best_mlen, best_off must be set */\n         assert(cur < LZ4_OPT_NUM);\n         assert(last_match_pos >= 1);  /* == 1 when only one candidate */\n         DEBUGLOG(6, \"reverse traversal, looking for shortest path (last_match_pos=%i)\", last_match_pos);\n         {   int candidate_pos = cur;\n             int selected_matchLength = best_mlen;\n             int selected_offset = best_off;\n             while (1) {  /* from end to beginning */\n                 int const next_matchLength = opt[candidate_pos].mlen;  /* can be 1, means literal */\n                 int const next_offset = opt[candidate_pos].off;\n                 DEBUGLOG(7, \"pos %i: sequence length %i\", candidate_pos, selected_matchLength);\n                 opt[candidate_pos].mlen = selected_matchLength;\n                 opt[candidate_pos].off = selected_offset;\n                 selected_matchLength = next_matchLength;\n                 selected_offset = next_offset;\n                 if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */\n                 assert(next_matchLength > 0);  /* can be 1, means literal */\n                 candidate_pos -= next_matchLength;\n         }   }\n\n         /* encode all recorded sequences in order */\n         {   int rPos = 0;  /* relative position (to ip) */\n             while (rPos < last_match_pos) {\n                 int const ml = opt[rPos].mlen;\n                 int const offset = opt[rPos].off;\n                 if (ml == 1) { ip++; rPos++; continue; }  /* literal; note: can end up with several literals, in which case, skip them */\n                 rPos += ml;\n                 assert(ml >= MINMATCH);\n                 assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));\n                 opSaved = op;\n                 if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, offset, limit, oend) ) {  /* updates ip, op and anchor */\n                     ovml = ml;\n                     ovoff = offset;\n                     goto _dest_overflow;\n         }   }   }\n     }  /* while (ip <= mflimit) */\n\n_last_literals:\n     /* Encode Last Literals */\n     {   size_t lastRunSize = (size_t)(iend - anchor);  /* literals */\n         size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;\n         size_t const totalSize = 1 + llAdd + lastRunSize;\n         if (limit == fillOutput) oend += LASTLITERALS;  /* restore correct value */\n         if (limit && (op + totalSize > oend)) {\n             if (limit == limitedOutput) { /* Check output limit */\n                retval = 0;\n                goto _return_label;\n             }\n             /* adapt lastRunSize to fill 'dst' */\n             lastRunSize  = (size_t)(oend - op) - 1 /*token*/;\n             llAdd = (lastRunSize + 256 - RUN_MASK) / 256;\n             lastRunSize -= llAdd;\n         }\n         DEBUGLOG(6, \"Final literal run : %i literals\", (int)lastRunSize);\n         ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */\n\n         if (lastRunSize >= RUN_MASK) {\n             size_t accumulator = lastRunSize - RUN_MASK;\n             *op++ = (RUN_MASK << ML_BITS);\n             for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;\n             *op++ = (BYTE) accumulator;\n         } else {\n             *op++ = (BYTE)(lastRunSize << ML_BITS);\n         }\n         LZ4_memcpy(op, anchor, lastRunSize);\n         op += lastRunSize;\n     }\n\n     /* End */\n     *srcSizePtr = (int) (((const char*)ip) - source);\n     retval = (int) ((char*)op-dst);\n     goto _return_label;\n\n_dest_overflow:\nif (limit == fillOutput) {\n     /* Assumption : ip, anchor, ovml and ovref must be set correctly */\n     size_t const ll = (size_t)(ip - anchor);\n     size_t const ll_addbytes = (ll + 240) / 255;\n     size_t const ll_totalCost = 1 + ll_addbytes + ll;\n     BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */\n     DEBUGLOG(6, \"Last sequence overflowing (only %i bytes remaining)\", (int)(oend-1-opSaved));\n     op = opSaved;  /* restore correct out pointer */\n     if (op + ll_totalCost <= maxLitPos) {\n         /* ll validated; now adjust match length */\n         size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost));\n         size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255);\n         assert(maxMlSize < INT_MAX); assert(ovml >= 0);\n         if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;\n         if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {\n             DEBUGLOG(6, \"Space to end : %i + ml (%i)\", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);\n             DEBUGLOG(6, \"Before : ip = %p, anchor = %p\", ip, anchor);\n             LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovoff, notLimited, oend);\n             DEBUGLOG(6, \"After : ip = %p, anchor = %p\", ip, anchor);\n     }   }\n     goto _last_literals;\n}\n_return_label:\n#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1\n     FREEMEM(opt);\n#endif\n     return retval;\n}\n"
  },
  {
    "path": "lib/LZ4F/lz4hc.h",
    "content": "/*\n   LZ4 HC - High Compression Mode of LZ4\n   Header File\n   Copyright (C) 2011-2020, Yann Collet.\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n   - LZ4 source repository : https://github.com/lz4/lz4\n   - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c\n*/\n#ifndef LZ4_HC_H_19834876238432\n#define LZ4_HC_H_19834876238432\n\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n/* --- Dependency --- */\n/* note : lz4hc requires lz4.h/lz4.c for compilation */\n#include \"lz4.h\"   /* stddef, LZ4LIB_API, LZ4_DEPRECATED */\n\n\n/* --- Useful constants --- */\n#define LZ4HC_CLEVEL_MIN         3\n#define LZ4HC_CLEVEL_DEFAULT     9\n#define LZ4HC_CLEVEL_OPT_MIN    10\n#define LZ4HC_CLEVEL_MAX        12\n\n\n/*-************************************\n *  Block Compression\n **************************************/\n/*! LZ4_compress_HC() :\n *  Compress data from `src` into `dst`, using the powerful but slower \"HC\" algorithm.\n * `dst` must be already allocated.\n *  Compression is guaranteed to succeed if `dstCapacity >= LZ4_compressBound(srcSize)` (see \"lz4.h\")\n *  Max supported `srcSize` value is LZ4_MAX_INPUT_SIZE (see \"lz4.h\")\n * `compressionLevel` : any value between 1 and LZ4HC_CLEVEL_MAX will work.\n *                      Values > LZ4HC_CLEVEL_MAX behave the same as LZ4HC_CLEVEL_MAX.\n * @return : the number of bytes written into 'dst'\n *           or 0 if compression fails.\n */\nLZ4LIB_API int LZ4_compress_HC (const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel);\n\n\n/* Note :\n *   Decompression functions are provided within \"lz4.h\" (BSD license)\n */\n\n\n/*! LZ4_compress_HC_extStateHC() :\n *  Same as LZ4_compress_HC(), but using an externally allocated memory segment for `state`.\n * `state` size is provided by LZ4_sizeofStateHC().\n *  Memory segment must be aligned on 8-bytes boundaries (which a normal malloc() should do properly).\n */\nLZ4LIB_API int LZ4_sizeofStateHC(void);\nLZ4LIB_API int LZ4_compress_HC_extStateHC(void* stateHC, const char* src, char* dst, int srcSize, int maxDstSize, int compressionLevel);\n\n\n/*! LZ4_compress_HC_destSize() : v1.9.0+\n *  Will compress as much data as possible from `src`\n *  to fit into `targetDstSize` budget.\n *  Result is provided in 2 parts :\n * @return : the number of bytes written into 'dst' (necessarily <= targetDstSize)\n *           or 0 if compression fails.\n * `srcSizePtr` : on success, *srcSizePtr is updated to indicate how much bytes were read from `src`\n */\nLZ4LIB_API int LZ4_compress_HC_destSize(void* stateHC,\n                                  const char* src, char* dst,\n                                        int* srcSizePtr, int targetDstSize,\n                                        int compressionLevel);\n\n\n/*-************************************\n *  Streaming Compression\n *  Bufferless synchronous API\n **************************************/\n typedef union LZ4_streamHC_u LZ4_streamHC_t;   /* incomplete type (defined later) */\n\n/*! LZ4_createStreamHC() and LZ4_freeStreamHC() :\n *  These functions create and release memory for LZ4 HC streaming state.\n *  Newly created states are automatically initialized.\n *  A same state can be used multiple times consecutively,\n *  starting with LZ4_resetStreamHC_fast() to start a new stream of blocks.\n */\nLZ4LIB_API LZ4_streamHC_t* LZ4_createStreamHC(void);\nLZ4LIB_API int             LZ4_freeStreamHC (LZ4_streamHC_t* streamHCPtr);\n\n/*\n  These functions compress data in successive blocks of any size,\n  using previous blocks as dictionary, to improve compression ratio.\n  One key assumption is that previous blocks (up to 64 KB) remain read-accessible while compressing next blocks.\n  There is an exception for ring buffers, which can be smaller than 64 KB.\n  Ring-buffer scenario is automatically detected and handled within LZ4_compress_HC_continue().\n\n  Before starting compression, state must be allocated and properly initialized.\n  LZ4_createStreamHC() does both, though compression level is set to LZ4HC_CLEVEL_DEFAULT.\n\n  Selecting the compression level can be done with LZ4_resetStreamHC_fast() (starts a new stream)\n  or LZ4_setCompressionLevel() (anytime, between blocks in the same stream) (experimental).\n  LZ4_resetStreamHC_fast() only works on states which have been properly initialized at least once,\n  which is automatically the case when state is created using LZ4_createStreamHC().\n\n  After reset, a first \"fictional block\" can be designated as initial dictionary,\n  using LZ4_loadDictHC() (Optional).\n\n  Invoke LZ4_compress_HC_continue() to compress each successive block.\n  The number of blocks is unlimited.\n  Previous input blocks, including initial dictionary when present,\n  must remain accessible and unmodified during compression.\n\n  It's allowed to update compression level anytime between blocks,\n  using LZ4_setCompressionLevel() (experimental).\n\n  'dst' buffer should be sized to handle worst case scenarios\n  (see LZ4_compressBound(), it ensures compression success).\n  In case of failure, the API does not guarantee recovery,\n  so the state _must_ be reset.\n  To ensure compression success\n  whenever `dst` buffer size cannot be made >= LZ4_compressBound(),\n  consider using LZ4_compress_HC_continue_destSize().\n\n  Whenever previous input blocks can't be preserved unmodified in-place during compression of next blocks,\n  it's possible to copy the last blocks into a more stable memory space, using LZ4_saveDictHC().\n  Return value of LZ4_saveDictHC() is the size of dictionary effectively saved into 'safeBuffer' (<= 64 KB)\n\n  After completing a streaming compression,\n  it's possible to start a new stream of blocks, using the same LZ4_streamHC_t state,\n  just by resetting it, using LZ4_resetStreamHC_fast().\n*/\n\nLZ4LIB_API void LZ4_resetStreamHC_fast(LZ4_streamHC_t* streamHCPtr, int compressionLevel);   /* v1.9.0+ */\nLZ4LIB_API int  LZ4_loadDictHC (LZ4_streamHC_t* streamHCPtr, const char* dictionary, int dictSize);\n\nLZ4LIB_API int LZ4_compress_HC_continue (LZ4_streamHC_t* streamHCPtr,\n                                   const char* src, char* dst,\n                                         int srcSize, int maxDstSize);\n\n/*! LZ4_compress_HC_continue_destSize() : v1.9.0+\n *  Similar to LZ4_compress_HC_continue(),\n *  but will read as much data as possible from `src`\n *  to fit into `targetDstSize` budget.\n *  Result is provided into 2 parts :\n * @return : the number of bytes written into 'dst' (necessarily <= targetDstSize)\n *           or 0 if compression fails.\n * `srcSizePtr` : on success, *srcSizePtr will be updated to indicate how much bytes were read from `src`.\n *           Note that this function may not consume the entire input.\n */\nLZ4LIB_API int LZ4_compress_HC_continue_destSize(LZ4_streamHC_t* LZ4_streamHCPtr,\n                                           const char* src, char* dst,\n                                                 int* srcSizePtr, int targetDstSize);\n\nLZ4LIB_API int LZ4_saveDictHC (LZ4_streamHC_t* streamHCPtr, char* safeBuffer, int maxDictSize);\n\n\n\n/*^**********************************************\n * !!!!!!   STATIC LINKING ONLY   !!!!!!\n ***********************************************/\n\n/*-******************************************************************\n * PRIVATE DEFINITIONS :\n * Do not use these definitions directly.\n * They are merely exposed to allow static allocation of `LZ4_streamHC_t`.\n * Declare an `LZ4_streamHC_t` directly, rather than any type below.\n * Even then, only do so in the context of static linking, as definitions may change between versions.\n ********************************************************************/\n\n#define LZ4HC_DICTIONARY_LOGSIZE 16\n#define LZ4HC_MAXD (1<<LZ4HC_DICTIONARY_LOGSIZE)\n#define LZ4HC_MAXD_MASK (LZ4HC_MAXD - 1)\n\n#define LZ4HC_HASH_LOG 15\n#define LZ4HC_HASHTABLESIZE (1 << LZ4HC_HASH_LOG)\n#define LZ4HC_HASH_MASK (LZ4HC_HASHTABLESIZE - 1)\n\n\n/* Never ever use these definitions directly !\n * Declare or allocate an LZ4_streamHC_t instead.\n**/\ntypedef struct LZ4HC_CCtx_internal LZ4HC_CCtx_internal;\nstruct LZ4HC_CCtx_internal\n{\n    LZ4_u32   hashTable[LZ4HC_HASHTABLESIZE];\n    LZ4_u16   chainTable[LZ4HC_MAXD];\n    const LZ4_byte* end;       /* next block here to continue on current prefix */\n    const LZ4_byte* prefixStart;  /* Indexes relative to this position */\n    const LZ4_byte* dictStart; /* alternate reference for extDict */\n    LZ4_u32   dictLimit;       /* below that point, need extDict */\n    LZ4_u32   lowLimit;        /* below that point, no more dict */\n    LZ4_u32   nextToUpdate;    /* index from which to continue dictionary update */\n    short     compressionLevel;\n    LZ4_i8    favorDecSpeed;   /* favor decompression speed if this flag set,\n                                  otherwise, favor compression ratio */\n    LZ4_i8    dirty;           /* stream has to be fully reset if this flag is set */\n    const LZ4HC_CCtx_internal* dictCtx;\n};\n\n#define LZ4_STREAMHC_MINSIZE  262200  /* static size, for inter-version compatibility */\nunion LZ4_streamHC_u {\n    char minStateSize[LZ4_STREAMHC_MINSIZE];\n    LZ4HC_CCtx_internal internal_donotuse;\n}; /* previously typedef'd to LZ4_streamHC_t */\n\n/* LZ4_streamHC_t :\n * This structure allows static allocation of LZ4 HC streaming state.\n * This can be used to allocate statically on stack, or as part of a larger structure.\n *\n * Such state **must** be initialized using LZ4_initStreamHC() before first use.\n *\n * Note that invoking LZ4_initStreamHC() is not required when\n * the state was created using LZ4_createStreamHC() (which is recommended).\n * Using the normal builder, a newly created state is automatically initialized.\n *\n * Static allocation shall only be used in combination with static linking.\n */\n\n/* LZ4_initStreamHC() : v1.9.0+\n * Required before first use of a statically allocated LZ4_streamHC_t.\n * Before v1.9.0 : use LZ4_resetStreamHC() instead\n */\nLZ4LIB_API LZ4_streamHC_t* LZ4_initStreamHC(void* buffer, size_t size);\n\n\n/*-************************************\n*  Deprecated Functions\n**************************************/\n/* see lz4.h LZ4_DISABLE_DEPRECATE_WARNINGS to turn off deprecation warnings */\n\n/* deprecated compression functions */\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC               (const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC2              (const char* source, char* dest, int inputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC() instead\") LZ4LIB_API int LZ4_compressHC2_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC_withStateHC               (void* state, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* source, char* dest, int inputSize, int maxOutputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC2_withStateHC              (void* state, const char* source, char* dest, int inputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_extStateHC() instead\") LZ4LIB_API int LZ4_compressHC2_limitedOutput_withStateHC(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC_continue               (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* source, char* dest, int inputSize, int maxOutputSize);\n\n/* Obsolete streaming functions; degraded functionality; do not use!\n *\n * In order to perform streaming compression, these functions depended on data\n * that is no longer tracked in the state. They have been preserved as well as\n * possible: using them will still produce a correct output. However, use of\n * LZ4_slideInputBufferHC() will truncate the history of the stream, rather\n * than preserve a window-sized chunk of history.\n */\n#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION)\nLZ4_DEPRECATED(\"use LZ4_createStreamHC() instead\") LZ4LIB_API void* LZ4_createHC (const char* inputBuffer);\nLZ4_DEPRECATED(\"use LZ4_freeStreamHC() instead\") LZ4LIB_API   int   LZ4_freeHC (void* LZ4HC_Data);\n#endif\nLZ4_DEPRECATED(\"use LZ4_saveDictHC() instead\") LZ4LIB_API     char* LZ4_slideInputBufferHC (void* LZ4HC_Data);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC2_continue               (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_compress_HC_continue() instead\") LZ4LIB_API int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* source, char* dest, int inputSize, int maxOutputSize, int compressionLevel);\nLZ4_DEPRECATED(\"use LZ4_createStreamHC() instead\") LZ4LIB_API int   LZ4_sizeofStreamStateHC(void);\nLZ4_DEPRECATED(\"use LZ4_initStreamHC() instead\") LZ4LIB_API  int   LZ4_resetStreamStateHC(void* state, char* inputBuffer);\n\n\n/* LZ4_resetStreamHC() is now replaced by LZ4_initStreamHC().\n * The intention is to emphasize the difference with LZ4_resetStreamHC_fast(),\n * which is now the recommended function to start a new stream of blocks,\n * but cannot be used to initialize a memory segment containing arbitrary garbage data.\n *\n * It is recommended to switch to LZ4_initStreamHC().\n * LZ4_resetStreamHC() will generate deprecation warnings in a future version.\n */\nLZ4LIB_API void LZ4_resetStreamHC (LZ4_streamHC_t* streamHCPtr, int compressionLevel);\n\n\n#if defined (__cplusplus)\n}\n#endif\n\n#endif /* LZ4_HC_H_19834876238432 */\n\n\n/*-**************************************************\n * !!!!!     STATIC LINKING ONLY     !!!!!\n * Following definitions are considered experimental.\n * They should not be linked from DLL,\n * as there is no guarantee of API stability yet.\n * Prototypes will be promoted to \"stable\" status\n * after successful usage in real-life scenarios.\n ***************************************************/\n#ifdef LZ4_HC_STATIC_LINKING_ONLY   /* protection macro */\n#ifndef LZ4_HC_SLO_098092834\n#define LZ4_HC_SLO_098092834\n\n#define LZ4_STATIC_LINKING_ONLY   /* LZ4LIB_STATIC_API */\n#include \"lz4.h\"\n\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n/*! LZ4_setCompressionLevel() : v1.8.0+ (experimental)\n *  It's possible to change compression level\n *  between successive invocations of LZ4_compress_HC_continue*()\n *  for dynamic adaptation.\n */\nLZ4LIB_STATIC_API void LZ4_setCompressionLevel(\n    LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);\n\n/*! LZ4_favorDecompressionSpeed() : v1.8.2+ (experimental)\n *  Opt. Parser will favor decompression speed over compression ratio.\n *  Only applicable to levels >= LZ4HC_CLEVEL_OPT_MIN.\n */\nLZ4LIB_STATIC_API void LZ4_favorDecompressionSpeed(\n    LZ4_streamHC_t* LZ4_streamHCPtr, int favor);\n\n/*! LZ4_resetStreamHC_fast() : v1.9.0+\n *  When an LZ4_streamHC_t is known to be in a internally coherent state,\n *  it can often be prepared for a new compression with almost no work, only\n *  sometimes falling back to the full, expensive reset that is always required\n *  when the stream is in an indeterminate state (i.e., the reset performed by\n *  LZ4_resetStreamHC()).\n *\n *  LZ4_streamHCs are guaranteed to be in a valid state when:\n *  - returned from LZ4_createStreamHC()\n *  - reset by LZ4_resetStreamHC()\n *  - memset(stream, 0, sizeof(LZ4_streamHC_t))\n *  - the stream was in a valid state and was reset by LZ4_resetStreamHC_fast()\n *  - the stream was in a valid state and was then used in any compression call\n *    that returned success\n *  - the stream was in an indeterminate state and was used in a compression\n *    call that fully reset the state (LZ4_compress_HC_extStateHC()) and that\n *    returned success\n *\n *  Note:\n *  A stream that was last used in a compression call that returned an error\n *  may be passed to this function. However, it will be fully reset, which will\n *  clear any existing history and settings from the context.\n */\nLZ4LIB_STATIC_API void LZ4_resetStreamHC_fast(\n    LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel);\n\n/*! LZ4_compress_HC_extStateHC_fastReset() :\n *  A variant of LZ4_compress_HC_extStateHC().\n *\n *  Using this variant avoids an expensive initialization step. It is only safe\n *  to call if the state buffer is known to be correctly initialized already\n *  (see above comment on LZ4_resetStreamHC_fast() for a definition of\n *  \"correctly initialized\"). From a high level, the difference is that this\n *  function initializes the provided state with a call to\n *  LZ4_resetStreamHC_fast() while LZ4_compress_HC_extStateHC() starts with a\n *  call to LZ4_resetStreamHC().\n */\nLZ4LIB_STATIC_API int LZ4_compress_HC_extStateHC_fastReset (\n    void* state,\n    const char* src, char* dst,\n    int srcSize, int dstCapacity,\n    int compressionLevel);\n\n/*! LZ4_attach_HC_dictionary() :\n *  This is an experimental API that allows for the efficient use of a\n *  static dictionary many times.\n *\n *  Rather than re-loading the dictionary buffer into a working context before\n *  each compression, or copying a pre-loaded dictionary's LZ4_streamHC_t into a\n *  working LZ4_streamHC_t, this function introduces a no-copy setup mechanism,\n *  in which the working stream references the dictionary stream in-place.\n *\n *  Several assumptions are made about the state of the dictionary stream.\n *  Currently, only streams which have been prepared by LZ4_loadDictHC() should\n *  be expected to work.\n *\n *  Alternatively, the provided dictionary stream pointer may be NULL, in which\n *  case any existing dictionary stream is unset.\n *\n *  A dictionary should only be attached to a stream without any history (i.e.,\n *  a stream that has just been reset).\n *\n *  The dictionary will remain attached to the working stream only for the\n *  current stream session. Calls to LZ4_resetStreamHC(_fast) will remove the\n *  dictionary context association from the working stream. The dictionary\n *  stream (and source buffer) must remain in-place / accessible / unchanged\n *  through the lifetime of the stream session.\n */\nLZ4LIB_STATIC_API void LZ4_attach_HC_dictionary(\n          LZ4_streamHC_t *working_stream,\n    const LZ4_streamHC_t *dictionary_stream);\n\n#if defined (__cplusplus)\n}\n#endif\n\n#endif   /* LZ4_HC_SLO_098092834 */\n#endif   /* LZ4_HC_STATIC_LINKING_ONLY */\n"
  },
  {
    "path": "lib/LZ4F/xxhash.c",
    "content": "/*\n*  xxHash - Fast Hash algorithm\n*  Copyright (C) 2012-2016, Yann Collet\n*\n*  BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n*\n*  Redistribution and use in source and binary forms, with or without\n*  modification, are permitted provided that the following conditions are\n*  met:\n*\n*  * Redistributions of source code must retain the above copyright\n*  notice, this list of conditions and the following disclaimer.\n*  * Redistributions in binary form must reproduce the above\n*  copyright notice, this list of conditions and the following disclaimer\n*  in the documentation and/or other materials provided with the\n*  distribution.\n*\n*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n*  \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n*  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n*  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n*  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n*  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n*  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n*  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*\n*  You can contact the author at :\n*  - xxHash homepage: http://www.xxhash.com\n*  - xxHash source repository : https://github.com/Cyan4973/xxHash\n*/\n\n\n/* *************************************\n*  Tuning parameters\n***************************************/\n/*!XXH_FORCE_MEMORY_ACCESS :\n * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable.\n * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal.\n * The below switch allow to select different access method for improved performance.\n * Method 0 (default) : use `memcpy()`. Safe and portable.\n * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable).\n *            This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`.\n * Method 2 : direct access. This method doesn't depend on compiler but violate C standard.\n *            It can generate buggy code on targets which do not support unaligned memory accesses.\n *            But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6)\n * See http://stackoverflow.com/a/32095106/646947 for details.\n * Prefer these methods in priority order (0 > 1 > 2)\n */\n#ifndef XXH_FORCE_MEMORY_ACCESS   /* can be defined externally, on command line for example */\n#  if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \\\n                        || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \\\n                        || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) )\n#    define XXH_FORCE_MEMORY_ACCESS 2\n#  elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || \\\n  (defined(__GNUC__) && ( defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) \\\n                    || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) \\\n                    || defined(__ARM_ARCH_7S__) ))\n#    define XXH_FORCE_MEMORY_ACCESS 1\n#  endif\n#endif\n\n/*!XXH_ACCEPT_NULL_INPUT_POINTER :\n * If input pointer is NULL, xxHash default behavior is to dereference it, triggering a segfault.\n * When this macro is enabled, xxHash actively checks input for null pointer.\n * It it is, result for null input pointers is the same as a null-length input.\n */\n#ifndef XXH_ACCEPT_NULL_INPUT_POINTER   /* can be defined externally */\n#  define XXH_ACCEPT_NULL_INPUT_POINTER 0\n#endif\n\n/*!XXH_FORCE_NATIVE_FORMAT :\n * By default, xxHash library provides endian-independent Hash values, based on little-endian convention.\n * Results are therefore identical for little-endian and big-endian CPU.\n * This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.\n * Should endian-independence be of no importance for your application, you may set the #define below to 1,\n * to improve speed for Big-endian CPU.\n * This option has no impact on Little_Endian CPU.\n */\n#ifndef XXH_FORCE_NATIVE_FORMAT   /* can be defined externally */\n#  define XXH_FORCE_NATIVE_FORMAT 0\n#endif\n\n/*!XXH_FORCE_ALIGN_CHECK :\n * This is a minor performance trick, only useful with lots of very small keys.\n * It means : check for aligned/unaligned input.\n * The check costs one initial branch per hash;\n * set it to 0 when the input is guaranteed to be aligned,\n * or when alignment doesn't matter for performance.\n */\n#ifndef XXH_FORCE_ALIGN_CHECK /* can be defined externally */\n#  if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)\n#    define XXH_FORCE_ALIGN_CHECK 0\n#  else\n#    define XXH_FORCE_ALIGN_CHECK 1\n#  endif\n#endif\n\n\n/* *************************************\n*  Includes & Memory related functions\n***************************************/\n/*! Modify the local functions below should you wish to use some other memory routines\n*   for malloc(), free() */\n#include <stdlib.h>\nstatic void* XXH_malloc(size_t s) { return malloc(s); }\nstatic void  XXH_free  (void* p)  { free(p); }\n/*! and for memcpy() */\n#include <string.h>\nstatic void* XXH_memcpy(void* dest, const void* src, size_t size) { return memcpy(dest,src,size); }\n\n#include <assert.h>   /* assert */\n\n#define XXH_STATIC_LINKING_ONLY\n#include \"xxhash.h\"\n\n\n/* *************************************\n*  Compiler Specific Options\n***************************************/\n#ifdef _MSC_VER    /* Visual Studio */\n#  pragma warning(disable : 4127)      /* disable: C4127: conditional expression is constant */\n#  define FORCE_INLINE static __forceinline\n#else\n#  if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L   /* C99 */\n#    ifdef __GNUC__\n#      define FORCE_INLINE static inline __attribute__((always_inline))\n#    else\n#      define FORCE_INLINE static inline\n#    endif\n#  else\n#    define FORCE_INLINE static\n#  endif /* __STDC_VERSION__ */\n#endif\n\n\n/* *************************************\n*  Basic Types\n***************************************/\n#ifndef MEM_MODULE\n# if !defined (__VMS) \\\n  && (defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n#   include <stdint.h>\n    typedef uint8_t  BYTE;\n    typedef uint16_t U16;\n    typedef uint32_t U32;\n# else\n    typedef unsigned char      BYTE;\n    typedef unsigned short     U16;\n    typedef unsigned int       U32;\n# endif\n#endif\n\n#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))\n\n/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */\nstatic U32 XXH_read32(const void* memPtr) { return *(const U32*) memPtr; }\n\n#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))\n\n/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */\n/* currently only defined for gcc and icc */\ntypedef union { U32 u32; } __attribute__((packed)) unalign;\nstatic U32 XXH_read32(const void* ptr) { return ((const unalign*)ptr)->u32; }\n\n#else\n\n/* portable and safe solution. Generally efficient.\n * see : http://stackoverflow.com/a/32095106/646947\n */\nstatic U32 XXH_read32(const void* memPtr)\n{\n    U32 val;\n    memcpy(&val, memPtr, sizeof(val));\n    return val;\n}\n\n#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */\n\n\n/* ****************************************\n*  Compiler-specific Functions and Macros\n******************************************/\n#define XXH_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)\n\n/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */\n#if defined(_MSC_VER)\n#  define XXH_rotl32(x,r) _rotl(x,r)\n#  define XXH_rotl64(x,r) _rotl64(x,r)\n#else\n#  define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))\n#  define XXH_rotl64(x,r) ((x << r) | (x >> (64 - r)))\n#endif\n\n#if defined(_MSC_VER)     /* Visual Studio */\n#  define XXH_swap32 _byteswap_ulong\n#elif XXH_GCC_VERSION >= 403\n#  define XXH_swap32 __builtin_bswap32\n#else\nstatic U32 XXH_swap32 (U32 x)\n{\n    return  ((x << 24) & 0xff000000 ) |\n            ((x <<  8) & 0x00ff0000 ) |\n            ((x >>  8) & 0x0000ff00 ) |\n            ((x >> 24) & 0x000000ff );\n}\n#endif\n\n\n/* *************************************\n*  Architecture Macros\n***************************************/\ntypedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;\n\n/* XXH_CPU_LITTLE_ENDIAN can be defined externally, for example on the compiler command line */\n#ifndef XXH_CPU_LITTLE_ENDIAN\nstatic int XXH_isLittleEndian(void)\n{\n    const union { U32 u; BYTE c[4]; } one = { 1 };   /* don't use static : performance detrimental  */\n    return one.c[0];\n}\n#   define XXH_CPU_LITTLE_ENDIAN   XXH_isLittleEndian()\n#endif\n\n\n/* ***************************\n*  Memory reads\n*****************************/\ntypedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;\n\nFORCE_INLINE U32 XXH_readLE32_align(const void* ptr, XXH_endianess endian, XXH_alignment align)\n{\n    if (align==XXH_unaligned)\n        return endian==XXH_littleEndian ? XXH_read32(ptr) : XXH_swap32(XXH_read32(ptr));\n    else\n        return endian==XXH_littleEndian ? *(const U32*)ptr : XXH_swap32(*(const U32*)ptr);\n}\n\nFORCE_INLINE U32 XXH_readLE32(const void* ptr, XXH_endianess endian)\n{\n    return XXH_readLE32_align(ptr, endian, XXH_unaligned);\n}\n\nstatic U32 XXH_readBE32(const void* ptr)\n{\n    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap32(XXH_read32(ptr)) : XXH_read32(ptr);\n}\n\n\n/* *************************************\n*  Macros\n***************************************/\n#define XXH_STATIC_ASSERT(c)  { enum { XXH_sa = 1/(int)(!!(c)) }; }  /* use after variable declarations */\nXXH_PUBLIC_API unsigned XXH_versionNumber (void) { return XXH_VERSION_NUMBER; }\n\n\n/* *******************************************************************\n*  32-bit hash functions\n*********************************************************************/\nstatic const U32 PRIME32_1 = 2654435761U;\nstatic const U32 PRIME32_2 = 2246822519U;\nstatic const U32 PRIME32_3 = 3266489917U;\nstatic const U32 PRIME32_4 =  668265263U;\nstatic const U32 PRIME32_5 =  374761393U;\n\nstatic U32 XXH32_round(U32 seed, U32 input)\n{\n    seed += input * PRIME32_2;\n    seed  = XXH_rotl32(seed, 13);\n    seed *= PRIME32_1;\n    return seed;\n}\n\n/* mix all bits */\nstatic U32 XXH32_avalanche(U32 h32)\n{\n    h32 ^= h32 >> 15;\n    h32 *= PRIME32_2;\n    h32 ^= h32 >> 13;\n    h32 *= PRIME32_3;\n    h32 ^= h32 >> 16;\n    return(h32);\n}\n\n#define XXH_get32bits(p) XXH_readLE32_align(p, endian, align)\n\nstatic U32\nXXH32_finalize(U32 h32, const void* ptr, size_t len,\n                XXH_endianess endian, XXH_alignment align)\n\n{\n    const BYTE* p = (const BYTE*)ptr;\n\n#define PROCESS1               \\\n    h32 += (*p++) * PRIME32_5; \\\n    h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;\n\n#define PROCESS4                         \\\n    h32 += XXH_get32bits(p) * PRIME32_3; \\\n    p+=4;                                \\\n    h32  = XXH_rotl32(h32, 17) * PRIME32_4 ;\n\n    switch(len&15)  /* or switch(bEnd - p) */\n    {\n      case 12:      PROCESS4;\n                    /* fallthrough */\n      case 8:       PROCESS4;\n                    /* fallthrough */\n      case 4:       PROCESS4;\n                    return XXH32_avalanche(h32);\n\n      case 13:      PROCESS4;\n                    /* fallthrough */\n      case 9:       PROCESS4;\n                    /* fallthrough */\n      case 5:       PROCESS4;\n                    PROCESS1;\n                    return XXH32_avalanche(h32);\n\n      case 14:      PROCESS4;\n                    /* fallthrough */\n      case 10:      PROCESS4;\n                    /* fallthrough */\n      case 6:       PROCESS4;\n                    PROCESS1;\n                    PROCESS1;\n                    return XXH32_avalanche(h32);\n\n      case 15:      PROCESS4;\n                    /* fallthrough */\n      case 11:      PROCESS4;\n                    /* fallthrough */\n      case 7:       PROCESS4;\n                    /* fallthrough */\n      case 3:       PROCESS1;\n                    /* fallthrough */\n      case 2:       PROCESS1;\n                    /* fallthrough */\n      case 1:       PROCESS1;\n                    /* fallthrough */\n      case 0:       return XXH32_avalanche(h32);\n    }\n    assert(0);\n    return h32;   /* reaching this point is deemed impossible */\n}\n\n\nFORCE_INLINE U32\nXXH32_endian_align(const void* input, size_t len, U32 seed,\n                    XXH_endianess endian, XXH_alignment align)\n{\n    const BYTE* p = (const BYTE*)input;\n    const BYTE* bEnd = p + len;\n    U32 h32;\n\n#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)\n    if (p==NULL) {\n        len=0;\n        bEnd=p=(const BYTE*)(size_t)16;\n    }\n#endif\n\n    if (len>=16) {\n        const BYTE* const limit = bEnd - 15;\n        U32 v1 = seed + PRIME32_1 + PRIME32_2;\n        U32 v2 = seed + PRIME32_2;\n        U32 v3 = seed + 0;\n        U32 v4 = seed - PRIME32_1;\n\n        do {\n            v1 = XXH32_round(v1, XXH_get32bits(p)); p+=4;\n            v2 = XXH32_round(v2, XXH_get32bits(p)); p+=4;\n            v3 = XXH32_round(v3, XXH_get32bits(p)); p+=4;\n            v4 = XXH32_round(v4, XXH_get32bits(p)); p+=4;\n        } while (p < limit);\n\n        h32 = XXH_rotl32(v1, 1)  + XXH_rotl32(v2, 7)\n            + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);\n    } else {\n        h32  = seed + PRIME32_5;\n    }\n\n    h32 += (U32)len;\n\n    return XXH32_finalize(h32, p, len&15, endian, align);\n}\n\n\nXXH_PUBLIC_API unsigned int XXH32 (const void* input, size_t len, unsigned int seed)\n{\n#if 0\n    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */\n    XXH32_state_t state;\n    XXH32_reset(&state, seed);\n    XXH32_update(&state, input, len);\n    return XXH32_digest(&state);\n#else\n    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\n\n    if (XXH_FORCE_ALIGN_CHECK) {\n        if ((((size_t)input) & 3) == 0) {   /* Input is 4-bytes aligned, leverage the speed benefit */\n            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n                return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);\n            else\n                return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);\n    }   }\n\n    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n        return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);\n    else\n        return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);\n#endif\n}\n\n\n\n/*======   Hash streaming   ======*/\n\nXXH_PUBLIC_API XXH32_state_t* XXH32_createState(void)\n{\n    return (XXH32_state_t*)XXH_malloc(sizeof(XXH32_state_t));\n}\nXXH_PUBLIC_API XXH_errorcode XXH32_freeState(XXH32_state_t* statePtr)\n{\n    XXH_free(statePtr);\n    return XXH_OK;\n}\n\nXXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dstState, const XXH32_state_t* srcState)\n{\n    memcpy(dstState, srcState, sizeof(*dstState));\n}\n\nXXH_PUBLIC_API XXH_errorcode XXH32_reset(XXH32_state_t* statePtr, unsigned int seed)\n{\n    XXH32_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */\n    memset(&state, 0, sizeof(state));\n    state.v1 = seed + PRIME32_1 + PRIME32_2;\n    state.v2 = seed + PRIME32_2;\n    state.v3 = seed + 0;\n    state.v4 = seed - PRIME32_1;\n    /* do not write into reserved, planned to be removed in a future version */\n    memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));\n    return XXH_OK;\n}\n\n\nFORCE_INLINE XXH_errorcode\nXXH32_update_endian(XXH32_state_t* state, const void* input, size_t len, XXH_endianess endian)\n{\n    if (input==NULL)\n#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)\n        return XXH_OK;\n#else\n        return XXH_ERROR;\n#endif\n\n    {   const BYTE* p = (const BYTE*)input;\n        const BYTE* const bEnd = p + len;\n\n        state->total_len_32 += (unsigned)len;\n        state->large_len |= (len>=16) | (state->total_len_32>=16);\n\n        if (state->memsize + len < 16)  {   /* fill in tmp buffer */\n            XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, len);\n            state->memsize += (unsigned)len;\n            return XXH_OK;\n        }\n\n        if (state->memsize) {   /* some data left from previous update */\n            XXH_memcpy((BYTE*)(state->mem32) + state->memsize, input, 16-state->memsize);\n            {   const U32* p32 = state->mem32;\n                state->v1 = XXH32_round(state->v1, XXH_readLE32(p32, endian)); p32++;\n                state->v2 = XXH32_round(state->v2, XXH_readLE32(p32, endian)); p32++;\n                state->v3 = XXH32_round(state->v3, XXH_readLE32(p32, endian)); p32++;\n                state->v4 = XXH32_round(state->v4, XXH_readLE32(p32, endian));\n            }\n            p += 16-state->memsize;\n            state->memsize = 0;\n        }\n\n        if (p <= bEnd-16) {\n            const BYTE* const limit = bEnd - 16;\n            U32 v1 = state->v1;\n            U32 v2 = state->v2;\n            U32 v3 = state->v3;\n            U32 v4 = state->v4;\n\n            do {\n                v1 = XXH32_round(v1, XXH_readLE32(p, endian)); p+=4;\n                v2 = XXH32_round(v2, XXH_readLE32(p, endian)); p+=4;\n                v3 = XXH32_round(v3, XXH_readLE32(p, endian)); p+=4;\n                v4 = XXH32_round(v4, XXH_readLE32(p, endian)); p+=4;\n            } while (p<=limit);\n\n            state->v1 = v1;\n            state->v2 = v2;\n            state->v3 = v3;\n            state->v4 = v4;\n        }\n\n        if (p < bEnd) {\n            XXH_memcpy(state->mem32, p, (size_t)(bEnd-p));\n            state->memsize = (unsigned)(bEnd-p);\n        }\n    }\n\n    return XXH_OK;\n}\n\n\nXXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* state_in, const void* input, size_t len)\n{\n    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\n\n    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n        return XXH32_update_endian(state_in, input, len, XXH_littleEndian);\n    else\n        return XXH32_update_endian(state_in, input, len, XXH_bigEndian);\n}\n\n\nFORCE_INLINE U32\nXXH32_digest_endian (const XXH32_state_t* state, XXH_endianess endian)\n{\n    U32 h32;\n\n    if (state->large_len) {\n        h32 = XXH_rotl32(state->v1, 1)\n            + XXH_rotl32(state->v2, 7)\n            + XXH_rotl32(state->v3, 12)\n            + XXH_rotl32(state->v4, 18);\n    } else {\n        h32 = state->v3 /* == seed */ + PRIME32_5;\n    }\n\n    h32 += state->total_len_32;\n\n    return XXH32_finalize(h32, state->mem32, state->memsize, endian, XXH_aligned);\n}\n\n\nXXH_PUBLIC_API unsigned int XXH32_digest (const XXH32_state_t* state_in)\n{\n    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\n\n    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n        return XXH32_digest_endian(state_in, XXH_littleEndian);\n    else\n        return XXH32_digest_endian(state_in, XXH_bigEndian);\n}\n\n\n/*======   Canonical representation   ======*/\n\n/*! Default XXH result types are basic unsigned 32 and 64 bits.\n*   The canonical representation follows human-readable write convention, aka big-endian (large digits first).\n*   These functions allow transformation of hash result into and from its canonical format.\n*   This way, hash values can be written into a file or buffer, remaining comparable across different systems.\n*/\n\nXXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash)\n{\n    XXH_STATIC_ASSERT(sizeof(XXH32_canonical_t) == sizeof(XXH32_hash_t));\n    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap32(hash);\n    memcpy(dst, &hash, sizeof(*dst));\n}\n\nXXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src)\n{\n    return XXH_readBE32(src);\n}\n\n\n#ifndef XXH_NO_LONG_LONG\n\n/* *******************************************************************\n*  64-bit hash functions\n*********************************************************************/\n\n/*======   Memory access   ======*/\n\n#ifndef MEM_MODULE\n# define MEM_MODULE\n# if !defined (__VMS) \\\n  && (defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n#   include <stdint.h>\n    typedef uint64_t U64;\n# else\n    /* if compiler doesn't support unsigned long long, replace by another 64-bit type */\n    typedef unsigned long long U64;\n# endif\n#endif\n\n\n#if (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==2))\n\n/* Force direct memory access. Only works on CPU which support unaligned memory access in hardware */\nstatic U64 XXH_read64(const void* memPtr) { return *(const U64*) memPtr; }\n\n#elif (defined(XXH_FORCE_MEMORY_ACCESS) && (XXH_FORCE_MEMORY_ACCESS==1))\n\n/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */\n/* currently only defined for gcc and icc */\ntypedef union { U32 u32; U64 u64; } __attribute__((packed)) unalign64;\nstatic U64 XXH_read64(const void* ptr) { return ((const unalign64*)ptr)->u64; }\n\n#else\n\n/* portable and safe solution. Generally efficient.\n * see : http://stackoverflow.com/a/32095106/646947\n */\n\nstatic U64 XXH_read64(const void* memPtr)\n{\n    U64 val;\n    memcpy(&val, memPtr, sizeof(val));\n    return val;\n}\n\n#endif   /* XXH_FORCE_DIRECT_MEMORY_ACCESS */\n\n#if defined(_MSC_VER)     /* Visual Studio */\n#  define XXH_swap64 _byteswap_uint64\n#elif XXH_GCC_VERSION >= 403\n#  define XXH_swap64 __builtin_bswap64\n#else\nstatic U64 XXH_swap64 (U64 x)\n{\n    return  ((x << 56) & 0xff00000000000000ULL) |\n            ((x << 40) & 0x00ff000000000000ULL) |\n            ((x << 24) & 0x0000ff0000000000ULL) |\n            ((x << 8)  & 0x000000ff00000000ULL) |\n            ((x >> 8)  & 0x00000000ff000000ULL) |\n            ((x >> 24) & 0x0000000000ff0000ULL) |\n            ((x >> 40) & 0x000000000000ff00ULL) |\n            ((x >> 56) & 0x00000000000000ffULL);\n}\n#endif\n\nFORCE_INLINE U64 XXH_readLE64_align(const void* ptr, XXH_endianess endian, XXH_alignment align)\n{\n    if (align==XXH_unaligned)\n        return endian==XXH_littleEndian ? XXH_read64(ptr) : XXH_swap64(XXH_read64(ptr));\n    else\n        return endian==XXH_littleEndian ? *(const U64*)ptr : XXH_swap64(*(const U64*)ptr);\n}\n\nFORCE_INLINE U64 XXH_readLE64(const void* ptr, XXH_endianess endian)\n{\n    return XXH_readLE64_align(ptr, endian, XXH_unaligned);\n}\n\nstatic U64 XXH_readBE64(const void* ptr)\n{\n    return XXH_CPU_LITTLE_ENDIAN ? XXH_swap64(XXH_read64(ptr)) : XXH_read64(ptr);\n}\n\n\n/*======   xxh64   ======*/\n\nstatic const U64 PRIME64_1 = 11400714785074694791ULL;\nstatic const U64 PRIME64_2 = 14029467366897019727ULL;\nstatic const U64 PRIME64_3 =  1609587929392839161ULL;\nstatic const U64 PRIME64_4 =  9650029242287828579ULL;\nstatic const U64 PRIME64_5 =  2870177450012600261ULL;\n\nstatic U64 XXH64_round(U64 acc, U64 input)\n{\n    acc += input * PRIME64_2;\n    acc  = XXH_rotl64(acc, 31);\n    acc *= PRIME64_1;\n    return acc;\n}\n\nstatic U64 XXH64_mergeRound(U64 acc, U64 val)\n{\n    val  = XXH64_round(0, val);\n    acc ^= val;\n    acc  = acc * PRIME64_1 + PRIME64_4;\n    return acc;\n}\n\nstatic U64 XXH64_avalanche(U64 h64)\n{\n    h64 ^= h64 >> 33;\n    h64 *= PRIME64_2;\n    h64 ^= h64 >> 29;\n    h64 *= PRIME64_3;\n    h64 ^= h64 >> 32;\n    return h64;\n}\n\n\n#define XXH_get64bits(p) XXH_readLE64_align(p, endian, align)\n\nstatic U64\nXXH64_finalize(U64 h64, const void* ptr, size_t len,\n               XXH_endianess endian, XXH_alignment align)\n{\n    const BYTE* p = (const BYTE*)ptr;\n\n#define PROCESS1_64            \\\n    h64 ^= (*p++) * PRIME64_5; \\\n    h64 = XXH_rotl64(h64, 11) * PRIME64_1;\n\n#define PROCESS4_64          \\\n    h64 ^= (U64)(XXH_get32bits(p)) * PRIME64_1; \\\n    p+=4;                    \\\n    h64 = XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3;\n\n#define PROCESS8_64 {        \\\n    U64 const k1 = XXH64_round(0, XXH_get64bits(p)); \\\n    p+=8;                    \\\n    h64 ^= k1;               \\\n    h64  = XXH_rotl64(h64,27) * PRIME64_1 + PRIME64_4; \\\n}\n\n    switch(len&31) {\n      case 24: PROCESS8_64;\n                    /* fallthrough */\n      case 16: PROCESS8_64;\n                    /* fallthrough */\n      case  8: PROCESS8_64;\n               return XXH64_avalanche(h64);\n\n      case 28: PROCESS8_64;\n                    /* fallthrough */\n      case 20: PROCESS8_64;\n                    /* fallthrough */\n      case 12: PROCESS8_64;\n                    /* fallthrough */\n      case  4: PROCESS4_64;\n               return XXH64_avalanche(h64);\n\n      case 25: PROCESS8_64;\n                    /* fallthrough */\n      case 17: PROCESS8_64;\n                    /* fallthrough */\n      case  9: PROCESS8_64;\n               PROCESS1_64;\n               return XXH64_avalanche(h64);\n\n      case 29: PROCESS8_64;\n                    /* fallthrough */\n      case 21: PROCESS8_64;\n                    /* fallthrough */\n      case 13: PROCESS8_64;\n                    /* fallthrough */\n      case  5: PROCESS4_64;\n               PROCESS1_64;\n               return XXH64_avalanche(h64);\n\n      case 26: PROCESS8_64;\n                    /* fallthrough */\n      case 18: PROCESS8_64;\n                    /* fallthrough */\n      case 10: PROCESS8_64;\n               PROCESS1_64;\n               PROCESS1_64;\n               return XXH64_avalanche(h64);\n\n      case 30: PROCESS8_64;\n                    /* fallthrough */\n      case 22: PROCESS8_64;\n                    /* fallthrough */\n      case 14: PROCESS8_64;\n                    /* fallthrough */\n      case  6: PROCESS4_64;\n               PROCESS1_64;\n               PROCESS1_64;\n               return XXH64_avalanche(h64);\n\n      case 27: PROCESS8_64;\n                    /* fallthrough */\n      case 19: PROCESS8_64;\n                    /* fallthrough */\n      case 11: PROCESS8_64;\n               PROCESS1_64;\n               PROCESS1_64;\n               PROCESS1_64;\n               return XXH64_avalanche(h64);\n\n      case 31: PROCESS8_64;\n                    /* fallthrough */\n      case 23: PROCESS8_64;\n                    /* fallthrough */\n      case 15: PROCESS8_64;\n                    /* fallthrough */\n      case  7: PROCESS4_64;\n                    /* fallthrough */\n      case  3: PROCESS1_64;\n                    /* fallthrough */\n      case  2: PROCESS1_64;\n                    /* fallthrough */\n      case  1: PROCESS1_64;\n                    /* fallthrough */\n      case  0: return XXH64_avalanche(h64);\n    }\n\n    /* impossible to reach */\n    assert(0);\n    return 0;  /* unreachable, but some compilers complain without it */\n}\n\nFORCE_INLINE U64\nXXH64_endian_align(const void* input, size_t len, U64 seed,\n                XXH_endianess endian, XXH_alignment align)\n{\n    const BYTE* p = (const BYTE*)input;\n    const BYTE* bEnd = p + len;\n    U64 h64;\n\n#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)\n    if (p==NULL) {\n        len=0;\n        bEnd=p=(const BYTE*)(size_t)32;\n    }\n#endif\n\n    if (len>=32) {\n        const BYTE* const limit = bEnd - 32;\n        U64 v1 = seed + PRIME64_1 + PRIME64_2;\n        U64 v2 = seed + PRIME64_2;\n        U64 v3 = seed + 0;\n        U64 v4 = seed - PRIME64_1;\n\n        do {\n            v1 = XXH64_round(v1, XXH_get64bits(p)); p+=8;\n            v2 = XXH64_round(v2, XXH_get64bits(p)); p+=8;\n            v3 = XXH64_round(v3, XXH_get64bits(p)); p+=8;\n            v4 = XXH64_round(v4, XXH_get64bits(p)); p+=8;\n        } while (p<=limit);\n\n        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);\n        h64 = XXH64_mergeRound(h64, v1);\n        h64 = XXH64_mergeRound(h64, v2);\n        h64 = XXH64_mergeRound(h64, v3);\n        h64 = XXH64_mergeRound(h64, v4);\n\n    } else {\n        h64  = seed + PRIME64_5;\n    }\n\n    h64 += (U64) len;\n\n    return XXH64_finalize(h64, p, len, endian, align);\n}\n\n\nXXH_PUBLIC_API unsigned long long XXH64 (const void* input, size_t len, unsigned long long seed)\n{\n#if 0\n    /* Simple version, good for code maintenance, but unfortunately slow for small inputs */\n    XXH64_state_t state;\n    XXH64_reset(&state, seed);\n    XXH64_update(&state, input, len);\n    return XXH64_digest(&state);\n#else\n    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\n\n    if (XXH_FORCE_ALIGN_CHECK) {\n        if ((((size_t)input) & 7)==0) {  /* Input is aligned, let's leverage the speed advantage */\n            if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n                return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);\n            else\n                return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);\n    }   }\n\n    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n        return XXH64_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);\n    else\n        return XXH64_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);\n#endif\n}\n\n/*======   Hash Streaming   ======*/\n\nXXH_PUBLIC_API XXH64_state_t* XXH64_createState(void)\n{\n    return (XXH64_state_t*)XXH_malloc(sizeof(XXH64_state_t));\n}\nXXH_PUBLIC_API XXH_errorcode XXH64_freeState(XXH64_state_t* statePtr)\n{\n    XXH_free(statePtr);\n    return XXH_OK;\n}\n\nXXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dstState, const XXH64_state_t* srcState)\n{\n    memcpy(dstState, srcState, sizeof(*dstState));\n}\n\nXXH_PUBLIC_API XXH_errorcode XXH64_reset(XXH64_state_t* statePtr, unsigned long long seed)\n{\n    XXH64_state_t state;   /* using a local state to memcpy() in order to avoid strict-aliasing warnings */\n    memset(&state, 0, sizeof(state));\n    state.v1 = seed + PRIME64_1 + PRIME64_2;\n    state.v2 = seed + PRIME64_2;\n    state.v3 = seed + 0;\n    state.v4 = seed - PRIME64_1;\n     /* do not write into reserved, planned to be removed in a future version */\n    memcpy(statePtr, &state, sizeof(state) - sizeof(state.reserved));\n    return XXH_OK;\n}\n\nFORCE_INLINE XXH_errorcode\nXXH64_update_endian (XXH64_state_t* state, const void* input, size_t len, XXH_endianess endian)\n{\n    if (input==NULL)\n#if defined(XXH_ACCEPT_NULL_INPUT_POINTER) && (XXH_ACCEPT_NULL_INPUT_POINTER>=1)\n        return XXH_OK;\n#else\n        return XXH_ERROR;\n#endif\n\n    {   const BYTE* p = (const BYTE*)input;\n        const BYTE* const bEnd = p + len;\n\n        state->total_len += len;\n\n        if (state->memsize + len < 32) {  /* fill in tmp buffer */\n            XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, len);\n            state->memsize += (U32)len;\n            return XXH_OK;\n        }\n\n        if (state->memsize) {   /* tmp buffer is full */\n            XXH_memcpy(((BYTE*)state->mem64) + state->memsize, input, 32-state->memsize);\n            state->v1 = XXH64_round(state->v1, XXH_readLE64(state->mem64+0, endian));\n            state->v2 = XXH64_round(state->v2, XXH_readLE64(state->mem64+1, endian));\n            state->v3 = XXH64_round(state->v3, XXH_readLE64(state->mem64+2, endian));\n            state->v4 = XXH64_round(state->v4, XXH_readLE64(state->mem64+3, endian));\n            p += 32-state->memsize;\n            state->memsize = 0;\n        }\n\n        if (p+32 <= bEnd) {\n            const BYTE* const limit = bEnd - 32;\n            U64 v1 = state->v1;\n            U64 v2 = state->v2;\n            U64 v3 = state->v3;\n            U64 v4 = state->v4;\n\n            do {\n                v1 = XXH64_round(v1, XXH_readLE64(p, endian)); p+=8;\n                v2 = XXH64_round(v2, XXH_readLE64(p, endian)); p+=8;\n                v3 = XXH64_round(v3, XXH_readLE64(p, endian)); p+=8;\n                v4 = XXH64_round(v4, XXH_readLE64(p, endian)); p+=8;\n            } while (p<=limit);\n\n            state->v1 = v1;\n            state->v2 = v2;\n            state->v3 = v3;\n            state->v4 = v4;\n        }\n\n        if (p < bEnd) {\n            XXH_memcpy(state->mem64, p, (size_t)(bEnd-p));\n            state->memsize = (unsigned)(bEnd-p);\n        }\n    }\n\n    return XXH_OK;\n}\n\nXXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* state_in, const void* input, size_t len)\n{\n    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\n\n    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n        return XXH64_update_endian(state_in, input, len, XXH_littleEndian);\n    else\n        return XXH64_update_endian(state_in, input, len, XXH_bigEndian);\n}\n\nFORCE_INLINE U64 XXH64_digest_endian (const XXH64_state_t* state, XXH_endianess endian)\n{\n    U64 h64;\n\n    if (state->total_len >= 32) {\n        U64 const v1 = state->v1;\n        U64 const v2 = state->v2;\n        U64 const v3 = state->v3;\n        U64 const v4 = state->v4;\n\n        h64 = XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18);\n        h64 = XXH64_mergeRound(h64, v1);\n        h64 = XXH64_mergeRound(h64, v2);\n        h64 = XXH64_mergeRound(h64, v3);\n        h64 = XXH64_mergeRound(h64, v4);\n    } else {\n        h64  = state->v3 /*seed*/ + PRIME64_5;\n    }\n\n    h64 += (U64) state->total_len;\n\n    return XXH64_finalize(h64, state->mem64, (size_t)state->total_len, endian, XXH_aligned);\n}\n\nXXH_PUBLIC_API unsigned long long XXH64_digest (const XXH64_state_t* state_in)\n{\n    XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;\n\n    if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)\n        return XXH64_digest_endian(state_in, XXH_littleEndian);\n    else\n        return XXH64_digest_endian(state_in, XXH_bigEndian);\n}\n\n\n/*====== Canonical representation   ======*/\n\nXXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash)\n{\n    XXH_STATIC_ASSERT(sizeof(XXH64_canonical_t) == sizeof(XXH64_hash_t));\n    if (XXH_CPU_LITTLE_ENDIAN) hash = XXH_swap64(hash);\n    memcpy(dst, &hash, sizeof(*dst));\n}\n\nXXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src)\n{\n    return XXH_readBE64(src);\n}\n\n#endif  /* XXH_NO_LONG_LONG */\n"
  },
  {
    "path": "lib/LZ4F/xxhash.h",
    "content": "/*\n   xxHash - Extremely Fast Hash algorithm\n   Header File\n   Copyright (C) 2012-2016, Yann Collet.\n\n   BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)\n\n   Redistribution and use in source and binary forms, with or without\n   modification, are permitted provided that the following conditions are\n   met:\n\n       * Redistributions of source code must retain the above copyright\n   notice, this list of conditions and the following disclaimer.\n       * Redistributions in binary form must reproduce the above\n   copyright notice, this list of conditions and the following disclaimer\n   in the documentation and/or other materials provided with the\n   distribution.\n\n   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n   You can contact the author at :\n   - xxHash source repository : https://github.com/Cyan4973/xxHash\n*/\n\n/* Notice extracted from xxHash homepage :\n\nxxHash is an extremely fast Hash algorithm, running at RAM speed limits.\nIt also successfully passes all tests from the SMHasher suite.\n\nComparison (single thread, Windows Seven 32 bits, using SMHasher on a Core 2 Duo @3GHz)\n\nName            Speed       Q.Score   Author\nxxHash          5.4 GB/s     10\nCrapWow         3.2 GB/s      2       Andrew\nMumurHash 3a    2.7 GB/s     10       Austin Appleby\nSpookyHash      2.0 GB/s     10       Bob Jenkins\nSBox            1.4 GB/s      9       Bret Mulvey\nLookup3         1.2 GB/s      9       Bob Jenkins\nSuperFastHash   1.2 GB/s      1       Paul Hsieh\nCityHash64      1.05 GB/s    10       Pike & Alakuijala\nFNV             0.55 GB/s     5       Fowler, Noll, Vo\nCRC32           0.43 GB/s     9\nMD5-32          0.33 GB/s    10       Ronald L. Rivest\nSHA1-32         0.28 GB/s    10\n\nQ.Score is a measure of quality of the hash function.\nIt depends on successfully passing SMHasher test set.\n10 is a perfect score.\n\nA 64-bit version, named XXH64, is available since r35.\nIt offers much better speed, but for 64-bit applications only.\nName     Speed on 64 bits    Speed on 32 bits\nXXH64       13.8 GB/s            1.9 GB/s\nXXH32        6.8 GB/s            6.0 GB/s\n*/\n\n#ifndef XXHASH_H_5627135585666179\n#define XXHASH_H_5627135585666179 1\n\n#if defined (__cplusplus)\nextern \"C\" {\n#endif\n\n\n/* ****************************\n*  Definitions\n******************************/\n#include <stddef.h>   /* size_t */\ntypedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;\n\n\n/* ****************************\n *  API modifier\n ******************************/\n/** XXH_INLINE_ALL (and XXH_PRIVATE_API)\n *  This is useful to include xxhash functions in `static` mode\n *  in order to inline them, and remove their symbol from the public list.\n *  Inlining can offer dramatic performance improvement on small keys.\n *  Methodology :\n *     #define XXH_INLINE_ALL\n *     #include \"xxhash.h\"\n * `xxhash.c` is automatically included.\n *  It's not useful to compile and link it as a separate module.\n */\n#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)\n#  ifndef XXH_STATIC_LINKING_ONLY\n#    define XXH_STATIC_LINKING_ONLY\n#  endif\n#  if defined(__GNUC__)\n#    define XXH_PUBLIC_API static __inline __attribute__((unused))\n#  elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)\n#    define XXH_PUBLIC_API static inline\n#  elif defined(_MSC_VER)\n#    define XXH_PUBLIC_API static __inline\n#  else\n     /* this version may generate warnings for unused static functions */\n#    define XXH_PUBLIC_API static\n#  endif\n#else\n#  define XXH_PUBLIC_API   /* do nothing */\n#endif /* XXH_INLINE_ALL || XXH_PRIVATE_API */\n\n/*! XXH_NAMESPACE, aka Namespace Emulation :\n *\n * If you want to include _and expose_ xxHash functions from within your own library,\n * but also want to avoid symbol collisions with other libraries which may also include xxHash,\n *\n * you can use XXH_NAMESPACE, to automatically prefix any public symbol from xxhash library\n * with the value of XXH_NAMESPACE (therefore, avoid NULL and numeric values).\n *\n * Note that no change is required within the calling program as long as it includes `xxhash.h` :\n * regular symbol name will be automatically translated by this header.\n */\n#ifdef XXH_NAMESPACE\n#  define XXH_CAT(A,B) A##B\n#  define XXH_NAME2(A,B) XXH_CAT(A,B)\n#  define XXH_versionNumber XXH_NAME2(XXH_NAMESPACE, XXH_versionNumber)\n#  define XXH32 XXH_NAME2(XXH_NAMESPACE, XXH32)\n#  define XXH32_createState XXH_NAME2(XXH_NAMESPACE, XXH32_createState)\n#  define XXH32_freeState XXH_NAME2(XXH_NAMESPACE, XXH32_freeState)\n#  define XXH32_reset XXH_NAME2(XXH_NAMESPACE, XXH32_reset)\n#  define XXH32_update XXH_NAME2(XXH_NAMESPACE, XXH32_update)\n#  define XXH32_digest XXH_NAME2(XXH_NAMESPACE, XXH32_digest)\n#  define XXH32_copyState XXH_NAME2(XXH_NAMESPACE, XXH32_copyState)\n#  define XXH32_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH32_canonicalFromHash)\n#  define XXH32_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH32_hashFromCanonical)\n#  define XXH64 XXH_NAME2(XXH_NAMESPACE, XXH64)\n#  define XXH64_createState XXH_NAME2(XXH_NAMESPACE, XXH64_createState)\n#  define XXH64_freeState XXH_NAME2(XXH_NAMESPACE, XXH64_freeState)\n#  define XXH64_reset XXH_NAME2(XXH_NAMESPACE, XXH64_reset)\n#  define XXH64_update XXH_NAME2(XXH_NAMESPACE, XXH64_update)\n#  define XXH64_digest XXH_NAME2(XXH_NAMESPACE, XXH64_digest)\n#  define XXH64_copyState XXH_NAME2(XXH_NAMESPACE, XXH64_copyState)\n#  define XXH64_canonicalFromHash XXH_NAME2(XXH_NAMESPACE, XXH64_canonicalFromHash)\n#  define XXH64_hashFromCanonical XXH_NAME2(XXH_NAMESPACE, XXH64_hashFromCanonical)\n#endif\n\n\n/* *************************************\n*  Version\n***************************************/\n#define XXH_VERSION_MAJOR    0\n#define XXH_VERSION_MINOR    6\n#define XXH_VERSION_RELEASE  5\n#define XXH_VERSION_NUMBER  (XXH_VERSION_MAJOR *100*100 + XXH_VERSION_MINOR *100 + XXH_VERSION_RELEASE)\nXXH_PUBLIC_API unsigned XXH_versionNumber (void);\n\n\n/*-**********************************************************************\n*  32-bit hash\n************************************************************************/\ntypedef unsigned int XXH32_hash_t;\n\n/*! XXH32() :\n    Calculate the 32-bit hash of sequence \"length\" bytes stored at memory address \"input\".\n    The memory between input & input+length must be valid (allocated and read-accessible).\n    \"seed\" can be used to alter the result predictably.\n    Speed on Core 2 Duo @ 3 GHz (single thread, SMHasher benchmark) : 5.4 GB/s */\nXXH_PUBLIC_API XXH32_hash_t XXH32 (const void* input, size_t length, unsigned int seed);\n\n/*======   Streaming   ======*/\ntypedef struct XXH32_state_s XXH32_state_t;   /* incomplete type */\nXXH_PUBLIC_API XXH32_state_t* XXH32_createState(void);\nXXH_PUBLIC_API XXH_errorcode  XXH32_freeState(XXH32_state_t* statePtr);\nXXH_PUBLIC_API void XXH32_copyState(XXH32_state_t* dst_state, const XXH32_state_t* src_state);\n\nXXH_PUBLIC_API XXH_errorcode XXH32_reset  (XXH32_state_t* statePtr, unsigned int seed);\nXXH_PUBLIC_API XXH_errorcode XXH32_update (XXH32_state_t* statePtr, const void* input, size_t length);\nXXH_PUBLIC_API XXH32_hash_t  XXH32_digest (const XXH32_state_t* statePtr);\n\n/*\n * Streaming functions generate the xxHash of an input provided in multiple segments.\n * Note that, for small input, they are slower than single-call functions, due to state management.\n * For small inputs, prefer `XXH32()` and `XXH64()`, which are better optimized.\n *\n * XXH state must first be allocated, using XXH*_createState() .\n *\n * Start a new hash by initializing state with a seed, using XXH*_reset().\n *\n * Then, feed the hash state by calling XXH*_update() as many times as necessary.\n * The function returns an error code, with 0 meaning OK, and any other value meaning there is an error.\n *\n * Finally, a hash value can be produced anytime, by using XXH*_digest().\n * This function returns the nn-bits hash as an int or long long.\n *\n * It's still possible to continue inserting input into the hash state after a digest,\n * and generate some new hashes later on, by calling again XXH*_digest().\n *\n * When done, free XXH state space if it was allocated dynamically.\n */\n\n/*======   Canonical representation   ======*/\n\ntypedef struct { unsigned char digest[4]; } XXH32_canonical_t;\nXXH_PUBLIC_API void XXH32_canonicalFromHash(XXH32_canonical_t* dst, XXH32_hash_t hash);\nXXH_PUBLIC_API XXH32_hash_t XXH32_hashFromCanonical(const XXH32_canonical_t* src);\n\n/* Default result type for XXH functions are primitive unsigned 32 and 64 bits.\n * The canonical representation uses human-readable write convention, aka big-endian (large digits first).\n * These functions allow transformation of hash result into and from its canonical format.\n * This way, hash values can be written into a file / memory, and remain comparable on different systems and programs.\n */\n\n\n#ifndef XXH_NO_LONG_LONG\n/*-**********************************************************************\n*  64-bit hash\n************************************************************************/\ntypedef unsigned long long XXH64_hash_t;\n\n/*! XXH64() :\n    Calculate the 64-bit hash of sequence of length \"len\" stored at memory address \"input\".\n    \"seed\" can be used to alter the result predictably.\n    This function runs faster on 64-bit systems, but slower on 32-bit systems (see benchmark).\n*/\nXXH_PUBLIC_API XXH64_hash_t XXH64 (const void* input, size_t length, unsigned long long seed);\n\n/*======   Streaming   ======*/\ntypedef struct XXH64_state_s XXH64_state_t;   /* incomplete type */\nXXH_PUBLIC_API XXH64_state_t* XXH64_createState(void);\nXXH_PUBLIC_API XXH_errorcode  XXH64_freeState(XXH64_state_t* statePtr);\nXXH_PUBLIC_API void XXH64_copyState(XXH64_state_t* dst_state, const XXH64_state_t* src_state);\n\nXXH_PUBLIC_API XXH_errorcode XXH64_reset  (XXH64_state_t* statePtr, unsigned long long seed);\nXXH_PUBLIC_API XXH_errorcode XXH64_update (XXH64_state_t* statePtr, const void* input, size_t length);\nXXH_PUBLIC_API XXH64_hash_t  XXH64_digest (const XXH64_state_t* statePtr);\n\n/*======   Canonical representation   ======*/\ntypedef struct { unsigned char digest[8]; } XXH64_canonical_t;\nXXH_PUBLIC_API void XXH64_canonicalFromHash(XXH64_canonical_t* dst, XXH64_hash_t hash);\nXXH_PUBLIC_API XXH64_hash_t XXH64_hashFromCanonical(const XXH64_canonical_t* src);\n#endif  /* XXH_NO_LONG_LONG */\n\n\n\n#ifdef XXH_STATIC_LINKING_ONLY\n\n/* ================================================================================================\n   This section contains declarations which are not guaranteed to remain stable.\n   They may change in future versions, becoming incompatible with a different version of the library.\n   These declarations should only be used with static linking.\n   Never use them in association with dynamic linking !\n=================================================================================================== */\n\n/* These definitions are only present to allow\n * static allocation of XXH state, on stack or in a struct for example.\n * Never **ever** use members directly. */\n\n#if !defined (__VMS) \\\n  && (defined (__cplusplus) \\\n  || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) )\n#   include <stdint.h>\n\nstruct XXH32_state_s {\n   uint32_t total_len_32;\n   uint32_t large_len;\n   uint32_t v1;\n   uint32_t v2;\n   uint32_t v3;\n   uint32_t v4;\n   uint32_t mem32[4];\n   uint32_t memsize;\n   uint32_t reserved;   /* never read nor write, might be removed in a future version */\n};   /* typedef'd to XXH32_state_t */\n\nstruct XXH64_state_s {\n   uint64_t total_len;\n   uint64_t v1;\n   uint64_t v2;\n   uint64_t v3;\n   uint64_t v4;\n   uint64_t mem64[4];\n   uint32_t memsize;\n   uint32_t reserved[2];          /* never read nor write, might be removed in a future version */\n};   /* typedef'd to XXH64_state_t */\n\n# else\n\nstruct XXH32_state_s {\n   unsigned total_len_32;\n   unsigned large_len;\n   unsigned v1;\n   unsigned v2;\n   unsigned v3;\n   unsigned v4;\n   unsigned mem32[4];\n   unsigned memsize;\n   unsigned reserved;   /* never read nor write, might be removed in a future version */\n};   /* typedef'd to XXH32_state_t */\n\n#   ifndef XXH_NO_LONG_LONG  /* remove 64-bit support */\nstruct XXH64_state_s {\n   unsigned long long total_len;\n   unsigned long long v1;\n   unsigned long long v2;\n   unsigned long long v3;\n   unsigned long long v4;\n   unsigned long long mem64[4];\n   unsigned memsize;\n   unsigned reserved[2];     /* never read nor write, might be removed in a future version */\n};   /* typedef'd to XXH64_state_t */\n#    endif\n\n# endif\n\n\n#if defined(XXH_INLINE_ALL) || defined(XXH_PRIVATE_API)\n#  include \"xxhash.c\"   /* include xxhash function bodies as `static`, for inlining */\n#endif\n\n#endif /* XXH_STATIC_LINKING_ONLY */\n\n\n#if defined (__cplusplus)\n}\n#endif\n\n#endif /* XXHASH_H_5627135585666179 */\n"
  },
  {
    "path": "lib/SOIL2/SOIL2.c",
    "content": "/*\n \tFork by Martin Lucas Golini\n\n \tOriginal author\n\tJonathan Dummer\n\t2007-07-26-10.36\n\n\tSimple OpenGL Image Library 2\n\n\tPublic Domain\n\tusing Sean Barret's stb_image as a base\n\n\tThanks to:\n\t* Sean Barret - for the awesome stb_image\n\t* Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts\n\t* everybody at gamedev.net\n*/\n\n#define SOIL_CHECK_FOR_GL_ERRORS 0\n\n#if defined( __APPLE_CC__ ) || defined ( __APPLE__ )\n\t#include <TargetConditionals.h>\n\n\t#if defined( __IPHONE__ ) || ( defined( TARGET_OS_IPHONE ) && TARGET_OS_IPHONE ) || ( defined( TARGET_IPHONE_SIMULATOR ) && TARGET_IPHONE_SIMULATOR )\n\t\t#define SOIL_PLATFORM_IOS\n\t\t#include <dlfcn.h>\n\t#else\n\t\t#define SOIL_PLATFORM_OSX\n\t#endif\n#elif defined( __ANDROID__ ) || defined( ANDROID )\n\t#define SOIL_PLATFORM_ANDROID\n#elif ( defined ( linux ) || defined( __linux__ ) || defined( __FreeBSD__ ) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined( __DragonFly__ ) || defined( __SVR4 ) )\n\t#define SOIL_X11_PLATFORM\n#endif\n\n#if ( defined( SOIL_PLATFORM_IOS ) || defined( SOIL_PLATFORM_ANDROID ) ) && ( !defined( SOIL_GLES1 ) && !defined( SOIL_GLES2 ) )\n\t#define SOIL_GLES2\n#endif\n\n#if ( defined( SOIL_GLES2 ) || defined( SOIL_GLES1 ) ) && !defined( SOIL_NO_EGL ) && !defined( SOIL_PLATFORM_IOS )\n\t#include <EGL/egl.h>\n#endif\n\n#if defined( SOIL_GLES2 )\n\t#ifdef SOIL_PLATFORM_IOS\n\t\t#include <OpenGLES/ES2/gl.h>\n\t\t#include <OpenGLES/ES2/glext.h>\n\t#else\n\t\t#include <GLES2/gl2.h>\n\t\t#include <GLES2/gl2ext.h>\n\t#endif\n\n\t#define APIENTRY GL_APIENTRY\n#elif defined( SOIL_GLES1 )\n\t#ifndef GL_GLEXT_PROTOTYPES\n\t#define GL_GLEXT_PROTOTYPES\n\t#endif\n\t#ifdef SOIL_PLATFORM_IOS\n\t\t#include <OpenGLES/ES1/gl.h>\n\t\t#include <OpenGLES/ES1/glext.h>\n\t#else\n\t\t#include <GLES/gl.h>\n\t\t#include <GLES/glext.h>\n\t#endif\n\n\t#define APIENTRY GL_APIENTRY\n#else\n\n#if defined( __WIN32__ ) || defined( _WIN32 ) || defined( WIN32 )\n\t#define SOIL_PLATFORM_WIN32\n\t#define WIN32_LEAN_AND_MEAN\n\t#include <windows.h>\n\t#include <wingdi.h>\n\t#include <GL/gl.h>\n#elif defined(__APPLE__) || defined(__APPLE_CC__)\n\t/*\tI can't test this Apple stuff!\t*/\n\t#include <OpenGL/gl.h>\n\t#include <Carbon/Carbon.h>\n\t#define APIENTRY\n#elif defined( SOIL_X11_PLATFORM )\n\t#include <GL/gl.h>\n\t#include <GL/glx.h>\n#else\n\t#include <GL/gl.h>\n#endif\n\n#endif\n\n#ifndef GL_BGRA\n#define GL_BGRA 0x80E1\n#endif\n\n#ifndef GL_RG\n#define GL_RG 0x8227\n#endif\n\n#ifndef GL_UNSIGNED_SHORT_4_4_4_4\n#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033\n#endif\n#ifndef GL_UNSIGNED_SHORT_5_5_5_1\n#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034\n#endif\n#ifndef GL_UNSIGNED_SHORT_5_6_5\n#define GL_UNSIGNED_SHORT_5_6_5 0x8363\n#endif\n\n#ifndef GL_UNSIGNED_BYTE_3_3_2\n#define GL_UNSIGNED_BYTE_3_3_2 0x8032\n#endif\n\n#include \"SOIL2.h\"\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n#define STB_IMAGE_WRITE_IMPLEMENTATION\n#include \"stb_image_write.h\"\n#include \"image_helper.h\"\n#include \"image_DXT.h\"\n#include \"pvr_helper.h\"\n#include \"pkm_helper.h\"\n\n#include <stdlib.h>\n#include <string.h>\n\nunsigned long SOIL_version() { return SOIL_COMPILED_VERSION; }\n\n/*\terror reporting\t*/\nconst char *result_string_pointer = \"SOIL initialized\";\n\n/*\tfor loading cube maps\t*/\nenum{\n\tSOIL_CAPABILITY_UNKNOWN = -1,\n\tSOIL_CAPABILITY_NONE = 0,\n\tSOIL_CAPABILITY_PRESENT = 1\n};\nstatic int has_cubemap_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_cubemap_capability( void );\n#define SOIL_TEXTURE_WRAP_R\t\t\t\t\t0x8072\n#define SOIL_CLAMP_TO_EDGE\t\t\t\t\t0x812F\n#define SOIL_NORMAL_MAP\t\t\t\t\t\t0x8511\n#define SOIL_REFLECTION_MAP\t\t\t\t\t0x8512\n#define SOIL_TEXTURE_CUBE_MAP\t\t\t\t0x8513\n#define SOIL_TEXTURE_BINDING_CUBE_MAP\t\t0x8514\n#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_X\t0x8515\n#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X\t0x8516\n#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y\t0x8517\n#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y\t0x8518\n#define SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z\t0x8519\n#define SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z\t0x851A\n#define SOIL_PROXY_TEXTURE_CUBE_MAP\t\t\t0x851B\n#define SOIL_MAX_CUBE_MAP_TEXTURE_SIZE\t\t0x851C\n/*\tfor non-power-of-two texture\t*/\n#define SOIL_IS_POW2( v ) ( ( v & ( v - 1 ) ) == 0 )\nstatic int has_NPOT_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_NPOT_capability( void );\n/*\tfor texture rectangles\t*/\nstatic int has_tex_rectangle_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_tex_rectangle_capability( void );\n#define SOIL_TEXTURE_RECTANGLE_ARB\t\t\t\t0x84F5\n#define SOIL_MAX_RECTANGLE_TEXTURE_SIZE_ARB\t\t0x84F8\n/*\tfor using DXT compression\t*/\nstatic int has_DXT_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_DXT_capability( void );\nstatic int has_3Dc_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_3Dc_capability( void );\n#define SOIL_GL_SRGB\t\t\t0x8C40\n#define SOIL_GL_SRGB_ALPHA\t\t0x8C42\n#define SOIL_RGB_S3TC_DXT1\t\t0x83F0\n#define SOIL_RGBA_S3TC_DXT1\t\t0x83F1\n#define SOIL_RGBA_S3TC_DXT3\t\t0x83F2\n#define SOIL_RGBA_S3TC_DXT5\t\t0x83F3\n#define SOIL_COMPRESSED_RG_RGTC2\t0x8DBD\n#define SOIL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT  0x8C4C\n#define SOIL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT 0x8C4F\nstatic int has_sRGB_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_sRGB_capability( void );\ntypedef void (APIENTRY * P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid * data);\nstatic P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC soilGlCompressedTexImage2D = NULL;\n\ntypedef void (APIENTRY *P_SOIL_GLGENERATEMIPMAPPROC)(GLenum target);\nstatic P_SOIL_GLGENERATEMIPMAPPROC soilGlGenerateMipmap = NULL;\n\nstatic int has_gen_mipmap_capability = SOIL_CAPABILITY_UNKNOWN;\nstatic int query_gen_mipmap_capability( void );\n\nstatic int has_PVR_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_PVR_capability( void );\nstatic int has_BGRA8888_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_BGRA8888_capability( void );\nstatic int has_ETC1_capability = SOIL_CAPABILITY_UNKNOWN;\nint query_ETC1_capability( void );\n\n/* GL_IMG_texture_compression_pvrtc */\n#define SOIL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG                      0x8C00\n#define SOIL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG                      0x8C01\n#define SOIL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG                     0x8C02\n#define SOIL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG                     0x8C03\n#define SOIL_GL_ETC1_RGB8_OES                                     0x8D64\n\n#if defined( SOIL_X11_PLATFORM ) || defined( SOIL_PLATFORM_WIN32 ) || defined( SOIL_PLATFORM_OSX ) || defined(__HAIKU__)\ntypedef const GLubyte *(APIENTRY * P_SOIL_glGetStringiFunc) (GLenum, GLuint);\nstatic P_SOIL_glGetStringiFunc soilGlGetStringiFunc = NULL;\n\nstatic int isAtLeastGL3()\n{\n\tstatic int is_gl3 = SOIL_CAPABILITY_UNKNOWN;\n\n\tif ( SOIL_CAPABILITY_UNKNOWN == is_gl3 )\n\t{\n\t\tconst char * verstr\t= (const char *) glGetString( GL_VERSION );\n\t\tis_gl3\t\t\t\t= ( verstr && ( atoi(verstr) >= 3 ) &&\n\t\t\t\t\t\t\t\tstrstr( verstr, \" ES \" ) == NULL );\n\t}\n\n\treturn is_gl3;\n}\n#else\nstatic int isAtLeastGL3()\n{\n\treturn SOIL_CAPABILITY_NONE;\n}\n#endif\n\n#ifdef SOIL_PLATFORM_WIN32\nstatic HMODULE openglModule = NULL;\nstatic int soilTestWinProcPointer(const PROC pTest)\n{\n\tptrdiff_t iTest;\n\tif(!pTest) return 0;\n\tiTest = (ptrdiff_t)pTest;\n\tif(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0;\n\treturn 1;\n}\n#endif\n\n#if defined(__sgi) || defined (__sun) || defined(__HAIKU__)\n#include <dlfcn.h>\n\nvoid* dlGetProcAddress (const char* name)\n{\n  static void* h = NULL;\n  static void* gpa;\n\n  if (h == NULL)\n  {\n\tif ((h = dlopen(NULL, RTLD_LAZY | RTLD_LOCAL)) == NULL) return NULL;\n\tgpa = dlsym(h, \"glXGetProcAddress\");\n  }\n\n  if (gpa != NULL)\n\treturn ((void*(*)(const GLubyte*))gpa)((const GLubyte*)name);\n  else\n\treturn dlsym(h, (const char*)name);\n}\n#endif\n\nvoid * SOIL_GL_GetProcAddress(const char *proc)\n{\n\tvoid *func = NULL;\n\n#if defined( SOIL_PLATFORM_IOS )\n\tfunc = dlsym( RTLD_DEFAULT, proc );\n#elif defined( SOIL_GLES2 ) || defined( SOIL_GLES1 )\n\t#ifndef SOIL_NO_EGL\n\t\tfunc = eglGetProcAddress( proc );\n\t#else\n\t\tfunc = NULL;\n\t#endif\n#elif defined( SOIL_PLATFORM_WIN32 )\n\tif ( NULL == openglModule )\n\t\topenglModule = LoadLibraryA(\"opengl32.dll\");\n\n\tfunc = (void*)wglGetProcAddress(proc);\n\n\tif (!soilTestWinProcPointer((const PROC)func)) {\n\t\tfunc = (void *)GetProcAddress(openglModule, proc);\n\t}\n\n#elif defined( SOIL_PLATFORM_OSX )\n\t/*\tI can't test this Apple stuff!\t*/\n\tCFBundleRef bundle;\n\tCFURLRef bundleURL =\n\tCFURLCreateWithFileSystemPath(\n\t\t\t\t\t\t\t\t  kCFAllocatorDefault,\n\t\t\t\t\t\t\t\t  CFSTR(\"/System/Library/Frameworks/OpenGL.framework\"),\n\t\t\t\t\t\t\t\t  kCFURLPOSIXPathStyle,\n\t\t\t\t\t\t\t\t  true );\n\tCFStringRef extensionName =\n\tCFStringCreateWithCString(\n\t\t\t\t\t\t\t  kCFAllocatorDefault,\n\t\t\t\t\t\t\t  proc,\n\t\t\t\t\t\t\t  kCFStringEncodingASCII );\n\tbundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );\n\tassert( bundle != NULL );\n\n\tfunc = CFBundleGetFunctionPointerForName( bundle, extensionName );\n\n\tCFRelease( bundleURL );\n\tCFRelease( extensionName );\n\tCFRelease( bundle );\n#elif defined( SOIL_X11_PLATFORM )\n\tfunc =\n#if !defined(GLX_VERSION_1_4)\n\tglXGetProcAddressARB\n#else\n\tglXGetProcAddress\n#endif\n\t( (const GLubyte *)proc );\n#elif defined(__sgi) || defined (__sun) || defined(__HAIKU__)\n\tfunc = dlGetProcAddress(proc);\n#endif\n\n\treturn func;\n}\n\n/* Based on the SDL2 implementation */\nint SOIL_GL_ExtensionSupported(const char *extension)\n{\n\tconst char *extensions;\n\tconst char *start;\n\tconst char *where, *terminator;\n\n\t/* Extension names should not have spaces. */\n\twhere = strchr(extension, ' ');\n\n\tif (where || *extension == '\\0')\n\t{\n\t\treturn 0;\n\t}\n\n\t#if defined( SOIL_X11_PLATFORM ) || defined( SOIL_PLATFORM_WIN32 ) || defined( SOIL_PLATFORM_OSX ) || defined(__HAIKU__)\n\t/* Lookup the available extensions */\n\tif ( isAtLeastGL3() )\n\t{\n\t\tGLint num_exts = 0;\n\t\tGLint i;\n\n\t\tif ( NULL == soilGlGetStringiFunc )\n\t\t{\n\t\t\tsoilGlGetStringiFunc = (P_SOIL_glGetStringiFunc)SOIL_GL_GetProcAddress(\"glGetStringi\");\n\n\t\t\tif ( NULL == soilGlGetStringiFunc )\n\t\t\t{\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\t#ifndef GL_NUM_EXTENSIONS\n\t\t#define GL_NUM_EXTENSIONS 0x821D\n\t\t#endif\n\t\tglGetIntegerv(GL_NUM_EXTENSIONS, &num_exts);\n\t\tfor (i = 0; i < num_exts; i++)\n\t\t{\n\t\t\tconst char *thisext = (const char *) soilGlGetStringiFunc(GL_EXTENSIONS, i);\n\n\t\t\tif (strcmp(thisext, extension) == 0)\n\t\t\t{\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t}\n\n\t\treturn 0;\n\t}\n\t#endif\n\n\t/* Try the old way with glGetString(GL_EXTENSIONS) ... */\n\textensions = (const char *) glGetString(GL_EXTENSIONS);\n\n\tif (!extensions)\n\t{\n\t\treturn 0;\n\t}\n\n\t/*\n\t * It takes a bit of care to be fool-proof about parsing the OpenGL\n\t * extensions string. Don't be fooled by sub-strings, etc.\n\t */\n\tstart = extensions;\n\n\tfor (;;) {\n\t\twhere = strstr(start, extension);\n\n\t\tif (!where)\n\t\t\tbreak;\n\n\t\tterminator = where + strlen(extension);\n\n\t\tif (where == start || *(where - 1) == ' ')\n\t\t\tif (*terminator == ' ' || *terminator == '\\0')\n\t\t\t\treturn 1;\n\n\t\tstart = terminator;\n\t}\n\n\treturn 0;\n}\n\n/*\tother functions\t*/\nunsigned int\n\tSOIL_internal_create_OGL_texture\n\t(\n\t\tconst unsigned char *const data,\n\t\tint *width, int *height, int channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags,\n\t\tunsigned int opengl_texture_type,\n\t\tunsigned int opengl_texture_target,\n\t\tunsigned int texture_check_size_enum\n\t);\n\n/*\tand the code magic begins here [8^)\t*/\nunsigned int\n\tSOIL_load_OGL_texture\n\t(\n\t\tconst char *filename,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img;\n\tint width, height, channels;\n\tunsigned int tex_id;\n\t/*\tdoes the user want direct uploading of the image as a DDS file?\t*/\n\tif( flags & SOIL_FLAG_DDS_LOAD_DIRECT )\n\t{\n\t\t/*\t1st try direct loading of the image as a DDS file\n\t\t\tnote: direct uploading will only load what is in the\n\t\t\tDDS file, no MIPmaps will be generated, the image will\n\t\t\tnot be flipped, etc.\t*/\n\t\ttex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 0 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif( flags & SOIL_FLAG_PVR_LOAD_DIRECT )\n\t{\n\t\ttex_id = SOIL_direct_load_PVR( filename, reuse_texture_ID, flags, 0 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif( flags & SOIL_FLAG_ETC1_LOAD_DIRECT )\n\t{\n\t\ttex_id = SOIL_direct_load_ETC1( filename, reuse_texture_ID, flags );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\t/*\ttry to load the image\t*/\n\timg = SOIL_load_image( filename, &width, &height, &channels, force_channels );\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t{\n\t\tchannels = force_channels;\n\t}\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/*\tOK, make it a texture!\t*/\n\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\timg, &width, &height, channels,\n\t\t\treuse_texture_ID, flags,\n\t\t\tGL_TEXTURE_2D, GL_TEXTURE_2D,\n\t\t\tGL_MAX_TEXTURE_SIZE );\n\t/*\tand nuke the image data\t*/\n\tSOIL_free_image_data( img );\n\t/*\tand return the handle, such as it is\t*/\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_load_OGL_HDR_texture\n\t(\n\t\tconst char *filename,\n\t\tint fake_HDR_format,\n\t\tint rescale_to_max,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img = NULL;\n\tint width, height, channels;\n\tunsigned int tex_id;\n\t/*\tno direct uploading of the image as a DDS file\t*/\n\t/* error check */\n\tif( (fake_HDR_format != SOIL_HDR_RGBE) &&\n\t\t(fake_HDR_format != SOIL_HDR_RGBdivA) &&\n\t\t(fake_HDR_format != SOIL_HDR_RGBdivA2) )\n\t{\n\t\tresult_string_pointer = \"Invalid fake HDR format specified\";\n\t\treturn 0;\n\t}\n\n\t/* check if the image is HDR */\n\tif ( stbi_is_hdr( filename ) )\n\t{\n\t\t/*\ttry to load the image (only the HDR type) */\n\t\timg = stbi_load( filename, &width, &height, &channels, 4 );\n\t}\n\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/* the load worked, do I need to convert it? */\n\tif( fake_HDR_format == SOIL_HDR_RGBdivA )\n\t{\n\t\tRGBE_to_RGBdivA( img, width, height, rescale_to_max );\n\t} else if( fake_HDR_format == SOIL_HDR_RGBdivA2 )\n\t{\n\t\tRGBE_to_RGBdivA2( img, width, height, rescale_to_max );\n\t}\n\t/*\tOK, make it a texture!\t*/\n\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\timg, &width, &height, channels,\n\t\t\treuse_texture_ID, flags,\n\t\t\tGL_TEXTURE_2D, GL_TEXTURE_2D,\n\t\t\tGL_MAX_TEXTURE_SIZE );\n\t/*\tand nuke the image data\t*/\n\tSOIL_free_image_data( img );\n\t/*\tand return the handle, such as it is\t*/\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_load_OGL_texture_from_memory\n\t(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img;\n\tint width, height, channels;\n\tunsigned int tex_id;\n\t/*\tdoes the user want direct uploading of the image as a DDS file?\t*/\n\tif( flags & SOIL_FLAG_DDS_LOAD_DIRECT )\n\t{\n\t\t/*\t1st try direct loading of the image as a DDS file\n\t\t\tnote: direct uploading will only load what is in the\n\t\t\tDDS file, no MIPmaps will be generated, the image will\n\t\t\tnot be flipped, etc.\t*/\n\t\ttex_id = SOIL_direct_load_DDS_from_memory(\n\t\t\t\tbuffer, buffer_length,\n\t\t\t\treuse_texture_ID, flags, 0 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif( flags & SOIL_FLAG_PVR_LOAD_DIRECT )\n\t{\n\t\ttex_id = SOIL_direct_load_PVR_from_memory(\n\t\t\t\tbuffer, buffer_length,\n\t\t\t\treuse_texture_ID, flags, 0 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif( flags & SOIL_FLAG_ETC1_LOAD_DIRECT )\n\t{\n\t\ttex_id = SOIL_direct_load_ETC1_from_memory(\n\t\t\t\tbuffer, buffer_length,\n\t\t\t\treuse_texture_ID, flags );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\t/*\ttry to load the image\t*/\n\timg = SOIL_load_image_from_memory(\n\t\t\t\t\tbuffer, buffer_length,\n\t\t\t\t\t&width, &height, &channels,\n\t\t\t\t\tforce_channels );\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t{\n\t\tchannels = force_channels;\n\t}\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/*\tOK, make it a texture!\t*/\n\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\timg, &width, &height, channels,\n\t\t\treuse_texture_ID, flags,\n\t\t\tGL_TEXTURE_2D, GL_TEXTURE_2D,\n\t\t\tGL_MAX_TEXTURE_SIZE );\n\t/*\tand nuke the image data\t*/\n\tSOIL_free_image_data( img );\n\t/*\tand return the handle, such as it is\t*/\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_load_OGL_cubemap\n\t(\n\t\tconst char *x_pos_file,\n\t\tconst char *x_neg_file,\n\t\tconst char *y_pos_file,\n\t\tconst char *y_neg_file,\n\t\tconst char *z_pos_file,\n\t\tconst char *z_neg_file,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img;\n\tint width, height, channels;\n\tunsigned int tex_id;\n\t/*\terror checking\t*/\n\tif( (x_pos_file == NULL) ||\n\t\t(x_neg_file == NULL) ||\n\t\t(y_pos_file == NULL) ||\n\t\t(y_neg_file == NULL) ||\n\t\t(z_pos_file == NULL) ||\n\t\t(z_neg_file == NULL) )\n\t{\n\t\tresult_string_pointer = \"Invalid cube map files list\";\n\t\treturn 0;\n\t}\n\t/*\tcapability checking\t*/\n\tif( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )\n\t{\n\t\tresult_string_pointer = \"No cube map capability present\";\n\t\treturn 0;\n\t}\n\t/*\t1st face: try to load the image\t*/\n\timg = SOIL_load_image( x_pos_file, &width, &height, &channels, force_channels );\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t{\n\t\tchannels = force_channels;\n\t}\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/*\tupload the texture, and create a texture ID if necessary\t*/\n\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\timg, &width, &height, channels,\n\t\t\treuse_texture_ID, flags,\n\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X,\n\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t/*\tand nuke the image data\t*/\n\tSOIL_free_image_data( img );\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image( x_neg_file, &width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image( y_pos_file, &width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image( y_neg_file, &width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image( z_pos_file, &width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image( z_neg_file, &width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tand return the handle, such as it is\t*/\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_load_OGL_cubemap_from_memory\n\t(\n\t\tconst unsigned char *const x_pos_buffer,\n\t\tint x_pos_buffer_length,\n\t\tconst unsigned char *const x_neg_buffer,\n\t\tint x_neg_buffer_length,\n\t\tconst unsigned char *const y_pos_buffer,\n\t\tint y_pos_buffer_length,\n\t\tconst unsigned char *const y_neg_buffer,\n\t\tint y_neg_buffer_length,\n\t\tconst unsigned char *const z_pos_buffer,\n\t\tint z_pos_buffer_length,\n\t\tconst unsigned char *const z_neg_buffer,\n\t\tint z_neg_buffer_length,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img;\n\tint width, height, channels;\n\tunsigned int tex_id;\n\t/*\terror checking\t*/\n\tif( (x_pos_buffer == NULL) ||\n\t\t(x_neg_buffer == NULL) ||\n\t\t(y_pos_buffer == NULL) ||\n\t\t(y_neg_buffer == NULL) ||\n\t\t(z_pos_buffer == NULL) ||\n\t\t(z_neg_buffer == NULL) )\n\t{\n\t\tresult_string_pointer = \"Invalid cube map buffers list\";\n\t\treturn 0;\n\t}\n\t/*\tcapability checking\t*/\n\tif( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )\n\t{\n\t\tresult_string_pointer = \"No cube map capability present\";\n\t\treturn 0;\n\t}\n\t/*\t1st face: try to load the image\t*/\n\timg = SOIL_load_image_from_memory(\n\t\t\tx_pos_buffer, x_pos_buffer_length,\n\t\t\t&width, &height, &channels, force_channels );\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t{\n\t\tchannels = force_channels;\n\t}\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/*\tupload the texture, and create a texture ID if necessary\t*/\n\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\timg, &width, &height, channels,\n\t\t\treuse_texture_ID, flags,\n\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_X,\n\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t/*\tand nuke the image data\t*/\n\tSOIL_free_image_data( img );\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image_from_memory(\n\t\t\t\tx_neg_buffer, x_neg_buffer_length,\n\t\t\t\t&width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image_from_memory(\n\t\t\t\ty_pos_buffer, y_pos_buffer_length,\n\t\t\t\t&width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image_from_memory(\n\t\t\t\ty_neg_buffer, y_neg_buffer_length,\n\t\t\t\t&width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image_from_memory(\n\t\t\t\tz_pos_buffer, z_pos_buffer_length,\n\t\t\t\t&width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tcontinue?\t*/\n\tif( tex_id != 0 )\n\t{\n\t\t/*\t1st face: try to load the image\t*/\n\t\timg = SOIL_load_image_from_memory(\n\t\t\t\tz_neg_buffer, z_neg_buffer_length,\n\t\t\t\t&width, &height, &channels, force_channels );\n\t\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\t\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t\t{\n\t\t\tchannels = force_channels;\n\t\t}\n\t\tif( NULL == img )\n\t\t{\n\t\t\t/*\timage loading failed\t*/\n\t\t\tresult_string_pointer = stbi_failure_reason();\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tupload the texture, but reuse the assigned texture ID\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\timg, &width, &height, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP, SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t\t/*\tand nuke the image data\t*/\n\t\tSOIL_free_image_data( img );\n\t}\n\t/*\tand return the handle, such as it is\t*/\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_load_OGL_single_cubemap\n\t(\n\t\tconst char *filename,\n\t\tconst char face_order[6],\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img;\n\tint width, height, channels, i;\n\tunsigned int tex_id = 0;\n\t/*\terror checking\t*/\n\tif( filename == NULL )\n\t{\n\t\tresult_string_pointer = \"Invalid single cube map file name\";\n\t\treturn 0;\n\t}\n\t/*\tdoes the user want direct uploading of the image as a DDS file?\t*/\n\tif( flags & SOIL_FLAG_DDS_LOAD_DIRECT )\n\t{\n\t\t/*\t1st try direct loading of the image as a DDS file\n\t\t\tnote: direct uploading will only load what is in the\n\t\t\tDDS file, no MIPmaps will be generated, the image will\n\t\t\tnot be flipped, etc.\t*/\n\t\ttex_id = SOIL_direct_load_DDS( filename, reuse_texture_ID, flags, 1 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif ( flags & SOIL_FLAG_PVR_LOAD_DIRECT )\n\t{\n\t\ttex_id = SOIL_direct_load_PVR( filename, reuse_texture_ID, flags, 1 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif ( flags & SOIL_FLAG_ETC1_LOAD_DIRECT )\n\t{\n\t\treturn 0;\n\t}\n\n\t/*\tface order checking\t*/\n\tfor( i = 0; i < 6; ++i )\n\t{\n\t\tif( (face_order[i] != 'N') &&\n\t\t\t(face_order[i] != 'S') &&\n\t\t\t(face_order[i] != 'W') &&\n\t\t\t(face_order[i] != 'E') &&\n\t\t\t(face_order[i] != 'U') &&\n\t\t\t(face_order[i] != 'D') )\n\t\t{\n\t\t\tresult_string_pointer = \"Invalid single cube map face order\";\n\t\t\treturn 0;\n\t\t};\n\t}\n\t/*\tcapability checking\t*/\n\tif( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )\n\t{\n\t\tresult_string_pointer = \"No cube map capability present\";\n\t\treturn 0;\n\t}\n\t/*\t1st off, try to load the full image\t*/\n\timg = SOIL_load_image( filename, &width, &height, &channels, force_channels );\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t{\n\t\tchannels = force_channels;\n\t}\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/*\tnow, does this image have the right dimensions?\t*/\n\tif( (width != 6*height) &&\n\t\t(6*width != height) )\n\t{\n\t\tSOIL_free_image_data( img );\n\t\tresult_string_pointer = \"Single cubemap image must have a 6:1 ratio\";\n\t\treturn 0;\n\t}\n\t/*\ttry the image split and create\t*/\n\ttex_id = SOIL_create_OGL_single_cubemap(\n\t\t\timg, width, height, channels,\n\t\t\tface_order, reuse_texture_ID, flags\n\t\t\t);\n\t/*\tnuke the temporary image data and return the texture handle\t*/\n\tSOIL_free_image_data( img );\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_load_OGL_single_cubemap_from_memory\n\t(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tconst char face_order[6],\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img;\n\tint width, height, channels, i;\n\tunsigned int tex_id = 0;\n\t/*\terror checking\t*/\n\tif( buffer == NULL )\n\t{\n\t\tresult_string_pointer = \"Invalid single cube map buffer\";\n\t\treturn 0;\n\t}\n\t/*\tdoes the user want direct uploading of the image as a DDS file?\t*/\n\tif( flags & SOIL_FLAG_DDS_LOAD_DIRECT )\n\t{\n\t\t/*\t1st try direct loading of the image as a DDS file\n\t\t\tnote: direct uploading will only load what is in the\n\t\t\tDDS file, no MIPmaps will be generated, the image will\n\t\t\tnot be flipped, etc.\t*/\n\t\ttex_id = SOIL_direct_load_DDS_from_memory(\n\t\t\t\tbuffer, buffer_length,\n\t\t\t\treuse_texture_ID, flags, 1 );\n\t\tif( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif ( flags & SOIL_FLAG_PVR_LOAD_DIRECT )\n\t{\n\t\ttex_id = SOIL_direct_load_PVR_from_memory(\n\t\t\t\tbuffer, buffer_length,\n\t\t\t\treuse_texture_ID, flags, 1 );\n\t\tif ( tex_id )\n\t\t{\n\t\t\t/*\they, it worked!!\t*/\n\t\t\treturn tex_id;\n\t\t}\n\t}\n\n\tif ( flags & SOIL_FLAG_ETC1_LOAD_DIRECT )\n\t{\n\t\treturn 0;\n\t}\n\n\t/*\tface order checking\t*/\n\tfor( i = 0; i < 6; ++i )\n\t{\n\t\tif( (face_order[i] != 'N') &&\n\t\t\t(face_order[i] != 'S') &&\n\t\t\t(face_order[i] != 'W') &&\n\t\t\t(face_order[i] != 'E') &&\n\t\t\t(face_order[i] != 'U') &&\n\t\t\t(face_order[i] != 'D') )\n\t\t{\n\t\t\tresult_string_pointer = \"Invalid single cube map face order\";\n\t\t\treturn 0;\n\t\t};\n\t}\n\t/*\tcapability checking\t*/\n\tif( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )\n\t{\n\t\tresult_string_pointer = \"No cube map capability present\";\n\t\treturn 0;\n\t}\n\t/*\t1st off, try to load the full image\t*/\n\timg = SOIL_load_image_from_memory(\n\t\t\tbuffer, buffer_length,\n\t\t\t&width, &height, &channels,\n\t\t\tforce_channels );\n\t/*\tchannels holds the original number of channels, which may have been forced\t*/\n\tif( (force_channels >= 1) && (force_channels <= 4) )\n\t{\n\t\tchannels = force_channels;\n\t}\n\tif( NULL == img )\n\t{\n\t\t/*\timage loading failed\t*/\n\t\tresult_string_pointer = stbi_failure_reason();\n\t\treturn 0;\n\t}\n\t/*\tnow, does this image have the right dimensions?\t*/\n\tif( (width != 6*height) &&\n\t\t(6*width != height) )\n\t{\n\t\tSOIL_free_image_data( img );\n\t\tresult_string_pointer = \"Single cubemap image must have a 6:1 ratio\";\n\t\treturn 0;\n\t}\n\t/*\ttry the image split and create\t*/\n\ttex_id = SOIL_create_OGL_single_cubemap(\n\t\t\timg, width, height, channels,\n\t\t\tface_order, reuse_texture_ID, flags\n\t\t\t);\n\t/*\tnuke the temporary image data and return the texture handle\t*/\n\tSOIL_free_image_data( img );\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_create_OGL_single_cubemap\n\t(\n\t\tconst unsigned char *const data,\n\t\tint width, int height, int channels,\n\t\tconst char face_order[6],\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* sub_img;\n\tint dw, dh, sz, i;\n\tunsigned int tex_id;\n\t/*\terror checking\t*/\n\tif( data == NULL )\n\t{\n\t\tresult_string_pointer = \"Invalid single cube map image data\";\n\t\treturn 0;\n\t}\n\t/*\tface order checking\t*/\n\tfor( i = 0; i < 6; ++i )\n\t{\n\t\tif( (face_order[i] != 'N') &&\n\t\t\t(face_order[i] != 'S') &&\n\t\t\t(face_order[i] != 'W') &&\n\t\t\t(face_order[i] != 'E') &&\n\t\t\t(face_order[i] != 'U') &&\n\t\t\t(face_order[i] != 'D') )\n\t\t{\n\t\t\tresult_string_pointer = \"Invalid single cube map face order\";\n\t\t\treturn 0;\n\t\t};\n\t}\n\t/*\tcapability checking\t*/\n\tif( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )\n\t{\n\t\tresult_string_pointer = \"No cube map capability present\";\n\t\treturn 0;\n\t}\n\t/*\tnow, does this image have the right dimensions?\t*/\n\tif( (width != 6*height) &&\n\t\t(6*width != height) )\n\t{\n\t\tresult_string_pointer = \"Single cubemap image must have a 6:1 ratio\";\n\t\treturn 0;\n\t}\n\t/*\twhich way am I stepping?\t*/\n\tif( width > height )\n\t{\n\t\tdw = height;\n\t\tdh = 0;\n\t} else\n\t{\n\t\tdw = 0;\n\t\tdh = width;\n\t}\n\tsz = dw+dh;\n\tsub_img = (unsigned char *)malloc( sz*sz*channels );\n\t/*\tdo the splitting and uploading\t*/\n\ttex_id = reuse_texture_ID;\n\tfor( i = 0; i < 6; ++i )\n\t{\n\t\tint x, y, idx = 0;\n\t\tunsigned int cubemap_target = 0;\n\t\t/*\tcopy in the sub-image\t*/\n\t\tfor( y = i*dh; y < i*dh+sz; ++y )\n\t\t{\n\t\t\tfor( x = i*dw*channels; x < (i*dw+sz)*channels; ++x )\n\t\t\t{\n\t\t\t\tsub_img[idx++] = data[y*width*channels+x];\n\t\t\t}\n\t\t}\n\t\t/*\twhat is my texture target?\n\t\t\tremember, this coordinate system is\n\t\t\tLHS if viewed from inside the cube!\t*/\n\t\tswitch( face_order[i] )\n\t\t{\n\t\tcase 'N':\n\t\t\tcubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Z;\n\t\t\tbreak;\n\t\tcase 'S':\n\t\t\tcubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;\n\t\t\tbreak;\n\t\tcase 'W':\n\t\t\tcubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_X;\n\t\t\tbreak;\n\t\tcase 'E':\n\t\t\tcubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;\n\t\t\tbreak;\n\t\tcase 'U':\n\t\t\tcubemap_target = SOIL_TEXTURE_CUBE_MAP_POSITIVE_Y;\n\t\t\tbreak;\n\t\tcase 'D':\n\t\t\tcubemap_target = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Y;\n\t\t\tbreak;\n\t\t}\n\t\t/*\tupload it as a texture\t*/\n\t\ttex_id = SOIL_internal_create_OGL_texture(\n\t\t\t\tsub_img, &sz, &sz, channels,\n\t\t\t\ttex_id, flags,\n\t\t\t\tSOIL_TEXTURE_CUBE_MAP,\n\t\t\t\tcubemap_target,\n\t\t\t\tSOIL_MAX_CUBE_MAP_TEXTURE_SIZE );\n\t}\n\t/*\tand nuke the image and sub-image data\t*/\n\tSOIL_free_image_data( sub_img );\n\t/*\tand return the handle, such as it is\t*/\n\treturn tex_id;\n}\n\nunsigned int\n\tSOIL_create_OGL_texture\n\t(\n\t\tconst unsigned char *const data,\n\t\tint *width, int *height, int channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t)\n{\n\t/*\twrapper function for 2D textures\t*/\n\treturn SOIL_internal_create_OGL_texture(\n\t\t\t\tdata, width, height, channels,\n\t\t\t\treuse_texture_ID, flags,\n\t\t\t\tGL_TEXTURE_2D, GL_TEXTURE_2D,\n\t\t\t\tGL_MAX_TEXTURE_SIZE );\n}\n\n#if SOIL_CHECK_FOR_GL_ERRORS\nvoid check_for_GL_errors( const char *calling_location )\n{\n\t/*\tcheck for errors\t*/\n\tGLenum err_code = glGetError();\n\twhile( GL_NO_ERROR != err_code )\n\t{\n\t\tprintf( \"OpenGL Error @ %s: %i\", calling_location, err_code );\n\t\terr_code = glGetError();\n\t}\n}\n#else\nvoid check_for_GL_errors( const char *calling_location )\n{\n\t/*\tno check for errors\t*/\n}\n#endif\n\nstatic void createMipmaps(const unsigned char *const img,\n\t\tint width, int height, int channels,\n\t\tunsigned int flags,\n\t\tunsigned int opengl_texture_target,\n\t\tunsigned int internal_texture_format,\n\t\tunsigned int original_texture_format,\n\t\tint DXT_mode)\n{\n\tif ( ( flags & SOIL_FLAG_GL_MIPMAPS ) && query_gen_mipmap_capability() == SOIL_CAPABILITY_PRESENT )\n\t{\n\t\tsoilGlGenerateMipmap(opengl_texture_target);\n\t}\n\telse\n\t{\n\t\tint MIPlevel = 1;\n\t\tint MIPwidth = (width+1) / 2;\n\t\tint MIPheight = (height+1) / 2;\n\t\tunsigned char *resampled = (unsigned char*)malloc( channels*MIPwidth*MIPheight );\n\n\t\twhile( ((1<<MIPlevel) <= width) || ((1<<MIPlevel) <= height) )\n\t\t{\n\t\t\t/*\tdo this MIPmap level\t*/\n\t\t\tmipmap_image(\n\t\t\t\t\timg, width, height, channels,\n\t\t\t\t\tresampled,\n\t\t\t\t\t(1 << MIPlevel), (1 << MIPlevel) );\n\n\t\t\t/*  upload the MIPmaps\t*/\n\t\t\tif( DXT_mode == SOIL_CAPABILITY_PRESENT )\n\t\t\t{\n\t\t\t\t/*\tuser wants me to do the DXT conversion!\t*/\n\t\t\t\tint DDS_size;\n\t\t\t\tunsigned char *DDS_data = NULL;\n\t\t\t\tif( (channels & 1) == 1 )\n\t\t\t\t{\n\t\t\t\t\t/*\tRGB, use DXT1\t*/\n\t\t\t\t\tDDS_data = convert_image_to_DXT1(\n\t\t\t\t\t\t\tresampled, MIPwidth, MIPheight, channels, &DDS_size );\n\t\t\t\t} else\n\t\t\t\t{\n\t\t\t\t\t/*\tRGBA, use DXT5\t*/\n\t\t\t\t\tDDS_data = convert_image_to_DXT5(\n\t\t\t\t\t\t\tresampled, MIPwidth, MIPheight, channels, &DDS_size );\n\t\t\t\t}\n\t\t\t\tif( DDS_data )\n\t\t\t\t{\n\t\t\t\t\tsoilGlCompressedTexImage2D(\n\t\t\t\t\t\topengl_texture_target, MIPlevel,\n\t\t\t\t\t\tinternal_texture_format, MIPwidth, MIPheight, 0,\n\t\t\t\t\t\tDDS_size, DDS_data );\n\t\t\t\t\tcheck_for_GL_errors( \"glCompressedTexImage2D\" );\n\t\t\t\t\tSOIL_free_image_data( DDS_data );\n\t\t\t\t} else\n\t\t\t\t{\n\t\t\t\t\t/*\tmy compression failed, try the OpenGL driver's version\t*/\n\t\t\t\t\tglTexImage2D(\n\t\t\t\t\t\topengl_texture_target, MIPlevel,\n\t\t\t\t\t\tinternal_texture_format, MIPwidth, MIPheight, 0,\n\t\t\t\t\t\toriginal_texture_format, GL_UNSIGNED_BYTE, resampled );\n\t\t\t\t\tcheck_for_GL_errors( \"glTexImage2D\" );\n\t\t\t\t}\n\t\t\t} else\n\t\t\t{\n\t\t\t\t/*\tuser want OpenGL to do all the work!\t*/\n\t\t\t\tglTexImage2D(\n\t\t\t\t\topengl_texture_target, MIPlevel,\n\t\t\t\t\tinternal_texture_format, MIPwidth, MIPheight, 0,\n\t\t\t\t\toriginal_texture_format, GL_UNSIGNED_BYTE, resampled );\n\t\t\t\tcheck_for_GL_errors( \"glTexImage2D\" );\n\t\t\t}\n\t\t\t/*\tprep for the next level\t*/\n\t\t\t++MIPlevel;\n\t\t\tMIPwidth = (MIPwidth + 1) / 2;\n\t\t\tMIPheight = (MIPheight + 1) / 2;\n\t\t}\n\n\t\tSOIL_free_image_data( resampled );\n\t}\n}\n\nunsigned int\n\tSOIL_internal_create_OGL_texture\n\t(\n\t\tconst unsigned char *const data,\n\t\tint *width, int *height, int channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags,\n\t\tunsigned int opengl_texture_type,\n\t\tunsigned int opengl_texture_target,\n\t\tunsigned int texture_check_size_enum\n\t)\n{\n\t/*\tvariables\t*/\n\tunsigned char* img = NULL;\n\tunsigned int tex_id;\n\tunsigned int internal_texture_format = 0, original_texture_format = 0;\n\tint DXT_mode = SOIL_CAPABILITY_UNKNOWN;\n\tint sRGB_texture = query_sRGB_capability() == SOIL_CAPABILITY_PRESENT && ( flags & SOIL_FLAG_SRGB_COLOR_SPACE );;\n\tint max_supported_size;\n\tint iwidth = *width;\n\tint iheight = *height;\n\tint needCopy;\n\tGLint unpack_aligment;\n\n\t/*\thow large of a texture can this OpenGL implementation handle?\t*/\n\t/*\ttexture_check_size_enum will be GL_MAX_TEXTURE_SIZE or SOIL_MAX_CUBE_MAP_TEXTURE_SIZE\t*/\n\tglGetIntegerv( texture_check_size_enum, &max_supported_size );\n\n\t/*\tIf the user wants to use the texture rectangle I kill a few flags\t*/\n\tif( flags & SOIL_FLAG_TEXTURE_RECTANGLE )\n\t{\n\t\t/*\twell, the user asked for it, can we do that?\t*/\n\t\tif( query_tex_rectangle_capability() == SOIL_CAPABILITY_PRESENT )\n\t\t{\n\t\t\t/*\tonly allow this if the user in _NOT_ trying to do a cubemap!\t*/\n\t\t\tif( opengl_texture_type == GL_TEXTURE_2D )\n\t\t\t{\n\t\t\t\t/*\tclean out the flags that cannot be used with texture rectangles\t*/\n\t\t\t\tflags &= ~(\n\t\t\t\t\t\tSOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS |\n\t\t\t\t\t\tSOIL_FLAG_TEXTURE_REPEATS\n\t\t\t\t\t);\n\t\t\t\t/*\tand change my target\t*/\n\t\t\t\topengl_texture_target = SOIL_TEXTURE_RECTANGLE_ARB;\n\t\t\t\topengl_texture_type = SOIL_TEXTURE_RECTANGLE_ARB;\n\t\t\t} else\n\t\t\t{\n\t\t\t\t/*\tnot allowed for any other uses (yes, I'm looking at you, cubemaps!)\t*/\n\t\t\t\tflags &= ~SOIL_FLAG_TEXTURE_RECTANGLE;\n\t\t\t}\n\n\t\t} else\n\t\t{\n\t\t\t/*\tcan't do it, and that is a breakable offense (uv coords use pixels instead of [0,1]!)\t*/\n\t\t\tresult_string_pointer = \"Texture Rectangle extension unsupported\";\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t/*\tif the user can't support NPOT textures, make sure we force the POT option\t*/\n\tif( (query_NPOT_capability() == SOIL_CAPABILITY_NONE) &&\n\t\t!(flags & SOIL_FLAG_TEXTURE_RECTANGLE) )\n\t{\n\t\t/*\tadd in the POT flag */\n\t\tflags |= SOIL_FLAG_POWER_OF_TWO;\n\t}\n\n\tneedCopy = ( ( flags & SOIL_FLAG_INVERT_Y ) ||\n\t\t\t\t ( flags & SOIL_FLAG_NTSC_SAFE_RGB ) ||\n\t\t\t\t ( flags & SOIL_FLAG_MULTIPLY_ALPHA ) ||\n\t\t\t\t ( flags & SOIL_FLAG_CoCg_Y )\n\t\t\t\t);\n\n\t/*\tcreate a copy the image data only if needed */\n\tif ( needCopy ) {\n\t\timg = (unsigned char*)malloc( iwidth*iheight*channels );\n\t\tmemcpy( img, data, iwidth*iheight*channels );\n\t}\n\n\t/*\tdoes the user want me to invert the image?\t*/\n\tif( flags & SOIL_FLAG_INVERT_Y )\n\t{\n\t\tint i, j;\n\t\tfor( j = 0; j*2 < iheight; ++j )\n\t\t{\n\t\t\tint index1 = j * iwidth * channels;\n\t\t\tint index2 = (iheight - 1 - j) * iwidth * channels;\n\t\t\tfor( i = iwidth * channels; i > 0; --i )\n\t\t\t{\n\t\t\t\tunsigned char temp = img[index1];\n\t\t\t\timg[index1] = img[index2];\n\t\t\t\timg[index2] = temp;\n\t\t\t\t++index1;\n\t\t\t\t++index2;\n\t\t\t}\n\t\t}\n\t}\n\t/*\tdoes the user want me to scale the colors into the NTSC safe RGB range?\t*/\n\tif( flags & SOIL_FLAG_NTSC_SAFE_RGB )\n\t{\n\t\tscale_image_RGB_to_NTSC_safe( img, iwidth, iheight, channels );\n\t}\n\t/*\tdoes the user want me to convert from straight to pre-multiplied alpha?\n\t\t(and do we even _have_ alpha?)\t*/\n\tif( flags & SOIL_FLAG_MULTIPLY_ALPHA )\n\t{\n\t\tint i;\n\t\tswitch( channels )\n\t\t{\n\t\tcase 2:\n\t\t\tfor( i = 0; i < 2*iwidth*iheight; i += 2 )\n\t\t\t{\n\t\t\t\timg[i] = (img[i] * img[i+1] + 128) >> 8;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\tfor( i = 0; i < 4*iwidth*iheight; i += 4 )\n\t\t\t{\n\t\t\t\timg[i+0] = (img[i+0] * img[i+3] + 128) >> 8;\n\t\t\t\timg[i+1] = (img[i+1] * img[i+3] + 128) >> 8;\n\t\t\t\timg[i+2] = (img[i+2] * img[i+3] + 128) >> 8;\n\t\t\t}\n\t\t\tbreak;\n\t\tdefault:\n\t\t\t/*\tno other number of channels contains alpha data\t*/\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t/*\tdo I need to make it a power of 2?\t*/\n\tif(\n\t\t( ( flags & SOIL_FLAG_POWER_OF_TWO) && ( !SOIL_IS_POW2(iwidth) || !SOIL_IS_POW2(iheight) ) ) ||\t/*\tuser asked for it and the texture is not power of 2\t*/\n\t\t( (flags & SOIL_FLAG_MIPMAPS)&& !( ( flags & SOIL_FLAG_GL_MIPMAPS ) &&\n\t\t\t\t\t\t\t\t\t\t   query_gen_mipmap_capability() == SOIL_CAPABILITY_PRESENT &&\n\t\t\t\t\t\t\t\t\t\t   query_NPOT_capability() == SOIL_CAPABILITY_PRESENT ) ) ||\t/*\tneed it for the MIP-maps when mipmaps required\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tand not GL mipmaps required and supported\t*/\n\t\t(iwidth > max_supported_size) ||\t\t/*\tit's too big, (make sure it's\t*/\n\t\t(iheight > max_supported_size) )\t\t/*\t2^n for later down-sampling)\t*/\n\t{\n\t\tint new_width = 1;\n\t\tint new_height = 1;\n\t\twhile( new_width < iwidth )\n\t\t{\n\t\t\tnew_width *= 2;\n\t\t}\n\t\twhile( new_height < iheight )\n\t\t{\n\t\t\tnew_height *= 2;\n\t\t}\n\t\t/*\tstill?\t*/\n\t\tif( (new_width != iwidth) || (new_height != iheight) )\n\t\t{\n\t\t\t/*\tyep, resize\t*/\n\t\t\tunsigned char *resampled = (unsigned char*)malloc( channels*new_width*new_height );\n\t\t\tup_scale_image(\n\t\t\t\t\tNULL != img ? img : data, iwidth, iheight, channels,\n\t\t\t\t\tresampled, new_width, new_height );\n\n\t\t\t/*\tnuke the old guy ( if a copy exists ), then point it at the new guy\t*/\n\t\t\tSOIL_free_image_data( img );\n\t\t\timg = resampled;\n\t\t\t*width = new_width;\n\t\t\t*height = new_height;\n\t\t\tiwidth = new_width;\n\t\t\tiheight = new_height;\n\t\t}\n\t}\n\t/*\tnow, if it is too large...\t*/\n\tif( (iwidth > max_supported_size) || (iheight > max_supported_size) )\n\t{\n\t\t/*\tI've already made it a power of two, so simply use the MIPmapping\n\t\t\tcode to reduce its size to the allowable maximum.\t*/\n\t\tunsigned char *resampled;\n\t\tint reduce_block_x = 1, reduce_block_y = 1;\n\t\tint new_width, new_height;\n\t\tif( iwidth > max_supported_size )\n\t\t{\n\t\t\treduce_block_x = iwidth / max_supported_size;\n\t\t}\n\t\tif( iheight > max_supported_size )\n\t\t{\n\t\t\treduce_block_y = iheight / max_supported_size;\n\t\t}\n\t\tnew_width = iwidth / reduce_block_x;\n\t\tnew_height = iheight / reduce_block_y;\n\t\tresampled = (unsigned char*)malloc( channels*new_width*new_height );\n\t\t/*\tperform the actual reduction\t*/\n\t\tmipmap_image( NULL != img ? img : data, iwidth, iheight, channels,\n\t\t\t\t\t\tresampled, reduce_block_x, reduce_block_y );\n\t\t/*\tnuke the old guy, then point it at the new guy\t*/\n\t\tSOIL_free_image_data( img );\n\t\timg = resampled;\n\t\t*width = new_width;\n\t\t*height = new_height;\n\t\tiwidth = new_width;\n\t\tiheight = new_height;\n\t}\n\t/*\tdoes the user want us to use YCoCg color space?\t*/\n\tif( flags & SOIL_FLAG_CoCg_Y )\n\t{\n\t\t/*\tthis will only work with RGB and RGBA images */\n\t\tconvert_RGB_to_YCoCg( img, iwidth, iheight, channels );\n\t}\n\t/*\tcreate the OpenGL texture ID handle\n\t\t(note: allowing a forced texture ID lets me reload a texture)\t*/\n\ttex_id = reuse_texture_ID;\n\tif( tex_id == 0 )\n\t{\n\t\tglGenTextures( 1, &tex_id );\n\t}\n\tcheck_for_GL_errors( \"glGenTextures\" );\n\t/* Note: sometimes glGenTextures fails (usually no OpenGL context)\t*/\n\tif( tex_id )\n\t{\n\t\t/*\tand what type am I using as the internal texture format?\t*/\n\t\tswitch( channels )\n\t\t{\n\t\tcase 1:\n\t\t\toriginal_texture_format = GL_LUMINANCE;\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\toriginal_texture_format = GL_LUMINANCE_ALPHA;\n\t\t\tbreak;\n\t\tcase 3:\n\t\t\toriginal_texture_format = GL_RGB;\n\t\t\tbreak;\n\t\tcase 4:\n\t\t\toriginal_texture_format = GL_RGBA;\n\t\t\tbreak;\n\t\t}\n\t\tinternal_texture_format = original_texture_format;\n\t\t/*\tdoes the user want me to, and can I, save as DXT?\t*/\n\t\tif( flags & SOIL_FLAG_COMPRESS_TO_DXT )\n\t\t{\n\t\t\tDXT_mode = query_DXT_capability();\n\t\t\tif( DXT_mode == SOIL_CAPABILITY_PRESENT )\n\t\t\t{\n\t\t\t\t/*\tI can use DXT, whether I compress it or OpenGL does\t*/\n\t\t\t\tif( (channels & 1) == 1 )\n\t\t\t\t{\n\t\t\t\t\t/*\t1 or 3 channels = DXT1\t*/\n\t\t\t\t\tinternal_texture_format = sRGB_texture ? SOIL_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : SOIL_RGB_S3TC_DXT1;\n\t\t\t\t} else\n\t\t\t\t{\n\t\t\t\t\t/*\t2 or 4 channels = DXT5\t*/\n\t\t\t\t\tinternal_texture_format = sRGB_texture ? SOIL_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : SOIL_RGBA_S3TC_DXT5;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if ( sRGB_texture )\n\t\t{\n\t\t\tswitch( channels )\n\t\t\t{\n\t\t\tcase 3:\n\t\t\t\tinternal_texture_format = SOIL_GL_SRGB;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\tinternal_texture_format = SOIL_GL_SRGB_ALPHA;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\t/*  bind an OpenGL texture ID\t*/\n\t\tglBindTexture( opengl_texture_type, tex_id );\n\t\tcheck_for_GL_errors( \"glBindTexture\" );\n\n\t\t/* set the unpack aligment */\n\t\tglGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_aligment);\n\t\tif ( 1 != unpack_aligment )\n\t\t{\n\t\t\tglPixelStorei(GL_UNPACK_ALIGNMENT,1);\n\t\t}\n\n\t\t/*  upload the main image\t*/\n\t\tif( DXT_mode == SOIL_CAPABILITY_PRESENT )\n\t\t{\n\t\t\t/*\tuser wants me to do the DXT conversion!\t*/\n\t\t\tint DDS_size;\n\t\t\tunsigned char *DDS_data = NULL;\n\t\t\tif( (channels & 1) == 1 )\n\t\t\t{\n\t\t\t\t/*\tRGB, use DXT1\t*/\n\t\t\t\tDDS_data = convert_image_to_DXT1( NULL != img ? img : data, iwidth, iheight, channels, &DDS_size );\n\t\t\t} else\n\t\t\t{\n\t\t\t\t/*\tRGBA, use DXT5\t*/\n\t\t\t\tDDS_data = convert_image_to_DXT5( NULL != img ? img : data, iwidth, iheight, channels, &DDS_size );\n\t\t\t}\n\t\t\tif( DDS_data )\n\t\t\t{\n\t\t\t\tsoilGlCompressedTexImage2D(\n\t\t\t\t\topengl_texture_target, 0,\n\t\t\t\t\tinternal_texture_format, iwidth, iheight, 0,\n\t\t\t\t\tDDS_size, DDS_data );\n\t\t\t\tcheck_for_GL_errors( \"glCompressedTexImage2D\" );\n\t\t\t\tSOIL_free_image_data( DDS_data );\n\t\t\t\t/*\tprintf( \"Internal DXT compressor\\n\" );\t*/\n\t\t\t} else\n\t\t\t{\n\t\t\t\t/*\tmy compression failed, try the OpenGL driver's version\t*/\n\t\t\t\tglTexImage2D(\n\t\t\t\t\topengl_texture_target, 0,\n\t\t\t\t\tinternal_texture_format, iwidth, iheight, 0,\n\t\t\t\t\toriginal_texture_format, GL_UNSIGNED_BYTE, NULL != img ? img : data );\n\t\t\t\tcheck_for_GL_errors( \"glTexImage2D\" );\n\t\t\t\t/*\tprintf( \"OpenGL DXT compressor\\n\" );\t*/\n\t\t\t}\n\t\t} else\n\t\t{\n\t\t\t/*\tuser want OpenGL to do all the work!\t*/\n\t\t\tglTexImage2D(\n\t\t\t\topengl_texture_target, 0,\n\t\t\t\tinternal_texture_format, iwidth, iheight, 0,\n\t\t\t\toriginal_texture_format, GL_UNSIGNED_BYTE, NULL != img ? img : data );\n\n\t\t\tcheck_for_GL_errors( \"glTexImage2D\" );\n\t\t\t/*printf( \"OpenGL DXT compressor\\n\" );\t*/\n\t\t}\n\n\t\t/*\tare any MIPmaps desired?\t*/\n\t\tif( flags & SOIL_FLAG_MIPMAPS || flags & SOIL_FLAG_GL_MIPMAPS )\n\t\t{\n\t\t\tcreateMipmaps( NULL != img ? img : data, iwidth, iheight, channels, flags, opengl_texture_target, internal_texture_format, original_texture_format, DXT_mode );\n\n\t\t\t/*\tinstruct OpenGL to use the MIPmaps\t*/\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );\n\t\t\tcheck_for_GL_errors( \"GL_TEXTURE_MIN/MAG_FILTER\" );\n\t\t} else\n\t\t{\n\t\t\t/*\tinstruct OpenGL _NOT_ to use the MIPmaps\t*/\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );\n\t\t\tcheck_for_GL_errors( \"GL_TEXTURE_MIN/MAG_FILTER\" );\n\t\t}\n\n\t\t/* recover the unpack aligment */\n\t\tif ( 1 != unpack_aligment )\n\t\t{\n\t\t\tglPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment);\n\t\t}\n\n\t\t/*\tdoes the user want clamping, or wrapping?\t*/\n\t\tif( flags & SOIL_FLAG_TEXTURE_REPEATS )\n\t\t{\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );\n\t\t\tif( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP )\n\t\t\t{\n\t\t\t\t/*\tSOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported\t*/\n\t\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );\n\t\t\t}\n\t\t\tcheck_for_GL_errors( \"GL_TEXTURE_WRAP_*\" );\n\t\t} else\n\t\t{\n\t\t\tunsigned int clamp_mode = SOIL_CLAMP_TO_EDGE;\n\t\t\t/* unsigned int clamp_mode = GL_CLAMP; */\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );\n\t\t\tif( opengl_texture_type == SOIL_TEXTURE_CUBE_MAP )\n\t\t\t{\n\t\t\t\t/*\tSOIL_TEXTURE_WRAP_R is invalid if cubemaps aren't supported\t*/\n\t\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );\n\t\t\t}\n\t\t\tcheck_for_GL_errors( \"GL_TEXTURE_WRAP_*\" );\n\t\t}\n\t\t/*\tdone\t*/\n\t\tresult_string_pointer = \"Image loaded as an OpenGL texture\";\n\t} else\n\t{\n\t\t/*\tfailed\t*/\n\t\tresult_string_pointer = \"Failed to generate an OpenGL texture name; missing OpenGL context?\";\n\t}\n\n\tSOIL_free_image_data( img );\n\n\treturn tex_id;\n}\n\nint\n\tSOIL_save_screenshot\n\t(\n\t\tconst char *filename,\n\t\tint image_type,\n\t\tint x, int y,\n\t\tint width, int height\n\t)\n{\n\tunsigned char *pixel_data;\n\tint i, j;\n\tint save_result;\n\tGLint pack_aligment;\n\n\t/*\terror checks\t*/\n\tif( (width < 1) || (height < 1) )\n\t{\n\t\tresult_string_pointer = \"Invalid screenshot dimensions\";\n\t\treturn 0;\n\t}\n\tif( (x < 0) || (y < 0) )\n\t{\n\t\tresult_string_pointer = \"Invalid screenshot location\";\n\t\treturn 0;\n\t}\n\tif( filename == NULL )\n\t{\n\t\tresult_string_pointer = \"Invalid screenshot filename\";\n\t\treturn 0;\n\t}\n\n\tglGetIntegerv(GL_PACK_ALIGNMENT, &pack_aligment);\n\tif ( 1 != pack_aligment )\n\t{\n\t\tglPixelStorei(GL_PACK_ALIGNMENT,1);\n\t}\n\n\t/*  Get the data from OpenGL\t*/\n\tpixel_data = (unsigned char*)malloc( 3*width*height );\n\tglReadPixels (x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixel_data);\n\n\tif ( 1 != pack_aligment )\n\t{\n\t\tglPixelStorei(GL_PACK_ALIGNMENT, pack_aligment);\n\t}\n\n\t/*\tinvert the image\t*/\n\tfor( j = 0; j*2 < height; ++j )\n\t{\n\t\tint index1 = j * width * 3;\n\t\tint index2 = (height - 1 - j) * width * 3;\n\t\tfor( i = width * 3; i > 0; --i )\n\t\t{\n\t\t\tunsigned char temp = pixel_data[index1];\n\t\t\tpixel_data[index1] = pixel_data[index2];\n\t\t\tpixel_data[index2] = temp;\n\t\t\t++index1;\n\t\t\t++index2;\n\t\t}\n\t}\n\n\t/*\tsave the image\t*/\n\tsave_result = SOIL_save_image( filename, image_type, width, height, 3, pixel_data);\n\n\t/*\tAnd free the memory\t*/\n\tSOIL_free_image_data( pixel_data );\n\treturn save_result;\n}\n\nunsigned char*\n\tSOIL_load_image\n\t(\n\t\tconst char *filename,\n\t\tint *width, int *height, int *channels,\n\t\tint force_channels\n\t)\n{\n\tunsigned char *result = stbi_load( filename,\n\t\t\twidth, height, channels, force_channels );\n\tif( result == NULL )\n\t{\n\t\tresult_string_pointer = stbi_failure_reason();\n\t} else\n\t{\n\t\tresult_string_pointer = \"Image loaded\";\n\t}\n\treturn result;\n}\n\nunsigned char*\n\tSOIL_load_image_from_memory\n\t(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tint *width, int *height, int *channels,\n\t\tint force_channels\n\t)\n{\n\tunsigned char *result = stbi_load_from_memory(\n\t\t\t\tbuffer, buffer_length,\n\t\t\t\twidth, height, channels,\n\t\t\t\tforce_channels );\n\tif( result == NULL )\n\t{\n\t\tresult_string_pointer = stbi_failure_reason();\n\t} else\n\t{\n\t\tresult_string_pointer = \"Image loaded from memory\";\n\t}\n\treturn result;\n}\n\n\nint\n\tSOIL_save_image\n\t(\n\t\tconst char *filename,\n\t\tint image_type,\n\t\tint width, int height, int channels,\n\t\tconst unsigned char *const data\n\t)\n{\n\treturn SOIL_save_image_quality( filename, image_type, width, height, channels, data, 80 );\n}\n\nint\n\tSOIL_save_image_quality\n\t(\n\t\tconst char *filename,\n\t\tint image_type,\n\t\tint width, int height, int channels,\n\t\tconst unsigned char *const data,\n\t\tint quality\n\t)\n{\n\tint save_result;\n\n\t/*\terror check\t*/\n\tif( (width < 1) || (height < 1) ||\n\t\t(channels < 1) || (channels > 4) ||\n\t\t(data == NULL) ||\n\t\t(filename == NULL) )\n\t{\n\t\treturn 0;\n\t}\n\tif( image_type == SOIL_SAVE_TYPE_BMP )\n\t{\n\t\tsave_result = stbi_write_bmp( filename,\n\t\t\t\twidth, height, channels, (const void*)data );\n\t} else\n\tif( image_type == SOIL_SAVE_TYPE_TGA )\n\t{\n\t\tsave_result = stbi_write_tga( filename,\n\t\t\t\twidth, height, channels, (const void*)data );\n\t} else\n\tif( image_type == SOIL_SAVE_TYPE_DDS )\n\t{\n\t\tsave_result = save_image_as_DDS( filename,\n\t\t\t\twidth, height, channels, (const unsigned char *const)data );\n\t} else\n\tif( image_type == SOIL_SAVE_TYPE_PNG )\n\t{\n\t\tsave_result = stbi_write_png( filename,\n\t\t\t\twidth, height, channels, (const void*)data, 0 );\n\t} else\n\tif ( image_type == SOIL_SAVE_TYPE_JPG )\n\t{\n\t\tsave_result = stbi_write_jpg( filename, width, height, channels, (const void*)data, quality );\n\t} else\n\tif ( image_type == SOIL_SAVE_TYPE_QOI )\n\t{\n\t\tsave_result = stbi_write_qoi( filename, width, height, channels, (const void*)data );\n\t}\n\telse\n\t{\n\t\tsave_result = 0;\n\t}\n\n\tif( save_result == 0 )\n\t{\n\t\tresult_string_pointer = \"Saving the image failed\";\n\t} else\n\t{\n\t\tresult_string_pointer = \"Image saved\";\n\t}\n\treturn save_result;\n}\n\n\ntypedef struct\n{\n\tunsigned char* buffer;\n\tint allocated; // number of bytes allocated to the buffer\n\tint written; // number of bytes written to the buffer\n\tint alloc_block_size; // size of blocks to alloc as memory is required\n} stbi_write_context;\n\nvoid write_to_memory(void* context, void* data, int size)\n{\n\tstbi_write_context* ctx = (stbi_write_context*)context;\n\n\tif(ctx == 0)\n\t\treturn;\n\n\tif (ctx->buffer == 0)\n\t{\n\t\t// safety\n\t\tctx->written = 0;\n\t\tctx->allocated = 0;\n\n\t\t// first alloc\n\t\twhile (ctx->allocated < (ctx->written + size))\n\t\t{\n\t\t\tctx->allocated += ctx->alloc_block_size;\n\t\t}\n\t\tctx->buffer = (unsigned char*) malloc(ctx->allocated);\n\t}\n\telse if((ctx->written + size) > ctx->allocated)\n\t{\n\t\tctx->allocated += ctx->alloc_block_size;\n\t\twhile (ctx->allocated < (ctx->written + size))\n\t\t{\n\t\t\tctx->allocated += ctx->alloc_block_size;\n\t\t}\n\n\t\tunsigned char* rebuff = (unsigned char*)realloc(ctx->buffer, ctx->allocated);\n\t\tif (rebuff == 0)\n\t\t{\n\t\t\t// out of memory\n\t\t\tfree(ctx->buffer);\n\t\t\tctx->buffer = 0;\n\t\t\tctx->allocated = 0;\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tctx->buffer = rebuff;\n\t\t}\n\t}\n\n\tif(ctx->buffer == 0)\n\t\treturn;\n\n\tmemcpy(ctx->buffer + ctx->written, data, size);\n\tctx->written += size;\n}\n\n\n// release the returned memory with SOIL_free_image_data\nunsigned char*\nSOIL_write_image_to_memory_quality\n(\n\tint image_type,\n\tint width, int height, int channels,\n\tconst unsigned char* const data,\n\tint quality,\n\tint* imageSize\n)\n{\n\tint save_result;\n\n\t/*\terror check\t*/\n\tif ((width < 1) || (height < 1) ||\n\t\t(channels < 1) || (channels > 4) ||\n\t\t(data == NULL) ||\n\t\t(imageSize == NULL)\n\t\t)\n\t{\n\t\treturn 0;\n\t}\n\n\tunsigned char* imageMemory = NULL;\n\t*imageSize = 0;\n\n\tstbi_write_context context;\n\tcontext.alloc_block_size = 4096; // 4k chunks\n\tcontext.buffer = 0;\n\tcontext.allocated = 0;\n\tcontext.written = 0;\n\n\tif (image_type == SOIL_SAVE_TYPE_BMP)\n\t{\n\t\tsave_result = stbi_write_bmp_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data);\n\t}\n\telse if (image_type == SOIL_SAVE_TYPE_TGA)\n\t{\n\t\tsave_result = stbi_write_tga_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data);\n\t}\n\telse if (image_type == SOIL_SAVE_TYPE_DDS)\n\t{\n\t\tsave_result = 0; // not supported thru stbi\n\t}\n\telse if (image_type == SOIL_SAVE_TYPE_PNG)\n\t{\n\t\tsave_result = stbi_write_png_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data, 0);\n\t}\n\telse if (image_type == SOIL_SAVE_TYPE_JPG)\n\t{\n\t\tsave_result = stbi_write_jpg_to_func(write_to_memory, &context, width, height, channels, (const unsigned char*)data, quality);\n\t}\n\telse\n\t{\n\t\tsave_result = 0;\n\t}\n\n\tif (save_result)\n\t{\n\t\timageMemory = context.buffer;\n\t\t*imageSize = context.written;\n\t}\n\telse\n\t{\n\t\tif (context.buffer)\n\t\t\tfree(context.buffer);\n\t}\n\n\tif (save_result == 0)\n\t{\n\t\tresult_string_pointer = \"writing the image failed\";\n\t}\n\telse\n\t{\n\t\tresult_string_pointer = \"Image written\";\n\t}\n\n\treturn imageMemory;\n}\n\n// release the returned memory with SOIL_free_image_data\nunsigned char*\nSOIL_write_image_to_memory\n(\n\tint image_type,\n\tint width, int height, int channels,\n\tconst unsigned char* const data,\n\tint* imageSize\n)\n{\n\treturn SOIL_write_image_to_memory_quality(image_type, width, height, channels, data, 80, imageSize);\n}\n\nvoid\n\tSOIL_free_image_data\n\t(\n\t\tunsigned char *img_data\n\t)\n{\n\tif ( img_data )\n\t\tfree( (void*)img_data );\n}\n\nconst char*\n\tSOIL_last_result\n\t(\n\t\tvoid\n\t)\n{\n\treturn result_string_pointer;\n}\n\n/* This circumvent a VS2022 compiler bug */\n#ifdef _MSC_VER\n#pragma optimize( \"\", off )\n#endif\nstatic inline int calc_total_block_size( int w, int h, int block_size ) {\n\treturn ( ( w + 3 ) >> 2 ) * ( ( h + 3 ) >> 2 ) * block_size;\n}\n#ifdef _MSC_VER\n#pragma optimize( \"\", on )\n#endif\n\nunsigned int SOIL_direct_load_DDS_from_memory(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap)\n{\n\n\tunsigned int buffer_index = 0;\n\tunsigned int tex_ID = 0;\n\n\tunsigned int internal_format = 0;\n\tunsigned char *DDS_data;\n\tunsigned int DDS_main_size;\n\tunsigned int DDS_full_size;\n\tint mipmaps, block_size = 16;\n\tunsigned int cf_target, ogl_target_start, ogl_target_end;\n\tunsigned int opengl_texture_type;\n\tunsigned int format_type = GL_UNSIGNED_BYTE;\n\n\t/*\t1st off, does the filename even exist?\t*/\n\tif( NULL == buffer )\n\t{\n\t\t/*\twe can't do it!\t*/\n\t\tresult_string_pointer = \"NULL buffer\";\n\t\treturn 0;\n\t}\n\tif( buffer_length < (int)sizeof( DDS_header ) )\n\t{\n\t\t/*\twe can't do it!\t*/\n\t\tresult_string_pointer = \"DDS file was too small to contain the DDS header\";\n\t\treturn 0;\n\t}\n\n\t// Try reading in the header\n\tDDS_header header;\n\tmemcpy( (void *)( &header ), (const void *)buffer, sizeof( DDS_header ) );\n\n\tbuffer_index += sizeof(DDS_header);\n\t/*\tguilty until proven innocent\t*/\n\tresult_string_pointer = \"Failed to read a known DDS header\";\n\t/*\tvalidate the header (warning, \"goto\"'s ahead, shield your eyes!!)\t*/\n\tunsigned int flag = ( 'D' << 0 ) | ( 'D' << 8 ) | ( 'S' << 16 ) | ( ' ' << 24 );\n\n\tif( header.dwMagic != flag ) { goto quick_exit; }\n\tif( header.dwSize != 124 ) { goto quick_exit; }\n\t/*\tI need all of these\t*/\n\tflag = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;\n\tif( ( header.dwFlags & flag ) != flag ) { goto quick_exit; }\n\t/*\tAccording to the MSDN spec, the dwFlags should contain\n\t    DDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if\n\t    uncompressed.  Some DDS writers do not conform to the\n\t    spec, so I need to make my reader more tolerant\t*/\n\t/*\tI need one of these\t*/\n\tflag = DDPF_FOURCC | DDPF_RGB | DDPF_LUMINANCE;\n\tif( ( header.sPixelFormat.dwFlags & flag ) == 0 ) { goto quick_exit; }\n\tif( header.sPixelFormat.dwSize != 32 ) { goto quick_exit; }\n\tif( ( header.sCaps.dwCaps1 & DDSCAPS_TEXTURE ) == 0 ) { goto quick_exit; }\n\n\tenum Magics\n\t{\n\t\tDXT1 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( 'T' << 16 ) | ( '1' << 24 ),\n\t\tDXT3 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( 'T' << 16 ) | ( '3' << 24 ),\n\t\tDXT5 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( 'T' << 16 ) | ( '5' << 24 ),\n\t\tATI2 = ( 'A' << 0 ) | ( 'T' << 8 ) | ( 'I' << 16 ) | ( '2' << 24 ),\n\t\tDX10 = ( 'D' << 0 ) | ( 'X' << 8 ) | ( '1' << 16 ) | ( '0' << 24 ),\n\t};\n\n\t// DX10 has an extended header\n\tDDS_HEADER_DXT10 dx10_header;\n\tif (header.sPixelFormat.dwFourCC == DX10) {\n\t\tmemcpy((void*)(&dx10_header), (const void*)&buffer[buffer_index], sizeof(DDS_HEADER_DXT10));\n\t\tbuffer_index += sizeof(dx10_header);\n\t}\n\n\t// make sure it is a type we can upload\n\tif ((header.sPixelFormat.dwFlags & DDPF_FOURCC)\n\t\t&& header.sPixelFormat.dwFourCC != DXT1\n\t\t&& header.sPixelFormat.dwFourCC != DXT3\n\t\t&& header.sPixelFormat.dwFourCC != DXT5\n\t\t&& header.sPixelFormat.dwFourCC != ATI2\n\t\t&& header.sPixelFormat.dwFourCC != DX10\n\t){\n\t\tgoto quick_exit;\n\t}\n\n\t/*\tOK, validated the header, let's load the image data\t*/\n\tresult_string_pointer = \"DDS header loaded and validated\";\n\n\tconst int width = header.dwWidth;\n\tconst int height = header.dwHeight;\n\tint uncompressed = 1 - ( header.sPixelFormat.dwFlags & DDPF_FOURCC ) / DDPF_FOURCC;\n\tint cubemap = ( header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP ) / DDSCAPS2_CUBEMAP;\n\tif( uncompressed )\n\t{\n\t\tif( header.sPixelFormat.dwRGBBitCount == 8 )\n\t\t{\n\t\t\tif( ( header.sPixelFormat.dwRBitMask == 0xe0 ) && ( header.sPixelFormat.dwGBitMask == 0x1c ) &&\n\t\t\t    ( header.sPixelFormat.dwBBitMask == 0x3 ) )\n\t\t\t{\n\t\t\t\tinternal_format = GL_RGB;\n\t\t\t\tformat_type = GL_UNSIGNED_BYTE_3_3_2;\n\t\t\t\tblock_size = 1;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tinternal_format = GL_LUMINANCE;\n\t\t\t\tblock_size = 1;\n\t\t\t}\n\t\t}\n\t\telse if( header.sPixelFormat.dwRGBBitCount == 16 )\n\t\t{\n\t\t\tif( ( header.sPixelFormat.dwRBitMask == 0xf800 ) && ( header.sPixelFormat.dwGBitMask == 0x7e0 ) &&\n\t\t\t    ( header.sPixelFormat.dwBBitMask == 0x1f ) )\n\t\t\t{\n\t\t\t\t// DXGI_FORMAT_B5G6R5_UNORM\n\t\t\t\tinternal_format = GL_RGBA;\n\t\t\t\tformat_type = GL_UNSIGNED_SHORT_5_5_5_1;\n\t\t\t\tblock_size = 2;\n\t\t\t}\n\t\t\telse if( ( header.sPixelFormat.dwRBitMask == 0xf00 ) && ( header.sPixelFormat.dwGBitMask == 0xf0 ) &&\n\t\t\t         ( header.sPixelFormat.dwBBitMask == 0xf ) && ( header.sPixelFormat.dwAlphaBitMask == 0xf000 ) )\n\t\t\t{\n\t\t\t\t// D3DFMT_A4R4G4B4\n\t\t\t\tinternal_format = GL_RGBA;\n\t\t\t\tformat_type = GL_UNSIGNED_SHORT_4_4_4_4;\n\t\t\t\tblock_size = 2;\n\t\t\t}\n\t\t\telse if( ( header.sPixelFormat.dwRBitMask == 0x7c00 ) && ( header.sPixelFormat.dwGBitMask == 0x3e0 ) &&\n\t\t\t         ( header.sPixelFormat.dwBBitMask == 0x1f ) )\n\t\t\t{\n\t\t\t\t// DXGI_FORMAT_B5G5R5A1_UNORM\n\t\t\t\tinternal_format = GL_RGBA;\n\t\t\t\tformat_type = GL_UNSIGNED_SHORT_5_5_5_1;\n\t\t\t\tblock_size = 2;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tinternal_format = GL_RG;\n\t\t\t\tblock_size = 2;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tinternal_format = GL_RGB;\n\t\t\tblock_size = 3;\n\t\t\tif( header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS )\n\t\t\t{\n\t\t\t\tinternal_format = GL_RGBA;\n\t\t\t\tblock_size = 4;\n\t\t\t}\n\t\t}\n\t\tDDS_main_size = width * height * block_size;\n\t}\n\telse\n\t{\n\t\tif( header.sPixelFormat.dwFourCC == ATI2 )\n\t\t{\n\t\t\tif( query_3Dc_capability() != SOIL_CAPABILITY_PRESENT )\n\t\t\t{\n\t\t\t\t/*\twe can't do it!\t*/\n\t\t\t\tresult_string_pointer = \"Direct upload of 3Dc images not supported by the OpenGL driver\";\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif( query_DXT_capability() != SOIL_CAPABILITY_PRESENT )\n\t\t\t{\n\t\t\t\t/*\twe can't do it!\t*/\n\t\t\t\tresult_string_pointer = \"Direct upload of S3TC images not supported by the OpenGL driver\";\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t}\n\n\t\tswitch( header.sPixelFormat.dwFourCC )\n\t\t{\n\t\tcase DXT1:\n\t\t\tinternal_format = SOIL_RGBA_S3TC_DXT1;\n\t\t\tblock_size = 8;\n\t\t\tbreak;\n\t\tcase DXT3:\n\t\t\tinternal_format = SOIL_RGBA_S3TC_DXT3;\n\t\t\tblock_size = 16;\n\t\t\tbreak;\n\t\tcase DXT5:\n\t\t\tinternal_format = SOIL_RGBA_S3TC_DXT5;\n\t\t\tblock_size = 16;\n\t\t\tbreak;\n\t\tcase ATI2:\n\t\t\tblock_size = 16;\n\t\t\tinternal_format = SOIL_COMPRESSED_RG_RGTC2;\n\t\t\tbreak;\n\t\tcase DX10:\n\t\t\tif (dx10_header.dxgiFormat != DXGI_FORMAT_BC5_UNORM) {\n\t\t\t\tresult_string_pointer = \"The DX10 reader only supports BC5 unorm at the moment\";\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tblock_size = 16;\n\t\t\tinternal_format = SOIL_COMPRESSED_RG_RGTC2;\n\t\t\tbreak;\n\t\t}\n\t\tDDS_main_size = ( ( width + 3 ) >> 2 ) * ( ( height + 3 ) >> 2 ) * block_size;\n\t}\n\n\tif( cubemap )\n\t{\n\t\t/* does the user want a cubemap?\t*/\n\t\tif( !loading_as_cubemap )\n\t\t{\n\t\t\t/*\twe can't do it!\t*/\n\t\t\tresult_string_pointer = \"DDS image was a cubemap\";\n\t\t\treturn 0;\n\t\t}\n\t\t/*\tcan we even handle cubemaps with the OpenGL driver?\t*/\n\t\tif( query_cubemap_capability() != SOIL_CAPABILITY_PRESENT )\n\t\t{\n\t\t\t/*\twe can't do it!\t*/\n\t\t\tresult_string_pointer = \"Direct upload of cubemap images not supported by the OpenGL driver\";\n\t\t\treturn 0;\n\t\t}\n\t\togl_target_start = SOIL_TEXTURE_CUBE_MAP_POSITIVE_X;\n\t\togl_target_end = SOIL_TEXTURE_CUBE_MAP_NEGATIVE_Z;\n\t\topengl_texture_type = SOIL_TEXTURE_CUBE_MAP;\n\t}\n\telse\n\t{\n\t\t/* does the user want a non-cubemap?\t*/\n\t\tif( loading_as_cubemap )\n\t\t{\n\t\t\t/*\twe can't do it!\t*/\n\t\t\tresult_string_pointer = \"DDS image was not a cubemap\";\n\t\t\treturn 0;\n\t\t}\n\t\togl_target_start = GL_TEXTURE_2D;\n\t\togl_target_end = GL_TEXTURE_2D;\n\t\topengl_texture_type = GL_TEXTURE_2D;\n\t}\n\n\tif( ( header.sCaps.dwCaps1 & DDSCAPS_MIPMAP ) && ( header.dwMipMapCount > 1 ) )\n\t{\n\t\tmipmaps = header.dwMipMapCount - 1;\n\t\tDDS_full_size = DDS_main_size;\n\n\t\tfor( int i = 1; i <= mipmaps; ++i )\n\t\t{\n\t\t\tint w = width >> i;\n\t\t\tint h = height >> i;\n\t\t\tif( w < 1 ) { w = 1; }\n\t\t\tif( h < 1 ) { h = 1; }\n\t\t\tif( uncompressed )\n\t\t\t{\n\t\t\t\t/*\tuncompressed DDS, simple MIPmap size calculation\t*/\n\t\t\t\tDDS_full_size += w * h * block_size;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t/*\tcompressed DDS, MIPmap size calculation is block based\t*/\n\t\t\t\tDDS_full_size += calc_total_block_size( w, h, block_size );\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t\tmipmaps = 0;\n\t\tDDS_full_size = DDS_main_size;\n\t}\n\tDDS_data = (unsigned char *)malloc( DDS_full_size );\n\t/*\tgot the image data RAM, create or use an existing OpenGL texture handle\t*/\n\ttex_ID = reuse_texture_ID;\n\tif( tex_ID == 0 ) { glGenTextures( 1, &tex_ID ); }\n\t/*  bind an OpenGL texture ID\t*/\n\tglBindTexture( opengl_texture_type, tex_ID );\n\t/*\tdo this for each face of the cubemap!\t*/\n\tfor( cf_target = ogl_target_start; cf_target <= ogl_target_end; ++cf_target )\n\t{\n\t\tif( buffer_index + DDS_full_size <= (unsigned int)buffer_length )\n\t\t{\n\t\t\tunsigned int byte_offset = DDS_main_size;\n\t\t\tmemcpy( (void *)DDS_data, (const void *)( &buffer[buffer_index] ), DDS_full_size );\n\t\t\tbuffer_index += DDS_full_size;\n\t\t\t/*\tupload the main chunk\t*/\n\t\t\tif( uncompressed )\n\t\t\t{\n\t\t\t\tif( ( header.sPixelFormat.dwRBitMask == 0xff0000 ) &&\n\t\t\t\t    ( ( block_size == 3 && internal_format == GL_RGB ) ||\n\t\t\t\t      ( block_size == 4 && internal_format == GL_RGBA ) ) )\n\t\t\t\t{\n\t\t\t\t\tfor( int i = 0; i < (int)DDS_full_size; i += block_size )\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned char temp = DDS_data[i];\n\t\t\t\t\t\tDDS_data[i] = DDS_data[i + 2];\n\t\t\t\t\t\tDDS_data[i + 2] = temp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if( block_size == 2 &&\n\t\t\t\t         ( header.sPixelFormat.dwRBitMask == 0xf800 || header.sPixelFormat.dwRBitMask == 0x7c00 ) )\n\t\t\t\t{\n\t\t\t\t\t// convert to R5G5B5A1\n\t\t\t\t\tfor( int i = 0; i < (int)DDS_full_size; i += block_size )\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned short pixel = DDS_data[i] << 0 | DDS_data[i + 1] << 8;\n\t\t\t\t\t\tchar r = ( ( pixel & header.sPixelFormat.dwRBitMask ) >> 10 );\n\t\t\t\t\t\tchar g = ( ( pixel & header.sPixelFormat.dwGBitMask ) >> 5 );\n\t\t\t\t\t\tchar b = ( ( pixel & header.sPixelFormat.dwBBitMask ) >> 0 );\n\t\t\t\t\t\tchar a = 1;\n\t\t\t\t\t\tif( header.sPixelFormat.dwAlphaBitMask != 0 )\n\t\t\t\t\t\t{ a = ( pixel & header.sPixelFormat.dwAlphaBitMask ) >> 15; }\n\t\t\t\t\t\tunsigned short pixel_new = ( r << 11 ) | ( g << 6 ) | ( b << 1 ) | a;\n\t\t\t\t\t\tDDS_data[i] = ( pixel_new >> 0 ) & 0xff;\n\t\t\t\t\t\tDDS_data[i + 1] = ( pixel_new >> 8 ) & 0xff;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if( block_size == 2 && ( header.sPixelFormat.dwRBitMask == 0xf00 ) &&\n\t\t\t\t         ( header.sPixelFormat.dwGBitMask == 0xf0 ) && ( header.sPixelFormat.dwBBitMask == 0xf ) &&\n\t\t\t\t         ( header.sPixelFormat.dwAlphaBitMask == 0xf000 ) )\n\t\t\t\t{\n\t\t\t\t\tfor( int i = 0; i < (int)DDS_full_size; i += block_size )\n\t\t\t\t\t{\n\t\t\t\t\t\tunsigned short pixel = DDS_data[i] << 0 | DDS_data[i + 1] << 8;\n\t\t\t\t\t\tchar r = ( ( pixel & header.sPixelFormat.dwRBitMask ) >> 8 );\n\t\t\t\t\t\tchar g = ( ( pixel & header.sPixelFormat.dwGBitMask ) >> 4 );\n\t\t\t\t\t\tchar b = ( ( pixel & header.sPixelFormat.dwBBitMask ) >> 0 );\n\t\t\t\t\t\tchar a = ( ( pixel & header.sPixelFormat.dwAlphaBitMask ) >> 12 );\n\t\t\t\t\t\tunsigned short pixel_new = ( r << 12 ) | ( g << 8 ) | ( b << 4 ) | a;\n\t\t\t\t\t\tDDS_data[i] = ( pixel_new >> 0 ) & 0xff;\n\t\t\t\t\t\tDDS_data[i + 1] = ( pixel_new >> 8 ) & 0xff;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tglTexImage2D( cf_target, 0, internal_format, width, height, 0, internal_format, format_type, DDS_data );\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsoilGlCompressedTexImage2D( cf_target, 0, internal_format, width, height, 0, DDS_main_size, DDS_data );\n\t\t\t}\n\t\t\t/*\tupload the mipmaps, if we have them\t*/\n\t\t\tfor( int i = 1; i <= mipmaps; ++i )\n\t\t\t{\n\t\t\t\tint w, h, mip_size;\n\t\t\t\tw = width >> i;\n\t\t\t\th = height >> i;\n\t\t\t\tif( w < 1 ) { w = 1; }\n\t\t\t\tif( h < 1 ) { h = 1; }\n\t\t\t\t/*\tupload this mipmap\t*/\n\t\t\t\tif( uncompressed )\n\t\t\t\t{\n\t\t\t\t\tmip_size = w * h * block_size;\n\t\t\t\t\tglTexImage2D( cf_target, i, internal_format, w, h, 0, internal_format, format_type,\n\t\t\t\t\t              &DDS_data[byte_offset] );\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tmip_size = ( ( w + 3 ) / 4 ) * ( ( h + 3 ) / 4 ) * block_size;\n\t\t\t\t\tsoilGlCompressedTexImage2D( cf_target, i, internal_format, w, h, 0, mip_size,\n\t\t\t\t\t                            &DDS_data[byte_offset] );\n\t\t\t\t}\n\t\t\t\t/*\tand move to the next mipmap\t*/\n\t\t\t\tbyte_offset += mip_size;\n\t\t\t}\n\t\t\t/*\tit worked!\t*/\n\t\t\tresult_string_pointer = \"DDS file loaded\";\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglDeleteTextures( 1, &tex_ID );\n\t\t\ttex_ID = 0;\n\t\t\tcf_target = ogl_target_end + 1;\n\t\t\tresult_string_pointer = \"DDS file was too small for expected image data\";\n\t\t}\n\t} /* end reading each face */\n\tSOIL_free_image_data( DDS_data );\n\tif( tex_ID )\n\t{\n\t\t/*\tdid I have MIPmaps?\t*/\n\t\tif( mipmaps > 0 )\n\t\t{\n\t\t\t/*\tinstruct OpenGL to use the MIPmaps\t*/\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );\n\t\t}\n\t\telse\n\t\t{\n\t\t\t/*\tinstruct OpenGL _NOT_ to use the MIPmaps\t*/\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );\n\t\t}\n\t\t/*\tdoes the user want clamping, or wrapping?\t*/\n\t\tif( flags & SOIL_FLAG_TEXTURE_REPEATS )\n\t\t{\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );\n\t\t}\n\t\telse\n\t\t{\n\t\t\tunsigned int clamp_mode = SOIL_CLAMP_TO_EDGE;\n\t\t\t/* unsigned int clamp_mode = GL_CLAMP; */\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );\n\t\t}\n\t}\n\nquick_exit:\n\treturn tex_ID;\n}\n\nunsigned int SOIL_direct_load_DDS(\n\t\tconst char *filename,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap )\n{\n\tFILE *f;\n\tunsigned char *buffer;\n\tsize_t buffer_length, bytes_read;\n\tunsigned int tex_ID = 0;\n\t/*\terror checks\t*/\n\tif( NULL == filename )\n\t{\n\t\tresult_string_pointer = \"NULL filename\";\n\t\treturn 0;\n\t}\n\tf = fopen( filename, \"rb\" );\n\tif( NULL == f )\n\t{\n\t\t/*\tthe file doesn't seem to exist (or be open-able)\t*/\n\t\tresult_string_pointer = \"Can not find DDS file\";\n\t\treturn 0;\n\t}\n\tfseek( f, 0, SEEK_END );\n\tbuffer_length = ftell( f );\n\tfseek( f, 0, SEEK_SET );\n\tbuffer = (unsigned char *) malloc( buffer_length );\n\tif( NULL == buffer )\n\t{\n\t\tresult_string_pointer = \"malloc failed\";\n\t\tfclose( f );\n\t\treturn 0;\n\t}\n\tbytes_read = fread( (void*)buffer, 1, buffer_length, f );\n\tfclose( f );\n\tif( bytes_read < buffer_length )\n\t{\n\t\t/*\thuh?\t*/\n\t\tbuffer_length = bytes_read;\n\t}\n\t/*\tnow try to do the loading\t*/\n\ttex_ID = SOIL_direct_load_DDS_from_memory(\n\t\t(const unsigned char *const)buffer, (int)buffer_length,\n\t\treuse_texture_ID, flags, loading_as_cubemap );\n\tSOIL_free_image_data( buffer );\n\treturn tex_ID;\n}\n\nunsigned int SOIL_direct_load_PVR_from_memory(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap )\n{\n\tPVR_Texture_Header* header = (PVR_Texture_Header*)buffer;\n\tint num_surfs = 1;\n\tGLuint tex_ID = 0;\n\tGLenum PVR_format = 0;\n\tGLenum PVR_type = GL_RGB;\n\tunsigned int opengl_texture_type = loading_as_cubemap ? SOIL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;\n\tint is_PVRTC_supported = query_PVR_capability() == SOIL_CAPABILITY_PRESENT;\n\tint is_BGRA8888_supported  = query_BGRA8888_capability() == SOIL_CAPABILITY_PRESENT;\n\tint is_compressed_format_supported = 0;\n\tint is_compressed_format = 0;\n\tint mipmaps = 0;\n\tint i;\n\tGLint unpack_aligment;\n\n\t// Check the header size\n\tif ( header->dwHeaderSize != sizeof(PVR_Texture_Header) ) {\n\t\tif ( header->dwHeaderSize == PVRTEX_V1_HEADER_SIZE ) {\n\t\t\tresult_string_pointer = \"this is an old pvr ( update the PVR file )\";\n\n\t\t\tif ( loading_as_cubemap ) {\n\t\t\t\tif( header->dwpfFlags & PVRTEX_CUBEMAP ) {\n\t\t\t\t\tnum_surfs = 6;\n\t\t\t\t} else {\n\t\t\t\t\tresult_string_pointer = \"tried to load a non-cubemap PVR as cubemap\";\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tresult_string_pointer = \"invalid PVR header\";\n\n\t\t\treturn 0;\n\t\t}\n\t} else {\n\t\tif ( loading_as_cubemap ) {\n\t\t\t// Header V2\n\t\t\tif( header->dwNumSurfs < 1 ) {\n\t\t\t\tif( header->dwpfFlags & PVRTEX_CUBEMAP ) {\n\t\t\t\t\tnum_surfs = 6;\n\t\t\t\t} else {\n\t\t\t\t\tresult_string_pointer = \"tried to load a non-cubemap PVR as cubemap\";\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tnum_surfs = header->dwNumSurfs;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check the magic identifier\n\tif ( header->dwPVR != PVRTEX_IDENTIFIER ) {\n\t\tresult_string_pointer = \"invalid PVR header\";\n\t\treturn 0;\n\t}\n\n\t/* Only accept untwiddled data UNLESS texture format is PVRTC */\n\tif ( ((header->dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE)\n\t\t&& ((header->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC2)\n\t\t&& ((header->dwpfFlags & PVRTEX_PIXELTYPE)!=OGL_PVRTC4) )\n\t{\n\t\t// We need to load untwiddled textures -- hw will twiddle for us.\n\t\tresult_string_pointer = \"pvr is not compressed ( untwiddled texture )\";\n\t\treturn 0;\n\t}\n\n\tswitch( header->dwpfFlags & PVRTEX_PIXELTYPE )\n\t{\n\t\tcase OGL_RGBA_4444:\n\t\t\tPVR_format = GL_UNSIGNED_SHORT_4_4_4_4;\n\t\t\tPVR_type = GL_RGBA;\n\t\t\tbreak;\n\t\tcase OGL_RGBA_5551:\n\t\t\tPVR_format = GL_UNSIGNED_SHORT_5_5_5_1;\n\t\t\tPVR_type = GL_RGBA;\n\t\t\tbreak;\n\t\tcase OGL_RGBA_8888:\n\t\t\tPVR_format = GL_UNSIGNED_BYTE;\n\t\t\tPVR_type = GL_RGBA;\n\t\t\tbreak;\n\t\tcase OGL_RGB_565:\n\t\t\tPVR_format = GL_UNSIGNED_SHORT_5_6_5;\n\t\t\tPVR_type = GL_RGB;\n\t\t\tbreak;\n\t\tcase OGL_RGB_555:\n\t\t\tresult_string_pointer = \"failed: pixel type OGL_RGB_555 not supported.\";\n\t\t\treturn 0;\n\t\tcase OGL_RGB_888:\n\t\t\tPVR_format = GL_UNSIGNED_BYTE;\n\t\t\tPVR_type = GL_RGB;\n\t\t\tbreak;\n\t\tcase OGL_I_8:\n\t\t\tPVR_format = GL_UNSIGNED_BYTE;\n\t\t\tPVR_type = GL_LUMINANCE;\n\t\t\tbreak;\n\t\tcase OGL_AI_88:\n\t\t\tPVR_format = GL_UNSIGNED_BYTE;\n\t\t\tPVR_type = GL_LUMINANCE_ALPHA;\n\t\t\tbreak;\n\t\tcase MGLPT_PVRTC2:\n\t\tcase OGL_PVRTC2:\n\t\t\tif(is_PVRTC_supported) {\n\t\t\t\tis_compressed_format_supported = is_compressed_format = 1;\n\t\t\t\tPVR_format = header->dwAlphaBitMask==0 ? SOIL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG : SOIL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG ;\t// PVRTC2\n\t\t\t} else {\n\t\t\t\tresult_string_pointer = \"error: PVRTC2 not supported.Decompress the texture first.\";\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase MGLPT_PVRTC4:\n\t\tcase OGL_PVRTC4:\n\t\t\tif(is_PVRTC_supported) {\n\t\t\t\tis_compressed_format_supported = is_compressed_format = 1;\n\t\t\t\tPVR_format = header->dwAlphaBitMask==0 ? SOIL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG : SOIL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG ;\t// PVRTC4\n\t\t\t} else {\n\t\t\t\tresult_string_pointer = \"error: PVRTC4 not supported. Decompress the texture first.\";\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase OGL_BGRA_8888:\n\t\t\tif(is_BGRA8888_supported) {\n\t\t\t\tPVR_format = GL_UNSIGNED_BYTE;\n\t\t\t\tPVR_type   = GL_BGRA;\n\t\t\t\tbreak;\n\t\t\t} else {\n\t\t\t\tresult_string_pointer = \"Unable to load GL_BGRA texture as extension GL_IMG_texture_format_BGRA8888 is unsupported.\";\n\t\t\t\treturn 0;\n\t\t\t}\n\t\tdefault:\t\t\t\t\t\t\t\t\t\t\t// NOT SUPPORTED\n\t\t\tresult_string_pointer = \"failed: pixel type not supported.\";\n\t\t\treturn 0;\n\t}\n\n\t#ifdef SOIL_GLES1\n\t//  check that this data is cube map data or not.\n\tif( loading_as_cubemap ) {\n\t\tresult_string_pointer = \"cube map textures are not available in GLES1.x.\";\n\t\treturn 0;\n\t}\n\t#endif\n\n\t// load the texture up\n\ttex_ID = reuse_texture_ID;\n\tif( tex_ID == 0 )\n\t{\n\t\tglGenTextures( 1, &tex_ID );\n\t}\n\n\tglBindTexture( opengl_texture_type, tex_ID );\n\n\tif( glGetError() ) {\n\t\tresult_string_pointer = \"failed: glBindTexture() failed.\";\n\t\treturn 0;\n\t}\n\n\tglGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_aligment);\n\tif ( 1 != unpack_aligment )\n\t{\n\t\tglPixelStorei(GL_UNPACK_ALIGNMENT,1);\t\t\t\t// Never have row-aligned in headers\n\t}\n\n\t#define _MAX( a, b ) (( a <= b )? b : a)\n\tfor(i=0; i<num_surfs; i++) {\n\t\tchar *texture_ptr = (char*)buffer + header->dwHeaderSize + header->dwTextureDataSize * i;\n\t\tchar *cur_texture_ptr = 0;\n\t\tint\tmipmap_level;\n\t\tunsigned int width= header->dwWidth, height = header->dwHeight;\n\t\tunsigned int compressed_image_size = 0;\n\n\t\tmipmaps = ( ( flags & SOIL_FLAG_MIPMAPS ) && (header->dwpfFlags & PVRTEX_MIPMAP) ) ? header->dwMipMapCount : 0;\n\n\t\tfor(mipmap_level = 0; mipmap_level <= mipmaps; width = _MAX(width/2, (unsigned int)1), height = _MAX(height/2, (unsigned int)1), mipmap_level++ ) {\n\t\t\t// Do Alpha-swap if needed\n\t\t\tcur_texture_ptr = texture_ptr;\n\n\t\t\t// Load the Texture\n\t\t\t/* If the texture is PVRTC then use GLCompressedTexImage2D */\n\t\t\tif( is_compressed_format ) {\n\t\t\t\t/* Calculate how many bytes this MIP level occupies */\n\t\t\t\tif ((header->dwpfFlags & PVRTEX_PIXELTYPE)==OGL_PVRTC2) {\n\t\t\t\t\tcompressed_image_size = ( _MAX(width, PVRTC2_MIN_TEXWIDTH) * _MAX(height, PVRTC2_MIN_TEXHEIGHT) * header->dwBitCount + 7 ) / 8;\n\t\t\t\t} else {// PVRTC4 case\n\t\t\t\t\tcompressed_image_size = ( _MAX(width, PVRTC4_MIN_TEXWIDTH) * _MAX(height, PVRTC4_MIN_TEXHEIGHT) * header->dwBitCount + 7 ) / 8;\n\t\t\t\t}\n\n\t\t\t\tif ( is_compressed_format_supported ) {\n\t\t\t\t\t/* Load compressed texture data at selected MIP level */\n\t\t\t\t\tif ( loading_as_cubemap ) {\n\t\t\t\t\t\tsoilGlCompressedTexImage2D( SOIL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mipmap_level, PVR_format, width, height, 0, compressed_image_size, cur_texture_ptr );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsoilGlCompressedTexImage2D( opengl_texture_type, mipmap_level, PVR_format, width, height, 0, compressed_image_size, cur_texture_ptr );\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tresult_string_pointer = \"failed: GPU doesnt support compressed textures\";\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t/* Load uncompressed texture data at selected MIP level */\n\t\t\t\tif ( loading_as_cubemap ) {\n\t\t\t\t\tglTexImage2D( SOIL_TEXTURE_CUBE_MAP_POSITIVE_X + i, mipmap_level, PVR_type, width, height, 0, PVR_type, PVR_format, cur_texture_ptr );\n\t\t\t\t} else {\n\t\t\t\t\tglTexImage2D( opengl_texture_type, mipmap_level, PVR_type, width, height, 0, PVR_type, PVR_format, cur_texture_ptr );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif( glGetError() ) {\n\t\t\t\tresult_string_pointer = \"failed: glCompressedTexImage2D() failed.\";\n\t\t\t\tif ( 1 != unpack_aligment )\n\t\t\t\t{\n\t\t\t\t\tglPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment);\n\t\t\t\t}\n\t\t\t\treturn 0;\n\t\t\t}\n\n\t\t\t// offset the texture pointer by one mip-map level\n\t\t\t/* PVRTC case */\n\t\t\tif ( is_compressed_format ) {\n\t\t\t\ttexture_ptr += compressed_image_size;\n\t\t\t} else {\n\t\t\t\t/* New formula that takes into account bit counts inferior to 8 (e.g. 1 bpp) */\n\t\t\t\ttexture_ptr += (width * height * header->dwBitCount + 7) / 8;\n\t\t\t}\n\t\t}\n\t}\n\t#undef _MAX\n\n\tif ( 1 != unpack_aligment )\n\t{\n\t\tglPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment);\n\t}\n\n\tif( tex_ID )\n\t{\n\t\t/*\tdid I have MIPmaps?\t*/\n\t\tif( mipmaps )\n\t\t{\n\t\t\t/*\tinstruct OpenGL to use the MIPmaps\t*/\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );\n\t\t} else\n\t\t{\n\t\t\t/*\tinstruct OpenGL _NOT_ to use the MIPmaps\t*/\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );\n\t\t}\n\n\t\t/*\tdoes the user want clamping, or wrapping?\t*/\n\t\tif( flags & SOIL_FLAG_TEXTURE_REPEATS )\n\t\t{\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );\n\t\t} else\n\t\t{\n\t\t\tunsigned int clamp_mode = SOIL_CLAMP_TO_EDGE;\n\t\t\t/* unsigned int clamp_mode = GL_CLAMP; */\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );\n\t\t}\n\t}\n\n\treturn tex_ID;\n}\n\nunsigned int SOIL_direct_load_PVR(\n\t\tconst char *filename,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap )\n{\n\tFILE *f;\n\tunsigned char *buffer;\n\tsize_t buffer_length, bytes_read;\n\tunsigned int tex_ID = 0;\n\t/*\terror checks\t*/\n\tif( NULL == filename )\n\t{\n\t\tresult_string_pointer = \"NULL filename\";\n\t\treturn 0;\n\t}\n\tf = fopen( filename, \"rb\" );\n\tif( NULL == f )\n\t{\n\t\t/*\tthe file doesn't seem to exist (or be open-able)\t*/\n\t\tresult_string_pointer = \"Can not find PVR file\";\n\t\treturn 0;\n\t}\n\tfseek( f, 0, SEEK_END );\n\tbuffer_length = ftell( f );\n\tfseek( f, 0, SEEK_SET );\n\tbuffer = (unsigned char *) malloc( buffer_length );\n\tif( NULL == buffer )\n\t{\n\t\tresult_string_pointer = \"malloc failed\";\n\t\tfclose( f );\n\t\treturn 0;\n\t}\n\tbytes_read = fread( (void*)buffer, 1, buffer_length, f );\n\tfclose( f );\n\tif( bytes_read < buffer_length )\n\t{\n\t\t/*\thuh?\t*/\n\t\tbuffer_length = bytes_read;\n\t}\n\t/*\tnow try to do the loading\t*/\n\ttex_ID = SOIL_direct_load_PVR_from_memory(\n\t\t(const unsigned char *const)buffer, (int)buffer_length,\n\t\treuse_texture_ID, flags, loading_as_cubemap );\n\tSOIL_free_image_data( buffer );\n\treturn tex_ID;\n}\n\nunsigned int SOIL_direct_load_ETC1_from_memory(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags )\n{\n\tGLuint tex_ID = 0;\n\tPKMHeader* header = (PKMHeader*)buffer;\n\tunsigned int opengl_texture_type = GL_TEXTURE_2D;\n\tunsigned int width;\n\tunsigned int height;\n\tunsigned long compressed_image_size = buffer_length - PKM_HEADER_SIZE;\n\tchar *texture_ptr = (char*)buffer + PKM_HEADER_SIZE;\n\tGLint unpack_aligment;\n\n\tif ( query_ETC1_capability() != SOIL_CAPABILITY_PRESENT ) {\n\t\tresult_string_pointer = \"error: ETC1 not supported. Decompress the texture first.\";\n\t\treturn 0;\n\t}\n\n\tif ( 0 != strcmp( header->aName, \"PKM 10\" ) ) {\n\t\tresult_string_pointer = \"error: PKM 10 header not found.\";\n\t\treturn 0;\n\t}\n\n\twidth = (header->iWidthMSB << 8) | header->iWidthLSB;\n\theight = (header->iHeightMSB << 8) | header->iHeightLSB;\n\tcompressed_image_size = (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1;\n\n\t// load the texture up\n\ttex_ID = reuse_texture_ID;\n\tif( tex_ID == 0 )\n\t{\n\t\tglGenTextures( 1, &tex_ID );\n\t}\n\n\tglBindTexture( opengl_texture_type, tex_ID );\n\n\tif( glGetError() ) {\n\t\tresult_string_pointer = \"failed: glBindTexture() failed.\";\n\t\treturn 0;\n\t}\n\n\tglGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_aligment);\n\tif ( 1 != unpack_aligment )\n\t{\n\t\tglPixelStorei(GL_UNPACK_ALIGNMENT,1);\t\t\t\t// Never have row-aligned in headers\n\t}\n\n\tsoilGlCompressedTexImage2D( opengl_texture_type, 0, SOIL_GL_ETC1_RGB8_OES, width, height, 0, compressed_image_size, texture_ptr );\n\n\tif( glGetError() ) {\n\t\tresult_string_pointer = \"failed: glCompressedTexImage2D() failed.\";\n\n\t\tif ( 1 != unpack_aligment )\n\t\t{\n\t\t\tglPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment);\n\t\t}\n\t\treturn 0;\n\t}\n\n\tif ( 1 != unpack_aligment )\n\t{\n\t\tglPixelStorei(GL_UNPACK_ALIGNMENT, unpack_aligment);\n\t}\n\n\tif( tex_ID )\n\t{\n\t\t/* No MIPmaps for ETC1 */\n\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR );\n\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR );\n\n\t\t/*\tdoes the user want clamping, or wrapping?\t*/\n\t\tif( flags & SOIL_FLAG_TEXTURE_REPEATS )\n\t\t{\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, GL_REPEAT );\n\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, GL_REPEAT );\n\t\t} else\n\t\t{\n\t\t\tunsigned int clamp_mode = SOIL_CLAMP_TO_EDGE;\n\t\t\t/* unsigned int clamp_mode = GL_CLAMP; */\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_S, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, GL_TEXTURE_WRAP_T, clamp_mode );\n\t\t\tglTexParameteri( opengl_texture_type, SOIL_TEXTURE_WRAP_R, clamp_mode );\n\t\t}\n\t}\n\n\treturn tex_ID;\n}\n\nunsigned int SOIL_direct_load_ETC1(const char *filename,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags )\n{\n\tFILE *f;\n\tunsigned char *buffer;\n\tsize_t buffer_length, bytes_read;\n\tunsigned int tex_ID = 0;\n\t/*\terror checks\t*/\n\tif( NULL == filename )\n\t{\n\t\tresult_string_pointer = \"NULL filename\";\n\t\treturn 0;\n\t}\n\tf = fopen( filename, \"rb\" );\n\tif( NULL == f )\n\t{\n\t\t/*\tthe file doesn't seem to exist (or be open-able)\t*/\n\t\tresult_string_pointer = \"Can not find PVR file\";\n\t\treturn 0;\n\t}\n\tfseek( f, 0, SEEK_END );\n\tbuffer_length = ftell( f );\n\tfseek( f, 0, SEEK_SET );\n\tbuffer = (unsigned char *) malloc( buffer_length );\n\tif( NULL == buffer )\n\t{\n\t\tresult_string_pointer = \"malloc failed\";\n\t\tfclose( f );\n\t\treturn 0;\n\t}\n\tbytes_read = fread( (void*)buffer, 1, buffer_length, f );\n\tfclose( f );\n\tif( bytes_read < buffer_length )\n\t{\n\t\t/*\thuh?\t*/\n\t\tbuffer_length = bytes_read;\n\t}\n\t/*\tnow try to do the loading\t*/\n\ttex_ID = SOIL_direct_load_ETC1_from_memory(\n\t\t(const unsigned char *const)buffer, (int)buffer_length,\n\t\treuse_texture_ID, flags );\n\tSOIL_free_image_data( buffer );\n\treturn tex_ID;\n}\n\nint query_NPOT_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_NPOT_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif( (0 == SOIL_GL_ExtensionSupported( \"GL_ARB_texture_non_power_of_two\" ) ) &&\n\t\t\t(0 == SOIL_GL_ExtensionSupported( \"GL_OES_texture_npot\" ) ) &&\n\t\t\t!isAtLeastGL3()\n\t\t  )\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_NPOT_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\t/*\tit's there!\t*/\n\t\t\thas_NPOT_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\n\t\t#if defined( __emscripten__ ) || defined( EMSCRIPTEN )\n\t\thas_NPOT_capability = SOIL_CAPABILITY_PRESENT;\n\t\t#endif\n\t}\n\t/*\tlet the user know if we can do non-power-of-two textures or not\t*/\n\treturn has_NPOT_capability;\n}\n\nint query_tex_rectangle_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_tex_rectangle_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif(\n\t\t\t(0 == SOIL_GL_ExtensionSupported( \"GL_ARB_texture_rectangle\" ) ) &&\n\t\t\t(0 == SOIL_GL_ExtensionSupported( \"GL_EXT_texture_rectangle\" ) ) &&\n\t\t\t(0 == SOIL_GL_ExtensionSupported( \"GL_NV_texture_rectangle\" ) ) &&\n\t\t\t!isAtLeastGL3() )\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_tex_rectangle_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\t/*\tit's there!\t*/\n\t\t\thas_tex_rectangle_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\t}\n\t/*\tlet the user know if we can do texture rectangles or not\t*/\n\treturn has_tex_rectangle_capability;\n}\n\nint query_cubemap_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_cubemap_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif(\n\t\t\t(0 == SOIL_GL_ExtensionSupported( \"GL_ARB_texture_cube_map\" ) ) &&\n\t\t\t(0 == SOIL_GL_ExtensionSupported( \"GL_EXT_texture_cube_map\" ) ) &&\n\t\t\t!isAtLeastGL3()\n\t\t  )\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_cubemap_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\t/*\tit's there!\t*/\n\t\t\thas_cubemap_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\t}\n\t/*\tlet the user know if we can do cubemaps or not\t*/\n\treturn has_cubemap_capability;\n}\n\nstatic P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC get_glCompressedTexImage2D_addr()\n{\n\t/*\tand find the address of the extension function\t*/\n\tP_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = NULL;\n\n#if defined( SOIL_PLATFORM_WIN32 ) || defined( SOIL_PLATFORM_OSX ) || defined( SOIL_X11_PLATFORM )\n\text_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)SOIL_GL_GetProcAddress( \"glCompressedTexImage2D\" );\n#else\n\text_addr = (P_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC)&glCompressedTexImage2D;\n#endif\n\n\treturn ext_addr;\n}\n\nint query_DXT_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_DXT_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif (\t0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\t\"GL_EXT_texture_compression_s3tc\" )  &&\n\t\t\t\t0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\t\"WEBGL_compressed_texture_s3tc \") &&\n\t\t\t\t0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\t\"WEBKIT_WEBGL_compressed_texture_s3tc\") &&\n\t\t\t\t0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\t\"MOZ_WEBGL_compressed_texture_s3tc\"\n\t\t\t\t)\n\t\t\t)\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_DXT_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\tP_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = get_glCompressedTexImage2D_addr();\n\n\t\t\t/*\tFlag it so no checks needed later\t*/\n\t\t\tif( NULL == ext_addr )\n\t\t\t{\n\t\t\t\t/*\thmm, not good!!  This should not happen, but does on my\n\t\t\t\t\tlaptop's VIA chipset.  The GL_EXT_texture_compression_s3tc\n\t\t\t\t\tspec requires that ARB_texture_compression be present too.\n\t\t\t\t\tthis means I can upload and have the OpenGL drive do the\n\t\t\t\t\tconversion, but I can't use my own routines or load DDS files\n\t\t\t\t\tfrom disk and upload them directly [8^(\t*/\n\t\t\t\thas_DXT_capability = SOIL_CAPABILITY_NONE;\n\t\t\t} else\n\t\t\t{\n\t\t\t\t/*\tall's well!\t*/\n\t\t\t\tsoilGlCompressedTexImage2D = ext_addr;\n\t\t\t\thas_DXT_capability = SOIL_CAPABILITY_PRESENT;\n\t\t\t}\n\t\t}\n\t}\n\t/*\tlet the user know if we can do DXT or not\t*/\n\treturn has_DXT_capability;\n}\n\nint query_3Dc_capability(void) {\n\t/*\tcheck for the capability\t*/\n\tif (has_3Dc_capability == SOIL_CAPABILITY_UNKNOWN)\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif (0 == SOIL_GL_ExtensionSupported(\n\t\t\t\"ARB_texture_compression_rgtc\") &&\n\t\t\t0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\"GL_ARB_texture_compression_rgtc\") &&\n\t\t\t0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\"GL_EXT_texture_compression_rgtc\")\n\t\t\t) {\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_3Dc_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\tP_SOIL_GLCOMPRESSEDTEXIMAGE2DPROC ext_addr = get_glCompressedTexImage2D_addr();\n\n\t\t\t/*\tFlag it so no checks needed later\t*/\n\t\t\tif (NULL == ext_addr)\n\t\t\t{\n\t\t\t\t/*\thmm, not good!!  This should not happen, but does on my\n\t\t\t\t\tlaptop's VIA chipset.  The GL_EXT_texture_compression_s3tc\n\t\t\t\t\tspec requires that ARB_texture_compression be present too.\n\t\t\t\t\tthis means I can upload and have the OpenGL drive do the\n\t\t\t\t\tconversion, but I can't use my own routines or load DDS files\n\t\t\t\t\tfrom disk and upload them directly [8^(\t*/\n\t\t\t\thas_3Dc_capability = SOIL_CAPABILITY_NONE;\n\t\t\t} else\n\t\t\t{\n\t\t\t\t/*\tall's well!\t*/\n\t\t\t\tsoilGlCompressedTexImage2D = ext_addr;\n\t\t\t\thas_3Dc_capability = SOIL_CAPABILITY_PRESENT;\n\t\t\t}\n\t\t}\n\t}\n\t/*\tlet the user know if we can do DXT or not\t*/\n\treturn has_3Dc_capability;\n}\n\nint query_PVR_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_PVR_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif (0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\"GL_IMG_texture_compression_pvrtc\" ) )\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_PVR_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\tif ( NULL == soilGlCompressedTexImage2D ) {\n\t\t\t\tsoilGlCompressedTexImage2D = get_glCompressedTexImage2D_addr();\n\t\t\t}\n\n\t\t\t/*\tit's there!\t*/\n\t\t\thas_PVR_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\t}\n\t/*\tlet the user know if we can do cubemaps or not\t*/\n\treturn has_PVR_capability;\n}\n\nint query_BGRA8888_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_BGRA8888_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif (0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\"GL_IMG_texture_format_BGRA8888\" ) )\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_BGRA8888_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\t/*\tit's there!\t*/\n\t\t\thas_BGRA8888_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\t}\n\t/*\tlet the user know if we can do cubemaps or not\t*/\n\treturn has_BGRA8888_capability;\n}\n\nint query_sRGB_capability( void )\n{\n\tif ( has_sRGB_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\tif (0 == SOIL_GL_ExtensionSupported( \"GL_EXT_texture_sRGB\" ) &&\n\t\t\t0 == SOIL_GL_ExtensionSupported( \"GL_EXT_sRGB\" ) &&\n\t\t\t0 == SOIL_GL_ExtensionSupported( \"EXT_sRGB\" ) &&\n\t\t\t!isAtLeastGL3()\n\t\t   )\n\t\t{\n\t\t\thas_sRGB_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\thas_sRGB_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\t}\n\n\treturn has_sRGB_capability;\n}\n\nint query_ETC1_capability( void )\n{\n\t/*\tcheck for the capability\t*/\n\tif( has_ETC1_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\t/*\twe haven't yet checked for the capability, do so\t*/\n\t\tif (0 == SOIL_GL_ExtensionSupported(\n\t\t\t\t\"GL_OES_compressed_ETC1_RGB8_texture\" ) )\n\t\t{\n\t\t\t/*\tnot there, flag the failure\t*/\n\t\t\thas_ETC1_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\tif ( NULL == soilGlCompressedTexImage2D ) {\n\t\t\t\tsoilGlCompressedTexImage2D = get_glCompressedTexImage2D_addr();\n\t\t\t}\n\n\t\t\t/*\tit's there!\t*/\n\t\t\thas_ETC1_capability = SOIL_CAPABILITY_PRESENT;\n\t\t}\n\t}\n\t/*\tlet the user know if we can do cubemaps or not\t*/\n\treturn has_ETC1_capability;\n}\n\nint query_gen_mipmap_capability( void )\n{\n\t/* check for the capability   */\n\tP_SOIL_GLGENERATEMIPMAPPROC ext_addr = NULL;\n\n\tif( has_gen_mipmap_capability == SOIL_CAPABILITY_UNKNOWN )\n\t{\n\t\tif (\t0 == SOIL_GL_ExtensionSupported( \"GL_ARB_framebuffer_object\" ) &&\n\t\t\t\t0 == SOIL_GL_ExtensionSupported( \"GL_EXT_framebuffer_object\" ) &&\n\t\t\t\t0 == SOIL_GL_ExtensionSupported( \"GL_OES_framebuffer_object\" ) &&\n\t\t\t\t!isAtLeastGL3()\n\t\t   )\n\t\t{\n\t\t\t/* not there, flag the failure */\n\t\t\thas_gen_mipmap_capability = SOIL_CAPABILITY_NONE;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t#if !defined( SOIL_GLES1 ) && !defined( SOIL_GLES2 )\n\n\t\t\text_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress(\"glGenerateMipmap\");\n\n\t\t\tif(ext_addr == NULL)\n\t\t\t{\n\t\t\t\text_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress(\"glGenerateMipmapEXT\");\n\t\t\t}\n\n\t\t\t#elif !defined( SOIL_NO_EGL )\n\n\t\t\text_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress(\"glGenerateMipmapOES\");\n\n\t\t\tif(ext_addr == NULL)\n\t\t\t{\n\t\t\t\text_addr = (P_SOIL_GLGENERATEMIPMAPPROC)SOIL_GL_GetProcAddress(\"glGenerateMipmap\");\n\t\t\t}\n\n\t\t\t#elif defined( SOIL_GLES2 )\n\t\t\t\text_addr = \t&glGenerateMipmap;\n\t\t\t#else /** SOIL_GLES1 */\n\t\t\t\text_addr = &glGenerateMipmapOES;\n\t\t\t#endif\n\t\t}\n\n\t\tif(ext_addr == NULL)\n\t\t{\n\t\t\t/* this should never happen */\n\t\t\thas_gen_mipmap_capability = SOIL_CAPABILITY_NONE;\n\t\t} else\n\t\t{\n\t\t\t/* it's there! */\n\t\t\thas_gen_mipmap_capability = SOIL_CAPABILITY_PRESENT;\n\t\t\tsoilGlGenerateMipmap = ext_addr;\n\t\t}\n\t}\n\n\treturn has_gen_mipmap_capability;\n}\n"
  },
  {
    "path": "lib/SOIL2/SOIL2.h",
    "content": "/**\n\t@mainpage SOIL2\n\n\tFork by Martin Lucas Golini\n\n\tOriginal author Jonathan Dummer\n\t2007-07-26-10.36\n\n\tSimple OpenGL Image Library 2\n\n\tA tiny c library for uploading images as\n\ttextures into OpenGL.  Also saving and\n\tloading of images is supported.\n\n\tI'm using Sean's Tool Box image loader as a base:\n\thttp://www.nothings.org/\n\n\tI'm upgrading it to load TGA and DDS files, and a direct\n\tpath for loading DDS files straight into OpenGL textures,\n\twhen applicable.\n\n\tImage Formats:\n\t- BMP\t\tload & save\n\t- TGA\t\tload & save\n\t- DDS\t\tload & save\n\t- PNG\t\tload & save\n\t- JPG\t\tload & save\n\t- QOI\t\tload & save\n\t- PSD\t\tload\n\t- HDR\t\tload\n\t- PIC\t\tload\n\n\tOpenGL Texture Features:\n\t- resample to power-of-two sizes\n\t- MIPmap generation\n\t- compressed texture S3TC formats (if supported)\n\t- can pre-multiply alpha for you, for better compositing\n\t- can flip image about the y-axis (except pre-compressed DDS files)\n\n\tThanks to:\n\t* Sean Barret - for the awesome stb_image\n\t* Dan Venkitachalam - for finding some non-compliant DDS files, and patching some explicit casts\n\t* everybody at gamedev.net\n**/\n\n#ifndef HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY\n#define HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#define SOIL_MAJOR_VERSION 1\n#define SOIL_MINOR_VERSION 3\n#define SOIL_PATCH_LEVEL 0\n\n#define SOIL_VERSION_NUM( X, Y, Z ) ( (X)*1000 + (Y)*100 + ( Z ) )\n\n#define SOIL_COMPILED_VERSION \\\n\tSOIL_VERSION_NUM( SOIL_MAJOR_VERSION, SOIL_MINOR_VERSION, SOIL_PATCH_LEVEL )\n\n#define SOIL_VERSION_ATLEAST( X, Y, Z ) ( SOIL_COMPILED_VERSION >= SOIL_VERSION_NUM( X, Y, Z ) )\n\n\tunsigned long SOIL_version();\n\n/**\n\tThe format of images that may be loaded (force_channels).\n\tSOIL_LOAD_AUTO leaves the image in whatever format it was found.\n\tSOIL_LOAD_L forces the image to load as Luminous (greyscale)\n\tSOIL_LOAD_LA forces the image to load as Luminous with Alpha\n\tSOIL_LOAD_RGB forces the image to load as Red Green Blue\n\tSOIL_LOAD_RGBA forces the image to load as Red Green Blue Alpha\n**/\nenum\n{\n\tSOIL_LOAD_AUTO = 0,\n\tSOIL_LOAD_L = 1,\n\tSOIL_LOAD_LA = 2,\n\tSOIL_LOAD_RGB = 3,\n\tSOIL_LOAD_RGBA = 4\n};\n\n/**\n\tPassed in as reuse_texture_ID, will cause SOIL to\n\tregister a new texture ID using glGenTextures().\n\tIf the value passed into reuse_texture_ID > 0 then\n\tSOIL will just re-use that texture ID (great for\n\treloading image assets in-game!)\n**/\nenum\n{\n\tSOIL_CREATE_NEW_ID = 0\n};\n\n/**\n\tflags you can pass into SOIL_load_OGL_texture()\n\tand SOIL_create_OGL_texture().\n\t(note that if SOIL_FLAG_DDS_LOAD_DIRECT is used\n\tthe rest of the flags with the exception of\n\tSOIL_FLAG_TEXTURE_REPEATS will be ignored while\n\tloading already-compressed DDS files.)\n\n\tSOIL_FLAG_POWER_OF_TWO: force the image to be POT\n\tSOIL_FLAG_MIPMAPS: generate mipmaps for the texture\n\tSOIL_FLAG_TEXTURE_REPEATS: otherwise will clamp\n\tSOIL_FLAG_MULTIPLY_ALPHA: for using (GL_ONE,GL_ONE_MINUS_SRC_ALPHA) blending\n\tSOIL_FLAG_INVERT_Y: flip the image vertically\n\tSOIL_FLAG_COMPRESS_TO_DXT: if the card can display them, will convert RGB to DXT1, RGBA to DXT5\n\tSOIL_FLAG_DDS_LOAD_DIRECT: will load DDS files directly without _ANY_ additional processing ( if supported )\n\tSOIL_FLAG_NTSC_SAFE_RGB: clamps RGB components to the range [16,235]\n\tSOIL_FLAG_CoCg_Y: Google YCoCg; RGB=>CoYCg, RGBA=>CoCgAY\n\tSOIL_FLAG_TEXTURE_RECTANGE: uses ARB_texture_rectangle ; pixel indexed & no repeat or MIPmaps or cubemaps\n\tSOIL_FLAG_PVR_LOAD_DIRECT: will load PVR files directly without _ANY_ additional processing ( if supported )\n**/\nenum\n{\n\tSOIL_FLAG_POWER_OF_TWO = 1,\n\tSOIL_FLAG_MIPMAPS = 2,\n\tSOIL_FLAG_TEXTURE_REPEATS = 4,\n\tSOIL_FLAG_MULTIPLY_ALPHA = 8,\n\tSOIL_FLAG_INVERT_Y = 16,\n\tSOIL_FLAG_COMPRESS_TO_DXT = 32,\n\tSOIL_FLAG_DDS_LOAD_DIRECT = 64,\n\tSOIL_FLAG_NTSC_SAFE_RGB = 128,\n\tSOIL_FLAG_CoCg_Y = 256,\n\tSOIL_FLAG_TEXTURE_RECTANGLE = 512,\n\tSOIL_FLAG_PVR_LOAD_DIRECT = 1024,\n\tSOIL_FLAG_ETC1_LOAD_DIRECT = 2048,\n\tSOIL_FLAG_GL_MIPMAPS = 4096,\n\tSOIL_FLAG_SRGB_COLOR_SPACE = 8192\n};\n\n/**\n\tThe types of images that may be saved.\n\t(TGA supports uncompressed RGB / RGBA)\n\t(BMP supports uncompressed RGB)\n\t(DDS supports DXT1 and DXT5)\n\t(PNG supports RGB / RGBA)\n**/\nenum\n{\n\tSOIL_SAVE_TYPE_TGA = 0,\n\tSOIL_SAVE_TYPE_BMP = 1,\n\tSOIL_SAVE_TYPE_PNG = 2,\n\tSOIL_SAVE_TYPE_DDS = 3,\n\tSOIL_SAVE_TYPE_JPG = 4,\n\tSOIL_SAVE_TYPE_QOI = 5\n};\n\n/**\n\tDefines the order of faces in a DDS cubemap.\n\tI recommend that you use the same order in single\n\timage cubemap files, so they will be interchangeable\n\twith DDS cubemaps when using SOIL.\n**/\n#define SOIL_DDS_CUBEMAP_FACE_ORDER \"EWUDNS\"\n\n/**\n\tThe types of internal fake HDR representations\n\n\tSOIL_HDR_RGBE:\t\tRGB * pow( 2.0, A - 128.0 )\n\tSOIL_HDR_RGBdivA:\tRGB / A\n\tSOIL_HDR_RGBdivA2:\tRGB / (A*A)\n**/\nenum\n{\n\tSOIL_HDR_RGBE = 0,\n\tSOIL_HDR_RGBdivA = 1,\n\tSOIL_HDR_RGBdivA2 = 2\n};\n\n/**\n\tLoads an image from disk into an OpenGL texture.\n\t\\param filename the name of the file to upload as a texture\n\t\\param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_texture\n\t(\n\t\tconst char *filename,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tLoads 6 images from disk into an OpenGL cubemap texture.\n\t\\param x_pos_file the name of the file to upload as the +x cube face\n\t\\param x_neg_file the name of the file to upload as the -x cube face\n\t\\param y_pos_file the name of the file to upload as the +y cube face\n\t\\param y_neg_file the name of the file to upload as the -y cube face\n\t\\param z_pos_file the name of the file to upload as the +z cube face\n\t\\param z_neg_file the name of the file to upload as the -z cube face\n\t\\param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_cubemap\n\t(\n\t\tconst char *x_pos_file,\n\t\tconst char *x_neg_file,\n\t\tconst char *y_pos_file,\n\t\tconst char *y_neg_file,\n\t\tconst char *z_pos_file,\n\t\tconst char *z_neg_file,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tLoads 1 image from disk and splits it into an OpenGL cubemap texture.\n\t\\param filename the name of the file to upload as a texture\n\t\\param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc.\n\t\\param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_single_cubemap\n\t(\n\t\tconst char *filename,\n\t\tconst char face_order[6],\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tLoads an HDR image from disk into an OpenGL texture.\n\t\\param filename the name of the file to upload as a texture\n\t\\param fake_HDR_format SOIL_HDR_RGBE, SOIL_HDR_RGBdivA, SOIL_HDR_RGBdivA2\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_HDR_texture\n\t(\n\t\tconst char *filename,\n\t\tint fake_HDR_format,\n\t\tint rescale_to_max,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tLoads an image from RAM into an OpenGL texture.\n\t\\param buffer the image data in RAM just as if it were still in a file\n\t\\param buffer_length the size of the buffer in bytes\n\t\\param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_texture_from_memory\n\t(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tLoads 6 images from memory into an OpenGL cubemap texture.\n\t\\param x_pos_buffer the image data in RAM to upload as the +x cube face\n\t\\param x_pos_buffer_length the size of the above buffer\n\t\\param x_neg_buffer the image data in RAM to upload as the +x cube face\n\t\\param x_neg_buffer_length the size of the above buffer\n\t\\param y_pos_buffer the image data in RAM to upload as the +x cube face\n\t\\param y_pos_buffer_length the size of the above buffer\n\t\\param y_neg_buffer the image data in RAM to upload as the +x cube face\n\t\\param y_neg_buffer_length the size of the above buffer\n\t\\param z_pos_buffer the image data in RAM to upload as the +x cube face\n\t\\param z_pos_buffer_length the size of the above buffer\n\t\\param z_neg_buffer the image data in RAM to upload as the +x cube face\n\t\\param z_neg_buffer_length the size of the above buffer\n\t\\param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_cubemap_from_memory\n\t(\n\t\tconst unsigned char *const x_pos_buffer,\n\t\tint x_pos_buffer_length,\n\t\tconst unsigned char *const x_neg_buffer,\n\t\tint x_neg_buffer_length,\n\t\tconst unsigned char *const y_pos_buffer,\n\t\tint y_pos_buffer_length,\n\t\tconst unsigned char *const y_neg_buffer,\n\t\tint y_neg_buffer_length,\n\t\tconst unsigned char *const z_pos_buffer,\n\t\tint z_pos_buffer_length,\n\t\tconst unsigned char *const z_neg_buffer,\n\t\tint z_neg_buffer_length,\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tLoads 1 image from RAM and splits it into an OpenGL cubemap texture.\n\t\\param buffer the image data in RAM just as if it were still in a file\n\t\\param buffer_length the size of the buffer in bytes\n\t\\param face_order the order of the faces in the file, any combination of NSWEUD, for North, South, Up, etc.\n\t\\param force_channels 0-image format, 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_load_OGL_single_cubemap_from_memory\n\t(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tconst char face_order[6],\n\t\tint force_channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tCreates a 2D OpenGL texture from raw image data.  Note that the raw data is\n\t_NOT_ freed after the upload (so the user can load various versions).\n\t\\param data the raw data to be uploaded as an OpenGL texture\n\t\\param width the pointer of the width of the image in pixels ( if the texture size change, width will be overrided with the new width )\n\t\\param height the pointer of the height of the image in pixels ( if the texture size change, height will be overrided with the new height )\n\t\\param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_create_OGL_texture\n\t(\n\t\tconst unsigned char *const data,\n\t\tint *width, int *height, int channels,\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tCreates an OpenGL cubemap texture by splitting up 1 image into 6 parts.\n\t\\param data the raw data to be uploaded as an OpenGL texture\n\t\\param width the width of the image in pixels\n\t\\param height the height of the image in pixels\n\t\\param channels the number of channels: 1-luminous, 2-luminous/alpha, 3-RGB, 4-RGBA\n\t\\param face_order the order of the faces in the file, and combination of NSWEUD, for North, South, Up, etc.\n\t\\param reuse_texture_ID 0-generate a new texture ID, otherwise reuse the texture ID (overwriting the old texture)\n\t\\param flags can be any of SOIL_FLAG_POWER_OF_TWO | SOIL_FLAG_MIPMAPS | SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MULTIPLY_ALPHA | SOIL_FLAG_INVERT_Y | SOIL_FLAG_COMPRESS_TO_DXT | SOIL_FLAG_DDS_LOAD_DIRECT\n\t\\return 0-failed, otherwise returns the OpenGL texture handle\n**/\nunsigned int\n\tSOIL_create_OGL_single_cubemap\n\t(\n\t\tconst unsigned char *const data,\n\t\tint width, int height, int channels,\n\t\tconst char face_order[6],\n\t\tunsigned int reuse_texture_ID,\n\t\tunsigned int flags\n\t);\n\n/**\n\tCaptures the OpenGL window (RGB) and saves it to disk\n\t\\return 0 if it failed, otherwise returns 1\n**/\nint\n\tSOIL_save_screenshot\n\t(\n\t\tconst char *filename,\n\t\tint image_type,\n\t\tint x, int y,\n\t\tint width, int height\n\t);\n\n/**\n\tLoads an image from disk into an array of unsigned chars.\n\tNote that *channels return the original channel count of the\n\timage.  If force_channels was other than SOIL_LOAD_AUTO,\n\tthe resulting image has force_channels, but *channels may be\n\tdifferent (if the original image had a different channel\n\tcount).\n\t\\return 0 if failed, otherwise returns 1\n**/\nunsigned char*\n\tSOIL_load_image\n\t(\n\t\tconst char *filename,\n\t\tint *width, int *height, int *channels,\n\t\tint force_channels\n\t);\n\n/**\n\tLoads an image from memory into an array of unsigned chars.\n\tNote that *channels return the original channel count of the\n\timage.  If force_channels was other than SOIL_LOAD_AUTO,\n\tthe resulting image has force_channels, but *channels may be\n\tdifferent (if the original image had a different channel\n\tcount).\n\t\\return 0 if failed, otherwise returns 1\n**/\nunsigned char*\n\tSOIL_load_image_from_memory\n\t(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tint *width, int *height, int *channels,\n\t\tint force_channels\n\t);\n\n/**\n\tSaves an image from an array of unsigned chars (RGBA) to disk\n\t\\param quality parameter only used for SOIL_SAVE_TYPE_JPG files, values accepted between 0 and 100.\n\t\\return 0 if failed, otherwise returns 1\n**/\nint\n\tSOIL_save_image_quality\n\t(\n\t\tconst char *filename,\n\t\tint image_type,\n\t\tint width, int height, int channels,\n\t\tconst unsigned char *const data,\n\t\tint quality\n\t);\n\nint\n\tSOIL_save_image\n\t(\n\t\tconst char *filename,\n\t\tint image_type,\n\t\tint width, int height, int channels,\n\t\tconst unsigned char *const data\n\t);\n\n\n/**\n\tSaves an image from an array of unsigned chars (RGBA) to a memory buffer in the target format.\n\tFree the buffer with SOIL_free_image_data.\n\t\\param quality parameter only used for SOIL_SAVE_TYPE_JPG files, values accepted between 0 and 100.\n\t\\param imageSize returns the byte count of the image.\n\t\\return 0 if failed, otherwise returns 1\n**/\n\nunsigned char*\nSOIL_write_image_to_memory_quality\n(\n\tint image_type,\n\tint width, int height, int channels,\n\tconst unsigned char* const data,\n\tint quality,\n\tint* imageSize\n);\n\nunsigned char*\nSOIL_write_image_to_memory\n(\n\tint image_type,\n\tint width, int height, int channels,\n\tconst unsigned char* const data,\n\tint* imageSize\n);\n\n/**\n\tFrees the image data (note, this is just C's \"free()\"...this function is\n\tpresent mostly so C++ programmers don't forget to use \"free()\" and call\n\t\"delete []\" instead [8^)\n**/\nvoid\n\tSOIL_free_image_data\n\t(\n\t\tunsigned char *img_data\n\t);\n\n/**\n\tThis function resturn a pointer to a string describing the last thing\n\tthat happened inside SOIL.  It can be used to determine why an image\n\tfailed to load.\n**/\nconst char*\n\tSOIL_last_result\n\t(\n\t\tvoid\n\t);\n\n/** @return The address of the GL function proc, or NULL if the function is not found. */\nvoid *\n\tSOIL_GL_GetProcAddress\n\t(\n\t\tconst char *proc\n\t);\n\n/** @return 1 if an OpenGL extension is supported for the current context, 0 otherwise. */\nint\n\tSOIL_GL_ExtensionSupported\n\t(\n\t\tconst char *extension\n\t);\n\n/** Loads the DDS texture directly to the GPU memory ( if supported ) */\nunsigned int SOIL_direct_load_DDS(\n\t\tconst char *filename,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap );\n\n/** Loads the DDS texture directly to the GPU memory ( if supported ) */\nunsigned int SOIL_direct_load_DDS_from_memory(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap );\n\n/** Loads the PVR texture directly to the GPU memory ( if supported ) */\nunsigned int SOIL_direct_load_PVR(\n\t\tconst char *filename,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap );\n\n/** Loads the PVR texture directly to the GPU memory ( if supported ) */\nunsigned int SOIL_direct_load_PVR_from_memory(\n\t\tconst unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags,\n\t\tint loading_as_cubemap );\n\n/** Loads the PVR texture directly to the GPU memory ( if supported ) */\nunsigned int SOIL_direct_load_ETC1(const char *filename,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags );\n\n/** Loads the PVR texture directly to the GPU memory ( if supported ) */\nunsigned int SOIL_direct_load_ETC1_from_memory(const unsigned char *const buffer,\n\t\tint buffer_length,\n\t\tunsigned int reuse_texture_ID,\n\t\tint flags );\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* HEADER_SIMPLE_OPENGL_IMAGE_LIBRARY\t*/\n"
  },
  {
    "path": "lib/SOIL2/image_DXT.c",
    "content": "/*\n\tJonathan Dummer\n\t2007-07-31-10.32\n\n\tsimple DXT compression / decompression code\n\n\tpublic domain\n*/\n\n#include \"image_DXT.h\"\n#include <math.h>\n#include <stdlib.h>\n#include <string.h>\n#include <stdio.h>\n\n/*\tset this =1 if you want to use the covarince matrix method...\n\twhich is better than my method of using standard deviations\n\toverall, except on the infintesimal chance that the power\n\tmethod fails for finding the largest eigenvector\t*/\n#define USE_COV_MAT\t1\n\n/********* Function Prototypes *********/\n/*\n\tTakes a 4x4 block of pixels and compresses it into 8 bytes\n\tin DXT1 format (color only, no alpha).  Speed is valued\n\tover prettyness, at least for now.\n*/\nvoid compress_DDS_color_block(\n\t\t\t\tint channels,\n\t\t\t\tconst unsigned char *const uncompressed,\n\t\t\t\tunsigned char compressed[8] );\n/*\n\tTakes a 4x4 block of pixels and compresses the alpha\n\tcomponent it into 8 bytes for use in DXT5 DDS files.\n\tSpeed is valued over prettyness, at least for now.\n*/\nvoid compress_DDS_alpha_block(\n\t\t\t\tconst unsigned char *const uncompressed,\n\t\t\t\tunsigned char compressed[8] );\n\n/********* Actual Exposed Functions *********/\nint\n\tsave_image_as_DDS\n\t(\n\t\tconst char *filename,\n\t\tint width, int height, int channels,\n\t\tconst unsigned char *const data\n\t)\n{\n\t/*\tvariables\t*/\n\tFILE *fout;\n\tunsigned char *DDS_data;\n\tDDS_header header;\n\tint DDS_size;\n\t/*\terror check\t*/\n\tif( (NULL == filename) ||\n\t\t(width < 1) || (height < 1) ||\n\t\t(channels < 1) || (channels > 4) ||\n\t\t(data == NULL ) )\n\t{\n\t\treturn 0;\n\t}\n\t/*\tConvert the image\t*/\n\tif( (channels & 1) == 1 )\n\t{\n\t\t/*\tno alpha, just use DXT1\t*/\n\t\tDDS_data = convert_image_to_DXT1( data, width, height, channels, &DDS_size );\n\t} else\n\t{\n\t\t/*\thas alpha, so use DXT5\t*/\n\t\tDDS_data = convert_image_to_DXT5( data, width, height, channels, &DDS_size );\n\t}\n\t/*\tsave it\t*/\n\tmemset( &header, 0, sizeof( DDS_header ) );\n\theader.dwMagic = ('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24);\n\theader.dwSize = 124;\n\theader.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT | DDSD_LINEARSIZE;\n\theader.dwWidth = width;\n\theader.dwHeight = height;\n\theader.dwPitchOrLinearSize = DDS_size;\n\theader.sPixelFormat.dwSize = 32;\n\theader.sPixelFormat.dwFlags = DDPF_FOURCC;\n\tif( (channels & 1) == 1 )\n\t{\n\t\theader.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('1' << 24);\n\t} else\n\t{\n\t\theader.sPixelFormat.dwFourCC = ('D' << 0) | ('X' << 8) | ('T' << 16) | ('5' << 24);\n\t}\n\theader.sCaps.dwCaps1 = DDSCAPS_TEXTURE;\n\t/*\twrite it out\t*/\n\tfout = fopen( filename, \"wb\");\n\tfwrite( &header, sizeof( DDS_header ), 1, fout );\n\tfwrite( DDS_data, 1, DDS_size, fout );\n\tfclose( fout );\n\t/*\tdone\t*/\n\tfree( DDS_data );\n\treturn 1;\n}\n\nunsigned char* convert_image_to_DXT1(\n\t\tconst unsigned char *const uncompressed,\n\t\tint width, int height, int channels,\n\t\tint *out_size )\n{\n\tunsigned char *compressed;\n\tint i, j, x, y;\n\tunsigned char ublock[16*3];\n\tunsigned char cblock[8];\n\tint index = 0, chan_step = 1;\n\t/*\terror check\t*/\n\t*out_size = 0;\n\tif( (width < 1) || (height < 1) ||\n\t\t(NULL == uncompressed) ||\n\t\t(channels < 1) || (channels > 4) )\n\t{\n\t\treturn NULL;\n\t}\n\t/*\tfor channels == 1 or 2, I do not step forward for R,G,B values\t*/\n\tif( channels < 3 )\n\t{\n\t\tchan_step = 0;\n\t}\n\t/*\tget the RAM for the compressed image\n\t\t(8 bytes per 4x4 pixel block)\t*/\n\t*out_size = ((width+3) >> 2) * ((height+3) >> 2) * 8;\n\tcompressed = (unsigned char*)malloc( *out_size );\n\t/*\tgo through each block\t*/\n\tfor( j = 0; j < height; j += 4 )\n\t{\n\t\tfor( i = 0; i < width; i += 4 )\n\t\t{\n\t\t\t/*\tcopy this block into a new one\t*/\n\t\t\tint idx = 0;\n\t\t\tint mx = 4, my = 4;\n\t\t\tif( j+4 >= height )\n\t\t\t{\n\t\t\t\tmy = height - j;\n\t\t\t}\n\t\t\tif( i+4 >= width )\n\t\t\t{\n\t\t\t\tmx = width - i;\n\t\t\t}\n\t\t\tfor( y = 0; y < my; ++y )\n\t\t\t{\n\t\t\t\tfor( x = 0; x < mx; ++x )\n\t\t\t\t{\n\t\t\t\t\tublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels];\n\t\t\t\t\tublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step];\n\t\t\t\t\tublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step];\n\t\t\t\t}\n\t\t\t\tfor( x = mx; x < 4; ++x )\n\t\t\t\t{\n\t\t\t\t\tublock[idx++] = ublock[0];\n\t\t\t\t\tublock[idx++] = ublock[1];\n\t\t\t\t\tublock[idx++] = ublock[2];\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor( y = my; y < 4; ++y )\n\t\t\t{\n\t\t\t\tfor( x = 0; x < 4; ++x )\n\t\t\t\t{\n\t\t\t\t\tublock[idx++] = ublock[0];\n\t\t\t\t\tublock[idx++] = ublock[1];\n\t\t\t\t\tublock[idx++] = ublock[2];\n\t\t\t\t}\n\t\t\t}\n\t\t\t/*\tcompress the block\t*/\n\t\t\tcompress_DDS_color_block( 3, ublock, cblock );\n\t\t\t/*\tcopy the data from the block into the main block\t*/\n\t\t\tfor( x = 0; x < 8; ++x )\n\t\t\t{\n\t\t\t\tcompressed[index++] = cblock[x];\n\t\t\t}\n\t\t}\n\t}\n\treturn compressed;\n}\n\nunsigned char* convert_image_to_DXT5(\n\t\tconst unsigned char *const uncompressed,\n\t\tint width, int height, int channels,\n\t\tint *out_size )\n{\n\tunsigned char *compressed;\n\tint i, j, x, y;\n\tunsigned char ublock[16*4];\n\tunsigned char cblock[8];\n\tint index = 0, chan_step = 1;\n\tint has_alpha;\n\t/*\terror check\t*/\n\t*out_size = 0;\n\tif( (width < 1) || (height < 1) ||\n\t\t(NULL == uncompressed) ||\n\t\t(channels < 1) || ( channels > 4) )\n\t{\n\t\treturn NULL;\n\t}\n\t/*\tfor channels == 1 or 2, I do not step forward for R,G,B vales\t*/\n\tif( channels < 3 )\n\t{\n\t\tchan_step = 0;\n\t}\n\t/*\t# channels = 1 or 3 have no alpha, 2 & 4 do have alpha\t*/\n\thas_alpha = 1 - (channels & 1);\n\t/*\tget the RAM for the compressed image\n\t\t(16 bytes per 4x4 pixel block)\t*/\n\t*out_size = ((width+3) >> 2) * ((height+3) >> 2) * 16;\n\tcompressed = (unsigned char*)malloc( *out_size );\n\t/*\tgo through each block\t*/\n\tfor( j = 0; j < height; j += 4 )\n\t{\n\t\tfor( i = 0; i < width; i += 4 )\n\t\t{\n\t\t\t/*\tlocal variables, and my block counter\t*/\n\t\t\tint idx = 0;\n\t\t\tint mx = 4, my = 4;\n\t\t\tif( j+4 >= height )\n\t\t\t{\n\t\t\t\tmy = height - j;\n\t\t\t}\n\t\t\tif( i+4 >= width )\n\t\t\t{\n\t\t\t\tmx = width - i;\n\t\t\t}\n\t\t\tfor( y = 0; y < my; ++y )\n\t\t\t{\n\t\t\t\tfor( x = 0; x < mx; ++x )\n\t\t\t\t{\n\t\t\t\t\tublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels];\n\t\t\t\t\tublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step];\n\t\t\t\t\tublock[idx++] = uncompressed[(j+y)*width*channels+(i+x)*channels+chan_step+chan_step];\n\t\t\t\t\tublock[idx++] =\n\t\t\t\t\t\thas_alpha * uncompressed[(j+y)*width*channels+(i+x)*channels+channels-1]\n\t\t\t\t\t\t+ (1-has_alpha)*255;\n\t\t\t\t}\n\t\t\t\tfor( x = mx; x < 4; ++x )\n\t\t\t\t{\n\t\t\t\t\tublock[idx++] = ublock[0];\n\t\t\t\t\tublock[idx++] = ublock[1];\n\t\t\t\t\tublock[idx++] = ublock[2];\n\t\t\t\t\tublock[idx++] = ublock[3];\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor( y = my; y < 4; ++y )\n\t\t\t{\n\t\t\t\tfor( x = 0; x < 4; ++x )\n\t\t\t\t{\n\t\t\t\t\tublock[idx++] = ublock[0];\n\t\t\t\t\tublock[idx++] = ublock[1];\n\t\t\t\t\tublock[idx++] = ublock[2];\n\t\t\t\t\tublock[idx++] = ublock[3];\n\t\t\t\t}\n\t\t\t}\n\t\t\t/*\tnow compress the alpha block\t*/\n\t\t\tcompress_DDS_alpha_block( ublock, cblock );\n\t\t\t/*\tcopy the data from the compressed alpha block into the main buffer\t*/\n\t\t\tfor( x = 0; x < 8; ++x )\n\t\t\t{\n\t\t\t\tcompressed[index++] = cblock[x];\n\t\t\t}\n\t\t\t/*\tthen compress the color block\t*/\n\t\t\tcompress_DDS_color_block( 4, ublock, cblock );\n\t\t\t/*\tcopy the data from the compressed color block into the main buffer\t*/\n\t\t\tfor( x = 0; x < 8; ++x )\n\t\t\t{\n\t\t\t\tcompressed[index++] = cblock[x];\n\t\t\t}\n\t\t}\n\t}\n\treturn compressed;\n}\n\n/********* Helper Functions *********/\nint convert_bit_range( int c, int from_bits, int to_bits )\n{\n\tint b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1);\n\treturn (b + (b >> from_bits)) >> from_bits;\n}\n\nint rgb_to_565( int r, int g, int b )\n{\n\treturn\n\t\t(convert_bit_range( r, 8, 5 ) << 11) |\n\t\t(convert_bit_range( g, 8, 6 ) << 05) |\n\t\t(convert_bit_range( b, 8, 5 ) << 00);\n}\n\nvoid rgb_888_from_565( unsigned int c, int *r, int *g, int *b )\n{\n\t*r = convert_bit_range( (c >> 11) & 31, 5, 8 );\n\t*g = convert_bit_range( (c >> 05) & 63, 6, 8 );\n\t*b = convert_bit_range( (c >> 00) & 31, 5, 8 );\n}\n\nvoid compute_color_line_STDEV(\n\t\tconst unsigned char *const uncompressed,\n\t\tint channels,\n\t\tfloat point[3], float direction[3] )\n{\n\tconst float inv_16 = 1.0f / 16.0f;\n\tint i;\n\tfloat sum_r = 0.0f, sum_g = 0.0f, sum_b = 0.0f;\n\tfloat sum_rr = 0.0f, sum_gg = 0.0f, sum_bb = 0.0f;\n\tfloat sum_rg = 0.0f, sum_rb = 0.0f, sum_gb = 0.0f;\n\t/*\tcalculate all data needed for the covariance matrix\n\t\t( to compare with _rygdxt code)\t*/\n\tfor( i = 0; i < 16*channels; i += channels )\n\t{\n\t\tsum_r += uncompressed[i+0];\n\t\tsum_rr += uncompressed[i+0] * uncompressed[i+0];\n\t\tsum_g += uncompressed[i+1];\n\t\tsum_gg += uncompressed[i+1] * uncompressed[i+1];\n\t\tsum_b += uncompressed[i+2];\n\t\tsum_bb += uncompressed[i+2] * uncompressed[i+2];\n\t\tsum_rg += uncompressed[i+0] * uncompressed[i+1];\n\t\tsum_rb += uncompressed[i+0] * uncompressed[i+2];\n\t\tsum_gb += uncompressed[i+1] * uncompressed[i+2];\n\t}\n\t/*\tconvert the sums to averages\t*/\n\tsum_r *= inv_16;\n\tsum_g *= inv_16;\n\tsum_b *= inv_16;\n\t/*\tand convert the squares to the squares of the value - avg_value\t*/\n\tsum_rr -= 16.0f * sum_r * sum_r;\n\tsum_gg -= 16.0f * sum_g * sum_g;\n\tsum_bb -= 16.0f * sum_b * sum_b;\n\tsum_rg -= 16.0f * sum_r * sum_g;\n\tsum_rb -= 16.0f * sum_r * sum_b;\n\tsum_gb -= 16.0f * sum_g * sum_b;\n\t/*\tthe point on the color line is the average\t*/\n\tpoint[0] = sum_r;\n\tpoint[1] = sum_g;\n\tpoint[2] = sum_b;\n\t#if USE_COV_MAT\n\t/*\n\t\tThe following idea was from ryg.\n\t\t(https://mollyrocket.com/forums/viewtopic.php?t=392)\n\t\tThe method worked great (less RMSE than mine) most of\n\t\tthe time, but had some issues handling some simple\n\t\tboundary cases, like full green next to full red,\n\t\twhich would generate a covariance matrix like this:\n\n\t\t| 1  -1  0 |\n\t\t| -1  1  0 |\n\t\t| 0   0  0 |\n\n\t\tFor a given starting vector, the power method can\n\t\tgenerate all zeros!  So no starting with {1,1,1}\n\t\tas I was doing!  This kind of error is still a\n\t\tslight posibillity, but will be very rare.\n\t*/\n\t/*\tuse the covariance matrix directly\n\t\t(1st iteration, don't use all 1.0 values!)\t*/\n\tsum_r = 1.0f;\n\tsum_g = 2.718281828f;\n\tsum_b = 3.141592654f;\n\tdirection[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;\n\tdirection[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;\n\tdirection[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;\n\t/*\t2nd iteration, use results from the 1st guy\t*/\n\tsum_r = direction[0];\n\tsum_g = direction[1];\n\tsum_b = direction[2];\n\tdirection[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;\n\tdirection[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;\n\tdirection[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;\n\t/*\t3rd iteration, use results from the 2nd guy\t*/\n\tsum_r = direction[0];\n\tsum_g = direction[1];\n\tsum_b = direction[2];\n\tdirection[0] = sum_r*sum_rr + sum_g*sum_rg + sum_b*sum_rb;\n\tdirection[1] = sum_r*sum_rg + sum_g*sum_gg + sum_b*sum_gb;\n\tdirection[2] = sum_r*sum_rb + sum_g*sum_gb + sum_b*sum_bb;\n\t#else\n\t/*\tuse my standard deviation method\n\t\t(very robust, a tiny bit slower and less accurate)\t*/\n\tdirection[0] = sqrt( sum_rr );\n\tdirection[1] = sqrt( sum_gg );\n\tdirection[2] = sqrt( sum_bb );\n\t/*\twhich has a greater component\t*/\n\tif( sum_gg > sum_rr )\n\t{\n\t\t/*\tgreen has greater component, so base the other signs off of green\t*/\n\t\tif( sum_rg < 0.0f )\n\t\t{\n\t\t\tdirection[0] = -direction[0];\n\t\t}\n\t\tif( sum_gb < 0.0f )\n\t\t{\n\t\t\tdirection[2] = -direction[2];\n\t\t}\n\t} else\n\t{\n\t\t/*\tred has a greater component\t*/\n\t\tif( sum_rg < 0.0f )\n\t\t{\n\t\t\tdirection[1] = -direction[1];\n\t\t}\n\t\tif( sum_rb < 0.0f )\n\t\t{\n\t\t\tdirection[2] = -direction[2];\n\t\t}\n\t}\n\t#endif\n}\n\nvoid LSE_master_colors_max_min(\n\t\tint *cmax, int *cmin,\n\t\tint channels,\n\t\tconst unsigned char *const uncompressed )\n{\n\tint i, j;\n\t/*\tthe master colors\t*/\n\tint c0[3], c1[3];\n\t/*\tused for fitting the line\t*/\n\tfloat sum_x[] = { 0.0f, 0.0f, 0.0f };\n\tfloat sum_x2[] = { 0.0f, 0.0f, 0.0f };\n\tfloat dot_max = 1.0f, dot_min = -1.0f;\n\tfloat vec_len2 = 0.0f;\n\tfloat dot;\n\t/*\terror check\t*/\n\tif( (channels < 3) || (channels > 4) )\n\t{\n\t\treturn;\n\t}\n\tcompute_color_line_STDEV( uncompressed, channels, sum_x, sum_x2 );\n\tvec_len2 = 1.0f / ( 0.00001f +\n\t\t\tsum_x2[0]*sum_x2[0] + sum_x2[1]*sum_x2[1] + sum_x2[2]*sum_x2[2] );\n\t/*\tfinding the max and min vector values\t*/\n\tdot_max =\n\t\t\t(\n\t\t\t\tsum_x2[0] * uncompressed[0] +\n\t\t\t\tsum_x2[1] * uncompressed[1] +\n\t\t\t\tsum_x2[2] * uncompressed[2]\n\t\t\t);\n\tdot_min = dot_max;\n\tfor( i = 1; i < 16; ++i )\n\t{\n\t\tdot =\n\t\t\t(\n\t\t\t\tsum_x2[0] * uncompressed[i*channels+0] +\n\t\t\t\tsum_x2[1] * uncompressed[i*channels+1] +\n\t\t\t\tsum_x2[2] * uncompressed[i*channels+2]\n\t\t\t);\n\t\tif( dot < dot_min )\n\t\t{\n\t\t\tdot_min = dot;\n\t\t} else if( dot > dot_max )\n\t\t{\n\t\t\tdot_max = dot;\n\t\t}\n\t}\n\t/*\tand the offset (from the average location)\t*/\n\tdot = sum_x2[0]*sum_x[0] + sum_x2[1]*sum_x[1] + sum_x2[2]*sum_x[2];\n\tdot_min -= dot;\n\tdot_max -= dot;\n\t/*\tpost multiply by the scaling factor\t*/\n\tdot_min *= vec_len2;\n\tdot_max *= vec_len2;\n\t/*\tOK, build the master colors\t*/\n\tfor( i = 0; i < 3; ++i )\n\t{\n\t\t/*\tcolor 0\t*/\n\t\tc0[i] = (int)(0.5f + sum_x[i] + dot_max * sum_x2[i]);\n\t\tif( c0[i] < 0 )\n\t\t{\n\t\t\tc0[i] = 0;\n\t\t} else if( c0[i] > 255 )\n\t\t{\n\t\t\tc0[i] = 255;\n\t\t}\n\t\t/*\tcolor 1\t*/\n\t\tc1[i] = (int)(0.5f + sum_x[i] + dot_min * sum_x2[i]);\n\t\tif( c1[i] < 0 )\n\t\t{\n\t\t\tc1[i] = 0;\n\t\t} else if( c1[i] > 255 )\n\t\t{\n\t\t\tc1[i] = 255;\n\t\t}\n\t}\n\t/*\tdown_sample (with rounding?)\t*/\n\ti = rgb_to_565( c0[0], c0[1], c0[2] );\n\tj = rgb_to_565( c1[0], c1[1], c1[2] );\n\tif( i > j )\n\t{\n\t\t*cmax = i;\n\t\t*cmin = j;\n\t} else\n\t{\n\t\t*cmax = j;\n\t\t*cmin = i;\n\t}\n}\n\nvoid\n\tcompress_DDS_color_block\n\t(\n\t\tint channels,\n\t\tconst unsigned char *const uncompressed,\n\t\tunsigned char compressed[8]\n\t)\n{\n\t/*\tvariables\t*/\n\tint i;\n\tint next_bit;\n\tint enc_c0, enc_c1;\n\tint c0[4], c1[4];\n\tfloat color_line[] = { 0.0f, 0.0f, 0.0f, 0.0f };\n\tfloat vec_len2 = 0.0f, dot_offset = 0.0f;\n\t/*\tstupid order\t*/\n\tint swizzle4[] = { 0, 2, 3, 1 };\n\t/*\tget the master colors\t*/\n\tLSE_master_colors_max_min( &enc_c0, &enc_c1, channels, uncompressed );\n\t/*\tstore the 565 color 0 and color 1\t*/\n\tcompressed[0] = (enc_c0 >> 0) & 255;\n\tcompressed[1] = (enc_c0 >> 8) & 255;\n\tcompressed[2] = (enc_c1 >> 0) & 255;\n\tcompressed[3] = (enc_c1 >> 8) & 255;\n\t/*\tzero out the compressed data\t*/\n\tcompressed[4] = 0;\n\tcompressed[5] = 0;\n\tcompressed[6] = 0;\n\tcompressed[7] = 0;\n\t/*\treconstitute the master color vectors\t*/\n\trgb_888_from_565( enc_c0, &c0[0], &c0[1], &c0[2] );\n\trgb_888_from_565( enc_c1, &c1[0], &c1[1], &c1[2] );\n\t/*\tthe new vector\t*/\n\tvec_len2 = 0.0f;\n\tfor( i = 0; i < 3; ++i )\n\t{\n\t\tcolor_line[i] = (float)(c1[i] - c0[i]);\n\t\tvec_len2 += color_line[i] * color_line[i];\n\t}\n\tif( vec_len2 > 0.0f )\n\t{\n\t\tvec_len2 = 1.0f / vec_len2;\n\t}\n\t/*\tpre-proform the scaling\t*/\n\tcolor_line[0] *= vec_len2;\n\tcolor_line[1] *= vec_len2;\n\tcolor_line[2] *= vec_len2;\n\t/*\tcompute the offset (constant) portion of the dot product\t*/\n\tdot_offset = color_line[0]*c0[0] + color_line[1]*c0[1] + color_line[2]*c0[2];\n\t/*\tstore the rest of the bits\t*/\n\tnext_bit = 8*4;\n\tfor( i = 0; i < 16; ++i )\n\t{\n\t\t/*\tfind the dot product of this color, to place it on the line\n\t\t\t(should be [-1,1])\t*/\n\t\tint next_value = 0;\n\t\tfloat dot_product =\n\t\t\tcolor_line[0] * uncompressed[i*channels+0] +\n\t\t\tcolor_line[1] * uncompressed[i*channels+1] +\n\t\t\tcolor_line[2] * uncompressed[i*channels+2] -\n\t\t\tdot_offset;\n\t\t/*\tmap to [0,3]\t*/\n\t\tnext_value = (int)( dot_product * 3.0f + 0.5f );\n\t\tif( next_value > 3 )\n\t\t{\n\t\t\tnext_value = 3;\n\t\t} else if( next_value < 0 )\n\t\t{\n\t\t\tnext_value = 0;\n\t\t}\n\t\t/*\tOK, store this value\t*/\n\t\tcompressed[next_bit >> 3] |= swizzle4[ next_value ] << (next_bit & 7);\n\t\tnext_bit += 2;\n\t}\n\t/*\tdone compressing to DXT1\t*/\n}\n\nvoid\n\tcompress_DDS_alpha_block\n\t(\n\t\tconst unsigned char *const uncompressed,\n\t\tunsigned char compressed[8]\n\t)\n{\n\t/*\tvariables\t*/\n\tint i;\n\tint next_bit;\n\tint a0, a1;\n\tfloat scale_me;\n\t/*\tstupid order\t*/\n\tint swizzle8[] = { 1, 7, 6, 5, 4, 3, 2, 0 };\n\t/*\tget the alpha limits (a0 > a1)\t*/\n\ta0 = a1 = uncompressed[3];\n\tfor( i = 4+3; i < 16*4; i += 4 )\n\t{\n\t\tif( uncompressed[i] > a0 )\n\t\t{\n\t\t\ta0 = uncompressed[i];\n\t\t} else if( uncompressed[i] < a1 )\n\t\t{\n\t\t\ta1 = uncompressed[i];\n\t\t}\n\t}\n\t/*\tstore those limits, and zero the rest of the compressed dataset\t*/\n\tcompressed[0] = a0;\n\tcompressed[1] = a1;\n\t/*\tzero out the compressed data\t*/\n\tcompressed[2] = 0;\n\tcompressed[3] = 0;\n\tcompressed[4] = 0;\n\tcompressed[5] = 0;\n\tcompressed[6] = 0;\n\tcompressed[7] = 0;\n\t/*\tstore the all of the alpha values\t*/\n\tnext_bit = 8*2;\n\tscale_me = 7.9999f / (a0 - a1);\n\tfor( i = 3; i < 16*4; i += 4 )\n\t{\n\t\t/*\tconvert this alpha value to a 3 bit number\t*/\n\t\tint svalue;\n\t\tint value = (int)((uncompressed[i] - a1) * scale_me);\n\t\tsvalue = swizzle8[ value&7 ];\n\t\t/*\tOK, store this value, start with the 1st byte\t*/\n\t\tcompressed[next_bit >> 3] |= svalue << (next_bit & 7);\n\t\tif( (next_bit & 7) > 5 )\n\t\t{\n\t\t\t/*\tspans 2 bytes, fill in the start of the 2nd byte\t*/\n\t\t\tcompressed[1 + (next_bit >> 3)] |= svalue >> (8 - (next_bit & 7) );\n\t\t}\n\t\tnext_bit += 3;\n\t}\n\t/*\tdone compressing to DXT1\t*/\n}\n"
  },
  {
    "path": "lib/SOIL2/image_DXT.h",
    "content": "/*\n\tJonathan Dummer\n\t2007-07-31-10.32\n\n\tsimple DXT compression / decompression code\n\n\tpublic domain\n*/\n\n#ifndef HEADER_IMAGE_DXT\n#define HEADER_IMAGE_DXT\n\n#include <stdint.h>\n\n/**\n\tConverts an image from an array of unsigned chars (RGB or RGBA) to\n\tDXT1 or DXT5, then saves the converted image to disk.\n\t\\return 0 if failed, otherwise returns 1\n**/\nint\nsave_image_as_DDS\n(\n    const char *filename,\n    int width, int height, int channels,\n    const unsigned char *const data\n);\n\n/**\n\ttake an image and convert it to DXT1 (no alpha)\n**/\nunsigned char*\nconvert_image_to_DXT1\n(\n    const unsigned char *const uncompressed,\n    int width, int height, int channels,\n    int *out_size\n);\n\n/**\n\ttake an image and convert it to DXT5 (with alpha)\n**/\nunsigned char*\nconvert_image_to_DXT5\n(\n    const unsigned char *const uncompressed,\n    int width, int height, int channels,\n    int *out_size\n);\n\n//\tA bunch of DirectDraw Surface structures and flags\ntypedef struct  \n{\n    uint32_t    dwMagic;\n    uint32_t    dwSize;\n    uint32_t    dwFlags;\n    uint32_t    dwHeight;\n    uint32_t    dwWidth;\n    uint32_t    dwPitchOrLinearSize;\n    uint32_t    dwDepth;\n    uint32_t    dwMipMapCount;\n    uint32_t    dwReserved1[ 11 ];\n\n    /*  DDPIXELFORMAT\t*/\n    struct\n    {\n        uint32_t    dwSize;\n        uint32_t    dwFlags;\n        uint32_t    dwFourCC;\n        uint32_t    dwRGBBitCount;\n        uint32_t    dwRBitMask;\n        uint32_t    dwGBitMask;\n        uint32_t    dwBBitMask;\n        uint32_t    dwAlphaBitMask;\n    } sPixelFormat;\n\n    /*  DDCAPS2\t*/\n    struct\n    {\n        uint32_t    dwCaps1;\n        uint32_t    dwCaps2;\n        uint32_t    dwDDSX;\n        uint32_t    dwReserved;\n    } sCaps;\n\n\n    unsigned int    dwReserved2;\n} DDS_header;\n\ntypedef enum {\n    DXGI_FORMAT_UNKNOWN = 0,\n    DXGI_FORMAT_R32G32B32A32_TYPELESS = 1,\n    DXGI_FORMAT_R32G32B32A32_FLOAT = 2,\n    DXGI_FORMAT_R32G32B32A32_UINT = 3,\n    DXGI_FORMAT_R32G32B32A32_SINT = 4,\n    DXGI_FORMAT_R32G32B32_TYPELESS = 5,\n    DXGI_FORMAT_R32G32B32_FLOAT = 6,\n    DXGI_FORMAT_R32G32B32_UINT = 7,\n    DXGI_FORMAT_R32G32B32_SINT = 8,\n    DXGI_FORMAT_R16G16B16A16_TYPELESS = 9,\n    DXGI_FORMAT_R16G16B16A16_FLOAT = 10,\n    DXGI_FORMAT_R16G16B16A16_UNORM = 11,\n    DXGI_FORMAT_R16G16B16A16_UINT = 12,\n    DXGI_FORMAT_R16G16B16A16_SNORM = 13,\n    DXGI_FORMAT_R16G16B16A16_SINT = 14,\n    DXGI_FORMAT_R32G32_TYPELESS = 15,\n    DXGI_FORMAT_R32G32_FLOAT = 16,\n    DXGI_FORMAT_R32G32_UINT = 17,\n    DXGI_FORMAT_R32G32_SINT = 18,\n    DXGI_FORMAT_R32G8X24_TYPELESS = 19,\n    DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20,\n    DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21,\n    DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22,\n    DXGI_FORMAT_R10G10B10A2_TYPELESS = 23,\n    DXGI_FORMAT_R10G10B10A2_UNORM = 24,\n    DXGI_FORMAT_R10G10B10A2_UINT = 25,\n    DXGI_FORMAT_R11G11B10_FLOAT = 26,\n    DXGI_FORMAT_R8G8B8A8_TYPELESS = 27,\n    DXGI_FORMAT_R8G8B8A8_UNORM = 28,\n    DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29,\n    DXGI_FORMAT_R8G8B8A8_UINT = 30,\n    DXGI_FORMAT_R8G8B8A8_SNORM = 31,\n    DXGI_FORMAT_R8G8B8A8_SINT = 32,\n    DXGI_FORMAT_R16G16_TYPELESS = 33,\n    DXGI_FORMAT_R16G16_FLOAT = 34,\n    DXGI_FORMAT_R16G16_UNORM = 35,\n    DXGI_FORMAT_R16G16_UINT = 36,\n    DXGI_FORMAT_R16G16_SNORM = 37,\n    DXGI_FORMAT_R16G16_SINT = 38,\n    DXGI_FORMAT_R32_TYPELESS = 39,\n    DXGI_FORMAT_D32_FLOAT = 40,\n    DXGI_FORMAT_R32_FLOAT = 41,\n    DXGI_FORMAT_R32_UINT = 42,\n    DXGI_FORMAT_R32_SINT = 43,\n    DXGI_FORMAT_R24G8_TYPELESS = 44,\n    DXGI_FORMAT_D24_UNORM_S8_UINT = 45,\n    DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46,\n    DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47,\n    DXGI_FORMAT_R8G8_TYPELESS = 48,\n    DXGI_FORMAT_R8G8_UNORM = 49,\n    DXGI_FORMAT_R8G8_UINT = 50,\n    DXGI_FORMAT_R8G8_SNORM = 51,\n    DXGI_FORMAT_R8G8_SINT = 52,\n    DXGI_FORMAT_R16_TYPELESS = 53,\n    DXGI_FORMAT_R16_FLOAT = 54,\n    DXGI_FORMAT_D16_UNORM = 55,\n    DXGI_FORMAT_R16_UNORM = 56,\n    DXGI_FORMAT_R16_UINT = 57,\n    DXGI_FORMAT_R16_SNORM = 58,\n    DXGI_FORMAT_R16_SINT = 59,\n    DXGI_FORMAT_R8_TYPELESS = 60,\n    DXGI_FORMAT_R8_UNORM = 61,\n    DXGI_FORMAT_R8_UINT = 62,\n    DXGI_FORMAT_R8_SNORM = 63,\n    DXGI_FORMAT_R8_SINT = 64,\n    DXGI_FORMAT_A8_UNORM = 65,\n    DXGI_FORMAT_R1_UNORM = 66,\n    DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67,\n    DXGI_FORMAT_R8G8_B8G8_UNORM = 68,\n    DXGI_FORMAT_G8R8_G8B8_UNORM = 69,\n    DXGI_FORMAT_BC1_TYPELESS = 70,\n    DXGI_FORMAT_BC1_UNORM = 71,\n    DXGI_FORMAT_BC1_UNORM_SRGB = 72,\n    DXGI_FORMAT_BC2_TYPELESS = 73,\n    DXGI_FORMAT_BC2_UNORM = 74,\n    DXGI_FORMAT_BC2_UNORM_SRGB = 75,\n    DXGI_FORMAT_BC3_TYPELESS = 76,\n    DXGI_FORMAT_BC3_UNORM = 77,\n    DXGI_FORMAT_BC3_UNORM_SRGB = 78,\n    DXGI_FORMAT_BC4_TYPELESS = 79,\n    DXGI_FORMAT_BC4_UNORM = 80,\n    DXGI_FORMAT_BC4_SNORM = 81,\n    DXGI_FORMAT_BC5_TYPELESS = 82,\n    DXGI_FORMAT_BC5_UNORM = 83,\n    DXGI_FORMAT_BC5_SNORM = 84,\n    DXGI_FORMAT_B5G6R5_UNORM = 85,\n    DXGI_FORMAT_B5G5R5A1_UNORM = 86,\n    DXGI_FORMAT_B8G8R8A8_UNORM = 87,\n    DXGI_FORMAT_B8G8R8X8_UNORM = 88,\n    DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89,\n    DXGI_FORMAT_B8G8R8A8_TYPELESS = 90,\n    DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91,\n    DXGI_FORMAT_B8G8R8X8_TYPELESS = 92,\n    DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93,\n    DXGI_FORMAT_BC6H_TYPELESS = 94,\n    DXGI_FORMAT_BC6H_UF16 = 95,\n    DXGI_FORMAT_BC6H_SF16 = 96,\n    DXGI_FORMAT_BC7_TYPELESS = 97,\n    DXGI_FORMAT_BC7_UNORM = 98,\n    DXGI_FORMAT_BC7_UNORM_SRGB = 99,\n    DXGI_FORMAT_AYUV = 100,\n    DXGI_FORMAT_Y410 = 101,\n    DXGI_FORMAT_Y416 = 102,\n    DXGI_FORMAT_NV12 = 103,\n    DXGI_FORMAT_P010 = 104,\n    DXGI_FORMAT_P016 = 105,\n    DXGI_FORMAT_420_OPAQUE = 106,\n    DXGI_FORMAT_YUY2 = 107,\n    DXGI_FORMAT_Y210 = 108,\n    DXGI_FORMAT_Y216 = 109,\n    DXGI_FORMAT_NV11 = 110,\n    DXGI_FORMAT_AI44 = 111,\n    DXGI_FORMAT_IA44 = 112,\n    DXGI_FORMAT_P8 = 113,\n    DXGI_FORMAT_A8P8 = 114,\n    DXGI_FORMAT_B4G4R4A4_UNORM = 115,\n    DXGI_FORMAT_P208 = 130,\n    DXGI_FORMAT_V208 = 131,\n    DXGI_FORMAT_V408 = 132,\n    DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE,\n    DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE,\n    DXGI_FORMAT_FORCE_UINT = 0xffffffff\n} DXGI_FORMAT;\n\ntypedef struct {\n    DXGI_FORMAT dxgiFormat;\n\n    uint32_t resourceDimension;\n    uint32_t miscFlag;\n    uint32_t arraySize;\n    uint32_t miscFlags2;\n} DDS_HEADER_DXT10;\n\n/*\tthe following constants were copied directly off the MSDN website\t*/\n\n/*\tThe dwFlags member of the original DDSURFACEDESC2 structure\n\tcan be set to one or more of the following values.\t*/\n#define DDSD_CAPS\t0x00000001\n#define DDSD_HEIGHT\t0x00000002\n#define DDSD_WIDTH\t0x00000004\n#define DDSD_PITCH\t0x00000008\n#define DDSD_PIXELFORMAT\t0x00001000\n#define DDSD_MIPMAPCOUNT\t0x00020000\n#define DDSD_LINEARSIZE\t0x00080000\n#define DDSD_DEPTH\t0x00800000\n\n/*\tDirectDraw Pixel Format\t*/\n#define DDPF_ALPHAPIXELS\t0x00000001\n#define DDPF_FOURCC\t0x00000004\n#define DDPF_RGB\t0x00000040\n#define DDPF_LUMINANCE 0x20000\n\n/*\tThe dwCaps1 member of the DDSCAPS2 structure can be\n\tset to one or more of the following values.\t*/\n#define DDSCAPS_COMPLEX\t0x00000008\n#define DDSCAPS_TEXTURE\t0x00001000\n#define DDSCAPS_MIPMAP\t0x00400000\n\n/*\tThe dwCaps2 member of the DDSCAPS2 structure can be\n\tset to one or more of the following values.\t\t*/\n#define DDSCAPS2_CUBEMAP\t0x00000200\n#define DDSCAPS2_CUBEMAP_POSITIVEX\t0x00000400\n#define DDSCAPS2_CUBEMAP_NEGATIVEX\t0x00000800\n#define DDSCAPS2_CUBEMAP_POSITIVEY\t0x00001000\n#define DDSCAPS2_CUBEMAP_NEGATIVEY\t0x00002000\n#define DDSCAPS2_CUBEMAP_POSITIVEZ\t0x00004000\n#define DDSCAPS2_CUBEMAP_NEGATIVEZ\t0x00008000\n#define DDSCAPS2_VOLUME\t0x00200000\n\n#endif /* HEADER_IMAGE_DXT\t*/\n"
  },
  {
    "path": "lib/SOIL2/image_helper.c",
    "content": "/*\n    Jonathan Dummer\n\n    image helper functions\n\n    MIT license\n*/\n\n#include \"image_helper.h\"\n#include <stdlib.h>\n#include <math.h>\n\n/*\tUpscaling the image uses simple bilinear interpolation\t*/\nint\n\tup_scale_image\n\t(\n\t\tconst unsigned char* const orig,\n\t\tint width, int height, int channels,\n\t\tunsigned char* resampled,\n\t\tint resampled_width, int resampled_height\n\t)\n{\n\tfloat dx, dy;\n\tint x, y, c;\n\n    /* error(s) check\t*/\n    if ( \t(width < 1) || (height < 1) ||\n            (resampled_width < 2) || (resampled_height < 2) ||\n            (channels < 1) ||\n            (NULL == orig) || (NULL == resampled) )\n    {\n        /*\tsignify badness\t*/\n        return 0;\n    }\n    /*\n\t\tfor each given pixel in the new map, find the exact location\n\t\tfrom the original map which would contribute to this guy\n\t*/\n    dx = (width - 1.0f) / (resampled_width - 1.0f);\n    dy = (height - 1.0f) / (resampled_height - 1.0f);\n    for ( y = 0; y < resampled_height; ++y )\n    {\n    \t/* find the base y index and fractional offset from that\t*/\n    \tfloat sampley = y * dy;\n    \tint inty = (int)sampley;\n    \t/*\tif( inty < 0 ) { inty = 0; } else\t*/\n\t\tif( inty > height - 2 ) { inty = height - 2; }\n\t\tsampley -= inty;\n        for ( x = 0; x < resampled_width; ++x )\n        {\n\t\t\tfloat samplex = x * dx;\n\t\t\tint intx = (int)samplex;\n\t\t\tint base_index;\n\t\t\t/* find the base x index and fractional offset from that\t*/\n\t\t\t/*\tif( intx < 0 ) { intx = 0; } else\t*/\n\t\t\tif( intx > width - 2 ) { intx = width - 2; }\n\t\t\tsamplex -= intx;\n\t\t\t/*\tbase index into the original image\t*/\n\t\t\tbase_index = (inty * width + intx) * channels;\n            for ( c = 0; c < channels; ++c )\n            {\n            \t/*\tdo the sampling\t*/\n\t\t\t\tfloat value = 0.5f;\n\t\t\t\tvalue += orig[base_index]\n\t\t\t\t\t\t\t*(1.0f-samplex)*(1.0f-sampley);\n\t\t\t\tvalue += orig[base_index+channels]\n\t\t\t\t\t\t\t*(samplex)*(1.0f-sampley);\n\t\t\t\tvalue += orig[base_index+width*channels]\n\t\t\t\t\t\t\t*(1.0f-samplex)*(sampley);\n\t\t\t\tvalue += orig[base_index+width*channels+channels]\n\t\t\t\t\t\t\t*(samplex)*(sampley);\n\t\t\t\t/*\tmove to the next channel\t*/\n\t\t\t\t++base_index;\n            \t/*\tsave the new value\t*/\n            \tresampled[y*resampled_width*channels+x*channels+c] =\n\t\t\t\t\t\t(unsigned char)(value);\n            }\n        }\n    }\n    /*\tdone\t*/\n    return 1;\n}\n\nint\n\tmipmap_image\n\t(\n\t\tconst unsigned char* const orig,\n\t\tint width, int height, int channels,\n\t\tunsigned char* resampled,\n\t\tint block_size_x, int block_size_y\n\t)\n{\n\tint mip_width, mip_height;\n\tint i, j, c;\n\n\t/*\terror check\t*/\n\tif( (width < 1) || (height < 1) ||\n\t\t(channels < 1) || (orig == NULL) ||\n\t\t(resampled == NULL) ||\n\t\t(block_size_x < 1) || (block_size_y < 1) )\n\t{\n\t\t/*\tnothing to do\t*/\n\t\treturn 0;\n\t}\n\tmip_width = width / block_size_x;\n\tmip_height = height / block_size_y;\n\tif( mip_width < 1 )\n\t{\n\t\tmip_width = 1;\n\t}\n\tif( mip_height < 1 )\n\t{\n\t\tmip_height = 1;\n\t}\n\tfor( j = 0; j < mip_height; ++j )\n\t{\n\t\tfor( i = 0; i < mip_width; ++i )\n\t\t{\n\t\t\tfor( c = 0; c < channels; ++c )\n\t\t\t{\n\t\t\t\tconst int index = (j*block_size_y)*width*channels + (i*block_size_x)*channels + c;\n\t\t\t\tint sum_value;\n\t\t\t\tint u,v;\n\t\t\t\tint u_block = block_size_x;\n\t\t\t\tint v_block = block_size_y;\n\t\t\t\tint block_area;\n\t\t\t\t/*\tdo a bit of checking so we don't over-run the boundaries\n\t\t\t\t\t(necessary for non-square textures!)\t*/\n\t\t\t\tif( block_size_x * (i+1) > width )\n\t\t\t\t{\n\t\t\t\t\tu_block = width - i*block_size_y;\n\t\t\t\t}\n\t\t\t\tif( block_size_y * (j+1) > height )\n\t\t\t\t{\n\t\t\t\t\tv_block = height - j*block_size_y;\n\t\t\t\t}\n\t\t\t\tblock_area = u_block*v_block;\n\t\t\t\t/*\tfor this pixel, see what the average\n\t\t\t\t\tof all the values in the block are.\n\t\t\t\t\tnote: start the sum at the rounding value, not at 0\t*/\n\t\t\t\tsum_value = block_area >> 1;\n\t\t\t\tfor( v = 0; v < v_block; ++v )\n\t\t\t\tfor( u = 0; u < u_block; ++u )\n\t\t\t\t{\n\t\t\t\t\tsum_value += orig[index + v*width*channels + u*channels];\n\t\t\t\t}\n\t\t\t\tresampled[j*mip_width*channels + i*channels + c] = sum_value / block_area;\n\t\t\t}\n\t\t}\n\t}\n\treturn 1;\n}\n\nint\n\tscale_image_RGB_to_NTSC_safe\n\t(\n\t\tunsigned char* orig,\n\t\tint width, int height, int channels\n\t)\n{\n\tconst float scale_lo = 16.0f - 0.499f;\n\tconst float scale_hi = 235.0f + 0.499f;\n\tint i, j;\n\tint nc = channels;\n\tunsigned char scale_LUT[256];\n\t/*\terror check\t*/\n\tif( (width < 1) || (height < 1) ||\n\t\t(channels < 1) || (orig == NULL) )\n\t{\n\t\t/*\tnothing to do\t*/\n\t\treturn 0;\n\t}\n\t/*\tset up the scaling Look Up Table\t*/\n\tfor( i = 0; i < 256; ++i )\n\t{\n\t\tscale_LUT[i] = (unsigned char)((scale_hi - scale_lo) * i / 255.0f + scale_lo);\n\t}\n\t/*\tfor channels = 2 or 4, ignore the alpha component\t*/\n\tnc -= 1 - (channels & 1);\n\t/*\tOK, go through the image and scale any non-alpha components\t*/\n\tfor( i = 0; i < width*height*channels; i += channels )\n\t{\n\t\tfor( j = 0; j < nc; ++j )\n\t\t{\n\t\t\torig[i+j] = scale_LUT[orig[i+j]];\n\t\t}\n\t}\n\treturn 1;\n}\n\nunsigned char clamp_byte( int x ) { return ( (x) < 0 ? (0) : ( (x) > 255 ? 255 : (x) ) ); }\n\n/*\n\tThis function takes the RGB components of the image\n\tand converts them into YCoCg.  3 components will be\n\tre-ordered to CoYCg (for optimum DXT1 compression),\n\twhile 4 components will be ordered CoCgAY (for DXT5\n\tcompression).\n*/\nint\n\tconvert_RGB_to_YCoCg\n\t(\n\t\tunsigned char* orig,\n\t\tint width, int height, int channels\n\t)\n{\n\tint i;\n\t/*\terror check\t*/\n\tif( (width < 1) || (height < 1) ||\n\t\t(channels < 3) || (channels > 4) ||\n\t\t(orig == NULL) )\n\t{\n\t\t/*\tnothing to do\t*/\n\t\treturn -1;\n\t}\n\t/*\tdo the conversion\t*/\n\tif( channels == 3 )\n\t{\n\t\tfor( i = 0; i < width*height*3; i += 3 )\n\t\t{\n\t\t\tint r = orig[i+0];\n\t\t\tint g = (orig[i+1] + 1) >> 1;\n\t\t\tint b = orig[i+2];\n\t\t\tint tmp = (2 + r + b) >> 2;\n\t\t\t/*\tCo\t*/\n\t\t\torig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );\n\t\t\t/*\tY\t*/\n\t\t\torig[i+1] = clamp_byte( g + tmp );\n\t\t\t/*\tCg\t*/\n\t\t\torig[i+2] = clamp_byte( 128 + g - tmp );\n\t\t}\n\t} else\n\t{\n\t\tfor( i = 0; i < width*height*4; i += 4 )\n\t\t{\n\t\t\tint r = orig[i+0];\n\t\t\tint g = (orig[i+1] + 1) >> 1;\n\t\t\tint b = orig[i+2];\n\t\t\tunsigned char a = orig[i+3];\n\t\t\tint tmp = (2 + r + b) >> 2;\n\t\t\t/*\tCo\t*/\n\t\t\torig[i+0] = clamp_byte( 128 + ((r - b + 1) >> 1) );\n\t\t\t/*\tCg\t*/\n\t\t\torig[i+1] = clamp_byte( 128 + g - tmp );\n\t\t\t/*\tAlpha\t*/\n\t\t\torig[i+2] = a;\n\t\t\t/*\tY\t*/\n\t\t\torig[i+3] = clamp_byte( g + tmp );\n\t\t}\n\t}\n\t/*\tdone\t*/\n\treturn 0;\n}\n\n/*\n\tThis function takes the YCoCg components of the image\n\tand converts them into RGB.  See above.\n*/\nint\n\tconvert_YCoCg_to_RGB\n\t(\n\t\tunsigned char* orig,\n\t\tint width, int height, int channels\n\t)\n{\n\tint i;\n\t/*\terror check\t*/\n\tif( (width < 1) || (height < 1) ||\n\t\t(channels < 3) || (channels > 4) ||\n\t\t(orig == NULL) )\n\t{\n\t\t/*\tnothing to do\t*/\n\t\treturn -1;\n\t}\n\t/*\tdo the conversion\t*/\n\tif( channels == 3 )\n\t{\n\t\tfor( i = 0; i < width*height*3; i += 3 )\n\t\t{\n\t\t\tint co = orig[i+0] - 128;\n\t\t\tint y  = orig[i+1];\n\t\t\tint cg = orig[i+2] - 128;\n\t\t\t/*\tR\t*/\n\t\t\torig[i+0] = clamp_byte( y + co - cg );\n\t\t\t/*\tG\t*/\n\t\t\torig[i+1] = clamp_byte( y + cg );\n\t\t\t/*\tB\t*/\n\t\t\torig[i+2] = clamp_byte( y - co - cg );\n\t\t}\n\t} else\n\t{\n\t\tfor( i = 0; i < width*height*4; i += 4 )\n\t\t{\n\t\t\tint co = orig[i+0] - 128;\n\t\t\tint cg = orig[i+1] - 128;\n\t\t\tunsigned char a  = orig[i+2];\n\t\t\tint y  = orig[i+3];\n\t\t\t/*\tR\t*/\n\t\t\torig[i+0] = clamp_byte( y + co - cg );\n\t\t\t/*\tG\t*/\n\t\t\torig[i+1] = clamp_byte( y + cg );\n\t\t\t/*\tB\t*/\n\t\t\torig[i+2] = clamp_byte( y - co - cg );\n\t\t\t/*\tA\t*/\n\t\t\torig[i+3] = a;\n\t\t}\n\t}\n\t/*\tdone\t*/\n\treturn 0;\n}\n\nfloat\nfind_max_RGBE\n(\n\tunsigned char *image,\n    int width, int height\n)\n{\n\tfloat max_val = 0.0f;\n\tunsigned char *img = image;\n\tint i, j;\n\tfor( i = width * height; i > 0; --i )\n\t{\n\t\t/* float scale = powf( 2.0f, img[3] - 128.0f ) / 255.0f; */\n\t\tfloat scale = (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );\n\t\tfor( j = 0; j < 3; ++j )\n\t\t{\n\t\t\tif( img[j] * scale > max_val )\n\t\t\t{\n\t\t\t\tmax_val = img[j] * scale;\n\t\t\t}\n\t\t}\n\t\t/* next pixel */\n\t\timg += 4;\n\t}\n\treturn max_val;\n}\n\nint\nRGBE_to_RGBdivA\n(\n    unsigned char *image,\n    int width, int height,\n    int rescale_to_max\n)\n{\n\t/* local variables */\n\tint i, iv;\n\tunsigned char *img = image;\n\tfloat scale = 1.0f;\n\t/* error check */\n\tif( (!image) || (width < 1) || (height < 1) )\n\t{\n\t\treturn 0;\n\t}\n\t/* convert (note: no negative numbers, but 0.0 is possible) */\n\tif( rescale_to_max )\n\t{\n\t\tscale = 255.0f / find_max_RGBE( image, width, height );\n\t}\n\tfor( i = width * height; i > 0; --i )\n\t{\n\t\t/* decode this pixel, and find the max */\n\t\tfloat r,g,b,e, m;\n\t\t/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */\n\t\te = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );\n\t\tr = e * img[0];\n\t\tg = e * img[1];\n\t\tb = e * img[2];\n\t\tm = (r > g) ? r : g;\n\t\tm = (b > m) ? b : m;\n\t\t/* and encode it into RGBdivA */\n\t\tiv = (m != 0.0f) ? (int)(255.0f / m) : 1;\n\t\tiv = (iv < 1) ? 1 : iv;\n\t\timg[3] = (iv > 255) ? 255 : iv;\n\t\tiv = (int)(img[3] * r + 0.5f);\n\t\timg[0] = (iv > 255) ? 255 : iv;\n\t\tiv = (int)(img[3] * g + 0.5f);\n\t\timg[1] = (iv > 255) ? 255 : iv;\n\t\tiv = (int)(img[3] * b + 0.5f);\n\t\timg[2] = (iv > 255) ? 255 : iv;\n\t\t/* and on to the next pixel */\n\t\timg += 4;\n\t}\n\treturn 1;\n}\n\nint\nRGBE_to_RGBdivA2\n(\n    unsigned char *image,\n    int width, int height,\n    int rescale_to_max\n)\n{\n\t/* local variables */\n\tint i, iv;\n\tunsigned char *img = image;\n\tfloat scale = 1.0f;\n\t/* error check */\n\tif( (!image) || (width < 1) || (height < 1) )\n\t{\n\t\treturn 0;\n\t}\n\t/* convert (note: no negative numbers, but 0.0 is possible) */\n\tif( rescale_to_max )\n\t{\n\t\tscale = 255.0f * 255.0f / find_max_RGBE( image, width, height );\n\t}\n\tfor( i = width * height; i > 0; --i )\n\t{\n\t\t/* decode this pixel, and find the max */\n\t\tfloat r,g,b,e, m;\n\t\t/* e = scale * powf( 2.0f, img[3] - 128.0f ) / 255.0f; */\n\t\te = scale * (float)ldexp( 1.0f / 255.0f, (int)(img[3]) - 128 );\n\t\tr = e * img[0];\n\t\tg = e * img[1];\n\t\tb = e * img[2];\n\t\tm = (r > g) ? r : g;\n\t\tm = (b > m) ? b : m;\n\t\t/* and encode it into RGBdivA */\n\t\tiv = (m != 0.0f) ? (int)sqrtf( 255.0f * 255.0f / m ) : 1;\n\t\tiv = (iv < 1) ? 1 : iv;\n\t\timg[3] = (iv > 255) ? 255 : iv;\n\t\tiv = (int)(img[3] * img[3] * r / 255.0f + 0.5f);\n\t\timg[0] = (iv > 255) ? 255 : iv;\n\t\tiv = (int)(img[3] * img[3] * g / 255.0f + 0.5f);\n\t\timg[1] = (iv > 255) ? 255 : iv;\n\t\tiv = (int)(img[3] * img[3] * b / 255.0f + 0.5f);\n\t\timg[2] = (iv > 255) ? 255 : iv;\n\t\t/* and on to the next pixel */\n\t\timg += 4;\n\t}\n\treturn 1;\n}\n"
  },
  {
    "path": "lib/SOIL2/image_helper.h",
    "content": "/*\n    Jonathan Dummer\n\n    Image helper functions\n\n    MIT license\n*/\n\n#ifndef HEADER_IMAGE_HELPER\n#define HEADER_IMAGE_HELPER\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/**\n\tThis function upscales an image.\n\tNot to be used to create MIPmaps,\n\tbut to make it square,\n\tor to make it a power-of-two sized.\n**/\nint\n\tup_scale_image\n\t(\n\t\tconst unsigned char* const orig,\n\t\tint width, int height, int channels,\n\t\tunsigned char* resampled,\n\t\tint resampled_width, int resampled_height\n\t);\n\n/**\n\tThis function downscales an image.\n\tUsed for creating MIPmaps,\n\tthe incoming image should be a\n\tpower-of-two sized.\n**/\nint\n\tmipmap_image\n\t(\n\t\tconst unsigned char* const orig,\n\t\tint width, int height, int channels,\n\t\tunsigned char* resampled,\n\t\tint block_size_x, int block_size_y\n\t);\n\n/**\n\tThis function takes the RGB components of the image\n\tand scales each channel from [0,255] to [16,235].\n\tThis makes the colors \"Safe\" for display on NTSC\n\tdisplays.  Note that this is _NOT_ a good idea for\n\tloading images like normal- or height-maps!\n**/\nint\n\tscale_image_RGB_to_NTSC_safe\n\t(\n\t\tunsigned char* orig,\n\t\tint width, int height, int channels\n\t);\n\n/**\n\tThis function takes the RGB components of the image\n\tand converts them into YCoCg.  3 components will be\n\tre-ordered to CoYCg (for optimum DXT1 compression),\n\twhile 4 components will be ordered CoCgAY (for DXT5\n\tcompression).\n**/\nint\n\tconvert_RGB_to_YCoCg\n\t(\n\t\tunsigned char* orig,\n\t\tint width, int height, int channels\n\t);\n\n/**\n\tThis function takes the YCoCg components of the image\n\tand converts them into RGB.  See above.\n**/\nint\n\tconvert_YCoCg_to_RGB\n\t(\n\t\tunsigned char* orig,\n\t\tint width, int height, int channels\n\t);\n\n/**\n\tConverts an HDR image from an array\n\tof unsigned chars (RGBE) to RGBdivA\n\t\\return 0 if failed, otherwise returns 1\n**/\nint\n\tRGBE_to_RGBdivA\n\t(\n\t\tunsigned char *image,\n\t\tint width, int height,\n\t\tint rescale_to_max\n\t);\n\n/**\n\tConverts an HDR image from an array\n\tof unsigned chars (RGBE) to RGBdivA2\n\t\\return 0 if failed, otherwise returns 1\n**/\nint\n\tRGBE_to_RGBdivA2\n\t(\n\t\tunsigned char *image,\n\t\tint width, int height,\n\t\tint rescale_to_max\n\t);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* HEADER_IMAGE_HELPER\t*/\n"
  },
  {
    "path": "lib/SOIL2/pkm_helper.h",
    "content": "#ifndef PKM_HELPER_H\n#define PKM_HELPER_H\n\ntypedef struct {\n\tchar aName[6];\n\tunsigned short iBlank;\n\tunsigned char iPaddedWidthMSB;\n\tunsigned char iPaddedWidthLSB;\n\tunsigned char iPaddedHeightMSB;\n\tunsigned char iPaddedHeightLSB;\n\tunsigned char iWidthMSB;\n\tunsigned char iWidthLSB;\n\tunsigned char iHeightMSB;\n\tunsigned char iHeightLSB;\n} PKMHeader;\n\n#define PKM_HEADER_SIZE 16\n\n#endif\n"
  },
  {
    "path": "lib/SOIL2/pvr_helper.h",
    "content": "#ifndef PVR_HELPER_H\n#define PVR_HELPER_H\n\n// Taken from PowerVR SDK\n\n/*!***************************************************************************\n Describes the header of a PVR header-texture\n *****************************************************************************/\ntypedef struct\n{\n\tunsigned int dwHeaderSize;\t\t\t/*!< size of the structure */\n\tunsigned int dwHeight;\t\t\t\t/*!< height of surface to be created */\n\tunsigned int dwWidth;\t\t\t\t/*!< width of input surface */\n\tunsigned int dwMipMapCount;\t\t\t/*!< number of mip-map levels requested */\n\tunsigned int dwpfFlags;\t\t\t\t/*!< pixel format flags */\n\tunsigned int dwTextureDataSize;\t\t/*!< Total size in bytes */\n\tunsigned int dwBitCount;\t\t\t/*!< number of bits per pixel  */\n\tunsigned int dwRBitMask;\t\t\t/*!< mask for red bit */\n\tunsigned int dwGBitMask;\t\t\t/*!< mask for green bits */\n\tunsigned int dwBBitMask;\t\t\t/*!< mask for blue bits */\n\tunsigned int dwAlphaBitMask;\t\t/*!< mask for alpha channel */\n\tunsigned int dwPVR;\t\t\t\t\t/*!< magic number identifying pvr file */\n\tunsigned int dwNumSurfs;\t\t\t/*!< the number of surfaces present in the pvr */\n} PVR_Texture_Header;\n\n/*****************************************************************************\n * ENUMS\n *****************************************************************************/\n\nenum PixelType\n{\n\tMGLPT_ARGB_4444 = 0x00,\n\tMGLPT_ARGB_1555,\n\tMGLPT_RGB_565,\n\tMGLPT_RGB_555,\n\tMGLPT_RGB_888,\n\tMGLPT_ARGB_8888,\n\tMGLPT_ARGB_8332,\n\tMGLPT_I_8,\n\tMGLPT_AI_88,\n\tMGLPT_1_BPP,\n\tMGLPT_VY1UY0,\n\tMGLPT_Y1VY0U,\n\tMGLPT_PVRTC2,\n\tMGLPT_PVRTC4,\n\tMGLPT_PVRTC2_2,\n\tMGLPT_PVRTC2_4,\n\t\n\tOGL_RGBA_4444= 0x10,\n\tOGL_RGBA_5551,\n\tOGL_RGBA_8888,\n\tOGL_RGB_565,\n\tOGL_RGB_555,\n\tOGL_RGB_888,\n\tOGL_I_8,\n\tOGL_AI_88,\n\tOGL_PVRTC2,\n\tOGL_PVRTC4,\n\t\n\t// OGL_BGRA_8888 extension\n\tOGL_BGRA_8888,\n\t\n\tD3D_DXT1 = 0x20,\n\tD3D_DXT2,\n\tD3D_DXT3,\n\tD3D_DXT4,\n\tD3D_DXT5,\n\t\n\tD3D_RGB_332,\n\tD3D_AI_44,\n\tD3D_LVU_655,\n\tD3D_XLVU_8888,\n\tD3D_QWVU_8888,\n\t\n\t//10 bits per channel\n\tD3D_ABGR_2101010,\n\tD3D_ARGB_2101010,\n\tD3D_AWVU_2101010,\n\t\n\t//16 bits per channel\n\tD3D_GR_1616,\n\tD3D_VU_1616,\n\tD3D_ABGR_16161616,\n\t\n\t//HDR formats\n\tD3D_R16F,\n\tD3D_GR_1616F,\n\tD3D_ABGR_16161616F,\n\t\n\t//32 bits per channel\n\tD3D_R32F,\n\tD3D_GR_3232F,\n\tD3D_ABGR_32323232F,\n\t\n\t// Ericsson\n\tETC_RGB_4BPP,\n\tETC_RGBA_EXPLICIT,\n\tETC_RGBA_INTERPOLATED,\n\t\n\t// DX10\n\t\n\t\n\tePT_DX10_R32G32B32A32_FLOAT= 0x50,\n\tePT_DX10_R32G32B32A32_UINT ,\n\tePT_DX10_R32G32B32A32_SINT,\n\t\n\tePT_DX10_R32G32B32_FLOAT,\n\tePT_DX10_R32G32B32_UINT,\n\tePT_DX10_R32G32B32_SINT,\n\t\n\tePT_DX10_R16G16B16A16_FLOAT ,\n\tePT_DX10_R16G16B16A16_UNORM,\n\tePT_DX10_R16G16B16A16_UINT ,\n\tePT_DX10_R16G16B16A16_SNORM ,\n\tePT_DX10_R16G16B16A16_SINT ,\n\t\n\tePT_DX10_R32G32_FLOAT ,\n\tePT_DX10_R32G32_UINT ,\n\tePT_DX10_R32G32_SINT ,\n\t\n\tePT_DX10_R10G10B10A2_UNORM ,\n\tePT_DX10_R10G10B10A2_UINT ,\n\t\n\tePT_DX10_R11G11B10_FLOAT ,\n\t\n\tePT_DX10_R8G8B8A8_UNORM ,\n\tePT_DX10_R8G8B8A8_UNORM_SRGB ,\n\tePT_DX10_R8G8B8A8_UINT ,\n\tePT_DX10_R8G8B8A8_SNORM ,\n\tePT_DX10_R8G8B8A8_SINT ,\n\t\n\tePT_DX10_R16G16_FLOAT ,\n\tePT_DX10_R16G16_UNORM ,\n\tePT_DX10_R16G16_UINT ,\n\tePT_DX10_R16G16_SNORM ,\n\tePT_DX10_R16G16_SINT ,\n\t\n\tePT_DX10_R32_FLOAT ,\n\tePT_DX10_R32_UINT ,\n\tePT_DX10_R32_SINT ,\n\t\n\tePT_DX10_R8G8_UNORM ,\n\tePT_DX10_R8G8_UINT ,\n\tePT_DX10_R8G8_SNORM ,\n\tePT_DX10_R8G8_SINT ,\n\t\n\tePT_DX10_R16_FLOAT ,\n\tePT_DX10_R16_UNORM ,\n\tePT_DX10_R16_UINT ,\n\tePT_DX10_R16_SNORM ,\n\tePT_DX10_R16_SINT ,\n\t\n\tePT_DX10_R8_UNORM,\n\tePT_DX10_R8_UINT,\n\tePT_DX10_R8_SNORM,\n\tePT_DX10_R8_SINT,\n\t\n\tePT_DX10_A8_UNORM,\n\tePT_DX10_R1_UNORM,\n\tePT_DX10_R9G9B9E5_SHAREDEXP,\n\tePT_DX10_R8G8_B8G8_UNORM,\n\tePT_DX10_G8R8_G8B8_UNORM,\n\t\n\tePT_DX10_BC1_UNORM,\n\tePT_DX10_BC1_UNORM_SRGB,\n\t\n\tePT_DX10_BC2_UNORM,\n\tePT_DX10_BC2_UNORM_SRGB,\n\t\n\tePT_DX10_BC3_UNORM,\n\tePT_DX10_BC3_UNORM_SRGB,\n\t\n\tePT_DX10_BC4_UNORM,\n\tePT_DX10_BC4_SNORM,\n\t\n\tePT_DX10_BC5_UNORM,\n\tePT_DX10_BC5_SNORM,\n\t\n\t//ePT_DX10_B5G6R5_UNORM,\t\t\t// defined but obsolete - won't actually load in DX10\n\t//ePT_DX10_B5G5R5A1_UNORM,\n\t//ePT_DX10_B8G8R8A8_UNORM,\n\t//ePT_DX10_B8G8R8X8_UNORM,\n\t\n\t// OpenVG\n\t\n\t/* RGB{A,X} channel ordering */\n\tePT_VG_sRGBX_8888  = 0x90,\n\tePT_VG_sRGBA_8888,\n\tePT_VG_sRGBA_8888_PRE,\n\tePT_VG_sRGB_565,\n\tePT_VG_sRGBA_5551,\n\tePT_VG_sRGBA_4444,\n\tePT_VG_sL_8,\n\tePT_VG_lRGBX_8888,\n\tePT_VG_lRGBA_8888,\n\tePT_VG_lRGBA_8888_PRE,\n\tePT_VG_lL_8,\n\tePT_VG_A_8,\n\tePT_VG_BW_1,\n\t\n\t/* {A,X}RGB channel ordering */\n\tePT_VG_sXRGB_8888,\n\tePT_VG_sARGB_8888,\n\tePT_VG_sARGB_8888_PRE,\n\tePT_VG_sARGB_1555,\n\tePT_VG_sARGB_4444,\n\tePT_VG_lXRGB_8888,\n\tePT_VG_lARGB_8888,\n\tePT_VG_lARGB_8888_PRE,\n\t\n\t/* BGR{A,X} channel ordering */\n\tePT_VG_sBGRX_8888,\n\tePT_VG_sBGRA_8888,\n\tePT_VG_sBGRA_8888_PRE,\n\tePT_VG_sBGR_565,\n\tePT_VG_sBGRA_5551,\n\tePT_VG_sBGRA_4444,\n\tePT_VG_lBGRX_8888,\n\tePT_VG_lBGRA_8888,\n\tePT_VG_lBGRA_8888_PRE,\n\t\n\t/* {A,X}BGR channel ordering */\n\tePT_VG_sXBGR_8888,\n\tePT_VG_sABGR_8888 ,\n\tePT_VG_sABGR_8888_PRE,\n\tePT_VG_sABGR_1555,\n\tePT_VG_sABGR_4444,\n\tePT_VG_lXBGR_8888,\n\tePT_VG_lABGR_8888,\n\tePT_VG_lABGR_8888_PRE,\n\t\n\t// max cap for iterating\n\tEND_OF_PIXEL_TYPES,\n\t\n\tMGLPT_NOTYPE = 0xff\n\t\n};\n\n/*****************************************************************************\n * constants\n *****************************************************************************/\n\n#define PVRTEX_MIPMAP\t\t(1<<8)\t\t// has mip map levels\n#define PVRTEX_TWIDDLE\t\t(1<<9)\t\t// is twiddled\n#define PVRTEX_BUMPMAP\t\t(1<<10)\t\t// has normals encoded for a bump map\n#define PVRTEX_TILING\t\t(1<<11)\t\t// is bordered for tiled pvr\n#define PVRTEX_CUBEMAP\t\t(1<<12)\t\t// is a cubemap/skybox\n#define PVRTEX_FALSEMIPCOL\t(1<<13)\t\t//\n#define PVRTEX_VOLUME\t\t(1<<14)\n#define PVRTEX_PIXELTYPE\t0xff\t\t\t// pixel type is always in the last 16bits of the flags\n#define PVRTEX_IDENTIFIER\t0x21525650\t// the pvr identifier is the characters 'P','V','R'\n\n#define PVRTEX_V1_HEADER_SIZE 44\t\t\t// old header size was 44 for identification purposes\n\n#define PVRTC2_MIN_TEXWIDTH\t\t16\n#define PVRTC2_MIN_TEXHEIGHT\t8\n#define PVRTC4_MIN_TEXWIDTH\t\t8\n#define PVRTC4_MIN_TEXHEIGHT\t8\n#define ETC_MIN_TEXWIDTH\t\t4\n#define ETC_MIN_TEXHEIGHT\t\t4\n#define DXT_MIN_TEXWIDTH\t\t4\n#define DXT_MIN_TEXHEIGHT\t\t4\n\n#endif\n"
  },
  {
    "path": "lib/SOIL2/stb_image.h",
    "content": "/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb\n                                  no warranty implied; use at your own risk\n\n   Do this:\n      #define STB_IMAGE_IMPLEMENTATION\n   before you include this file in *one* C or C++ file to create the implementation.\n\n   // i.e. it should look like this:\n   #include ...\n   #include ...\n   #include ...\n   #define STB_IMAGE_IMPLEMENTATION\n   #include \"stb_image.h\"\n\n   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.\n   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free\n\n\n   QUICK NOTES:\n      Primarily of interest to game developers and other people who can\n          avoid problematic images and only need the trivial interface\n\n      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)\n      PNG 1/2/4/8/16-bit-per-channel\n\n      TGA (not sure what subset, if a subset)\n      BMP non-1bpp, non-RLE\n      PSD (composited view only, no extra channels, 8/16 bit-per-channel)\n\n      GIF (*comp always reports as 4-channel)\n      HDR (radiance rgbE format)\n      PIC (Softimage PIC)\n      PNM (PPM and PGM binary only)\n\n      Animated GIF still needs a proper API, but here's one way to do it:\n          http://gist.github.com/urraka/685d9a6340b26b830d49\n\n      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)\n      - decode from arbitrary I/O callbacks\n      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)\n\n   Full documentation under \"DOCUMENTATION\" below.\n\n\nLICENSE\n\n  See end of file for license information.\n\nRECENT REVISION HISTORY:\n\n      2.27  (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes\n      2.26  (2020-07-13) many minor fixes\n      2.25  (2020-02-02) fix warnings\n      2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically\n      2.23  (2019-08-11) fix clang static analysis warning\n      2.22  (2019-03-04) gif fixes, fix warnings\n      2.21  (2019-02-25) fix typo in comment\n      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs\n      2.19  (2018-02-11) fix warning\n      2.18  (2018-01-30) fix warnings\n      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings\n      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes\n      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64\n                         RGB-format JPEG; remove white matting in PSD;\n                         allocate large structures on the stack;\n                         correct channel count for PNG & BMP\n      2.10  (2016-01-22) avoid warning introduced in 2.09\n      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED\n\n   See end of file for full revision history.\n\n\n ============================    Contributors    =========================\n\n Image formats                          Extensions, features\n    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)\n    Nicolas Schulz (hdr, psd)              Martin \"SpartanJ\" Golini (stbi_info)\n    Jonathan Dummer (tga)                  James \"moose2000\" Brown (iPhone PNG)\n    Jean-Marc Lienher (gif)                Ben \"Disch\" Wenger (io callbacks)\n    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)\n    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)\n    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)\n    github:urraka (animated gif)           Junggon Kim (PNM comments)\n    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)\n                                           socks-the-fox (16-bit PNG)\n                                           Jeremy Sawicki (handle all ImageNet JPGs)\n Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)\n    Fabian \"ryg\" Giesen                    Anael Seghezzi (is-16-bit query)\n    Arseny Kapoulkine                      Simon Breuss (16-bit PNM)\n    John-Mark Allen\n    Carmelo J Fdez-Aguera\n\n Bug & warning fixes\n    Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko\n    Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski\n    Phil Jordan                                Dave Moore           Roy Eltham\n    Hayaki Saito            Nathan Reed        Won Chun\n    Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community\n    Thomas Ruf              Ronny Chevalier                         github:rlyeh\n    Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou\n    Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk\n    Eugene Golushkov        Laurent Gomila     Cort Stratton        github:snagar\n    Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex\n    Cass Everitt            Ryamond Barbiero                        github:grim210\n    Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw\n    Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus\n    Josh Tobin                                 Matthew Gregan       github:poppolopoppo\n    Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji\n    Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007\n                            Brad Weinberger    Matvey Cherevko      github:mosra\n    Luca Sas                Alexander Veselov  Zack Middleton       [reserved]\n    Ryan C. Gordon          [reserved]                              [reserved]\n                     DO NOT ADD YOUR NAME HERE\n\n                     Jacko Dirks\n\n  To add your name to the credits, pick a random blank space in the middle and fill it.\n  80% of merge conflicts on stb PRs are due to people adding their name at the end\n  of the credits.\n*/\n\n#ifndef STBI_INCLUDE_STB_IMAGE_H\n#define STBI_INCLUDE_STB_IMAGE_H\n\n// DOCUMENTATION\n//\n// Limitations:\n//    - no 12-bit-per-channel JPEG\n//    - no JPEGs with arithmetic coding\n//    - GIF always returns *comp=4\n//\n// Basic usage (see HDR discussion below for HDR usage):\n//    int x,y,n;\n//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n//    // ... process data if not NULL ...\n//    // ... x = width, y = height, n = # 8-bit components per pixel ...\n//    // ... replace '0' with '1'..'4' to force that many components per pixel\n//    // ... but 'n' will always be the number that it would have been if you said 0\n//    stbi_image_free(data)\n//\n// Standard parameters:\n//    int *x                 -- outputs image width in pixels\n//    int *y                 -- outputs image height in pixels\n//    int *channels_in_file  -- outputs # of image components in image file\n//    int desired_channels   -- if non-zero, # of image components requested in result\n//\n// The return value from an image loader is an 'unsigned char *' which points\n// to the pixel data, or NULL on an allocation failure or if the image is\n// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,\n// with each pixel consisting of N interleaved 8-bit components; the first\n// pixel pointed to is top-left-most in the image. There is no padding between\n// image scanlines or between pixels, regardless of format. The number of\n// components N is 'desired_channels' if desired_channels is non-zero, or\n// *channels_in_file otherwise. If desired_channels is non-zero,\n// *channels_in_file has the number of components that _would_ have been\n// output otherwise. E.g. if you set desired_channels to 4, you will always\n// get RGBA output, but you can check *channels_in_file to see if it's trivially\n// opaque because e.g. there were only 3 channels in the source image.\n//\n// An output image with N components has the following components interleaved\n// in this order in each pixel:\n//\n//     N=#comp     components\n//       1           grey\n//       2           grey, alpha\n//       3           red, green, blue\n//       4           red, green, blue, alpha\n//\n// If image loading fails for any reason, the return value will be NULL,\n// and *x, *y, *channels_in_file will be unchanged. The function\n// stbi_failure_reason() can be queried for an extremely brief, end-user\n// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS\n// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly\n// more user-friendly ones.\n//\n// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.\n//\n// To query the width, height and component count of an image without having to\n// decode the full file, you can use the stbi_info family of functions:\n//\n//   int x,y,n,ok;\n//   ok = stbi_info(filename, &x, &y, &n);\n//   // returns ok=1 and sets x, y, n if image is a supported format,\n//   // 0 otherwise.\n//\n// Note that stb_image pervasively uses ints in its public API for sizes,\n// including sizes of memory buffers. This is now part of the API and thus\n// hard to change without causing breakage. As a result, the various image\n// loaders all have certain limits on image size; these differ somewhat\n// by format but generally boil down to either just under 2GB or just under\n// 1GB. When the decoded image would be larger than this, stb_image decoding\n// will fail.\n//\n// Additionally, stb_image will reject image files that have any of their\n// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,\n// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,\n// the only way to have an image with such dimensions load correctly\n// is for it to have a rather extreme aspect ratio. Either way, the\n// assumption here is that such larger images are likely to be malformed\n// or malicious. If you do need to load an image with individual dimensions\n// larger than that, and it still fits in the overall size limit, you can\n// #define STBI_MAX_DIMENSIONS on your own to be something larger.\n//\n// ===========================================================================\n//\n// UNICODE:\n//\n//   If compiling for Windows and you wish to use Unicode filenames, compile\n//   with\n//       #define STBI_WINDOWS_UTF8\n//   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert\n//   Windows wchar_t filenames to utf8.\n//\n// ===========================================================================\n//\n// Philosophy\n//\n// stb libraries are designed with the following priorities:\n//\n//    1. easy to use\n//    2. easy to maintain\n//    3. good performance\n//\n// Sometimes I let \"good performance\" creep up in priority over \"easy to maintain\",\n// and for best performance I may provide less-easy-to-use APIs that give higher\n// performance, in addition to the easy-to-use ones. Nevertheless, it's important\n// to keep in mind that from the standpoint of you, a client of this library,\n// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.\n//\n// Some secondary priorities arise directly from the first two, some of which\n// provide more explicit reasons why performance can't be emphasized.\n//\n//    - Portable (\"ease of use\")\n//    - Small source code footprint (\"easy to maintain\")\n//    - No dependencies (\"ease of use\")\n//\n// ===========================================================================\n//\n// I/O callbacks\n//\n// I/O callbacks allow you to read from arbitrary sources, like packaged\n// files or some other source. Data read from callbacks are processed\n// through a small internal buffer (currently 128 bytes) to try to reduce\n// overhead.\n//\n// The three functions you must define are \"read\" (reads some bytes of data),\n// \"skip\" (skips some bytes of data), \"eof\" (reports if the stream is at the end).\n//\n// ===========================================================================\n//\n// SIMD support\n//\n// The JPEG decoder will try to automatically use SIMD kernels on x86 when\n// supported by the compiler. For ARM Neon support, you must explicitly\n// request it.\n//\n// (The old do-it-yourself SIMD API is no longer supported in the current\n// code.)\n//\n// On x86, SSE2 will automatically be used when available based on a run-time\n// test; if not, the generic C versions are used as a fall-back. On ARM targets,\n// the typical path is to have separate builds for NEON and non-NEON devices\n// (at least this is true for iOS and Android). Therefore, the NEON support is\n// toggled by a build flag: define STBI_NEON to get NEON loops.\n//\n// If for some reason you do not want to use any of SIMD code, or if\n// you have issues compiling it, you can disable it entirely by\n// defining STBI_NO_SIMD.\n//\n// ===========================================================================\n//\n// HDR image support   (disable by defining STBI_NO_HDR)\n//\n// stb_image supports loading HDR images in general, and currently the Radiance\n// .HDR file format specifically. You can still load any file through the existing\n// interface; if you attempt to load an HDR file, it will be automatically remapped\n// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;\n// both of these constants can be reconfigured through this interface:\n//\n//     stbi_hdr_to_ldr_gamma(2.2f);\n//     stbi_hdr_to_ldr_scale(1.0f);\n//\n// (note, do not use _inverse_ constants; stbi_image will invert them\n// appropriately).\n//\n// Additionally, there is a new, parallel interface for loading files as\n// (linear) floats to preserve the full dynamic range:\n//\n//    float *data = stbi_loadf(filename, &x, &y, &n, 0);\n//\n// If you load LDR images through this interface, those images will\n// be promoted to floating point values, run through the inverse of\n// constants corresponding to the above:\n//\n//     stbi_ldr_to_hdr_scale(1.0f);\n//     stbi_ldr_to_hdr_gamma(2.2f);\n//\n// Finally, given a filename (or an open file or memory block--see header\n// file for details) containing image data, you can query for the \"most\n// appropriate\" interface to use (that is, whether the image is HDR or\n// not), using:\n//\n//     stbi_is_hdr(char *filename);\n//\n// ===========================================================================\n//\n// iPhone PNG support:\n//\n// We optionally support converting iPhone-formatted PNGs (which store\n// premultiplied BGRA) back to RGB, even though they're internally encoded\n// differently. To enable this conversion, call\n// stbi_convert_iphone_png_to_rgb(1).\n//\n// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per\n// pixel to remove any premultiplied alpha *only* if the image file explicitly\n// says there's premultiplied data (currently only happens in iPhone images,\n// and only if iPhone convert-to-rgb processing is on).\n//\n// ===========================================================================\n//\n// ADDITIONAL CONFIGURATION\n//\n//  - You can suppress implementation of any of the decoders to reduce\n//    your code footprint by #defining one or more of the following\n//    symbols before creating the implementation.\n//\n//        STBI_NO_JPEG\n//        STBI_NO_PNG\n//        STBI_NO_BMP\n//        STBI_NO_PSD\n//        STBI_NO_TGA\n//        STBI_NO_GIF\n//        STBI_NO_HDR\n//        STBI_NO_PIC\n//        STBI_NO_PNM   (.ppm and .pgm)\n//\n//  - You can request *only* certain decoders and suppress all other ones\n//    (this will be more forward-compatible, as addition of new decoders\n//    doesn't require you to disable them explicitly):\n//\n//        STBI_ONLY_JPEG\n//        STBI_ONLY_PNG\n//        STBI_ONLY_BMP\n//        STBI_ONLY_PSD\n//        STBI_ONLY_TGA\n//        STBI_ONLY_GIF\n//        STBI_ONLY_HDR\n//        STBI_ONLY_PIC\n//        STBI_ONLY_PNM   (.ppm and .pgm)\n//\n//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still\n//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB\n//\n//  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater\n//    than that size (in either width or height) without further processing.\n//    This is to let programs in the wild set an upper bound to prevent\n//    denial-of-service attacks on untrusted data, as one could generate a\n//    valid image of gigantic dimensions and force stb_image to allocate a\n//    huge block of memory and spend disproportionate time decoding it. By\n//    default this is set to (1 << 24), which is 16777216, but that's still\n//    very big.\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif // STBI_NO_STDIO\n\n#define STBI_VERSION 1\n\nenum\n{\n   STBI_default = 0, // only used for desired_channels\n\n   STBI_grey       = 1,\n   STBI_grey_alpha = 2,\n   STBI_rgb        = 3,\n   STBI_rgb_alpha  = 4\n};\n\n#include <stdlib.h>\ntypedef unsigned char stbi_uc;\ntypedef unsigned short stbi_us;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef STBIDEF\n#ifdef STB_IMAGE_STATIC\n#define STBIDEF static\n#else\n#define STBIDEF extern\n#endif\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PRIMARY API - works on images of any type\n//\n\n//\n// load image by filename, open file, or memory buffer\n//\n\ntypedef struct\n{\n   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read\n   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative\n   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data\n} stbi_io_callbacks;\n\n////////////////////////////////////\n//\n// 8-bits-per-channel interface\n//\n\nSTBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n// for stbi_load_from_file, file pointer is left pointing immediately after image\n#endif\n\n#ifndef STBI_NO_GIF\nSTBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);\n#endif\n\n#ifdef STBI_WINDOWS_UTF8\nSTBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n\n////////////////////////////////////\n//\n// 16-bits-per-channel interface\n//\n\nSTBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n#endif\n\n////////////////////////////////////\n//\n// float-per-channel interface\n//\n#ifndef STBI_NO_LINEAR\n   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);\n\n   #ifndef STBI_NO_STDIO\n   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n   #endif\n#endif\n\n#ifndef STBI_NO_HDR\n   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);\n   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_LINEAR\n   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);\n   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);\n#endif // STBI_NO_LINEAR\n\n// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR\nSTBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);\nSTBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename);\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f);\n#endif // STBI_NO_STDIO\n\n\n// get a VERY brief reason for failure\n// on most compilers (and ALL modern mainstream compilers) this is threadsafe\nSTBIDEF const char *stbi_failure_reason  (void);\n\n// free the loaded image -- this is just free()\nSTBIDEF void     stbi_image_free      (void *retval_from_stbi_load);\n\n// get image dimensions & components without fully decoding\nSTBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\nSTBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);\nSTBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);\nSTBIDEF int      stbi_is_16_bit          (char const *filename);\nSTBIDEF int      stbi_is_16_bit_from_file(FILE *f);\n#endif\n\n\n\n// for image formats that explicitly notate that they have premultiplied alpha,\n// we just return the colors as stored in the file. set this flag to force\n// unpremultiplication. results are undefined if the unpremultiply overflow.\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);\n\n// indicate whether we should process iphone images back to canonical format,\n// or just pass them through \"as-is\"\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);\n\n// flip the image vertically, so the first pixel in the output array is the bottom left\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);\n\n// as above, but only applies to images loaded on the thread that calls the function\n// this function is only available if your compiler supports thread-local variables;\n// calling it will fail to link if your compiler doesn't\nSTBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);\nSTBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);\nSTBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);\n\n// ZLIB client - used by PNG, available for other purposes\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);\nSTBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\n#ifndef STBI_NO_DDS\n#include \"stbi_DDS.h\"\n#endif\n\n#ifndef STBI_NO_PVR\n#include \"stbi_pvr.h\"\n#endif\n\n#ifndef STBI_NO_PKM\n#include \"stbi_pkm.h\"\n#endif\n\n#ifndef STBI_NO_QOI\n#include \"stbi_qoi.h\"\n#endif\n\n#ifndef STBI_NO_EXT\n#include \"stbi_ext.h\"\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n//\n//\n////   end header file   /////////////////////////////////////////////////////\n#endif // STBI_INCLUDE_STB_IMAGE_H\n\n#ifdef STB_IMAGE_IMPLEMENTATION\n\n#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \\\n  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \\\n  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \\\n  || defined(STBI_ONLY_QOI) || defined(STBI_ONLY_ZLIB)\n   #ifndef STBI_ONLY_JPEG\n   #define STBI_NO_JPEG\n   #endif\n   #ifndef STBI_ONLY_PNG\n   #define STBI_NO_PNG\n   #endif\n   #ifndef STBI_ONLY_BMP\n   #define STBI_NO_BMP\n   #endif\n   #ifndef STBI_ONLY_PSD\n   #define STBI_NO_PSD\n   #endif\n   #ifndef STBI_ONLY_TGA\n   #define STBI_NO_TGA\n   #endif\n   #ifndef STBI_ONLY_GIF\n   #define STBI_NO_GIF\n   #endif\n   #ifndef STBI_ONLY_HDR\n   #define STBI_NO_HDR\n   #endif\n   #ifndef STBI_ONLY_PIC\n   #define STBI_NO_PIC\n   #endif\n   #ifndef STBI_ONLY_PNM\n   #define STBI_NO_PNM\n   #endif\n   #ifndef STBI_ONLY_QOI\n   #define STBI_NO_QOI\n   #endif\n#endif\n\n#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)\n#define STBI_NO_ZLIB\n#endif\n\n\n#include <stdarg.h>\n#include <stddef.h> // ptrdiff_t on osx\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)\n#include <math.h>  // ldexp, pow\n#endif\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif\n\n#ifndef STBI_ASSERT\n#include <assert.h>\n#define STBI_ASSERT(x) assert(x)\n#endif\n\n#ifdef __cplusplus\n#define STBI_EXTERN extern \"C\"\n#else\n#define STBI_EXTERN extern\n#endif\n\n\n#ifndef _MSC_VER\n   #ifdef __cplusplus\n   #define stbi_inline inline\n   #else\n   #define stbi_inline\n   #endif\n#else\n   #define stbi_inline __forceinline\n#endif\n\n#ifndef STBI_NO_THREAD_LOCALS\n   #if defined(__cplusplus) &&  __cplusplus >= 201103L\n      #define STBI_THREAD_LOCAL       thread_local\n   #elif defined(__GNUC__) && __GNUC__ < 5\n      #define STBI_THREAD_LOCAL       __thread\n   #elif defined(_MSC_VER)\n      #define STBI_THREAD_LOCAL       __declspec(thread)\n   #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)\n      #define STBI_THREAD_LOCAL       _Thread_local\n   #endif\n\n   #ifndef STBI_THREAD_LOCAL\n      #if defined(__GNUC__)\n        #define STBI_THREAD_LOCAL       __thread\n      #endif\n   #endif\n#endif\n\n#ifdef _MSC_VER\ntypedef unsigned short stbi__uint16;\ntypedef   signed short stbi__int16;\ntypedef unsigned int   stbi__uint32;\ntypedef   signed int   stbi__int32;\n#else\n#include <stdint.h>\ntypedef uint16_t stbi__uint16;\ntypedef int16_t  stbi__int16;\ntypedef uint32_t stbi__uint32;\ntypedef int32_t  stbi__int32;\n#endif\n\n// should produce compiler error if size is wrong\ntypedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];\n\n#ifdef _MSC_VER\n#define STBI_NOTUSED(v)  (void)(v)\n#else\n#define STBI_NOTUSED(v)  (void)sizeof(v)\n#endif\n\n#ifdef _MSC_VER\n#define STBI_HAS_LROTL\n#endif\n\n#ifdef STBI_HAS_LROTL\n   #define stbi_lrot(x,y)  _lrotl(x,y)\n#else\n   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (-(y) & 31)))\n#endif\n\n#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))\n// ok\n#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBI_MALLOC\n#define STBI_MALLOC(sz)           malloc(sz)\n#define STBI_REALLOC(p,newsz)     realloc(p,newsz)\n#define STBI_FREE(p)              free(p)\n#endif\n\n#ifndef STBI_REALLOC_SIZED\n#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)\n#endif\n\n// x86/x64 detection\n#if defined(__x86_64__) || defined(_M_X64)\n#define STBI__X64_TARGET\n#elif defined(__i386) || defined(_M_IX86)\n#define STBI__X86_TARGET\n#endif\n\n#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)\n// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET\n//\n// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the\n// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.\n// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not\n// simultaneously enabling \"-mstackrealign\".\n//\n// See https://github.com/nothings/stb/issues/81 for more information.\n//\n// So default to no SSE2 on 32-bit MinGW. If you've read this far and added\n// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.\n#define STBI_NO_SIMD\n#endif\n\n#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))\n#define STBI_SSE2\n#include <emmintrin.h>\n\n#ifdef _MSC_VER\n\n#if _MSC_VER >= 1400  // not VC6\n#include <intrin.h> // __cpuid\nstatic int stbi__cpuid3(void)\n{\n   int info[4];\n   __cpuid(info,1);\n   return info[3];\n}\n#else\nstatic int stbi__cpuid3(void)\n{\n   int res;\n   __asm {\n      mov  eax,1\n      cpuid\n      mov  res,edx\n   }\n   return res;\n}\n#endif\n\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n\n#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)\nstatic int stbi__sse2_available(void)\n{\n   int info3 = stbi__cpuid3();\n   return ((info3 >> 26) & 1) != 0;\n}\n#endif\n\n#else // assume GCC-style if not VC++\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n\n#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)\nstatic int stbi__sse2_available(void)\n{\n   // If we're even attempting to compile this on GCC/Clang, that means\n   // -msse2 is on, which means the compiler is allowed to use SSE2\n   // instructions at will, and so are we.\n   return 1;\n}\n#endif\n\n#endif\n#endif\n\n// ARM NEON\n#if defined(STBI_NO_SIMD) && defined(STBI_NEON)\n#undef STBI_NEON\n#endif\n\n#ifdef STBI_NEON\n#include <arm_neon.h>\n#ifdef _MSC_VER\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n#else\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n#endif\n\n#ifndef STBI_SIMD_ALIGN\n#define STBI_SIMD_ALIGN(type, name) type name\n#endif\n\n#ifndef STBI_MAX_DIMENSIONS\n#define STBI_MAX_DIMENSIONS (1 << 24)\n#endif\n\n///////////////////////////////////////////////\n//\n//  stbi__context struct and start_xxx functions\n\n// stbi__context structure is our basic context used by all images, so it\n// contains all the IO context, plus some basic image information\ntypedef struct\n{\n   stbi__uint32 img_x, img_y;\n   int img_n, img_out_n;\n\n   stbi_io_callbacks io;\n   void *io_user_data;\n\n   int read_from_callbacks;\n   int buflen;\n   stbi_uc buffer_start[128];\n   int callback_already_read;\n\n   stbi_uc *img_buffer, *img_buffer_end;\n   stbi_uc *img_buffer_original, *img_buffer_original_end;\n} stbi__context;\n\n\nstatic void stbi__refill_buffer(stbi__context *s);\n\n// initialize a memory-decode context\nstatic void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)\n{\n   s->io.read = NULL;\n   s->read_from_callbacks = 0;\n   s->callback_already_read = 0;\n   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;\n   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;\n}\n\n// initialize a callback-based context\nstatic void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)\n{\n   s->io = *c;\n   s->io_user_data = user;\n   s->buflen = sizeof(s->buffer_start);\n   s->read_from_callbacks = 1;\n   s->callback_already_read = 0;\n   s->img_buffer = s->img_buffer_original = s->buffer_start;\n   stbi__refill_buffer(s);\n   s->img_buffer_original_end = s->img_buffer_end;\n}\n\n#ifndef STBI_NO_STDIO\n\nstatic int stbi__stdio_read(void *user, char *data, int size)\n{\n   return (int) fread(data,1,size,(FILE*) user);\n}\n\nstatic void stbi__stdio_skip(void *user, int n)\n{\n   int ch;\n   fseek((FILE*) user, n, SEEK_CUR);\n   ch = fgetc((FILE*) user);  /* have to read a byte to reset feof()'s flag */\n   if (ch != EOF) {\n      ungetc(ch, (FILE *) user);  /* push byte back onto stream if valid. */\n   }\n}\n\nstatic int stbi__stdio_eof(void *user)\n{\n   return feof((FILE*) user) || ferror((FILE *) user);\n}\n\nstatic stbi_io_callbacks stbi__stdio_callbacks =\n{\n   stbi__stdio_read,\n   stbi__stdio_skip,\n   stbi__stdio_eof,\n};\n\nstatic void stbi__start_file(stbi__context *s, FILE *f)\n{\n   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);\n}\n\n//static void stop_file(stbi__context *s) { }\n\n#endif // !STBI_NO_STDIO\n\nstatic void stbi__rewind(stbi__context *s)\n{\n   // conceptually rewind SHOULD rewind to the beginning of the stream,\n   // but we just rewind to the beginning of the initial buffer, because\n   // we only use it after doing 'test', which only ever looks at at most 92 bytes\n   s->img_buffer = s->img_buffer_original;\n   s->img_buffer_end = s->img_buffer_original_end;\n}\n\nenum\n{\n   STBI_ORDER_RGB,\n   STBI_ORDER_BGR\n};\n\ntypedef struct\n{\n   int bits_per_channel;\n   int num_channels;\n   int channel_order;\n} stbi__result_info;\n\n#ifndef STBI_NO_JPEG\nstatic int      stbi__jpeg_test(stbi__context *s);\nstatic void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNG\nstatic int      stbi__png_test(stbi__context *s);\nstatic void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__png_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_BMP\nstatic int      stbi__bmp_test(stbi__context *s);\nstatic void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_TGA\nstatic int      stbi__tga_test(stbi__context *s);\nstatic void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int      stbi__psd_test(stbi__context *s);\nstatic void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);\nstatic int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__psd_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic int      stbi__hdr_test(stbi__context *s);\nstatic float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int      stbi__pic_test(stbi__context *s);\nstatic void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_GIF\nstatic int      stbi__gif_test(stbi__context *s);\nstatic void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic void    *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);\nstatic int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNM\nstatic int      stbi__pnm_test(stbi__context *s);\nstatic void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__pnm_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_DDS\nstatic int      stbi__dds_test(stbi__context *s);\nstatic void    *stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__dds_info(stbi__context *s, int *x, int *y, int *comp, int *iscompressed);\n#endif\n\n#ifndef STBI_NO_PVR\nstatic int      stbi__pvr_test(stbi__context *s);\nstatic void    *stbi__pvr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__pvr_info(stbi__context *s, int *x, int *y, int *comp, int * iscompressed);\n#endif\n\n#ifndef STBI_NO_PKM\nstatic int      stbi__pkm_test(stbi__context *s);\nstatic void    *stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__pkm_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_QOI\nstatic int      stbi__qoi_test(stbi__context *s);\nstatic void    *stbi__qoi_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__qoi_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\nstatic\n#ifdef STBI_THREAD_LOCAL\nSTBI_THREAD_LOCAL\n#endif\nconst char *stbi__g_failure_reason;\n\nSTBIDEF const char *stbi_failure_reason(void)\n{\n   return stbi__g_failure_reason;\n}\n\n#ifndef STBI_NO_FAILURE_STRINGS\nstatic int stbi__err(const char *str)\n{\n   stbi__g_failure_reason = str;\n   return 0;\n}\n#endif\n\nstatic void *stbi__malloc(size_t size)\n{\n    return STBI_MALLOC(size);\n}\n\n// stb_image uses ints pervasively, including for offset calculations.\n// therefore the largest decoded image size we can support with the\n// current code, even on 64-bit targets, is INT_MAX. this is not a\n// significant limitation for the intended use case.\n//\n// we do, however, need to make sure our size calculations don't\n// overflow. hence a few helper functions for size calculations that\n// multiply integers together, making sure that they're non-negative\n// and no overflow occurs.\n\n// return 1 if the sum is valid, 0 on overflow.\n// negative terms are considered invalid.\nstatic int stbi__addsizes_valid(int a, int b)\n{\n   if (b < 0) return 0;\n   // now 0 <= b <= INT_MAX, hence also\n   // 0 <= INT_MAX - b <= INTMAX.\n   // And \"a + b <= INT_MAX\" (which might overflow) is the\n   // same as a <= INT_MAX - b (no overflow)\n   return a <= INT_MAX - b;\n}\n\n// returns 1 if the product is valid, 0 on overflow.\n// negative factors are considered invalid.\nstatic int stbi__mul2sizes_valid(int a, int b)\n{\n   if (a < 0 || b < 0) return 0;\n   if (b == 0) return 1; // mul-by-0 is always safe\n   // portable way to check for no overflows in a*b\n   return a <= INT_MAX/b;\n}\n\n#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)\n// returns 1 if \"a*b + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad2sizes_valid(int a, int b, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);\n}\n#endif\n\n// returns 1 if \"a*b*c + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad3sizes_valid(int a, int b, int c, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__addsizes_valid(a*b*c, add);\n}\n\n// returns 1 if \"a*b*c*d + add\" has no negative terms/factors and doesn't overflow\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)\nstatic int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);\n}\n#endif\n\n#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)\n// mallocs with size overflow checking\nstatic void *stbi__malloc_mad2(int a, int b, int add)\n{\n   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;\n   return stbi__malloc(a*b + add);\n}\n#endif\n\nstatic void *stbi__malloc_mad3(int a, int b, int c, int add)\n{\n   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;\n   return stbi__malloc(a*b*c + add);\n}\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)\nstatic void *stbi__malloc_mad4(int a, int b, int c, int d, int add)\n{\n   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;\n   return stbi__malloc(a*b*c*d + add);\n}\n#endif\n\n// stbi__err - error\n// stbi__errpf - error returning pointer to float\n// stbi__errpuc - error returning pointer to unsigned char\n\n#ifdef STBI_NO_FAILURE_STRINGS\n   #define stbi__err(x,y)  0\n#elif defined(STBI_FAILURE_USERMSG)\n   #define stbi__err(x,y)  stbi__err(y)\n#else\n   #define stbi__err(x,y)  stbi__err(x)\n#endif\n\n#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))\n#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))\n\nSTBIDEF void stbi_image_free(void *retval_from_stbi_load)\n{\n   STBI_FREE(retval_from_stbi_load);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);\n#endif\n\nstatic int stbi__vertically_flip_on_load_global = 0;\n\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)\n{\n   stbi__vertically_flip_on_load_global = flag_true_if_should_flip;\n}\n\n#ifndef STBI_THREAD_LOCAL\n#define stbi__vertically_flip_on_load  stbi__vertically_flip_on_load_global\n#else\nstatic STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;\n\nSTBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)\n{\n   stbi__vertically_flip_on_load_local = flag_true_if_should_flip;\n   stbi__vertically_flip_on_load_set = 1;\n}\n\n#define stbi__vertically_flip_on_load  (stbi__vertically_flip_on_load_set       \\\n                                         ? stbi__vertically_flip_on_load_local  \\\n                                         : stbi__vertically_flip_on_load_global)\n#endif // STBI_THREAD_LOCAL\n\nstatic void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields\n   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed\n   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order\n   ri->num_channels = 0;\n\n   // test the formats with a very explicit header first (at least a FOURCC\n   // or distinctive magic number first)\n   #ifndef STBI_NO_PNG\n   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);\n   #else\n   STBI_NOTUSED(bpc);\n   #endif\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_DDS\n   if (stbi__dds_test(s))  return stbi__dds_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_PVR\n   if (stbi__pvr_test(s))  return stbi__pvr_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_PKM\n   if (stbi__pkm_test(s))  return stbi__pkm_load(s,x,y,comp,req_comp);\n   #endif\n   // then the formats that can end up attempting to load with just 1 or 2\n   // bytes matching expectations; these are prone to false positives, so\n   // try them later\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_QOI\n   if (stbi__qoi_test(s))  return stbi__qoi_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);\n      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);\n   }\n   #endif\n\n   #ifndef STBI_NO_TGA\n   // test tga last because it's a crappy test!\n   if (stbi__tga_test(s))\n      return stbi__tga_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   return stbi__errpuc(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi_uc *reduced;\n\n   reduced = (stbi_uc *) stbi__malloc(img_len);\n   if (reduced == NULL) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling\n\n   STBI_FREE(orig);\n   return reduced;\n}\n\nstatic stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi__uint16 *enlarged;\n\n   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);\n   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff\n\n   STBI_FREE(orig);\n   return enlarged;\n}\n\nstatic void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)\n{\n   int row;\n   size_t bytes_per_row = (size_t)w * bytes_per_pixel;\n   stbi_uc temp[2048];\n   stbi_uc *bytes = (stbi_uc *)image;\n\n   for (row = 0; row < (h>>1); row++) {\n      stbi_uc *row0 = bytes + row*bytes_per_row;\n      stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;\n      // swap row0 with row1\n      size_t bytes_left = bytes_per_row;\n      while (bytes_left) {\n         size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);\n         memcpy(temp, row0, bytes_copy);\n         memcpy(row0, row1, bytes_copy);\n         memcpy(row1, temp, bytes_copy);\n         row0 += bytes_copy;\n         row1 += bytes_copy;\n         bytes_left -= bytes_copy;\n      }\n   }\n}\n\n#ifndef STBI_NO_GIF\nstatic void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)\n{\n   int slice;\n   int slice_size = w * h * bytes_per_pixel;\n\n   stbi_uc *bytes = (stbi_uc *)image;\n   for (slice = 0; slice < z; ++slice) {\n      stbi__vertical_flip(bytes, w, h, bytes_per_pixel);\n      bytes += slice_size;\n   }\n}\n#endif\n\nstatic unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);\n\n   if (result == NULL)\n      return NULL;\n\n   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.\n   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);\n\n   if (ri.bits_per_channel != 8) {\n      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 8;\n   }\n\n   // @TODO: move stbi__convert_format to here\n\n   if (stbi__vertically_flip_on_load) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));\n   }\n\n   return (unsigned char *) result;\n}\n\nstatic stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);\n\n   if (result == NULL)\n      return NULL;\n\n   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.\n   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);\n\n   if (ri.bits_per_channel != 16) {\n      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 16;\n   }\n\n   // @TODO: move stbi__convert_format16 to here\n   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision\n\n   if (stbi__vertically_flip_on_load) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));\n   }\n\n   return (stbi__uint16 *) result;\n}\n\n#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)\nstatic void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)\n{\n   if (stbi__vertically_flip_on_load && result != NULL) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(float));\n   }\n}\n#endif\n\n#ifndef STBI_NO_STDIO\n\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\nSTBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n#endif\n\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\nSTBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n\treturn WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbi__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n\tif (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n\tif (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\tif (0 != _wfopen_s(&f, wFilename, wMode))\n\t\tf = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\n\nSTBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   unsigned char *result;\n   if (!f) return stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__uint16 *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   stbi__uint16 *result;\n   if (!f) return (stbi_us *) stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file_16(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\n\n#endif //!STBI_NO_STDIO\n\nSTBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);\n}\n\nSTBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);\n   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_GIF\nSTBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n\n   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);\n   if (stbi__vertically_flip_on_load) {\n      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );\n   }\n\n   return result;\n}\n#endif\n\n#ifndef STBI_NO_LINEAR\nstatic float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *data;\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      stbi__result_info ri;\n      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);\n      if (hdr_data)\n         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);\n      return hdr_data;\n   }\n   #endif\n   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);\n   if (data)\n      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);\n   return stbi__errpf(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nSTBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   float *result;\n   FILE *f = stbi__fopen(filename, \"rb\");\n   if (!f) return stbi__errpf(\"can't fopen\", \"Unable to open file\");\n   result = stbi_loadf_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n#endif // !STBI_NO_STDIO\n\n#endif // !STBI_NO_LINEAR\n\n// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is\n// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always\n// reports false!\n\nSTBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(buffer);\n   STBI_NOTUSED(len);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   int result=0;\n   if (f) {\n      result = stbi_is_hdr_from_file(f);\n      fclose(f);\n   }\n   return result;\n}\n\nSTBIDEF int stbi_is_hdr_from_file(FILE *f)\n{\n   #ifndef STBI_NO_HDR\n   long pos = ftell(f);\n   int res;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   res = stbi__hdr_test(&s);\n   fseek(f, pos, SEEK_SET);\n   return res;\n   #else\n   STBI_NOTUSED(f);\n   return 0;\n   #endif\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(clbk);\n   STBI_NOTUSED(user);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;\n\nSTBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }\nSTBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }\n#endif\n\nstatic float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;\n\nSTBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }\nSTBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Common code used by all image loaders\n//\n\nenum\n{\n   STBI__SCAN_load=0,\n   STBI__SCAN_type,\n   STBI__SCAN_header\n};\n\nstatic void stbi__refill_buffer(stbi__context *s)\n{\n   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);\n   s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);\n   if (n == 0) {\n      // at end of file, treat same as if from memory, but need to handle case\n      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file\n      s->read_from_callbacks = 0;\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start+1;\n      *s->img_buffer = 0;\n   } else {\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start + n;\n   }\n}\n\nstbi_inline static stbi_uc stbi__get8(stbi__context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n   if (s->read_from_callbacks) {\n      stbi__refill_buffer(s);\n      return *s->img_buffer++;\n   }\n   return 0;\n}\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\nstbi_inline static int stbi__at_eof(stbi__context *s)\n{\n   if (s->io.read) {\n      if (!(s->io.eof)(s->io_user_data)) return 0;\n      // if feof() is true, check if buffer = end\n      // special case: we've only got the special 0 character at the end\n      if (s->read_from_callbacks == 0) return 1;\n   }\n\n   return s->img_buffer >= s->img_buffer_end;\n}\n#endif\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic void stbi__skip(stbi__context *s, int n)\n{\n   if (n == 0) return;  // already there!\n   if (n < 0) {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         s->img_buffer = s->img_buffer_end;\n         (s->io.skip)(s->io_user_data, n - blen);\n         return;\n      }\n   }\n   s->img_buffer += n;\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)\n// nothing\n#else\nstatic int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)\n{\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         int res, count;\n\n         memcpy(buffer, s->img_buffer, blen);\n\n         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);\n         res = (count == (n-blen));\n         s->img_buffer = s->img_buffer_end;\n         return res;\n      }\n   }\n\n   if (s->img_buffer+n <= s->img_buffer_end) {\n      memcpy(buffer, s->img_buffer, n);\n      s->img_buffer += n;\n      return 1;\n   } else\n      return 0;\n}\n#endif\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic int stbi__get16be(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return (z << 8) + stbi__get8(s);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) && defined(STBI_NO_QOI)\n// nothing\n#else\nstatic stbi__uint32 stbi__get32be(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16be(s);\n   return (z << 16) + stbi__get16be(s);\n}\n#endif\n\n#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)\n// nothing\n#else\nstatic int stbi__get16le(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return z + (stbi__get8(s) << 8);\n}\n#endif\n\n#ifndef STBI_NO_BMP\nstatic stbi__uint32 stbi__get32le(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16le(s);\n   z += (stbi__uint32)stbi__get16le(s) << 16;\n   return z;\n}\n#endif\n\n#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\n//////////////////////////////////////////////////////////////////////////////\n//\n//  generic converter from built-in img_n to req_comp\n//    individual types do this automatically as much as possible (e.g. jpeg\n//    does all cases internally since it needs to colorspace convert anyway,\n//    and it never has alpha, so very few cases ). png can automatically\n//    interleave an alpha=255 channel, but falls back to this for other cases\n//\n//  assume data buffer is malloced, so malloc a new one and free that one\n//  only failure mode is malloc failing\n\nstatic stbi_uc stbi__compute_y(int r, int g, int b)\n{\n   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\nstatic unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   unsigned char *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      unsigned char *src  = data + j * x * img_n   ;\n      unsigned char *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                  } break;\n         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255;    } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                    } break;\n         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc(\"unsupported\", \"Unsupported format conversion\");\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)\n// nothing\n#else\nstatic stbi__uint16 stbi__compute_y_16(int r, int g, int b)\n{\n   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)\n// nothing\n#else\nstatic stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   stbi__uint16 *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      stbi__uint16 *src  = data + j * x * img_n   ;\n      stbi__uint16 *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                     } break;\n         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                       } break;\n         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc(\"unsupported\", \"Unsupported format conversion\");\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n#endif\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)\n{\n   int i,k,n;\n   float *output;\n   if (!data) return NULL;\n   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpf(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);\n      }\n   }\n   if (n < comp) {\n      for (i=0; i < x*y; ++i) {\n         output[i*comp + n] = data[i*comp + n]/255.0f;\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n#ifndef STBI_NO_HDR\n#define stbi__float2int(x)   ((int) (x))\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)\n{\n   int i,k,n;\n   stbi_uc *output;\n   if (!data) return NULL;\n   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n      if (k < comp) {\n         float z = data[i*comp+k] * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  \"baseline\" JPEG/JFIF decoder\n//\n//    simple implementation\n//      - doesn't support delayed output of y-dimension\n//      - simple interface (only one output format: 8-bit interleaved RGB)\n//      - doesn't try to recover corrupt jpegs\n//      - doesn't allow partial loading, loading multiple at once\n//      - still fast on x86 (copying globals into locals doesn't help x86)\n//      - allocates lots of intermediate memory (full size of all components)\n//        - non-interleaved case requires this anyway\n//        - allows good upsampling (see next)\n//    high-quality\n//      - upsampled channels are bilinearly interpolated, even across blocks\n//      - quality integer IDCT derived from IJG's 'slow'\n//    performance\n//      - fast huffman; reasonable integer IDCT\n//      - some SIMD kernels for common paths on targets with SSE2/NEON\n//      - uses a lot of intermediate memory, could cache poorly\n\n#ifndef STBI_NO_JPEG\n\n// huffman decoding acceleration\n#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache\n\ntypedef struct\n{\n   stbi_uc  fast[1 << FAST_BITS];\n   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win\n   stbi__uint16 code[256];\n   stbi_uc  values[256];\n   stbi_uc  size[257];\n   unsigned int maxcode[18];\n   int    delta[17];   // old 'firstsymbol' - old 'firstcode'\n} stbi__huffman;\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi__huffman huff_dc[4];\n   stbi__huffman huff_ac[4];\n   stbi__uint16 dequant[4][64];\n   stbi__int16 fast_ac[4][1 << FAST_BITS];\n\n// sizes for components, interleaved MCUs\n   int img_h_max, img_v_max;\n   int img_mcu_x, img_mcu_y;\n   int img_mcu_w, img_mcu_h;\n\n// definition of jpeg image component\n   struct\n   {\n      int id;\n      int h,v;\n      int tq;\n      int hd,ha;\n      int dc_pred;\n\n      int x,y,w2,h2;\n      stbi_uc *data;\n      void *raw_data, *raw_coeff;\n      stbi_uc *linebuf;\n      short   *coeff;   // progressive only\n      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks\n   } img_comp[4];\n\n   stbi__uint32   code_buffer; // jpeg entropy-coded buffer\n   int            code_bits;   // number of valid bits\n   unsigned char  marker;      // marker seen while filling entropy buffer\n   int            nomore;      // flag if we saw a marker so must stop\n\n   int            progressive;\n   int            spec_start;\n   int            spec_end;\n   int            succ_high;\n   int            succ_low;\n   int            eob_run;\n   int            jfif;\n   int            app14_color_transform; // Adobe APP14 tag\n   int            rgb;\n\n   int scan_n, order[4];\n   int restart_interval, todo;\n\n// kernels\n   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);\n   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);\n   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);\n} stbi__jpeg;\n\nstatic int stbi__build_huffman(stbi__huffman *h, int *count)\n{\n   int i,j,k=0;\n   unsigned int code;\n   // build size list for each symbol (from JPEG spec)\n   for (i=0; i < 16; ++i)\n      for (j=0; j < count[i]; ++j)\n         h->size[k++] = (stbi_uc) (i+1);\n   h->size[k] = 0;\n\n   // compute actual symbols (from jpeg spec)\n   code = 0;\n   k = 0;\n   for(j=1; j <= 16; ++j) {\n      // compute delta to add to code to compute symbol id\n      h->delta[j] = k - code;\n      if (h->size[k] == j) {\n         while (h->size[k] == j)\n            h->code[k++] = (stbi__uint16) (code++);\n         if (code-1 >= (1u << j)) return stbi__err(\"bad code lengths\",\"Corrupt JPEG\");\n      }\n      // compute largest code + 1 for this size, preshifted as needed later\n      h->maxcode[j] = code << (16-j);\n      code <<= 1;\n   }\n   h->maxcode[j] = 0xffffffff;\n\n   // build non-spec acceleration table; 255 is flag for not-accelerated\n   memset(h->fast, 255, 1 << FAST_BITS);\n   for (i=0; i < k; ++i) {\n      int s = h->size[i];\n      if (s <= FAST_BITS) {\n         int c = h->code[i] << (FAST_BITS-s);\n         int m = 1 << (FAST_BITS-s);\n         for (j=0; j < m; ++j) {\n            h->fast[c+j] = (stbi_uc) i;\n         }\n      }\n   }\n   return 1;\n}\n\n// build a table that decodes both magnitude and value of small ACs in\n// one go.\nstatic void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)\n{\n   int i;\n   for (i=0; i < (1 << FAST_BITS); ++i) {\n      stbi_uc fast = h->fast[i];\n      fast_ac[i] = 0;\n      if (fast < 255) {\n         int rs = h->values[fast];\n         int run = (rs >> 4) & 15;\n         int magbits = rs & 15;\n         int len = h->size[fast];\n\n         if (magbits && len + magbits <= FAST_BITS) {\n            // magnitude code followed by receive_extend code\n            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);\n            int m = 1 << (magbits - 1);\n            if (k < m) k += (~0U << magbits) + 1;\n            // if the result is small enough, we can fit it in fast_ac table\n            if (k >= -128 && k <= 127)\n               fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));\n         }\n      }\n   }\n}\n\nstatic void stbi__grow_buffer_unsafe(stbi__jpeg *j)\n{\n   do {\n      unsigned int b = j->nomore ? 0 : stbi__get8(j->s);\n      if (b == 0xff) {\n         int c = stbi__get8(j->s);\n         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes\n         if (c != 0) {\n            j->marker = (unsigned char) c;\n            j->nomore = 1;\n            return;\n         }\n      }\n      j->code_buffer |= b << (24 - j->code_bits);\n      j->code_bits += 8;\n   } while (j->code_bits <= 24);\n}\n\n// (1 << n) - 1\nstatic const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};\n\n// decode a jpeg huffman value from the bitstream\nstbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)\n{\n   unsigned int temp;\n   int c,k;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   // look at the top FAST_BITS and determine what symbol ID it is,\n   // if the code is <= FAST_BITS\n   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   k = h->fast[c];\n   if (k < 255) {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   // naive test is to shift the code_buffer down so k bits are\n   // valid, then test against maxcode. To speed this up, we've\n   // preshifted maxcode left so that it has (16-k) 0s at the\n   // end; in other words, regardless of the number of bits, it\n   // wants to be compared against something shifted to have 16;\n   // that way we don't need to shift inside the loop.\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n   if (k == 17) {\n      // error! code not found\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   // convert the huffman code to the symbol id\n   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];\n   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);\n\n   // convert the id to a symbol\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n// bias[n] = (-1<<n) + 1\nstatic const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};\n\n// combined JPEG 'receive' and JPEG 'extend', since baseline\n// always extends everything it receives.\nstbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   int sgn;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n\n   sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k + (stbi__jbias[n] & (sgn - 1));\n}\n\n// get some unsigned bits\nstbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k;\n}\n\nstbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)\n{\n   unsigned int k;\n   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);\n   k = j->code_buffer;\n   j->code_buffer <<= 1;\n   --j->code_bits;\n   return k & 0x80000000;\n}\n\n// given a value that's at position X in the zigzag stream,\n// where does it appear in the 8x8 matrix coded as row-major?\nstatic const stbi_uc stbi__jpeg_dezigzag[64+15] =\n{\n    0,  1,  8, 16,  9,  2,  3, 10,\n   17, 24, 32, 25, 18, 11,  4,  5,\n   12, 19, 26, 33, 40, 48, 41, 34,\n   27, 20, 13,  6,  7, 14, 21, 28,\n   35, 42, 49, 56, 57, 50, 43, 36,\n   29, 22, 15, 23, 30, 37, 44, 51,\n   58, 59, 52, 45, 38, 31, 39, 46,\n   53, 60, 61, 54, 47, 55, 62, 63,\n   // let corrupt input sample past end\n   63, 63, 63, 63, 63, 63, 63, 63,\n   63, 63, 63, 63, 63, 63, 63\n};\n\n// decode one 64-entry block--\nstatic int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)\n{\n   int diff,dc,k;\n   int t;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n   t = stbi__jpeg_huff_decode(j, hdc);\n   if (t < 0 || t > 15) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n\n   // 0 all the ac values now so we can do it 32-bits at a time\n   memset(data,0,64*sizeof(data[0]));\n\n   diff = t ? stbi__extend_receive(j, t) : 0;\n   dc = j->img_comp[b].dc_pred + diff;\n   j->img_comp[b].dc_pred = dc;\n   data[0] = (short) (dc * dequant[0]);\n\n   // decode AC components, see JPEG spec\n   k = 1;\n   do {\n      unsigned int zig;\n      int c,r,s;\n      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n      r = fac[c];\n      if (r) { // fast-AC path\n         k += (r >> 4) & 15; // run\n         s = r & 15; // combined length\n         j->code_buffer <<= s;\n         j->code_bits -= s;\n         // decode into unzigzag'd location\n         zig = stbi__jpeg_dezigzag[k++];\n         data[zig] = (short) ((r >> 8) * dequant[zig]);\n      } else {\n         int rs = stbi__jpeg_huff_decode(j, hac);\n         if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n         s = rs & 15;\n         r = rs >> 4;\n         if (s == 0) {\n            if (rs != 0xf0) break; // end block\n            k += 16;\n         } else {\n            k += r;\n            // decode into unzigzag'd location\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);\n         }\n      }\n   } while (k < 64);\n   return 1;\n}\n\nstatic int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)\n{\n   int diff,dc;\n   int t;\n   if (j->spec_end != 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   if (j->succ_high == 0) {\n      // first scan for DC coefficient, must be first\n      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now\n      t = stbi__jpeg_huff_decode(j, hdc);\n      if (t < 0 || t > 15) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n      diff = t ? stbi__extend_receive(j, t) : 0;\n\n      dc = j->img_comp[b].dc_pred + diff;\n      j->img_comp[b].dc_pred = dc;\n      data[0] = (short) (dc * (1 << j->succ_low));\n   } else {\n      // refinement scan for DC coefficient\n      if (stbi__jpeg_get_bit(j))\n         data[0] += (short) (1 << j->succ_low);\n   }\n   return 1;\n}\n\n// @OPTIMIZE: store non-zigzagged during the decode passes,\n// and only de-zigzag when dequantizing\nstatic int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)\n{\n   int k;\n   if (j->spec_start == 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->succ_high == 0) {\n      int shift = j->succ_low;\n\n      if (j->eob_run) {\n         --j->eob_run;\n         return 1;\n      }\n\n      k = j->spec_start;\n      do {\n         unsigned int zig;\n         int c,r,s;\n         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n         r = fac[c];\n         if (r) { // fast-AC path\n            k += (r >> 4) & 15; // run\n            s = r & 15; // combined length\n            j->code_buffer <<= s;\n            j->code_bits -= s;\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) ((r >> 8) * (1 << shift));\n         } else {\n            int rs = stbi__jpeg_huff_decode(j, hac);\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r);\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  --j->eob_run;\n                  break;\n               }\n               k += 16;\n            } else {\n               k += r;\n               zig = stbi__jpeg_dezigzag[k++];\n               data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift));\n            }\n         }\n      } while (k <= j->spec_end);\n   } else {\n      // refinement scan for these AC coefficients\n\n      short bit = (short) (1 << j->succ_low);\n\n      if (j->eob_run) {\n         --j->eob_run;\n         for (k = j->spec_start; k <= j->spec_end; ++k) {\n            short *p = &data[stbi__jpeg_dezigzag[k]];\n            if (*p != 0)\n               if (stbi__jpeg_get_bit(j))\n                  if ((*p & bit)==0) {\n                     if (*p > 0)\n                        *p += bit;\n                     else\n                        *p -= bit;\n                  }\n         }\n      } else {\n         k = j->spec_start;\n         do {\n            int r,s;\n            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r) - 1;\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  r = 64; // force end of block\n               } else {\n                  // r=15 s=0 should write 16 0s, so we just do\n                  // a run of 15 0s and then write s (which is 0),\n                  // so we don't have to do anything special here\n               }\n            } else {\n               if (s != 1) return stbi__err(\"bad huffman code\", \"Corrupt JPEG\");\n               // sign bit\n               if (stbi__jpeg_get_bit(j))\n                  s = bit;\n               else\n                  s = -bit;\n            }\n\n            // advance by r\n            while (k <= j->spec_end) {\n               short *p = &data[stbi__jpeg_dezigzag[k++]];\n               if (*p != 0) {\n                  if (stbi__jpeg_get_bit(j))\n                     if ((*p & bit)==0) {\n                        if (*p > 0)\n                           *p += bit;\n                        else\n                           *p -= bit;\n                     }\n               } else {\n                  if (r == 0) {\n                     *p = (short) s;\n                     break;\n                  }\n                  --r;\n               }\n            }\n         } while (k <= j->spec_end);\n      }\n   }\n   return 1;\n}\n\n// take a -128..127 value and stbi__clamp it and convert to 0..255\nstbi_inline static stbi_uc stbi__clamp(int x)\n{\n   // trick to use a single test to catch both cases\n   if ((unsigned int) x > 255) {\n      if (x < 0) return 0;\n      if (x > 255) return 255;\n   }\n   return (stbi_uc) x;\n}\n\n#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))\n#define stbi__fsh(x)  ((x) * 4096)\n\n// derived from jidctint -- DCT_ISLOW\n#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \\\n   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \\\n   p2 = s2;                                    \\\n   p3 = s6;                                    \\\n   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \\\n   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \\\n   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \\\n   p2 = s0;                                    \\\n   p3 = s4;                                    \\\n   t0 = stbi__fsh(p2+p3);                      \\\n   t1 = stbi__fsh(p2-p3);                      \\\n   x0 = t0+t3;                                 \\\n   x3 = t0-t3;                                 \\\n   x1 = t1+t2;                                 \\\n   x2 = t1-t2;                                 \\\n   t0 = s7;                                    \\\n   t1 = s5;                                    \\\n   t2 = s3;                                    \\\n   t3 = s1;                                    \\\n   p3 = t0+t2;                                 \\\n   p4 = t1+t3;                                 \\\n   p1 = t0+t3;                                 \\\n   p2 = t1+t2;                                 \\\n   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \\\n   t0 = t0*stbi__f2f( 0.298631336f);           \\\n   t1 = t1*stbi__f2f( 2.053119869f);           \\\n   t2 = t2*stbi__f2f( 3.072711026f);           \\\n   t3 = t3*stbi__f2f( 1.501321110f);           \\\n   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \\\n   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \\\n   p3 = p3*stbi__f2f(-1.961570560f);           \\\n   p4 = p4*stbi__f2f(-0.390180644f);           \\\n   t3 += p1+p4;                                \\\n   t2 += p2+p3;                                \\\n   t1 += p2+p4;                                \\\n   t0 += p1+p3;\n\nstatic void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])\n{\n   int i,val[64],*v=val;\n   stbi_uc *o;\n   short *d = data;\n\n   // columns\n   for (i=0; i < 8; ++i,++d, ++v) {\n      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing\n      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0\n           && d[40]==0 && d[48]==0 && d[56]==0) {\n         //    no shortcut                 0     seconds\n         //    (1|2|3|4|5|6|7)==0          0     seconds\n         //    all separate               -0.047 seconds\n         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds\n         int dcterm = d[0]*4;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      } else {\n         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])\n         // constants scaled things up by 1<<12; let's bring them back\n         // down, but keep 2 extra bits of precision\n         x0 += 512; x1 += 512; x2 += 512; x3 += 512;\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {\n      // no fast case since the first 1D IDCT spread components out\n      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])\n      // constants scaled things up by 1<<12, plus we had 1<<2 from first\n      // loop, plus horizontal and vertical each scale by sqrt(8) so together\n      // we've got an extra 1<<3, so 1<<17 total we need to remove.\n      // so we want to round that, which means adding 0.5 * 1<<17,\n      // aka 65536. Also, we'll end up with -128 to 127 that we want\n      // to encode as 0..255 by adding 128, so we'll add that before the shift\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n      // tried computing the shifts into temps, or'ing the temps to see\n      // if any were out of range, but that was slower\n      o[0] = stbi__clamp((x0+t3) >> 17);\n      o[7] = stbi__clamp((x0-t3) >> 17);\n      o[1] = stbi__clamp((x1+t2) >> 17);\n      o[6] = stbi__clamp((x1-t2) >> 17);\n      o[2] = stbi__clamp((x2+t1) >> 17);\n      o[5] = stbi__clamp((x2-t1) >> 17);\n      o[3] = stbi__clamp((x3+t0) >> 17);\n      o[4] = stbi__clamp((x3-t0) >> 17);\n   }\n}\n\n#ifdef STBI_SSE2\n// sse2 integer IDCT. not the fastest possible implementation but it\n// produces bit-identical results to the generic C version so it's\n// fully \"transparent\".\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   // This is constructed to match our regular (generic) integer IDCT exactly.\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n\n   // dot product constant: even elems=x, odd elems=y\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)\n   // out(1) = c1[even]*x + c1[odd]*y\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   // out = in << 12  (in 16-bit, out 32-bit)\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   // wide add\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   // wide sub\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   // butterfly a/b, add bias, then shift by \"s\" and pack\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   // 8-bit interleave step (for transposes)\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   // 16-bit interleave step (for transposes)\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         /* even part */ \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         /* odd part */ \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));\n   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));\n   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));\n   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));\n   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));\n   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));\n   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));\n   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));\n\n   // rounding biases in column/row passes, see stbi__idct_block for explanation.\n   __m128i bias_0 = _mm_set1_epi32(512);\n   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n   // load\n   row0 = _mm_load_si128((const __m128i *) (data + 0*8));\n   row1 = _mm_load_si128((const __m128i *) (data + 1*8));\n   row2 = _mm_load_si128((const __m128i *) (data + 2*8));\n   row3 = _mm_load_si128((const __m128i *) (data + 3*8));\n   row4 = _mm_load_si128((const __m128i *) (data + 4*8));\n   row5 = _mm_load_si128((const __m128i *) (data + 5*8));\n   row6 = _mm_load_si128((const __m128i *) (data + 6*8));\n   row7 = _mm_load_si128((const __m128i *) (data + 7*8));\n\n   // column pass\n   dct_pass(bias_0, 10);\n\n   {\n      // 16bit 8x8 transpose pass 1\n      dct_interleave16(row0, row4);\n      dct_interleave16(row1, row5);\n      dct_interleave16(row2, row6);\n      dct_interleave16(row3, row7);\n\n      // transpose pass 2\n      dct_interleave16(row0, row2);\n      dct_interleave16(row1, row3);\n      dct_interleave16(row4, row6);\n      dct_interleave16(row5, row7);\n\n      // transpose pass 3\n      dct_interleave16(row0, row1);\n      dct_interleave16(row2, row3);\n      dct_interleave16(row4, row5);\n      dct_interleave16(row6, row7);\n   }\n\n   // row pass\n   dct_pass(bias_1, 17);\n\n   {\n      // pack\n      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7\n      __m128i p1 = _mm_packus_epi16(row2, row3);\n      __m128i p2 = _mm_packus_epi16(row4, row5);\n      __m128i p3 = _mm_packus_epi16(row6, row7);\n\n      // 8bit 8x8 transpose pass 1\n      dct_interleave8(p0, p2); // a0e0a1e1...\n      dct_interleave8(p1, p3); // c0g0c1g1...\n\n      // transpose pass 2\n      dct_interleave8(p0, p1); // a0c0e0g0...\n      dct_interleave8(p2, p3); // b0d0f0h0...\n\n      // transpose pass 3\n      dct_interleave8(p0, p2); // a0b0c0d0...\n      dct_interleave8(p1, p3); // a4b4c4d4...\n\n      // store\n      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n   }\n\n#undef dct_const\n#undef dct_rot\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_interleave8\n#undef dct_interleave16\n#undef dct_pass\n}\n\n#endif // STBI_SSE2\n\n#ifdef STBI_NEON\n\n// NEON integer IDCT. should produce bit-identical\n// results to the generic C version.\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;\n\n   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));\n   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));\n   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));\n   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));\n   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));\n   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));\n   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));\n   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));\n   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));\n   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));\n   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));\n   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));\n\n#define dct_long_mul(out, inq, coeff) \\\n   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)\n\n#define dct_long_mac(out, acc, inq, coeff) \\\n   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)\n\n#define dct_widen(out, inq) \\\n   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \\\n   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)\n\n// wide add\n#define dct_wadd(out, a, b) \\\n   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)\n\n// wide sub\n#define dct_wsub(out, a, b) \\\n   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)\n\n// butterfly a/b, then shift using \"shiftop\" by \"s\" and pack\n#define dct_bfly32o(out0,out1, a,b,shiftop,s) \\\n   { \\\n      dct_wadd(sum, a, b); \\\n      dct_wsub(dif, a, b); \\\n      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \\\n      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \\\n   }\n\n#define dct_pass(shiftop, shift) \\\n   { \\\n      /* even part */ \\\n      int16x8_t sum26 = vaddq_s16(row2, row6); \\\n      dct_long_mul(p1e, sum26, rot0_0); \\\n      dct_long_mac(t2e, p1e, row6, rot0_1); \\\n      dct_long_mac(t3e, p1e, row2, rot0_2); \\\n      int16x8_t sum04 = vaddq_s16(row0, row4); \\\n      int16x8_t dif04 = vsubq_s16(row0, row4); \\\n      dct_widen(t0e, sum04); \\\n      dct_widen(t1e, dif04); \\\n      dct_wadd(x0, t0e, t3e); \\\n      dct_wsub(x3, t0e, t3e); \\\n      dct_wadd(x1, t1e, t2e); \\\n      dct_wsub(x2, t1e, t2e); \\\n      /* odd part */ \\\n      int16x8_t sum15 = vaddq_s16(row1, row5); \\\n      int16x8_t sum17 = vaddq_s16(row1, row7); \\\n      int16x8_t sum35 = vaddq_s16(row3, row5); \\\n      int16x8_t sum37 = vaddq_s16(row3, row7); \\\n      int16x8_t sumodd = vaddq_s16(sum17, sum35); \\\n      dct_long_mul(p5o, sumodd, rot1_0); \\\n      dct_long_mac(p1o, p5o, sum17, rot1_1); \\\n      dct_long_mac(p2o, p5o, sum35, rot1_2); \\\n      dct_long_mul(p3o, sum37, rot2_0); \\\n      dct_long_mul(p4o, sum15, rot2_1); \\\n      dct_wadd(sump13o, p1o, p3o); \\\n      dct_wadd(sump24o, p2o, p4o); \\\n      dct_wadd(sump23o, p2o, p3o); \\\n      dct_wadd(sump14o, p1o, p4o); \\\n      dct_long_mac(x4, sump13o, row7, rot3_0); \\\n      dct_long_mac(x5, sump24o, row5, rot3_1); \\\n      dct_long_mac(x6, sump23o, row3, rot3_2); \\\n      dct_long_mac(x7, sump14o, row1, rot3_3); \\\n      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \\\n      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \\\n      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \\\n      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \\\n   }\n\n   // load\n   row0 = vld1q_s16(data + 0*8);\n   row1 = vld1q_s16(data + 1*8);\n   row2 = vld1q_s16(data + 2*8);\n   row3 = vld1q_s16(data + 3*8);\n   row4 = vld1q_s16(data + 4*8);\n   row5 = vld1q_s16(data + 5*8);\n   row6 = vld1q_s16(data + 6*8);\n   row7 = vld1q_s16(data + 7*8);\n\n   // add DC bias\n   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));\n\n   // column pass\n   dct_pass(vrshrn_n_s32, 10);\n\n   // 16bit 8x8 transpose\n   {\n// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.\n// whether compilers actually get this is another story, sadly.\n#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }\n#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }\n\n      // pass 1\n      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6\n      dct_trn16(row2, row3);\n      dct_trn16(row4, row5);\n      dct_trn16(row6, row7);\n\n      // pass 2\n      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4\n      dct_trn32(row1, row3);\n      dct_trn32(row4, row6);\n      dct_trn32(row5, row7);\n\n      // pass 3\n      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0\n      dct_trn64(row1, row5);\n      dct_trn64(row2, row6);\n      dct_trn64(row3, row7);\n\n#undef dct_trn16\n#undef dct_trn32\n#undef dct_trn64\n   }\n\n   // row pass\n   // vrshrn_n_s32 only supports shifts up to 16, we need\n   // 17. so do a non-rounding shift of 16 first then follow\n   // up with a rounding shift by 1.\n   dct_pass(vshrn_n_s32, 16);\n\n   {\n      // pack and round\n      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);\n      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);\n      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);\n      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);\n      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);\n      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);\n      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);\n      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);\n\n      // again, these can translate into one instruction, but often don't.\n#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }\n#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }\n\n      // sadly can't use interleaved stores here since we only write\n      // 8 bytes to each scan line!\n\n      // 8x8 8-bit transpose pass 1\n      dct_trn8_8(p0, p1);\n      dct_trn8_8(p2, p3);\n      dct_trn8_8(p4, p5);\n      dct_trn8_8(p6, p7);\n\n      // pass 2\n      dct_trn8_16(p0, p2);\n      dct_trn8_16(p1, p3);\n      dct_trn8_16(p4, p6);\n      dct_trn8_16(p5, p7);\n\n      // pass 3\n      dct_trn8_32(p0, p4);\n      dct_trn8_32(p1, p5);\n      dct_trn8_32(p2, p6);\n      dct_trn8_32(p3, p7);\n\n      // store\n      vst1_u8(out, p0); out += out_stride;\n      vst1_u8(out, p1); out += out_stride;\n      vst1_u8(out, p2); out += out_stride;\n      vst1_u8(out, p3); out += out_stride;\n      vst1_u8(out, p4); out += out_stride;\n      vst1_u8(out, p5); out += out_stride;\n      vst1_u8(out, p6); out += out_stride;\n      vst1_u8(out, p7);\n\n#undef dct_trn8_8\n#undef dct_trn8_16\n#undef dct_trn8_32\n   }\n\n#undef dct_long_mul\n#undef dct_long_mac\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_pass\n}\n\n#endif // STBI_NEON\n\n#define STBI__MARKER_none  0xff\n// if there's a pending marker from the entropy stream, return that\n// otherwise, fetch from the stream and get a marker. if there's no\n// marker, return 0xff, which is never a valid marker value\nstatic stbi_uc stbi__get_marker(stbi__jpeg *j)\n{\n   stbi_uc x;\n   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }\n   x = stbi__get8(j->s);\n   if (x != 0xff) return STBI__MARKER_none;\n   while (x == 0xff)\n      x = stbi__get8(j->s); // consume repeated 0xff fill bytes\n   return x;\n}\n\n// in each scan, we'll have scan_n components, and the order\n// of the components is specified by order[]\n#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)\n\n// after a restart interval, stbi__jpeg_reset the entropy decoder and\n// the dc prediction\nstatic void stbi__jpeg_reset(stbi__jpeg *j)\n{\n   j->code_bits = 0;\n   j->code_buffer = 0;\n   j->nomore = 0;\n   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;\n   j->marker = STBI__MARKER_none;\n   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;\n   j->eob_run = 0;\n   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,\n   // since we don't even allow 1<<30 pixels\n}\n\nstatic int stbi__parse_entropy_coded_data(stbi__jpeg *z)\n{\n   stbi__jpeg_reset(z);\n   if (!z->progressive) {\n      if (z->scan_n == 1) {\n         int i,j;\n         STBI_SIMD_ALIGN(short, data[64]);\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               int ha = z->img_comp[n].ha;\n               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  // if it's NOT a restart, then just bail, so we get corrupt data\n                  // rather than no data\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         STBI_SIMD_ALIGN(short, data[64]);\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x)*8;\n                        int y2 = (j*z->img_comp[n].v + y)*8;\n                        int ha = z->img_comp[n].ha;\n                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   } else {\n      if (z->scan_n == 1) {\n         int i,j;\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               if (z->spec_start == 0) {\n                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                     return 0;\n               } else {\n                  int ha = z->img_comp[n].ha;\n                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))\n                     return 0;\n               }\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x);\n                        int y2 = (j*z->img_comp[n].v + y);\n                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);\n                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                           return 0;\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   }\n}\n\nstatic void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)\n{\n   int i;\n   for (i=0; i < 64; ++i)\n      data[i] *= dequant[i];\n}\n\nstatic void stbi__jpeg_finish(stbi__jpeg *z)\n{\n   if (z->progressive) {\n      // dequantize and idct the data\n      int i,j,n;\n      for (n=0; n < z->s->img_n; ++n) {\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi__process_marker(stbi__jpeg *z, int m)\n{\n   int L;\n   switch (m) {\n      case STBI__MARKER_none: // no marker found\n         return stbi__err(\"expected marker\",\"Corrupt JPEG\");\n\n      case 0xDD: // DRI - specify restart interval\n         if (stbi__get16be(z->s) != 4) return stbi__err(\"bad DRI len\",\"Corrupt JPEG\");\n         z->restart_interval = stbi__get16be(z->s);\n         return 1;\n\n      case 0xDB: // DQT - define quantization table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            int q = stbi__get8(z->s);\n            int p = q >> 4, sixteen = (p != 0);\n            int t = q & 15,i;\n            if (p != 0 && p != 1) return stbi__err(\"bad DQT type\",\"Corrupt JPEG\");\n            if (t > 3) return stbi__err(\"bad DQT table\",\"Corrupt JPEG\");\n\n            for (i=0; i < 64; ++i)\n               z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));\n            L -= (sixteen ? 129 : 65);\n         }\n         return L==0;\n\n      case 0xC4: // DHT - define huffman table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            stbi_uc *v;\n            int sizes[16],i,n=0;\n            int q = stbi__get8(z->s);\n            int tc = q >> 4;\n            int th = q & 15;\n            if (tc > 1 || th > 3) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\");\n            for (i=0; i < 16; ++i) {\n               sizes[i] = stbi__get8(z->s);\n               n += sizes[i];\n            }\n            L -= 17;\n            if (tc == 0) {\n               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;\n               v = z->huff_dc[th].values;\n            } else {\n               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;\n               v = z->huff_ac[th].values;\n            }\n            for (i=0; i < n; ++i)\n               v[i] = stbi__get8(z->s);\n            if (tc != 0)\n               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);\n            L -= n;\n         }\n         return L==0;\n   }\n\n   // check for comment block or APP blocks\n   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {\n      L = stbi__get16be(z->s);\n      if (L < 2) {\n         if (m == 0xFE)\n            return stbi__err(\"bad COM len\",\"Corrupt JPEG\");\n         else\n            return stbi__err(\"bad APP len\",\"Corrupt JPEG\");\n      }\n      L -= 2;\n\n      if (m == 0xE0 && L >= 5) { // JFIF APP0 segment\n         static const unsigned char tag[5] = {'J','F','I','F','\\0'};\n         int ok = 1;\n         int i;\n         for (i=0; i < 5; ++i)\n            if (stbi__get8(z->s) != tag[i])\n               ok = 0;\n         L -= 5;\n         if (ok)\n            z->jfif = 1;\n      } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment\n         static const unsigned char tag[6] = {'A','d','o','b','e','\\0'};\n         int ok = 1;\n         int i;\n         for (i=0; i < 6; ++i)\n            if (stbi__get8(z->s) != tag[i])\n               ok = 0;\n         L -= 6;\n         if (ok) {\n            stbi__get8(z->s); // version\n            stbi__get16be(z->s); // flags0\n            stbi__get16be(z->s); // flags1\n            z->app14_color_transform = stbi__get8(z->s); // color transform\n            L -= 6;\n         }\n      }\n\n      stbi__skip(z->s, L);\n      return 1;\n   }\n\n   return stbi__err(\"unknown marker\",\"Corrupt JPEG\");\n}\n\n// after we see SOS\nstatic int stbi__process_scan_header(stbi__jpeg *z)\n{\n   int i;\n   int Ls = stbi__get16be(z->s);\n   z->scan_n = stbi__get8(z->s);\n   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err(\"bad SOS component count\",\"Corrupt JPEG\");\n   if (Ls != 6+2*z->scan_n) return stbi__err(\"bad SOS len\",\"Corrupt JPEG\");\n   for (i=0; i < z->scan_n; ++i) {\n      int id = stbi__get8(z->s), which;\n      int q = stbi__get8(z->s);\n      for (which = 0; which < z->s->img_n; ++which)\n         if (z->img_comp[which].id == id)\n            break;\n      if (which == z->s->img_n) return 0; // no match\n      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err(\"bad DC huff\",\"Corrupt JPEG\");\n      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err(\"bad AC huff\",\"Corrupt JPEG\");\n      z->order[i] = which;\n   }\n\n   {\n      int aa;\n      z->spec_start = stbi__get8(z->s);\n      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0\n      aa = stbi__get8(z->s);\n      z->succ_high = (aa >> 4);\n      z->succ_low  = (aa & 15);\n      if (z->progressive) {\n         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)\n            return stbi__err(\"bad SOS\", \"Corrupt JPEG\");\n      } else {\n         if (z->spec_start != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         z->spec_end = 63;\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)\n{\n   int i;\n   for (i=0; i < ncomp; ++i) {\n      if (z->img_comp[i].raw_data) {\n         STBI_FREE(z->img_comp[i].raw_data);\n         z->img_comp[i].raw_data = NULL;\n         z->img_comp[i].data = NULL;\n      }\n      if (z->img_comp[i].raw_coeff) {\n         STBI_FREE(z->img_comp[i].raw_coeff);\n         z->img_comp[i].raw_coeff = 0;\n         z->img_comp[i].coeff = 0;\n      }\n      if (z->img_comp[i].linebuf) {\n         STBI_FREE(z->img_comp[i].linebuf);\n         z->img_comp[i].linebuf = NULL;\n      }\n   }\n   return why;\n}\n\nstatic int stbi__process_frame_header(stbi__jpeg *z, int scan)\n{\n   stbi__context *s = z->s;\n   int Lf,p,i,q, h_max=1,v_max=1,c;\n   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\"); // JPEG\n   p  = stbi__get8(s);            if (p != 8) return stbi__err(\"only 8-bit\",\"JPEG format not supported: 8-bit only\"); // JPEG baseline\n   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err(\"no header height\", \"JPEG format not supported: delayed height\"); // Legal, but we don't handle it--but neither does IJG\n   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err(\"0 width\",\"Corrupt JPEG\"); // JPEG requires\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   c = stbi__get8(s);\n   if (c != 3 && c != 1 && c != 4) return stbi__err(\"bad component count\",\"Corrupt JPEG\");\n   s->img_n = c;\n   for (i=0; i < c; ++i) {\n      z->img_comp[i].data = NULL;\n      z->img_comp[i].linebuf = NULL;\n   }\n\n   if (Lf != 8+3*s->img_n) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\");\n\n   z->rgb = 0;\n   for (i=0; i < s->img_n; ++i) {\n      static const unsigned char rgb[3] = { 'R', 'G', 'B' };\n      z->img_comp[i].id = stbi__get8(s);\n      if (s->img_n == 3 && z->img_comp[i].id == rgb[i])\n         ++z->rgb;\n      q = stbi__get8(s);\n      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err(\"bad TQ\",\"Corrupt JPEG\");\n   }\n\n   if (scan != STBI__SCAN_load) return 1;\n\n   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err(\"too large\", \"Image too large to decode\");\n\n   for (i=0; i < s->img_n; ++i) {\n      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;\n      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;\n   }\n\n   // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios\n   // and I've never seen a non-corrupted JPEG file actually use them\n   for (i=0; i < s->img_n; ++i) {\n      if (h_max % z->img_comp[i].h != 0) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      if (v_max % z->img_comp[i].v != 0) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n   }\n\n   // compute interleaved mcu info\n   z->img_h_max = h_max;\n   z->img_v_max = v_max;\n   z->img_mcu_w = h_max * 8;\n   z->img_mcu_h = v_max * 8;\n   // these sizes can't be more than 17 bits\n   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;\n   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;\n\n   for (i=0; i < s->img_n; ++i) {\n      // number of effective pixels (e.g. for non-interleaved MCU)\n      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n      // to simplify generation, we'll allocate enough memory to decode\n      // the bogus oversized data from using interleaved MCUs and their\n      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't\n      // discard the extra data until colorspace conversion\n      //\n      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)\n      // so these muls can't overflow with 32-bit ints (which we require)\n      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;\n      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;\n      z->img_comp[i].coeff = 0;\n      z->img_comp[i].raw_coeff = 0;\n      z->img_comp[i].linebuf = NULL;\n      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);\n      if (z->img_comp[i].raw_data == NULL)\n         return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n      // align blocks for idct using mmx/sse\n      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);\n      if (z->progressive) {\n         // w2, h2 are multiples of 8 (see above)\n         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;\n         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;\n         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);\n         if (z->img_comp[i].raw_coeff == NULL)\n            return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);\n      }\n   }\n\n   return 1;\n}\n\n// use comparisons since in some cases we handle more than one case (e.g. SOF)\n#define stbi__DNL(x)         ((x) == 0xdc)\n#define stbi__SOI(x)         ((x) == 0xd8)\n#define stbi__EOI(x)         ((x) == 0xd9)\n#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)\n#define stbi__SOS(x)         ((x) == 0xda)\n\n#define stbi__SOF_progressive(x)   ((x) == 0xc2)\n\nstatic int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)\n{\n   int m;\n   z->jfif = 0;\n   z->app14_color_transform = -1; // valid values are 0,1,2\n   z->marker = STBI__MARKER_none; // initialize cached marker to empty\n   m = stbi__get_marker(z);\n   if (!stbi__SOI(m)) return stbi__err(\"no SOI\",\"Corrupt JPEG\");\n   if (scan == STBI__SCAN_type) return 1;\n   m = stbi__get_marker(z);\n   while (!stbi__SOF(m)) {\n      if (!stbi__process_marker(z,m)) return 0;\n      m = stbi__get_marker(z);\n      while (m == STBI__MARKER_none) {\n         // some files have extra padding after their blocks, so ok, we'll scan\n         if (stbi__at_eof(z->s)) return stbi__err(\"no SOF\", \"Corrupt JPEG\");\n         m = stbi__get_marker(z);\n      }\n   }\n   z->progressive = stbi__SOF_progressive(m);\n   if (!stbi__process_frame_header(z, scan)) return 0;\n   return 1;\n}\n\n// decode image to YCbCr format\nstatic int stbi__decode_jpeg_image(stbi__jpeg *j)\n{\n   int m;\n   for (m = 0; m < 4; m++) {\n      j->img_comp[m].raw_data = NULL;\n      j->img_comp[m].raw_coeff = NULL;\n   }\n   j->restart_interval = 0;\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;\n   m = stbi__get_marker(j);\n   while (!stbi__EOI(m)) {\n      if (stbi__SOS(m)) {\n         if (!stbi__process_scan_header(j)) return 0;\n         if (!stbi__parse_entropy_coded_data(j)) return 0;\n         if (j->marker == STBI__MARKER_none ) {\n            // handle 0s at the end of image data from IP Kamera 9060\n            while (!stbi__at_eof(j->s)) {\n               int x = stbi__get8(j->s);\n               if (x == 255) {\n                  j->marker = stbi__get8(j->s);\n                  break;\n               }\n            }\n            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0\n         }\n      } else if (stbi__DNL(m)) {\n         int Ld = stbi__get16be(j->s);\n         stbi__uint32 NL = stbi__get16be(j->s);\n         if (Ld != 4) return stbi__err(\"bad DNL len\", \"Corrupt JPEG\");\n         if (NL != j->s->img_y) return stbi__err(\"bad DNL height\", \"Corrupt JPEG\");\n      } else {\n         if (!stbi__process_marker(j, m)) return 0;\n      }\n      m = stbi__get_marker(j);\n   }\n   if (j->progressive)\n      stbi__jpeg_finish(j);\n   return 1;\n}\n\n// static jfif-centered resampling (across block boundaries)\n\ntypedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,\n                                    int w, int hs);\n\n#define stbi__div4(x) ((stbi_uc) ((x) >> 2))\n\nstatic stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   STBI_NOTUSED(out);\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(w);\n   STBI_NOTUSED(hs);\n   return in_near;\n}\n\nstatic stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples vertically for every one in input\n   int i;\n   STBI_NOTUSED(hs);\n   for (i=0; i < w; ++i)\n      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);\n   return out;\n}\n\nstatic stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples horizontally for every one in input\n   int i;\n   stbi_uc *input = in_near;\n\n   if (w == 1) {\n      // if only one sample, can't do any interpolation\n      out[0] = out[1] = input[0];\n      return out;\n   }\n\n   out[0] = input[0];\n   out[1] = stbi__div4(input[0]*3 + input[1] + 2);\n   for (i=1; i < w-1; ++i) {\n      int n = 3*input[i]+2;\n      out[i*2+0] = stbi__div4(n+input[i-1]);\n      out[i*2+1] = stbi__div4(n+input[i+1]);\n   }\n   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);\n   out[i*2+1] = input[w-1];\n\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#define stbi__div16(x) ((stbi_uc) ((x) >> 4))\n\nstatic stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i,t0,t1;\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   out[0] = stbi__div4(t1+2);\n   for (i=1; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i=0,t0,t1;\n\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   // process groups of 8 pixels for as long as we can.\n   // note we can't handle the last pixel in a row in this loop\n   // because we need to handle the filter boundary conditions.\n   for (; i < ((w-1) & ~7); i += 8) {\n#if defined(STBI_SSE2)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      __m128i zero  = _mm_setzero_si128();\n      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));\n      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));\n      __m128i farw  = _mm_unpacklo_epi8(farb, zero);\n      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);\n      __m128i diff  = _mm_sub_epi16(farw, nearw);\n      __m128i nears = _mm_slli_epi16(nearw, 2);\n      __m128i curr  = _mm_add_epi16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      __m128i prv0 = _mm_slli_si128(curr, 2);\n      __m128i nxt0 = _mm_srli_si128(curr, 2);\n      __m128i prev = _mm_insert_epi16(prv0, t1, 0);\n      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      __m128i bias  = _mm_set1_epi16(8);\n      __m128i curs = _mm_slli_epi16(curr, 2);\n      __m128i prvd = _mm_sub_epi16(prev, curr);\n      __m128i nxtd = _mm_sub_epi16(next, curr);\n      __m128i curb = _mm_add_epi16(curs, bias);\n      __m128i even = _mm_add_epi16(prvd, curb);\n      __m128i odd  = _mm_add_epi16(nxtd, curb);\n\n      // interleave even and odd pixels, then undo scaling.\n      __m128i int0 = _mm_unpacklo_epi16(even, odd);\n      __m128i int1 = _mm_unpackhi_epi16(even, odd);\n      __m128i de0  = _mm_srli_epi16(int0, 4);\n      __m128i de1  = _mm_srli_epi16(int1, 4);\n\n      // pack and write output\n      __m128i outv = _mm_packus_epi16(de0, de1);\n      _mm_storeu_si128((__m128i *) (out + i*2), outv);\n#elif defined(STBI_NEON)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      uint8x8_t farb  = vld1_u8(in_far + i);\n      uint8x8_t nearb = vld1_u8(in_near + i);\n      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));\n      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));\n      int16x8_t curr  = vaddq_s16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      int16x8_t prv0 = vextq_s16(curr, curr, 7);\n      int16x8_t nxt0 = vextq_s16(curr, curr, 1);\n      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);\n      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      int16x8_t curs = vshlq_n_s16(curr, 2);\n      int16x8_t prvd = vsubq_s16(prev, curr);\n      int16x8_t nxtd = vsubq_s16(next, curr);\n      int16x8_t even = vaddq_s16(curs, prvd);\n      int16x8_t odd  = vaddq_s16(curs, nxtd);\n\n      // undo scaling and round, then store with even/odd phases interleaved\n      uint8x8x2_t o;\n      o.val[0] = vqrshrun_n_s16(even, 4);\n      o.val[1] = vqrshrun_n_s16(odd,  4);\n      vst2_u8(out + i*2, o);\n#endif\n\n      // \"previous\" value for next iter\n      t1 = 3*in_near[i+7] + in_far[i+7];\n   }\n\n   t0 = t1;\n   t1 = 3*in_near[i] + in_far[i];\n   out[i*2] = stbi__div16(3*t1 + t0 + 8);\n\n   for (++i; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n#endif\n\nstatic stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // resample with nearest-neighbor\n   int i,j;\n   STBI_NOTUSED(in_far);\n   for (i=0; i < w; ++i)\n      for (j=0; j < hs; ++j)\n         out[i*hs+j] = in_near[i];\n   return out;\n}\n\n// this is a reduced-precision calculation of YCbCr-to-RGB introduced\n// to make sure the code produces the same results in both SIMD and scalar\n#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)\nstatic void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)\n{\n   int i;\n   for (i=0; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed +  cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)\n{\n   int i = 0;\n\n#ifdef STBI_SSE2\n   // step == 3 is pretty ugly on the final interleave, and i'm not convinced\n   // it's useful in practice (you wouldn't use it for textures, for example).\n   // so just accelerate step == 4 case.\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);\n      __m128i xw = _mm_set1_epi16(255); // alpha channel\n\n      for (; i+7 < count; i += 8) {\n         // load\n         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));\n         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));\n         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));\n         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128\n         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128\n\n         // unpack to short (and left-shift cr, cb by 8)\n         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);\n         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);\n         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);\n\n         // color transform\n         __m128i yws = _mm_srli_epi16(yw, 4);\n         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);\n         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);\n         __m128i rws = _mm_add_epi16(cr0, yws);\n         __m128i gwt = _mm_add_epi16(cb0, yws);\n         __m128i bws = _mm_add_epi16(yws, cb1);\n         __m128i gws = _mm_add_epi16(gwt, cr1);\n\n         // descale\n         __m128i rw = _mm_srai_epi16(rws, 4);\n         __m128i bw = _mm_srai_epi16(bws, 4);\n         __m128i gw = _mm_srai_epi16(gws, 4);\n\n         // back to byte, set up for transpose\n         __m128i brb = _mm_packus_epi16(rw, bw);\n         __m128i gxb = _mm_packus_epi16(gw, xw);\n\n         // transpose to interleave channels\n         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);\n         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);\n         __m128i o0 = _mm_unpacklo_epi16(t0, t1);\n         __m128i o1 = _mm_unpackhi_epi16(t0, t1);\n\n         // store\n         _mm_storeu_si128((__m128i *) (out + 0), o0);\n         _mm_storeu_si128((__m128i *) (out + 16), o1);\n         out += 32;\n      }\n   }\n#endif\n\n#ifdef STBI_NEON\n   // in this version, step=3 support would be easy to add. but is there demand?\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i+7 < count; i += 8) {\n         // load\n         uint8x8_t y_bytes  = vld1_u8(y + i);\n         uint8x8_t cr_bytes = vld1_u8(pcr + i);\n         uint8x8_t cb_bytes = vld1_u8(pcb + i);\n         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));\n         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));\n\n         // expand to s16\n         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));\n         int16x8_t crw = vshll_n_s8(cr_biased, 7);\n         int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n         // color transform\n         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n         int16x8_t rws = vaddq_s16(yws, cr0);\n         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);\n         int16x8_t bws = vaddq_s16(yws, cb1);\n\n         // undo scaling, round, convert to byte\n         uint8x8x4_t o;\n         o.val[0] = vqrshrun_n_s16(rws, 4);\n         o.val[1] = vqrshrun_n_s16(gws, 4);\n         o.val[2] = vqrshrun_n_s16(bws, 4);\n         o.val[3] = vdup_n_u8(255);\n\n         // store, interleaving r/g/b/a\n         vst4_u8(out, o);\n         out += 8*4;\n      }\n   }\n#endif\n\n   for (; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed + cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#endif\n\n// set up the kernels\nstatic void stbi__setup_jpeg(stbi__jpeg *j)\n{\n   j->idct_block_kernel = stbi__idct_block;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;\n\n#ifdef STBI_SSE2\n   if (stbi__sse2_available()) {\n      j->idct_block_kernel = stbi__idct_simd;\n      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n   }\n#endif\n\n#ifdef STBI_NEON\n   j->idct_block_kernel = stbi__idct_simd;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n#endif\n}\n\n// clean up the temporary component buffers\nstatic void stbi__cleanup_jpeg(stbi__jpeg *j)\n{\n   stbi__free_jpeg_components(j, j->s->img_n, 0);\n}\n\ntypedef struct\n{\n   resample_row_func resample;\n   stbi_uc *line0,*line1;\n   int hs,vs;   // expansion factor in each axis\n   int w_lores; // horizontal pixels pre-expansion\n   int ystep;   // how far through vertical expansion we are\n   int ypos;    // which pre-expansion row we're on\n} stbi__resample;\n\n// fast 0..255 * 0..255 => 0..255 rounded multiplication\nstatic stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)\n{\n   unsigned int t = x*y + 128;\n   return (stbi_uc) ((t + (t >>8)) >> 8);\n}\n\nstatic stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)\n{\n   int n, decode_n, is_rgb;\n   z->s->img_n = 0; // make stbi__cleanup_jpeg safe\n\n   // validate req_comp\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n\n   // load a jpeg image from whichever source, but leave in YCbCr format\n   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // determine actual number of components to generate\n   n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;\n\n   is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));\n\n   if (z->s->img_n == 3 && n < 3 && !is_rgb)\n      decode_n = 1;\n   else\n      decode_n = z->s->img_n;\n\n   // nothing to do if no components requested; check this now to avoid\n   // accessing uninitialized coutput[0] later\n   if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // resample and color-convert\n   {\n      int k;\n      unsigned int i,j;\n      stbi_uc *output;\n      stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };\n\n      stbi__resample res_comp[4];\n\n      for (k=0; k < decode_n; ++k) {\n         stbi__resample *r = &res_comp[k];\n\n         // allocate line buffer big enough for upsampling off the edges\n         // with upsample factor of 4\n         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);\n         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n         r->hs      = z->img_h_max / z->img_comp[k].h;\n         r->vs      = z->img_v_max / z->img_comp[k].v;\n         r->ystep   = r->vs >> 1;\n         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;\n         r->ypos    = 0;\n         r->line0   = r->line1 = z->img_comp[k].data;\n\n         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;\n         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;\n         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;\n         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;\n         else                               r->resample = stbi__resample_row_generic;\n      }\n\n      // can't error after this so, this is safe\n      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);\n      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n      // now go ahead and resample\n      for (j=0; j < z->s->img_y; ++j) {\n         stbi_uc *out = output + n * z->s->img_x * j;\n         for (k=0; k < decode_n; ++k) {\n            stbi__resample *r = &res_comp[k];\n            int y_bot = r->ystep >= (r->vs >> 1);\n            coutput[k] = r->resample(z->img_comp[k].linebuf,\n                                     y_bot ? r->line1 : r->line0,\n                                     y_bot ? r->line0 : r->line1,\n                                     r->w_lores, r->hs);\n            if (++r->ystep >= r->vs) {\n               r->ystep = 0;\n               r->line0 = r->line1;\n               if (++r->ypos < z->img_comp[k].y)\n                  r->line1 += z->img_comp[k].w2;\n            }\n         }\n         if (n >= 3) {\n            stbi_uc *y = coutput[0];\n            if (z->s->img_n == 3) {\n               if (is_rgb) {\n                  for (i=0; i < z->s->img_x; ++i) {\n                     out[0] = y[i];\n                     out[1] = coutput[1][i];\n                     out[2] = coutput[2][i];\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else {\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else if (z->s->img_n == 4) {\n               if (z->app14_color_transform == 0) { // CMYK\n                  for (i=0; i < z->s->img_x; ++i) {\n                     stbi_uc m = coutput[3][i];\n                     out[0] = stbi__blinn_8x8(coutput[0][i], m);\n                     out[1] = stbi__blinn_8x8(coutput[1][i], m);\n                     out[2] = stbi__blinn_8x8(coutput[2][i], m);\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else if (z->app14_color_transform == 2) { // YCCK\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n                  for (i=0; i < z->s->img_x; ++i) {\n                     stbi_uc m = coutput[3][i];\n                     out[0] = stbi__blinn_8x8(255 - out[0], m);\n                     out[1] = stbi__blinn_8x8(255 - out[1], m);\n                     out[2] = stbi__blinn_8x8(255 - out[2], m);\n                     out += n;\n                  }\n               } else { // YCbCr + alpha?  Ignore the fourth channel for now\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = out[1] = out[2] = y[i];\n                  out[3] = 255; // not used if n==3\n                  out += n;\n               }\n         } else {\n            if (is_rgb) {\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i)\n                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n               else {\n                  for (i=0; i < z->s->img_x; ++i, out += 2) {\n                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n                     out[1] = 255;\n                  }\n               }\n            } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {\n               for (i=0; i < z->s->img_x; ++i) {\n                  stbi_uc m = coutput[3][i];\n                  stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);\n                  stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);\n                  stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);\n                  out[0] = stbi__compute_y(r, g, b);\n                  out[1] = 255;\n                  out += n;\n               }\n            } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);\n                  out[1] = 255;\n                  out += n;\n               }\n            } else {\n               stbi_uc *y = coutput[0];\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];\n               else\n                  for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }\n            }\n         }\n      }\n      stbi__cleanup_jpeg(z);\n      *out_x = z->s->img_x;\n      *out_y = z->s->img_y;\n      if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output\n      return output;\n   }\n}\n\nstatic void * stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   unsigned char* result;\n   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));\n   if (!j) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   STBI_NOTUSED(ri);\n   j->s = s;\n   stbi__setup_jpeg(j);\n   result = load_jpeg_image(j, x,y,comp,req_comp);\n   STBI_FREE(j);\n   return result;\n}\n\nstatic int stbi__jpeg_test(stbi__context *s)\n{\n   int r;\n   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));\n   if (!j) return stbi__err(\"outofmem\", \"Out of memory\");\n   j->s = s;\n   stbi__setup_jpeg(j);\n   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);\n   stbi__rewind(s);\n   STBI_FREE(j);\n   return r;\n}\n\nstatic int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)\n{\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {\n      stbi__rewind( j->s );\n      return 0;\n   }\n   if (x) *x = j->s->img_x;\n   if (y) *y = j->s->img_y;\n   if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;\n   return 1;\n}\n\nstatic int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int result;\n   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));\n   if (!j) return stbi__err(\"outofmem\", \"Out of memory\");\n   j->s = s;\n   result = stbi__jpeg_info_raw(j, x, y, comp);\n   STBI_FREE(j);\n   return result;\n}\n#endif\n\n// public domain zlib decode    v0.2  Sean Barrett 2006-11-18\n//    simple implementation\n//      - all input must be provided in an upfront buffer\n//      - all output is written to a single output buffer (can malloc/realloc)\n//    performance\n//      - fast huffman\n\n#ifndef STBI_NO_ZLIB\n\n// fast-way is faster to check than jpeg huffman, but slow way is slower\n#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables\n#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)\n#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet\n\n// zlib-style huffman encoding\n// (jpegs packs from left, zlib from right, so can't share code)\ntypedef struct\n{\n   stbi__uint16 fast[1 << STBI__ZFAST_BITS];\n   stbi__uint16 firstcode[16];\n   int maxcode[17];\n   stbi__uint16 firstsymbol[16];\n   stbi_uc  size[STBI__ZNSYMS];\n   stbi__uint16 value[STBI__ZNSYMS];\n} stbi__zhuffman;\n\nstbi_inline static int stbi__bitreverse16(int n)\n{\n  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);\n  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);\n  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);\n  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);\n  return n;\n}\n\nstbi_inline static int stbi__bit_reverse(int v, int bits)\n{\n   STBI_ASSERT(bits <= 16);\n   // to bit reverse n bits, reverse 16 and shift\n   // e.g. 11 bits, bit reverse and shift away 5\n   return stbi__bitreverse16(v) >> (16-bits);\n}\n\nstatic int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)\n{\n   int i,k=0;\n   int code, next_code[16], sizes[17];\n\n   // DEFLATE spec for generating codes\n   memset(sizes, 0, sizeof(sizes));\n   memset(z->fast, 0, sizeof(z->fast));\n   for (i=0; i < num; ++i)\n      ++sizes[sizelist[i]];\n   sizes[0] = 0;\n   for (i=1; i < 16; ++i)\n      if (sizes[i] > (1 << i))\n         return stbi__err(\"bad sizes\", \"Corrupt PNG\");\n   code = 0;\n   for (i=1; i < 16; ++i) {\n      next_code[i] = code;\n      z->firstcode[i] = (stbi__uint16) code;\n      z->firstsymbol[i] = (stbi__uint16) k;\n      code = (code + sizes[i]);\n      if (sizes[i])\n         if (code-1 >= (1 << i)) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n      z->maxcode[i] = code << (16-i); // preshift for inner loop\n      code <<= 1;\n      k += sizes[i];\n   }\n   z->maxcode[16] = 0x10000; // sentinel\n   for (i=0; i < num; ++i) {\n      int s = sizelist[i];\n      if (s) {\n         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];\n         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);\n         z->size [c] = (stbi_uc     ) s;\n         z->value[c] = (stbi__uint16) i;\n         if (s <= STBI__ZFAST_BITS) {\n            int j = stbi__bit_reverse(next_code[s],s);\n            while (j < (1 << STBI__ZFAST_BITS)) {\n               z->fast[j] = fastv;\n               j += (1 << s);\n            }\n         }\n         ++next_code[s];\n      }\n   }\n   return 1;\n}\n\n// zlib-from-memory implementation for PNG reading\n//    because PNG allows splitting the zlib stream arbitrarily,\n//    and it's annoying structurally to have PNG call ZLIB call PNG,\n//    we require PNG read all the IDATs and combine them into a single\n//    memory buffer\n\ntypedef struct\n{\n   stbi_uc *zbuffer, *zbuffer_end;\n   int num_bits;\n   stbi__uint32 code_buffer;\n\n   char *zout;\n   char *zout_start;\n   char *zout_end;\n   int   z_expandable;\n\n   stbi__zhuffman z_length, z_distance;\n} stbi__zbuf;\n\nstbi_inline static int stbi__zeof(stbi__zbuf *z)\n{\n   return (z->zbuffer >= z->zbuffer_end);\n}\n\nstbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)\n{\n   return stbi__zeof(z) ? 0 : *z->zbuffer++;\n}\n\nstatic void stbi__fill_bits(stbi__zbuf *z)\n{\n   do {\n      if (z->code_buffer >= (1U << z->num_bits)) {\n        z->zbuffer = z->zbuffer_end;  /* treat this as EOF so we fail. */\n        return;\n      }\n      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;\n      z->num_bits += 8;\n   } while (z->num_bits <= 24);\n}\n\nstbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)\n{\n   unsigned int k;\n   if (z->num_bits < n) stbi__fill_bits(z);\n   k = z->code_buffer & ((1 << n) - 1);\n   z->code_buffer >>= n;\n   z->num_bits -= n;\n   return k;\n}\n\nstatic int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s,k;\n   // not resolved by fast table, so compute it the slow way\n   // use jpeg approach, which requires MSbits at top\n   k = stbi__bit_reverse(a->code_buffer, 16);\n   for (s=STBI__ZFAST_BITS+1; ; ++s)\n      if (k < z->maxcode[s])\n         break;\n   if (s >= 16) return -1; // invalid code!\n   // code size is s, so:\n   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];\n   if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere!\n   if (z->size[b] != s) return -1;  // was originally an assert, but report failure instead.\n   a->code_buffer >>= s;\n   a->num_bits -= s;\n   return z->value[b];\n}\n\nstbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s;\n   if (a->num_bits < 16) {\n      if (stbi__zeof(a)) {\n         return -1;   /* report error for unexpected end of data. */\n      }\n      stbi__fill_bits(a);\n   }\n   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];\n   if (b) {\n      s = b >> 9;\n      a->code_buffer >>= s;\n      a->num_bits -= s;\n      return b & 511;\n   }\n   return stbi__zhuffman_decode_slowpath(a, z);\n}\n\nstatic int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes\n{\n   char *q;\n   unsigned int cur, limit, old_limit;\n   z->zout = zout;\n   if (!z->z_expandable) return stbi__err(\"output buffer limit\",\"Corrupt PNG\");\n   cur   = (unsigned int) (z->zout - z->zout_start);\n   limit = old_limit = (unsigned) (z->zout_end - z->zout_start);\n   if (UINT_MAX - cur < (unsigned) n) return stbi__err(\"outofmem\", \"Out of memory\");\n   while (cur + n > limit) {\n      if(limit > UINT_MAX / 2) return stbi__err(\"outofmem\", \"Out of memory\");\n      limit *= 2;\n   }\n   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);\n   STBI_NOTUSED(old_limit);\n   if (q == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n   z->zout_start = q;\n   z->zout       = q + cur;\n   z->zout_end   = q + limit;\n   return 1;\n}\n\nstatic const int stbi__zlength_base[31] = {\n   3,4,5,6,7,8,9,10,11,13,\n   15,17,19,23,27,31,35,43,51,59,\n   67,83,99,115,131,163,195,227,258,0,0 };\n\nstatic const int stbi__zlength_extra[31]=\n{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };\n\nstatic const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,\n257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};\n\nstatic const int stbi__zdist_extra[32] =\n{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nstatic int stbi__parse_huffman_block(stbi__zbuf *a)\n{\n   char *zout = a->zout;\n   for(;;) {\n      int z = stbi__zhuffman_decode(a, &a->z_length);\n      if (z < 256) {\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // error in huffman codes\n         if (zout >= a->zout_end) {\n            if (!stbi__zexpand(a, zout, 1)) return 0;\n            zout = a->zout;\n         }\n         *zout++ = (char) z;\n      } else {\n         stbi_uc *p;\n         int len,dist;\n         if (z == 256) {\n            a->zout = zout;\n            return 1;\n         }\n         z -= 257;\n         len = stbi__zlength_base[z];\n         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);\n         z = stbi__zhuffman_decode(a, &a->z_distance);\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\");\n         dist = stbi__zdist_base[z];\n         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);\n         if (zout - a->zout_start < dist) return stbi__err(\"bad dist\",\"Corrupt PNG\");\n         if (zout + len > a->zout_end) {\n            if (!stbi__zexpand(a, zout, len)) return 0;\n            zout = a->zout;\n         }\n         p = (stbi_uc *) (zout - dist);\n         if (dist == 1) { // run of one byte; common in images.\n            stbi_uc v = *p;\n            if (len) { do *zout++ = v; while (--len); }\n         } else {\n            if (len) { do *zout++ = *p++; while (--len); }\n         }\n      }\n   }\n}\n\nstatic int stbi__compute_huffman_codes(stbi__zbuf *a)\n{\n   static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };\n   stbi__zhuffman z_codelength;\n   stbi_uc lencodes[286+32+137];//padding for maximum single op\n   stbi_uc codelength_sizes[19];\n   int i,n;\n\n   int hlit  = stbi__zreceive(a,5) + 257;\n   int hdist = stbi__zreceive(a,5) + 1;\n   int hclen = stbi__zreceive(a,4) + 4;\n   int ntot  = hlit + hdist;\n\n   memset(codelength_sizes, 0, sizeof(codelength_sizes));\n   for (i=0; i < hclen; ++i) {\n      int s = stbi__zreceive(a,3);\n      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;\n   }\n   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;\n\n   n = 0;\n   while (n < ntot) {\n      int c = stbi__zhuffman_decode(a, &z_codelength);\n      if (c < 0 || c >= 19) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n      if (c < 16)\n         lencodes[n++] = (stbi_uc) c;\n      else {\n         stbi_uc fill = 0;\n         if (c == 16) {\n            c = stbi__zreceive(a,2)+3;\n            if (n == 0) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n            fill = lencodes[n-1];\n         } else if (c == 17) {\n            c = stbi__zreceive(a,3)+3;\n         } else if (c == 18) {\n            c = stbi__zreceive(a,7)+11;\n         } else {\n            return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         }\n         if (ntot - n < c) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         memset(lencodes+n, fill, c);\n         n += c;\n      }\n   }\n   if (n != ntot) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;\n   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;\n   return 1;\n}\n\nstatic int stbi__parse_uncompressed_block(stbi__zbuf *a)\n{\n   stbi_uc header[4];\n   int len,nlen,k;\n   if (a->num_bits & 7)\n      stbi__zreceive(a, a->num_bits & 7); // discard\n   // drain the bit-packed data into header\n   k = 0;\n   while (a->num_bits > 0) {\n      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check\n      a->code_buffer >>= 8;\n      a->num_bits -= 8;\n   }\n   if (a->num_bits < 0) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   // now fill header the normal way\n   while (k < 4)\n      header[k++] = stbi__zget8(a);\n   len  = header[1] * 256 + header[0];\n   nlen = header[3] * 256 + header[2];\n   if (nlen != (len ^ 0xffff)) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   if (a->zbuffer + len > a->zbuffer_end) return stbi__err(\"read past buffer\",\"Corrupt PNG\");\n   if (a->zout + len > a->zout_end)\n      if (!stbi__zexpand(a, a->zout, len)) return 0;\n   memcpy(a->zout, a->zbuffer, len);\n   a->zbuffer += len;\n   a->zout += len;\n   return 1;\n}\n\nstatic int stbi__parse_zlib_header(stbi__zbuf *a)\n{\n   int cmf   = stbi__zget8(a);\n   int cm    = cmf & 15;\n   /* int cinfo = cmf >> 4; */\n   int flg   = stbi__zget8(a);\n   if (stbi__zeof(a)) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if ((cmf*256+flg) % 31 != 0) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if (flg & 32) return stbi__err(\"no preset dict\",\"Corrupt PNG\"); // preset dictionary not allowed in png\n   if (cm != 8) return stbi__err(\"bad compression\",\"Corrupt PNG\"); // DEFLATE required for png\n   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output\n   return 1;\n}\n\nstatic const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =\n{\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8\n};\nstatic const stbi_uc stbi__zdefault_distance[32] =\n{\n   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5\n};\n/*\nInit algorithm:\n{\n   int i;   // use <= to match clearly with spec\n   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;\n   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;\n   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;\n   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;\n\n   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;\n}\n*/\n\nstatic int stbi__parse_zlib(stbi__zbuf *a, int parse_header)\n{\n   int final, type;\n   if (parse_header)\n      if (!stbi__parse_zlib_header(a)) return 0;\n   a->num_bits = 0;\n   a->code_buffer = 0;\n   do {\n      final = stbi__zreceive(a,1);\n      type = stbi__zreceive(a,2);\n      if (type == 0) {\n         if (!stbi__parse_uncompressed_block(a)) return 0;\n      } else if (type == 3) {\n         return 0;\n      } else {\n         if (type == 1) {\n            // use fixed code lengths\n            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , STBI__ZNSYMS)) return 0;\n            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;\n         } else {\n            if (!stbi__compute_huffman_codes(a)) return 0;\n         }\n         if (!stbi__parse_huffman_block(a)) return 0;\n      }\n   } while (!final);\n   return 1;\n}\n\nstatic int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)\n{\n   a->zout_start = obuf;\n   a->zout       = obuf;\n   a->zout_end   = obuf + olen;\n   a->z_expandable = exp;\n\n   return stbi__parse_zlib(a, parse_header);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)\n{\n   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(16384);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer+len;\n   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n#endif\n\n// public domain \"baseline\" PNG decoder   v0.10  Sean Barrett 2006-11-18\n//    simple implementation\n//      - only 8-bit samples\n//      - no CRC checking\n//      - allocates lots of intermediate memory\n//        - avoids problem of streaming data between subsystems\n//        - avoids explicit window management\n//    performance\n//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding\n\n#ifndef STBI_NO_PNG\ntypedef struct\n{\n   stbi__uint32 length;\n   stbi__uint32 type;\n} stbi__pngchunk;\n\nstatic stbi__pngchunk stbi__get_chunk_header(stbi__context *s)\n{\n   stbi__pngchunk c;\n   c.length = stbi__get32be(s);\n   c.type   = stbi__get32be(s);\n   return c;\n}\n\nstatic int stbi__check_png_header(stbi__context *s)\n{\n   static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };\n   int i;\n   for (i=0; i < 8; ++i)\n      if (stbi__get8(s) != png_sig[i]) return stbi__err(\"bad png sig\",\"Not a PNG\");\n   return 1;\n}\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi_uc *idata, *expanded, *out;\n   int depth;\n} stbi__png;\n\n\nenum {\n   STBI__F_none=0,\n   STBI__F_sub=1,\n   STBI__F_up=2,\n   STBI__F_avg=3,\n   STBI__F_paeth=4,\n   // synthetic filters used for first scanline to avoid needing a dummy row of 0s\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic stbi_uc first_row_filter[5] =\n{\n   STBI__F_none,\n   STBI__F_sub,\n   STBI__F_none,\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic int stbi__paeth(int a, int b, int c)\n{\n   int p = a + b - c;\n   int pa = abs(p-a);\n   int pb = abs(p-b);\n   int pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return a;\n   if (pb <= pc) return b;\n   return c;\n}\n\nstatic const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };\n\n// create the png data from post-deflated data\nstatic int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)\n{\n   int bytes = (depth == 16? 2 : 1);\n   stbi__context *s = a->s;\n   stbi__uint32 i,j,stride = x*out_n*bytes;\n   stbi__uint32 img_len, img_width_bytes;\n   int k;\n   int img_n = s->img_n; // copy it into a local for later\n\n   int output_bytes = out_n*bytes;\n   int filter_bytes = img_n*bytes;\n   int width = x;\n\n   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);\n   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into\n   if (!a->out) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err(\"too large\", \"Corrupt PNG\");\n   img_width_bytes = (((img_n * x * depth) + 7) >> 3);\n   img_len = (img_width_bytes + 1) * y;\n\n   // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,\n   // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),\n   // so just check for raw_len < img_len always.\n   if (raw_len < img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n\n   for (j=0; j < y; ++j) {\n      stbi_uc *cur = a->out + stride*j;\n      stbi_uc *prior;\n      int filter = *raw++;\n\n      if (filter > 4)\n         return stbi__err(\"invalid filter\",\"Corrupt PNG\");\n\n      if (depth < 8) {\n         if (img_width_bytes > x) return stbi__err(\"invalid width\",\"Corrupt PNG\");\n         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place\n         filter_bytes = 1;\n         width = img_width_bytes;\n      }\n      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above\n\n      // if first row, use special filter that doesn't sample previous row\n      if (j == 0) filter = first_row_filter[filter];\n\n      // handle first byte explicitly\n      for (k=0; k < filter_bytes; ++k) {\n         switch (filter) {\n            case STBI__F_none       : cur[k] = raw[k]; break;\n            case STBI__F_sub        : cur[k] = raw[k]; break;\n            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;\n            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;\n            case STBI__F_avg_first  : cur[k] = raw[k]; break;\n            case STBI__F_paeth_first: cur[k] = raw[k]; break;\n         }\n      }\n\n      if (depth == 8) {\n         if (img_n != out_n)\n            cur[img_n] = 255; // first pixel\n         raw += img_n;\n         cur += out_n;\n         prior += out_n;\n      } else if (depth == 16) {\n         if (img_n != out_n) {\n            cur[filter_bytes]   = 255; // first pixel top byte\n            cur[filter_bytes+1] = 255; // first pixel bottom byte\n         }\n         raw += filter_bytes;\n         cur += output_bytes;\n         prior += output_bytes;\n      } else {\n         raw += 1;\n         cur += 1;\n         prior += 1;\n      }\n\n      // this is a little gross, so that we don't switch per-pixel or per-component\n      if (depth < 8 || img_n == out_n) {\n         int nk = (width - 1)*filter_bytes;\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (k=0; k < nk; ++k)\n         switch (filter) {\n            // \"none\" filter turns into a memcpy here; make that explicit.\n            case STBI__F_none:         memcpy(cur, raw, nk); break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n         raw += nk;\n      } else {\n         STBI_ASSERT(img_n+1 == out_n);\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \\\n                   for (k=0; k < filter_bytes; ++k)\n         switch (filter) {\n            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n\n         // the loop above sets the high byte of the pixels' alpha, but for\n         // 16 bit png files we also need the low byte set. we'll do that here.\n         if (depth == 16) {\n            cur = a->out + stride*j; // start at the beginning of the row again\n            for (i=0; i < x; ++i,cur+=output_bytes) {\n               cur[filter_bytes+1] = 255;\n            }\n         }\n      }\n   }\n\n   // we make a separate pass to expand bits to pixels; for performance,\n   // this could run two scanlines behind the above code, so it won't\n   // intefere with filtering but will still be in the cache.\n   if (depth < 8) {\n      for (j=0; j < y; ++j) {\n         stbi_uc *cur = a->out + stride*j;\n         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;\n         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit\n         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop\n         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range\n\n         // note that the final byte might overshoot and write more data than desired.\n         // we can allocate enough data that this never writes out of memory, but it\n         // could also overwrite the next scanline. can it overwrite non-empty data\n         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.\n         // so we need to explicitly clamp the final ones\n\n         if (depth == 4) {\n            for (k=x*img_n; k >= 2; k-=2, ++in) {\n               *cur++ = scale * ((*in >> 4)       );\n               *cur++ = scale * ((*in     ) & 0x0f);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 4)       );\n         } else if (depth == 2) {\n            for (k=x*img_n; k >= 4; k-=4, ++in) {\n               *cur++ = scale * ((*in >> 6)       );\n               *cur++ = scale * ((*in >> 4) & 0x03);\n               *cur++ = scale * ((*in >> 2) & 0x03);\n               *cur++ = scale * ((*in     ) & 0x03);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 6)       );\n            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);\n            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);\n         } else if (depth == 1) {\n            for (k=x*img_n; k >= 8; k-=8, ++in) {\n               *cur++ = scale * ((*in >> 7)       );\n               *cur++ = scale * ((*in >> 6) & 0x01);\n               *cur++ = scale * ((*in >> 5) & 0x01);\n               *cur++ = scale * ((*in >> 4) & 0x01);\n               *cur++ = scale * ((*in >> 3) & 0x01);\n               *cur++ = scale * ((*in >> 2) & 0x01);\n               *cur++ = scale * ((*in >> 1) & 0x01);\n               *cur++ = scale * ((*in     ) & 0x01);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 7)       );\n            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);\n            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);\n            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);\n            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);\n            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);\n            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);\n         }\n         if (img_n != out_n) {\n            int q;\n            // insert alpha = 255\n            cur = a->out + stride*j;\n            if (img_n == 1) {\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*2+1] = 255;\n                  cur[q*2+0] = cur[q];\n               }\n            } else {\n               STBI_ASSERT(img_n == 3);\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*4+3] = 255;\n                  cur[q*4+2] = cur[q*3+2];\n                  cur[q*4+1] = cur[q*3+1];\n                  cur[q*4+0] = cur[q*3+0];\n               }\n            }\n         }\n      }\n   } else if (depth == 16) {\n      // force the image data from big-endian to platform-native.\n      // this is done in a separate pass due to the decoding relying\n      // on the data being untouched, but could probably be done\n      // per-line during decode if care is taken.\n      stbi_uc *cur = a->out;\n      stbi__uint16 *cur16 = (stbi__uint16*)cur;\n\n      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {\n         *cur16 = (cur[0] << 8) | cur[1];\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)\n{\n   int bytes = (depth == 16 ? 2 : 1);\n   int out_bytes = out_n * bytes;\n   stbi_uc *final;\n   int p;\n   if (!interlaced)\n      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);\n\n   // de-interlacing\n   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);\n   if (!final) return stbi__err(\"outofmem\", \"Out of memory\");\n   for (p=0; p < 7; ++p) {\n      int xorig[] = { 0,4,0,2,0,1,0 };\n      int yorig[] = { 0,0,4,0,2,0,1 };\n      int xspc[]  = { 8,8,4,4,2,2,1 };\n      int yspc[]  = { 8,8,8,4,4,2,2 };\n      int i,j,x,y;\n      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1\n      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];\n      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];\n      if (x && y) {\n         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;\n         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {\n            STBI_FREE(final);\n            return 0;\n         }\n         for (j=0; j < y; ++j) {\n            for (i=0; i < x; ++i) {\n               int out_y = j*yspc[p]+yorig[p];\n               int out_x = i*xspc[p]+xorig[p];\n               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,\n                      a->out + (j*x+i)*out_bytes, out_bytes);\n            }\n         }\n         STBI_FREE(a->out);\n         image_data += img_len;\n         image_data_len -= img_len;\n      }\n   }\n   a->out = final;\n\n   return 1;\n}\n\nstatic int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 255 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i=0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 255);\n         p += 2;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi__uint16 *p = (stbi__uint16*) z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 65535 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i = 0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 65535);\n         p += 2;\n      }\n   } else {\n      for (i = 0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)\n{\n   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;\n   stbi_uc *p, *temp_out, *orig = a->out;\n\n   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);\n   if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   // between here and free(out) below, exitting would leak\n   temp_out = p;\n\n   if (pal_img_n == 3) {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p += 3;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p[3] = palette[n+3];\n         p += 4;\n      }\n   }\n   STBI_FREE(a->out);\n   a->out = temp_out;\n\n   STBI_NOTUSED(len);\n\n   return 1;\n}\n\nstatic int stbi__unpremultiply_on_load_global = 0;\nstatic int stbi__de_iphone_flag_global = 0;\n\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag_global = flag_true_if_should_convert;\n}\n\n#ifndef STBI_THREAD_LOCAL\n#define stbi__unpremultiply_on_load  stbi__unpremultiply_on_load_global\n#define stbi__de_iphone_flag  stbi__de_iphone_flag_global\n#else\nstatic STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;\nstatic STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;\n\nSTBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;\n   stbi__unpremultiply_on_load_set = 1;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag_local = flag_true_if_should_convert;\n   stbi__de_iphone_flag_set = 1;\n}\n\n#define stbi__unpremultiply_on_load  (stbi__unpremultiply_on_load_set           \\\n                                       ? stbi__unpremultiply_on_load_local      \\\n                                       : stbi__unpremultiply_on_load_global)\n#define stbi__de_iphone_flag  (stbi__de_iphone_flag_set                         \\\n                                ? stbi__de_iphone_flag_local                    \\\n                                : stbi__de_iphone_flag_global)\n#endif // STBI_THREAD_LOCAL\n\nstatic void stbi__de_iphone(stbi__png *z)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   if (s->img_out_n == 3) {  // convert bgr to rgb\n      for (i=0; i < pixel_count; ++i) {\n         stbi_uc t = p[0];\n         p[0] = p[2];\n         p[2] = t;\n         p += 3;\n      }\n   } else {\n      STBI_ASSERT(s->img_out_n == 4);\n      if (stbi__unpremultiply_on_load) {\n         // convert bgr to rgb and unpremultiply\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc a = p[3];\n            stbi_uc t = p[0];\n            if (a) {\n               stbi_uc half = a / 2;\n               p[0] = (p[2] * 255 + half) / a;\n               p[1] = (p[1] * 255 + half) / a;\n               p[2] = ( t   * 255 + half) / a;\n            } else {\n               p[0] = p[2];\n               p[2] = t;\n            }\n            p += 4;\n         }\n      } else {\n         // convert bgr to rgb\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc t = p[0];\n            p[0] = p[2];\n            p[2] = t;\n            p += 4;\n         }\n      }\n   }\n}\n\n#define STBI__PNG_TYPE(a,b,c,d)  (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))\n\nstatic int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)\n{\n   stbi_uc palette[1024], pal_img_n=0;\n   stbi_uc has_trans=0, tc[3]={0};\n   stbi__uint16 tc16[3];\n   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;\n   int first=1,k,interlace=0, color=0, is_iphone=0;\n   stbi__context *s = z->s;\n\n   z->expanded = NULL;\n   z->idata = NULL;\n   z->out = NULL;\n\n   if (!stbi__check_png_header(s)) return 0;\n\n   if (scan == STBI__SCAN_type) return 1;\n\n   for (;;) {\n      stbi__pngchunk c = stbi__get_chunk_header(s);\n      switch (c.type) {\n         case STBI__PNG_TYPE('C','g','B','I'):\n            is_iphone = 1;\n            stbi__skip(s, c.length);\n            break;\n         case STBI__PNG_TYPE('I','H','D','R'): {\n            int comp,filter;\n            if (!first) return stbi__err(\"multiple IHDR\",\"Corrupt PNG\");\n            first = 0;\n            if (c.length != 13) return stbi__err(\"bad IHDR len\",\"Corrupt PNG\");\n            s->img_x = stbi__get32be(s);\n            s->img_y = stbi__get32be(s);\n            if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err(\"1/2/4/8/16-bit only\",\"PNG not supported: 1/2/4/8/16-bit only\");\n            color = stbi__get8(s);  if (color > 6)         return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3 && z->depth == 16)                  return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            comp  = stbi__get8(s);  if (comp) return stbi__err(\"bad comp method\",\"Corrupt PNG\");\n            filter= stbi__get8(s);  if (filter) return stbi__err(\"bad filter method\",\"Corrupt PNG\");\n            interlace = stbi__get8(s); if (interlace>1) return stbi__err(\"bad interlace method\",\"Corrupt PNG\");\n            if (!s->img_x || !s->img_y) return stbi__err(\"0-pixel image\",\"Corrupt PNG\");\n            if (!pal_img_n) {\n               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);\n               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err(\"too large\", \"Image too large to decode\");\n               if (scan == STBI__SCAN_header) return 1;\n            } else {\n               // if paletted, then pal_n is our final components, and\n               // img_n is # components to decompress/filter.\n               s->img_n = 1;\n               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err(\"too large\",\"Corrupt PNG\");\n               // if SCAN_header, have to scan to see if we have a tRNS\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('P','L','T','E'):  {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (c.length > 256*3) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            pal_len = c.length / 3;\n            if (pal_len * 3 != c.length) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            for (i=0; i < pal_len; ++i) {\n               palette[i*4+0] = stbi__get8(s);\n               palette[i*4+1] = stbi__get8(s);\n               palette[i*4+2] = stbi__get8(s);\n               palette[i*4+3] = 255;\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('t','R','N','S'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (z->idata) return stbi__err(\"tRNS after IDAT\",\"Corrupt PNG\");\n            if (pal_img_n) {\n               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }\n               if (pal_len == 0) return stbi__err(\"tRNS before PLTE\",\"Corrupt PNG\");\n               if (c.length > pal_len) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               pal_img_n = 4;\n               for (i=0; i < c.length; ++i)\n                  palette[i*4+3] = stbi__get8(s);\n            } else {\n               if (!(s->img_n & 1)) return stbi__err(\"tRNS with alpha\",\"Corrupt PNG\");\n               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               has_trans = 1;\n               if (z->depth == 16) {\n                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is\n               } else {\n                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger\n               }\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','D','A','T'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (pal_img_n && !pal_len) return stbi__err(\"no PLTE\",\"Corrupt PNG\");\n            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }\n            if ((int)(ioff + c.length) < (int)ioff) return 0;\n            if (ioff + c.length > idata_limit) {\n               stbi__uint32 idata_limit_old = idata_limit;\n               stbi_uc *p;\n               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;\n               while (ioff + c.length > idata_limit)\n                  idata_limit *= 2;\n               STBI_NOTUSED(idata_limit_old);\n               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n               z->idata = p;\n            }\n            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err(\"outofdata\",\"Corrupt PNG\");\n            ioff += c.length;\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','E','N','D'): {\n            stbi__uint32 raw_len, bpl;\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (scan != STBI__SCAN_load) return 1;\n            if (z->idata == NULL) return stbi__err(\"no IDAT\",\"Corrupt PNG\");\n            // initial guess for decoded data size to avoid unnecessary reallocs\n            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component\n            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;\n            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);\n            if (z->expanded == NULL) return 0; // zlib should set error\n            STBI_FREE(z->idata); z->idata = NULL;\n            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)\n               s->img_out_n = s->img_n+1;\n            else\n               s->img_out_n = s->img_n;\n            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;\n            if (has_trans) {\n               if (z->depth == 16) {\n                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;\n               } else {\n                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;\n               }\n            }\n            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)\n               stbi__de_iphone(z);\n            if (pal_img_n) {\n               // pal_img_n == 3 or 4\n               s->img_n = pal_img_n; // record the actual colors we had\n               s->img_out_n = pal_img_n;\n               if (req_comp >= 3) s->img_out_n = req_comp;\n               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))\n                  return 0;\n            } else if (has_trans) {\n               // non-paletted image with tRNS -> source image has (constant) alpha\n               ++s->img_n;\n            }\n            STBI_FREE(z->expanded); z->expanded = NULL;\n            // end of PNG chunk, read and skip CRC\n            stbi__get32be(s);\n            return 1;\n         }\n\n         default:\n            // if critical, fail\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if ((c.type & (1 << 29)) == 0) {\n               #ifndef STBI_NO_FAILURE_STRINGS\n               // not threadsafe\n               static char invalid_chunk[] = \"XXXX PNG chunk not known\";\n               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);\n               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);\n               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);\n               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);\n               #endif\n               return stbi__err(invalid_chunk, \"PNG not supported: unknown PNG chunk type\");\n            }\n            stbi__skip(s, c.length);\n            break;\n      }\n      // end of PNG chunk, read and skip CRC\n      stbi__get32be(s);\n   }\n}\n\nstatic void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)\n{\n   void *result=NULL;\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {\n      if (p->depth <= 8)\n         ri->bits_per_channel = 8;\n      else if (p->depth == 16)\n         ri->bits_per_channel = 16;\n      else\n         return stbi__errpuc(\"bad bits_per_channel\", \"PNG not supported: unsupported color depth\");\n      result = p->out;\n      p->out = NULL;\n      if (req_comp && req_comp != p->s->img_out_n) {\n         if (ri->bits_per_channel == 8)\n            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         else\n            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         p->s->img_out_n = req_comp;\n         if (result == NULL) return result;\n      }\n      *x = p->s->img_x;\n      *y = p->s->img_y;\n      if (n) *n = p->s->img_n;\n   }\n   STBI_FREE(p->out);      p->out      = NULL;\n   STBI_FREE(p->expanded); p->expanded = NULL;\n   STBI_FREE(p->idata);    p->idata    = NULL;\n\n   return result;\n}\n\nstatic void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__do_png(&p, x,y,comp,req_comp, ri);\n}\n\nstatic int stbi__png_test(stbi__context *s)\n{\n   int r;\n   r = stbi__check_png_header(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)\n{\n   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {\n      stbi__rewind( p->s );\n      return 0;\n   }\n   if (x) *x = p->s->img_x;\n   if (y) *y = p->s->img_y;\n   if (comp) *comp = p->s->img_n;\n   return 1;\n}\n\nstatic int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__png_info_raw(&p, x, y, comp);\n}\n\nstatic int stbi__png_is16(stbi__context *s)\n{\n   stbi__png p;\n   p.s = s;\n   if (!stbi__png_info_raw(&p, NULL, NULL, NULL))\n\t   return 0;\n   if (p.depth != 16) {\n      stbi__rewind(p.s);\n      return 0;\n   }\n   return 1;\n}\n#endif\n\n// Microsoft/Windows BMP image\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_test_raw(stbi__context *s)\n{\n   int r;\n   int sz;\n   if (stbi__get8(s) != 'B') return 0;\n   if (stbi__get8(s) != 'M') return 0;\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   stbi__get32le(s); // discard data offset\n   sz = stbi__get32le(s);\n   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);\n   return r;\n}\n\nstatic int stbi__bmp_test(stbi__context *s)\n{\n   int r = stbi__bmp_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\n\n// returns 0..31 for the highest set bit\nstatic int stbi__high_bit(unsigned int z)\n{\n   int n=0;\n   if (z == 0) return -1;\n   if (z >= 0x10000) { n += 16; z >>= 16; }\n   if (z >= 0x00100) { n +=  8; z >>=  8; }\n   if (z >= 0x00010) { n +=  4; z >>=  4; }\n   if (z >= 0x00004) { n +=  2; z >>=  2; }\n   if (z >= 0x00002) { n +=  1;/* >>=  1;*/ }\n   return n;\n}\n\nstatic int stbi__bitcount(unsigned int a)\n{\n   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2\n   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4\n   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits\n   a = (a + (a >> 8)); // max 16 per 8 bits\n   a = (a + (a >> 16)); // max 32 per 8 bits\n   return a & 0xff;\n}\n\n// extract an arbitrarily-aligned N-bit value (N=bits)\n// from v, and then make it 8-bits long and fractionally\n// extend it to full full range.\nstatic int stbi__shiftsigned(unsigned int v, int shift, int bits)\n{\n   static unsigned int mul_table[9] = {\n      0,\n      0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,\n      0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,\n   };\n   static unsigned int shift_table[9] = {\n      0, 0,0,1,0,2,4,6,0,\n   };\n   if (shift < 0)\n      v <<= -shift;\n   else\n      v >>= shift;\n   STBI_ASSERT(v < 256);\n   v >>= (8-bits);\n   STBI_ASSERT(bits >= 0 && bits <= 8);\n   return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];\n}\n\ntypedef struct\n{\n   int bpp, offset, hsz;\n   unsigned int mr,mg,mb,ma, all_a;\n   int extra_read;\n} stbi__bmp_data;\n\nstatic int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)\n{\n   // BI_BITFIELDS specifies masks explicitly, don't override\n   if (compress == 3)\n      return 1;\n\n   if (compress == 0) {\n      if (info->bpp == 16) {\n         info->mr = 31u << 10;\n         info->mg = 31u <<  5;\n         info->mb = 31u <<  0;\n      } else if (info->bpp == 32) {\n         info->mr = 0xffu << 16;\n         info->mg = 0xffu <<  8;\n         info->mb = 0xffu <<  0;\n         info->ma = 0xffu << 24;\n         info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0\n      } else {\n         // otherwise, use defaults, which is all-0\n         info->mr = info->mg = info->mb = info->ma = 0;\n      }\n      return 1;\n   }\n   return 0; // error\n}\n\nstatic void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)\n{\n   int hsz;\n   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc(\"not BMP\", \"Corrupt BMP\");\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   info->offset = stbi__get32le(s);\n   info->hsz = hsz = stbi__get32le(s);\n   info->mr = info->mg = info->mb = info->ma = 0;\n   info->extra_read = 14;\n\n   if (info->offset < 0) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n\n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc(\"unknown BMP\", \"BMP type not supported: unknown\");\n   if (hsz == 12) {\n      s->img_x = stbi__get16le(s);\n      s->img_y = stbi__get16le(s);\n   } else {\n      s->img_x = stbi__get32le(s);\n      s->img_y = stbi__get32le(s);\n   }\n   if (stbi__get16le(s) != 1) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n   info->bpp = stbi__get16le(s);\n   if (hsz != 12) {\n      int compress = stbi__get32le(s);\n      if (compress == 1 || compress == 2) return stbi__errpuc(\"BMP RLE\", \"BMP type not supported: RLE\");\n      if (compress >= 4) return stbi__errpuc(\"BMP JPEG/PNG\", \"BMP type not supported: unsupported compression\"); // this includes PNG/JPEG modes\n      if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc(\"bad BMP\", \"bad BMP\"); // bitfields requires 16 or 32 bits/pixel\n      stbi__get32le(s); // discard sizeof\n      stbi__get32le(s); // discard hres\n      stbi__get32le(s); // discard vres\n      stbi__get32le(s); // discard colorsused\n      stbi__get32le(s); // discard max important\n      if (hsz == 40 || hsz == 56) {\n         if (hsz == 56) {\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n         }\n         if (info->bpp == 16 || info->bpp == 32) {\n            if (compress == 0) {\n               stbi__bmp_set_mask_defaults(info, compress);\n            } else if (compress == 3) {\n               info->mr = stbi__get32le(s);\n               info->mg = stbi__get32le(s);\n               info->mb = stbi__get32le(s);\n               info->extra_read += 12;\n               // not documented, but generated by photoshop and handled by mspaint\n               if (info->mr == info->mg && info->mg == info->mb) {\n                  // ?!?!?\n                  return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n               }\n            } else\n               return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         }\n      } else {\n         // V4/V5 header\n         int i;\n         if (hsz != 108 && hsz != 124)\n            return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         info->mr = stbi__get32le(s);\n         info->mg = stbi__get32le(s);\n         info->mb = stbi__get32le(s);\n         info->ma = stbi__get32le(s);\n         if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs\n            stbi__bmp_set_mask_defaults(info, compress);\n         stbi__get32le(s); // discard color space\n         for (i=0; i < 12; ++i)\n            stbi__get32le(s); // discard color space parameters\n         if (hsz == 124) {\n            stbi__get32le(s); // discard rendering intent\n            stbi__get32le(s); // discard offset of profile data\n            stbi__get32le(s); // discard size of profile data\n            stbi__get32le(s); // discard reserved\n         }\n      }\n   }\n   return (void *) 1;\n}\n\n\nstatic void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;\n   stbi_uc pal[256][4];\n   int psize=0,i,j,width;\n   int flip_vertically, pad, target;\n   stbi__bmp_data info;\n   STBI_NOTUSED(ri);\n\n   info.all_a = 255;\n   if (stbi__bmp_parse_header(s, &info) == NULL)\n      return NULL; // error code already set\n\n   flip_vertically = ((int) s->img_y) > 0;\n   s->img_y = abs((int) s->img_y);\n\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   mr = info.mr;\n   mg = info.mg;\n   mb = info.mb;\n   ma = info.ma;\n   all_a = info.all_a;\n\n   if (info.hsz == 12) {\n      if (info.bpp < 24)\n         psize = (info.offset - info.extra_read - 24) / 3;\n   } else {\n      if (info.bpp < 16)\n         psize = (info.offset - info.extra_read - info.hsz) >> 2;\n   }\n   if (psize == 0) {\n      if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) {\n        return stbi__errpuc(\"bad offset\", \"Corrupt BMP\");\n      }\n   }\n\n   if (info.bpp == 24 && ma == 0xff000000)\n      s->img_n = 3;\n   else\n      s->img_n = ma ? 4 : 3;\n   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4\n      target = req_comp;\n   else\n      target = s->img_n; // if they want monochrome, we'll post-convert\n\n   // sanity-check size\n   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt BMP\");\n\n   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (info.bpp < 16) {\n      int z=0;\n      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc(\"invalid\", \"Corrupt BMP\"); }\n      for (i=0; i < psize; ++i) {\n         pal[i][2] = stbi__get8(s);\n         pal[i][1] = stbi__get8(s);\n         pal[i][0] = stbi__get8(s);\n         if (info.hsz != 12) stbi__get8(s);\n         pal[i][3] = 255;\n      }\n      stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));\n      if (info.bpp == 1) width = (s->img_x + 7) >> 3;\n      else if (info.bpp == 4) width = (s->img_x + 1) >> 1;\n      else if (info.bpp == 8) width = s->img_x;\n      else { STBI_FREE(out); return stbi__errpuc(\"bad bpp\", \"Corrupt BMP\"); }\n      pad = (-width)&3;\n      if (info.bpp == 1) {\n         for (j=0; j < (int) s->img_y; ++j) {\n            int bit_offset = 7, v = stbi__get8(s);\n            for (i=0; i < (int) s->img_x; ++i) {\n               int color = (v>>bit_offset)&0x1;\n               out[z++] = pal[color][0];\n               out[z++] = pal[color][1];\n               out[z++] = pal[color][2];\n               if (target == 4) out[z++] = 255;\n               if (i+1 == (int) s->img_x) break;\n               if((--bit_offset) < 0) {\n                  bit_offset = 7;\n                  v = stbi__get8(s);\n               }\n            }\n            stbi__skip(s, pad);\n         }\n      } else {\n         for (j=0; j < (int) s->img_y; ++j) {\n            for (i=0; i < (int) s->img_x; i += 2) {\n               int v=stbi__get8(s),v2=0;\n               if (info.bpp == 4) {\n                  v2 = v & 15;\n                  v >>= 4;\n               }\n               out[z++] = pal[v][0];\n               out[z++] = pal[v][1];\n               out[z++] = pal[v][2];\n               if (target == 4) out[z++] = 255;\n               if (i+1 == (int) s->img_x) break;\n               v = (info.bpp == 8) ? stbi__get8(s) : v2;\n               out[z++] = pal[v][0];\n               out[z++] = pal[v][1];\n               out[z++] = pal[v][2];\n               if (target == 4) out[z++] = 255;\n            }\n            stbi__skip(s, pad);\n         }\n      }\n   } else {\n      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;\n      int z = 0;\n      int easy=0;\n      stbi__skip(s, info.offset - info.extra_read - info.hsz);\n      if (info.bpp == 24) width = 3 * s->img_x;\n      else if (info.bpp == 16) width = 2*s->img_x;\n      else /* bpp = 32 and pad = 0 */ width=0;\n      pad = (-width) & 3;\n      if (info.bpp == 24) {\n         easy = 1;\n      } else if (info.bpp == 32) {\n         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)\n            easy = 2;\n      }\n      if (!easy) {\n         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n         // right shift amt to put high bit in position #7\n         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);\n         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);\n         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);\n         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);\n         if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n      }\n      for (j=0; j < (int) s->img_y; ++j) {\n         if (easy) {\n            for (i=0; i < (int) s->img_x; ++i) {\n               unsigned char a;\n               out[z+2] = stbi__get8(s);\n               out[z+1] = stbi__get8(s);\n               out[z+0] = stbi__get8(s);\n               z += 3;\n               a = (easy == 2 ? stbi__get8(s) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = a;\n            }\n         } else {\n            int bpp = info.bpp;\n            for (i=0; i < (int) s->img_x; ++i) {\n               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));\n               unsigned int a;\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));\n               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = STBI__BYTECAST(a);\n            }\n         }\n         stbi__skip(s, pad);\n      }\n   }\n\n   // if alpha channel is all 0s, replace with all 255s\n   if (target == 4 && all_a == 0)\n      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)\n         out[i] = 255;\n\n   if (flip_vertically) {\n      stbi_uc t;\n      for (j=0; j < (int) s->img_y>>1; ++j) {\n         stbi_uc *p1 = out +      j     *s->img_x*target;\n         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;\n         for (i=0; i < (int) s->img_x*target; ++i) {\n            t = p1[i]; p1[i] = p2[i]; p2[i] = t;\n         }\n      }\n   }\n\n   if (req_comp && req_comp != target) {\n      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n   return out;\n}\n#endif\n\n// Targa Truevision - TGA\n// by Jonathan Dummer\n#ifndef STBI_NO_TGA\n// returns STBI_rgb or whatever, 0 on error\nstatic int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)\n{\n   // only RGB or RGBA (incl. 16bit) or grey allowed\n   if (is_rgb16) *is_rgb16 = 0;\n   switch(bits_per_pixel) {\n      case 8:  return STBI_grey;\n      case 16: if(is_grey) return STBI_grey_alpha;\n               // fallthrough\n      case 15: if(is_rgb16) *is_rgb16 = 1;\n               return STBI_rgb;\n      case 24: // fallthrough\n      case 32: return bits_per_pixel/8;\n      default: return 0;\n   }\n}\n\nstatic int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)\n{\n    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;\n    int sz, tga_colormap_type;\n    stbi__get8(s);                   // discard Offset\n    tga_colormap_type = stbi__get8(s); // colormap type\n    if( tga_colormap_type > 1 ) {\n        stbi__rewind(s);\n        return 0;      // only RGB or indexed allowed\n    }\n    tga_image_type = stbi__get8(s); // image type\n    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image\n        if (tga_image_type != 1 && tga_image_type != 9) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n        sz = stbi__get8(s);    //   check bits per palette color entry\n        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip image x and y origin\n        tga_colormap_bpp = sz;\n    } else { // \"normal\" image w/o colormap - only RGB or grey allowed, +/- RLE\n        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {\n            stbi__rewind(s);\n            return 0; // only RGB or grey allowed, +/- RLE\n        }\n        stbi__skip(s,9); // skip colormap specification and image x/y origin\n        tga_colormap_bpp = 0;\n    }\n    tga_w = stbi__get16le(s);\n    if( tga_w < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test width\n    }\n    tga_h = stbi__get16le(s);\n    if( tga_h < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test height\n    }\n    tga_bits_per_pixel = stbi__get8(s); // bits per pixel\n    stbi__get8(s); // ignore alpha bits\n    if (tga_colormap_bpp != 0) {\n        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {\n            // when using a colormap, tga_bits_per_pixel is the size of the indexes\n            // I don't think anything but 8 or 16bit indexes makes sense\n            stbi__rewind(s);\n            return 0;\n        }\n        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);\n    } else {\n        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);\n    }\n    if(!tga_comp) {\n      stbi__rewind(s);\n      return 0;\n    }\n    if (x) *x = tga_w;\n    if (y) *y = tga_h;\n    if (comp) *comp = tga_comp;\n    return 1;                   // seems to have passed everything\n}\n\nstatic int stbi__tga_test(stbi__context *s)\n{\n   int res = 0;\n   int sz, tga_color_type;\n   stbi__get8(s);      //   discard Offset\n   tga_color_type = stbi__get8(s);   //   color type\n   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed\n   sz = stbi__get8(s);   //   image type\n   if ( tga_color_type == 1 ) { // colormapped (paletted) image\n      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9\n      stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n      sz = stbi__get8(s);    //   check bits per palette color entry\n      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n      stbi__skip(s,4);       // skip image x and y origin\n   } else { // \"normal\" image w/o colormap\n      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE\n      stbi__skip(s,9); // skip colormap specification and image x/y origin\n   }\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height\n   sz = stbi__get8(s);   //   bits per pixel\n   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index\n   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n\n   res = 1; // if we got this far, everything's good and we can return 1 instead of 0\n\nerrorEnd:\n   stbi__rewind(s);\n   return res;\n}\n\n// read 16bit value and convert to 24bit RGB\nstatic void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)\n{\n   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);\n   stbi__uint16 fiveBitMask = 31;\n   // we have 3 channels with 5bits each\n   int r = (px >> 10) & fiveBitMask;\n   int g = (px >> 5) & fiveBitMask;\n   int b = px & fiveBitMask;\n   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later\n   out[0] = (stbi_uc)((r * 255)/31);\n   out[1] = (stbi_uc)((g * 255)/31);\n   out[2] = (stbi_uc)((b * 255)/31);\n\n   // some people claim that the most significant bit might be used for alpha\n   // (possibly if an alpha-bit is set in the \"image descriptor byte\")\n   // but that only made 16bit test images completely translucent..\n   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.\n}\n\nstatic void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   //   read in the TGA header stuff\n   int tga_offset = stbi__get8(s);\n   int tga_indexed = stbi__get8(s);\n   int tga_image_type = stbi__get8(s);\n   int tga_is_RLE = 0;\n   int tga_palette_start = stbi__get16le(s);\n   int tga_palette_len = stbi__get16le(s);\n   int tga_palette_bits = stbi__get8(s);\n   int tga_x_origin = stbi__get16le(s);\n   int tga_y_origin = stbi__get16le(s);\n   int tga_width = stbi__get16le(s);\n   int tga_height = stbi__get16le(s);\n   int tga_bits_per_pixel = stbi__get8(s);\n   int tga_comp, tga_rgb16=0;\n   int tga_inverted = stbi__get8(s);\n   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)\n   //   image data\n   unsigned char *tga_data;\n   unsigned char *tga_palette = NULL;\n   int i, j;\n   unsigned char raw_data[4] = {0};\n   int RLE_count = 0;\n   int RLE_repeating = 0;\n   int read_next_pixel = 1;\n   STBI_NOTUSED(ri);\n   STBI_NOTUSED(tga_x_origin); // @TODO\n   STBI_NOTUSED(tga_y_origin); // @TODO\n\n   if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   //   do a tiny bit of precessing\n   if ( tga_image_type >= 8 )\n   {\n      tga_image_type -= 8;\n      tga_is_RLE = 1;\n   }\n   tga_inverted = 1 - ((tga_inverted >> 5) & 1);\n\n   //   If I'm paletted, then I'll use the number of bits from the palette\n   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);\n   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);\n\n   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency\n      return stbi__errpuc(\"bad format\", \"Can't find out TGA pixelformat\");\n\n   //   tga info\n   *x = tga_width;\n   *y = tga_height;\n   if (comp) *comp = tga_comp;\n\n   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt TGA\");\n\n   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);\n   if (!tga_data) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   // skip to the data's starting position (offset usually = 0)\n   stbi__skip(s, tga_offset );\n\n   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {\n      for (i=0; i < tga_height; ++i) {\n         int row = tga_inverted ? tga_height -i - 1 : i;\n         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;\n         stbi__getn(s, tga_row, tga_width * tga_comp);\n      }\n   } else  {\n      //   do I need to load a palette?\n      if ( tga_indexed)\n      {\n         if (tga_palette_len == 0) {  /* you have to have at least one entry! */\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n\n         //   any data to skip? (offset usually = 0)\n         stbi__skip(s, tga_palette_start );\n         //   load the palette\n         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);\n         if (!tga_palette) {\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"outofmem\", \"Out of memory\");\n         }\n         if (tga_rgb16) {\n            stbi_uc *pal_entry = tga_palette;\n            STBI_ASSERT(tga_comp == STBI_rgb);\n            for (i=0; i < tga_palette_len; ++i) {\n               stbi__tga_read_rgb16(s, pal_entry);\n               pal_entry += tga_comp;\n            }\n         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {\n               STBI_FREE(tga_data);\n               STBI_FREE(tga_palette);\n               return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n      }\n      //   load the data\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?\n         if ( tga_is_RLE )\n         {\n            if ( RLE_count == 0 )\n            {\n               //   yep, get the next byte as a RLE command\n               int RLE_cmd = stbi__get8(s);\n               RLE_count = 1 + (RLE_cmd & 127);\n               RLE_repeating = RLE_cmd >> 7;\n               read_next_pixel = 1;\n            } else if ( !RLE_repeating )\n            {\n               read_next_pixel = 1;\n            }\n         } else\n         {\n            read_next_pixel = 1;\n         }\n         //   OK, if I need to read a pixel, do it now\n         if ( read_next_pixel )\n         {\n            //   load however much data we did have\n            if ( tga_indexed )\n            {\n               // read in index, then perform the lookup\n               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);\n               if ( pal_idx >= tga_palette_len ) {\n                  // invalid index\n                  pal_idx = 0;\n               }\n               pal_idx *= tga_comp;\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = tga_palette[pal_idx+j];\n               }\n            } else if(tga_rgb16) {\n               STBI_ASSERT(tga_comp == STBI_rgb);\n               stbi__tga_read_rgb16(s, raw_data);\n            } else {\n               //   read in the data raw\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = stbi__get8(s);\n               }\n            }\n            //   clear the reading flag for the next pixel\n            read_next_pixel = 0;\n         } // end of reading a pixel\n\n         // copy data\n         for (j = 0; j < tga_comp; ++j)\n           tga_data[i*tga_comp+j] = raw_data[j];\n\n         //   in case we're in RLE mode, keep counting down\n         --RLE_count;\n      }\n      //   do I need to invert the image?\n      if ( tga_inverted )\n      {\n         for (j = 0; j*2 < tga_height; ++j)\n         {\n            int index1 = j * tga_width * tga_comp;\n            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;\n            for (i = tga_width * tga_comp; i > 0; --i)\n            {\n               unsigned char temp = tga_data[index1];\n               tga_data[index1] = tga_data[index2];\n               tga_data[index2] = temp;\n               ++index1;\n               ++index2;\n            }\n         }\n      }\n      //   clear my palette, if I had one\n      if ( tga_palette != NULL )\n      {\n         STBI_FREE( tga_palette );\n      }\n   }\n\n   // swap RGB - if the source data was RGB16, it already is in the right order\n   if (tga_comp >= 3 && !tga_rgb16)\n   {\n      unsigned char* tga_pixel = tga_data;\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         unsigned char temp = tga_pixel[0];\n         tga_pixel[0] = tga_pixel[2];\n         tga_pixel[2] = temp;\n         tga_pixel += tga_comp;\n      }\n   }\n\n   // convert to target component count\n   if (req_comp && req_comp != tga_comp)\n      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);\n\n   //   the things I do to get rid of an error message, and yet keep\n   //   Microsoft's C compilers happy... [8^(\n   tga_palette_start = tga_palette_len = tga_palette_bits =\n         tga_x_origin = tga_y_origin = 0;\n   STBI_NOTUSED(tga_palette_start);\n   //   OK, done\n   return tga_data;\n}\n#endif\n\n// *************************************************************************************************\n// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_test(stbi__context *s)\n{\n   int r = (stbi__get32be(s) == 0x38425053);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)\n{\n   int count, nleft, len;\n\n   count = 0;\n   while ((nleft = pixelCount - count) > 0) {\n      len = stbi__get8(s);\n      if (len == 128) {\n         // No-op.\n      } else if (len < 128) {\n         // Copy next len+1 bytes literally.\n         len++;\n         if (len > nleft) return 0; // corrupt data\n         count += len;\n         while (len) {\n            *p = stbi__get8(s);\n            p += 4;\n            len--;\n         }\n      } else if (len > 128) {\n         stbi_uc   val;\n         // Next -len+1 bytes in the dest are replicated from next source byte.\n         // (Interpret len as a negative 8-bit int.)\n         len = 257 - len;\n         if (len > nleft) return 0; // corrupt data\n         val = stbi__get8(s);\n         count += len;\n         while (len) {\n            *p = val;\n            p += 4;\n            len--;\n         }\n      }\n   }\n\n   return 1;\n}\n\nstatic void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   int pixelCount;\n   int channelCount, compression;\n   int channel, i;\n   int bitdepth;\n   int w,h;\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   if (stbi__get32be(s) != 0x38425053)   // \"8BPS\"\n      return stbi__errpuc(\"not PSD\", \"Corrupt PSD image\");\n\n   // Check file type version.\n   if (stbi__get16be(s) != 1)\n      return stbi__errpuc(\"wrong version\", \"Unsupported version of PSD image\");\n\n   // Skip 6 reserved bytes.\n   stbi__skip(s, 6 );\n\n   // Read the number of channels (R, G, B, A, etc).\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16)\n      return stbi__errpuc(\"wrong channel count\", \"Unsupported number of channels in PSD image\");\n\n   // Read the rows and columns of the image.\n   h = stbi__get32be(s);\n   w = stbi__get32be(s);\n\n   if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   // Make sure the depth is 8 bits.\n   bitdepth = stbi__get16be(s);\n   if (bitdepth != 8 && bitdepth != 16)\n      return stbi__errpuc(\"unsupported bit depth\", \"PSD bit depth is not 8 or 16 bit\");\n\n   // Make sure the color mode is RGB.\n   // Valid options are:\n   //   0: Bitmap\n   //   1: Grayscale\n   //   2: Indexed color\n   //   3: RGB color\n   //   4: CMYK color\n   //   7: Multichannel\n   //   8: Duotone\n   //   9: Lab color\n   if (stbi__get16be(s) != 3)\n      return stbi__errpuc(\"wrong color format\", \"PSD is not in RGB color format\");\n\n   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)\n   stbi__skip(s,stbi__get32be(s) );\n\n   // Skip the image resources.  (resolution, pen tool paths, etc)\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Skip the reserved data.\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Find out if the data is compressed.\n   // Known values:\n   //   0: no compression\n   //   1: RLE compressed\n   compression = stbi__get16be(s);\n   if (compression > 1)\n      return stbi__errpuc(\"bad compression\", \"PSD has an unknown compression format\");\n\n   // Check size\n   if (!stbi__mad3sizes_valid(4, w, h, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt PSD\");\n\n   // Create the destination image.\n\n   if (!compression && bitdepth == 16 && bpc == 16) {\n      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);\n      ri->bits_per_channel = 16;\n   } else\n      out = (stbi_uc *) stbi__malloc(4 * w*h);\n\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   pixelCount = w*h;\n\n   // Initialize the data to zero.\n   //memset( out, 0, pixelCount * 4 );\n\n   // Finally, the image data.\n   if (compression) {\n      // RLE as used by .PSD and .TIFF\n      // Loop until you get the number of unpacked bytes you are expecting:\n      //     Read the next source byte into n.\n      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.\n      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.\n      //     Else if n is 128, noop.\n      // Endloop\n\n      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,\n      // which we're going to just skip.\n      stbi__skip(s, h * channelCount * 2 );\n\n      // Read the RLE data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         stbi_uc *p;\n\n         p = out+channel;\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            for (i = 0; i < pixelCount; i++, p += 4)\n               *p = (channel == 3 ? 255 : 0);\n         } else {\n            // Read the RLE data.\n            if (!stbi__psd_decode_rle(s, p, pixelCount)) {\n               STBI_FREE(out);\n               return stbi__errpuc(\"corrupt\", \"bad RLE data\");\n            }\n         }\n      }\n\n   } else {\n      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)\n      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.\n\n      // Read the data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            if (bitdepth == 16 && bpc == 16) {\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               stbi__uint16 val = channel == 3 ? 65535 : 0;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = val;\n            } else {\n               stbi_uc *p = out+channel;\n               stbi_uc val = channel == 3 ? 255 : 0;\n               for (i = 0; i < pixelCount; i++, p += 4)\n                  *p = val;\n            }\n         } else {\n            if (ri->bits_per_channel == 16) {    // output bpc\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = (stbi__uint16) stbi__get16be(s);\n            } else {\n               stbi_uc *p = out+channel;\n               if (bitdepth == 16) {  // input bpc\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = (stbi_uc) (stbi__get16be(s) >> 8);\n               } else {\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = stbi__get8(s);\n               }\n            }\n         }\n      }\n   }\n\n   // remove weird white matte from PSD\n   if (channelCount >= 4) {\n      if (ri->bits_per_channel == 16) {\n         for (i=0; i < w*h; ++i) {\n            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 65535) {\n               float a = pixel[3] / 65535.0f;\n               float ra = 1.0f / a;\n               float inv_a = 65535.0f * (1 - ra);\n               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);\n               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);\n               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);\n            }\n         }\n      } else {\n         for (i=0; i < w*h; ++i) {\n            unsigned char *pixel = out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 255) {\n               float a = pixel[3] / 255.0f;\n               float ra = 1.0f / a;\n               float inv_a = 255.0f * (1 - ra);\n               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);\n               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);\n               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);\n            }\n         }\n      }\n   }\n\n   // convert to desired output format\n   if (req_comp && req_comp != 4) {\n      if (ri->bits_per_channel == 16)\n         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);\n      else\n         out = stbi__convert_format(out, 4, req_comp, w, h);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   if (comp) *comp = 4;\n   *y = h;\n   *x = w;\n\n   return out;\n}\n#endif\n\n// *************************************************************************************************\n// Softimage PIC loader\n// by Tom Seddon\n//\n// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format\n// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_is4(stbi__context *s,const char *str)\n{\n   int i;\n   for (i=0; i<4; ++i)\n      if (stbi__get8(s) != (stbi_uc)str[i])\n         return 0;\n\n   return 1;\n}\n\nstatic int stbi__pic_test_core(stbi__context *s)\n{\n   int i;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\"))\n      return 0;\n\n   for(i=0;i<84;++i)\n      stbi__get8(s);\n\n   if (!stbi__pic_is4(s,\"PICT\"))\n      return 0;\n\n   return 1;\n}\n\ntypedef struct\n{\n   stbi_uc size,type,channel;\n} stbi__pic_packet;\n\nstatic stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)\n{\n   int mask=0x80, i;\n\n   for (i=0; i<4; ++i, mask>>=1) {\n      if (channel & mask) {\n         if (stbi__at_eof(s)) return stbi__errpuc(\"bad file\",\"PIC file too short\");\n         dest[i]=stbi__get8(s);\n      }\n   }\n\n   return dest;\n}\n\nstatic void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)\n{\n   int mask=0x80,i;\n\n   for (i=0;i<4; ++i, mask>>=1)\n      if (channel&mask)\n         dest[i]=src[i];\n}\n\nstatic stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)\n{\n   int act_comp=0,num_packets=0,y,chained;\n   stbi__pic_packet packets[10];\n\n   // this will (should...) cater for even some bizarre stuff like having data\n    // for the same channel in multiple packets.\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return stbi__errpuc(\"bad format\",\"too many packets\");\n\n      packet = &packets[num_packets++];\n\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s))          return stbi__errpuc(\"bad file\",\"file too short (reading packets)\");\n      if (packet->size != 8)  return stbi__errpuc(\"bad format\",\"packet isn't 8bpp\");\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?\n\n   for(y=0; y<height; ++y) {\n      int packet_idx;\n\n      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {\n         stbi__pic_packet *packet = &packets[packet_idx];\n         stbi_uc *dest = result+y*width*4;\n\n         switch (packet->type) {\n            default:\n               return stbi__errpuc(\"bad format\",\"packet has bad compression type\");\n\n            case 0: {//uncompressed\n               int x;\n\n               for(x=0;x<width;++x, dest+=4)\n                  if (!stbi__readval(s,packet->channel,dest))\n                     return 0;\n               break;\n            }\n\n            case 1://Pure RLE\n               {\n                  int left=width, i;\n\n                  while (left>0) {\n                     stbi_uc count,value[4];\n\n                     count=stbi__get8(s);\n                     if (stbi__at_eof(s))   return stbi__errpuc(\"bad file\",\"file too short (pure read count)\");\n\n                     if (count > left)\n                        count = (stbi_uc) left;\n\n                     if (!stbi__readval(s,packet->channel,value))  return 0;\n\n                     for(i=0; i<count; ++i,dest+=4)\n                        stbi__copyval(packet->channel,dest,value);\n                     left -= count;\n                  }\n               }\n               break;\n\n            case 2: {//Mixed RLE\n               int left=width;\n               while (left>0) {\n                  int count = stbi__get8(s), i;\n                  if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (mixed read count)\");\n\n                  if (count >= 128) { // Repeated\n                     stbi_uc value[4];\n\n                     if (count==128)\n                        count = stbi__get16be(s);\n                     else\n                        count -= 127;\n                     if (count > left)\n                        return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     if (!stbi__readval(s,packet->channel,value))\n                        return 0;\n\n                     for(i=0;i<count;++i, dest += 4)\n                        stbi__copyval(packet->channel,dest,value);\n                  } else { // Raw\n                     ++count;\n                     if (count>left) return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     for(i=0;i<count;++i, dest+=4)\n                        if (!stbi__readval(s,packet->channel,dest))\n                           return 0;\n                  }\n                  left-=count;\n               }\n               break;\n            }\n         }\n      }\n   }\n\n   return result;\n}\n\nstatic void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *result;\n   int i, x,y, internal_comp;\n   STBI_NOTUSED(ri);\n\n   if (!comp) comp = &internal_comp;\n\n   for (i=0; i<92; ++i)\n      stbi__get8(s);\n\n   x = stbi__get16be(s);\n   y = stbi__get16be(s);\n\n   if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (pic header)\");\n   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc(\"too large\", \"PIC image too large to decode\");\n\n   stbi__get32be(s); //skip `ratio'\n   stbi__get16be(s); //skip `fields'\n   stbi__get16be(s); //skip `pad'\n\n   // intermediate buffer is RGBA\n   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);\n   if (!result) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   memset(result, 0xff, x*y*4);\n\n   if (!stbi__pic_load_core(s,x,y,comp, result)) {\n      STBI_FREE(result);\n      result=0;\n   }\n   *px = x;\n   *py = y;\n   if (req_comp == 0) req_comp = *comp;\n   result=stbi__convert_format(result,4,req_comp,x,y);\n\n   return result;\n}\n\nstatic int stbi__pic_test(stbi__context *s)\n{\n   int r = stbi__pic_test_core(s);\n   stbi__rewind(s);\n   return r;\n}\n#endif\n\n// *************************************************************************************************\n// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb\n\n#ifndef STBI_NO_GIF\ntypedef struct\n{\n   stbi__int16 prefix;\n   stbi_uc first;\n   stbi_uc suffix;\n} stbi__gif_lzw;\n\ntypedef struct\n{\n   int w,h;\n   stbi_uc *out;                 // output buffer (always 4 components)\n   stbi_uc *background;          // The current \"background\" as far as a gif is concerned\n   stbi_uc *history;\n   int flags, bgindex, ratio, transparent, eflags;\n   stbi_uc  pal[256][4];\n   stbi_uc lpal[256][4];\n   stbi__gif_lzw codes[8192];\n   stbi_uc *color_table;\n   int parse, step;\n   int lflags;\n   int start_x, start_y;\n   int max_x, max_y;\n   int cur_x, cur_y;\n   int line_size;\n   int delay;\n} stbi__gif;\n\nstatic int stbi__gif_test_raw(stbi__context *s)\n{\n   int sz;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;\n   sz = stbi__get8(s);\n   if (sz != '9' && sz != '7') return 0;\n   if (stbi__get8(s) != 'a') return 0;\n   return 1;\n}\n\nstatic int stbi__gif_test(stbi__context *s)\n{\n   int r = stbi__gif_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)\n{\n   int i;\n   for (i=0; i < num_entries; ++i) {\n      pal[i][2] = stbi__get8(s);\n      pal[i][1] = stbi__get8(s);\n      pal[i][0] = stbi__get8(s);\n      pal[i][3] = transp == i ? 0 : 255;\n   }\n}\n\nstatic int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)\n{\n   stbi_uc version;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')\n      return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   version = stbi__get8(s);\n   if (version != '7' && version != '9')    return stbi__err(\"not GIF\", \"Corrupt GIF\");\n   if (stbi__get8(s) != 'a')                return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   stbi__g_failure_reason = \"\";\n   g->w = stbi__get16le(s);\n   g->h = stbi__get16le(s);\n   g->flags = stbi__get8(s);\n   g->bgindex = stbi__get8(s);\n   g->ratio = stbi__get8(s);\n   g->transparent = -1;\n\n   if (g->w > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   if (g->h > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n\n   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments\n\n   if (is_info) return 1;\n\n   if (g->flags & 0x80)\n      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);\n\n   return 1;\n}\n\nstatic int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));\n   if (!g) return stbi__err(\"outofmem\", \"Out of memory\");\n   if (!stbi__gif_header(s, g, comp, 1)) {\n      STBI_FREE(g);\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = g->w;\n   if (y) *y = g->h;\n   STBI_FREE(g);\n   return 1;\n}\n\nstatic void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)\n{\n   stbi_uc *p, *c;\n   int idx;\n\n   // recurse to decode the prefixes, since the linked-list is backwards,\n   // and working backwards through an interleaved image would be nasty\n   if (g->codes[code].prefix >= 0)\n      stbi__out_gif_code(g, g->codes[code].prefix);\n\n   if (g->cur_y >= g->max_y) return;\n\n   idx = g->cur_x + g->cur_y;\n   p = &g->out[idx];\n   g->history[idx / 4] = 1;\n\n   c = &g->color_table[g->codes[code].suffix * 4];\n   if (c[3] > 128) { // don't render transparent pixels;\n      p[0] = c[2];\n      p[1] = c[1];\n      p[2] = c[0];\n      p[3] = c[3];\n   }\n   g->cur_x += 4;\n\n   if (g->cur_x >= g->max_x) {\n      g->cur_x = g->start_x;\n      g->cur_y += g->step;\n\n      while (g->cur_y >= g->max_y && g->parse > 0) {\n         g->step = (1 << g->parse) * g->line_size;\n         g->cur_y = g->start_y + (g->step >> 1);\n         --g->parse;\n      }\n   }\n}\n\nstatic stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)\n{\n   stbi_uc lzw_cs;\n   stbi__int32 len, init_code;\n   stbi__uint32 first;\n   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;\n   stbi__gif_lzw *p;\n\n   lzw_cs = stbi__get8(s);\n   if (lzw_cs > 12) return NULL;\n   clear = 1 << lzw_cs;\n   first = 1;\n   codesize = lzw_cs + 1;\n   codemask = (1 << codesize) - 1;\n   bits = 0;\n   valid_bits = 0;\n   for (init_code = 0; init_code < clear; init_code++) {\n      g->codes[init_code].prefix = -1;\n      g->codes[init_code].first = (stbi_uc) init_code;\n      g->codes[init_code].suffix = (stbi_uc) init_code;\n   }\n\n   // support no starting clear code\n   avail = clear+2;\n   oldcode = -1;\n\n   len = 0;\n   for(;;) {\n      if (valid_bits < codesize) {\n         if (len == 0) {\n            len = stbi__get8(s); // start new block\n            if (len == 0)\n               return g->out;\n         }\n         --len;\n         bits |= (stbi__int32) stbi__get8(s) << valid_bits;\n         valid_bits += 8;\n      } else {\n         stbi__int32 code = bits & codemask;\n         bits >>= codesize;\n         valid_bits -= codesize;\n         // @OPTIMIZE: is there some way we can accelerate the non-clear path?\n         if (code == clear) {  // clear code\n            codesize = lzw_cs + 1;\n            codemask = (1 << codesize) - 1;\n            avail = clear + 2;\n            oldcode = -1;\n            first = 0;\n         } else if (code == clear + 1) { // end of stream code\n            stbi__skip(s, len);\n            while ((len = stbi__get8(s)) > 0)\n               stbi__skip(s,len);\n            return g->out;\n         } else if (code <= avail) {\n            if (first) {\n               return stbi__errpuc(\"no clear code\", \"Corrupt GIF\");\n            }\n\n            if (oldcode >= 0) {\n               p = &g->codes[avail++];\n               if (avail > 8192) {\n                  return stbi__errpuc(\"too many codes\", \"Corrupt GIF\");\n               }\n\n               p->prefix = (stbi__int16) oldcode;\n               p->first = g->codes[oldcode].first;\n               p->suffix = (code == avail) ? p->first : g->codes[code].first;\n            } else if (code == avail)\n               return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n\n            stbi__out_gif_code(g, (stbi__uint16) code);\n\n            if ((avail & codemask) == 0 && avail <= 0x0FFF) {\n               codesize++;\n               codemask = (1 << codesize) - 1;\n            }\n\n            oldcode = code;\n         } else {\n            return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n         }\n      }\n   }\n}\n\n// this function is designed to support animated gifs, although stb_image doesn't support it\n// two back is the image from two frames ago, used for a very specific disposal format\nstatic stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)\n{\n   int dispose;\n   int first_frame;\n   int pi;\n   int pcount;\n   STBI_NOTUSED(req_comp);\n\n   // on first frame, any non-written pixels get the background colour (non-transparent)\n   first_frame = 0;\n   if (g->out == 0) {\n      if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header\n      if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))\n         return stbi__errpuc(\"too large\", \"GIF image is too large\");\n      pcount = g->w * g->h;\n      g->out = (stbi_uc *) stbi__malloc(4 * pcount);\n      g->background = (stbi_uc *) stbi__malloc(4 * pcount);\n      g->history = (stbi_uc *) stbi__malloc(pcount);\n      if (!g->out || !g->background || !g->history)\n         return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n      // image is treated as \"transparent\" at the start - ie, nothing overwrites the current background;\n      // background colour is only used for pixels that are not rendered first frame, after that \"background\"\n      // color refers to the color that was there the previous frame.\n      memset(g->out, 0x00, 4 * pcount);\n      memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)\n      memset(g->history, 0x00, pcount);        // pixels that were affected previous frame\n      first_frame = 1;\n   } else {\n      // second frame - how do we dispose of the previous one?\n      dispose = (g->eflags & 0x1C) >> 2;\n      pcount = g->w * g->h;\n\n      if ((dispose == 3) && (two_back == 0)) {\n         dispose = 2; // if I don't have an image to revert back to, default to the old background\n      }\n\n      if (dispose == 3) { // use previous graphic\n         for (pi = 0; pi < pcount; ++pi) {\n            if (g->history[pi]) {\n               memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );\n            }\n         }\n      } else if (dispose == 2) {\n         // restore what was changed last frame to background before that frame;\n         for (pi = 0; pi < pcount; ++pi) {\n            if (g->history[pi]) {\n               memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );\n            }\n         }\n      } else {\n         // This is a non-disposal case eithe way, so just\n         // leave the pixels as is, and they will become the new background\n         // 1: do not dispose\n         // 0:  not specified.\n      }\n\n      // background is what out is after the undoing of the previou frame;\n      memcpy( g->background, g->out, 4 * g->w * g->h );\n   }\n\n   // clear my history;\n   memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame\n\n   for (;;) {\n      int tag = stbi__get8(s);\n      switch (tag) {\n         case 0x2C: /* Image Descriptor */\n         {\n            stbi__int32 x, y, w, h;\n            stbi_uc *o;\n\n            x = stbi__get16le(s);\n            y = stbi__get16le(s);\n            w = stbi__get16le(s);\n            h = stbi__get16le(s);\n            if (((x + w) > (g->w)) || ((y + h) > (g->h)))\n               return stbi__errpuc(\"bad Image Descriptor\", \"Corrupt GIF\");\n\n            g->line_size = g->w * 4;\n            g->start_x = x * 4;\n            g->start_y = y * g->line_size;\n            g->max_x   = g->start_x + w * 4;\n            g->max_y   = g->start_y + h * g->line_size;\n            g->cur_x   = g->start_x;\n            g->cur_y   = g->start_y;\n\n            // if the width of the specified rectangle is 0, that means\n            // we may not see *any* pixels or the image is malformed;\n            // to make sure this is caught, move the current y down to\n            // max_y (which is what out_gif_code checks).\n            if (w == 0)\n               g->cur_y = g->max_y;\n\n            g->lflags = stbi__get8(s);\n\n            if (g->lflags & 0x40) {\n               g->step = 8 * g->line_size; // first interlaced spacing\n               g->parse = 3;\n            } else {\n               g->step = g->line_size;\n               g->parse = 0;\n            }\n\n            if (g->lflags & 0x80) {\n               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);\n               g->color_table = (stbi_uc *) g->lpal;\n            } else if (g->flags & 0x80) {\n               g->color_table = (stbi_uc *) g->pal;\n            } else\n               return stbi__errpuc(\"missing color table\", \"Corrupt GIF\");\n\n            o = stbi__process_gif_raster(s, g);\n            if (!o) return NULL;\n\n            // if this was the first frame,\n            pcount = g->w * g->h;\n            if (first_frame && (g->bgindex > 0)) {\n               // if first frame, any pixel not drawn to gets the background color\n               for (pi = 0; pi < pcount; ++pi) {\n                  if (g->history[pi] == 0) {\n                     g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;\n                     memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );\n                  }\n               }\n            }\n\n            return o;\n         }\n\n         case 0x21: // Comment Extension.\n         {\n            int len;\n            int ext = stbi__get8(s);\n            if (ext == 0xF9) { // Graphic Control Extension.\n               len = stbi__get8(s);\n               if (len == 4) {\n                  g->eflags = stbi__get8(s);\n                  g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.\n\n                  // unset old transparent\n                  if (g->transparent >= 0) {\n                     g->pal[g->transparent][3] = 255;\n                  }\n                  if (g->eflags & 0x01) {\n                     g->transparent = stbi__get8(s);\n                     if (g->transparent >= 0) {\n                        g->pal[g->transparent][3] = 0;\n                     }\n                  } else {\n                     // don't need transparent\n                     stbi__skip(s, 1);\n                     g->transparent = -1;\n                  }\n               } else {\n                  stbi__skip(s, len);\n                  break;\n               }\n            }\n            while ((len = stbi__get8(s)) != 0) {\n               stbi__skip(s, len);\n            }\n            break;\n         }\n\n         case 0x3B: // gif stream termination code\n            return (stbi_uc *) s; // using '1' causes warning on some compilers\n\n         default:\n            return stbi__errpuc(\"unknown code\", \"Corrupt GIF\");\n      }\n   }\n}\n\nstatic void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)\n{\n   STBI_FREE(g->out);\n   STBI_FREE(g->history);\n   STBI_FREE(g->background);\n\n   if (out) STBI_FREE(out);\n   if (delays && *delays) STBI_FREE(*delays);\n   return stbi__errpuc(\"outofmem\", \"Out of memory\");\n}\n\nstatic void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)\n{\n   if (stbi__gif_test(s)) {\n      int layers = 0;\n      stbi_uc *u = 0;\n      stbi_uc *out = 0;\n      stbi_uc *two_back = 0;\n      stbi__gif g;\n      int stride;\n      int out_size = 0;\n      int delays_size = 0;\n\n      STBI_NOTUSED(out_size);\n      STBI_NOTUSED(delays_size);\n\n      memset(&g, 0, sizeof(g));\n      if (delays) {\n         *delays = 0;\n      }\n\n      do {\n         u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);\n         if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n\n         if (u) {\n            *x = g.w;\n            *y = g.h;\n            ++layers;\n            stride = g.w * g.h * 4;\n\n            if (out) {\n               void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );\n               if (!tmp)\n                  return stbi__load_gif_main_outofmem(&g, out, delays);\n               else {\n                   out = (stbi_uc*) tmp;\n                   out_size = layers * stride;\n               }\n\n               if (delays) {\n                  int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );\n                  if (!new_delays)\n                     return stbi__load_gif_main_outofmem(&g, out, delays);\n                  *delays = new_delays;\n                  delays_size = layers * sizeof(int);\n               }\n            } else {\n               out = (stbi_uc*)stbi__malloc( layers * stride );\n               if (!out)\n                  return stbi__load_gif_main_outofmem(&g, out, delays);\n               out_size = layers * stride;\n               if (delays) {\n                  *delays = (int*) stbi__malloc( layers * sizeof(int) );\n                  if (!*delays)\n                     return stbi__load_gif_main_outofmem(&g, out, delays);\n                  delays_size = layers * sizeof(int);\n               }\n            }\n            memcpy( out + ((layers - 1) * stride), u, stride );\n            if (layers >= 2) {\n               two_back = out - 2 * stride;\n            }\n\n            if (delays) {\n               (*delays)[layers - 1U] = g.delay;\n            }\n         }\n      } while (u != 0);\n\n      // free temp buffer;\n      STBI_FREE(g.out);\n      STBI_FREE(g.history);\n      STBI_FREE(g.background);\n\n      // do the final conversion after loading everything;\n      if (req_comp && req_comp != 4)\n         out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);\n\n      *z = layers;\n      return out;\n   } else {\n      return stbi__errpuc(\"not GIF\", \"Image was not as a gif type.\");\n   }\n}\n\nstatic void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *u = 0;\n   stbi__gif g;\n   memset(&g, 0, sizeof(g));\n   STBI_NOTUSED(ri);\n\n   u = stbi__gif_load_next(s, &g, comp, req_comp, 0);\n   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n   if (u) {\n      *x = g.w;\n      *y = g.h;\n\n      // moved conversion to after successful load so that the same\n      // can be done for multiple frames.\n      if (req_comp && req_comp != 4)\n         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);\n   } else if (g.out) {\n      // if there was an error and we allocated an image buffer, free it!\n      STBI_FREE(g.out);\n   }\n\n   // free buffers needed for multiple frame loading;\n   STBI_FREE(g.history);\n   STBI_FREE(g.background);\n\n   return u;\n}\n\nstatic int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   return stbi__gif_info_raw(s,x,y,comp);\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR loader\n// originally by Nicolas Schulz\n#ifndef STBI_NO_HDR\nstatic int stbi__hdr_test_core(stbi__context *s, const char *signature)\n{\n   int i;\n   for (i=0; signature[i]; ++i)\n      if (stbi__get8(s) != signature[i])\n          return 0;\n   stbi__rewind(s);\n   return 1;\n}\n\nstatic int stbi__hdr_test(stbi__context* s)\n{\n   int r = stbi__hdr_test_core(s, \"#?RADIANCE\\n\");\n   stbi__rewind(s);\n   if(!r) {\n       r = stbi__hdr_test_core(s, \"#?RGBE\\n\");\n       stbi__rewind(s);\n   }\n   return r;\n}\n\n#define STBI__HDR_BUFLEN  1024\nstatic char *stbi__hdr_gettoken(stbi__context *z, char *buffer)\n{\n   int len=0;\n   char c = '\\0';\n\n   c = (char) stbi__get8(z);\n\n   while (!stbi__at_eof(z) && c != '\\n') {\n      buffer[len++] = c;\n      if (len == STBI__HDR_BUFLEN-1) {\n         // flush to end of line\n         while (!stbi__at_eof(z) && stbi__get8(z) != '\\n')\n            ;\n         break;\n      }\n      c = (char) stbi__get8(z);\n   }\n\n   buffer[len] = 0;\n   return buffer;\n}\n\nstatic void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)\n{\n   if ( input[3] != 0 ) {\n      float f1;\n      // Exponent\n      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));\n      if (req_comp <= 2)\n         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;\n      else {\n         output[0] = input[0] * f1;\n         output[1] = input[1] * f1;\n         output[2] = input[2] * f1;\n      }\n      if (req_comp == 2) output[1] = 1;\n      if (req_comp == 4) output[3] = 1;\n   } else {\n      switch (req_comp) {\n         case 4: output[3] = 1; /* fallthrough */\n         case 3: output[0] = output[1] = output[2] = 0;\n                 break;\n         case 2: output[1] = 1; /* fallthrough */\n         case 1: output[0] = 0;\n                 break;\n      }\n   }\n}\n\nstatic float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int width, height;\n   stbi_uc *scanline;\n   float *hdr_data;\n   int len;\n   unsigned char count, value;\n   int i, j, k, c1,c2, z;\n   const char *headerToken;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   headerToken = stbi__hdr_gettoken(s,buffer);\n   if (strcmp(headerToken, \"#?RADIANCE\") != 0 && strcmp(headerToken, \"#?RGBE\") != 0)\n      return stbi__errpf(\"not HDR\", \"Corrupt HDR image\");\n\n   // Parse header\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid)    return stbi__errpf(\"unsupported format\", \"Unsupported HDR format\");\n\n   // Parse width and height\n   // can't use sscanf() if we're not using stdio!\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   height = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   width = (int) strtol(token, NULL, 10);\n\n   if (height > STBI_MAX_DIMENSIONS) return stbi__errpf(\"too large\",\"Very large image (corrupt?)\");\n   if (width > STBI_MAX_DIMENSIONS) return stbi__errpf(\"too large\",\"Very large image (corrupt?)\");\n\n   *x = width;\n   *y = height;\n\n   if (comp) *comp = 3;\n   if (req_comp == 0) req_comp = 3;\n\n   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))\n      return stbi__errpf(\"too large\", \"HDR image is too large\");\n\n   // Read data\n   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);\n   if (!hdr_data)\n      return stbi__errpf(\"outofmem\", \"Out of memory\");\n\n   // Load image data\n   // image data is stored as some number of sca\n   if ( width < 8 || width >= 32768) {\n      // Read flat data\n      for (j=0; j < height; ++j) {\n         for (i=0; i < width; ++i) {\n            stbi_uc rgbe[4];\n           main_decode_loop:\n            stbi__getn(s, rgbe, 4);\n            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);\n         }\n      }\n   } else {\n      // Read RLE-encoded data\n      scanline = NULL;\n\n      for (j = 0; j < height; ++j) {\n         c1 = stbi__get8(s);\n         c2 = stbi__get8(s);\n         len = stbi__get8(s);\n         if (c1 != 2 || c2 != 2 || (len & 0x80)) {\n            // not run-length encoded, so we have to actually use THIS data as a decoded\n            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)\n            stbi_uc rgbe[4];\n            rgbe[0] = (stbi_uc) c1;\n            rgbe[1] = (stbi_uc) c2;\n            rgbe[2] = (stbi_uc) len;\n            rgbe[3] = (stbi_uc) stbi__get8(s);\n            stbi__hdr_convert(hdr_data, rgbe, req_comp);\n            i = 1;\n            j = 0;\n            STBI_FREE(scanline);\n            goto main_decode_loop; // yes, this makes no sense\n         }\n         len <<= 8;\n         len |= stbi__get8(s);\n         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"invalid decoded scanline length\", \"corrupt HDR\"); }\n         if (scanline == NULL) {\n            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);\n            if (!scanline) {\n               STBI_FREE(hdr_data);\n               return stbi__errpf(\"outofmem\", \"Out of memory\");\n            }\n         }\n\n         for (k = 0; k < 4; ++k) {\n            int nleft;\n            i = 0;\n            while ((nleft = width - i) > 0) {\n               count = stbi__get8(s);\n               if (count > 128) {\n                  // Run\n                  value = stbi__get8(s);\n                  count -= 128;\n                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = value;\n               } else {\n                  // Dump\n                  if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = stbi__get8(s);\n               }\n            }\n         }\n         for (i=0; i < width; ++i)\n            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);\n      }\n      if (scanline)\n         STBI_FREE(scanline);\n   }\n\n   return hdr_data;\n}\n\nstatic int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int dummy;\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   if (stbi__hdr_test(s) == 0) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *y = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *x = (int) strtol(token, NULL, 10);\n   *comp = 3;\n   return 1;\n}\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   void *p;\n   stbi__bmp_data info;\n\n   info.all_a = 255;\n   p = stbi__bmp_parse_header(s, &info);\n   if (p == NULL) {\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = s->img_x;\n   if (y) *y = s->img_y;\n   if (comp) {\n      if (info.bpp == 24 && info.ma == 0xff000000)\n         *comp = 3;\n      else\n         *comp = info.ma ? 4 : 3;\n   }\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int channelCount, dummy, depth;\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *y = stbi__get32be(s);\n   *x = stbi__get32be(s);\n   depth = stbi__get16be(s);\n   if (depth != 8 && depth != 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 3) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *comp = 4;\n   return 1;\n}\n\nstatic int stbi__psd_is16(stbi__context *s)\n{\n   int channelCount, depth;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   STBI_NOTUSED(stbi__get32be(s));\n   STBI_NOTUSED(stbi__get32be(s));\n   depth = stbi__get16be(s);\n   if (depth != 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int act_comp=0,num_packets=0,chained,dummy;\n   stbi__pic_packet packets[10];\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\")) {\n      stbi__rewind(s);\n      return 0;\n   }\n\n   stbi__skip(s, 88);\n\n   *x = stbi__get16be(s);\n   *y = stbi__get16be(s);\n   if (stbi__at_eof(s)) {\n      stbi__rewind( s);\n      return 0;\n   }\n   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {\n      stbi__rewind( s );\n      return 0;\n   }\n\n   stbi__skip(s, 8);\n\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return 0;\n\n      packet = &packets[num_packets++];\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s)) {\n          stbi__rewind( s );\n          return 0;\n      }\n      if (packet->size != 8) {\n          stbi__rewind( s );\n          return 0;\n      }\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3);\n\n   return 1;\n}\n#endif\n\n// *************************************************************************************************\n// Portable Gray Map and Portable Pixel Map loader\n// by Ken Miller\n//\n// PGM: http://netpbm.sourceforge.net/doc/pgm.html\n// PPM: http://netpbm.sourceforge.net/doc/ppm.html\n//\n// Known limitations:\n//    Does not support comments in the header section\n//    Does not support ASCII image data (formats P2 and P3)\n\n#ifndef STBI_NO_PNM\n\nstatic int      stbi__pnm_test(stbi__context *s)\n{\n   char p, t;\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n\nstatic void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n);\n   if (ri->bits_per_channel == 0)\n      return 0;\n\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n\n   if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0))\n      return stbi__errpuc(\"too large\", \"PNM too large\");\n\n   out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8));\n\n   if (req_comp && req_comp != s->img_n) {\n      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n   return out;\n}\n\nstatic int      stbi__pnm_isspace(char c)\n{\n   return c == ' ' || c == '\\t' || c == '\\n' || c == '\\v' || c == '\\f' || c == '\\r';\n}\n\nstatic void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)\n{\n   for (;;) {\n      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))\n         *c = (char) stbi__get8(s);\n\n      if (stbi__at_eof(s) || *c != '#')\n         break;\n\n      while (!stbi__at_eof(s) && *c != '\\n' && *c != '\\r' )\n         *c = (char) stbi__get8(s);\n   }\n}\n\nstatic int      stbi__pnm_isdigit(char c)\n{\n   return c >= '0' && c <= '9';\n}\n\nstatic int      stbi__pnm_getinteger(stbi__context *s, char *c)\n{\n   int value = 0;\n\n   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {\n      value = value*10 + (*c - '0');\n      *c = (char) stbi__get8(s);\n   }\n\n   return value;\n}\n\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int maxv, dummy;\n   char c, p, t;\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   stbi__rewind(s);\n\n   // Get identifier\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind(s);\n       return 0;\n   }\n\n   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm\n\n   c = (char) stbi__get8(s);\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *x = stbi__pnm_getinteger(s, &c); // read width\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *y = stbi__pnm_getinteger(s, &c); // read height\n   stbi__pnm_skip_whitespace(s, &c);\n\n   maxv = stbi__pnm_getinteger(s, &c);  // read max value\n   if (maxv > 65535)\n      return stbi__err(\"max value > 65535\", \"PPM image supports only 8-bit and 16-bit images\");\n   else if (maxv > 255)\n      return 16;\n   else\n      return 8;\n}\n\nstatic int stbi__pnm_is16(stbi__context *s)\n{\n   if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)\n\t   return 1;\n   return 0;\n}\n#endif\n\nstatic int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_info(s, x, y, comp)) return 1;\n   #endif\n\n   #ifndef STBI_NO_PNG\n   if (stbi__png_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_DDS\n   if (stbi__dds_info(s, x, y, comp, NULL))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PVR\n   if (stbi__pvr_info(s, x, y, comp, NULL))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PKM\n   if (stbi__pkm_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_QOI\n   if (stbi__qoi_info(s, x, y, comp))  return 1;\n   #endif\n\n   // test tga last because it's a crappy test!\n   #ifndef STBI_NO_TGA\n   if (stbi__tga_info(s, x, y, comp))\n       return 1;\n   #endif\n   return stbi__err(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic int stbi__is_16_main(stbi__context *s)\n{\n   #ifndef STBI_NO_PNG\n   if (stbi__png_is16(s))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_is16(s))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_is16(s))  return 1;\n   #endif\n   return 0;\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_info_from_file(f, x, y, comp);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__info_main(&s,x,y,comp);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n\nSTBIDEF int stbi_is_16_bit(char const *filename)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_is_16_bit_from_file(f);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_is_16_bit_from_file(FILE *f)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__is_16_main(&s);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__is_16_main(&s);\n}\n\nSTBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__is_16_main(&s);\n}\n\n// add in my DDS loading support\n#ifndef STBI_NO_DDS\n#include \"stbi_DDS_c.h\"\n#endif\n\n// add in my pvr loading support\n#ifndef STBI_NO_PVR\n#include \"stbi_pvr_c.h\"\n#endif\n\n// add in my pkm ( ETC1 ) loading support\n#ifndef STBI_NO_PKM\n#include \"stbi_pkm_c.h\"\n#endif\n\n#ifndef STBI_NO_EXT\n#include \"stbi_ext_c.h\"\n#endif\n\n// Quite OK Image loader\n// by Jack Bendtsen\n#ifndef STBI_NO_QOI\n#include \"stbi_qoi_c.h\"\n#endif\n\n#endif // STB_IMAGE_IMPLEMENTATION\n\n/*\n   revision history:\n      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs\n      2.19  (2018-02-11) fix warning\n      2.18  (2018-01-30) fix warnings\n      2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug\n                         1-bit BMP\n                         *_is_16_bit api\n                         avoid warnings\n      2.16  (2017-07-23) all functions have 16-bit variants;\n                         STBI_NO_STDIO works again;\n                         compilation fixes;\n                         fix rounding in unpremultiply;\n                         optimize vertical flip;\n                         disable raw_len validation;\n                         documentation fixes\n      2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;\n                         warning fixes; disable run-time SSE detection on gcc;\n                         uniform handling of optional \"return\" values;\n                         thread-safe initialization of zlib tables\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) allocate large structures on the stack\n                         remove white matting for transparent PSD\n                         fix reported channel count for PNG & BMP\n                         re-enable SSE2 in non-gcc 64-bit\n                         support RGB-formatted JPEG\n                         read 16-bit PNGs (only as 8-bit)\n      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED\n      2.09  (2016-01-16) allow comments in PNM files\n                         16-bit-per-pixel TGA (not bit-per-component)\n                         info() for TGA could break due to .hdr handling\n                         info() for BMP to shares code instead of sloppy parse\n                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc\n                         code cleanup\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) fix compiler warnings\n                         partial animated GIF support\n                         limited 16-bpc PSD support\n                         #ifdef unused functions\n                         bug with < 92 byte PIC,PNM,HDR,TGA\n      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value\n      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning\n      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit\n      2.03  (2015-04-12) extra corruption checking (mmozeiko)\n                         stbi_set_flip_vertically_on_load (nguillemot)\n                         fix NEON support; fix mingw support\n      2.02  (2015-01-19) fix incorrect assert, fix warning\n      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2\n      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG\n      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)\n                         progressive JPEG (stb)\n                         PGM/PPM support (Ken Miller)\n                         STBI_MALLOC,STBI_REALLOC,STBI_FREE\n                         GIF bugfix -- seemingly never worked\n                         STBI_NO_*, STBI_ONLY_*\n      1.48  (2014-12-14) fix incorrectly-named assert()\n      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)\n                         optimize PNG (ryg)\n                         fix bug in interlaced PNG with user-specified channel count (stb)\n      1.46  (2014-08-26)\n              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG\n      1.45  (2014-08-16)\n              fix MSVC-ARM internal compiler error by wrapping malloc\n      1.44  (2014-08-07)\n              various warning fixes from Ronny Chevalier\n      1.43  (2014-07-15)\n              fix MSVC-only compiler problem in code changed in 1.42\n      1.42  (2014-07-09)\n              don't define _CRT_SECURE_NO_WARNINGS (affects user code)\n              fixes to stbi__cleanup_jpeg path\n              added STBI_ASSERT to avoid requiring assert.h\n      1.41  (2014-06-25)\n              fix search&replace from 1.36 that messed up comments/error messages\n      1.40  (2014-06-22)\n              fix gcc struct-initialization warning\n      1.39  (2014-06-15)\n              fix to TGA optimization when req_comp != number of components in TGA;\n              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)\n              add support for BMP version 5 (more ignored fields)\n      1.38  (2014-06-06)\n              suppress MSVC warnings on integer casts truncating values\n              fix accidental rename of 'skip' field of I/O\n      1.37  (2014-06-04)\n              remove duplicate typedef\n      1.36  (2014-06-03)\n              convert to header file single-file library\n              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL\n      1.35  (2014-05-27)\n              various warnings\n              fix broken STBI_SIMD path\n              fix bug where stbi_load_from_file no longer left file pointer in correct place\n              fix broken non-easy path for 32-bit BMP (possibly never used)\n              TGA optimization by Arseny Kapoulkine\n      1.34  (unknown)\n              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case\n      1.33  (2011-07-14)\n              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements\n      1.32  (2011-07-13)\n              support for \"info\" function for all supported filetypes (SpartanJ)\n      1.31  (2011-06-20)\n              a few more leak fixes, bug in PNG handling (SpartanJ)\n      1.30  (2011-06-11)\n              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)\n              removed deprecated format-specific test/load functions\n              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway\n              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)\n              fix inefficiency in decoding 32-bit BMP (David Woo)\n      1.29  (2010-08-16)\n              various warning fixes from Aurelien Pocheville\n      1.28  (2010-08-01)\n              fix bug in GIF palette transparency (SpartanJ)\n      1.27  (2010-08-01)\n              cast-to-stbi_uc to fix warnings\n      1.26  (2010-07-24)\n              fix bug in file buffering for PNG reported by SpartanJ\n      1.25  (2010-07-17)\n              refix trans_data warning (Won Chun)\n      1.24  (2010-07-12)\n              perf improvements reading from files on platforms with lock-heavy fgetc()\n              minor perf improvements for jpeg\n              deprecated type-specific functions so we'll get feedback if they're needed\n              attempt to fix trans_data warning (Won Chun)\n      1.23    fixed bug in iPhone support\n      1.22  (2010-07-10)\n              removed image *writing* support\n              stbi_info support from Jetro Lauha\n              GIF support from Jean-Marc Lienher\n              iPhone PNG-extensions from James Brown\n              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)\n      1.21    fix use of 'stbi_uc' in header (reported by jon blow)\n      1.20    added support for Softimage PIC, by Tom Seddon\n      1.19    bug in interlaced PNG corruption check (found by ryg)\n      1.18  (2008-08-02)\n              fix a threading bug (local mutable static)\n      1.17    support interlaced PNG\n      1.16    major bugfix - stbi__convert_format converted one too many pixels\n      1.15    initialize some fields for thread safety\n      1.14    fix threadsafe conversion bug\n              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)\n      1.13    threadsafe\n      1.12    const qualifiers in the API\n      1.11    Support installable IDCT, colorspace conversion routines\n      1.10    Fixes for 64-bit (don't use \"unsigned long\")\n              optimized upsampling by Fabian \"ryg\" Giesen\n      1.09    Fix format-conversion for PSD code (bad global variables!)\n      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz\n      1.07    attempt to fix C++ warning/errors again\n      1.06    attempt to fix C++ warning/errors again\n      1.05    fix TGA loading to return correct *comp and use good luminance calc\n      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free\n      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR\n      1.02    support for (subset of) HDR files, float interface for preferred access to them\n      1.01    fix bug: possible bug in handling right-side up bmps... not sure\n              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all\n      1.00    interface to zlib that skips zlib header\n      0.99    correct handling of alpha in palette\n      0.98    TGA loader by lonesock; dynamically add loaders (untested)\n      0.97    jpeg errors on too large a file; also catch another malloc failure\n      0.96    fix detection of invalid v value - particleman@mollyrocket forum\n      0.95    during header scan, seek to markers in case of padding\n      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same\n      0.93    handle jpegtran output; verbose errors\n      0.92    read 4,8,16,24,32-bit BMP files of several formats\n      0.91    output 24-bit Windows 3.0 BMP files\n      0.90    fix a few more warnings; bump version number to approach 1.0\n      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd\n      0.60    fix compiling as c++\n      0.59    fix warnings: merge Dave Moore's -Wall fixes\n      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian\n      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available\n      0.56    fix bug: zlib uncompressed mode len vs. nlen\n      0.55    fix bug: restart_interval not initialized to 0\n      0.54    allow NULL for 'int *comp'\n      0.53    fix bug in png 3->4; speedup png decoding\n      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments\n      0.51    obey req_comp requests, 1-component jpegs return as 1-component,\n              on 'test' only check type, not whether we support this variant\n      0.50  (2006-11-19)\n              first released version\n*/\n\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "lib/SOIL2/stb_image_write.h",
    "content": "/* stb_image_write - v1.16 - public domain - http://nothings.org/stb\n   writes out PNG/BMP/TGA/JPEG/HDR images to C stdio - Sean Barrett 2010-2015\n                                     no warranty implied; use at your own risk\n\n   Before #including,\n\n       #define STB_IMAGE_WRITE_IMPLEMENTATION\n\n   in the file that you want to have the implementation.\n\n   Will probably not work correctly with strict-aliasing optimizations.\n\nABOUT:\n\n   This header file is a library for writing images to C stdio or a callback.\n\n   The PNG output is not optimal; it is 20-50% larger than the file\n   written by a decent optimizing implementation; though providing a custom\n   zlib compress function (see STBIW_ZLIB_COMPRESS) can mitigate that.\n   This library is designed for source code compactness and simplicity,\n   not optimal image file size or run-time performance.\n\nBUILDING:\n\n   You can #define STBIW_ASSERT(x) before the #include to avoid using assert.h.\n   You can #define STBIW_MALLOC(), STBIW_REALLOC(), and STBIW_FREE() to replace\n   malloc,realloc,free.\n   You can #define STBIW_MEMMOVE() to replace memmove()\n   You can #define STBIW_ZLIB_COMPRESS to use a custom zlib-style compress function\n   for PNG compression (instead of the builtin one), it must have the following signature:\n   unsigned char * my_compress(unsigned char *data, int data_len, int *out_len, int quality);\n   The returned data will be freed with STBIW_FREE() (free() by default),\n   so it must be heap allocated with STBIW_MALLOC() (malloc() by default),\n\nUNICODE:\n\n   If compiling for Windows and you wish to use Unicode filenames, compile\n   with\n       #define STBIW_WINDOWS_UTF8\n   and pass utf8-encoded filenames. Call stbiw_convert_wchar_to_utf8 to convert\n   Windows wchar_t filenames to utf8.\n\nUSAGE:\n\n   There are five functions, one for each image file format:\n\n     int stbi_write_png(char const *filename, int w, int h, int comp, const void *data, int stride_in_bytes);\n     int stbi_write_bmp(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_tga(char const *filename, int w, int h, int comp, const void *data);\n     int stbi_write_jpg(char const *filename, int w, int h, int comp, const void *data, int quality);\n     int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\n\n     void stbi_flip_vertically_on_write(int flag); // flag is non-zero to flip data vertically\n\n   There are also five equivalent functions that use an arbitrary write function. You are\n   expected to open/close your file-equivalent before and after calling these:\n\n     int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\n     int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n     int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\n     int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality);\n\n   where the callback is:\n      void stbi_write_func(void *context, void *data, int size);\n\n   You can configure it with these global variables:\n      int stbi_write_tga_with_rle;             // defaults to true; set to 0 to disable RLE\n      int stbi_write_png_compression_level;    // defaults to 8; set to higher for more compression\n      int stbi_write_force_png_filter;         // defaults to -1; set to 0..5 to force a filter mode\n\n\n   You can define STBI_WRITE_NO_STDIO to disable the file variant of these\n   functions, so the library will not use stdio.h at all. However, this will\n   also disable HDR writing, because it requires stdio for formatted output.\n\n   Each function returns 0 on failure and non-0 on success.\n\n   The functions create an image file defined by the parameters. The image\n   is a rectangle of pixels stored from left-to-right, top-to-bottom.\n   Each pixel contains 'comp' channels of data stored interleaved with 8-bits\n   per channel, in the following order: 1=Y, 2=YA, 3=RGB, 4=RGBA. (Y is\n   monochrome color.) The rectangle is 'w' pixels wide and 'h' pixels tall.\n   The *data pointer points to the first byte of the top-left-most pixel.\n   For PNG, \"stride_in_bytes\" is the distance in bytes from the first byte of\n   a row of pixels to the first byte of the next row of pixels.\n\n   PNG creates output files with the same number of components as the input.\n   The BMP format expands Y to RGB in the file format and does not\n   output alpha.\n\n   PNG supports writing rectangles of data even when the bytes storing rows of\n   data are not consecutive in memory (e.g. sub-rectangles of a larger image),\n   by supplying the stride between the beginning of adjacent rows. The other\n   formats do not. (Thus you cannot write a native-format BMP through the BMP\n   writer, both because it is in BGR order and because it may have padding\n   at the end of the line.)\n\n   PNG allows you to set the deflate compression level by setting the global\n   variable 'stbi_write_png_compression_level' (it defaults to 8).\n\n   HDR expects linear float data. Since the format is always 32-bit rgb(e)\n   data, alpha (if provided) is discarded, and for monochrome data it is\n   replicated across all three channels.\n\n   TGA supports RLE or non-RLE compressed data. To use non-RLE-compressed\n   data, set the global variable 'stbi_write_tga_with_rle' to 0.\n\n   JPEG does ignore alpha channels in input data; quality is between 1 and 100.\n   Higher quality looks better but results in a bigger image.\n   JPEG baseline (no JPEG progressive).\n\nCREDITS:\n\n\n   Sean Barrett           -    PNG/BMP/TGA\n   Baldur Karlsson        -    HDR\n   Jean-Sebastien Guay    -    TGA monochrome\n   Tim Kelsey             -    misc enhancements\n   Alan Hickman           -    TGA RLE\n   Emmanuel Julien        -    initial file IO callback implementation\n   Jon Olick              -    original jo_jpeg.cpp code\n   Daniel Gibson          -    integrate JPEG, allow external zlib\n   Aarni Koskela          -    allow choosing PNG filter\n\n   bugfixes:\n      github:Chribba\n      Guillaume Chereau\n      github:jry2\n      github:romigrou\n      Sergio Gonzalez\n      Jonas Karlsson\n      Filip Wasil\n      Thatcher Ulrich\n      github:poppolopoppo\n      Patrick Boettcher\n      github:xeekworx\n      Cap Petschulat\n      Simon Rodriguez\n      Ivan Tikhonov\n      github:ignotion\n      Adam Schackart\n      Andrew Kensler\n\nLICENSE\n\n  See end of file for license information.\n\n*/\n\n#ifndef INCLUDE_STB_IMAGE_WRITE_H\n#define INCLUDE_STB_IMAGE_WRITE_H\n\n#include <stdlib.h>\n\n// if STB_IMAGE_WRITE_STATIC causes problems, try defining STBIWDEF to 'inline' or 'static inline'\n#ifndef STBIWDEF\n#ifdef STB_IMAGE_WRITE_STATIC\n#define STBIWDEF  static\n#else\n#ifdef __cplusplus\n#define STBIWDEF  extern \"C\"\n#else\n#define STBIWDEF  extern\n#endif\n#endif\n#endif\n\n#ifndef STB_IMAGE_WRITE_STATIC  // C++ forbids static forward declarations\nSTBIWDEF int stbi_write_tga_with_rle;\nSTBIWDEF int stbi_write_png_compression_level;\nSTBIWDEF int stbi_write_force_png_filter;\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga(char const *filename, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr(char const *filename, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void  *data, int quality);\n#ifndef STBI_WRITE_NO_QOI\nSTBIWDEF int stbi_write_qoi(char const *filename, int w, int h, int comp, const void  *data);\n#endif\n\n#ifdef STBIW_WINDOWS_UTF8\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n#endif\n\ntypedef void stbi_write_func(void *context, void *data, int size);\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data, int stride_in_bytes);\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const float *data);\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void  *data, int quality);\n#ifndef STBI_WRITE_NO_QOI\nSTBIWDEF int stbi_write_qoi_to_func(stbi_write_func *func, void *context, int w, int h, int comp, const void  *data);\n#endif\nSTBIWDEF void stbi_flip_vertically_on_write(int flip_boolean);\n\n#endif//INCLUDE_STB_IMAGE_WRITE_H\n\n#ifdef STB_IMAGE_WRITE_IMPLEMENTATION\n\n#ifdef _WIN32\n   #ifndef _CRT_SECURE_NO_WARNINGS\n   #define _CRT_SECURE_NO_WARNINGS\n   #endif\n   #ifndef _CRT_NONSTDC_NO_DEPRECATE\n   #define _CRT_NONSTDC_NO_DEPRECATE\n   #endif\n#endif\n\n#ifndef STBI_WRITE_NO_STDIO\n#include <stdio.h>\n#endif // STBI_WRITE_NO_STDIO\n\n#include <stdarg.h>\n#include <stdlib.h>\n#include <string.h>\n#include <math.h>\n\n#if defined(STBIW_MALLOC) && defined(STBIW_FREE) && (defined(STBIW_REALLOC) || defined(STBIW_REALLOC_SIZED))\n// ok\n#elif !defined(STBIW_MALLOC) && !defined(STBIW_FREE) && !defined(STBIW_REALLOC) && !defined(STBIW_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBIW_MALLOC, STBIW_FREE, and STBIW_REALLOC (or STBIW_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBIW_MALLOC\n#define STBIW_MALLOC(sz)        malloc(sz)\n#define STBIW_REALLOC(p,newsz)  realloc(p,newsz)\n#define STBIW_FREE(p)           free(p)\n#endif\n\n#ifndef STBIW_REALLOC_SIZED\n#define STBIW_REALLOC_SIZED(p,oldsz,newsz) STBIW_REALLOC(p,newsz)\n#endif\n\n\n#ifndef STBIW_MEMMOVE\n#define STBIW_MEMMOVE(a,b,sz) memmove(a,b,sz)\n#endif\n\n\n#ifndef STBIW_ASSERT\n#include <assert.h>\n#define STBIW_ASSERT(x) assert(x)\n#endif\n\n#define STBIW_UCHAR(x) (unsigned char) ((x) & 0xff)\n\n#ifdef STB_IMAGE_WRITE_STATIC\nstatic int stbi_write_png_compression_level = 8;\nstatic int stbi_write_tga_with_rle = 1;\nstatic int stbi_write_force_png_filter = -1;\n#else\nint stbi_write_png_compression_level = 8;\nint stbi_write_tga_with_rle = 1;\nint stbi_write_force_png_filter = -1;\n#endif\n\nstatic int stbi__flip_vertically_on_write = 0;\n\nSTBIWDEF void stbi_flip_vertically_on_write(int flag)\n{\n   stbi__flip_vertically_on_write = flag;\n}\n\ntypedef struct\n{\n   stbi_write_func *func;\n   void *context;\n   unsigned char buffer[64];\n   int buf_used;\n} stbi__write_context;\n\n// initialize a callback-based context\nstatic void stbi__start_write_callbacks(stbi__write_context *s, stbi_write_func *c, void *context)\n{\n   s->func    = c;\n   s->context = context;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbi__stdio_write(void *context, void *data, int size)\n{\n   fwrite(data,1,size,(FILE*) context);\n}\n\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n#ifdef __cplusplus\n#define STBIW_EXTERN extern \"C\"\n#else\n#define STBIW_EXTERN extern\n#endif\nSTBIW_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBIW_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n\nSTBIWDEF int stbiw_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n   return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbiw__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBIW_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n   if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != _wfopen_s(&f, wFilename, wMode))\n      f = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\nstatic int stbi__start_write_file(stbi__write_context *s, const char *filename)\n{\n   FILE *f = stbiw__fopen(filename, \"wb\");\n   stbi__start_write_callbacks(s, stbi__stdio_write, (void *) f);\n   return f != NULL;\n}\n\nstatic void stbi__end_write_file(stbi__write_context *s)\n{\n   fclose((FILE *)s->context);\n}\n\n#endif // !STBI_WRITE_NO_STDIO\n\ntypedef unsigned int stbiw_uint32;\ntypedef int stb_image_write_test[sizeof(stbiw_uint32)==4 ? 1 : -1];\n\nstatic void stbiw__writefv(stbi__write_context *s, const char *fmt, va_list v)\n{\n   while (*fmt) {\n      switch (*fmt++) {\n         case ' ': break;\n         case '1': { unsigned char x = STBIW_UCHAR(va_arg(v, int));\n                     s->func(s->context,&x,1);\n                     break; }\n         case '2': { int x = va_arg(v,int);\n                     unsigned char b[2];\n                     b[0] = STBIW_UCHAR(x);\n                     b[1] = STBIW_UCHAR(x>>8);\n                     s->func(s->context,b,2);\n                     break; }\n         case '4': { stbiw_uint32 x = va_arg(v,int);\n                     unsigned char b[4];\n                     b[0]=STBIW_UCHAR(x);\n                     b[1]=STBIW_UCHAR(x>>8);\n                     b[2]=STBIW_UCHAR(x>>16);\n                     b[3]=STBIW_UCHAR(x>>24);\n                     s->func(s->context,b,4);\n                     break; }\n         default:\n            STBIW_ASSERT(0);\n            return;\n      }\n   }\n}\n\nstatic void stbiw__writef(stbi__write_context *s, const char *fmt, ...)\n{\n   va_list v;\n   va_start(v, fmt);\n   stbiw__writefv(s, fmt, v);\n   va_end(v);\n}\n\nstatic void stbiw__write_flush(stbi__write_context *s)\n{\n   if (s->buf_used) {\n      s->func(s->context, &s->buffer, s->buf_used);\n      s->buf_used = 0;\n   }\n}\n\nstatic void stbiw__putc(stbi__write_context *s, unsigned char c)\n{\n   s->func(s->context, &c, 1);\n}\n\nstatic void stbiw__write1(stbi__write_context *s, unsigned char a)\n{\n   if ((size_t)s->buf_used + 1 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   s->buffer[s->buf_used++] = a;\n}\n\nstatic void stbiw__write3(stbi__write_context *s, unsigned char a, unsigned char b, unsigned char c)\n{\n   int n;\n   if ((size_t)s->buf_used + 3 > sizeof(s->buffer))\n      stbiw__write_flush(s);\n   n = s->buf_used;\n   s->buf_used = n+3;\n   s->buffer[n+0] = a;\n   s->buffer[n+1] = b;\n   s->buffer[n+2] = c;\n}\n\nstatic void stbiw__write_pixel(stbi__write_context *s, int rgb_dir, int comp, int write_alpha, int expand_mono, unsigned char *d)\n{\n   unsigned char bg[3] = { 255, 0, 255}, px[3];\n   int k;\n\n   if (write_alpha < 0)\n      stbiw__write1(s, d[comp - 1]);\n\n   switch (comp) {\n      case 2: // 2 pixels = mono + alpha, alpha is written separately, so same as 1-channel case\n      case 1:\n         if (expand_mono)\n            stbiw__write3(s, d[0], d[0], d[0]); // monochrome bmp\n         else\n            stbiw__write1(s, d[0]);  // monochrome TGA\n         break;\n      case 4:\n         if (!write_alpha) {\n            // composite against pink background\n            for (k = 0; k < 3; ++k)\n               px[k] = bg[k] + ((d[k] - bg[k]) * d[3]) / 255;\n            stbiw__write3(s, px[1 - rgb_dir], px[1], px[1 + rgb_dir]);\n            break;\n         }\n         /* FALLTHROUGH */\n      case 3:\n         stbiw__write3(s, d[1 - rgb_dir], d[1], d[1 + rgb_dir]);\n         break;\n   }\n   if (write_alpha > 0)\n      stbiw__write1(s, d[comp - 1]);\n}\n\nstatic void stbiw__write_pixels(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, void *data, int write_alpha, int scanline_pad, int expand_mono)\n{\n   stbiw_uint32 zero = 0;\n   int i,j, j_end;\n\n   if (y <= 0)\n      return;\n\n   if (stbi__flip_vertically_on_write)\n      vdir *= -1;\n\n   if (vdir < 0) {\n      j_end = -1; j = y-1;\n   } else {\n      j_end =  y; j = 0;\n   }\n\n   for (; j != j_end; j += vdir) {\n      for (i=0; i < x; ++i) {\n         unsigned char *d = (unsigned char *) data + (j*x+i)*comp;\n         stbiw__write_pixel(s, rgb_dir, comp, write_alpha, expand_mono, d);\n      }\n      stbiw__write_flush(s);\n      s->func(s->context, &zero, scanline_pad);\n   }\n}\n\nstatic int stbiw__outfile(stbi__write_context *s, int rgb_dir, int vdir, int x, int y, int comp, int expand_mono, void *data, int alpha, int pad, const char *fmt, ...)\n{\n   if (y < 0 || x < 0) {\n      return 0;\n   } else {\n      va_list v;\n      va_start(v, fmt);\n      stbiw__writefv(s, fmt, v);\n      va_end(v);\n      stbiw__write_pixels(s,rgb_dir,vdir,x,y,comp,data,alpha,pad, expand_mono);\n      return 1;\n   }\n}\n\nstatic int stbi_write_bmp_core(stbi__write_context *s, int x, int y, int comp, const void *data)\n{\n   if (comp != 4) {\n      // write RGB bitmap\n      int pad = (-x*3) & 3;\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *) data,0,pad,\n              \"11 4 22 4\" \"4 44 22 444444\",\n              'B', 'M', 14+40+(x*3+pad)*y, 0,0, 14+40,  // file header\n               40, x,y, 1,24, 0,0,0,0,0,0);             // bitmap header\n   } else {\n      // RGBA bitmaps need a v4 header\n      // use BI_BITFIELDS mode with 32bpp and alpha mask\n      // (straight BI_RGB with alpha mask doesn't work in most readers)\n      return stbiw__outfile(s,-1,-1,x,y,comp,1,(void *)data,1,0,\n         \"11 4 22 4\" \"4 44 22 444444 4444 4 444 444 444 444\",\n         'B', 'M', 14+108+x*y*4, 0, 0, 14+108, // file header\n         108, x,y, 1,32, 3,0,0,0,0,0, 0xff0000,0xff00,0xff,0xff000000u, 0, 0,0,0, 0,0,0, 0,0,0, 0,0,0); // bitmap V4 header\n   }\n}\n\nSTBIWDEF int stbi_write_bmp_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_bmp_core(&s, x, y, comp, data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_bmp(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_bmp_core(&s, x, y, comp, data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif //!STBI_WRITE_NO_STDIO\n\nstatic int stbi_write_tga_core(stbi__write_context *s, int x, int y, int comp, void *data)\n{\n   int has_alpha = (comp == 2 || comp == 4);\n   int colorbytes = has_alpha ? comp-1 : comp;\n   int format = colorbytes < 2 ? 3 : 2; // 3 color channels (RGB/RGBA) = 2, 1 color channel (Y/YA) = 3\n\n   if (y < 0 || x < 0)\n      return 0;\n\n   if (!stbi_write_tga_with_rle) {\n      return stbiw__outfile(s, -1, -1, x, y, comp, 0, (void *) data, has_alpha, 0,\n         \"111 221 2222 11\", 0, 0, format, 0, 0, 0, 0, 0, x, y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n   } else {\n      int i,j,k;\n      int jend, jdir;\n\n      stbiw__writef(s, \"111 221 2222 11\", 0,0,format+8, 0,0,0, 0,0,x,y, (colorbytes + has_alpha) * 8, has_alpha * 8);\n\n      if (stbi__flip_vertically_on_write) {\n         j = 0;\n         jend = y;\n         jdir = 1;\n      } else {\n         j = y-1;\n         jend = -1;\n         jdir = -1;\n      }\n      for (; j != jend; j += jdir) {\n         unsigned char *row = (unsigned char *) data + j * x * comp;\n         int len;\n\n         for (i = 0; i < x; i += len) {\n            unsigned char *begin = row + i * comp;\n            int diff = 1;\n            len = 1;\n\n            if (i < x - 1) {\n               ++len;\n               diff = memcmp(begin, row + (i + 1) * comp, comp);\n               if (diff) {\n                  const unsigned char *prev = begin;\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (memcmp(prev, row + k * comp, comp)) {\n                        prev += comp;\n                        ++len;\n                     } else {\n                        --len;\n                        break;\n                     }\n                  }\n               } else {\n                  for (k = i + 2; k < x && len < 128; ++k) {\n                     if (!memcmp(begin, row + k * comp, comp)) {\n                        ++len;\n                     } else {\n                        break;\n                     }\n                  }\n               }\n            }\n\n            if (diff) {\n               unsigned char header = STBIW_UCHAR(len - 1);\n               stbiw__write1(s, header);\n               for (k = 0; k < len; ++k) {\n                  stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin + k * comp);\n               }\n            } else {\n               unsigned char header = STBIW_UCHAR(len - 129);\n               stbiw__write1(s, header);\n               stbiw__write_pixel(s, -1, comp, has_alpha, 0, begin);\n            }\n         }\n      }\n      stbiw__write_flush(s);\n   }\n   return 1;\n}\n\nSTBIWDEF int stbi_write_tga_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_tga_core(&s, x, y, comp, (void *) data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_tga(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_tga_core(&s, x, y, comp, (void *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR writer\n// by Baldur Karlsson\n\n#define stbiw__max(a, b)  ((a) > (b) ? (a) : (b))\n\n#ifndef STBI_WRITE_NO_STDIO\n\nstatic void stbiw__linear_to_rgbe(unsigned char *rgbe, float *linear)\n{\n   int exponent;\n   float maxcomp = stbiw__max(linear[0], stbiw__max(linear[1], linear[2]));\n\n   if (maxcomp < 1e-32f) {\n      rgbe[0] = rgbe[1] = rgbe[2] = rgbe[3] = 0;\n   } else {\n      float normalize = (float) frexp(maxcomp, &exponent) * 256.0f/maxcomp;\n\n      rgbe[0] = (unsigned char)(linear[0] * normalize);\n      rgbe[1] = (unsigned char)(linear[1] * normalize);\n      rgbe[2] = (unsigned char)(linear[2] * normalize);\n      rgbe[3] = (unsigned char)(exponent + 128);\n   }\n}\n\nstatic void stbiw__write_run_data(stbi__write_context *s, int length, unsigned char databyte)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length+128);\n   STBIW_ASSERT(length+128 <= 255);\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, &databyte, 1);\n}\n\nstatic void stbiw__write_dump_data(stbi__write_context *s, int length, unsigned char *data)\n{\n   unsigned char lengthbyte = STBIW_UCHAR(length);\n   STBIW_ASSERT(length <= 128); // inconsistent with spec but consistent with official code\n   s->func(s->context, &lengthbyte, 1);\n   s->func(s->context, data, length);\n}\n\nstatic void stbiw__write_hdr_scanline(stbi__write_context *s, int width, int ncomp, unsigned char *scratch, float *scanline)\n{\n   unsigned char scanlineheader[4] = { 2, 2, 0, 0 };\n   unsigned char rgbe[4];\n   float linear[3];\n   int x;\n\n   scanlineheader[2] = (width&0xff00)>>8;\n   scanlineheader[3] = (width&0x00ff);\n\n   /* skip RLE for images too small or large */\n   if (width < 8 || width >= 32768) {\n      for (x=0; x < width; x++) {\n         switch (ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         s->func(s->context, rgbe, 4);\n      }\n   } else {\n      int c,r;\n      /* encode into scratch buffer */\n      for (x=0; x < width; x++) {\n         switch(ncomp) {\n            case 4: /* fallthrough */\n            case 3: linear[2] = scanline[x*ncomp + 2];\n                    linear[1] = scanline[x*ncomp + 1];\n                    linear[0] = scanline[x*ncomp + 0];\n                    break;\n            default:\n                    linear[0] = linear[1] = linear[2] = scanline[x*ncomp + 0];\n                    break;\n         }\n         stbiw__linear_to_rgbe(rgbe, linear);\n         scratch[x + width*0] = rgbe[0];\n         scratch[x + width*1] = rgbe[1];\n         scratch[x + width*2] = rgbe[2];\n         scratch[x + width*3] = rgbe[3];\n      }\n\n      s->func(s->context, scanlineheader, 4);\n\n      /* RLE each component separately */\n      for (c=0; c < 4; c++) {\n         unsigned char *comp = &scratch[width*c];\n\n         x = 0;\n         while (x < width) {\n            // find first run\n            r = x;\n            while (r+2 < width) {\n               if (comp[r] == comp[r+1] && comp[r] == comp[r+2])\n                  break;\n               ++r;\n            }\n            if (r+2 >= width)\n               r = width;\n            // dump up to first run\n            while (x < r) {\n               int len = r-x;\n               if (len > 128) len = 128;\n               stbiw__write_dump_data(s, len, &comp[x]);\n               x += len;\n            }\n            // if there's a run, output it\n            if (r+2 < width) { // same test as what we break out of in search loop, so only true if we break'd\n               // find next byte after run\n               while (r < width && comp[r] == comp[x])\n                  ++r;\n               // output run up to r\n               while (x < r) {\n                  int len = r-x;\n                  if (len > 127) len = 127;\n                  stbiw__write_run_data(s, len, comp[x]);\n                  x += len;\n               }\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, float *data)\n{\n   if (y <= 0 || x <= 0 || data == NULL)\n      return 0;\n   else {\n      // Each component is stored separately. Allocate scratch space for full output scanline.\n      unsigned char *scratch = (unsigned char *) STBIW_MALLOC(x*4);\n      int i, len;\n      char buffer[128];\n      char header[] = \"#?RADIANCE\\n# Written by stb_image_write.h\\nFORMAT=32-bit_rle_rgbe\\n\";\n      s->func(s->context, header, sizeof(header)-1);\n\n#ifdef __STDC_LIB_EXT1__\n      len = sprintf_s(buffer, sizeof(buffer), \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#else\n      len = sprintf(buffer, \"EXPOSURE=          1.0000000000000\\n\\n-Y %d +X %d\\n\", y, x);\n#endif\n      s->func(s->context, buffer, len);\n\n      for(i=0; i < y; i++)\n         stbiw__write_hdr_scanline(s, x, comp, scratch, data + comp*x*(stbi__flip_vertically_on_write ? y-1-i : i));\n      STBIW_FREE(scratch);\n      return 1;\n   }\n}\n\nSTBIWDEF int stbi_write_hdr_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n}\n\nSTBIWDEF int stbi_write_hdr(char const *filename, int x, int y, int comp, const float *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_hdr_core(&s, x, y, comp, (float *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif // STBI_WRITE_NO_STDIO\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PNG writer\n//\n\n#ifndef STBIW_ZLIB_COMPRESS\n// stretchy buffer; stbiw__sbpush() == vector<>::push_back() -- stbiw__sbcount() == vector<>::size()\n#define stbiw__sbraw(a) ((int *) (void *) (a) - 2)\n#define stbiw__sbm(a)   stbiw__sbraw(a)[0]\n#define stbiw__sbn(a)   stbiw__sbraw(a)[1]\n\n#define stbiw__sbneedgrow(a,n)  ((a)==0 || stbiw__sbn(a)+n >= stbiw__sbm(a))\n#define stbiw__sbmaybegrow(a,n) (stbiw__sbneedgrow(a,(n)) ? stbiw__sbgrow(a,n) : 0)\n#define stbiw__sbgrow(a,n)  stbiw__sbgrowf((void **) &(a), (n), sizeof(*(a)))\n\n#define stbiw__sbpush(a, v)      (stbiw__sbmaybegrow(a,1), (a)[stbiw__sbn(a)++] = (v))\n#define stbiw__sbcount(a)        ((a) ? stbiw__sbn(a) : 0)\n#define stbiw__sbfree(a)         ((a) ? STBIW_FREE(stbiw__sbraw(a)),0 : 0)\n\nstatic void *stbiw__sbgrowf(void **arr, int increment, int itemsize)\n{\n   int m = *arr ? 2*stbiw__sbm(*arr)+increment : increment+1;\n   void *p = STBIW_REALLOC_SIZED(*arr ? stbiw__sbraw(*arr) : 0, *arr ? (stbiw__sbm(*arr)*itemsize + sizeof(int)*2) : 0, itemsize * m + sizeof(int)*2);\n   STBIW_ASSERT(p);\n   if (p) {\n      if (!*arr) ((int *) p)[1] = 0;\n      *arr = (void *) ((int *) p + 2);\n      stbiw__sbm(*arr) = m;\n   }\n   return *arr;\n}\n\nstatic unsigned char *stbiw__zlib_flushf(unsigned char *data, unsigned int *bitbuffer, int *bitcount)\n{\n   while (*bitcount >= 8) {\n      stbiw__sbpush(data, STBIW_UCHAR(*bitbuffer));\n      *bitbuffer >>= 8;\n      *bitcount -= 8;\n   }\n   return data;\n}\n\nstatic int stbiw__zlib_bitrev(int code, int codebits)\n{\n   int res=0;\n   while (codebits--) {\n      res = (res << 1) | (code & 1);\n      code >>= 1;\n   }\n   return res;\n}\n\nstatic unsigned int stbiw__zlib_countm(unsigned char *a, unsigned char *b, int limit)\n{\n   int i;\n   for (i=0; i < limit && i < 258; ++i)\n      if (a[i] != b[i]) break;\n   return i;\n}\n\nstatic unsigned int stbiw__zhash(unsigned char *data)\n{\n   stbiw_uint32 hash = data[0] + (data[1] << 8) + (data[2] << 16);\n   hash ^= hash << 3;\n   hash += hash >> 5;\n   hash ^= hash << 4;\n   hash += hash >> 17;\n   hash ^= hash << 25;\n   hash += hash >> 6;\n   return hash;\n}\n\n#define stbiw__zlib_flush() (out = stbiw__zlib_flushf(out, &bitbuf, &bitcount))\n#define stbiw__zlib_add(code,codebits) \\\n      (bitbuf |= (code) << bitcount, bitcount += (codebits), stbiw__zlib_flush())\n#define stbiw__zlib_huffa(b,c)  stbiw__zlib_add(stbiw__zlib_bitrev(b,c),c)\n// default huffman tables\n#define stbiw__zlib_huff1(n)  stbiw__zlib_huffa(0x30 + (n), 8)\n#define stbiw__zlib_huff2(n)  stbiw__zlib_huffa(0x190 + (n)-144, 9)\n#define stbiw__zlib_huff3(n)  stbiw__zlib_huffa(0 + (n)-256,7)\n#define stbiw__zlib_huff4(n)  stbiw__zlib_huffa(0xc0 + (n)-280,8)\n#define stbiw__zlib_huff(n)  ((n) <= 143 ? stbiw__zlib_huff1(n) : (n) <= 255 ? stbiw__zlib_huff2(n) : (n) <= 279 ? stbiw__zlib_huff3(n) : stbiw__zlib_huff4(n))\n#define stbiw__zlib_huffb(n) ((n) <= 143 ? stbiw__zlib_huff1(n) : stbiw__zlib_huff2(n))\n\n#define stbiw__ZHASH   16384\n\n#endif // STBIW_ZLIB_COMPRESS\n\nSTBIWDEF unsigned char * stbi_zlib_compress(unsigned char *data, int data_len, int *out_len, int quality)\n{\n#ifdef STBIW_ZLIB_COMPRESS\n   // user provided a zlib compress implementation, use that\n   return STBIW_ZLIB_COMPRESS(data, data_len, out_len, quality);\n#else // use builtin\n   static unsigned short lengthc[] = { 3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258, 259 };\n   static unsigned char  lengtheb[]= { 0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4,  4,  5,  5,  5,  5,  0 };\n   static unsigned short distc[]   = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577, 32768 };\n   static unsigned char  disteb[]  = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 };\n   unsigned int bitbuf=0;\n   int i,j, bitcount=0;\n   unsigned char *out = NULL;\n   unsigned char ***hash_table = (unsigned char***) STBIW_MALLOC(stbiw__ZHASH * sizeof(unsigned char**));\n   if (hash_table == NULL)\n      return NULL;\n   if (quality < 5) quality = 5;\n\n   stbiw__sbpush(out, 0x78);   // DEFLATE 32K window\n   stbiw__sbpush(out, 0x5e);   // FLEVEL = 1\n   stbiw__zlib_add(1,1);  // BFINAL = 1\n   stbiw__zlib_add(1,2);  // BTYPE = 1 -- fixed huffman\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      hash_table[i] = NULL;\n\n   i=0;\n   while (i < data_len-3) {\n      // hash next 3 bytes of data to be compressed\n      int h = stbiw__zhash(data+i)&(stbiw__ZHASH-1), best=3;\n      unsigned char *bestloc = 0;\n      unsigned char **hlist = hash_table[h];\n      int n = stbiw__sbcount(hlist);\n      for (j=0; j < n; ++j) {\n         if (hlist[j]-data > i-32768) { // if entry lies within window\n            int d = stbiw__zlib_countm(hlist[j], data+i, data_len-i);\n            if (d >= best) { best=d; bestloc=hlist[j]; }\n         }\n      }\n      // when hash table entry is too long, delete half the entries\n      if (hash_table[h] && stbiw__sbn(hash_table[h]) == 2*quality) {\n         STBIW_MEMMOVE(hash_table[h], hash_table[h]+quality, sizeof(hash_table[h][0])*quality);\n         stbiw__sbn(hash_table[h]) = quality;\n      }\n      stbiw__sbpush(hash_table[h],data+i);\n\n      if (bestloc) {\n         // \"lazy matching\" - check match at *next* byte, and if it's better, do cur byte as literal\n         h = stbiw__zhash(data+i+1)&(stbiw__ZHASH-1);\n         hlist = hash_table[h];\n         n = stbiw__sbcount(hlist);\n         for (j=0; j < n; ++j) {\n            if (hlist[j]-data > i-32767) {\n               int e = stbiw__zlib_countm(hlist[j], data+i+1, data_len-i-1);\n               if (e > best) { // if next match is better, bail on current match\n                  bestloc = NULL;\n                  break;\n               }\n            }\n         }\n      }\n\n      if (bestloc) {\n         int d = (int) (data+i - bestloc); // distance back\n         STBIW_ASSERT(d <= 32767 && best <= 258);\n         for (j=0; best > lengthc[j+1]-1; ++j);\n         stbiw__zlib_huff(j+257);\n         if (lengtheb[j]) stbiw__zlib_add(best - lengthc[j], lengtheb[j]);\n         for (j=0; d > distc[j+1]-1; ++j);\n         stbiw__zlib_add(stbiw__zlib_bitrev(j,5),5);\n         if (disteb[j]) stbiw__zlib_add(d - distc[j], disteb[j]);\n         i += best;\n      } else {\n         stbiw__zlib_huffb(data[i]);\n         ++i;\n      }\n   }\n   // write out final bytes\n   for (;i < data_len; ++i)\n      stbiw__zlib_huffb(data[i]);\n   stbiw__zlib_huff(256); // end of block\n   // pad with 0 bits to byte boundary\n   while (bitcount)\n      stbiw__zlib_add(0,1);\n\n   for (i=0; i < stbiw__ZHASH; ++i)\n      (void) stbiw__sbfree(hash_table[i]);\n   STBIW_FREE(hash_table);\n\n   // store uncompressed instead if compression was worse\n   if (stbiw__sbn(out) > data_len + 2 + ((data_len+32766)/32767)*5) {\n      stbiw__sbn(out) = 2;  // truncate to DEFLATE 32K window and FLEVEL = 1\n      for (j = 0; j < data_len;) {\n         int blocklen = data_len - j;\n         if (blocklen > 32767) blocklen = 32767;\n         stbiw__sbpush(out, data_len - j == blocklen); // BFINAL = ?, BTYPE = 0 -- no compression\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen)); // LEN\n         stbiw__sbpush(out, STBIW_UCHAR(blocklen >> 8));\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen)); // NLEN\n         stbiw__sbpush(out, STBIW_UCHAR(~blocklen >> 8));\n         memcpy(out+stbiw__sbn(out), data+j, blocklen);\n         stbiw__sbn(out) += blocklen;\n         j += blocklen;\n      }\n   }\n\n   {\n      // compute adler32 on input\n      unsigned int s1=1, s2=0;\n      int blocklen = (int) (data_len % 5552);\n      j=0;\n      while (j < data_len) {\n         for (i=0; i < blocklen; ++i) { s1 += data[j+i]; s2 += s1; }\n         s1 %= 65521; s2 %= 65521;\n         j += blocklen;\n         blocklen = 5552;\n      }\n      stbiw__sbpush(out, STBIW_UCHAR(s2 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s2));\n      stbiw__sbpush(out, STBIW_UCHAR(s1 >> 8));\n      stbiw__sbpush(out, STBIW_UCHAR(s1));\n   }\n   *out_len = stbiw__sbn(out);\n   // make returned pointer freeable\n   STBIW_MEMMOVE(stbiw__sbraw(out), out, *out_len);\n   return (unsigned char *) stbiw__sbraw(out);\n#endif // STBIW_ZLIB_COMPRESS\n}\n\nstatic unsigned int stbiw__crc32(unsigned char *buffer, int len)\n{\n#ifdef STBIW_CRC32\n    return STBIW_CRC32(buffer, len);\n#else\n   static unsigned int crc_table[256] =\n   {\n      0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,\n      0x0eDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,\n      0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,\n      0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,\n      0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,\n      0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,\n      0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,\n      0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,\n      0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,\n      0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,\n      0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,\n      0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,\n      0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,\n      0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,\n      0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,\n      0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,\n      0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,\n      0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,\n      0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,\n      0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,\n      0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,\n      0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,\n      0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,\n      0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,\n      0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,\n      0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,\n      0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,\n      0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,\n      0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,\n      0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,\n      0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,\n      0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D\n   };\n\n   unsigned int crc = ~0u;\n   int i;\n   for (i=0; i < len; ++i)\n      crc = (crc >> 8) ^ crc_table[buffer[i] ^ (crc & 0xff)];\n   return ~crc;\n#endif\n}\n\n#define stbiw__wpng4(o,a,b,c,d) ((o)[0]=STBIW_UCHAR(a),(o)[1]=STBIW_UCHAR(b),(o)[2]=STBIW_UCHAR(c),(o)[3]=STBIW_UCHAR(d),(o)+=4)\n#define stbiw__wp32(data,v) stbiw__wpng4(data, (v)>>24,(v)>>16,(v)>>8,(v));\n#define stbiw__wptag(data,s) stbiw__wpng4(data, s[0],s[1],s[2],s[3])\n\nstatic void stbiw__wpcrc(unsigned char **data, int len)\n{\n   unsigned int crc = stbiw__crc32(*data - len - 4, len+4);\n   stbiw__wp32(*data, crc);\n}\n\nstatic unsigned char stbiw__paeth(int a, int b, int c)\n{\n   int p = a + b - c, pa = abs(p-a), pb = abs(p-b), pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return STBIW_UCHAR(a);\n   if (pb <= pc) return STBIW_UCHAR(b);\n   return STBIW_UCHAR(c);\n}\n\n// @OPTIMIZE: provide an option that always forces left-predict or paeth predict\nstatic void stbiw__encode_png_line(unsigned char *pixels, int stride_bytes, int width, int height, int y, int n, int filter_type, signed char *line_buffer)\n{\n   static int mapping[] = { 0,1,2,3,4 };\n   static int firstmap[] = { 0,1,0,5,6 };\n   int *mymap = (y != 0) ? mapping : firstmap;\n   int i;\n   int type = mymap[filter_type];\n   unsigned char *z = pixels + stride_bytes * (stbi__flip_vertically_on_write ? height-1-y : y);\n   int signed_stride = stbi__flip_vertically_on_write ? -stride_bytes : stride_bytes;\n\n   if (type==0) {\n      memcpy(line_buffer, z, width*n);\n      return;\n   }\n\n   // first loop isn't optimized since it's just one pixel\n   for (i = 0; i < n; ++i) {\n      switch (type) {\n         case 1: line_buffer[i] = z[i]; break;\n         case 2: line_buffer[i] = z[i] - z[i-signed_stride]; break;\n         case 3: line_buffer[i] = z[i] - (z[i-signed_stride]>>1); break;\n         case 4: line_buffer[i] = (signed char) (z[i] - stbiw__paeth(0,z[i-signed_stride],0)); break;\n         case 5: line_buffer[i] = z[i]; break;\n         case 6: line_buffer[i] = z[i]; break;\n      }\n   }\n   switch (type) {\n      case 1: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-n]; break;\n      case 2: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - z[i-signed_stride]; break;\n      case 3: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - ((z[i-n] + z[i-signed_stride])>>1); break;\n      case 4: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], z[i-signed_stride], z[i-signed_stride-n]); break;\n      case 5: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - (z[i-n]>>1); break;\n      case 6: for (i=n; i < width*n; ++i) line_buffer[i] = z[i] - stbiw__paeth(z[i-n], 0,0); break;\n   }\n}\n\nSTBIWDEF unsigned char *stbi_write_png_to_mem(const unsigned char *pixels, int stride_bytes, int x, int y, int n, int *out_len)\n{\n   int force_filter = stbi_write_force_png_filter;\n   int ctype[5] = { -1, 0, 4, 2, 6 };\n   unsigned char sig[8] = { 137,80,78,71,13,10,26,10 };\n   unsigned char *out,*o, *filt, *zlib;\n   signed char *line_buffer;\n   int j,zlen;\n\n   if (stride_bytes == 0)\n      stride_bytes = x * n;\n\n   if (force_filter >= 5) {\n      force_filter = -1;\n   }\n\n   filt = (unsigned char *) STBIW_MALLOC((x*n+1) * y); if (!filt) return 0;\n   line_buffer = (signed char *) STBIW_MALLOC(x * n); if (!line_buffer) { STBIW_FREE(filt); return 0; }\n   for (j=0; j < y; ++j) {\n      int filter_type;\n      if (force_filter > -1) {\n         filter_type = force_filter;\n         stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, force_filter, line_buffer);\n      } else { // Estimate the best filter by running through all of them:\n         int best_filter = 0, best_filter_val = 0x7fffffff, est, i;\n         for (filter_type = 0; filter_type < 5; filter_type++) {\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, filter_type, line_buffer);\n\n            // Estimate the entropy of the line using this filter; the less, the better.\n            est = 0;\n            for (i = 0; i < x*n; ++i) {\n               est += abs((signed char) line_buffer[i]);\n            }\n            if (est < best_filter_val) {\n               best_filter_val = est;\n               best_filter = filter_type;\n            }\n         }\n         if (filter_type != best_filter) {  // If the last iteration already got us the best filter, don't redo it\n            stbiw__encode_png_line((unsigned char*)(pixels), stride_bytes, x, y, j, n, best_filter, line_buffer);\n            filter_type = best_filter;\n         }\n      }\n      // when we get here, filter_type contains the filter type, and line_buffer contains the data\n      filt[j*(x*n+1)] = (unsigned char) filter_type;\n      STBIW_MEMMOVE(filt+j*(x*n+1)+1, line_buffer, x*n);\n   }\n   STBIW_FREE(line_buffer);\n   zlib = stbi_zlib_compress(filt, y*( x*n+1), &zlen, stbi_write_png_compression_level);\n   STBIW_FREE(filt);\n   if (!zlib) return 0;\n\n   // each tag requires 12 bytes of overhead\n   out = (unsigned char *) STBIW_MALLOC(8 + 12+13 + 12+zlen + 12);\n   if (!out) return 0;\n   *out_len = 8 + 12+13 + 12+zlen + 12;\n\n   o=out;\n   STBIW_MEMMOVE(o,sig,8); o+= 8;\n   stbiw__wp32(o, 13); // header length\n   stbiw__wptag(o, \"IHDR\");\n   stbiw__wp32(o, x);\n   stbiw__wp32(o, y);\n   *o++ = 8;\n   *o++ = STBIW_UCHAR(ctype[n]);\n   *o++ = 0;\n   *o++ = 0;\n   *o++ = 0;\n   stbiw__wpcrc(&o,13);\n\n   stbiw__wp32(o, zlen);\n   stbiw__wptag(o, \"IDAT\");\n   STBIW_MEMMOVE(o, zlib, zlen);\n   o += zlen;\n   STBIW_FREE(zlib);\n   stbiw__wpcrc(&o, zlen);\n\n   stbiw__wp32(o,0);\n   stbiw__wptag(o, \"IEND\");\n   stbiw__wpcrc(&o,0);\n\n   STBIW_ASSERT(o == out + *out_len);\n\n   return out;\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_png(char const *filename, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   FILE *f;\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n\n   f = stbiw__fopen(filename, \"wb\");\n   if (!f) { STBIW_FREE(png); return 0; }\n   fwrite(png, 1, len, f);\n   fclose(f);\n   STBIW_FREE(png);\n   return 1;\n}\n#endif\n\nSTBIWDEF int stbi_write_png_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int stride_bytes)\n{\n   int len;\n   unsigned char *png = stbi_write_png_to_mem((const unsigned char *) data, stride_bytes, x, y, comp, &len);\n   if (png == NULL) return 0;\n   func(context, png, len);\n   STBIW_FREE(png);\n   return 1;\n}\n\n\n/* ***************************************************************************\n *\n * JPEG writer\n *\n * This is based on Jon Olick's jo_jpeg.cpp:\n * public domain Simple, Minimalistic JPEG writer - http://www.jonolick.com/code.html\n */\n\nstatic const unsigned char stbiw__jpg_ZigZag[] = { 0,1,5,6,14,15,27,28,2,4,7,13,16,26,29,42,3,8,12,17,25,30,41,43,9,11,18,\n      24,31,40,44,53,10,19,23,32,39,45,52,54,20,22,33,38,46,51,55,60,21,34,37,47,50,56,59,61,35,36,48,49,57,58,62,63 };\n\nstatic void stbiw__jpg_writeBits(stbi__write_context *s, int *bitBufP, int *bitCntP, const unsigned short *bs) {\n   int bitBuf = *bitBufP, bitCnt = *bitCntP;\n   bitCnt += bs[1];\n   bitBuf |= bs[0] << (24 - bitCnt);\n   while(bitCnt >= 8) {\n      unsigned char c = (bitBuf >> 16) & 255;\n      stbiw__putc(s, c);\n      if(c == 255) {\n         stbiw__putc(s, 0);\n      }\n      bitBuf <<= 8;\n      bitCnt -= 8;\n   }\n   *bitBufP = bitBuf;\n   *bitCntP = bitCnt;\n}\n\nstatic void stbiw__jpg_DCT(float *d0p, float *d1p, float *d2p, float *d3p, float *d4p, float *d5p, float *d6p, float *d7p) {\n   float d0 = *d0p, d1 = *d1p, d2 = *d2p, d3 = *d3p, d4 = *d4p, d5 = *d5p, d6 = *d6p, d7 = *d7p;\n   float z1, z2, z3, z4, z5, z11, z13;\n\n   float tmp0 = d0 + d7;\n   float tmp7 = d0 - d7;\n   float tmp1 = d1 + d6;\n   float tmp6 = d1 - d6;\n   float tmp2 = d2 + d5;\n   float tmp5 = d2 - d5;\n   float tmp3 = d3 + d4;\n   float tmp4 = d3 - d4;\n\n   // Even part\n   float tmp10 = tmp0 + tmp3;   // phase 2\n   float tmp13 = tmp0 - tmp3;\n   float tmp11 = tmp1 + tmp2;\n   float tmp12 = tmp1 - tmp2;\n\n   d0 = tmp10 + tmp11;       // phase 3\n   d4 = tmp10 - tmp11;\n\n   z1 = (tmp12 + tmp13) * 0.707106781f; // c4\n   d2 = tmp13 + z1;       // phase 5\n   d6 = tmp13 - z1;\n\n   // Odd part\n   tmp10 = tmp4 + tmp5;       // phase 2\n   tmp11 = tmp5 + tmp6;\n   tmp12 = tmp6 + tmp7;\n\n   // The rotator is modified from fig 4-8 to avoid extra negations.\n   z5 = (tmp10 - tmp12) * 0.382683433f; // c6\n   z2 = tmp10 * 0.541196100f + z5; // c2-c6\n   z4 = tmp12 * 1.306562965f + z5; // c2+c6\n   z3 = tmp11 * 0.707106781f; // c4\n\n   z11 = tmp7 + z3;      // phase 5\n   z13 = tmp7 - z3;\n\n   *d5p = z13 + z2;         // phase 6\n   *d3p = z13 - z2;\n   *d1p = z11 + z4;\n   *d7p = z11 - z4;\n\n   *d0p = d0;  *d2p = d2;  *d4p = d4;  *d6p = d6;\n}\n\nstatic void stbiw__jpg_calcBits(int val, unsigned short bits[2]) {\n   int tmp1 = val < 0 ? -val : val;\n   val = val < 0 ? val-1 : val;\n   bits[1] = 1;\n   while(tmp1 >>= 1) {\n      ++bits[1];\n   }\n   bits[0] = val & ((1<<bits[1])-1);\n}\n\nstatic int stbiw__jpg_processDU(stbi__write_context *s, int *bitBuf, int *bitCnt, float *CDU, int du_stride, float *fdtbl, int DC, const unsigned short HTDC[256][2], const unsigned short HTAC[256][2]) {\n   const unsigned short EOB[2] = { HTAC[0x00][0], HTAC[0x00][1] };\n   const unsigned short M16zeroes[2] = { HTAC[0xF0][0], HTAC[0xF0][1] };\n   int dataOff, i, j, n, diff, end0pos, x, y;\n   int DU[64];\n\n   // DCT rows\n   for(dataOff=0, n=du_stride*8; dataOff<n; dataOff+=du_stride) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+1], &CDU[dataOff+2], &CDU[dataOff+3], &CDU[dataOff+4], &CDU[dataOff+5], &CDU[dataOff+6], &CDU[dataOff+7]);\n   }\n   // DCT columns\n   for(dataOff=0; dataOff<8; ++dataOff) {\n      stbiw__jpg_DCT(&CDU[dataOff], &CDU[dataOff+du_stride], &CDU[dataOff+du_stride*2], &CDU[dataOff+du_stride*3], &CDU[dataOff+du_stride*4],\n                     &CDU[dataOff+du_stride*5], &CDU[dataOff+du_stride*6], &CDU[dataOff+du_stride*7]);\n   }\n   // Quantize/descale/zigzag the coefficients\n   for(y = 0, j=0; y < 8; ++y) {\n      for(x = 0; x < 8; ++x,++j) {\n         float v;\n         i = y*du_stride+x;\n         v = CDU[i]*fdtbl[j];\n         // DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? ceilf(v - 0.5f) : floorf(v + 0.5f));\n         // ceilf() and floorf() are C99, not C89, but I /think/ they're not needed here anyway?\n         DU[stbiw__jpg_ZigZag[j]] = (int)(v < 0 ? v - 0.5f : v + 0.5f);\n      }\n   }\n\n   // Encode DC\n   diff = DU[0] - DC;\n   if (diff == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[0]);\n   } else {\n      unsigned short bits[2];\n      stbiw__jpg_calcBits(diff, bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTDC[bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   // Encode ACs\n   end0pos = 63;\n   for(; (end0pos>0)&&(DU[end0pos]==0); --end0pos) {\n   }\n   // end0pos = first element in reverse order !=0\n   if(end0pos == 0) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n      return DU[0];\n   }\n   for(i = 1; i <= end0pos; ++i) {\n      int startpos = i;\n      int nrzeroes;\n      unsigned short bits[2];\n      for (; DU[i]==0 && i<=end0pos; ++i) {\n      }\n      nrzeroes = i-startpos;\n      if ( nrzeroes >= 16 ) {\n         int lng = nrzeroes>>4;\n         int nrmarker;\n         for (nrmarker=1; nrmarker <= lng; ++nrmarker)\n            stbiw__jpg_writeBits(s, bitBuf, bitCnt, M16zeroes);\n         nrzeroes &= 15;\n      }\n      stbiw__jpg_calcBits(DU[i], bits);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, HTAC[(nrzeroes<<4)+bits[1]]);\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, bits);\n   }\n   if(end0pos != 63) {\n      stbiw__jpg_writeBits(s, bitBuf, bitCnt, EOB);\n   }\n   return DU[0];\n}\n\nstatic int stbi_write_jpg_core(stbi__write_context *s, int width, int height, int comp, const void* data, int quality) {\n   // Constants that don't pollute global namespace\n   static const unsigned char std_dc_luminance_nrcodes[] = {0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0};\n   static const unsigned char std_dc_luminance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_luminance_nrcodes[] = {0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d};\n   static const unsigned char std_ac_luminance_values[] = {\n      0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\n      0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\n      0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\n      0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\n      0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\n      0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\n      0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   static const unsigned char std_dc_chrominance_nrcodes[] = {0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0};\n   static const unsigned char std_dc_chrominance_values[] = {0,1,2,3,4,5,6,7,8,9,10,11};\n   static const unsigned char std_ac_chrominance_nrcodes[] = {0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77};\n   static const unsigned char std_ac_chrominance_values[] = {\n      0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\n      0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\n      0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\n      0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\n      0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\n      0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\n      0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa\n   };\n   // Huffman tables\n   static const unsigned short YDC_HT[256][2] = { {0,2},{2,3},{3,3},{4,3},{5,3},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9}};\n   static const unsigned short UVDC_HT[256][2] = { {0,2},{1,2},{2,2},{6,3},{14,4},{30,5},{62,6},{126,7},{254,8},{510,9},{1022,10},{2046,11}};\n   static const unsigned short YAC_HT[256][2] = {\n      {10,4},{0,2},{1,2},{4,3},{11,4},{26,5},{120,7},{248,8},{1014,10},{65410,16},{65411,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {12,4},{27,5},{121,7},{502,9},{2038,11},{65412,16},{65413,16},{65414,16},{65415,16},{65416,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {28,5},{249,8},{1015,10},{4084,12},{65417,16},{65418,16},{65419,16},{65420,16},{65421,16},{65422,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{503,9},{4085,12},{65423,16},{65424,16},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1016,10},{65430,16},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2039,11},{65438,16},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {123,7},{4086,12},{65446,16},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {250,8},{4087,12},{65454,16},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{32704,15},{65462,16},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65470,16},{65471,16},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65479,16},{65480,16},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1017,10},{65488,16},{65489,16},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{65497,16},{65498,16},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2040,11},{65506,16},{65507,16},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {65515,16},{65516,16},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65525,16},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const unsigned short UVAC_HT[256][2] = {\n      {0,2},{1,2},{4,3},{10,4},{24,5},{25,5},{56,6},{120,7},{500,9},{1014,10},{4084,12},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {11,4},{57,6},{246,8},{501,9},{2038,11},{4085,12},{65416,16},{65417,16},{65418,16},{65419,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {26,5},{247,8},{1015,10},{4086,12},{32706,15},{65420,16},{65421,16},{65422,16},{65423,16},{65424,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {27,5},{248,8},{1016,10},{4087,12},{65425,16},{65426,16},{65427,16},{65428,16},{65429,16},{65430,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {58,6},{502,9},{65431,16},{65432,16},{65433,16},{65434,16},{65435,16},{65436,16},{65437,16},{65438,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {59,6},{1017,10},{65439,16},{65440,16},{65441,16},{65442,16},{65443,16},{65444,16},{65445,16},{65446,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {121,7},{2039,11},{65447,16},{65448,16},{65449,16},{65450,16},{65451,16},{65452,16},{65453,16},{65454,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {122,7},{2040,11},{65455,16},{65456,16},{65457,16},{65458,16},{65459,16},{65460,16},{65461,16},{65462,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {249,8},{65463,16},{65464,16},{65465,16},{65466,16},{65467,16},{65468,16},{65469,16},{65470,16},{65471,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {503,9},{65472,16},{65473,16},{65474,16},{65475,16},{65476,16},{65477,16},{65478,16},{65479,16},{65480,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {504,9},{65481,16},{65482,16},{65483,16},{65484,16},{65485,16},{65486,16},{65487,16},{65488,16},{65489,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {505,9},{65490,16},{65491,16},{65492,16},{65493,16},{65494,16},{65495,16},{65496,16},{65497,16},{65498,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {506,9},{65499,16},{65500,16},{65501,16},{65502,16},{65503,16},{65504,16},{65505,16},{65506,16},{65507,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {2041,11},{65508,16},{65509,16},{65510,16},{65511,16},{65512,16},{65513,16},{65514,16},{65515,16},{65516,16},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {16352,14},{65517,16},{65518,16},{65519,16},{65520,16},{65521,16},{65522,16},{65523,16},{65524,16},{65525,16},{0,0},{0,0},{0,0},{0,0},{0,0},\n      {1018,10},{32707,15},{65526,16},{65527,16},{65528,16},{65529,16},{65530,16},{65531,16},{65532,16},{65533,16},{65534,16},{0,0},{0,0},{0,0},{0,0},{0,0}\n   };\n   static const int YQT[] = {16,11,10,16,24,40,51,61,12,12,14,19,26,58,60,55,14,13,16,24,40,57,69,56,14,17,22,29,51,87,80,62,18,22,\n                             37,56,68,109,103,77,24,35,55,64,81,104,113,92,49,64,78,87,103,121,120,101,72,92,95,98,112,100,103,99};\n   static const int UVQT[] = {17,18,24,47,99,99,99,99,18,21,26,66,99,99,99,99,24,26,56,99,99,99,99,99,47,66,99,99,99,99,99,99,\n                              99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99};\n   static const float aasf[] = { 1.0f * 2.828427125f, 1.387039845f * 2.828427125f, 1.306562965f * 2.828427125f, 1.175875602f * 2.828427125f,\n                                 1.0f * 2.828427125f, 0.785694958f * 2.828427125f, 0.541196100f * 2.828427125f, 0.275899379f * 2.828427125f };\n\n   int row, col, i, k, subsample;\n   float fdtbl_Y[64], fdtbl_UV[64];\n   unsigned char YTable[64], UVTable[64];\n\n   if(!data || !width || !height || comp > 4 || comp < 1) {\n      return 0;\n   }\n\n   quality = quality ? quality : 90;\n   subsample = quality <= 90 ? 1 : 0;\n   quality = quality < 1 ? 1 : quality > 100 ? 100 : quality;\n   quality = quality < 50 ? 5000 / quality : 200 - quality * 2;\n\n   for(i = 0; i < 64; ++i) {\n      int uvti, yti = (YQT[i]*quality+50)/100;\n      YTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (yti < 1 ? 1 : yti > 255 ? 255 : yti);\n      uvti = (UVQT[i]*quality+50)/100;\n      UVTable[stbiw__jpg_ZigZag[i]] = (unsigned char) (uvti < 1 ? 1 : uvti > 255 ? 255 : uvti);\n   }\n\n   for(row = 0, k = 0; row < 8; ++row) {\n      for(col = 0; col < 8; ++col, ++k) {\n         fdtbl_Y[k]  = 1 / (YTable [stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n         fdtbl_UV[k] = 1 / (UVTable[stbiw__jpg_ZigZag[k]] * aasf[row] * aasf[col]);\n      }\n   }\n\n   // Write Headers\n   {\n      static const unsigned char head0[] = { 0xFF,0xD8,0xFF,0xE0,0,0x10,'J','F','I','F',0,1,1,0,0,1,0,1,0,0,0xFF,0xDB,0,0x84,0 };\n      static const unsigned char head2[] = { 0xFF,0xDA,0,0xC,3,1,0,2,0x11,3,0x11,0,0x3F,0 };\n      const unsigned char head1[] = { 0xFF,0xC0,0,0x11,8,(unsigned char)(height>>8),STBIW_UCHAR(height),(unsigned char)(width>>8),STBIW_UCHAR(width),\n                                      3,1,(unsigned char)(subsample?0x22:0x11),0,2,0x11,1,3,0x11,1,0xFF,0xC4,0x01,0xA2,0 };\n      s->func(s->context, (void*)head0, sizeof(head0));\n      s->func(s->context, (void*)YTable, sizeof(YTable));\n      stbiw__putc(s, 1);\n      s->func(s->context, UVTable, sizeof(UVTable));\n      s->func(s->context, (void*)head1, sizeof(head1));\n      s->func(s->context, (void*)(std_dc_luminance_nrcodes+1), sizeof(std_dc_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_luminance_values, sizeof(std_dc_luminance_values));\n      stbiw__putc(s, 0x10); // HTYACinfo\n      s->func(s->context, (void*)(std_ac_luminance_nrcodes+1), sizeof(std_ac_luminance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_luminance_values, sizeof(std_ac_luminance_values));\n      stbiw__putc(s, 1); // HTUDCinfo\n      s->func(s->context, (void*)(std_dc_chrominance_nrcodes+1), sizeof(std_dc_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_dc_chrominance_values, sizeof(std_dc_chrominance_values));\n      stbiw__putc(s, 0x11); // HTUACinfo\n      s->func(s->context, (void*)(std_ac_chrominance_nrcodes+1), sizeof(std_ac_chrominance_nrcodes)-1);\n      s->func(s->context, (void*)std_ac_chrominance_values, sizeof(std_ac_chrominance_values));\n      s->func(s->context, (void*)head2, sizeof(head2));\n   }\n\n   // Encode 8x8 macroblocks\n   {\n      static const unsigned short fillBits[] = {0x7F, 7};\n      int DCY=0, DCU=0, DCV=0;\n      int bitBuf=0, bitCnt=0;\n      // comp == 2 is grey+alpha (alpha is ignored)\n      int ofsG = comp > 2 ? 1 : 0, ofsB = comp > 2 ? 2 : 0;\n      const unsigned char *dataR = (const unsigned char *)data;\n      const unsigned char *dataG = dataR + ofsG;\n      const unsigned char *dataB = dataR + ofsB;\n      int x, y, pos;\n      if(subsample) {\n         for(y = 0; y < height; y += 16) {\n            for(x = 0; x < width; x += 16) {\n               float Y[256], U[256], V[256];\n               for(row = y, pos = 0; row < y+16; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+16; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+0,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+8,   16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+128, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y+136, 16, fdtbl_Y, DCY, YDC_HT, YAC_HT);\n\n               // subsample U,V\n               {\n                  float subU[64], subV[64];\n                  int yy, xx;\n                  for(yy = 0, pos = 0; yy < 8; ++yy) {\n                     for(xx = 0; xx < 8; ++xx, ++pos) {\n                        int j = yy*32+xx*2;\n                        subU[pos] = (U[j+0] + U[j+1] + U[j+16] + U[j+17]) * 0.25f;\n                        subV[pos] = (V[j+0] + V[j+1] + V[j+16] + V[j+17]) * 0.25f;\n                     }\n                  }\n                  DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subU, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n                  DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, subV, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n               }\n            }\n         }\n      } else {\n         for(y = 0; y < height; y += 8) {\n            for(x = 0; x < width; x += 8) {\n               float Y[64], U[64], V[64];\n               for(row = y, pos = 0; row < y+8; ++row) {\n                  // row >= height => use last input row\n                  int clamped_row = (row < height) ? row : height - 1;\n                  int base_p = (stbi__flip_vertically_on_write ? (height-1-clamped_row) : clamped_row)*width*comp;\n                  for(col = x; col < x+8; ++col, ++pos) {\n                     // if col >= width => use pixel from last input column\n                     int p = base_p + ((col < width) ? col : (width-1))*comp;\n                     float r = dataR[p], g = dataG[p], b = dataB[p];\n                     Y[pos]= +0.29900f*r + 0.58700f*g + 0.11400f*b - 128;\n                     U[pos]= -0.16874f*r - 0.33126f*g + 0.50000f*b;\n                     V[pos]= +0.50000f*r - 0.41869f*g - 0.08131f*b;\n                  }\n               }\n\n               DCY = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, Y, 8, fdtbl_Y,  DCY, YDC_HT, YAC_HT);\n               DCU = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, U, 8, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\n               DCV = stbiw__jpg_processDU(s, &bitBuf, &bitCnt, V, 8, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\n            }\n         }\n      }\n\n      // Do the bit alignment of the EOI marker\n      stbiw__jpg_writeBits(s, &bitBuf, &bitCnt, fillBits);\n   }\n\n   // EOI\n   stbiw__putc(s, 0xFF);\n   stbiw__putc(s, 0xD9);\n\n   return 1;\n}\n\nSTBIWDEF int stbi_write_jpg_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_jpg_core(&s, x, y, comp, (void *) data, quality);\n}\n\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_jpg(char const *filename, int x, int y, int comp, const void *data, int quality)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_jpg_core(&s, x, y, comp, data, quality);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n\n#ifndef STBI_WRITE_NO_QOI\n#include \"stbi_qoi_write.h\"\n#endif\n\n#endif // STB_IMAGE_WRITE_IMPLEMENTATION\n\n/* Revision history\n      1.16  (2021-07-11)\n             make Deflate code emit uncompressed blocks when it would otherwise expand\n             support writing BMPs with alpha channel\n      1.15  (2020-07-13) unknown\n      1.14  (2020-02-02) updated JPEG writer to downsample chroma channels\n      1.13\n      1.12\n      1.11  (2019-08-11)\n\n      1.10  (2019-02-07)\n             support utf8 filenames in Windows; fix warnings and platform ifdefs\n      1.09  (2018-02-11)\n             fix typo in zlib quality API, improve STB_I_W_STATIC in C++\n      1.08  (2018-01-29)\n             add stbi__flip_vertically_on_write, external zlib, zlib quality, choose PNG filter\n      1.07  (2017-07-24)\n             doc fix\n      1.06 (2017-07-23)\n             writing JPEG (using Jon Olick's code)\n      1.05   ???\n      1.04 (2017-03-03)\n             monochrome BMP expansion\n      1.03   ???\n      1.02 (2016-04-02)\n             avoid allocating large structures on the stack\n      1.01 (2016-01-16)\n             STBIW_REALLOC_SIZED: support allocators with no realloc support\n             avoid race-condition in crc initialization\n             minor compile issues\n      1.00 (2015-09-14)\n             installable file IO function\n      0.99 (2015-09-13)\n             warning fixes; TGA rle support\n      0.98 (2015-04-08)\n             added STBIW_MALLOC, STBIW_ASSERT etc\n      0.97 (2015-01-18)\n             fixed HDR asserts, rewrote HDR rle logic\n      0.96 (2015-01-17)\n             add HDR output\n             fix monochrome BMP\n      0.95 (2014-08-17)\n             add monochrome TGA output\n      0.94 (2014-05-31)\n             rename private functions to avoid conflicts with stb_image.h\n      0.93 (2014-05-27)\n             warning fixes\n      0.92 (2010-08-01)\n             casts to unsigned char to fix warnings\n      0.91 (2010-07-17)\n             first public release\n      0.90   first internal release\n*/\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "lib/SOIL2/stbi_DDS.h",
    "content": "/*\n\tadding DDS loading support to stbi\n*/\n\n#ifndef HEADER_STB_IMAGE_DDS_AUGMENTATION\n#define HEADER_STB_IMAGE_DDS_AUGMENTATION\n\n/*\tis it a DDS file? */\nextern int      stbi__dds_test_memory      (stbi_uc const *buffer, int len);\nextern int      stbi__dds_test_callbacks   (stbi_io_callbacks const *clbk, void *user);\n\nextern void    *stbi__dds_load_from_path   (const char *filename,           int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__dds_test_filename    (char const *filename);\nextern int      stbi__dds_test_file        (FILE *f);\nextern void    *stbi__dds_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp);\n#endif\n\nextern int      stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed);\nextern int      stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed);\n\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__dds_info_from_path   (char const *filename,     int *x, int *y, int *comp, int *iscompressed);\nextern int      stbi__dds_info_from_file   (FILE *f,                  int *x, int *y, int *comp, int *iscompressed);\n#endif\n\n/*\n//\n////   end header file   /////////////////////////////////////////////////////*/\n#endif /* HEADER_STB_IMAGE_DDS_AUGMENTATION */\n"
  },
  {
    "path": "lib/SOIL2/stbi_DDS_c.h",
    "content": "\n///\tDDS file support, does decoding, _not_ direct uploading\n///\t(use SOIL for that ;-)\n\n#include \"image_DXT.h\"\n\nstatic int stbi__dds_test(stbi__context *s)\n{\n\t//\tcheck the magic number\n\tif (stbi__get8(s) != 'D') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != 'D') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != 'S') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != ' ') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\t//\tcheck header size\n\tif (stbi__get32le(s) != 124) {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\t// Also rewind because the loader needs to read the header\n\tstbi__rewind(s);\n\n\treturn 1;\n}\n#ifndef STBI_NO_STDIO\n\nint      stbi__dds_test_filename        \t\t(char const *filename)\n{\n   int r;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   r = stbi__dds_test_file(f);\n   fclose(f);\n   return r;\n}\n\nint      stbi__dds_test_file        (FILE *f)\n{\n   stbi__context s;\n   int r,n = ftell(f);\n   stbi__start_file(&s,f);\n   r = stbi__dds_test(&s);\n   fseek(f,n,SEEK_SET);\n   return r;\n}\n#endif\n\nint      stbi__dds_test_memory      (stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__dds_test(&s);\n}\n\nint      stbi__dds_test_callbacks      (stbi_io_callbacks const *clbk, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__dds_test(&s);\n}\n\n//\thelper functions\nint stbi_convert_bit_range( int c, int from_bits, int to_bits )\n{\n\tint b = (1 << (from_bits - 1)) + c * ((1 << to_bits) - 1);\n\treturn (b + (b >> from_bits)) >> from_bits;\n}\nvoid stbi_rgb_888_from_565( unsigned int c, int *r, int *g, int *b )\n{\n\t*r = stbi_convert_bit_range( (c >> 11) & 31, 5, 8 );\n\t*g = stbi_convert_bit_range( (c >> 05) & 63, 6, 8 );\n\t*b = stbi_convert_bit_range( (c >> 00) & 31, 5, 8 );\n}\nvoid stbi_decode_DXT1_block(\n\t\t\tunsigned char uncompressed[16*4],\n\t\t\tunsigned char compressed[8] )\n{\n\tint next_bit = 4*8;\n\tint i, r, g, b;\n\tint c0, c1;\n\tunsigned char decode_colors[4*4];\n\t//\tfind the 2 primary colors\n\tc0 = compressed[0] + (compressed[1] << 8);\n\tc1 = compressed[2] + (compressed[3] << 8);\n\tstbi_rgb_888_from_565( c0, &r, &g, &b );\n\tdecode_colors[0] = r;\n\tdecode_colors[1] = g;\n\tdecode_colors[2] = b;\n\tdecode_colors[3] = 255;\n\tstbi_rgb_888_from_565( c1, &r, &g, &b );\n\tdecode_colors[4] = r;\n\tdecode_colors[5] = g;\n\tdecode_colors[6] = b;\n\tdecode_colors[7] = 255;\n\tif( c0 > c1 )\n\t{\n\t\t//\tno alpha, 2 interpolated colors\n\t\tdecode_colors[8] = (2*decode_colors[0] + decode_colors[4]) / 3;\n\t\tdecode_colors[9] = (2*decode_colors[1] + decode_colors[5]) / 3;\n\t\tdecode_colors[10] = (2*decode_colors[2] + decode_colors[6]) / 3;\n\t\tdecode_colors[11] = 255;\n\t\tdecode_colors[12] = (decode_colors[0] + 2*decode_colors[4]) / 3;\n\t\tdecode_colors[13] = (decode_colors[1] + 2*decode_colors[5]) / 3;\n\t\tdecode_colors[14] = (decode_colors[2] + 2*decode_colors[6]) / 3;\n\t\tdecode_colors[15] = 255;\n\t} else\n\t{\n\t\t//\t1 interpolated color, alpha\n\t\tdecode_colors[8] = (decode_colors[0] + decode_colors[4]) / 2;\n\t\tdecode_colors[9] = (decode_colors[1] + decode_colors[5]) / 2;\n\t\tdecode_colors[10] = (decode_colors[2] + decode_colors[6]) / 2;\n\t\tdecode_colors[11] = 255;\n\t\tdecode_colors[12] = 0;\n\t\tdecode_colors[13] = 0;\n\t\tdecode_colors[14] = 0;\n\t\tdecode_colors[15] = 0;\n\t}\n\t//\tdecode the block\n\tfor( i = 0; i < 16*4; i += 4 )\n\t{\n\t\tint idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 4;\n\t\tnext_bit += 2;\n\t\tuncompressed[i+0] = decode_colors[idx+0];\n\t\tuncompressed[i+1] = decode_colors[idx+1];\n\t\tuncompressed[i+2] = decode_colors[idx+2];\n\t\tuncompressed[i+3] = decode_colors[idx+3];\n\t}\n\t//\tdone\n}\nvoid stbi_decode_DXT23_alpha_block(\n\t\t\tunsigned char uncompressed[16*4],\n\t\t\tunsigned char compressed[8] )\n{\n\tint i, next_bit = 0;\n\t//\teach alpha value gets 4 bits\n\tfor( i = 3; i < 16*4; i += 4 )\n\t{\n\t\tuncompressed[i] = stbi_convert_bit_range(\n\t\t\t\t(compressed[next_bit>>3] >> (next_bit&7)) & 15,\n\t\t\t\t4, 8 );\n\t\tnext_bit += 4;\n\t}\n}\nvoid stbi_decode_DXT45_alpha_block(\n\t\t\tunsigned char uncompressed[16*4],\n\t\t\tunsigned char compressed[8] )\n{\n\tint i, next_bit = 8*2;\n\tunsigned char decode_alpha[8];\n\t//\teach alpha value gets 3 bits, and the 1st 2 bytes are the range\n\tdecode_alpha[0] = compressed[0];\n\tdecode_alpha[1] = compressed[1];\n\tif( decode_alpha[0] > decode_alpha[1] )\n\t{\n\t\t//\t6 step intermediate\n\t\tdecode_alpha[2] = (6*decode_alpha[0] + 1*decode_alpha[1]) / 7;\n\t\tdecode_alpha[3] = (5*decode_alpha[0] + 2*decode_alpha[1]) / 7;\n\t\tdecode_alpha[4] = (4*decode_alpha[0] + 3*decode_alpha[1]) / 7;\n\t\tdecode_alpha[5] = (3*decode_alpha[0] + 4*decode_alpha[1]) / 7;\n\t\tdecode_alpha[6] = (2*decode_alpha[0] + 5*decode_alpha[1]) / 7;\n\t\tdecode_alpha[7] = (1*decode_alpha[0] + 6*decode_alpha[1]) / 7;\n\t} else\n\t{\n\t\t//\t4 step intermediate, pluss full and none\n\t\tdecode_alpha[2] = (4*decode_alpha[0] + 1*decode_alpha[1]) / 5;\n\t\tdecode_alpha[3] = (3*decode_alpha[0] + 2*decode_alpha[1]) / 5;\n\t\tdecode_alpha[4] = (2*decode_alpha[0] + 3*decode_alpha[1]) / 5;\n\t\tdecode_alpha[5] = (1*decode_alpha[0] + 4*decode_alpha[1]) / 5;\n\t\tdecode_alpha[6] = 0;\n\t\tdecode_alpha[7] = 255;\n\t}\n\tfor( i = 3; i < 16*4; i += 4 )\n\t{\n\t\tint idx = 0, bit;\n\t\tbit = (compressed[next_bit>>3] >> (next_bit&7)) & 1;\n\t\tidx += bit << 0;\n\t\t++next_bit;\n\t\tbit = (compressed[next_bit>>3] >> (next_bit&7)) & 1;\n\t\tidx += bit << 1;\n\t\t++next_bit;\n\t\tbit = (compressed[next_bit>>3] >> (next_bit&7)) & 1;\n\t\tidx += bit << 2;\n\t\t++next_bit;\n\t\tuncompressed[i] = decode_alpha[idx & 7];\n\t}\n\t//\tdone\n}\nvoid stbi_decode_DXT_color_block(\n\t\t\tunsigned char uncompressed[16*4],\n\t\t\tunsigned char compressed[8] )\n{\n\tint next_bit = 4*8;\n\tint i, r, g, b;\n\tint c0, c1;\n\tunsigned char decode_colors[4*3];\n\t//\tfind the 2 primary colors\n\tc0 = compressed[0] + (compressed[1] << 8);\n\tc1 = compressed[2] + (compressed[3] << 8);\n\tstbi_rgb_888_from_565( c0, &r, &g, &b );\n\tdecode_colors[0] = r;\n\tdecode_colors[1] = g;\n\tdecode_colors[2] = b;\n\tstbi_rgb_888_from_565( c1, &r, &g, &b );\n\tdecode_colors[3] = r;\n\tdecode_colors[4] = g;\n\tdecode_colors[5] = b;\n\t//\tLike DXT1, but no choicees:\n\t//\tno alpha, 2 interpolated colors\n\tdecode_colors[6] = (2*decode_colors[0] + decode_colors[3]) / 3;\n\tdecode_colors[7] = (2*decode_colors[1] + decode_colors[4]) / 3;\n\tdecode_colors[8] = (2*decode_colors[2] + decode_colors[5]) / 3;\n\tdecode_colors[9] = (decode_colors[0] + 2*decode_colors[3]) / 3;\n\tdecode_colors[10] = (decode_colors[1] + 2*decode_colors[4]) / 3;\n\tdecode_colors[11] = (decode_colors[2] + 2*decode_colors[5]) / 3;\n\t//\tdecode the block\n\tfor( i = 0; i < 16*4; i += 4 )\n\t{\n\t\tint idx = ((compressed[next_bit>>3] >> (next_bit & 7)) & 3) * 3;\n\t\tnext_bit += 2;\n\t\tuncompressed[i+0] = decode_colors[idx+0];\n\t\tuncompressed[i+1] = decode_colors[idx+1];\n\t\tuncompressed[i+2] = decode_colors[idx+2];\n\t}\n\t//\tdone\n}\n\nstatic int stbi__dds_info( stbi__context *s, int *x, int *y, int *comp, int *iscompressed ) {\n\tint is_compressed,has_alpha;\n\tunsigned int flags;\n\tDDS_header header={0};\n\n\tif( sizeof( DDS_header ) != 128 )\n\t{\n\t\treturn 0;\n\t}\n\n\tstbi__getn( s, (stbi_uc*)(&header), 128 );\n\n\tif( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) {\n\t   stbi__rewind( s );\n\t   return 0;\n\t}\n\tif( header.dwSize != 124 ) {\n\t   stbi__rewind( s );\n\t   return 0;\n\t}\n\tflags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;\n\tif( (header.dwFlags & flags) != flags ) {\n\t   stbi__rewind( s );\n\t   return 0;\n\t}\n\tif( header.sPixelFormat.dwSize != 32 ) {\n\t   stbi__rewind( s );\n\t   return 0;\n\t}\n\tflags = DDPF_FOURCC | DDPF_RGB;\n\tif( (header.sPixelFormat.dwFlags & flags) == 0 ) {\n\t   stbi__rewind( s );\n\t   return 0;\n\t}\n\tif( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) {\n\t   stbi__rewind( s );\n\t   return 0;\n\t}\n\n\tis_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;\n\thas_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS;\n\n\t*x = header.dwWidth;\n\t*y = header.dwHeight;\n\n\tif ( !is_compressed ) {\n\t\t*comp = 3;\n\n\t\tif ( has_alpha )\n\t\t\t*comp = 4;\n\t}\n\telse\n\t\t*comp = 4;\n\n\tif ( iscompressed )\n\t\t*iscompressed = is_compressed;\n\n\treturn 1;\n}\n\nint stbi__dds_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed)\n{\n\tstbi__context s;\n\tstbi__start_mem(&s,buffer, len);\n\treturn stbi__dds_info( &s, x, y, comp, iscompressed );\n}\n\nint stbi__dds_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed)\n{\n\tstbi__context s;\n\tstbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n\treturn stbi__dds_info( &s, x, y, comp, iscompressed );\n}\n\n#ifndef STBI_NO_STDIO\nint stbi__dds_info_from_path(char const *filename,     int *x, int *y, int *comp, int *iscompressed)\n{\n   int res;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   res = stbi__dds_info_from_file( f, x, y, comp, iscompressed );\n   fclose(f);\n   return res;\n}\n\nint stbi__dds_info_from_file(FILE *f,                  int *x, int *y, int *comp, int *iscompressed)\n{\n   stbi__context s;\n   int res;\n   long n = ftell(f);\n   stbi__start_file(&s, f);\n   res = stbi__dds_info(&s, x, y, comp, iscompressed);\n   fseek(f, n, SEEK_SET);\n   return res;\n}\n#endif\n\nstatic void * stbi__dds_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n\t//\tall variables go up front\n\tstbi_uc *dds_data = NULL;\n\tstbi_uc block[16*4];\n\tstbi_uc compressed[8];\n\tint flags, DXT_family;\n\tint has_alpha, has_mipmap;\n\tint is_compressed, cubemap_faces;\n\tint block_pitch, num_blocks;\n\tDDS_header header={0};\n\tint i, sz, cf;\n\t//\tload the header\n\tif( sizeof( DDS_header ) != 128 )\n\t{\n\t\treturn NULL;\n\t}\n\tstbi__getn( s, (stbi_uc*)(&header), 128 );\n\t//\tand do some checking\n\tif( header.dwMagic != (('D' << 0) | ('D' << 8) | ('S' << 16) | (' ' << 24)) ) return NULL;\n\tif( header.dwSize != 124 ) return NULL;\n\tflags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT;\n\tif( (header.dwFlags & flags) != (unsigned int)flags ) return NULL;\n\t/*\tAccording to the MSDN spec, the dwFlags should contain\n\t\tDDSD_LINEARSIZE if it's compressed, or DDSD_PITCH if\n\t\tuncompressed.  Some DDS writers do not conform to the\n\t\tspec, so I need to make my reader more tolerant\t*/\n\tif( header.sPixelFormat.dwSize != 32 ) return NULL;\n\tflags = DDPF_FOURCC | DDPF_RGB;\n\tif( (header.sPixelFormat.dwFlags & flags) == 0 ) return NULL;\n\tif( (header.sCaps.dwCaps1 & DDSCAPS_TEXTURE) == 0 ) return NULL;\n\t//\tget the image data\n\ts->img_x = header.dwWidth;\n\ts->img_y = header.dwHeight;\n\ts->img_n = 4;\n\tis_compressed = (header.sPixelFormat.dwFlags & DDPF_FOURCC) / DDPF_FOURCC;\n\thas_alpha = (header.sPixelFormat.dwFlags & DDPF_ALPHAPIXELS) / DDPF_ALPHAPIXELS;\n\thas_mipmap = (header.sCaps.dwCaps1 & DDSCAPS_MIPMAP) && (header.dwMipMapCount > 1);\n\tcubemap_faces = (header.sCaps.dwCaps2 & DDSCAPS2_CUBEMAP) / DDSCAPS2_CUBEMAP;\n\t/*\tI need cubemaps to have square faces\t*/\n\tcubemap_faces &= (s->img_x == s->img_y);\n\tcubemap_faces *= 5;\n\tcubemap_faces += 1;\n\tblock_pitch = (s->img_x+3) >> 2;\n\tnum_blocks = block_pitch * ((s->img_y+3) >> 2);\n\t/*\tlet the user know what's going on\t*/\n\t*x = s->img_x;\n\t*y = s->img_y;\n\t*comp = s->img_n;\n\t/*\tis this uncompressed?\t*/\n\tif( is_compressed )\n\t{\n\t\t/*\tcompressed\t*/\n\t\t//\tnote: header.sPixelFormat.dwFourCC is something like (('D'<<0)|('X'<<8)|('T'<<16)|('1'<<24))\n\t\tDXT_family = 1 + (header.sPixelFormat.dwFourCC >> 24) - '1';\n\t\tif( (DXT_family < 1) || (DXT_family > 5) ) return NULL;\n\t\t/*\tcheck the expected size...oops, nevermind...\n\t\t\tthose non-compliant writers leave\n\t\t\tdwPitchOrLinearSize == 0\t*/\n\t\t//\tpassed all the tests, get the RAM for decoding\n\t\tsz = (s->img_x)*(s->img_y)*4*cubemap_faces;\n\t\tdds_data = (unsigned char*)malloc( sz );\n\t\t/*\tdo this once for each face\t*/\n\t\tfor( cf = 0; cf < cubemap_faces; ++ cf )\n\t\t{\n\t\t\t//\tnow read and decode all the blocks\n\t\t\tfor( i = 0; i < num_blocks; ++i )\n\t\t\t{\n\t\t\t\t//\twhere are we?\n\t\t\t\tint bx, by, bw=4, bh=4;\n\t\t\t\tint ref_x = 4 * (i % block_pitch);\n\t\t\t\tint ref_y = 4 * (i / block_pitch);\n\t\t\t\t//\tget the next block's worth of compressed data, and decompress it\n\t\t\t\tif( DXT_family == 1 )\n\t\t\t\t{\n\t\t\t\t\t//\tDXT1\n\t\t\t\t\tstbi__getn( s, compressed, 8 );\n\t\t\t\t\tstbi_decode_DXT1_block( block, compressed );\n\t\t\t\t} else if( DXT_family < 4 )\n\t\t\t\t{\n\t\t\t\t\t//\tDXT2/3\n\t\t\t\t\tstbi__getn( s, compressed, 8 );\n\t\t\t\t\tstbi_decode_DXT23_alpha_block ( block, compressed );\n\t\t\t\t\tstbi__getn( s, compressed, 8 );\n\t\t\t\t\tstbi_decode_DXT_color_block ( block, compressed );\n\t\t\t\t} else\n\t\t\t\t{\n\t\t\t\t\t//\tDXT4/5\n\t\t\t\t\tstbi__getn( s, compressed, 8 );\n\t\t\t\t\tstbi_decode_DXT45_alpha_block ( block, compressed );\n\t\t\t\t\tstbi__getn( s, compressed, 8 );\n\t\t\t\t\tstbi_decode_DXT_color_block ( block, compressed );\n\t\t\t\t}\n\t\t\t\t//\tis this a partial block?\n\t\t\t\tif( ref_x + 4 > (int)s->img_x )\n\t\t\t\t{\n\t\t\t\t\tbw = s->img_x - ref_x;\n\t\t\t\t}\n\t\t\t\tif( ref_y + 4 > (int)s->img_y )\n\t\t\t\t{\n\t\t\t\t\tbh = s->img_y - ref_y;\n\t\t\t\t}\n\t\t\t\t//\tnow drop our decompressed data into the buffer\n\t\t\t\tfor( by = 0; by < bh; ++by )\n\t\t\t\t{\n\t\t\t\t\tint idx = 4*((ref_y+by+cf*s->img_x)*s->img_x + ref_x);\n\t\t\t\t\tfor( bx = 0; bx < bw*4; ++bx )\n\t\t\t\t\t{\n\n\t\t\t\t\t\tdds_data[idx+bx] = block[by*16+bx];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/*\tdone reading and decoding the main image...\n\t\t\t\tstbi__skip MIPmaps if present\t*/\n\t\t\tif( has_mipmap )\n\t\t\t{\n\t\t\t\tint block_size = 16;\n\t\t\t\tif( DXT_family == 1 )\n\t\t\t\t{\n\t\t\t\t\tblock_size = 8;\n\t\t\t\t}\n\t\t\t\tfor( i = 1; i < (int)header.dwMipMapCount; ++i )\n\t\t\t\t{\n\t\t\t\t\tint mx = s->img_x >> (i + 2);\n\t\t\t\t\tint my = s->img_y >> (i + 2);\n\t\t\t\t\tif( mx < 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tmx = 1;\n\t\t\t\t\t}\n\t\t\t\t\tif( my < 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tmy = 1;\n\t\t\t\t\t}\n\t\t\t\t\tstbi__skip( s, mx*my*block_size );\n\t\t\t\t}\n\t\t\t}\n\t\t}/* per cubemap face */\n\t} else\n\t{\n\t\t/*\tuncompressed\t*/\n\t\tDXT_family = 0;\n\t\ts->img_n = 3;\n\t\tif( has_alpha )\n\t\t{\n\t\t\ts->img_n = 4;\n\t\t}\n\t\t*comp = s->img_n;\n\t\tsz = s->img_x*s->img_y*s->img_n*cubemap_faces;\n\t\tdds_data = (unsigned char*)malloc( sz );\n\t\t/*\tdo this once for each face\t*/\n\t\tfor( cf = 0; cf < cubemap_faces; ++ cf )\n\t\t{\n\t\t\t/*\tread the main image for this face\t*/\n\t\t\tstbi__getn( s, &dds_data[cf*s->img_x*s->img_y*s->img_n], s->img_x*s->img_y*s->img_n );\n\t\t\t/*\tdone reading and decoding the main image...\n\t\t\t\tstbi__skip MIPmaps if present\t*/\n\t\t\tif( has_mipmap )\n\t\t\t{\n\t\t\t\tfor( i = 1; i < (int)header.dwMipMapCount; ++i )\n\t\t\t\t{\n\t\t\t\t\tint mx = s->img_x >> i;\n\t\t\t\t\tint my = s->img_y >> i;\n\t\t\t\t\tif( mx < 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tmx = 1;\n\t\t\t\t\t}\n\t\t\t\t\tif( my < 1 )\n\t\t\t\t\t{\n\t\t\t\t\t\tmy = 1;\n\t\t\t\t\t}\n\t\t\t\t\tstbi__skip( s, mx*my*s->img_n );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t/*\tdata was BGR, I need it RGB\t*/\n\t\tfor( i = 0; i < sz; i += s->img_n )\n\t\t{\n\t\t\tunsigned char temp = dds_data[i];\n\t\t\tdds_data[i] = dds_data[i+2];\n\t\t\tdds_data[i+2] = temp;\n\t\t}\n\t}\n\t/*\tfinished decompressing into RGBA,\n\t\tadjust the y size if we have a cubemap\n\t\tnote: sz is already up to date\t*/\n\ts->img_y *= cubemap_faces;\n\t*y = s->img_y;\n\t//\tdid the user want something else, or\n\t//\tsee if all the alpha values are 255 (i.e. no transparency)\n\thas_alpha = 0;\n\tif( s->img_n == 4)\n\t{\n\t\tfor( i = 3; (i < sz) && (has_alpha == 0); i += 4 )\n\t\t{\n\t\t\thas_alpha |= (dds_data[i] < 255);\n\t\t}\n\t}\n\tif( (req_comp <= 4) && (req_comp >= 1) )\n\t{\n\t\t//\tuser has some requirements, meet them\n\t\tif( req_comp != s->img_n )\n\t\t{\n\t\t\tdds_data = stbi__convert_format( dds_data, s->img_n, req_comp, s->img_x, s->img_y );\n\t\t\t*comp = req_comp;\n\t\t}\n\t} else\n\t{\n\t\t//\tuser had no requirements, only drop to RGB is no alpha\n\t\tif( (has_alpha == 0) && (s->img_n == 4) )\n\t\t{\n\t\t\tdds_data = stbi__convert_format( dds_data, 4, 3, s->img_x, s->img_y );\n\t\t\t*comp = 3;\n\t\t}\n\t}\n\t//\tOK, done\n\treturn dds_data;\n}\n\n#ifndef STBI_NO_STDIO\nvoid *stbi__dds_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n\tstbi__start_file(&s,f);\n\treturn stbi__dds_load(&s,x,y,comp,req_comp);\n}\n\nvoid *stbi__dds_load_from_path             (const char *filename,           int *x, int *y, int *comp, int req_comp)\n{\n   void *data;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return NULL;\n   data = stbi__dds_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return data;\n}\n#endif\n\nvoid *stbi__dds_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__dds_load(&s,x,y,comp,req_comp);\n}\n\nvoid *stbi__dds_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__dds_load(&s,x,y,comp,req_comp);\n}\n"
  },
  {
    "path": "lib/SOIL2/stbi_ext.h",
    "content": "#ifndef HEADER_STB_IMAGE_EXT\n#define HEADER_STB_IMAGE_EXT\n\nenum {\n\tSTBI_unknown= 0,\n\tSTBI_jpeg\t= 1,\n\tSTBI_png\t= 2,\n\tSTBI_bmp\t= 3,\n\tSTBI_gif\t= 4,\n\tSTBI_tga\t= 5,\n\tSTBI_psd\t= 6,\n\tSTBI_pic\t= 7,\n\tSTBI_pnm\t= 8,\n\tSTBI_dds\t= 9,\n\tSTBI_pvr\t= 10,\n\tSTBI_pkm\t= 11,\n\tSTBI_hdr\t= 12,\n\tSTBI_qoi\t= 13\n};\n\nextern int      stbi_test_from_memory      (stbi_uc const *buffer, int len);\nextern int      stbi_test_from_callbacks   (stbi_io_callbacks const *clbk, void *user);\n\n#ifndef STBI_NO_STDIO\nextern int      stbi_test\t\t\t\t\t(char const *filename);\nextern int      stbi_test_from_file        (FILE *f);\n#endif\n\n#endif /* HEADER_STB_IMAGE_EXT */\n"
  },
  {
    "path": "lib/SOIL2/stbi_ext_c.h",
    "content": "\nstatic int stbi_test_main(stbi__context *s)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_test(s)) return STBI_jpeg;\n   #endif\n   #ifndef STBI_NO_PNG\n   if (stbi__png_test(s))  return STBI_png;\n   #endif\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_test(s))  return STBI_bmp;\n   #endif\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_test(s))  return STBI_gif;\n   #endif\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_test(s))  return STBI_psd;\n   #endif\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_test(s))  return STBI_pic;\n   #endif\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_test(s))  return STBI_pnm;\n   #endif\n   #ifndef STBI_NO_DDS\n   if (stbi__dds_test(s))  return STBI_dds;\n   #endif\n   #ifndef STBI_NO_PVR\n   if (stbi__pvr_test(s))  return STBI_pvr;\n   #endif\n   #ifndef STBI_NO_PKM\n   if (stbi__pkm_test(s))  return STBI_pkm;\n   #endif\n   #ifndef STBI_NO_QOI\n   if (stbi__qoi_test(s))  return STBI_qoi;\n   #endif\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s))  return STBI_hdr;\n   #endif\n   #ifndef STBI_NO_TGA\n   if (stbi__tga_test(s))  return STBI_tga;\n   #endif\n   return STBI_unknown;\n}\n\n#ifndef STBI_NO_STDIO\nint stbi_test_from_file(FILE *f)\n{\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi_test_main(&s);\n}\n\nint stbi_test(char const *filename)\n{\n   FILE *f = fopen(filename, \"rb\");\n   int result;\n   if (!f) return STBI_unknown;\n   result = stbi_test_from_file(f);\n   fclose(f);\n   return result;\n}\n#endif //!STBI_NO_STDIO\n\nint stbi_test_from_memory(stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi_test_main(&s);\n}\n\nint stbi_test_from_callbacks(stbi_io_callbacks const *clbk, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi_test_main(&s);\n}\n"
  },
  {
    "path": "lib/SOIL2/stbi_pkm.h",
    "content": "/*\n\tadding PKM loading support to stbi\n*/\n\n#ifndef HEADER_STB_IMAGE_PKM_AUGMENTATION\n#define HEADER_STB_IMAGE_PKM_AUGMENTATION\n\n/*\tis it a PKM file? */\nextern int      stbi__pkm_test_memory      (stbi_uc const *buffer, int len);\nextern int      stbi__pkm_test_callbacks   (stbi_io_callbacks const *clbk, void *user);\n\nextern void    *stbi__pkm_load_from_path   (char const *filename,           int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__pkm_test_filename    (char const *filename);\nextern int      stbi__pkm_test_file        (FILE *f);\nextern void    *stbi__pkm_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp);\n#endif\n\nextern int      stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nextern int      stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\n\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__pkm_info_from_path   (char const *filename,     int *x, int *y, int *comp);\nextern int      stbi__pkm_info_from_file   (FILE *f,                  int *x, int *y, int *comp);\n#endif\n\n/*\n//\n////   end header file   /////////////////////////////////////////////////////*/\n#endif /* HEADER_STB_IMAGE_PKM_AUGMENTATION */\n"
  },
  {
    "path": "lib/SOIL2/stbi_pkm_c.h",
    "content": "#include \"pkm_helper.h\"\n#include \"wfETC.h\"\n\nstatic int stbi__pkm_test(stbi__context *s)\n{\n\t//\tcheck the magic number\n\tif (stbi__get8(s) != 'P') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != 'K') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != 'M') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != ' ') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != '1') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tif (stbi__get8(s) != '0') {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\tstbi__rewind(s);\n\treturn 1;\n}\n\n#ifndef STBI_NO_STDIO\n\nint      stbi__pkm_test_filename        \t\t(char const *filename)\n{\n   int r;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   r = stbi__pkm_test_file(f);\n   fclose(f);\n   return r;\n}\n\nint      stbi__pkm_test_file        (FILE *f)\n{\n   stbi__context s;\n   int r,n = ftell(f);\n   stbi__start_file(&s,f);\n   r = stbi__pkm_test(&s);\n   fseek(f,n,SEEK_SET);\n   return r;\n}\n#endif\n\nint      stbi__pkm_test_memory      (stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__pkm_test(&s);\n}\n\nint      stbi__pkm_test_callbacks      (stbi_io_callbacks const *clbk, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__pkm_test(&s);\n}\n\nstatic int stbi__pkm_info(stbi__context *s, int *x, int *y, int *comp )\n{\n\tPKMHeader header;\n\tunsigned int width, height;\n\n\tstbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) );\n\n\tif ( 0 != strncmp( header.aName, \"PKM 10\", sizeof(header.aName) ) ) {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\twidth = (header.iWidthMSB << 8) | header.iWidthLSB;\n\theight = (header.iHeightMSB << 8) | header.iHeightLSB;\n\n\t*x = s->img_x = width;\n\t*y = s->img_y = height;\n\t*comp = s->img_n = 3;\n\n\tstbi__rewind(s);\n\n\treturn 1;\n}\n\nint stbi__pkm_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp )\n{\n\tstbi__context s;\n\tstbi__start_mem(&s,buffer, len);\n\treturn stbi__pkm_info( &s, x, y, comp );\n}\n\nint stbi__pkm_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp)\n{\n\tstbi__context s;\n\tstbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n\treturn stbi__pkm_info( &s, x, y, comp );\n}\n\n#ifndef STBI_NO_STDIO\nint stbi__pkm_info_from_path(char const *filename,     int *x, int *y, int *comp)\n{\n   int res;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   res = stbi__pkm_info_from_file( f, x, y, comp );\n   fclose(f);\n   return res;\n}\n\nint stbi__pkm_info_from_file(FILE *f,                  int *x, int *y, int *comp)\n{\n   stbi__context s;\n   int res;\n   long n = ftell(f);\n   stbi__start_file(&s, f);\n   res = stbi__pkm_info(&s, x, y, comp);\n   fseek(f, n, SEEK_SET);\n   return res;\n}\n#endif\n\nstatic void * stbi__pkm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n\tstbi_uc *pkm_data = NULL;\n\tstbi_uc *pkm_res_data = NULL;\n\tPKMHeader header;\n\tunsigned int width;\n\tunsigned int height;\n\tunsigned int compressed_size;\n\n\tstbi__getn( s, (stbi_uc*)(&header), sizeof(PKMHeader) );\n\n\tif ( 0 != strncmp( header.aName, \"PKM 10\", sizeof(header.aName) ) ) {\n\t\treturn NULL;\n\t}\n\n\twidth = (header.iWidthMSB << 8) | header.iWidthLSB;\n\theight = (header.iHeightMSB << 8) | header.iHeightLSB;\n\n\t*x = s->img_x = width;\n\t*y = s->img_y = height;\n\t*comp = s->img_n = 4;\n\n\tcompressed_size = (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1;\n\n\tpkm_data = (stbi_uc *)malloc(compressed_size);\n\tstbi__getn( s, pkm_data, compressed_size );\n\n\tpkm_res_data = (stbi_uc *)malloc(width * height * s->img_n);\n\n\twfETC1_DecodeImage(pkm_data, pkm_res_data, width, height);\n\n\tfree( pkm_data );\n\n\tif ( NULL != pkm_res_data ) {\n\t\tif( (req_comp < 4) && (req_comp >= 1) ) {\n\t\t\t//\tuser has some requirements, meet them\n\t\t\tif( req_comp != s->img_n ) {\n\t\t\t\tpkm_res_data = stbi__convert_format( pkm_res_data, s->img_n, req_comp, s->img_x, s->img_y );\n\t\t\t\t*comp = req_comp;\n\t\t\t}\n\t\t}\n\n\t\treturn (stbi_uc *)pkm_res_data;\n\t} else {\n\t\tfree( pkm_res_data );\n\t}\n\n\treturn NULL;\n}\n\n#ifndef STBI_NO_STDIO\nvoid *stbi__pkm_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n\tstbi__start_file(&s,f);\n\treturn stbi__pkm_load(&s,x,y,comp,req_comp);\n}\n\nvoid *stbi__pkm_load_from_path             (char const*filename,           int *x, int *y, int *comp, int req_comp)\n{\n   void *data;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return NULL;\n   data = stbi__pkm_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return data;\n}\n#endif\n\nvoid *stbi__pkm_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__pkm_load(&s,x,y,comp,req_comp);\n}\n\nvoid *stbi__pkm_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__pkm_load(&s,x,y,comp,req_comp);\n}\n"
  },
  {
    "path": "lib/SOIL2/stbi_pvr.h",
    "content": "/*\n\tadding PVR loading support to stbi\n*/\n\n#ifndef HEADER_STB_IMAGE_PVR_AUGMENTATION\n#define HEADER_STB_IMAGE_PVR_AUGMENTATION\n\n/*\tis it a PVR file? */\nextern int      stbi__pvr_test_memory      (stbi_uc const *buffer, int len);\nextern int      stbi__pvr_test_callbacks   (stbi_io_callbacks const *clbk, void *user);\n\nextern void    *stbi__pvr_load_from_path   (char const *filename,           int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__pvr_test_filename    (char const *filename);\nextern int      stbi__pvr_test_file        (FILE *f);\nextern void    *stbi__pvr_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp);\n#endif\n\nextern int      stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int *iscompressed);\nextern int      stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int *iscompressed);\n\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__pvr_info_from_path   (char const *filename,     int *x, int *y, int *comp, int *iscompressed);\nextern int      stbi__pvr_info_from_file   (FILE *f,                  int *x, int *y, int *comp, int *iscompressed);\n#endif\n\n/*\n//\n////   end header file   /////////////////////////////////////////////////////*/\n#endif /* HEADER_STB_IMAGE_PVR_AUGMENTATION */\n"
  },
  {
    "path": "lib/SOIL2/stbi_pvr_c.h",
    "content": "#include \"pvr_helper.h\"\n\nstatic int stbi__pvr_test(stbi__context *s)\n{\n\t//\tcheck header size\n\tif (stbi__get32le(s) != sizeof(PVR_Texture_Header)) {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\t// stbi__skip until the magic number\n\tstbi__skip(s, 10*4);\n\n\t// check the magic number\n\tif ( stbi__get32le(s) != PVRTEX_IDENTIFIER ) {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\t// Also rewind because the loader needs to read the header\n\tstbi__rewind(s);\n\n\treturn 1;\n}\n\n#ifndef STBI_NO_STDIO\n\nint      stbi__pvr_test_filename        \t\t(char const *filename)\n{\n   int r;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   r = stbi__pvr_test_file(f);\n   fclose(f);\n   return r;\n}\n\nint      stbi__pvr_test_file        (FILE *f)\n{\n   stbi__context s;\n   int r,n = ftell(f);\n   stbi__start_file(&s,f);\n   r = stbi__pvr_test(&s);\n   fseek(f,n,SEEK_SET);\n   return r;\n}\n#endif\n\nint      stbi__pvr_test_memory      (stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__pvr_test(&s);\n}\n\nint      stbi__pvr_test_callbacks      (stbi_io_callbacks const *clbk, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__pvr_test(&s);\n}\n\nstatic int stbi__pvr_info(stbi__context *s, int *x, int *y, int *comp, int * iscompressed )\n{\n\tPVR_Texture_Header header={0};\n\n\tstbi__getn( s, (stbi_uc*)(&header), sizeof(PVR_Texture_Header) );\n\n\t// Check the header size\n\tif ( header.dwHeaderSize != sizeof(PVR_Texture_Header) ) {\n\t\tstbi__rewind( s );\n\t\treturn 0;\n\t}\n\n\t// Check the magic identifier\n\tif ( header.dwPVR != PVRTEX_IDENTIFIER ) {\n\t\tstbi__rewind(s);\n\t\treturn 0;\n\t}\n\n\t*x = s->img_x = header.dwWidth;\n\t*y = s->img_y = header.dwHeight;\n\t*comp = s->img_n = ( header.dwBitCount + 7 ) / 8;\n\n\tif ( iscompressed )\n\t\t*iscompressed = 0;\n\n\tswitch ( header.dwpfFlags & PVRTEX_PIXELTYPE )\n\t{\n\t\tcase OGL_RGBA_4444:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_RGBA_5551:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_RGBA_8888:\n\t\t\ts->img_n = 4;\n\t\t\tbreak;\n\t\tcase OGL_RGB_565:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_RGB_888:\n\t\t\ts->img_n = 3;\n\t\t\tbreak;\n\t\tcase OGL_I_8:\n\t\t\ts->img_n = 1;\n\t\t\tbreak;\n\t\tcase OGL_AI_88:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_PVRTC2:\n\t\t\ts->img_n = 4;\n\t\t\tif ( iscompressed )\n\t\t\t\t*iscompressed = 1;\n\t\t\tbreak;\n\t\tcase OGL_PVRTC4:\n\t\t\ts->img_n = 4;\n\t\t\tif ( iscompressed )\n\t\t\t\t*iscompressed = 1;\n\t\t\tbreak;\n\t\tcase OGL_RGB_555:\n\t\tdefault:\n\t\t\tstbi__rewind(s);\n\t\t\treturn 0;\n\t}\n\n\t*comp = s->img_n;\n\n\treturn 1;\n}\n\nint stbi__pvr_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int * iscompressed )\n{\n\tstbi__context s;\n\tstbi__start_mem(&s,buffer, len);\n\treturn stbi__pvr_info( &s, x, y, comp, iscompressed );\n}\n\nint stbi__pvr_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int * iscompressed)\n{\n\tstbi__context s;\n\tstbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n\treturn stbi__pvr_info( &s, x, y, comp, iscompressed );\n}\n\n#ifndef STBI_NO_STDIO\nint stbi__pvr_info_from_path(char const *filename,     int *x, int *y, int *comp, int * iscompressed)\n{\n   int res;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   res = stbi__pvr_info_from_file( f, x, y, comp, iscompressed );\n   fclose(f);\n   return res;\n}\n\nint stbi__pvr_info_from_file(FILE *f,                  int *x, int *y, int *comp, int * iscompressed)\n{\n   stbi__context s;\n   int res;\n   long n = ftell(f);\n   stbi__start_file(&s, f);\n   res = stbi__pvr_info(&s, x, y, comp, iscompressed);\n   fseek(f, n, SEEK_SET);\n   return res;\n}\n#endif\n\n/******************************************************************************\n Taken from:\n @File         PVRTDecompress.cpp\n @Title        PVRTDecompress\n @Copyright    Copyright (C)  Imagination Technologies Limited.\n @Platform     ANSI compatible\n @Description  PVRTC Texture Decompression.\n******************************************************************************/\n\ntypedef unsigned char      PVRTuint8;\ntypedef unsigned short     PVRTuint16;\ntypedef unsigned int       PVRTuint32;\n\n/*****************************************************************************\n * defines and consts\n *****************************************************************************/\n#define PT_INDEX (2)\t// The Punch-through index\n\n#define BLK_Y_SIZE \t(4) // always 4 for all 2D block types\n\n#define BLK_X_MAX\t(8)\t// Max X dimension for blocks\n\n#define BLK_X_2BPP\t(8) // dimensions for the two formats\n#define BLK_X_4BPP\t(4)\n\n#define WRAP_COORD(Val, Size) ((Val) & ((Size)-1))\n\n#define POWER_OF_2(X)   util_number_is_power_2(X)\n\n/*\n\tDefine an expression to either wrap or clamp large or small vals to the\n\tlegal coordinate range\n*/\n#define PVRT_MIN(a,b)            (((a) < (b)) ? (a) : (b))\n#define PVRT_MAX(a,b)            (((a) > (b)) ? (a) : (b))\n#define PVRT_CLAMP(x, l, h)      (PVRT_MIN((h), PVRT_MAX((x), (l))))\n\n#define LIMIT_COORD(Val, Size, AssumeImageTiles) \\\n\t  ((AssumeImageTiles)? WRAP_COORD((Val), (Size)): PVRT_CLAMP((Val), 0, (Size)-1))\n\n/*****************************************************************************\n * Useful typedefs\n *****************************************************************************/\ntypedef PVRTuint32 U32;\ntypedef PVRTuint8 U8;\n\n/***********************************************************\n\t\t\t\tDECOMPRESSION ROUTINES\n************************************************************/\n\n/*!***********************************************************************\n @Struct\tAMTC_BLOCK_STRUCT\n @Brief\n*************************************************************************/\ntypedef struct\n{\n\t// Uses 64 bits pre block\n\tU32 PackedData[2];\n}AMTC_BLOCK_STRUCT;\n\n /*!***********************************************************************\n  @Function\t\tutil_number_is_power_2\n  @Input\t\tinput A number\n  @Returns\t\tTRUE if the number is an integer power of two, else FALSE.\n  @Description\tCheck that a number is an integer power of two, i.e.\n\t\t\t\t1, 2, 4, 8, ... etc.\n\t\t\t\tReturns FALSE for zero.\n*************************************************************************/\nint util_number_is_power_2( unsigned  input )\n{\n  unsigned minus1;\n\n  if( !input ) return 0;\n\n  minus1 = input - 1;\n  return ( (input | minus1) == (input ^ minus1) ) ? 1 : 0;\n}\n\n/*!***********************************************************************\n @Function\t\tUnpack5554Colour\n @Input\t\t\tpBlock\n @Input\t\t\tABColours\n @Description\tGiven a block, extract the colour information and convert\n\t\t\t\tto 5554 formats\n*************************************************************************/\nstatic void Unpack5554Colour(const AMTC_BLOCK_STRUCT *pBlock,\n\t\t\t\t\t\t\t int   ABColours[2][4])\n{\n\tU32 RawBits[2];\n\n\tint i;\n\n\t// Extract A and B\n\tRawBits[0] = pBlock->PackedData[1] & (0xFFFE); // 15 bits (shifted up by one)\n\tRawBits[1] = pBlock->PackedData[1] >> 16;\t   // 16 bits\n\n\t// step through both colours\n\tfor(i = 0; i < 2; i++)\n\t{\n\t\t// If completely opaque\n\t\tif(RawBits[i] & (1<<15))\n\t\t{\n\t\t\t// Extract R and G (both 5 bit)\n\t\t\tABColours[i][0] = (RawBits[i] >> 10) & 0x1F;\n\t\t\tABColours[i][1] = (RawBits[i] >>  5) & 0x1F;\n\n\t\t\t/*\n\t\t\t\tThe precision of Blue depends on  A or B. If A then we need to\n\t\t\t\treplicate the top bit to get 5 bits in total\n\t\t\t*/\n\t\t\tABColours[i][2] = RawBits[i] & 0x1F;\n\t\t\tif(i==0)\n\t\t\t{\n\t\t\t\tABColours[0][2] |= ABColours[0][2] >> 4;\n\t\t\t}\n\n\t\t\t// set 4bit alpha fully on...\n\t\t\tABColours[i][3] = 0xF;\n\t\t}\n\t\telse // Else if colour has variable translucency\n\t\t{\n\t\t\t/*\n\t\t\t\tExtract R and G (both 4 bit).\n\t\t\t\t(Leave a space on the end for the replication of bits\n\t\t\t*/\n\t\t\tABColours[i][0] = (RawBits[i] >>  (8-1)) & 0x1E;\n\t\t\tABColours[i][1] = (RawBits[i] >>  (4-1)) & 0x1E;\n\n\t\t\t// replicate bits to truly expand to 5 bits\n\t\t\tABColours[i][0] |= ABColours[i][0] >> 4;\n\t\t\tABColours[i][1] |= ABColours[i][1] >> 4;\n\n\t\t\t// grab the 3(+padding) or 4 bits of blue and add an extra padding bit\n\t\t\tABColours[i][2] = (RawBits[i] & 0xF) << 1;\n\n\t\t\t/*\n\t\t\t\texpand from 3 to 5 bits if this is from colour A, or 4 to 5 bits if from\n\t\t\t\tcolour B\n\t\t\t*/\n\t\t\tif(i==0)\n\t\t\t{\n\t\t\t\tABColours[0][2] |= ABColours[0][2] >> 3;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tABColours[0][2] |= ABColours[0][2] >> 4;\n\t\t\t}\n\n\t\t\t// Set the alpha bits to be 3 + a zero on the end\n\t\t\tABColours[i][3] = (RawBits[i] >> 11) & 0xE;\n\t\t}\n\t}\n}\n\n/*!***********************************************************************\n @Function\t\tUnpackModulations\n @Input\t\t\tpBlock\n @Input\t\t\tDo2bitMode\n @Input\t\t\tModulationVals\n @Input\t\t\tModulationModes\n @Input\t\t\tStartX\n @Input\t\t\tStartY\n @Description\tGiven the block and the texture type and it's relative\n\t\t\t\tposition in the 2x2 group of blocks, extract the bit\n\t\t\t\tpatterns for the fully defined pixels.\n*************************************************************************/\nstatic void\tUnpackModulations(const AMTC_BLOCK_STRUCT *pBlock,\n\t\t\t\t\t\t\t  const int Do2bitMode,\n\t\t\t\t\t\t\t  int ModulationVals[8][16],\n\t\t\t\t\t\t\t  int ModulationModes[8][16],\n\t\t\t\t\t\t\t  int StartX,\n\t\t\t\t\t\t\t  int StartY)\n{\n\tint BlockModMode;\n\tU32 ModulationBits;\n\n\tint x, y;\n\n\tBlockModMode= pBlock->PackedData[1] & 1;\n\tModulationBits\t= pBlock->PackedData[0];\n\n\t// if it's in an interpolated mode\n\tif(Do2bitMode && BlockModMode)\n\t{\n\t\t/*\n\t\t\trun through all the pixels in the block. Note we can now treat all the\n\t\t\t\"stored\" values as if they have 2bits (even when they didn't!)\n\t\t*/\n\t\tfor(y = 0; y < BLK_Y_SIZE; y++)\n\t\t{\n\t\t\tfor(x = 0; x < BLK_X_2BPP; x++)\n\t\t\t{\n\t\t\t\tModulationModes[y+StartY][x+StartX] = BlockModMode;\n\n\t\t\t\t// if this is a stored value...\n\t\t\t\tif(((x^y)&1) == 0)\n\t\t\t\t{\n\t\t\t\t\tModulationVals[y+StartY][x+StartX] = ModulationBits & 3;\n\t\t\t\t\tModulationBits >>= 2;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if(Do2bitMode) // else if direct encoded 2bit mode - i.e. 1 mode bit per pixel\n\t{\n\t\tfor(y = 0; y < BLK_Y_SIZE; y++)\n\t\t{\n\t\t\tfor(x = 0; x < BLK_X_2BPP; x++)\n\t\t\t{\n\t\t\t\tModulationModes[y+StartY][x+StartX] = BlockModMode;\n\n\t\t\t\t// double the bits so 0=> 00, and 1=>11\n\t\t\t\tif(ModulationBits & 1)\n\t\t\t\t{\n\t\t\t\t\tModulationVals[y+StartY][x+StartX] = 0x3;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tModulationVals[y+StartY][x+StartX] = 0x0;\n\t\t\t\t}\n\t\t\t\tModulationBits >>= 1;\n\t\t\t}\n\t\t}\n\t}\n\telse // else its the 4bpp mode so each value has 2 bits\n\t{\n\t\tfor(y = 0; y < BLK_Y_SIZE; y++)\n\t\t{\n\t\t\tfor(x = 0; x < BLK_X_4BPP; x++)\n\t\t\t{\n\t\t\t\tModulationModes[y+StartY][x+StartX] = BlockModMode;\n\n\t\t\t\tModulationVals[y+StartY][x+StartX] = ModulationBits & 3;\n\t\t\t\tModulationBits >>= 2;\n\t\t\t}\n\t\t}\n\t}\n\n\t// make sure nothing is left over\n\tassert(ModulationBits==0);\n}\n\n/*!***********************************************************************\n @Function\t\tInterpolateColours\n @Input\t\t\tColourP\n @Input\t\t\tColourQ\n @Input\t\t\tColourR\n @Input\t\t\tColourS\n @Input\t\t\tDo2bitMode\n @Input\t\t\tx\n @Input\t\t\ty\n @Modified\t\tResult\n @Description\tThis performs a HW bit accurate interpolation of either the\n\t\t\t\tA or B colours for a particular pixel.\n\n\t\t\t\tNOTE: It is assumed that the source colours are in ARGB 5554\n\t\t\t\tformat - This means that some \"preparation\" of the values will\n\t\t\t\tbe necessary.\n*************************************************************************/\nstatic void InterpolateColours(const int ColourP[4],\n\t\t\t\t\t\t  const int ColourQ[4],\n\t\t\t\t\t\t  const int ColourR[4],\n\t\t\t\t\t\t  const int ColourS[4],\n\t\t\t\t\t\t  const int Do2bitMode,\n\t\t\t\t\t\t  const int x,\n\t\t\t\t\t\t  const int y,\n\t\t\t\t\t\t  int Result[4])\n{\n\tint u, v, uscale;\n\tint k;\n\n\tint tmp1, tmp2;\n\n\tint P[4], Q[4], R[4], S[4];\n\n\t// Copy the colours\n\tfor(k = 0; k < 4; k++)\n\t{\n\t\tP[k] = ColourP[k];\n\t\tQ[k] = ColourQ[k];\n\t\tR[k] = ColourR[k];\n\t\tS[k] = ColourS[k];\n\t}\n\n\t// put the x and y values into the right range\n\tv = (y & 0x3) | ((~y & 0x2) << 1);\n\n\tif(Do2bitMode)\n\t\tu = (x & 0x7) | ((~x & 0x4) << 1);\n\telse\n\t\tu = (x & 0x3) | ((~x & 0x2) << 1);\n\n\t// get the u and v scale amounts\n\tv  = v - BLK_Y_SIZE/2;\n\n\tif(Do2bitMode)\n\t{\n\t\tu = u - BLK_X_2BPP/2;\n\t\tuscale = 8;\n\t}\n\telse\n\t{\n\t\tu = u - BLK_X_4BPP/2;\n\t\tuscale = 4;\n\t}\n\n\tfor(k = 0; k < 4; k++)\n\t{\n\t\ttmp1 = P[k] * uscale + u * (Q[k] - P[k]);\n\t\ttmp2 = R[k] * uscale + u * (S[k] - R[k]);\n\n\t\ttmp1 = tmp1 * 4 + v * (tmp2 - tmp1);\n\n\t\tResult[k] = tmp1;\n\t}\n\n\t// Lop off the appropriate number of bits to get us to 8 bit precision\n\tif(Do2bitMode)\n\t{\n\t\t// do RGB\n\t\tfor(k = 0; k < 3; k++)\n\t\t{\n\t\t\tResult[k] >>= 2;\n\t\t}\n\n\t\tResult[3] >>= 1;\n\t}\n\telse\n\t{\n\t\t// do RGB  (A is ok)\n\t\tfor(k = 0; k < 3; k++)\n\t\t{\n\t\t\tResult[k] >>= 1;\n\t\t}\n\t}\n\n\t// sanity check\n\tfor(k = 0; k < 4; k++)\n\t{\n\t\tassert(Result[k] < 256);\n\t}\n\n\n\t/*\n\t\tConvert from 5554 to 8888\n\n\t\tdo RGB 5.3 => 8\n\t*/\n\tfor(k = 0; k < 3; k++)\n\t{\n\t\tResult[k] += Result[k] >> 5;\n\t}\n\n\tResult[3] += Result[3] >> 4;\n\n\t// 2nd sanity check\n\tfor(k = 0; k < 4; k++)\n\t{\n\t\tassert(Result[k] < 256);\n\t}\n\n}\n\n/*!***********************************************************************\n @Function\t\tGetModulationValue\n @Input\t\t\tx\n @Input\t\t\ty\n @Input\t\t\tDo2bitMode\n @Input\t\t\tModulationVals\n @Input\t\t\tModulationModes\n @Input\t\t\tMod\n @Input\t\t\tDoPT\n @Description\tGet the modulation value as a numerator of a fraction of 8ths\n*************************************************************************/\nstatic void GetModulationValue(int x,\n\t\t\t\t\t\t\t   int y,\n\t\t\t\t\t\t\t   const int Do2bitMode,\n\t\t\t\t\t\t\t   const int ModulationVals[8][16],\n\t\t\t\t\t\t\t   const int ModulationModes[8][16],\n\t\t\t\t\t\t\t   int *Mod,\n\t\t\t\t\t\t\t   int *DoPT)\n{\n\tstatic const int RepVals0[4] = {0, 3, 5, 8};\n\tstatic const int RepVals1[4] = {0, 4, 4, 8};\n\n\tint ModVal;\n\n\t// Map X and Y into the local 2x2 block\n\ty = (y & 0x3) | ((~y & 0x2) << 1);\n\n\tif(Do2bitMode)\n\t\tx = (x & 0x7) | ((~x & 0x4) << 1);\n\telse\n\t\tx = (x & 0x3) | ((~x & 0x2) << 1);\n\n\t// assume no PT for now\n\t*DoPT = 0;\n\n\t// extract the modulation value. If a simple encoding\n\tif(ModulationModes[y][x]==0)\n\t{\n\t\tModVal = RepVals0[ModulationVals[y][x]];\n\t}\n\telse if(Do2bitMode)\n\t{\n\t\t// if this is a stored value\n\t\tif(((x^y)&1)==0)\n\t\t\tModVal = RepVals0[ModulationVals[y][x]];\n\t\telse if(ModulationModes[y][x] == 1) // else average from the neighbours if H&V interpolation..\n\t\t{\n\t\t\tModVal = (RepVals0[ModulationVals[y-1][x]] +\n\t\t\t\t\t  RepVals0[ModulationVals[y+1][x]] +\n\t\t\t\t\t  RepVals0[ModulationVals[y][x-1]] +\n\t\t\t\t\t  RepVals0[ModulationVals[y][x+1]] + 2) / 4;\n\t\t}\n\t\telse if(ModulationModes[y][x] == 2) // else if H-Only\n\t\t{\n\t\t\tModVal = (RepVals0[ModulationVals[y][x-1]] +\n\t\t\t\t\t  RepVals0[ModulationVals[y][x+1]] + 1) / 2;\n\t\t}\n\t\telse // else it's V-Only\n\t\t{\n\t\t\tModVal = (RepVals0[ModulationVals[y-1][x]] +\n\t\t\t\t\t  RepVals0[ModulationVals[y+1][x]] + 1) / 2;\n\t\t}\n\t}\n\telse // else it's 4BPP and PT encoding\n\t{\n\t\tModVal = RepVals1[ModulationVals[y][x]];\n\n\t\t*DoPT = ModulationVals[y][x] == PT_INDEX;\n\t}\n\n\t*Mod =ModVal;\n}\n\nstatic int DisableTwiddlingRoutine = 0;\n\n/*!***********************************************************************\n @Function\t\tTwiddleUV\n @Input\t\t\tYSize\tY dimension of the texture in pixels\n @Input\t\t\tXSize\tX dimension of the texture in pixels\n @Input\t\t\tYPos\tPixel Y position\n @Input\t\t\tXPos\tPixel X position\n @Returns\t\tThe twiddled offset of the pixel\n @Description\tGiven the Block (or pixel) coordinates and the dimension of\n\t\t\t\tthe texture in blocks (or pixels) this returns the twiddled\n\t\t\t\toffset of the block (or pixel) from the start of the map.\n\n\t\t\t\tNOTE the dimensions of the texture must be a power of 2\n*************************************************************************/\nstatic U32 TwiddleUV(U32 YSize, U32 XSize, U32 YPos, U32 XPos)\n{\n\tU32 Twiddled;\n\n\tU32 MinDimension;\n\tU32 MaxValue;\n\n\tU32 SrcBitPos;\n\tU32 DstBitPos;\n\n\tint ShiftCount;\n\n\tassert(YPos < YSize);\n\tassert(XPos < XSize);\n\n\tassert(POWER_OF_2(YSize));\n\tassert(POWER_OF_2(XSize));\n\n\tif(YSize < XSize)\n\t{\n\t\tMinDimension = YSize;\n\t\tMaxValue\t = XPos;\n\t}\n\telse\n\t{\n\t\tMinDimension = XSize;\n\t\tMaxValue\t = YPos;\n\t}\n\n\t// Nasty hack to disable twiddling\n\tif(DisableTwiddlingRoutine)\n\t\treturn (YPos* XSize + XPos);\n\n\t// Step through all the bits in the \"minimum\" dimension\n\tSrcBitPos = 1;\n\tDstBitPos = 1;\n\tTwiddled  = 0;\n\tShiftCount = 0;\n\n\twhile(SrcBitPos < MinDimension)\n\t{\n\t\tif(YPos & SrcBitPos)\n\t\t{\n\t\t\tTwiddled |= DstBitPos;\n\t\t}\n\n\t\tif(XPos & SrcBitPos)\n\t\t{\n\t\t\tTwiddled |= (DstBitPos << 1);\n\t\t}\n\n\n\t\tSrcBitPos <<= 1;\n\t\tDstBitPos <<= 2;\n\t\tShiftCount += 1;\n\n\t}\n\n\t// prepend any unused bits\n\tMaxValue >>= ShiftCount;\n\n\tTwiddled |=  (MaxValue << (2*ShiftCount));\n\n\treturn Twiddled;\n}\n\n/***********************************************************/\n/*\n// Decompress\n//\n// Takes the compressed input data and outputs the equivalent decompressed\n// image.\n*/\n/***********************************************************/\n\nstatic void Decompress(AMTC_BLOCK_STRUCT *pCompressedData,\n\t\t\t\t\t   const int Do2bitMode,\n\t\t\t\t\t   const int XDim,\n\t\t\t\t\t   const int YDim,\n\t\t\t\t\t   const int AssumeImageTiles,\n\t\t\t\t\t   unsigned char* pResultImage)\n{\n\tint x, y;\n\tint i, j;\n\n\tint BlkX, BlkY;\n\tint BlkXp1, BlkYp1;\n\tint XBlockSize;\n\tint BlkXDim, BlkYDim;\n\n\tint StartX, StartY;\n\n\tint ModulationVals[8][16];\n\tint ModulationModes[8][16];\n\n\tint Mod, DoPT;\n\n\tunsigned int uPosition;\n\n\t/*\n\t// local neighbourhood of blocks\n\t*/\n\tAMTC_BLOCK_STRUCT *pBlocks[2][2];\n\n\tAMTC_BLOCK_STRUCT *pPrevious[2][2] = {{NULL, NULL}, {NULL, NULL}};\n\n\t/*\n\t// Low precision colours extracted from the blocks\n\t*/\n\tstruct\n\t{\n\t\tint Reps[2][4];\n\t}Colours5554[2][2];\n\n\t/*\n\t// Interpolated A and B colours for the pixel\n\t*/\n\tint ASig[4], BSig[4];\n\n\tint Result[4];\n\n\tif(Do2bitMode)\n\t{\n\t\tXBlockSize = BLK_X_2BPP;\n\t}\n\telse\n\t{\n\t\tXBlockSize = BLK_X_4BPP;\n\t}\n\n\n\t/*\n\t// For MBX don't allow the sizes to get too small\n\t*/\n\tBlkXDim = PVRT_MAX(2, XDim / XBlockSize);\n\tBlkYDim = PVRT_MAX(2, YDim / BLK_Y_SIZE);\n\n\t/*\n\t// Step through the pixels of the image decompressing each one in turn\n\t//\n\t// Note that this is a hideously inefficient way to do this!\n\t*/\n\tfor(y = 0; y < YDim; y++)\n\t{\n\t\tfor(x = 0; x < XDim; x++)\n\t\t{\n\t\t\t/*\n\t\t\t// map this pixel to the top left neighbourhood of blocks\n\t\t\t*/\n\t\t\tBlkX = (x - XBlockSize/2);\n\t\t\tBlkY = (y - BLK_Y_SIZE/2);\n\n\t\t\tBlkX = LIMIT_COORD(BlkX, XDim, AssumeImageTiles);\n\t\t\tBlkY = LIMIT_COORD(BlkY, YDim, AssumeImageTiles);\n\n\n\t\t\tBlkX /= XBlockSize;\n\t\t\tBlkY /= BLK_Y_SIZE;\n\n\t\t\t//BlkX = LIMIT_COORD(BlkX, BlkXDim, AssumeImageTiles);\n\t\t\t//BlkY = LIMIT_COORD(BlkY, BlkYDim, AssumeImageTiles);\n\n\n\t\t\t/*\n\t\t\t// compute the positions of the other 3 blocks\n\t\t\t*/\n\t\t\tBlkXp1 = LIMIT_COORD(BlkX+1, BlkXDim, AssumeImageTiles);\n\t\t\tBlkYp1 = LIMIT_COORD(BlkY+1, BlkYDim, AssumeImageTiles);\n\n\t\t\t/*\n\t\t\t// Map to block memory locations\n\t\t\t*/\n\t\t\tpBlocks[0][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkX);\n\t\t\tpBlocks[0][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkY, BlkXp1);\n\t\t\tpBlocks[1][0] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkX);\n\t\t\tpBlocks[1][1] = pCompressedData +TwiddleUV(BlkYDim, BlkXDim, BlkYp1, BlkXp1);\n\n\n\t\t\t/*\n\t\t\t// extract the colours and the modulation information IF the previous values\n\t\t\t// have changed.\n\t\t\t*/\n\t\t\tif(memcmp(pPrevious, pBlocks, 4*sizeof(void*)) != 0)\n\t\t\t{\n\t\t\t\tStartY = 0;\n\t\t\t\tfor(i = 0; i < 2; i++)\n\t\t\t\t{\n\t\t\t\t\tStartX = 0;\n\t\t\t\t\tfor(j = 0; j < 2; j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tUnpack5554Colour(pBlocks[i][j], Colours5554[i][j].Reps);\n\n\t\t\t\t\t\tUnpackModulations(pBlocks[i][j],\n\t\t\t\t\t\t\tDo2bitMode,\n\t\t\t\t\t\t\tModulationVals,\n\t\t\t\t\t\t\tModulationModes,\n\t\t\t\t\t\t\tStartX, StartY);\n\n\t\t\t\t\t\tStartX += XBlockSize;\n\t\t\t\t\t}/*end for j*/\n\n\t\t\t\t\tStartY += BLK_Y_SIZE;\n\t\t\t\t}/*end for i*/\n\n\t\t\t\t/*\n\t\t\t\t// make a copy of the new pointers\n\t\t\t\t*/\n\t\t\t\tmemcpy(pPrevious, pBlocks, 4*sizeof(void*));\n\t\t\t}/*end if the blocks have changed*/\n\n\n\t\t\t/*\n\t\t\t// decompress the pixel.  First compute the interpolated A and B signals\n\t\t\t*/\n\t\t\tInterpolateColours(Colours5554[0][0].Reps[0],\n\t\t\t\tColours5554[0][1].Reps[0],\n\t\t\t\tColours5554[1][0].Reps[0],\n\t\t\t\tColours5554[1][1].Reps[0],\n\t\t\t\tDo2bitMode, x, y,\n\t\t\t\tASig);\n\n\t\t\tInterpolateColours(Colours5554[0][0].Reps[1],\n\t\t\t\tColours5554[0][1].Reps[1],\n\t\t\t\tColours5554[1][0].Reps[1],\n\t\t\t\tColours5554[1][1].Reps[1],\n\t\t\t\tDo2bitMode, x, y,\n\t\t\t\tBSig);\n\n\t\t\tGetModulationValue(x,y, Do2bitMode, (const int (*)[16])ModulationVals, (const int (*)[16])ModulationModes,\n\t\t\t\t&Mod, &DoPT);\n\n\t\t\t/*\n\t\t\t// compute the modulated colour\n\t\t\t*/\n\t\t\tfor(i = 0; i < 4; i++)\n\t\t\t{\n\t\t\t\tResult[i] = ASig[i] * 8 + Mod * (BSig[i] - ASig[i]);\n\t\t\t\tResult[i] >>= 3;\n\t\t\t}\n\t\t\tif(DoPT)\n\t\t\t{\n\t\t\t\tResult[3] = 0;\n\t\t\t}\n\n\t\t\t/*\n\t\t\t// Store the result in the output image\n\t\t\t*/\n\t\t\tuPosition = (x+y*XDim)<<2;\n\t\t\tpResultImage[uPosition+0] = (unsigned char)Result[0];\n\t\t\tpResultImage[uPosition+1] = (unsigned char)Result[1];\n\t\t\tpResultImage[uPosition+2] = (unsigned char)Result[2];\n\t\t\tpResultImage[uPosition+3] = (unsigned char)Result[3];\n\n\t\t}/*end for x*/\n\t}/*end for y*/\n\n}\n\nstatic void * stbi__pvr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n\tstbi_uc *pvr_data = NULL;\n\tstbi_uc *pvr_res_data = NULL;\n\tPVR_Texture_Header header={0};\n\tint iscompressed = 0;\n\tint bitmode = 0;\n\tunsigned int levelSize = 0;\n\n\tstbi__getn( s, (stbi_uc*)(&header), sizeof(PVR_Texture_Header) );\n\n\t// Check the header size\n\tif ( header.dwHeaderSize != sizeof(PVR_Texture_Header) ) {\n\t\treturn NULL;\n\t}\n\n\t// Check the magic identifier\n\tif ( header.dwPVR != PVRTEX_IDENTIFIER ) {\n\t\treturn NULL;\n\t}\n\n\t*x = s->img_x = header.dwWidth;\n\t*y = s->img_y = header.dwHeight;\n\n\t/* Get if the texture is compressed and the texture mode ( 2bpp or 4bpp ) */\n\tswitch ( header.dwpfFlags & PVRTEX_PIXELTYPE )\n\t{\n\t\tcase OGL_RGBA_4444:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_RGBA_5551:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_RGBA_8888:\n\t\t\ts->img_n = 4;\n\t\t\tbreak;\n\t\tcase OGL_RGB_565:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_RGB_888:\n\t\t\ts->img_n = 3;\n\t\t\tbreak;\n\t\tcase OGL_I_8:\n\t\t\ts->img_n = 1;\n\t\t\tbreak;\n\t\tcase OGL_AI_88:\n\t\t\ts->img_n = 2;\n\t\t\tbreak;\n\t\tcase OGL_PVRTC2:\n\t\t\tbitmode = 1;\n\t\t\ts->img_n = 4;\n\t\t\tiscompressed = 1;\n\t\t\tbreak;\n\t\tcase OGL_PVRTC4:\n\t\t\ts->img_n = 4;\n\t\t\tiscompressed = 1;\n\t\t\tbreak;\n\t\tcase OGL_RGB_555:\n\t\tdefault:\n\t\t\treturn NULL;\n\t}\n\n\t*comp = s->img_n;\n\n\t// Load only the first mip map level\n\tlevelSize = (s->img_x * s->img_y * header.dwBitCount + 7) / 8;\n\n\t// get the raw data\n\tpvr_data = (stbi_uc *)malloc( levelSize );\n\tstbi__getn( s, pvr_data, levelSize );\n\n\t// if compressed decompress as RGBA\n\tif ( iscompressed ) {\n\t\tpvr_res_data = (stbi_uc *)malloc( s->img_x * s->img_y * 4 );\n\t\tDecompress( (AMTC_BLOCK_STRUCT*)pvr_data, bitmode, s->img_x, s->img_y, 1, (unsigned char*)pvr_res_data );\n\t\tfree( pvr_data );\n\t} else {\n\t\t// otherwise use the raw data\n\t\tpvr_res_data = pvr_data;\n\t}\n\n\tif( (req_comp <= 4) && (req_comp >= 1) ) {\n\t\t//\tuser has some requirements, meet them\n\t\tif( req_comp != s->img_n ) {\n\t\t\tpvr_res_data = stbi__convert_format( pvr_res_data, s->img_n, req_comp, s->img_x, s->img_y );\n\t\t\t*comp = req_comp;\n\t\t}\n\t}\n\n\treturn pvr_res_data;\n}\n\n#ifndef STBI_NO_STDIO\nvoid *stbi__pvr_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n\tstbi__start_file(&s,f);\n\treturn stbi__pvr_load(&s,x,y,comp,req_comp);\n}\n\nvoid *stbi__pvr_load_from_path             (char const*filename,           int *x, int *y, int *comp, int req_comp)\n{\n   void *data;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return NULL;\n   data = stbi__pvr_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return data;\n}\n#endif\n\nvoid *stbi__pvr_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__pvr_load(&s,x,y,comp,req_comp);\n}\n\nvoid *stbi__pvr_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n\tstbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__pvr_load(&s,x,y,comp,req_comp);\n}\n"
  },
  {
    "path": "lib/SOIL2/stbi_qoi.h",
    "content": "/*\n\tadding QOI loading support to stbi\n*/\n\n#ifndef HEADER_STB_IMAGE_QOI_AUGMENTATION\n#define HEADER_STB_IMAGE_QOI_AUGMENTATION\n\n/*\tis it a QOI file? */\nextern int      stbi__qoi_test_memory      (stbi_uc const *buffer, int len);\nextern int      stbi__qoi_test_callbacks   (stbi_io_callbacks const *clbk, void *user);\n\nextern void    *stbi__qoi_load_from_path   (char const *filename,           int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__qoi_load_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);\nextern void    *stbi__qoi_load_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__qoi_test_filename    (char const *filename);\nextern int      stbi__qoi_test_file        (FILE *f);\nextern void    *stbi__qoi_load_from_file   (FILE *f,                  int *x, int *y, int *comp, int req_comp);\n#endif\n\nextern int      stbi__qoi_info_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nextern int      stbi__qoi_info_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\n\n\n#ifndef STBI_NO_STDIO\nextern int      stbi__qoi_info_from_path   (char const *filename,     int *x, int *y, int *comp);\nextern int      stbi__qoi_info_from_file   (FILE *f,                  int *x, int *y, int *comp);\n#endif\n\n/*\n//\n////   end header file   /////////////////////////////////////////////////////*/\n#endif /* HEADER_STB_IMAGE_QOI_AUGMENTATION */\n\n"
  },
  {
    "path": "lib/SOIL2/stbi_qoi_c.h",
    "content": "\nstatic int stbi__qoi_test(stbi__context *s)\n{\n   int i;\n   for (i = 0; i < 4; i++) {\n      if (stbi__get8(s) != \"qoif\"[i]) {\n         stbi__rewind(s);\n         return 0;\n      }\n   }\n   return 1;\n}\n\n#ifndef STBI_NO_STDIO\n\nint stbi__qoi_test_filename(char const *filename)\n{\n   int r;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   r = stbi__qoi_test_file(f);\n   fclose(f);\n   return r;\n}\n\nint stbi__qoi_test_file(FILE *f)\n{\n   stbi__context s;\n   int r,n = ftell(f);\n   stbi__start_file(&s,f);\n   r = stbi__qoi_test(&s);\n   fseek(f,n,SEEK_SET);\n   return r;\n}\n#endif\n\nint      stbi__qoi_test_memory      (stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__qoi_test(&s);\n}\n\nint      stbi__qoi_test_callbacks      (stbi_io_callbacks const *clbk, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__qoi_test(&s);\n}\n\nstatic int stbi__qoi_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__uint32 length;\n\n   stbi__rewind(s);\n\n   int i;\n   for (i = 0; i < 4; i++) {\n      if (stbi__get8(s) != \"qoif\"[i]) {\n         stbi__rewind(s);\n         return 0;\n      }\n   }\n\n   length = stbi__get32be(s);\n   if (x) *x = (int)length;\n\n   length = stbi__get32be(s);\n   if (y) *y = (int)length;\n\n   int channels   = stbi__get8(s);       // 3 = RGB, 4 = RGBA\n   int colorspace = stbi__get8(s) != 0;  // 0 = sRGB with linear alpha, 1 = all channels linear\n\n   if (comp) *comp = channels;\n\n   return 1 + colorspace;\n}\n\nint stbi__qoi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp )\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__qoi_info( &s, x, y, comp );\n}\n\nint stbi__qoi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__qoi_info( &s, x, y, comp );\n}\n\n#ifndef STBI_NO_STDIO\nint stbi__qoi_info_from_path(char const *filename, int *x, int *y, int *comp)\n{\n   int res;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return 0;\n   res = stbi__qoi_info_from_file( f, x, y, comp );\n   fclose(f);\n   return res;\n}\n\nint stbi__qoi_info_from_file(FILE *f, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   int res;\n   long n = ftell(f);\n   stbi__start_file(&s, f);\n   res = stbi__qoi_info(&s, x, y, comp);\n   fseek(f, n, SEEK_SET);\n   return res;\n}\n#endif\n\nstatic void *stbi__qoi_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   if (!stbi__qoi_info(s, (int*)&s->img_x, (int*)&s->img_y, &s->img_n))\n      return NULL;\n\n   if (req_comp == 3 || req_comp == 4)\n      s->img_n = req_comp;\n\n   if (x) *x = s->img_x;\n   if (y) *y = s->img_y;\n   if (comp) *comp = s->img_n;\n\n   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0))\n      return stbi__errpuc(\"too large\", \"QOI too large\");\n\n   stbi_uc *out = (stbi_uc *) stbi__malloc_mad3(s->img_x, s->img_y, s->img_n, 0);\n   if (!out)\n      return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   stbi_uc *dst = out;\n   stbi_uc *end = &dst[s->img_x * s->img_y * s->img_n];\n\n   stbi__uint32 c = 255;\n   stbi__uint32 recent[0x40];\n   memset(recent, 0, 0x40*sizeof(stbi__uint32));\n\n   while (dst < end) {\n      stbi_uc tag = stbi__get8(s);\n      if (tag == 0xfe) {\n         stbi__uint32 rgb =\n            ((stbi__uint32) stbi__get8(s) << 24) |\n            ((stbi__uint32) stbi__get8(s) << 16) |\n            ((stbi__uint32) stbi__get8(s) << 8);\n         c = (c & 0xff) | rgb;\n      }\n      else if (tag == 0xff) {\n         c =\n            ((stbi__uint32) stbi__get8(s) << 24) |\n            ((stbi__uint32) stbi__get8(s) << 16) |\n            ((stbi__uint32) stbi__get8(s) << 8) |\n            (stbi__uint32) stbi__get8(s);\n      }\n      else if ((tag >> 6) == 0) {\n         c = recent[tag];\n      }\n      else if ((tag >> 6) == 1) {\n         stbi_uc r = (c >> 24) + ((tag >> 4) & 3) - 2;\n         stbi_uc g = (c >> 16) + ((tag >> 2) & 3) - 2;\n         stbi_uc b = (c >> 8)  + (tag & 3) - 2;\n         c = (c & 0xff) | ((stbi__uint32) r << 24) | ((stbi__uint32) g << 16) | ((stbi__uint32) b << 8);\n      }\n      else if ((tag >> 6) == 2) {\n         stbi_uc rb = stbi__get8(s);\n         stbi_uc dg = (tag & 0x3f) - 32;\n         stbi_uc r = (c >> 24) + dg + (rb >> 4) - 8;\n         stbi_uc g = (c >> 16) + dg;\n         stbi_uc b = (c >> 8)  + dg + (rb & 0xf) - 8;\n         c = (c & 0xff) | ((stbi__uint32) r << 24) | ((stbi__uint32) g << 16) | ((stbi__uint32) b << 8);\n      }\n      else {\n         int run = tag & 0x3f;\n         if (&dst[run * s->img_n] > end)\n            break;\n\n         if (s->img_n == 3) {\n            int i;\n            for (i = 0; i < run; i++) {\n               *dst++ = c >> 24;\n               *dst++ = c >> 16;\n               *dst++ = c >> 8;\n            }\n         }\n         else {\n            int i;\n            for (i = 0; i < run; i++) {\n               *dst++ = c >> 24;\n               *dst++ = c >> 16;\n               *dst++ = c >> 8;\n               *dst++ = c;\n            }\n         }\n      }\n\n      *dst++ = c >> 24;\n      *dst++ = c >> 16;\n      *dst++ = c >> 8;\n      if (s->img_n != 3) *dst++ = c;\n\n      recent[0x3f & (\n         ((c >> 24) & 0xff) * 3u +\n         ((c >> 16) & 0xff) * 5u +\n         ((c >>  8) & 0xff) * 7u +\n         (c & 0xff) * 11u\n      )] = c;\n   }\n\n   if (req_comp)\n      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);\n\n   return out;\n}\n\n#ifndef STBI_NO_STDIO\nvoid *stbi__qoi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__result_info ri;\n   stbi__start_file(&s,f);\n   return stbi__qoi_load(&s,x,y,comp,req_comp,&ri);\n}\n\nvoid *stbi__qoi_load_from_path(char const*filename, int *x, int *y, int *comp, int req_comp)\n{\n   void *data;\n   FILE *f = fopen(filename, \"rb\");\n   if (!f) return NULL;\n   data = stbi__qoi_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return data;\n}\n#endif\n\nvoid *stbi__qoi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__result_info ri;\n   stbi__start_mem(&s,buffer, len);\n   return stbi__qoi_load(&s,x,y,comp,req_comp,&ri);\n}\n\nvoid *stbi__qoi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__result_info ri;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__qoi_load(&s,x,y,comp,req_comp,&ri);\n}\n"
  },
  {
    "path": "lib/SOIL2/stbi_qoi_write.h",
    "content": "\n#ifndef NULL\n#define NULL 0\n#endif\n\n#define QOI_SRGB   0\n#define QOI_LINEAR 1\n\ntypedef struct {\n   unsigned int width;\n   unsigned int height;\n   unsigned char channels;\n   unsigned char colorspace;\n} qoi_desc;\n\n#ifndef QOI_ZEROARR\n   #define QOI_ZEROARR(a) memset((a),0,sizeof(a))\n#endif\n\n#define QOI_OP_INDEX  0x00 /* 00xxxxxx */\n#define QOI_OP_DIFF   0x40 /* 01xxxxxx */\n#define QOI_OP_LUMA   0x80 /* 10xxxxxx */\n#define QOI_OP_RUN    0xc0 /* 11xxxxxx */\n#define QOI_OP_RGB    0xfe /* 11111110 */\n#define QOI_OP_RGBA   0xff /* 11111111 */\n\n#define QOI_COLOR_HASH(C) (C.rgba.r*3 + C.rgba.g*5 + C.rgba.b*7 + C.rgba.a*11)\n#define QOI_MAGIC \\\n   (((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \\\n    ((unsigned int)'i') <<  8 | ((unsigned int)'f'))\n#define QOI_HEADER_SIZE 14\n\n/* 2GB is the max file size that this implementation can safely handle. We guard\nagainst anything larger than that, assuming the worst case with 5 bytes per\npixel, rounded down to a nice clean value. 400 million pixels ought to be\nenough for anybody. */\n#define QOI_PIXELS_MAX ((unsigned int)400000000)\n\ntypedef union {\n   struct { unsigned char r, g, b, a; } rgba;\n   unsigned int v;\n} qoi_rgba_t;\n\nstatic const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1};\n\nstatic void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {\n   bytes[(*p)++] = (0xff000000 & v) >> 24;\n   bytes[(*p)++] = (0x00ff0000 & v) >> 16;\n   bytes[(*p)++] = (0x0000ff00 & v) >> 8;\n   bytes[(*p)++] = (0x000000ff & v);\n}\n\nstatic void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {\n   int i, max_size, p, run;\n   int px_len, px_end, px_pos, channels;\n   unsigned char *bytes;\n   const unsigned char *pixels;\n   qoi_rgba_t index[64];\n   qoi_rgba_t px, px_prev;\n\n   if (\n      data == NULL || out_len == NULL || desc == NULL ||\n      desc->width == 0 || desc->height == 0 ||\n      desc->channels < 3 || desc->channels > 4 ||\n      desc->colorspace > 1 ||\n      desc->height >= QOI_PIXELS_MAX / desc->width\n   ) {\n      return NULL;\n   }\n\n   max_size =\n      desc->width * desc->height * (desc->channels + 1) +\n      QOI_HEADER_SIZE + sizeof(qoi_padding);\n\n   p = 0;\n   bytes = (unsigned char *) STBIW_MALLOC(max_size);\n   if (!bytes) {\n      return NULL;\n   }\n\n   qoi_write_32(bytes, &p, QOI_MAGIC);\n   qoi_write_32(bytes, &p, desc->width);\n   qoi_write_32(bytes, &p, desc->height);\n   bytes[p++] = desc->channels;\n   bytes[p++] = desc->colorspace;\n\n\n   pixels = (const unsigned char *)data;\n\n   QOI_ZEROARR(index);\n\n   run = 0;\n   px_prev.rgba.r = 0;\n   px_prev.rgba.g = 0;\n   px_prev.rgba.b = 0;\n   px_prev.rgba.a = 255;\n   px = px_prev;\n\n   px_len = desc->width * desc->height * desc->channels;\n   px_end = px_len - desc->channels;\n   channels = desc->channels;\n\n   for (px_pos = 0; px_pos < px_len; px_pos += channels) {\n      px.rgba.r = pixels[px_pos + 0];\n      px.rgba.g = pixels[px_pos + 1];\n      px.rgba.b = pixels[px_pos + 2];\n\n      if (channels == 4) {\n         px.rgba.a = pixels[px_pos + 3];\n      }\n\n      if (px.v == px_prev.v) {\n         run++;\n         if (run == 62 || px_pos == px_end) {\n            bytes[p++] = QOI_OP_RUN | (run - 1);\n            run = 0;\n         }\n      }\n      else {\n         int index_pos;\n\n         if (run > 0) {\n            bytes[p++] = QOI_OP_RUN | (run - 1);\n            run = 0;\n         }\n\n         index_pos = QOI_COLOR_HASH(px) % 64;\n\n         if (index[index_pos].v == px.v) {\n            bytes[p++] = QOI_OP_INDEX | index_pos;\n         }\n         else {\n            index[index_pos] = px;\n\n            if (px.rgba.a == px_prev.rgba.a) {\n               signed char vr = px.rgba.r - px_prev.rgba.r;\n               signed char vg = px.rgba.g - px_prev.rgba.g;\n               signed char vb = px.rgba.b - px_prev.rgba.b;\n\n               signed char vg_r = vr - vg;\n               signed char vg_b = vb - vg;\n\n               if (\n                  vr > -3 && vr < 2 &&\n                  vg > -3 && vg < 2 &&\n                  vb > -3 && vb < 2\n               ) {\n                  bytes[p++] = QOI_OP_DIFF | (vr + 2) << 4 | (vg + 2) << 2 | (vb + 2);\n               }\n               else if (\n                  vg_r >  -9 && vg_r <  8 &&\n                  vg   > -33 && vg   < 32 &&\n                  vg_b >  -9 && vg_b <  8\n               ) {\n                  bytes[p++] = QOI_OP_LUMA     | (vg   + 32);\n                  bytes[p++] = (vg_r + 8) << 4 | (vg_b +  8);\n               }\n               else {\n                  bytes[p++] = QOI_OP_RGB;\n                  bytes[p++] = px.rgba.r;\n                  bytes[p++] = px.rgba.g;\n                  bytes[p++] = px.rgba.b;\n               }\n            }\n            else {\n               bytes[p++] = QOI_OP_RGBA;\n               bytes[p++] = px.rgba.r;\n               bytes[p++] = px.rgba.g;\n               bytes[p++] = px.rgba.b;\n               bytes[p++] = px.rgba.a;\n            }\n         }\n      }\n      px_prev = px;\n   }\n\n   for (i = 0; i < (int)sizeof(qoi_padding); i++) {\n      bytes[p++] = qoi_padding[i];\n   }\n\n   *out_len = p;\n   return bytes;\n}\n\nstatic int stbi_write_qoi_core(stbi__write_context *s, int x, int y, int comp, const void*data)\n{\n   if (y <= 0 || x <= 0 || data == NULL)\n      return 0;\n   qoi_desc desc;\n   desc.width = x;\n   desc.height = y;\n   desc.channels = comp;\n   desc.colorspace = QOI_LINEAR;\n   int out_len = 0;\n   void* res = qoi_encode(data, &desc, &out_len);\n   if (res != NULL)\n      s->func(s->context, res, out_len);\n   return res != NULL ? 1 : 0;\n}\n\nSTBIWDEF int stbi_write_qoi_to_func(stbi_write_func *func, void *context, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   stbi__start_write_callbacks(&s, func, context);\n   return stbi_write_qoi_core(&s, x, y, comp, (void *) data);\n}\n\n#ifndef STBI_WRITE_NO_STDIO\nSTBIWDEF int stbi_write_qoi(char const *filename, int x, int y, int comp, const void *data)\n{\n   stbi__write_context s = { 0 };\n   if (stbi__start_write_file(&s,filename)) {\n      int r = stbi_write_qoi_core(&s, x, y, comp, (void *) data);\n      stbi__end_write_file(&s);\n      return r;\n   } else\n      return 0;\n}\n#endif\n"
  },
  {
    "path": "lib/SOIL2/wfETC.c",
    "content": "\n#include \"wfETC.h\"\n\n// specification: http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt\n\n#ifdef WF_LITTLE_ENDIAN\n\t#define WF_ETC1_COLOR_OFFSET( offset ) ( (64-(offset)) - (4-((offset)%8))*2 )\n\t#define WF_ETC1_PIXEL_OFFSET( offset ) ( (32-(offset)) - (4-((offset)%8))*2 )\n#else\n\t#define WF_ETC1_COLOR_OFFSET( offset ) (offset-32)\n\t#define WF_ETC1_PIXEL_OFFSET( offset ) offset\n#endif\n\n#define WF_INLINE\n#define WF_ASSUME( expr )\n\n#ifndef WF_EXPECT\n\t#if defined __GNUC__ && __GNUC__\n\t\t#define WF_EXPECT( expr, val ) __builtin_expect( expr, val )\n\t#else\n\t\t#define WF_EXPECT( expr, val ) expr\n\t#endif\n#endif\n\n// this table is rearranged from the specification so we do not have to add any logic to index into it\nconst int32_t wfETC_IntensityTables[8][4] = \n{\n\t{  2,   8,  -2, -8   },\n\t{  5,  17,  -5, -17  },\n\t{  9,  29,  -9, -29  },\n\t{ 13,  42, -13, -42  },\n\t{ 18,  60, -18, -60  },\n\t{ 24,  80, -24, -80  },\n\t{ 33, 106, -33, -106 },\n\t{ 47, 183, -47, -183 }\n};\n\nWF_INLINE\nint32_t wfETC_ClampColor( const int32_t x )\n{\n\tif( x < 0   ) { return 0; }\n\tif( x > 255 ) { return 255; }\n\treturn x;\n}\n\n#define WF_ETC1_BUILD_COLOR( dst, blockIdx, colorIdx, intensityTable, baseColor ) \\\n\tdst[ blockIdx ][ colorIdx ] = WF_ETC_RGBA( \\\n\t\twfETC_ClampColor( intensityTable[ blockIdx ][ colorIdx ] + baseColor[ blockIdx ][ 0 ] ), \\\n\t\twfETC_ClampColor( intensityTable[ blockIdx ][ colorIdx ] + baseColor[ blockIdx ][ 1 ] ), \\\n\t\twfETC_ClampColor( intensityTable[ blockIdx ][ colorIdx ] + baseColor[ blockIdx ][ 2 ] ), \\\n\t\t255 \\\n\t);\n\ntypedef struct _wfETC1_Block\n{\n\tint32_t baseColorsAndFlags;\n\tint32_t pixels;\n} wfETC1_Block;\n\n#define WF_ETC1_CHECK_DIFF_BIT( block ) ( block->baseColorsAndFlags & (1<<WF_ETC1_COLOR_OFFSET(33)) )\n#define WF_ETC1_CHECK_FLIP_BIT( block ) ( block->baseColorsAndFlags & (1<<WF_ETC1_COLOR_OFFSET(32)) )\n\nWF_INLINE\nint32_t wfETC1_ReadColor4( const wfETC1_Block* block, const uint32_t offset )\n{\n\tconst uint32_t bitOffset = WF_ETC1_COLOR_OFFSET(offset);\n\tconst int32_t color = ( block->baseColorsAndFlags >> bitOffset ) & 0xf;\n\treturn color | (color<<4);\n}\n\nconst int32_t wfETC1_Color3IdxLUT[] = { 0, 1, 2, 3, -4, -3, -2, -1 };\n\nWF_INLINE\nvoid wfETC1_ReadColor53( const wfETC1_Block* block, const uint32_t offset3, int32_t* WF_RESTRICT dst5, int32_t* WF_RESTRICT dst3 )\n{\n\t// read the 5 bit color and expand to 8 bit\n\t{\n\t\tconst uint32_t bitOffset = WF_ETC1_COLOR_OFFSET((offset3+3));\n\t\tconst int32_t color = ( block->baseColorsAndFlags >> (bitOffset-3) ) & 0xf8;\n\t\t*dst5 = color | (color>>5);\n\t}\n\n\t// read the 3 bit color and expand to 8 bit\n\t{\n\t\tconst uint32_t bitOffset = WF_ETC1_COLOR_OFFSET(offset3);\n\t\tconst int32_t offset = wfETC1_Color3IdxLUT[ ( block->baseColorsAndFlags >> bitOffset ) & 0x7 ];\n\t\tint32_t color = (*dst5>>3) + offset;\n\t\tcolor <<= 3;\n\t\tcolor |= (color>>5) & 0x7;\n\t\t*dst3 = color;\n\t}\n}\n\nWF_INLINE\nint32_t wfETC1_ReadPixel( const wfETC1_Block* block, const uint32_t offset )\n{\n\treturn\n\t\t(  (block->pixels>>WF_ETC1_PIXEL_OFFSET(offset)) & 0x1  )\n\t\t|\n\t\t(  ( (block->pixels>>WF_ETC1_PIXEL_OFFSET(16+offset)) & 0x1 ) << 1 )\n\t;\n}\n\nvoid wfETC1_DecodeBlock( const void* WF_RESTRICT src, void* WF_RESTRICT pDst, const uint32_t dstStride )\n{\n\tconst wfETC1_Block* WF_RESTRICT block = ( wfETC1_Block* )src;\n\tint32_t* WF_RESTRICT dst = (int32_t*)pDst;\n\n\tint32_t baseColors[2][3]; // [sub-block][r,g,b]\n\tint32_t colors[2][4]; // [sub-block][colorIdx]\n\n\t// individual mode\n\tif( WF_ETC1_CHECK_DIFF_BIT( block ) == 0 )\n\t{\n\t\tbaseColors[0][0] = wfETC1_ReadColor4( block, 60 );\n\t\tbaseColors[0][1] = wfETC1_ReadColor4( block, 52 );\n\t\tbaseColors[0][2] = wfETC1_ReadColor4( block, 44 );\n\t\tbaseColors[1][0] = wfETC1_ReadColor4( block, 56 );\n\t\tbaseColors[1][1] = wfETC1_ReadColor4( block, 48 );\n\t\tbaseColors[1][2] = wfETC1_ReadColor4( block, 40 );\n\t}\n\t// differential mode\n\telse\n\t{\n\t\twfETC1_ReadColor53( block, 56, &baseColors[0][0], &baseColors[1][0] );\n\t\twfETC1_ReadColor53( block, 48, &baseColors[0][1], &baseColors[1][1] );\n\t\twfETC1_ReadColor53( block, 40, &baseColors[0][2], &baseColors[1][2] );\n\t}\n\n\t// build color tables\n\t{\n\t\tconst int32_t* intensityTable[2] = // [sub-block]\n\t\t{\n\t\t\twfETC_IntensityTables[ ( block->baseColorsAndFlags >> WF_ETC1_COLOR_OFFSET(37) ) & 0x7 ],\n\t\t\twfETC_IntensityTables[ ( block->baseColorsAndFlags >> WF_ETC1_COLOR_OFFSET(34) ) & 0x7 ]\n\t\t};\n\t\tWF_ETC1_BUILD_COLOR( colors, 0, 0, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 0, 1, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 0, 2, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 0, 3, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 1, 0, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 1, 1, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 1, 2, intensityTable, baseColors );\n\t\tWF_ETC1_BUILD_COLOR( colors, 1, 3, intensityTable, baseColors );\n\t}\n\n\t// vertical split\n\tif( WF_ETC1_CHECK_FLIP_BIT( block ) == 0 )\n\t{\n\t\t// row 0\n\t\tdst[0] = colors[0][ wfETC1_ReadPixel( block, 0  ) ];\n\t\tdst[1] = colors[0][ wfETC1_ReadPixel( block, 4  ) ];\n\t\tdst[2] = colors[1][ wfETC1_ReadPixel( block, 8  ) ];\n\t\tdst[3] = colors[1][ wfETC1_ReadPixel( block, 12 ) ];\n\t\tdst += dstStride;\n\n\t\t// row 1\n\t\tdst[0] = colors[0][ wfETC1_ReadPixel( block, 1  ) ];\n\t\tdst[1] = colors[0][ wfETC1_ReadPixel( block, 5  ) ];\n\t\tdst[2] = colors[1][ wfETC1_ReadPixel( block, 9  ) ];\n\t\tdst[3] = colors[1][ wfETC1_ReadPixel( block, 13 ) ];\n\t\tdst += dstStride;\n\n\t\t// row 2\n\t\tdst[0] = colors[0][ wfETC1_ReadPixel( block, 2  ) ];\n\t\tdst[1] = colors[0][ wfETC1_ReadPixel( block, 6  ) ];\n\t\tdst[2] = colors[1][ wfETC1_ReadPixel( block, 10 ) ];\n\t\tdst[3] = colors[1][ wfETC1_ReadPixel( block, 14 ) ];\n\t\tdst += dstStride;\n\n\t\t// row 3\n\t\tdst[0] = colors[0][ wfETC1_ReadPixel( block, 3  ) ];\n\t\tdst[1] = colors[0][ wfETC1_ReadPixel( block, 7  ) ];\n\t\tdst[2] = colors[1][ wfETC1_ReadPixel( block, 11 ) ];\n\t\tdst[3] = colors[1][ wfETC1_ReadPixel( block, 15 ) ];\n\t\t//dst += dstStride;\n\t}\n\t// horizontal split\n\telse\n\t{\n\t\t// row 0\n\t\tdst[0] = colors[0][ wfETC1_ReadPixel( block, 0  ) ];\n\t\tdst[1] = colors[0][ wfETC1_ReadPixel( block, 4  ) ];\n\t\tdst[2] = colors[0][ wfETC1_ReadPixel( block, 8  ) ];\n\t\tdst[3] = colors[0][ wfETC1_ReadPixel( block, 12 ) ];\n\t\tdst += dstStride;\n\n\t\t// row 1\n\t\tdst[0] = colors[0][ wfETC1_ReadPixel( block, 1  ) ];\n\t\tdst[1] = colors[0][ wfETC1_ReadPixel( block, 5  ) ];\n\t\tdst[2] = colors[0][ wfETC1_ReadPixel( block, 9  ) ];\n\t\tdst[3] = colors[0][ wfETC1_ReadPixel( block, 13 ) ];\n\t\tdst += dstStride;\n\n\t\t// row 2\n\t\tdst[0] = colors[1][ wfETC1_ReadPixel( block, 2  ) ];\n\t\tdst[1] = colors[1][ wfETC1_ReadPixel( block, 6  ) ];\n\t\tdst[2] = colors[1][ wfETC1_ReadPixel( block, 10 ) ];\n\t\tdst[3] = colors[1][ wfETC1_ReadPixel( block, 14 ) ];\n\t\tdst += dstStride;\n\n\t\t// row 3\n\t\tdst[0] = colors[1][ wfETC1_ReadPixel( block, 3  ) ];\n\t\tdst[1] = colors[1][ wfETC1_ReadPixel( block, 7  ) ];\n\t\tdst[2] = colors[1][ wfETC1_ReadPixel( block, 11 ) ];\n\t\tdst[3] = colors[1][ wfETC1_ReadPixel( block, 15 ) ];\n\t\t//dst += dstStride;\n\t}\n}\n\nvoid wfETC1_DecodeImage( const void* WF_RESTRICT pSrc, void* WF_RESTRICT pDst, const uint32_t width, const uint32_t height )\n{\n\tconst uint8_t* WF_RESTRICT src = (uint8_t*)pSrc;\n\tuint8_t* WF_RESTRICT dst = (uint8_t*)pDst;\n\tconst uint32_t widthBlocks  = width/4;\n\tconst uint32_t heightBlocks = height/4;\n\tuint32_t x, y;\n\tfor( y = 0; y != heightBlocks; ++y )\n\t{\n\t\tfor( x = 0; x != widthBlocks; ++x )\n\t\t{\n\t\t\twfETC1_DecodeBlock( src, dst, width );\n\t\t\tsrc += 8;\n\t\t\tdst += 16;\n\t\t}\n\t\tdst += width*4*3;\n\t}\n}\n"
  },
  {
    "path": "lib/SOIL2/wfETC.h",
    "content": "#ifndef WF_ETC_H\n#define WF_ETC_H\n\n#define WF_LITTLE_ENDIAN\n\n// Qt ordering\n#define WF_ETC_RGBA( r, g, b, a ) ( ((a)<<24) | ((r)<<16) | ((g)<<8) | (b) ) // colors have been clamped by the time we hit here, so there should be no need to mask\n\n#ifdef _MSC_VER\n\t#if _MSC_VER < 1300\n\t   typedef signed   char  int8_t;\n\t   typedef unsigned char  uint8_t;\n\t   typedef signed   short int16_t;\n\t   typedef unsigned short uint16_t;\n\t   typedef signed   int   int32_t;\n\t   typedef unsigned int   uint32_t;\n\t#else\n\t   typedef signed   __int8  int8_t;\n\t   typedef unsigned __int8  uint8_t;\n\t   typedef signed   __int16 int16_t;\n\t   typedef unsigned __int16 uint16_t;\n\t   typedef signed   __int32 int32_t;\n\t   typedef unsigned __int32 uint32_t;\n\t#endif\n\ttypedef signed   __int64 int64_t;\n\ttypedef unsigned __int64 uint64_t;\n#else\n\t#include <stdint.h>\n#endif\n\n#ifndef WF_RESTRICT\n\t#if defined MSC_VER\n\t\t#define WF_RESTRICT __restrict\n\t#elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L\n\t\t#define WF_RESTRICT restrict\n\t#else\n\t\t#define WF_RESTRICT\n\t#endif\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nextern void wfETC1_DecodeBlock( const void* WF_RESTRICT src, void* WF_RESTRICT dst, const uint32_t dstStride /*=4*/ ); //!< stride in pixels; must be a multiple of four\n\nextern void wfETC1_DecodeImage( const void* WF_RESTRICT src, void* WF_RESTRICT dst, const uint32_t width, const uint32_t height ); //!< width/height in pixels; must be multiples of four\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // WF_ETC_H\n"
  },
  {
    "path": "lib/TinyXML-2/tinyxml2.cpp",
    "content": "/*\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n#include \"tinyxml2.h\"\n\n#include <new>\t\t// yes, this one new style header, is in the Android SDK.\n#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)\n#   include <stddef.h>\n#   include <stdarg.h>\n#else\n#   include <cstddef>\n#   include <cstdarg>\n#endif\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)\n\t// Microsoft Visual Studio, version 2005 and higher. Not WinCE.\n\t/*int _snprintf_s(\n\t   char *buffer,\n\t   size_t sizeOfBuffer,\n\t   size_t count,\n\t   const char *format [,\n\t\t  argument] ...\n\t);*/\n\tstatic inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )\n\t{\n\t\tva_list va;\n\t\tva_start( va, format );\n\t\tconst int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );\n\t\tva_end( va );\n\t\treturn result;\n\t}\n\n\tstatic inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )\n\t{\n\t\tconst int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );\n\t\treturn result;\n\t}\n\n\t#define TIXML_VSCPRINTF\t_vscprintf\n\t#define TIXML_SSCANF\tsscanf_s\n#elif defined _MSC_VER\n\t// Microsoft Visual Studio 2003 and earlier or WinCE\n\t#define TIXML_SNPRINTF\t_snprintf\n\t#define TIXML_VSNPRINTF _vsnprintf\n\t#define TIXML_SSCANF\tsscanf\n\t#if (_MSC_VER < 1400 ) && (!defined WINCE)\n\t\t// Microsoft Visual Studio 2003 and not WinCE.\n\t\t#define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.\n\t#else\n\t\t// Microsoft Visual Studio 2003 and earlier or WinCE.\n\t\tstatic inline int TIXML_VSCPRINTF( const char* format, va_list va )\n\t\t{\n\t\t\tint len = 512;\n\t\t\tfor (;;) {\n\t\t\t\tlen = len*2;\n\t\t\t\tchar* str = new char[len]();\n\t\t\t\tconst int required = _vsnprintf(str, len, format, va);\n\t\t\t\tdelete[] str;\n\t\t\t\tif ( required != -1 ) {\n\t\t\t\t\tTIXMLASSERT( required >= 0 );\n\t\t\t\t\tlen = required;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tTIXMLASSERT( len >= 0 );\n\t\t\treturn len;\n\t\t}\n\t#endif\n#else\n\t// GCC version 3 and higher\n\t//#warning( \"Using sn* functions.\" )\n\t#define TIXML_SNPRINTF\tsnprintf\n\t#define TIXML_VSNPRINTF\tvsnprintf\n\tstatic inline int TIXML_VSCPRINTF( const char* format, va_list va )\n\t{\n\t\tint len = vsnprintf( 0, 0, format, va );\n\t\tTIXMLASSERT( len >= 0 );\n\t\treturn len;\n\t}\n\t#define TIXML_SSCANF   sscanf\n#endif\n\n#if defined(_WIN64)\n\t#define TIXML_FSEEK _fseeki64\n\t#define TIXML_FTELL _ftelli64\n#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)\n\t#define TIXML_FSEEK fseeko\n\t#define TIXML_FTELL ftello\n#elif defined(__ANDROID__) && __ANDROID_API__ > 24\n\t#define TIXML_FSEEK fseeko64\n\t#define TIXML_FTELL ftello64\n#else\n\t#define TIXML_FSEEK fseek\n\t#define TIXML_FTELL ftell\n#endif\n\n\nstatic const char LINE_FEED\t\t\t\t= static_cast<char>(0x0a);\t\t\t// all line endings are normalized to LF\nstatic const char LF = LINE_FEED;\nstatic const char CARRIAGE_RETURN\t\t= static_cast<char>(0x0d);\t\t\t// CR gets filtered out\nstatic const char CR = CARRIAGE_RETURN;\nstatic const char SINGLE_QUOTE\t\t\t= '\\'';\nstatic const char DOUBLE_QUOTE\t\t\t= '\\\"';\n\n// Bunch of unicode info at:\n//\t\thttp://www.unicode.org/faq/utf_bom.html\n//\tef bb bf (Microsoft \"lead bytes\") - designates UTF-8\n\nstatic const unsigned char TIXML_UTF_LEAD_0 = 0xefU;\nstatic const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;\nstatic const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;\n\nnamespace tinyxml2\n{\n\nstruct Entity {\n    const char* pattern;\n    int length;\n    char value;\n};\n\nstatic const int NUM_ENTITIES = 5;\nstatic const Entity entities[NUM_ENTITIES] = {\n    { \"quot\", 4,\tDOUBLE_QUOTE },\n    { \"amp\", 3,\t\t'&'  },\n    { \"apos\", 4,\tSINGLE_QUOTE },\n    { \"lt\",\t2, \t\t'<'\t },\n    { \"gt\",\t2,\t\t'>'\t }\n};\n\n\nStrPair::~StrPair()\n{\n    Reset();\n}\n\n\nvoid StrPair::TransferTo( StrPair* other )\n{\n    if ( this == other ) {\n        return;\n    }\n    // This in effect implements the assignment operator by \"moving\"\n    // ownership (as in auto_ptr).\n\n    TIXMLASSERT( other != 0 );\n    TIXMLASSERT( other->_flags == 0 );\n    TIXMLASSERT( other->_start == 0 );\n    TIXMLASSERT( other->_end == 0 );\n\n    other->Reset();\n\n    other->_flags = _flags;\n    other->_start = _start;\n    other->_end = _end;\n\n    _flags = 0;\n    _start = 0;\n    _end = 0;\n}\n\n\nvoid StrPair::Reset()\n{\n    if ( _flags & NEEDS_DELETE ) {\n        delete [] _start;\n    }\n    _flags = 0;\n    _start = 0;\n    _end = 0;\n}\n\n\nvoid StrPair::SetStr( const char* str, int flags )\n{\n    TIXMLASSERT( str );\n    Reset();\n    size_t len = strlen( str );\n    TIXMLASSERT( _start == 0 );\n    _start = new char[ len+1 ];\n    memcpy( _start, str, len+1 );\n    _end = _start + len;\n    _flags = flags | NEEDS_DELETE;\n}\n\n\nchar* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )\n{\n    TIXMLASSERT( p );\n    TIXMLASSERT( endTag && *endTag );\n\tTIXMLASSERT(curLineNumPtr);\n\n    char* start = p;\n    const char  endChar = *endTag;\n    size_t length = strlen( endTag );\n\n    // Inner loop of text parsing.\n    while ( *p ) {\n        if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {\n            Set( start, p, strFlags );\n            return p + length;\n        } else if (*p == '\\n') {\n            ++(*curLineNumPtr);\n        }\n        ++p;\n        TIXMLASSERT( p );\n    }\n    return 0;\n}\n\n\nchar* StrPair::ParseName( char* p )\n{\n    if ( !p || !(*p) ) {\n        return 0;\n    }\n    if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {\n        return 0;\n    }\n\n    char* const start = p;\n    ++p;\n    while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {\n        ++p;\n    }\n\n    Set( start, p, 0 );\n    return p;\n}\n\n\nvoid StrPair::CollapseWhitespace()\n{\n    // Adjusting _start would cause undefined behavior on delete[]\n    TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );\n    // Trim leading space.\n    _start = XMLUtil::SkipWhiteSpace( _start, 0 );\n\n    if ( *_start ) {\n        const char* p = _start;\t// the read pointer\n        char* q = _start;\t// the write pointer\n\n        while( *p ) {\n            if ( XMLUtil::IsWhiteSpace( *p )) {\n                p = XMLUtil::SkipWhiteSpace( p, 0 );\n                if ( *p == 0 ) {\n                    break;    // don't write to q; this trims the trailing space.\n                }\n                *q = ' ';\n                ++q;\n            }\n            *q = *p;\n            ++q;\n            ++p;\n        }\n        *q = 0;\n    }\n}\n\n\nconst char* StrPair::GetStr()\n{\n    TIXMLASSERT( _start );\n    TIXMLASSERT( _end );\n    if ( _flags & NEEDS_FLUSH ) {\n        *_end = 0;\n        _flags ^= NEEDS_FLUSH;\n\n        if ( _flags ) {\n            const char* p = _start;\t// the read pointer\n            char* q = _start;\t// the write pointer\n\n            while( p < _end ) {\n                if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {\n                    // CR-LF pair becomes LF\n                    // CR alone becomes LF\n                    // LF-CR becomes LF\n                    if ( *(p+1) == LF ) {\n                        p += 2;\n                    }\n                    else {\n                        ++p;\n                    }\n                    *q = LF;\n                    ++q;\n                }\n                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {\n                    if ( *(p+1) == CR ) {\n                        p += 2;\n                    }\n                    else {\n                        ++p;\n                    }\n                    *q = LF;\n                    ++q;\n                }\n                else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {\n                    // Entities handled by tinyXML2:\n                    // - special entities in the entity table [in/out]\n                    // - numeric character reference [in]\n                    //   &#20013; or &#x4e2d;\n\n                    if ( *(p+1) == '#' ) {\n                        const int buflen = 10;\n                        char buf[buflen] = { 0 };\n                        int len = 0;\n                        const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );\n                        if ( adjusted == 0 ) {\n                            *q = *p;\n                            ++p;\n                            ++q;\n                        }\n                        else {\n                            TIXMLASSERT( 0 <= len && len <= buflen );\n                            TIXMLASSERT( q + len <= adjusted );\n                            p = adjusted;\n                            memcpy( q, buf, len );\n                            q += len;\n                        }\n                    }\n                    else {\n                        bool entityFound = false;\n                        for( int i = 0; i < NUM_ENTITIES; ++i ) {\n                            const Entity& entity = entities[i];\n                            if ( strncmp( p + 1, entity.pattern, entity.length ) == 0\n                                    && *( p + entity.length + 1 ) == ';' ) {\n                                // Found an entity - convert.\n                                *q = entity.value;\n                                ++q;\n                                p += entity.length + 2;\n                                entityFound = true;\n                                break;\n                            }\n                        }\n                        if ( !entityFound ) {\n                            // fixme: treat as error?\n                            ++p;\n                            ++q;\n                        }\n                    }\n                }\n                else {\n                    *q = *p;\n                    ++p;\n                    ++q;\n                }\n            }\n            *q = 0;\n        }\n        // The loop below has plenty going on, and this\n        // is a less useful mode. Break it out.\n        if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {\n            CollapseWhitespace();\n        }\n        _flags = (_flags & NEEDS_DELETE);\n    }\n    TIXMLASSERT( _start );\n    return _start;\n}\n\n\n\n\n// --------- XMLUtil ----------- //\n\nconst char* XMLUtil::writeBoolTrue  = \"true\";\nconst char* XMLUtil::writeBoolFalse = \"false\";\n\nvoid XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)\n{\n\tstatic const char* defTrue  = \"true\";\n\tstatic const char* defFalse = \"false\";\n\n\twriteBoolTrue = (writeTrue) ? writeTrue : defTrue;\n\twriteBoolFalse = (writeFalse) ? writeFalse : defFalse;\n}\n\n\nconst char* XMLUtil::ReadBOM( const char* p, bool* bom )\n{\n    TIXMLASSERT( p );\n    TIXMLASSERT( bom );\n    *bom = false;\n    const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);\n    // Check for BOM:\n    if (    *(pu+0) == TIXML_UTF_LEAD_0\n            && *(pu+1) == TIXML_UTF_LEAD_1\n            && *(pu+2) == TIXML_UTF_LEAD_2 ) {\n        *bom = true;\n        p += 3;\n    }\n    TIXMLASSERT( p );\n    return p;\n}\n\n\nvoid XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )\n{\n    const unsigned long BYTE_MASK = 0xBF;\n    const unsigned long BYTE_MARK = 0x80;\n    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };\n\n    if (input < 0x80) {\n        *length = 1;\n    }\n    else if ( input < 0x800 ) {\n        *length = 2;\n    }\n    else if ( input < 0x10000 ) {\n        *length = 3;\n    }\n    else if ( input < 0x200000 ) {\n        *length = 4;\n    }\n    else {\n        *length = 0;    // This code won't convert this correctly anyway.\n        return;\n    }\n\n    output += *length;\n\n    // Scary scary fall throughs are annotated with carefully designed comments\n    // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc\n    switch (*length) {\n        case 4:\n            --output;\n            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);\n            input >>= 6;\n            //fall through\n        case 3:\n            --output;\n            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);\n            input >>= 6;\n            //fall through\n        case 2:\n            --output;\n            *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);\n            input >>= 6;\n            //fall through\n        case 1:\n            --output;\n            *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);\n            break;\n        default:\n            TIXMLASSERT( false );\n    }\n}\n\n\nconst char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )\n{\n    // Presume an entity, and pull it out.\n    *length = 0;\n\n    if ( *(p+1) == '#' && *(p+2) ) {\n        unsigned long ucs = 0;\n        TIXMLASSERT( sizeof( ucs ) >= 4 );\n        ptrdiff_t delta = 0;\n        unsigned mult = 1;\n        static const char SEMICOLON = ';';\n\n        if ( *(p+2) == 'x' ) {\n            // Hexadecimal.\n            const char* q = p+3;\n            if ( !(*q) ) {\n                return 0;\n            }\n\n            q = strchr( q, SEMICOLON );\n\n            if ( !q ) {\n                return 0;\n            }\n            TIXMLASSERT( *q == SEMICOLON );\n\n            delta = q-p;\n            --q;\n\n            while ( *q != 'x' ) {\n                unsigned int digit = 0;\n\n                if ( *q >= '0' && *q <= '9' ) {\n                    digit = *q - '0';\n                }\n                else if ( *q >= 'a' && *q <= 'f' ) {\n                    digit = *q - 'a' + 10;\n                }\n                else if ( *q >= 'A' && *q <= 'F' ) {\n                    digit = *q - 'A' + 10;\n                }\n                else {\n                    return 0;\n                }\n                TIXMLASSERT( digit < 16 );\n                TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );\n                const unsigned int digitScaled = mult * digit;\n                TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );\n                ucs += digitScaled;\n                TIXMLASSERT( mult <= UINT_MAX / 16 );\n                mult *= 16;\n                --q;\n            }\n        }\n        else {\n            // Decimal.\n            const char* q = p+2;\n            if ( !(*q) ) {\n                return 0;\n            }\n\n            q = strchr( q, SEMICOLON );\n\n            if ( !q ) {\n                return 0;\n            }\n            TIXMLASSERT( *q == SEMICOLON );\n\n            delta = q-p;\n            --q;\n\n            while ( *q != '#' ) {\n                if ( *q >= '0' && *q <= '9' ) {\n                    const unsigned int digit = *q - '0';\n                    TIXMLASSERT( digit < 10 );\n                    TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );\n                    const unsigned int digitScaled = mult * digit;\n                    TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );\n                    ucs += digitScaled;\n                }\n                else {\n                    return 0;\n                }\n                TIXMLASSERT( mult <= UINT_MAX / 10 );\n                mult *= 10;\n                --q;\n            }\n        }\n        // convert the UCS to UTF-8\n        ConvertUTF32ToUTF8( ucs, value, length );\n        return p + delta + 1;\n    }\n    return p+1;\n}\n\n\nvoid XMLUtil::ToStr( int v, char* buffer, int bufferSize )\n{\n    TIXML_SNPRINTF( buffer, bufferSize, \"%d\", v );\n}\n\n\nvoid XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )\n{\n    TIXML_SNPRINTF( buffer, bufferSize, \"%u\", v );\n}\n\n\nvoid XMLUtil::ToStr( bool v, char* buffer, int bufferSize )\n{\n    TIXML_SNPRINTF( buffer, bufferSize, \"%s\", v ? writeBoolTrue : writeBoolFalse);\n}\n\n/*\n\tToStr() of a number is a very tricky topic.\n\thttps://github.com/leethomason/tinyxml2/issues/106\n*/\nvoid XMLUtil::ToStr( float v, char* buffer, int bufferSize )\n{\n    TIXML_SNPRINTF( buffer, bufferSize, \"%.8g\", v );\n}\n\n\nvoid XMLUtil::ToStr( double v, char* buffer, int bufferSize )\n{\n    TIXML_SNPRINTF( buffer, bufferSize, \"%.17g\", v );\n}\n\n\nvoid XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )\n{\n\t// horrible syntax trick to make the compiler happy about %lld\n\tTIXML_SNPRINTF(buffer, bufferSize, \"%lld\", static_cast<long long>(v));\n}\n\nvoid XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )\n{\n    // horrible syntax trick to make the compiler happy about %llu\n    TIXML_SNPRINTF(buffer, bufferSize, \"%llu\", static_cast<unsigned long long>(v));\n}\n\nbool XMLUtil::ToInt(const char* str, int* value)\n{\n    if (IsPrefixHex(str)) {\n        unsigned v;\n        if (TIXML_SSCANF(str, \"%x\", &v) == 1) {\n            *value = static_cast<int>(v);\n            return true;\n        }\n    }\n    else {\n        if (TIXML_SSCANF(str, \"%d\", value) == 1) {\n            return true;\n        }\n    }\n    return false;\n}\n\nbool XMLUtil::ToUnsigned(const char* str, unsigned* value)\n{\n    if (TIXML_SSCANF(str, IsPrefixHex(str) ? \"%x\" : \"%u\", value) == 1) {\n        return true;\n    }\n    return false;\n}\n\nbool XMLUtil::ToBool( const char* str, bool* value )\n{\n    int ival = 0;\n    if ( ToInt( str, &ival )) {\n        *value = (ival==0) ? false : true;\n        return true;\n    }\n    static const char* TRUE_VALS[] = { \"true\", \"True\", \"TRUE\", 0 };\n    static const char* FALSE_VALS[] = { \"false\", \"False\", \"FALSE\", 0 };\n\n    for (int i = 0; TRUE_VALS[i]; ++i) {\n        if (StringEqual(str, TRUE_VALS[i])) {\n            *value = true;\n            return true;\n        }\n    }\n    for (int i = 0; FALSE_VALS[i]; ++i) {\n        if (StringEqual(str, FALSE_VALS[i])) {\n            *value = false;\n            return true;\n        }\n    }\n    return false;\n}\n\n\nbool XMLUtil::ToFloat( const char* str, float* value )\n{\n    if ( TIXML_SSCANF( str, \"%f\", value ) == 1 ) {\n        return true;\n    }\n    return false;\n}\n\n\nbool XMLUtil::ToDouble( const char* str, double* value )\n{\n    if ( TIXML_SSCANF( str, \"%lf\", value ) == 1 ) {\n        return true;\n    }\n    return false;\n}\n\n\nbool XMLUtil::ToInt64(const char* str, int64_t* value)\n{\n    if (IsPrefixHex(str)) {\n        unsigned long long v = 0;\t// horrible syntax trick to make the compiler happy about %llx\n        if (TIXML_SSCANF(str, \"%llx\", &v) == 1) {\n            *value = static_cast<int64_t>(v);\n            return true;\n        }\n    }\n    else {\n        long long v = 0;\t// horrible syntax trick to make the compiler happy about %lld\n        if (TIXML_SSCANF(str, \"%lld\", &v) == 1) {\n            *value = static_cast<int64_t>(v);\n            return true;\n        }\n    }\n\treturn false;\n}\n\n\nbool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {\n    unsigned long long v = 0;\t// horrible syntax trick to make the compiler happy about %llu\n    if(TIXML_SSCANF(str, IsPrefixHex(str) ? \"%llx\" : \"%llu\", &v) == 1) {\n        *value = (uint64_t)v;\n        return true;\n    }\n    return false;\n}\n\n\nchar* XMLDocument::Identify( char* p, XMLNode** node, bool first )\n{\n    TIXMLASSERT( node );\n    TIXMLASSERT( p );\n    char* const start = p;\n    int const startLine = _parseCurLineNum;\n    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );\n    if( !*p ) {\n        *node = 0;\n        TIXMLASSERT( p );\n        return p;\n    }\n\n    // These strings define the matching patterns:\n    static const char* xmlHeader\t\t= { \"<?\" };\n    static const char* commentHeader\t= { \"<!--\" };\n    static const char* cdataHeader\t\t= { \"<![CDATA[\" };\n    static const char* dtdHeader\t\t= { \"<!\" };\n    static const char* elementHeader\t= { \"<\" };\t// and a header for everything else; check last.\n\n    static const int xmlHeaderLen\t\t= 2;\n    static const int commentHeaderLen\t= 4;\n    static const int cdataHeaderLen\t\t= 9;\n    static const int dtdHeaderLen\t\t= 2;\n    static const int elementHeaderLen\t= 1;\n\n    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );\t\t// use same memory pool\n    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );\t// use same memory pool\n    XMLNode* returnNode = 0;\n    if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {\n        returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );\n        returnNode->_parseLineNum = _parseCurLineNum;\n        p += xmlHeaderLen;\n    }\n    else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {\n        returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );\n        returnNode->_parseLineNum = _parseCurLineNum;\n        p += commentHeaderLen;\n    }\n    else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {\n        XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );\n        returnNode = text;\n        returnNode->_parseLineNum = _parseCurLineNum;\n        p += cdataHeaderLen;\n        text->SetCData( true );\n    }\n    else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {\n        returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );\n        returnNode->_parseLineNum = _parseCurLineNum;\n        p += dtdHeaderLen;\n    }\n    else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {\n\n        // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag\n        if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') {\n            returnNode = CreateUnlinkedNode<XMLText>(_textPool);\n            returnNode->_parseLineNum = startLine;\n            p = start;\t// Back it up, all the text counts.\n            _parseCurLineNum = startLine;\n        }\n        else {\n            returnNode = CreateUnlinkedNode<XMLElement>(_elementPool);\n            returnNode->_parseLineNum = _parseCurLineNum;\n            p += elementHeaderLen;\n        }\n    }\n    else {\n        returnNode = CreateUnlinkedNode<XMLText>( _textPool );\n        returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character\n        p = start;\t// Back it up, all the text counts.\n        _parseCurLineNum = startLine;\n    }\n\n    TIXMLASSERT( returnNode );\n    TIXMLASSERT( p );\n    *node = returnNode;\n    return p;\n}\n\n\nbool XMLDocument::Accept( XMLVisitor* visitor ) const\n{\n    TIXMLASSERT( visitor );\n    if ( visitor->VisitEnter( *this ) ) {\n        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {\n            if ( !node->Accept( visitor ) ) {\n                break;\n            }\n        }\n    }\n    return visitor->VisitExit( *this );\n}\n\n\n// --------- XMLNode ----------- //\n\nXMLNode::XMLNode( XMLDocument* doc ) :\n    _document( doc ),\n    _parent( 0 ),\n    _value(),\n    _parseLineNum( 0 ),\n    _firstChild( 0 ), _lastChild( 0 ),\n    _prev( 0 ), _next( 0 ),\n\t_userData( 0 ),\n    _memPool( 0 )\n{\n}\n\n\nXMLNode::~XMLNode()\n{\n    DeleteChildren();\n    if ( _parent ) {\n        _parent->Unlink( this );\n    }\n}\n\n// ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2.\n\nint XMLNode::ChildElementCount(const char *value) const {\n\tint count = 0;\n\n\tconst XMLElement *e = FirstChildElement(value);\n\n\twhile (e) {\n\t\te = e->NextSiblingElement(value);\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n\nint XMLNode::ChildElementCount() const {\n\tint count = 0;\n\n\tconst XMLElement *e = FirstChildElement();\n\n\twhile (e) {\n\t\te = e->NextSiblingElement();\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n\nconst char* XMLNode::Value() const\n{\n    // Edge case: XMLDocuments don't have a Value. Return null.\n    if ( this->ToDocument() )\n        return 0;\n    return _value.GetStr();\n}\n\nvoid XMLNode::SetValue( const char* str, bool staticMem )\n{\n    if ( staticMem ) {\n        _value.SetInternedStr( str );\n    }\n    else {\n        _value.SetStr( str );\n    }\n}\n\nXMLNode* XMLNode::DeepClone(XMLDocument* target) const\n{\n\tXMLNode* clone = this->ShallowClone(target);\n\tif (!clone) return 0;\n\n\tfor (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {\n\t\tXMLNode* childClone = child->DeepClone(target);\n\t\tTIXMLASSERT(childClone);\n\t\tclone->InsertEndChild(childClone);\n\t}\n\treturn clone;\n}\n\nvoid XMLNode::DeleteChildren()\n{\n    while( _firstChild ) {\n        TIXMLASSERT( _lastChild );\n        DeleteChild( _firstChild );\n    }\n    _firstChild = _lastChild = 0;\n}\n\n\nvoid XMLNode::Unlink( XMLNode* child )\n{\n    TIXMLASSERT( child );\n    TIXMLASSERT( child->_document == _document );\n    TIXMLASSERT( child->_parent == this );\n    if ( child == _firstChild ) {\n        _firstChild = _firstChild->_next;\n    }\n    if ( child == _lastChild ) {\n        _lastChild = _lastChild->_prev;\n    }\n\n    if ( child->_prev ) {\n        child->_prev->_next = child->_next;\n    }\n    if ( child->_next ) {\n        child->_next->_prev = child->_prev;\n    }\n\tchild->_next = 0;\n\tchild->_prev = 0;\n\tchild->_parent = 0;\n}\n\n\nvoid XMLNode::DeleteChild( XMLNode* node )\n{\n    TIXMLASSERT( node );\n    TIXMLASSERT( node->_document == _document );\n    TIXMLASSERT( node->_parent == this );\n    Unlink( node );\n\tTIXMLASSERT(node->_prev == 0);\n\tTIXMLASSERT(node->_next == 0);\n\tTIXMLASSERT(node->_parent == 0);\n    DeleteNode( node );\n}\n\n\nXMLNode* XMLNode::InsertEndChild( XMLNode* addThis )\n{\n    TIXMLASSERT( addThis );\n    if ( addThis->_document != _document ) {\n        TIXMLASSERT( false );\n        return 0;\n    }\n    InsertChildPreamble( addThis );\n\n    if ( _lastChild ) {\n        TIXMLASSERT( _firstChild );\n        TIXMLASSERT( _lastChild->_next == 0 );\n        _lastChild->_next = addThis;\n        addThis->_prev = _lastChild;\n        _lastChild = addThis;\n\n        addThis->_next = 0;\n    }\n    else {\n        TIXMLASSERT( _firstChild == 0 );\n        _firstChild = _lastChild = addThis;\n\n        addThis->_prev = 0;\n        addThis->_next = 0;\n    }\n    addThis->_parent = this;\n    return addThis;\n}\n\n\nXMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )\n{\n    TIXMLASSERT( addThis );\n    if ( addThis->_document != _document ) {\n        TIXMLASSERT( false );\n        return 0;\n    }\n    InsertChildPreamble( addThis );\n\n    if ( _firstChild ) {\n        TIXMLASSERT( _lastChild );\n        TIXMLASSERT( _firstChild->_prev == 0 );\n\n        _firstChild->_prev = addThis;\n        addThis->_next = _firstChild;\n        _firstChild = addThis;\n\n        addThis->_prev = 0;\n    }\n    else {\n        TIXMLASSERT( _lastChild == 0 );\n        _firstChild = _lastChild = addThis;\n\n        addThis->_prev = 0;\n        addThis->_next = 0;\n    }\n    addThis->_parent = this;\n    return addThis;\n}\n\n\nXMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )\n{\n    TIXMLASSERT( addThis );\n    if ( addThis->_document != _document ) {\n        TIXMLASSERT( false );\n        return 0;\n    }\n\n    TIXMLASSERT( afterThis );\n\n    if ( afterThis->_parent != this ) {\n        TIXMLASSERT( false );\n        return 0;\n    }\n    if ( afterThis == addThis ) {\n        // Current state: BeforeThis -> AddThis -> OneAfterAddThis\n        // Now AddThis must disappear from it's location and then\n        // reappear between BeforeThis and OneAfterAddThis.\n        // So just leave it where it is.\n        return addThis;\n    }\n\n    if ( afterThis->_next == 0 ) {\n        // The last node or the only node.\n        return InsertEndChild( addThis );\n    }\n    InsertChildPreamble( addThis );\n    addThis->_prev = afterThis;\n    addThis->_next = afterThis->_next;\n    afterThis->_next->_prev = addThis;\n    afterThis->_next = addThis;\n    addThis->_parent = this;\n    return addThis;\n}\n\n\n\n\nconst XMLElement* XMLNode::FirstChildElement( const char* name ) const\n{\n    for( const XMLNode* node = _firstChild; node; node = node->_next ) {\n        const XMLElement* element = node->ToElementWithName( name );\n        if ( element ) {\n            return element;\n        }\n    }\n    return 0;\n}\n\n\nconst XMLElement* XMLNode::LastChildElement( const char* name ) const\n{\n    for( const XMLNode* node = _lastChild; node; node = node->_prev ) {\n        const XMLElement* element = node->ToElementWithName( name );\n        if ( element ) {\n            return element;\n        }\n    }\n    return 0;\n}\n\n\nconst XMLElement* XMLNode::NextSiblingElement( const char* name ) const\n{\n    for( const XMLNode* node = _next; node; node = node->_next ) {\n        const XMLElement* element = node->ToElementWithName( name );\n        if ( element ) {\n            return element;\n        }\n    }\n    return 0;\n}\n\n\nconst XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const\n{\n    for( const XMLNode* node = _prev; node; node = node->_prev ) {\n        const XMLElement* element = node->ToElementWithName( name );\n        if ( element ) {\n            return element;\n        }\n    }\n    return 0;\n}\n\n\nchar* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )\n{\n    // This is a recursive method, but thinking about it \"at the current level\"\n    // it is a pretty simple flat list:\n    //\t\t<foo/>\n    //\t\t<!-- comment -->\n    //\n    // With a special case:\n    //\t\t<foo>\n    //\t\t</foo>\n    //\t\t<!-- comment -->\n    //\n    // Where the closing element (/foo) *must* be the next thing after the opening\n    // element, and the names must match. BUT the tricky bit is that the closing\n    // element will be read by the child.\n    //\n    // 'endTag' is the end tag for this node, it is returned by a call to a child.\n    // 'parentEnd' is the end tag for the parent, which is filled in and returned.\n\n\tXMLDocument::DepthTracker tracker(_document);\n\tif (_document->Error())\n\t\treturn 0;\n\n\tbool first = true;\n\twhile( p && *p ) {\n        XMLNode* node = 0;\n\n        p = _document->Identify( p, &node, first );\n        TIXMLASSERT( p );\n        if ( node == 0 ) {\n            break;\n        }\n        first = false;\n\n       const int initialLineNum = node->_parseLineNum;\n\n        StrPair endTag;\n        p = node->ParseDeep( p, &endTag, curLineNumPtr );\n        if ( !p ) {\n            _document->DeleteNode( node );\n            if ( !_document->Error() ) {\n                _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);\n            }\n            break;\n        }\n\n        const XMLDeclaration* const decl = node->ToDeclaration();\n        if ( decl ) {\n            // Declarations are only allowed at document level\n            //\n            // Multiple declarations are allowed but all declarations\n            // must occur before anything else. \n            //\n            // Optimized due to a security test case. If the first node is \n            // a declaration, and the last node is a declaration, then only \n            // declarations have so far been added.\n            bool wellLocated = false;\n\n            if (ToDocument()) {\n                if (FirstChild()) {\n                    wellLocated =\n                        FirstChild() &&\n                        FirstChild()->ToDeclaration() &&\n                        LastChild() &&\n                        LastChild()->ToDeclaration();\n                }\n                else {\n                    wellLocated = true;\n                }\n            }\n            if ( !wellLocated ) {\n                _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, \"XMLDeclaration value=%s\", decl->Value());\n                _document->DeleteNode( node );\n                break;\n            }\n        }\n\n        XMLElement* ele = node->ToElement();\n        if ( ele ) {\n            // We read the end tag. Return it to the parent.\n            if ( ele->ClosingType() == XMLElement::CLOSING ) {\n                if ( parentEndTag ) {\n                    ele->_value.TransferTo( parentEndTag );\n                }\n                node->_memPool->SetTracked();   // created and then immediately deleted.\n                DeleteNode( node );\n                return p;\n            }\n\n            // Handle an end tag returned to this level.\n            // And handle a bunch of annoying errors.\n            bool mismatch = false;\n            if ( endTag.Empty() ) {\n                if ( ele->ClosingType() == XMLElement::OPEN ) {\n                    mismatch = true;\n                }\n            }\n            else {\n                if ( ele->ClosingType() != XMLElement::OPEN ) {\n                    mismatch = true;\n                }\n                else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {\n                    mismatch = true;\n                }\n            }\n            if ( mismatch ) {\n                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, \"XMLElement name=%s\", ele->Name());\n                _document->DeleteNode( node );\n                break;\n            }\n        }\n        InsertEndChild( node );\n    }\n    return 0;\n}\n\n/*static*/ void XMLNode::DeleteNode( XMLNode* node )\n{\n    if ( node == 0 ) {\n        return;\n    }\n\tTIXMLASSERT(node->_document);\n\tif (!node->ToDocument()) {\n\t\tnode->_document->MarkInUse(node);\n\t}\n\n    MemPool* pool = node->_memPool;\n    node->~XMLNode();\n    pool->Free( node );\n}\n\nvoid XMLNode::InsertChildPreamble( XMLNode* insertThis ) const\n{\n    TIXMLASSERT( insertThis );\n    TIXMLASSERT( insertThis->_document == _document );\n\n\tif (insertThis->_parent) {\n        insertThis->_parent->Unlink( insertThis );\n\t}\n\telse {\n\t\tinsertThis->_document->MarkInUse(insertThis);\n        insertThis->_memPool->SetTracked();\n\t}\n}\n\nconst XMLElement* XMLNode::ToElementWithName( const char* name ) const\n{\n    const XMLElement* element = this->ToElement();\n    if ( element == 0 ) {\n        return 0;\n    }\n    if ( name == 0 ) {\n        return element;\n    }\n    if ( XMLUtil::StringEqual( element->Name(), name ) ) {\n       return element;\n    }\n    return 0;\n}\n\n// --------- XMLText ---------- //\nchar* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\n{\n    if ( this->CData() ) {\n        p = _value.ParseText( p, \"]]>\", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );\n        if ( !p ) {\n            _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );\n        }\n        return p;\n    }\n    else {\n        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;\n        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {\n            flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;\n        }\n\n        p = _value.ParseText( p, \"<\", flags, curLineNumPtr );\n        if ( p && *p ) {\n            return p-1;\n        }\n        if ( !p ) {\n            _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );\n        }\n    }\n    return 0;\n}\n\n\nXMLNode* XMLText::ShallowClone( XMLDocument* doc ) const\n{\n    if ( !doc ) {\n        doc = _document;\n    }\n    XMLText* text = doc->NewText( Value() );\t// fixme: this will always allocate memory. Intern?\n    text->SetCData( this->CData() );\n    return text;\n}\n\n\nbool XMLText::ShallowEqual( const XMLNode* compare ) const\n{\n    TIXMLASSERT( compare );\n    const XMLText* text = compare->ToText();\n    return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );\n}\n\n\nbool XMLText::Accept( XMLVisitor* visitor ) const\n{\n    TIXMLASSERT( visitor );\n    return visitor->Visit( *this );\n}\n\n\n// --------- XMLComment ---------- //\n\nXMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )\n{\n}\n\n\nXMLComment::~XMLComment()\n{\n}\n\n\nchar* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\n{\n    // Comment parses as text.\n    p = _value.ParseText( p, \"-->\", StrPair::COMMENT, curLineNumPtr );\n    if ( p == 0 ) {\n        _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );\n    }\n    return p;\n}\n\n\nXMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const\n{\n    if ( !doc ) {\n        doc = _document;\n    }\n    XMLComment* comment = doc->NewComment( Value() );\t// fixme: this will always allocate memory. Intern?\n    return comment;\n}\n\n\nbool XMLComment::ShallowEqual( const XMLNode* compare ) const\n{\n    TIXMLASSERT( compare );\n    const XMLComment* comment = compare->ToComment();\n    return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));\n}\n\n\nbool XMLComment::Accept( XMLVisitor* visitor ) const\n{\n    TIXMLASSERT( visitor );\n    return visitor->Visit( *this );\n}\n\n\n// --------- XMLDeclaration ---------- //\n\nXMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )\n{\n}\n\n\nXMLDeclaration::~XMLDeclaration()\n{\n    //printf( \"~XMLDeclaration\\n\" );\n}\n\n\nchar* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\n{\n    // Declaration parses as text.\n    p = _value.ParseText( p, \"?>\", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );\n    if ( p == 0 ) {\n        _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );\n    }\n    return p;\n}\n\n\nXMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const\n{\n    if ( !doc ) {\n        doc = _document;\n    }\n    XMLDeclaration* dec = doc->NewDeclaration( Value() );\t// fixme: this will always allocate memory. Intern?\n    return dec;\n}\n\n\nbool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const\n{\n    TIXMLASSERT( compare );\n    const XMLDeclaration* declaration = compare->ToDeclaration();\n    return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));\n}\n\n\n\nbool XMLDeclaration::Accept( XMLVisitor* visitor ) const\n{\n    TIXMLASSERT( visitor );\n    return visitor->Visit( *this );\n}\n\n// --------- XMLUnknown ---------- //\n\nXMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )\n{\n}\n\n\nXMLUnknown::~XMLUnknown()\n{\n}\n\n\nchar* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )\n{\n    // Unknown parses as text.\n    p = _value.ParseText( p, \">\", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );\n    if ( !p ) {\n        _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );\n    }\n    return p;\n}\n\n\nXMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const\n{\n    if ( !doc ) {\n        doc = _document;\n    }\n    XMLUnknown* text = doc->NewUnknown( Value() );\t// fixme: this will always allocate memory. Intern?\n    return text;\n}\n\n\nbool XMLUnknown::ShallowEqual( const XMLNode* compare ) const\n{\n    TIXMLASSERT( compare );\n    const XMLUnknown* unknown = compare->ToUnknown();\n    return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));\n}\n\n\nbool XMLUnknown::Accept( XMLVisitor* visitor ) const\n{\n    TIXMLASSERT( visitor );\n    return visitor->Visit( *this );\n}\n\n// --------- XMLAttribute ---------- //\n\nconst char* XMLAttribute::Name() const\n{\n    return _name.GetStr();\n}\n\nconst char* XMLAttribute::Value() const\n{\n    return _value.GetStr();\n}\n\nchar* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )\n{\n    // Parse using the name rules: bug fix, was using ParseText before\n    p = _name.ParseName( p );\n    if ( !p || !*p ) {\n        return 0;\n    }\n\n    // Skip white space before =\n    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\n    if ( *p != '=' ) {\n        return 0;\n    }\n\n    ++p;\t// move up to opening quote\n    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\n    if ( *p != '\\\"' && *p != '\\'' ) {\n        return 0;\n    }\n\n    const char endTag[2] = { *p, 0 };\n    ++p;\t// move past opening quote\n\n    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );\n    return p;\n}\n\n\nvoid XMLAttribute::SetName( const char* n )\n{\n    _name.SetStr( n );\n}\n\n\nXMLError XMLAttribute::QueryIntValue( int* value ) const\n{\n    if ( XMLUtil::ToInt( Value(), value )) {\n        return XML_SUCCESS;\n    }\n    return XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nXMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const\n{\n    if ( XMLUtil::ToUnsigned( Value(), value )) {\n        return XML_SUCCESS;\n    }\n    return XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nXMLError XMLAttribute::QueryInt64Value(int64_t* value) const\n{\n\tif (XMLUtil::ToInt64(Value(), value)) {\n\t\treturn XML_SUCCESS;\n\t}\n\treturn XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nXMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const\n{\n    if(XMLUtil::ToUnsigned64(Value(), value)) {\n        return XML_SUCCESS;\n    }\n    return XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nXMLError XMLAttribute::QueryBoolValue( bool* value ) const\n{\n    if ( XMLUtil::ToBool( Value(), value )) {\n        return XML_SUCCESS;\n    }\n    return XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nXMLError XMLAttribute::QueryFloatValue( float* value ) const\n{\n    if ( XMLUtil::ToFloat( Value(), value )) {\n        return XML_SUCCESS;\n    }\n    return XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nXMLError XMLAttribute::QueryDoubleValue( double* value ) const\n{\n    if ( XMLUtil::ToDouble( Value(), value )) {\n        return XML_SUCCESS;\n    }\n    return XML_WRONG_ATTRIBUTE_TYPE;\n}\n\n\nvoid XMLAttribute::SetAttribute( const char* v )\n{\n    _value.SetStr( v );\n}\n\n\nvoid XMLAttribute::SetAttribute( int v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    _value.SetStr( buf );\n}\n\n\nvoid XMLAttribute::SetAttribute( unsigned v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    _value.SetStr( buf );\n}\n\n\nvoid XMLAttribute::SetAttribute(int64_t v)\n{\n\tchar buf[BUF_SIZE];\n\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\t_value.SetStr(buf);\n}\n\nvoid XMLAttribute::SetAttribute(uint64_t v)\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr(v, buf, BUF_SIZE);\n    _value.SetStr(buf);\n}\n\n\nvoid XMLAttribute::SetAttribute( bool v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    _value.SetStr( buf );\n}\n\nvoid XMLAttribute::SetAttribute( double v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    _value.SetStr( buf );\n}\n\nvoid XMLAttribute::SetAttribute( float v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    _value.SetStr( buf );\n}\n\n\n// --------- XMLElement ---------- //\nXMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),\n    _closingType( OPEN ),\n    _rootAttribute( 0 )\n{\n}\n\n\nXMLElement::~XMLElement()\n{\n    while( _rootAttribute ) {\n        XMLAttribute* next = _rootAttribute->_next;\n        DeleteAttribute( _rootAttribute );\n        _rootAttribute = next;\n    }\n}\n\n\nconst XMLAttribute* XMLElement::FindAttribute( const char* name ) const\n{\n    for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {\n        if ( XMLUtil::StringEqual( a->Name(), name ) ) {\n            return a;\n        }\n    }\n    return 0;\n}\n\n\nconst char* XMLElement::Attribute( const char* name, const char* value ) const\n{\n    const XMLAttribute* a = FindAttribute( name );\n    if ( !a ) {\n        return 0;\n    }\n    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {\n        return a->Value();\n    }\n    return 0;\n}\n\nint XMLElement::IntAttribute(const char* name, int defaultValue) const\n{\n\tint i = defaultValue;\n\tQueryIntAttribute(name, &i);\n\treturn i;\n}\n\nunsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const\n{\n\tunsigned i = defaultValue;\n\tQueryUnsignedAttribute(name, &i);\n\treturn i;\n}\n\nint64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const\n{\n\tint64_t i = defaultValue;\n\tQueryInt64Attribute(name, &i);\n\treturn i;\n}\n\nuint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const\n{\n\tuint64_t i = defaultValue;\n\tQueryUnsigned64Attribute(name, &i);\n\treturn i;\n}\n\nbool XMLElement::BoolAttribute(const char* name, bool defaultValue) const\n{\n\tbool b = defaultValue;\n\tQueryBoolAttribute(name, &b);\n\treturn b;\n}\n\ndouble XMLElement::DoubleAttribute(const char* name, double defaultValue) const\n{\n\tdouble d = defaultValue;\n\tQueryDoubleAttribute(name, &d);\n\treturn d;\n}\n\nfloat XMLElement::FloatAttribute(const char* name, float defaultValue) const\n{\n\tfloat f = defaultValue;\n\tQueryFloatAttribute(name, &f);\n\treturn f;\n}\n\nconst char* XMLElement::GetText() const\n{\n    /* skip comment node */\n    const XMLNode* node = FirstChild();\n    while (node) {\n        if (node->ToComment()) {\n            node = node->NextSibling();\n            continue;\n        }\n        break;\n    }\n\n    if ( node && node->ToText() ) {\n        return node->Value();\n    }\n    return 0;\n}\n\n\nvoid\tXMLElement::SetText( const char* inText )\n{\n\tif ( FirstChild() && FirstChild()->ToText() )\n\t\tFirstChild()->SetValue( inText );\n\telse {\n\t\tXMLText*\ttheText = GetDocument()->NewText( inText );\n\t\tInsertFirstChild( theText );\n\t}\n}\n\n\nvoid XMLElement::SetText( int v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    SetText( buf );\n}\n\n\nvoid XMLElement::SetText( unsigned v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    SetText( buf );\n}\n\n\nvoid XMLElement::SetText(int64_t v)\n{\n\tchar buf[BUF_SIZE];\n\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\tSetText(buf);\n}\n\nvoid XMLElement::SetText(uint64_t v) {\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr(v, buf, BUF_SIZE);\n    SetText(buf);\n}\n\n\nvoid XMLElement::SetText( bool v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    SetText( buf );\n}\n\n\nvoid XMLElement::SetText( float v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    SetText( buf );\n}\n\n\nvoid XMLElement::SetText( double v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    SetText( buf );\n}\n\n\nXMLError XMLElement::QueryIntText( int* ival ) const\n{\n    if ( FirstChild() && FirstChild()->ToText() ) {\n        const char* t = FirstChild()->Value();\n        if ( XMLUtil::ToInt( t, ival ) ) {\n            return XML_SUCCESS;\n        }\n        return XML_CAN_NOT_CONVERT_TEXT;\n    }\n    return XML_NO_TEXT_NODE;\n}\n\n\nXMLError XMLElement::QueryUnsignedText( unsigned* uval ) const\n{\n    if ( FirstChild() && FirstChild()->ToText() ) {\n        const char* t = FirstChild()->Value();\n        if ( XMLUtil::ToUnsigned( t, uval ) ) {\n            return XML_SUCCESS;\n        }\n        return XML_CAN_NOT_CONVERT_TEXT;\n    }\n    return XML_NO_TEXT_NODE;\n}\n\n\nXMLError XMLElement::QueryInt64Text(int64_t* ival) const\n{\n\tif (FirstChild() && FirstChild()->ToText()) {\n\t\tconst char* t = FirstChild()->Value();\n\t\tif (XMLUtil::ToInt64(t, ival)) {\n\t\t\treturn XML_SUCCESS;\n\t\t}\n\t\treturn XML_CAN_NOT_CONVERT_TEXT;\n\t}\n\treturn XML_NO_TEXT_NODE;\n}\n\n\nXMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const\n{\n    if(FirstChild() && FirstChild()->ToText()) {\n        const char* t = FirstChild()->Value();\n        if(XMLUtil::ToUnsigned64(t, uval)) {\n            return XML_SUCCESS;\n        }\n        return XML_CAN_NOT_CONVERT_TEXT;\n    }\n    return XML_NO_TEXT_NODE;\n}\n\n\nXMLError XMLElement::QueryBoolText( bool* bval ) const\n{\n    if ( FirstChild() && FirstChild()->ToText() ) {\n        const char* t = FirstChild()->Value();\n        if ( XMLUtil::ToBool( t, bval ) ) {\n            return XML_SUCCESS;\n        }\n        return XML_CAN_NOT_CONVERT_TEXT;\n    }\n    return XML_NO_TEXT_NODE;\n}\n\n\nXMLError XMLElement::QueryDoubleText( double* dval ) const\n{\n    if ( FirstChild() && FirstChild()->ToText() ) {\n        const char* t = FirstChild()->Value();\n        if ( XMLUtil::ToDouble( t, dval ) ) {\n            return XML_SUCCESS;\n        }\n        return XML_CAN_NOT_CONVERT_TEXT;\n    }\n    return XML_NO_TEXT_NODE;\n}\n\n\nXMLError XMLElement::QueryFloatText( float* fval ) const\n{\n    if ( FirstChild() && FirstChild()->ToText() ) {\n        const char* t = FirstChild()->Value();\n        if ( XMLUtil::ToFloat( t, fval ) ) {\n            return XML_SUCCESS;\n        }\n        return XML_CAN_NOT_CONVERT_TEXT;\n    }\n    return XML_NO_TEXT_NODE;\n}\n\nint XMLElement::IntText(int defaultValue) const\n{\n\tint i = defaultValue;\n\tQueryIntText(&i);\n\treturn i;\n}\n\nunsigned XMLElement::UnsignedText(unsigned defaultValue) const\n{\n\tunsigned i = defaultValue;\n\tQueryUnsignedText(&i);\n\treturn i;\n}\n\nint64_t XMLElement::Int64Text(int64_t defaultValue) const\n{\n\tint64_t i = defaultValue;\n\tQueryInt64Text(&i);\n\treturn i;\n}\n\nuint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const\n{\n\tuint64_t i = defaultValue;\n\tQueryUnsigned64Text(&i);\n\treturn i;\n}\n\nbool XMLElement::BoolText(bool defaultValue) const\n{\n\tbool b = defaultValue;\n\tQueryBoolText(&b);\n\treturn b;\n}\n\ndouble XMLElement::DoubleText(double defaultValue) const\n{\n\tdouble d = defaultValue;\n\tQueryDoubleText(&d);\n\treturn d;\n}\n\nfloat XMLElement::FloatText(float defaultValue) const\n{\n\tfloat f = defaultValue;\n\tQueryFloatText(&f);\n\treturn f;\n}\n\n\nXMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )\n{\n    XMLAttribute* last = 0;\n    XMLAttribute* attrib = 0;\n    for( attrib = _rootAttribute;\n            attrib;\n            last = attrib, attrib = attrib->_next ) {\n        if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {\n            break;\n        }\n    }\n    if ( !attrib ) {\n        attrib = CreateAttribute();\n        TIXMLASSERT( attrib );\n        if ( last ) {\n            TIXMLASSERT( last->_next == 0 );\n            last->_next = attrib;\n        }\n        else {\n            TIXMLASSERT( _rootAttribute == 0 );\n            _rootAttribute = attrib;\n        }\n        attrib->SetName( name );\n    }\n    return attrib;\n}\n\n\nvoid XMLElement::DeleteAttribute( const char* name )\n{\n    XMLAttribute* prev = 0;\n    for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {\n        if ( XMLUtil::StringEqual( name, a->Name() ) ) {\n            if ( prev ) {\n                prev->_next = a->_next;\n            }\n            else {\n                _rootAttribute = a->_next;\n            }\n            DeleteAttribute( a );\n            break;\n        }\n        prev = a;\n    }\n}\n\n\nchar* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )\n{\n    XMLAttribute* prevAttribute = 0;\n\n    // Read the attributes.\n    while( p ) {\n        p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\n        if ( !(*p) ) {\n            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, \"XMLElement name=%s\", Name() );\n            return 0;\n        }\n\n        // attribute.\n        if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {\n            XMLAttribute* attrib = CreateAttribute();\n            TIXMLASSERT( attrib );\n            attrib->_parseLineNum = _document->_parseCurLineNum;\n\n            const int attrLineNum = attrib->_parseLineNum;\n\n            p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );\n            if ( !p || Attribute( attrib->Name() ) ) {\n                DeleteAttribute( attrib );\n                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, \"XMLElement name=%s\", Name() );\n                return 0;\n            }\n            // There is a minor bug here: if the attribute in the source xml\n            // document is duplicated, it will not be detected and the\n            // attribute will be doubly added. However, tracking the 'prevAttribute'\n            // avoids re-scanning the attribute list. Preferring performance for\n            // now, may reconsider in the future.\n            if ( prevAttribute ) {\n                TIXMLASSERT( prevAttribute->_next == 0 );\n                prevAttribute->_next = attrib;\n            }\n            else {\n                TIXMLASSERT( _rootAttribute == 0 );\n                _rootAttribute = attrib;\n            }\n            prevAttribute = attrib;\n        }\n        // end of the tag\n        else if ( *p == '>' ) {\n            ++p;\n            break;\n        }\n        // end of the tag\n        else if ( *p == '/' && *(p+1) == '>' ) {\n            _closingType = CLOSED;\n            return p+2;\t// done; sealed element.\n        }\n        else {\n            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );\n            return 0;\n        }\n    }\n    return p;\n}\n\nvoid XMLElement::DeleteAttribute( XMLAttribute* attribute )\n{\n    if ( attribute == 0 ) {\n        return;\n    }\n    MemPool* pool = attribute->_memPool;\n    attribute->~XMLAttribute();\n    pool->Free( attribute );\n}\n\nXMLAttribute* XMLElement::CreateAttribute()\n{\n    TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );\n    XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();\n    TIXMLASSERT( attrib );\n    attrib->_memPool = &_document->_attributePool;\n    attrib->_memPool->SetTracked();\n    return attrib;\n}\n\n\nXMLElement* XMLElement::InsertNewChildElement(const char* name)\n{\n    XMLElement* node = _document->NewElement(name);\n    return InsertEndChild(node) ? node : 0;\n}\n\nXMLComment* XMLElement::InsertNewComment(const char* comment)\n{\n    XMLComment* node = _document->NewComment(comment);\n    return InsertEndChild(node) ? node : 0;\n}\n\nXMLText* XMLElement::InsertNewText(const char* text)\n{\n    XMLText* node = _document->NewText(text);\n    return InsertEndChild(node) ? node : 0;\n}\n\nXMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)\n{\n    XMLDeclaration* node = _document->NewDeclaration(text);\n    return InsertEndChild(node) ? node : 0;\n}\n\nXMLUnknown* XMLElement::InsertNewUnknown(const char* text)\n{\n    XMLUnknown* node = _document->NewUnknown(text);\n    return InsertEndChild(node) ? node : 0;\n}\n\n\n\n//\n//\t<ele></ele>\n//\t<ele>foo<b>bar</b></ele>\n//\nchar* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )\n{\n    // Read the element name.\n    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );\n\n    // The closing element is the </element> form. It is\n    // parsed just like a regular element then deleted from\n    // the DOM.\n    if ( *p == '/' ) {\n        _closingType = CLOSING;\n        ++p;\n    }\n\n    p = _value.ParseName( p );\n    if ( _value.Empty() ) {\n        return 0;\n    }\n\n    p = ParseAttributes( p, curLineNumPtr );\n    if ( !p || !*p || _closingType != OPEN ) {\n        return p;\n    }\n\n    p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );\n    return p;\n}\n\n\n\nXMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const\n{\n    if ( !doc ) {\n        doc = _document;\n    }\n    XMLElement* element = doc->NewElement( Value() );\t\t\t\t\t// fixme: this will always allocate memory. Intern?\n    for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {\n        element->SetAttribute( a->Name(), a->Value() );\t\t\t\t\t// fixme: this will always allocate memory. Intern?\n    }\n    return element;\n}\n\n\nbool XMLElement::ShallowEqual( const XMLNode* compare ) const\n{\n    TIXMLASSERT( compare );\n    const XMLElement* other = compare->ToElement();\n    if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {\n\n        const XMLAttribute* a=FirstAttribute();\n        const XMLAttribute* b=other->FirstAttribute();\n\n        while ( a && b ) {\n            if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {\n                return false;\n            }\n            a = a->Next();\n            b = b->Next();\n        }\n        if ( a || b ) {\n            // different count\n            return false;\n        }\n        return true;\n    }\n    return false;\n}\n\n\nbool XMLElement::Accept( XMLVisitor* visitor ) const\n{\n    TIXMLASSERT( visitor );\n    if ( visitor->VisitEnter( *this, _rootAttribute ) ) {\n        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {\n            if ( !node->Accept( visitor ) ) {\n                break;\n            }\n        }\n    }\n    return visitor->VisitExit( *this );\n}\n\n\n// --------- XMLDocument ----------- //\n\n// Warning: List must match 'enum XMLError'\nconst char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {\n    \"XML_SUCCESS\",\n    \"XML_NO_ATTRIBUTE\",\n    \"XML_WRONG_ATTRIBUTE_TYPE\",\n    \"XML_ERROR_FILE_NOT_FOUND\",\n    \"XML_ERROR_FILE_COULD_NOT_BE_OPENED\",\n    \"XML_ERROR_FILE_READ_ERROR\",\n    \"XML_ERROR_PARSING_ELEMENT\",\n    \"XML_ERROR_PARSING_ATTRIBUTE\",\n    \"XML_ERROR_PARSING_TEXT\",\n    \"XML_ERROR_PARSING_CDATA\",\n    \"XML_ERROR_PARSING_COMMENT\",\n    \"XML_ERROR_PARSING_DECLARATION\",\n    \"XML_ERROR_PARSING_UNKNOWN\",\n    \"XML_ERROR_EMPTY_DOCUMENT\",\n    \"XML_ERROR_MISMATCHED_ELEMENT\",\n    \"XML_ERROR_PARSING\",\n    \"XML_CAN_NOT_CONVERT_TEXT\",\n    \"XML_NO_TEXT_NODE\",\n\t\"XML_ELEMENT_DEPTH_EXCEEDED\"\n};\n\n\nXMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :\n    XMLNode( 0 ),\n    _writeBOM( false ),\n    _processEntities( processEntities ),\n    _errorID(XML_SUCCESS),\n    _whitespaceMode( whitespaceMode ),\n    _errorStr(),\n    _errorLineNum( 0 ),\n    _charBuffer( 0 ),\n    _parseCurLineNum( 0 ),\n\t_parsingDepth(0),\n    _unlinked(),\n    _elementPool(),\n    _attributePool(),\n    _textPool(),\n    _commentPool()\n{\n    // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)\n    _document = this;\n}\n\n\nXMLDocument::~XMLDocument()\n{\n    Clear();\n}\n\n\nvoid XMLDocument::MarkInUse(const XMLNode* const node)\n{\n\tTIXMLASSERT(node);\n\tTIXMLASSERT(node->_parent == 0);\n\n\tfor (size_t i = 0; i < _unlinked.Size(); ++i) {\n\t\tif (node == _unlinked[i]) {\n\t\t\t_unlinked.SwapRemove(i);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid XMLDocument::Clear()\n{\n    DeleteChildren();\n\twhile( _unlinked.Size()) {\n\t\tDeleteNode(_unlinked[0]);\t// Will remove from _unlinked as part of delete.\n\t}\n\n#ifdef TINYXML2_DEBUG\n    const bool hadError = Error();\n#endif\n    ClearError();\n\n    delete [] _charBuffer;\n    _charBuffer = 0;\n\t_parsingDepth = 0;\n\n#if 0\n    _textPool.Trace( \"text\" );\n    _elementPool.Trace( \"element\" );\n    _commentPool.Trace( \"comment\" );\n    _attributePool.Trace( \"attribute\" );\n#endif\n\n#ifdef TINYXML2_DEBUG\n    if ( !hadError ) {\n        TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );\n        TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );\n        TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );\n        TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );\n    }\n#endif\n}\n\n\nvoid XMLDocument::DeepCopy(XMLDocument* target) const\n{\n\tTIXMLASSERT(target);\n    if (target == this) {\n        return; // technically success - a no-op.\n    }\n\n\ttarget->Clear();\n\tfor (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {\n\t\ttarget->InsertEndChild(node->DeepClone(target));\n\t}\n}\n\nXMLElement* XMLDocument::NewElement( const char* name )\n{\n    XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );\n    ele->SetName( name );\n    return ele;\n}\n\n\nXMLComment* XMLDocument::NewComment( const char* str )\n{\n    XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );\n    comment->SetValue( str );\n    return comment;\n}\n\n\nXMLText* XMLDocument::NewText( const char* str )\n{\n    XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );\n    text->SetValue( str );\n    return text;\n}\n\n\nXMLDeclaration* XMLDocument::NewDeclaration( const char* str )\n{\n    XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );\n    dec->SetValue( str ? str : \"xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"\" );\n    return dec;\n}\n\n\nXMLUnknown* XMLDocument::NewUnknown( const char* str )\n{\n    XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );\n    unk->SetValue( str );\n    return unk;\n}\n\nstatic FILE* callfopen( const char* filepath, const char* mode )\n{\n    TIXMLASSERT( filepath );\n    TIXMLASSERT( mode );\n#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)\n    FILE* fp = 0;\n    const errno_t err = fopen_s( &fp, filepath, mode );\n    if ( err ) {\n        return 0;\n    }\n#else\n    FILE* fp = fopen( filepath, mode );\n#endif\n    return fp;\n}\n\nvoid XMLDocument::DeleteNode( XMLNode* node )\t{\n    TIXMLASSERT( node );\n    TIXMLASSERT(node->_document == this );\n    if (node->_parent) {\n        node->_parent->DeleteChild( node );\n    }\n    else {\n        // Isn't in the tree.\n        // Use the parent delete.\n        // Also, we need to mark it tracked: we 'know'\n        // it was never used.\n        node->_memPool->SetTracked();\n        // Call the static XMLNode version:\n        XMLNode::DeleteNode(node);\n    }\n}\n\n\nXMLError XMLDocument::LoadFile( const char* filename )\n{\n    if ( !filename ) {\n        TIXMLASSERT( false );\n        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, \"filename=<null>\" );\n        return _errorID;\n    }\n\n    Clear();\n    FILE* fp = callfopen( filename, \"rb\" );\n    if ( !fp ) {\n        SetError( XML_ERROR_FILE_NOT_FOUND, 0, \"filename=%s\", filename );\n        return _errorID;\n    }\n    LoadFile( fp );\n    fclose( fp );\n    return _errorID;\n}\n\nXMLError XMLDocument::LoadFile( FILE* fp )\n{\n    Clear();\n\n    TIXML_FSEEK( fp, 0, SEEK_SET );\n    if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {\n        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\n        return _errorID;\n    }\n\n    TIXML_FSEEK( fp, 0, SEEK_END );\n\n    unsigned long long filelength;\n    {\n        const long long fileLengthSigned = TIXML_FTELL( fp );\n        TIXML_FSEEK( fp, 0, SEEK_SET );\n        if ( fileLengthSigned == -1L ) {\n            SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\n            return _errorID;\n        }\n        TIXMLASSERT( fileLengthSigned >= 0 );\n        filelength = static_cast<unsigned long long>(fileLengthSigned);\n    }\n\n    const size_t maxSizeT = static_cast<size_t>(-1);\n    // We'll do the comparison as an unsigned long long, because that's guaranteed to be at\n    // least 8 bytes, even on a 32-bit platform.\n    if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {\n        // Cannot handle files which won't fit in buffer together with null terminator\n        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\n        return _errorID;\n    }\n\n    if ( filelength == 0 ) {\n        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );\n        return _errorID;\n    }\n\n    const size_t size = static_cast<size_t>(filelength);\n    TIXMLASSERT( _charBuffer == 0 );\n    _charBuffer = new char[size+1];\n    const size_t read = fread( _charBuffer, 1, size, fp );\n    if ( read != size ) {\n        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );\n        return _errorID;\n    }\n\n    _charBuffer[size] = 0;\n\n    Parse();\n    return _errorID;\n}\n\n\nXMLError XMLDocument::SaveFile( const char* filename, bool compact )\n{\n    if ( !filename ) {\n        TIXMLASSERT( false );\n        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, \"filename=<null>\" );\n        return _errorID;\n    }\n\n    FILE* fp = callfopen( filename, \"w\" );\n    if ( !fp ) {\n        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, \"filename=%s\", filename );\n        return _errorID;\n    }\n    SaveFile(fp, compact);\n    fclose( fp );\n    return _errorID;\n}\n\n\nXMLError XMLDocument::SaveFile( FILE* fp, bool compact )\n{\n    // Clear any error from the last save, otherwise it will get reported\n    // for *this* call.\n    ClearError();\n    XMLPrinter stream( fp, compact );\n    Print( &stream );\n    return _errorID;\n}\n\n\nXMLError XMLDocument::Parse( const char* xml, size_t nBytes )\n{\n    Clear();\n\n    if ( nBytes == 0 || !xml || !*xml ) {\n        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );\n        return _errorID;\n    }\n    if ( nBytes == static_cast<size_t>(-1) ) {\n        nBytes = strlen( xml );\n    }\n    TIXMLASSERT( _charBuffer == 0 );\n    _charBuffer = new char[ nBytes+1 ];\n    memcpy( _charBuffer, xml, nBytes );\n    _charBuffer[nBytes] = 0;\n\n    Parse();\n    if ( Error() ) {\n        // clean up now essentially dangling memory.\n        // and the parse fail can put objects in the\n        // pools that are dead and inaccessible.\n        DeleteChildren();\n        _elementPool.Clear();\n        _attributePool.Clear();\n        _textPool.Clear();\n        _commentPool.Clear();\n    }\n    return _errorID;\n}\n\n\nvoid XMLDocument::Print( XMLPrinter* streamer ) const\n{\n    if ( streamer ) {\n        Accept( streamer );\n    }\n    else {\n        XMLPrinter stdoutStreamer( stdout );\n        Accept( &stdoutStreamer );\n    }\n}\n\n\nvoid XMLDocument::ClearError() {\n    _errorID = XML_SUCCESS;\n    _errorLineNum = 0;\n    _errorStr.Reset();\n}\n\n\nvoid XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )\n{\n    TIXMLASSERT(error >= 0 && error < XML_ERROR_COUNT);\n    _errorID = error;\n    _errorLineNum = lineNum;\n\t_errorStr.Reset();\n\n    const size_t BUFFER_SIZE = 1000;\n    char* buffer = new char[BUFFER_SIZE];\n\n    TIXMLASSERT(sizeof(error) <= sizeof(int));\n    TIXML_SNPRINTF(buffer, BUFFER_SIZE, \"Error=%s ErrorID=%d (0x%x) Line number=%d\",\n        ErrorIDToName(error), static_cast<int>(error), static_cast<unsigned int>(error), lineNum);\n\n\tif (format) {\n\t\tsize_t len = strlen(buffer);\n\t\tTIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, \": \");\n\t\tlen = strlen(buffer);\n\n\t\tva_list va;\n\t\tva_start(va, format);\n\t\tTIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);\n\t\tva_end(va);\n\t}\n\t_errorStr.SetStr(buffer);\n\tdelete[] buffer;\n}\n\n\n/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)\n{\n\tTIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );\n    const char* errorName = _errorNames[errorID];\n    TIXMLASSERT( errorName && errorName[0] );\n    return errorName;\n}\n\nconst char* XMLDocument::ErrorStr() const\n{\n\treturn _errorStr.Empty() ? \"\" : _errorStr.GetStr();\n}\n\n\nvoid XMLDocument::PrintError() const\n{\n    printf(\"%s\\n\", ErrorStr());\n}\n\nconst char* XMLDocument::ErrorName() const\n{\n    return ErrorIDToName(_errorID);\n}\n\nvoid XMLDocument::Parse()\n{\n    TIXMLASSERT( NoChildren() ); // Clear() must have been called previously\n    TIXMLASSERT( _charBuffer );\n    _parseCurLineNum = 1;\n    _parseLineNum = 1;\n    char* p = _charBuffer;\n    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );\n    p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );\n    if ( !*p ) {\n        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );\n        return;\n    }\n    ParseDeep(p, 0, &_parseCurLineNum );\n}\n\nvoid XMLDocument::PushDepth()\n{\n\t_parsingDepth++;\n\tif (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {\n\t\tSetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, \"Element nesting is too deep.\" );\n\t}\n}\n\nvoid XMLDocument::PopDepth()\n{\n\tTIXMLASSERT(_parsingDepth > 0);\n\t--_parsingDepth;\n}\n\nXMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :\n    _elementJustOpened( false ),\n    _stack(),\n    _firstElement( true ),\n    _fp( file ),\n    _depth( depth ),\n    _textDepth( -1 ),\n    _processEntities( true ),\n    _compactMode( compact ),\n    _buffer()\n{\n    for( int i=0; i<ENTITY_RANGE; ++i ) {\n        _entityFlag[i] = false;\n        _restrictedEntityFlag[i] = false;\n    }\n    for( int i=0; i<NUM_ENTITIES; ++i ) {\n        const char entityValue = entities[i].value;\n        const unsigned char flagIndex = static_cast<unsigned char>(entityValue);\n        TIXMLASSERT( flagIndex < ENTITY_RANGE );\n        _entityFlag[flagIndex] = true;\n    }\n    _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;\n    _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;\n    _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;\t// not required, but consistency is nice\n    _buffer.Push( 0 );\n}\n\n\nvoid XMLPrinter::Print( const char* format, ... )\n{\n    va_list     va;\n    va_start( va, format );\n\n    if ( _fp ) {\n        vfprintf( _fp, format, va );\n    }\n    else {\n        const int len = TIXML_VSCPRINTF( format, va );\n        // Close out and re-start the va-args\n        va_end( va );\n        TIXMLASSERT( len >= 0 );\n        va_start( va, format );\n        TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );\n        char* p = _buffer.PushArr( len ) - 1;\t// back up over the null terminator.\n\t\tTIXML_VSNPRINTF( p, len+1, format, va );\n    }\n    va_end( va );\n}\n\n\nvoid XMLPrinter::Write( const char* data, size_t size )\n{\n    if ( _fp ) {\n        fwrite ( data , sizeof(char), size, _fp);\n    }\n    else {\n        char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.\n        memcpy( p, data, size );\n        p[size] = 0;\n    }\n}\n\n\nvoid XMLPrinter::Putc( char ch )\n{\n    if ( _fp ) {\n        fputc ( ch, _fp);\n    }\n    else {\n        char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.\n        p[0] = ch;\n        p[1] = 0;\n    }\n}\n\n\nvoid XMLPrinter::PrintSpace( int depth )\n{\n    for( int i=0; i<depth; ++i ) {\n        Write( \"    \" );\n    }\n}\n\n\nvoid XMLPrinter::PrintString( const char* p, bool restricted )\n{\n    // Look for runs of bytes between entities to print.\n    const char* q = p;\n\n    if ( _processEntities ) {\n        const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;\n        while ( *q ) {\n            TIXMLASSERT( p <= q );\n            // Remember, char is sometimes signed. (How many times has that bitten me?)\n            if ( *q > 0 && *q < ENTITY_RANGE ) {\n                // Check for entities. If one is found, flush\n                // the stream up until the entity, write the\n                // entity, and keep looking.\n                if ( flag[static_cast<unsigned char>(*q)] ) {\n                    while ( p < q ) {\n                        const size_t delta = q - p;\n                        const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);\n                        Write( p, toPrint );\n                        p += toPrint;\n                    }\n                    bool entityPatternPrinted = false;\n                    for( int i=0; i<NUM_ENTITIES; ++i ) {\n                        if ( entities[i].value == *q ) {\n                            Putc( '&' );\n                            Write( entities[i].pattern, entities[i].length );\n                            Putc( ';' );\n                            entityPatternPrinted = true;\n                            break;\n                        }\n                    }\n                    if ( !entityPatternPrinted ) {\n                        // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release\n                        TIXMLASSERT( false );\n                    }\n                    ++p;\n                }\n            }\n            ++q;\n            TIXMLASSERT( p <= q );\n        }\n        // Flush the remaining string. This will be the entire\n        // string if an entity wasn't found.\n        if ( p < q ) {\n            const size_t delta = q - p;\n            const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);\n            Write( p, toPrint );\n        }\n    }\n    else {\n        Write( p );\n    }\n}\n\n\nvoid XMLPrinter::PushHeader( bool writeBOM, bool writeDec )\n{\n    if ( writeBOM ) {\n        static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };\n        Write( reinterpret_cast< const char* >( bom ) );\n    }\n    if ( writeDec ) {\n        PushDeclaration( \"xml version=\\\"1.0\\\"\" );\n    }\n}\n\nvoid XMLPrinter::PrepareForNewNode( bool compactMode )\n{\n    SealElementIfJustOpened();\n\n    if ( compactMode ) {\n        return;\n    }\n\n    if ( _firstElement ) {\n        PrintSpace (_depth);\n    } else if ( _textDepth < 0) {\n        Putc( '\\n' );\n        PrintSpace( _depth );\n    }\n\n    _firstElement = false;\n}\n\nvoid XMLPrinter::OpenElement( const char* name, bool compactMode )\n{\n    PrepareForNewNode( compactMode );\n    _stack.Push( name );\n\n    Write ( \"<\" );\n    Write ( name );\n\n    _elementJustOpened = true;\n    ++_depth;\n}\n\n\nvoid XMLPrinter::PushAttribute( const char* name, const char* value )\n{\n    TIXMLASSERT( _elementJustOpened );\n    Putc ( ' ' );\n    Write( name );\n    Write( \"=\\\"\" );\n    PrintString( value, false );\n    Putc ( '\\\"' );\n}\n\n\nvoid XMLPrinter::PushAttribute( const char* name, int v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    PushAttribute( name, buf );\n}\n\n\nvoid XMLPrinter::PushAttribute( const char* name, unsigned v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    PushAttribute( name, buf );\n}\n\n\nvoid XMLPrinter::PushAttribute(const char* name, int64_t v)\n{\n\tchar buf[BUF_SIZE];\n\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\tPushAttribute(name, buf);\n}\n\n\nvoid XMLPrinter::PushAttribute(const char* name, uint64_t v)\n{\n\tchar buf[BUF_SIZE];\n\tXMLUtil::ToStr(v, buf, BUF_SIZE);\n\tPushAttribute(name, buf);\n}\n\n\nvoid XMLPrinter::PushAttribute( const char* name, bool v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    PushAttribute( name, buf );\n}\n\n\nvoid XMLPrinter::PushAttribute( const char* name, double v )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( v, buf, BUF_SIZE );\n    PushAttribute( name, buf );\n}\n\n\nvoid XMLPrinter::CloseElement( bool compactMode )\n{\n    --_depth;\n    const char* name = _stack.Pop();\n\n    if ( _elementJustOpened ) {\n        Write( \"/>\" );\n    }\n    else {\n        if ( _textDepth < 0 && !compactMode) {\n            Putc( '\\n' );\n            PrintSpace( _depth );\n        }\n        Write ( \"</\" );\n        Write ( name );\n        Write ( \">\" );\n    }\n\n    if ( _textDepth == _depth ) {\n        _textDepth = -1;\n    }\n    if ( _depth == 0 && !compactMode) {\n        Putc( '\\n' );\n    }\n    _elementJustOpened = false;\n}\n\n\nvoid XMLPrinter::SealElementIfJustOpened()\n{\n    if ( !_elementJustOpened ) {\n        return;\n    }\n    _elementJustOpened = false;\n    Putc( '>' );\n}\n\n\nvoid XMLPrinter::PushText( const char* text, bool cdata )\n{\n    _textDepth = _depth-1;\n\n    SealElementIfJustOpened();\n    if ( cdata ) {\n        Write( \"<![CDATA[\" );\n        Write( text );\n        Write( \"]]>\" );\n    }\n    else {\n        PrintString( text, true );\n    }\n}\n\n\nvoid XMLPrinter::PushText( int64_t value )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( value, buf, BUF_SIZE );\n    PushText( buf, false );\n}\n\n\nvoid XMLPrinter::PushText( uint64_t value )\n{\n\tchar buf[BUF_SIZE];\n\tXMLUtil::ToStr(value, buf, BUF_SIZE);\n\tPushText(buf, false);\n}\n\n\nvoid XMLPrinter::PushText( int value )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( value, buf, BUF_SIZE );\n    PushText( buf, false );\n}\n\n\nvoid XMLPrinter::PushText( unsigned value )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( value, buf, BUF_SIZE );\n    PushText( buf, false );\n}\n\n\nvoid XMLPrinter::PushText( bool value )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( value, buf, BUF_SIZE );\n    PushText( buf, false );\n}\n\n\nvoid XMLPrinter::PushText( float value )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( value, buf, BUF_SIZE );\n    PushText( buf, false );\n}\n\n\nvoid XMLPrinter::PushText( double value )\n{\n    char buf[BUF_SIZE];\n    XMLUtil::ToStr( value, buf, BUF_SIZE );\n    PushText( buf, false );\n}\n\n\nvoid XMLPrinter::PushComment( const char* comment )\n{\n    PrepareForNewNode( _compactMode );\n\n    Write( \"<!--\" );\n    Write( comment );\n    Write( \"-->\" );\n}\n\n\nvoid XMLPrinter::PushDeclaration( const char* value )\n{\n    PrepareForNewNode( _compactMode );\n\n    Write( \"<?\" );\n    Write( value );\n    Write( \"?>\" );\n}\n\n\nvoid XMLPrinter::PushUnknown( const char* value )\n{\n    PrepareForNewNode( _compactMode );\n\n    Write( \"<!\" );\n    Write( value );\n    Putc( '>' );\n}\n\n\nbool XMLPrinter::VisitEnter( const XMLDocument& doc )\n{\n    _processEntities = doc.ProcessEntities();\n    if ( doc.HasBOM() ) {\n        PushHeader( true, false );\n    }\n    return true;\n}\n\n\nbool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )\n{\n    const XMLElement* parentElem = 0;\n    if ( element.Parent() ) {\n        parentElem = element.Parent()->ToElement();\n    }\n    const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;\n    OpenElement( element.Name(), compactMode );\n    while ( attribute ) {\n        PushAttribute( attribute->Name(), attribute->Value() );\n        attribute = attribute->Next();\n    }\n    return true;\n}\n\n\nbool XMLPrinter::VisitExit( const XMLElement& element )\n{\n    CloseElement( CompactMode(element) );\n    return true;\n}\n\n\nbool XMLPrinter::Visit( const XMLText& text )\n{\n    PushText( text.Value(), text.CData() );\n    return true;\n}\n\n\nbool XMLPrinter::Visit( const XMLComment& comment )\n{\n    PushComment( comment.Value() );\n    return true;\n}\n\nbool XMLPrinter::Visit( const XMLDeclaration& declaration )\n{\n    PushDeclaration( declaration.Value() );\n    return true;\n}\n\n\nbool XMLPrinter::Visit( const XMLUnknown& unknown )\n{\n    PushUnknown( unknown.Value() );\n    return true;\n}\n\n}   // namespace tinyxml2\n"
  },
  {
    "path": "lib/TinyXML-2/tinyxml2.h",
    "content": "/*\nOriginal code by Lee Thomason (www.grinninglizard.com)\n\nThis software is provided 'as-is', without any express or implied\nwarranty. In no event will the authors be held liable for any\ndamages arising from the use of this software.\n\nPermission is granted to anyone to use this software for any\npurpose, including commercial applications, and to alter it and\nredistribute it freely, subject to the following restrictions:\n\n1. The origin of this software must not be misrepresented; you must\nnot claim that you wrote the original software. If you use this\nsoftware in a product, an acknowledgment in the product documentation\nwould be appreciated but is not required.\n\n2. Altered source versions must be plainly marked as such, and\nmust not be misrepresented as being the original software.\n\n3. This notice may not be removed or altered from any source\ndistribution.\n*/\n\n#ifndef TINYXML2_INCLUDED\n#define TINYXML2_INCLUDED\n\n#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)\n#   include <ctype.h>\n#   include <limits.h>\n#   include <stdio.h>\n#   include <stdlib.h>\n#   include <string.h>\n#\tif defined(__PS3__)\n#\t\tinclude <stddef.h>\n#\tendif\n#else\n#   include <cctype>\n#   include <climits>\n#   include <cstdio>\n#   include <cstdlib>\n#   include <cstring>\n#endif\n#include <stdint.h>\n\n/*\n\tgcc:\n        g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe\n\n    Formatting, Artistic Style:\n        AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h\n*/\n\n#if defined( _DEBUG ) || defined (__DEBUG__)\n#   ifndef TINYXML2_DEBUG\n#       define TINYXML2_DEBUG\n#   endif\n#endif\n\n#ifdef _MSC_VER\n#   pragma warning(push)\n#   pragma warning(disable: 4251)\n#endif\n\n#ifdef _MSC_VER\n#   ifdef TINYXML2_EXPORT\n#       define TINYXML2_LIB __declspec(dllexport)\n#   elif defined(TINYXML2_IMPORT)\n#       define TINYXML2_LIB __declspec(dllimport)\n#   else\n#       define TINYXML2_LIB\n#   endif\n#elif __GNUC__ >= 4\n#   define TINYXML2_LIB __attribute__((visibility(\"default\")))\n#else\n#   define TINYXML2_LIB\n#endif\n\n\n#if !defined(TIXMLASSERT)\n#if defined(TINYXML2_DEBUG)\n#   if defined(_MSC_VER)\n#       // \"(void)0,\" is for suppressing C4127 warning in \"assert(false)\", \"assert(true)\" and the like\n#       define TIXMLASSERT( x )           do { if ( !((void)0,(x))) { __debugbreak(); } } while(false)\n#   elif defined (ANDROID_NDK)\n#       include <android/log.h>\n#       define TIXMLASSERT( x )           do { if ( !(x)) { __android_log_assert( \"assert\", \"grinliz\", \"ASSERT in '%s' at %d.\", __FILE__, __LINE__ ); } } while(false)\n#   else\n#       include <assert.h>\n#       define TIXMLASSERT                assert\n#   endif\n#else\n#   define TIXMLASSERT( x )               do {} while(false)\n#endif\n#endif\n\n/* Versioning, past 1.0.14:\n\thttp://semver.org/\n*/\nstatic const int TIXML2_MAJOR_VERSION = 10;\nstatic const int TIXML2_MINOR_VERSION = 0;\nstatic const int TIXML2_PATCH_VERSION = 0;\n\n#define TINYXML2_MAJOR_VERSION 10\n#define TINYXML2_MINOR_VERSION 0\n#define TINYXML2_PATCH_VERSION 0\n\n// A fixed element depth limit is problematic. There needs to be a\n// limit to avoid a stack overflow. However, that limit varies per\n// system, and the capacity of the stack. On the other hand, it's a trivial\n// attack that can result from ill, malicious, or even correctly formed XML,\n// so there needs to be a limit in place.\nstatic const int TINYXML2_MAX_ELEMENT_DEPTH = 500;\n\nnamespace tinyxml2\n{\nclass XMLDocument;\nclass XMLElement;\nclass XMLAttribute;\nclass XMLComment;\nclass XMLText;\nclass XMLDeclaration;\nclass XMLUnknown;\nclass XMLPrinter;\n\n/*\n\tA class that wraps strings. Normally stores the start and end\n\tpointers into the XML file itself, and will apply normalization\n\tand entity translation if actually read. Can also store (and memory\n\tmanage) a traditional char[]\n\n    Isn't clear why TINYXML2_LIB is needed; but seems to fix #719\n*/\nclass TINYXML2_LIB StrPair\n{\npublic:\n    enum Mode {\n        NEEDS_ENTITY_PROCESSING\t\t\t= 0x01,\n        NEEDS_NEWLINE_NORMALIZATION\t\t= 0x02,\n        NEEDS_WHITESPACE_COLLAPSING     = 0x04,\n\n        TEXT_ELEMENT\t\t            = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\n        TEXT_ELEMENT_LEAVE_ENTITIES\t\t= NEEDS_NEWLINE_NORMALIZATION,\n        ATTRIBUTE_NAME\t\t            = 0,\n        ATTRIBUTE_VALUE\t\t            = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,\n        ATTRIBUTE_VALUE_LEAVE_ENTITIES  = NEEDS_NEWLINE_NORMALIZATION,\n        COMMENT\t\t\t\t\t\t\t= NEEDS_NEWLINE_NORMALIZATION\n    };\n\n    StrPair() : _flags( 0 ), _start( 0 ), _end( 0 ) {}\n    ~StrPair();\n\n    void Set( char* start, char* end, int flags ) {\n        TIXMLASSERT( start );\n        TIXMLASSERT( end );\n        Reset();\n        _start  = start;\n        _end    = end;\n        _flags  = flags | NEEDS_FLUSH;\n    }\n\n    const char* GetStr();\n\n    bool Empty() const {\n        return _start == _end;\n    }\n\n    void SetInternedStr( const char* str ) {\n        Reset();\n        _start = const_cast<char*>(str);\n    }\n\n    void SetStr( const char* str, int flags=0 );\n\n    char* ParseText( char* in, const char* endTag, int strFlags, int* curLineNumPtr );\n    char* ParseName( char* in );\n\n    void TransferTo( StrPair* other );\n\tvoid Reset();\n\nprivate:\n    void CollapseWhitespace();\n\n    enum {\n        NEEDS_FLUSH = 0x100,\n        NEEDS_DELETE = 0x200\n    };\n\n    int     _flags;\n    char*   _start;\n    char*   _end;\n\n    StrPair( const StrPair& other );\t// not supported\n    void operator=( const StrPair& other );\t// not supported, use TransferTo()\n};\n\n\n/*\n\tA dynamic array of Plain Old Data. Doesn't support constructors, etc.\n\tHas a small initial memory pool, so that low or no usage will not\n\tcause a call to new/delete\n*/\ntemplate <class T, size_t INITIAL_SIZE>\nclass DynArray\n{\npublic:\n    DynArray() :\n        _mem( _pool ),\n        _allocated( INITIAL_SIZE ),\n        _size( 0 )\n    {\n    }\n\n    ~DynArray() {\n        if ( _mem != _pool ) {\n            delete [] _mem;\n        }\n    }\n\n    void Clear() {\n        _size = 0;\n    }\n\n    void Push( T t ) {\n        TIXMLASSERT( _size < INT_MAX );\n        EnsureCapacity( _size+1 );\n        _mem[_size] = t;\n        ++_size;\n    }\n\n    T* PushArr( size_t count ) {\n        TIXMLASSERT( _size <= SIZE_MAX - count );\n        EnsureCapacity( _size+count );\n        T* ret = &_mem[_size];\n        _size += count;\n        return ret;\n    }\n\n    T Pop() {\n        TIXMLASSERT( _size > 0 );\n        --_size;\n        return _mem[_size];\n    }\n\n    void PopArr( size_t count ) {\n        TIXMLASSERT( _size >= count );\n        _size -= count;\n    }\n\n    bool Empty() const\t\t\t\t\t{\n        return _size == 0;\n    }\n\n    T& operator[](size_t i) {\n        TIXMLASSERT( i < _size );\n        return _mem[i];\n    }\n\n    const T& operator[](size_t i) const {\n        TIXMLASSERT( i < _size );\n        return _mem[i];\n    }\n\n    const T& PeekTop() const            {\n        TIXMLASSERT( _size > 0 );\n        return _mem[ _size - 1];\n    }\n\n    size_t Size() const {\n        TIXMLASSERT( _size >= 0 );\n        return _size;\n    }\n\n    size_t Capacity() const {\n        TIXMLASSERT( _allocated >= INITIAL_SIZE );\n        return _allocated;\n    }\n\n\tvoid SwapRemove(size_t i) {\n\t\tTIXMLASSERT(i < _size);\n\t\tTIXMLASSERT(_size > 0);\n\t\t_mem[i] = _mem[_size - 1];\n\t\t--_size;\n\t}\n\n    const T* Mem() const\t\t\t\t{\n        TIXMLASSERT( _mem );\n        return _mem;\n    }\n\n    T* Mem() {\n        TIXMLASSERT( _mem );\n        return _mem;\n    }\n\nprivate:\n    DynArray( const DynArray& ); // not supported\n    void operator=( const DynArray& ); // not supported\n\n    void EnsureCapacity( size_t cap ) {\n        TIXMLASSERT( cap > 0 );\n        if ( cap > _allocated ) {\n            TIXMLASSERT( cap <= SIZE_MAX / 2 / sizeof(T));\n            const size_t newAllocated = cap * 2;\n            T* newMem = new T[newAllocated];\n            TIXMLASSERT( newAllocated >= _size );\n            memcpy( newMem, _mem, sizeof(T) * _size );\t// warning: not using constructors, only works for PODs\n            if ( _mem != _pool ) {\n                delete [] _mem;\n            }\n            _mem = newMem;\n            _allocated = newAllocated;\n        }\n    }\n\n    T*  _mem;\n    T   _pool[INITIAL_SIZE];\n    size_t _allocated;\t\t// objects allocated\n    size_t _size;\t\t\t// number objects in use\n};\n\n\n/*\n\tParent virtual class of a pool for fast allocation\n\tand deallocation of objects.\n*/\nclass MemPool\n{\npublic:\n    MemPool() {}\n    virtual ~MemPool() {}\n\n    virtual size_t ItemSize() const = 0;\n    virtual void* Alloc() = 0;\n    virtual void Free( void* ) = 0;\n    virtual void SetTracked() = 0;\n};\n\n\n/*\n\tTemplate child class to create pools of the correct type.\n*/\ntemplate< size_t ITEM_SIZE >\nclass MemPoolT : public MemPool\n{\npublic:\n    MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0)\t{}\n    ~MemPoolT() {\n        MemPoolT< ITEM_SIZE >::Clear();\n    }\n\n    void Clear() {\n        // Delete the blocks.\n        while( !_blockPtrs.Empty()) {\n            Block* lastBlock = _blockPtrs.Pop();\n            delete lastBlock;\n        }\n        _root = 0;\n        _currentAllocs = 0;\n        _nAllocs = 0;\n        _maxAllocs = 0;\n        _nUntracked = 0;\n    }\n\n    virtual size_t ItemSize() const override {\n        return ITEM_SIZE;\n    }\n    size_t CurrentAllocs() const {\n        return _currentAllocs;\n    }\n\n    virtual void* Alloc() override{\n        if ( !_root ) {\n            // Need a new block.\n            Block* block = new Block;\n            _blockPtrs.Push( block );\n\n            Item* blockItems = block->items;\n            for( size_t i = 0; i < ITEMS_PER_BLOCK - 1; ++i ) {\n                blockItems[i].next = &(blockItems[i + 1]);\n            }\n            blockItems[ITEMS_PER_BLOCK - 1].next = 0;\n            _root = blockItems;\n        }\n        Item* const result = _root;\n        TIXMLASSERT( result != 0 );\n        _root = _root->next;\n\n        ++_currentAllocs;\n        if ( _currentAllocs > _maxAllocs ) {\n            _maxAllocs = _currentAllocs;\n        }\n        ++_nAllocs;\n        ++_nUntracked;\n        return result;\n    }\n\n    virtual void Free( void* mem ) override {\n        if ( !mem ) {\n            return;\n        }\n        --_currentAllocs;\n        Item* item = static_cast<Item*>( mem );\n#ifdef TINYXML2_DEBUG\n        memset( item, 0xfe, sizeof( *item ) );\n#endif\n        item->next = _root;\n        _root = item;\n    }\n    void Trace( const char* name ) {\n        printf( \"Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\\n\",\n                name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,\n                ITEM_SIZE, _nAllocs, _blockPtrs.Size() );\n    }\n\n    void SetTracked() override {\n        --_nUntracked;\n    }\n\n    size_t Untracked() const {\n        return _nUntracked;\n    }\n\n\t// This number is perf sensitive. 4k seems like a good tradeoff on my machine.\n\t// The test file is large, 170k.\n\t// Release:\t\tVS2010 gcc(no opt)\n\t//\t\t1k:\t\t4000\n\t//\t\t2k:\t\t4000\n\t//\t\t4k:\t\t3900\t21000\n\t//\t\t16k:\t5200\n\t//\t\t32k:\t4300\n\t//\t\t64k:\t4000\t21000\n    // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK\n    // in private part if ITEMS_PER_BLOCK is private\n    enum { ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE };\n\nprivate:\n    MemPoolT( const MemPoolT& ); // not supported\n    void operator=( const MemPoolT& ); // not supported\n\n    union Item {\n        Item*   next;\n        char    itemData[static_cast<size_t>(ITEM_SIZE)];\n    };\n    struct Block {\n        Item items[ITEMS_PER_BLOCK];\n    };\n    DynArray< Block*, 10 > _blockPtrs;\n    Item* _root;\n\n    size_t _currentAllocs;\n    size_t _nAllocs;\n    size_t _maxAllocs;\n    size_t _nUntracked;\n};\n\n\n\n/**\n\tImplements the interface to the \"Visitor pattern\" (see the Accept() method.)\n\tIf you call the Accept() method, it requires being passed a XMLVisitor\n\tclass to handle callbacks. For nodes that contain other nodes (Document, Element)\n\tyou will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs\n\tare simply called with Visit().\n\n\tIf you return 'true' from a Visit method, recursive parsing will continue. If you return\n\tfalse, <b>no children of this node or its siblings</b> will be visited.\n\n\tAll flavors of Visit methods have a default implementation that returns 'true' (continue\n\tvisiting). You need to only override methods that are interesting to you.\n\n\tGenerally Accept() is called on the XMLDocument, although all nodes support visiting.\n\n\tYou should never change the document from a callback.\n\n\t@sa XMLNode::Accept()\n*/\nclass TINYXML2_LIB XMLVisitor\n{\npublic:\n    virtual ~XMLVisitor() {}\n\n    /// Visit a document.\n    virtual bool VisitEnter( const XMLDocument& /*doc*/ )\t\t\t{\n        return true;\n    }\n    /// Visit a document.\n    virtual bool VisitExit( const XMLDocument& /*doc*/ )\t\t\t{\n        return true;\n    }\n\n    /// Visit an element.\n    virtual bool VisitEnter( const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/ )\t{\n        return true;\n    }\n    /// Visit an element.\n    virtual bool VisitExit( const XMLElement& /*element*/ )\t\t\t{\n        return true;\n    }\n\n    /// Visit a declaration.\n    virtual bool Visit( const XMLDeclaration& /*declaration*/ )\t\t{\n        return true;\n    }\n    /// Visit a text node.\n    virtual bool Visit( const XMLText& /*text*/ )\t\t\t\t\t{\n        return true;\n    }\n    /// Visit a comment node.\n    virtual bool Visit( const XMLComment& /*comment*/ )\t\t\t\t{\n        return true;\n    }\n    /// Visit an unknown node.\n    virtual bool Visit( const XMLUnknown& /*unknown*/ )\t\t\t\t{\n        return true;\n    }\n};\n\n// WARNING: must match XMLDocument::_errorNames[]\nenum XMLError {\n    XML_SUCCESS = 0,\n    XML_NO_ATTRIBUTE,\n    XML_WRONG_ATTRIBUTE_TYPE,\n    XML_ERROR_FILE_NOT_FOUND,\n    XML_ERROR_FILE_COULD_NOT_BE_OPENED,\n    XML_ERROR_FILE_READ_ERROR,\n    XML_ERROR_PARSING_ELEMENT,\n    XML_ERROR_PARSING_ATTRIBUTE,\n    XML_ERROR_PARSING_TEXT,\n    XML_ERROR_PARSING_CDATA,\n    XML_ERROR_PARSING_COMMENT,\n    XML_ERROR_PARSING_DECLARATION,\n    XML_ERROR_PARSING_UNKNOWN,\n    XML_ERROR_EMPTY_DOCUMENT,\n    XML_ERROR_MISMATCHED_ELEMENT,\n    XML_ERROR_PARSING,\n    XML_CAN_NOT_CONVERT_TEXT,\n    XML_NO_TEXT_NODE,\n\tXML_ELEMENT_DEPTH_EXCEEDED,\n\n\tXML_ERROR_COUNT\n};\n\n\n/*\n\tUtility functionality.\n*/\nclass TINYXML2_LIB XMLUtil\n{\npublic:\n    static const char* SkipWhiteSpace( const char* p, int* curLineNumPtr )\t{\n        TIXMLASSERT( p );\n\n        while( IsWhiteSpace(*p) ) {\n            if (curLineNumPtr && *p == '\\n') {\n                ++(*curLineNumPtr);\n            }\n            ++p;\n        }\n        TIXMLASSERT( p );\n        return p;\n    }\n    static char* SkipWhiteSpace( char* const p, int* curLineNumPtr ) {\n        return const_cast<char*>( SkipWhiteSpace( const_cast<const char*>(p), curLineNumPtr ) );\n    }\n\n    // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't\n    // correct, but simple, and usually works.\n    static bool IsWhiteSpace( char p )\t\t\t\t\t{\n        return !IsUTF8Continuation(p) && isspace( static_cast<unsigned char>(p) );\n    }\n\n    inline static bool IsNameStartChar( unsigned char ch ) {\n        if ( ch >= 128 ) {\n            // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()\n            return true;\n        }\n        if ( isalpha( ch ) ) {\n            return true;\n        }\n        return ch == ':' || ch == '_';\n    }\n\n    inline static bool IsNameChar( unsigned char ch ) {\n        return IsNameStartChar( ch )\n               || isdigit( ch )\n               || ch == '.'\n               || ch == '-';\n    }\n\n    inline static bool IsPrefixHex( const char* p) {\n        p = SkipWhiteSpace(p, 0);\n        return p && *p == '0' && ( *(p + 1) == 'x' || *(p + 1) == 'X');\n    }\n\n    inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX )  {\n        if ( p == q ) {\n            return true;\n        }\n        TIXMLASSERT( p );\n        TIXMLASSERT( q );\n        TIXMLASSERT( nChar >= 0 );\n        return strncmp( p, q, static_cast<size_t>(nChar) ) == 0;\n    }\n\n    inline static bool IsUTF8Continuation( const char p ) {\n        return ( p & 0x80 ) != 0;\n    }\n\n    static const char* ReadBOM( const char* p, bool* hasBOM );\n    // p is the starting location,\n    // the UTF-8 value of the entity will be placed in value, and length filled in.\n    static const char* GetCharacterRef( const char* p, char* value, int* length );\n    static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );\n\n    // converts primitive types to strings\n    static void ToStr( int v, char* buffer, int bufferSize );\n    static void ToStr( unsigned v, char* buffer, int bufferSize );\n    static void ToStr( bool v, char* buffer, int bufferSize );\n    static void ToStr( float v, char* buffer, int bufferSize );\n    static void ToStr( double v, char* buffer, int bufferSize );\n\tstatic void ToStr(int64_t v, char* buffer, int bufferSize);\n    static void ToStr(uint64_t v, char* buffer, int bufferSize);\n\n    // converts strings to primitive types\n    static bool\tToInt( const char* str, int* value );\n    static bool ToUnsigned( const char* str, unsigned* value );\n    static bool\tToBool( const char* str, bool* value );\n    static bool\tToFloat( const char* str, float* value );\n    static bool ToDouble( const char* str, double* value );\n\tstatic bool ToInt64(const char* str, int64_t* value);\n    static bool ToUnsigned64(const char* str, uint64_t* value);\n\t// Changes what is serialized for a boolean value.\n\t// Default to \"true\" and \"false\". Shouldn't be changed\n\t// unless you have a special testing or compatibility need.\n\t// Be careful: static, global, & not thread safe.\n\t// Be sure to set static const memory as parameters.\n\tstatic void SetBoolSerialization(const char* writeTrue, const char* writeFalse);\n\nprivate:\n\tstatic const char* writeBoolTrue;\n\tstatic const char* writeBoolFalse;\n};\n\n\n/** XMLNode is a base class for every object that is in the\n\tXML Document Object Model (DOM), except XMLAttributes.\n\tNodes have siblings, a parent, and children which can\n\tbe navigated. A node is always in a XMLDocument.\n\tThe type of a XMLNode can be queried, and it can\n\tbe cast to its more defined type.\n\n\tA XMLDocument allocates memory for all its Nodes.\n\tWhen the XMLDocument gets deleted, all its Nodes\n\twill also be deleted.\n\n\t@verbatim\n\tA Document can contain:\tElement\t(container or leaf)\n\t\t\t\t\t\t\tComment (leaf)\n\t\t\t\t\t\t\tUnknown (leaf)\n\t\t\t\t\t\t\tDeclaration( leaf )\n\n\tAn Element can contain:\tElement (container or leaf)\n\t\t\t\t\t\t\tText\t(leaf)\n\t\t\t\t\t\t\tAttributes (not on tree)\n\t\t\t\t\t\t\tComment (leaf)\n\t\t\t\t\t\t\tUnknown (leaf)\n\n\t@endverbatim\n*/\nclass TINYXML2_LIB XMLNode\n{\n    friend class XMLDocument;\n    friend class XMLElement;\npublic:\n\n    /// Get the XMLDocument that owns this XMLNode.\n    const XMLDocument* GetDocument() const\t{\n        TIXMLASSERT( _document );\n        return _document;\n    }\n    /// Get the XMLDocument that owns this XMLNode.\n    XMLDocument* GetDocument()\t\t\t\t{\n        TIXMLASSERT( _document );\n        return _document;\n    }\n\n    /// Safely cast to an Element, or null.\n    virtual XMLElement*\t\tToElement()\t\t{\n        return 0;\n    }\n    /// Safely cast to Text, or null.\n    virtual XMLText*\t\tToText()\t\t{\n        return 0;\n    }\n    /// Safely cast to a Comment, or null.\n    virtual XMLComment*\t\tToComment()\t\t{\n        return 0;\n    }\n    /// Safely cast to a Document, or null.\n    virtual XMLDocument*\tToDocument()\t{\n        return 0;\n    }\n    /// Safely cast to a Declaration, or null.\n    virtual XMLDeclaration*\tToDeclaration()\t{\n        return 0;\n    }\n    /// Safely cast to an Unknown, or null.\n    virtual XMLUnknown*\t\tToUnknown()\t\t{\n        return 0;\n    }\n\n    virtual const XMLElement*\t\tToElement() const\t\t{\n        return 0;\n    }\n    virtual const XMLText*\t\t\tToText() const\t\t\t{\n        return 0;\n    }\n    virtual const XMLComment*\t\tToComment() const\t\t{\n        return 0;\n    }\n    virtual const XMLDocument*\t\tToDocument() const\t\t{\n        return 0;\n    }\n    virtual const XMLDeclaration*\tToDeclaration() const\t{\n        return 0;\n    }\n    virtual const XMLUnknown*\t\tToUnknown() const\t\t{\n        return 0;\n    }\n\n    // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2.\n\n    int ChildElementCount(const char *value) const;\n\n    int ChildElementCount() const;\n\n    /** The meaning of 'value' changes for the specific type.\n    \t@verbatim\n    \tDocument:\tempty (NULL is returned, not an empty string)\n    \tElement:\tname of the element\n    \tComment:\tthe comment text\n    \tUnknown:\tthe tag contents\n    \tText:\t\tthe text string\n    \t@endverbatim\n    */\n    const char* Value() const;\n\n    /** Set the Value of an XML node.\n    \t@sa Value()\n    */\n    void SetValue( const char* val, bool staticMem=false );\n\n    /// Gets the line number the node is in, if the document was parsed from a file.\n    int GetLineNum() const { return _parseLineNum; }\n\n    /// Get the parent of this node on the DOM.\n    const XMLNode*\tParent() const\t\t\t{\n        return _parent;\n    }\n\n    XMLNode* Parent()\t\t\t\t\t\t{\n        return _parent;\n    }\n\n    /// Returns true if this node has no children.\n    bool NoChildren() const\t\t\t\t\t{\n        return !_firstChild;\n    }\n\n    /// Get the first child node, or null if none exists.\n    const XMLNode*  FirstChild() const\t\t{\n        return _firstChild;\n    }\n\n    XMLNode*\t\tFirstChild()\t\t\t{\n        return _firstChild;\n    }\n\n    /** Get the first child element, or optionally the first child\n        element with the specified name.\n    */\n    const XMLElement* FirstChildElement( const char* name = 0 ) const;\n\n    XMLElement* FirstChildElement( const char* name = 0 )\t{\n        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement( name ));\n    }\n\n    /// Get the last child node, or null if none exists.\n    const XMLNode*\tLastChild() const\t\t\t\t\t\t{\n        return _lastChild;\n    }\n\n    XMLNode*\t\tLastChild()\t\t\t\t\t\t\t\t{\n        return _lastChild;\n    }\n\n    /** Get the last child element or optionally the last child\n        element with the specified name.\n    */\n    const XMLElement* LastChildElement( const char* name = 0 ) const;\n\n    XMLElement* LastChildElement( const char* name = 0 )\t{\n        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name) );\n    }\n\n    /// Get the previous (left) sibling node of this node.\n    const XMLNode*\tPreviousSibling() const\t\t\t\t\t{\n        return _prev;\n    }\n\n    XMLNode*\tPreviousSibling()\t\t\t\t\t\t\t{\n        return _prev;\n    }\n\n    /// Get the previous (left) sibling element of this node, with an optionally supplied name.\n    const XMLElement*\tPreviousSiblingElement( const char* name = 0 ) const ;\n\n    XMLElement*\tPreviousSiblingElement( const char* name = 0 ) {\n        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( name ) );\n    }\n\n    /// Get the next (right) sibling node of this node.\n    const XMLNode*\tNextSibling() const\t\t\t\t\t\t{\n        return _next;\n    }\n\n    XMLNode*\tNextSibling()\t\t\t\t\t\t\t\t{\n        return _next;\n    }\n\n    /// Get the next (right) sibling element of this node, with an optionally supplied name.\n    const XMLElement*\tNextSiblingElement( const char* name = 0 ) const;\n\n    XMLElement*\tNextSiblingElement( const char* name = 0 )\t{\n        return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( name ) );\n    }\n\n    /**\n    \tAdd a child node as the last (right) child.\n\t\tIf the child node is already part of the document,\n\t\tit is moved from its old location to the new location.\n\t\tReturns the addThis argument or 0 if the node does not\n\t\tbelong to the same document.\n    */\n    XMLNode* InsertEndChild( XMLNode* addThis );\n\n    XMLNode* LinkEndChild( XMLNode* addThis )\t{\n        return InsertEndChild( addThis );\n    }\n    /**\n    \tAdd a child node as the first (left) child.\n\t\tIf the child node is already part of the document,\n\t\tit is moved from its old location to the new location.\n\t\tReturns the addThis argument or 0 if the node does not\n\t\tbelong to the same document.\n    */\n    XMLNode* InsertFirstChild( XMLNode* addThis );\n    /**\n    \tAdd a node after the specified child node.\n\t\tIf the child node is already part of the document,\n\t\tit is moved from its old location to the new location.\n\t\tReturns the addThis argument or 0 if the afterThis node\n\t\tis not a child of this node, or if the node does not\n\t\tbelong to the same document.\n    */\n    XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );\n\n    /**\n    \tDelete all the children of this node.\n    */\n    void DeleteChildren();\n\n    /**\n    \tDelete a child of this node.\n    */\n    void DeleteChild( XMLNode* node );\n\n    /**\n    \tMake a copy of this node, but not its children.\n    \tYou may pass in a Document pointer that will be\n    \tthe owner of the new Node. If the 'document' is\n    \tnull, then the node returned will be allocated\n    \tfrom the current Document. (this->GetDocument())\n\n    \tNote: if called on a XMLDocument, this will return null.\n    */\n    virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;\n\n\t/**\n\t\tMake a copy of this node and all its children.\n\n\t\tIf the 'target' is null, then the nodes will\n\t\tbe allocated in the current document. If 'target'\n        is specified, the memory will be allocated in the\n        specified XMLDocument.\n\n\t\tNOTE: This is probably not the correct tool to\n\t\tcopy a document, since XMLDocuments can have multiple\n\t\ttop level XMLNodes. You probably want to use\n        XMLDocument::DeepCopy()\n\t*/\n\tXMLNode* DeepClone( XMLDocument* target ) const;\n\n    /**\n    \tTest if 2 nodes are the same, but don't test children.\n    \tThe 2 nodes do not need to be in the same Document.\n\n    \tNote: if called on a XMLDocument, this will return false.\n    */\n    virtual bool ShallowEqual( const XMLNode* compare ) const = 0;\n\n    /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the\n    \tXML tree will be conditionally visited and the host will be called back\n    \tvia the XMLVisitor interface.\n\n    \tThis is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse\n    \tthe XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this\n    \tinterface versus any other.)\n\n    \tThe interface has been based on ideas from:\n\n    \t- http://www.saxproject.org/\n    \t- http://c2.com/cgi/wiki?HierarchicalVisitorPattern\n\n    \tWhich are both good references for \"visiting\".\n\n    \tAn example of using Accept():\n    \t@verbatim\n    \tXMLPrinter printer;\n    \ttinyxmlDoc.Accept( &printer );\n    \tconst char* xmlcstr = printer.CStr();\n    \t@endverbatim\n    */\n    virtual bool Accept( XMLVisitor* visitor ) const = 0;\n\n\t/**\n\t\tSet user data into the XMLNode. TinyXML-2 in\n\t\tno way processes or interprets user data.\n\t\tIt is initially 0.\n\t*/\n\tvoid SetUserData(void* userData)\t{ _userData = userData; }\n\n\t/**\n\t\tGet user data set into the XMLNode. TinyXML-2 in\n\t\tno way processes or interprets user data.\n\t\tIt is initially 0.\n\t*/\n\tvoid* GetUserData() const\t\t\t{ return _userData; }\n\nprotected:\n    explicit XMLNode( XMLDocument* );\n    virtual ~XMLNode();\n\n    virtual char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr);\n\n    XMLDocument*\t_document;\n    XMLNode*\t\t_parent;\n    mutable StrPair\t_value;\n    int             _parseLineNum;\n\n    XMLNode*\t\t_firstChild;\n    XMLNode*\t\t_lastChild;\n\n    XMLNode*\t\t_prev;\n    XMLNode*\t\t_next;\n\n\tvoid*\t\t\t_userData;\n\nprivate:\n    MemPool*\t\t_memPool;\n    void Unlink( XMLNode* child );\n    static void DeleteNode( XMLNode* node );\n    void InsertChildPreamble( XMLNode* insertThis ) const;\n    const XMLElement* ToElementWithName( const char* name ) const;\n\n    XMLNode( const XMLNode& );\t// not supported\n    XMLNode& operator=( const XMLNode& );\t// not supported\n};\n\n\n/** XML text.\n\n\tNote that a text node can have child element nodes, for example:\n\t@verbatim\n\t<root>This is <b>bold</b></root>\n\t@endverbatim\n\n\tA text node can have 2 ways to output the next. \"normal\" output\n\tand CDATA. It will default to the mode it was parsed from the XML file and\n\tyou generally want to leave it alone, but you can change the output mode with\n\tSetCData() and query it with CData().\n*/\nclass TINYXML2_LIB XMLText : public XMLNode\n{\n    friend class XMLDocument;\npublic:\n    virtual bool Accept( XMLVisitor* visitor ) const override;\n\n    virtual XMLText* ToText() override\t\t{\n        return this;\n    }\n    virtual const XMLText* ToText() const override {\n        return this;\n    }\n\n    /// Declare whether this should be CDATA or standard text.\n    void SetCData( bool isCData )\t\t\t{\n        _isCData = isCData;\n    }\n    /// Returns true if this is a CDATA text element.\n    bool CData() const\t\t\t\t\t\t{\n        return _isCData;\n    }\n\n    virtual XMLNode* ShallowClone( XMLDocument* document ) const override;\n    virtual bool ShallowEqual( const XMLNode* compare ) const override;\n\nprotected:\n    explicit XMLText( XMLDocument* doc )\t: XMLNode( doc ), _isCData( false )\t{}\n    virtual ~XMLText()\t\t\t\t\t\t\t\t\t\t\t\t{}\n\n    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override;\n\nprivate:\n    bool _isCData;\n\n    XMLText( const XMLText& );\t// not supported\n    XMLText& operator=( const XMLText& );\t// not supported\n};\n\n\n/** An XML Comment. */\nclass TINYXML2_LIB XMLComment : public XMLNode\n{\n    friend class XMLDocument;\npublic:\n    virtual XMLComment*\tToComment() override\t\t{\n        return this;\n    }\n    virtual const XMLComment* ToComment() const override {\n        return this;\n    }\n\n    virtual bool Accept( XMLVisitor* visitor ) const override;\n\n    virtual XMLNode* ShallowClone( XMLDocument* document ) const override;\n    virtual bool ShallowEqual( const XMLNode* compare ) const override;\n\nprotected:\n    explicit XMLComment( XMLDocument* doc );\n    virtual ~XMLComment();\n\n    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr) override;\n\nprivate:\n    XMLComment( const XMLComment& );\t// not supported\n    XMLComment& operator=( const XMLComment& );\t// not supported\n};\n\n\n/** In correct XML the declaration is the first entry in the file.\n\t@verbatim\n\t\t<?xml version=\"1.0\" standalone=\"yes\"?>\n\t@endverbatim\n\n\tTinyXML-2 will happily read or write files without a declaration,\n\thowever.\n\n\tThe text of the declaration isn't interpreted. It is parsed\n\tand written as a string.\n*/\nclass TINYXML2_LIB XMLDeclaration : public XMLNode\n{\n    friend class XMLDocument;\npublic:\n    virtual XMLDeclaration*\tToDeclaration() override\t\t{\n        return this;\n    }\n    virtual const XMLDeclaration* ToDeclaration() const override {\n        return this;\n    }\n\n    virtual bool Accept( XMLVisitor* visitor ) const override;\n\n    virtual XMLNode* ShallowClone( XMLDocument* document ) const override;\n    virtual bool ShallowEqual( const XMLNode* compare ) const override;\n\nprotected:\n    explicit XMLDeclaration( XMLDocument* doc );\n    virtual ~XMLDeclaration();\n\n    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override;\n\nprivate:\n    XMLDeclaration( const XMLDeclaration& );\t// not supported\n    XMLDeclaration& operator=( const XMLDeclaration& );\t// not supported\n};\n\n\n/** Any tag that TinyXML-2 doesn't recognize is saved as an\n\tunknown. It is a tag of text, but should not be modified.\n\tIt will be written back to the XML, unchanged, when the file\n\tis saved.\n\n\tDTD tags get thrown into XMLUnknowns.\n*/\nclass TINYXML2_LIB XMLUnknown : public XMLNode\n{\n    friend class XMLDocument;\npublic:\n    virtual XMLUnknown*\tToUnknown() override\t\t{\n        return this;\n    }\n    virtual const XMLUnknown* ToUnknown() const override {\n        return this;\n    }\n\n    virtual bool Accept( XMLVisitor* visitor ) const override;\n\n    virtual XMLNode* ShallowClone( XMLDocument* document ) const override;\n    virtual bool ShallowEqual( const XMLNode* compare ) const override;\n\nprotected:\n    explicit XMLUnknown( XMLDocument* doc );\n    virtual ~XMLUnknown();\n\n    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override;\n\nprivate:\n    XMLUnknown( const XMLUnknown& );\t// not supported\n    XMLUnknown& operator=( const XMLUnknown& );\t// not supported\n};\n\n\n\n/** An attribute is a name-value pair. Elements have an arbitrary\n\tnumber of attributes, each with a unique name.\n\n\t@note The attributes are not XMLNodes. You may only query the\n\tNext() attribute in a list.\n*/\nclass TINYXML2_LIB XMLAttribute\n{\n    friend class XMLElement;\npublic:\n    /// The name of the attribute.\n    const char* Name() const;\n\n    /// The value of the attribute.\n    const char* Value() const;\n\n    /// Gets the line number the attribute is in, if the document was parsed from a file.\n    int GetLineNum() const { return _parseLineNum; }\n\n    /// The next attribute in the list.\n    const XMLAttribute* Next() const {\n        return _next;\n    }\n\n    /** IntValue interprets the attribute as an integer, and returns the value.\n        If the value isn't an integer, 0 will be returned. There is no error checking;\n    \tuse QueryIntValue() if you need error checking.\n    */\n\tint\tIntValue() const {\n\t\tint i = 0;\n\t\tQueryIntValue(&i);\n\t\treturn i;\n\t}\n\n\tint64_t Int64Value() const {\n\t\tint64_t i = 0;\n\t\tQueryInt64Value(&i);\n\t\treturn i;\n\t}\n\n    uint64_t Unsigned64Value() const {\n        uint64_t i = 0;\n        QueryUnsigned64Value(&i);\n        return i;\n    }\n\n    /// Query as an unsigned integer. See IntValue()\n    unsigned UnsignedValue() const\t\t\t{\n        unsigned i=0;\n        QueryUnsignedValue( &i );\n        return i;\n    }\n    /// Query as a boolean. See IntValue()\n    bool\t BoolValue() const\t\t\t\t{\n        bool b=false;\n        QueryBoolValue( &b );\n        return b;\n    }\n    /// Query as a double. See IntValue()\n    double \t DoubleValue() const\t\t\t{\n        double d=0;\n        QueryDoubleValue( &d );\n        return d;\n    }\n    /// Query as a float. See IntValue()\n    float\t FloatValue() const\t\t\t\t{\n        float f=0;\n        QueryFloatValue( &f );\n        return f;\n    }\n\n    /** QueryIntValue interprets the attribute as an integer, and returns the value\n    \tin the provided parameter. The function will return XML_SUCCESS on success,\n    \tand XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.\n    */\n    XMLError QueryIntValue( int* value ) const;\n    /// See QueryIntValue\n    XMLError QueryUnsignedValue( unsigned int* value ) const;\n\t/// See QueryIntValue\n\tXMLError QueryInt64Value(int64_t* value) const;\n    /// See QueryIntValue\n    XMLError QueryUnsigned64Value(uint64_t* value) const;\n\t/// See QueryIntValue\n    XMLError QueryBoolValue( bool* value ) const;\n    /// See QueryIntValue\n    XMLError QueryDoubleValue( double* value ) const;\n    /// See QueryIntValue\n    XMLError QueryFloatValue( float* value ) const;\n\n    /// Set the attribute to a string value.\n    void SetAttribute( const char* value );\n    /// Set the attribute to value.\n    void SetAttribute( int value );\n    /// Set the attribute to value.\n    void SetAttribute( unsigned value );\n\t/// Set the attribute to value.\n\tvoid SetAttribute(int64_t value);\n    /// Set the attribute to value.\n    void SetAttribute(uint64_t value);\n    /// Set the attribute to value.\n    void SetAttribute( bool value );\n    /// Set the attribute to value.\n    void SetAttribute( double value );\n    /// Set the attribute to value.\n    void SetAttribute( float value );\n\nprivate:\n    enum { BUF_SIZE = 200 };\n\n    XMLAttribute() : _name(), _value(),_parseLineNum( 0 ), _next( 0 ), _memPool( 0 ) {}\n    virtual ~XMLAttribute()\t{}\n\n    XMLAttribute( const XMLAttribute& );\t// not supported\n    void operator=( const XMLAttribute& );\t// not supported\n    void SetName( const char* name );\n\n    char* ParseDeep( char* p, bool processEntities, int* curLineNumPtr );\n\n    mutable StrPair _name;\n    mutable StrPair _value;\n    int             _parseLineNum;\n    XMLAttribute*   _next;\n    MemPool*        _memPool;\n};\n\n\n/** The element is a container class. It has a value, the element name,\n\tand can contain other elements, text, comments, and unknowns.\n\tElements also contain an arbitrary number of attributes.\n*/\nclass TINYXML2_LIB XMLElement : public XMLNode\n{\n    friend class XMLDocument;\npublic:\n    /// Get the name of an element (which is the Value() of the node.)\n    const char* Name() const\t\t{\n        return Value();\n    }\n    /// Set the name of the element.\n    void SetName( const char* str, bool staticMem=false )\t{\n        SetValue( str, staticMem );\n    }\n\n    virtual XMLElement* ToElement() override\t{\n        return this;\n    }\n    virtual const XMLElement* ToElement() const override {\n        return this;\n    }\n    virtual bool Accept( XMLVisitor* visitor ) const override;\n\n    /** Given an attribute name, Attribute() returns the value\n    \tfor the attribute of that name, or null if none\n    \texists. For example:\n\n    \t@verbatim\n    \tconst char* value = ele->Attribute( \"foo\" );\n    \t@endverbatim\n\n    \tThe 'value' parameter is normally null. However, if specified,\n    \tthe attribute will only be returned if the 'name' and 'value'\n    \tmatch. This allow you to write code:\n\n    \t@verbatim\n    \tif ( ele->Attribute( \"foo\", \"bar\" ) ) callFooIsBar();\n    \t@endverbatim\n\n    \trather than:\n    \t@verbatim\n    \tif ( ele->Attribute( \"foo\" ) ) {\n    \t\tif ( strcmp( ele->Attribute( \"foo\" ), \"bar\" ) == 0 ) callFooIsBar();\n    \t}\n    \t@endverbatim\n    */\n    const char* Attribute( const char* name, const char* value=0 ) const;\n\n    /** Given an attribute name, IntAttribute() returns the value\n    \tof the attribute interpreted as an integer. The default\n        value will be returned if the attribute isn't present,\n        or if there is an error. (For a method with error\n    \tchecking, see QueryIntAttribute()).\n    */\n\tint IntAttribute(const char* name, int defaultValue = 0) const;\n    /// See IntAttribute()\n\tunsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;\n\t/// See IntAttribute()\n\tint64_t Int64Attribute(const char* name, int64_t defaultValue = 0) const;\n    /// See IntAttribute()\n    uint64_t Unsigned64Attribute(const char* name, uint64_t defaultValue = 0) const;\n\t/// See IntAttribute()\n\tbool BoolAttribute(const char* name, bool defaultValue = false) const;\n    /// See IntAttribute()\n\tdouble DoubleAttribute(const char* name, double defaultValue = 0) const;\n    /// See IntAttribute()\n\tfloat FloatAttribute(const char* name, float defaultValue = 0) const;\n\n    /** Given an attribute name, QueryIntAttribute() returns\n    \tXML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion\n    \tcan't be performed, or XML_NO_ATTRIBUTE if the attribute\n    \tdoesn't exist. If successful, the result of the conversion\n    \twill be written to 'value'. If not successful, nothing will\n    \tbe written to 'value'. This allows you to provide default\n    \tvalue:\n\n    \t@verbatim\n    \tint value = 10;\n    \tQueryIntAttribute( \"foo\", &value );\t\t// if \"foo\" isn't found, value will still be 10\n    \t@endverbatim\n    */\n    XMLError QueryIntAttribute( const char* name, int* value ) const\t\t\t\t{\n        const XMLAttribute* a = FindAttribute( name );\n        if ( !a ) {\n            return XML_NO_ATTRIBUTE;\n        }\n        return a->QueryIntValue( value );\n    }\n\n\t/// See QueryIntAttribute()\n    XMLError QueryUnsignedAttribute( const char* name, unsigned int* value ) const\t{\n        const XMLAttribute* a = FindAttribute( name );\n        if ( !a ) {\n            return XML_NO_ATTRIBUTE;\n        }\n        return a->QueryUnsignedValue( value );\n    }\n\n\t/// See QueryIntAttribute()\n\tXMLError QueryInt64Attribute(const char* name, int64_t* value) const {\n\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\tif (!a) {\n\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t}\n\t\treturn a->QueryInt64Value(value);\n\t}\n\n    /// See QueryIntAttribute()\n    XMLError QueryUnsigned64Attribute(const char* name, uint64_t* value) const {\n        const XMLAttribute* a = FindAttribute(name);\n        if(!a) {\n            return XML_NO_ATTRIBUTE;\n        }\n        return a->QueryUnsigned64Value(value);\n    }\n\n\t/// See QueryIntAttribute()\n    XMLError QueryBoolAttribute( const char* name, bool* value ) const\t\t\t\t{\n        const XMLAttribute* a = FindAttribute( name );\n        if ( !a ) {\n            return XML_NO_ATTRIBUTE;\n        }\n        return a->QueryBoolValue( value );\n    }\n    /// See QueryIntAttribute()\n    XMLError QueryDoubleAttribute( const char* name, double* value ) const\t\t\t{\n        const XMLAttribute* a = FindAttribute( name );\n        if ( !a ) {\n            return XML_NO_ATTRIBUTE;\n        }\n        return a->QueryDoubleValue( value );\n    }\n    /// See QueryIntAttribute()\n    XMLError QueryFloatAttribute( const char* name, float* value ) const\t\t\t{\n        const XMLAttribute* a = FindAttribute( name );\n        if ( !a ) {\n            return XML_NO_ATTRIBUTE;\n        }\n        return a->QueryFloatValue( value );\n    }\n\n\t/// See QueryIntAttribute()\n\tXMLError QueryStringAttribute(const char* name, const char** value) const {\n\t\tconst XMLAttribute* a = FindAttribute(name);\n\t\tif (!a) {\n\t\t\treturn XML_NO_ATTRIBUTE;\n\t\t}\n\t\t*value = a->Value();\n\t\treturn XML_SUCCESS;\n\t}\n\n\n\n    /** Given an attribute name, QueryAttribute() returns\n    \tXML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion\n    \tcan't be performed, or XML_NO_ATTRIBUTE if the attribute\n    \tdoesn't exist. It is overloaded for the primitive types,\n\t\tand is a generally more convenient replacement of\n\t\tQueryIntAttribute() and related functions.\n\n\t\tIf successful, the result of the conversion\n    \twill be written to 'value'. If not successful, nothing will\n    \tbe written to 'value'. This allows you to provide default\n    \tvalue:\n\n    \t@verbatim\n    \tint value = 10;\n    \tQueryAttribute( \"foo\", &value );\t\t// if \"foo\" isn't found, value will still be 10\n    \t@endverbatim\n    */\n\tXMLError QueryAttribute( const char* name, int* value ) const {\n\t\treturn QueryIntAttribute( name, value );\n\t}\n\n\tXMLError QueryAttribute( const char* name, unsigned int* value ) const {\n\t\treturn QueryUnsignedAttribute( name, value );\n\t}\n\n\tXMLError QueryAttribute(const char* name, int64_t* value) const {\n\t\treturn QueryInt64Attribute(name, value);\n\t}\n\n    XMLError QueryAttribute(const char* name, uint64_t* value) const {\n        return QueryUnsigned64Attribute(name, value);\n    }\n\n    XMLError QueryAttribute( const char* name, bool* value ) const {\n\t\treturn QueryBoolAttribute( name, value );\n\t}\n\n\tXMLError QueryAttribute( const char* name, double* value ) const {\n\t\treturn QueryDoubleAttribute( name, value );\n\t}\n\n\tXMLError QueryAttribute( const char* name, float* value ) const {\n\t\treturn QueryFloatAttribute( name, value );\n\t}\n\n\tXMLError QueryAttribute(const char* name, const char** value) const {\n\t\treturn QueryStringAttribute(name, value);\n\t}\n\n\t/// Sets the named attribute to value.\n    void SetAttribute( const char* name, const char* value )\t{\n        XMLAttribute* a = FindOrCreateAttribute( name );\n        a->SetAttribute( value );\n    }\n    /// Sets the named attribute to value.\n    void SetAttribute( const char* name, int value )\t\t\t{\n        XMLAttribute* a = FindOrCreateAttribute( name );\n        a->SetAttribute( value );\n    }\n    /// Sets the named attribute to value.\n    void SetAttribute( const char* name, unsigned value )\t\t{\n        XMLAttribute* a = FindOrCreateAttribute( name );\n        a->SetAttribute( value );\n    }\n\n\t/// Sets the named attribute to value.\n\tvoid SetAttribute(const char* name, int64_t value) {\n\t\tXMLAttribute* a = FindOrCreateAttribute(name);\n\t\ta->SetAttribute(value);\n\t}\n\n    /// Sets the named attribute to value.\n    void SetAttribute(const char* name, uint64_t value) {\n        XMLAttribute* a = FindOrCreateAttribute(name);\n        a->SetAttribute(value);\n    }\n\n    /// Sets the named attribute to value.\n    void SetAttribute( const char* name, bool value )\t\t\t{\n        XMLAttribute* a = FindOrCreateAttribute( name );\n        a->SetAttribute( value );\n    }\n    /// Sets the named attribute to value.\n    void SetAttribute( const char* name, double value )\t\t{\n        XMLAttribute* a = FindOrCreateAttribute( name );\n        a->SetAttribute( value );\n    }\n    /// Sets the named attribute to value.\n    void SetAttribute( const char* name, float value )\t\t{\n        XMLAttribute* a = FindOrCreateAttribute( name );\n        a->SetAttribute( value );\n    }\n\n    /**\n    \tDelete an attribute.\n    */\n    void DeleteAttribute( const char* name );\n\n    /// Return the first attribute in the list.\n    const XMLAttribute* FirstAttribute() const {\n        return _rootAttribute;\n    }\n    /// Query a specific attribute in the list.\n    const XMLAttribute* FindAttribute( const char* name ) const;\n\n    /** Convenience function for easy access to the text inside an element. Although easy\n    \tand concise, GetText() is limited compared to getting the XMLText child\n    \tand accessing it directly.\n\n    \tIf the first child of 'this' is a XMLText, the GetText()\n    \treturns the character string of the Text node, else null is returned.\n\n    \tThis is a convenient method for getting the text of simple contained text:\n    \t@verbatim\n    \t<foo>This is text</foo>\n    \t\tconst char* str = fooElement->GetText();\n    \t@endverbatim\n\n    \t'str' will be a pointer to \"This is text\".\n\n    \tNote that this function can be misleading. If the element foo was created from\n    \tthis XML:\n    \t@verbatim\n    \t\t<foo><b>This is text</b></foo>\n    \t@endverbatim\n\n    \tthen the value of str would be null. The first child node isn't a text node, it is\n    \tanother element. From this XML:\n    \t@verbatim\n    \t\t<foo>This is <b>text</b></foo>\n    \t@endverbatim\n    \tGetText() will return \"This is \".\n    */\n    const char* GetText() const;\n\n    /** Convenience function for easy access to the text inside an element. Although easy\n    \tand concise, SetText() is limited compared to creating an XMLText child\n    \tand mutating it directly.\n\n    \tIf the first child of 'this' is a XMLText, SetText() sets its value to\n\t\tthe given string, otherwise it will create a first child that is an XMLText.\n\n    \tThis is a convenient method for setting the text of simple contained text:\n    \t@verbatim\n    \t<foo>This is text</foo>\n    \t\tfooElement->SetText( \"Hullaballoo!\" );\n     \t<foo>Hullaballoo!</foo>\n\t\t@endverbatim\n\n    \tNote that this function can be misleading. If the element foo was created from\n    \tthis XML:\n    \t@verbatim\n    \t\t<foo><b>This is text</b></foo>\n    \t@endverbatim\n\n    \tthen it will not change \"This is text\", but rather prefix it with a text element:\n    \t@verbatim\n    \t\t<foo>Hullaballoo!<b>This is text</b></foo>\n    \t@endverbatim\n\n\t\tFor this XML:\n    \t@verbatim\n    \t\t<foo />\n    \t@endverbatim\n    \tSetText() will generate\n    \t@verbatim\n    \t\t<foo>Hullaballoo!</foo>\n    \t@endverbatim\n    */\n\tvoid SetText( const char* inText );\n    /// Convenience method for setting text inside an element. See SetText() for important limitations.\n    void SetText( int value );\n    /// Convenience method for setting text inside an element. See SetText() for important limitations.\n    void SetText( unsigned value );\n\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n\tvoid SetText(int64_t value);\n    /// Convenience method for setting text inside an element. See SetText() for important limitations.\n    void SetText(uint64_t value);\n\t/// Convenience method for setting text inside an element. See SetText() for important limitations.\n    void SetText( bool value );\n    /// Convenience method for setting text inside an element. See SetText() for important limitations.\n    void SetText( double value );\n    /// Convenience method for setting text inside an element. See SetText() for important limitations.\n    void SetText( float value );\n\n    /**\n    \tConvenience method to query the value of a child text node. This is probably best\n    \tshown by example. Given you have a document is this form:\n    \t@verbatim\n    \t\t<point>\n    \t\t\t<x>1</x>\n    \t\t\t<y>1.4</y>\n    \t\t</point>\n    \t@endverbatim\n\n    \tThe QueryIntText() and similar functions provide a safe and easier way to get to the\n    \t\"value\" of x and y.\n\n    \t@verbatim\n    \t\tint x = 0;\n    \t\tfloat y = 0;\t// types of x and y are contrived for example\n    \t\tconst XMLElement* xElement = pointElement->FirstChildElement( \"x\" );\n    \t\tconst XMLElement* yElement = pointElement->FirstChildElement( \"y\" );\n    \t\txElement->QueryIntText( &x );\n    \t\tyElement->QueryFloatText( &y );\n    \t@endverbatim\n\n    \t@returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted\n    \t\t\t to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.\n\n    */\n    XMLError QueryIntText( int* ival ) const;\n    /// See QueryIntText()\n    XMLError QueryUnsignedText( unsigned* uval ) const;\n\t/// See QueryIntText()\n\tXMLError QueryInt64Text(int64_t* uval) const;\n\t/// See QueryIntText()\n\tXMLError QueryUnsigned64Text(uint64_t* uval) const;\n\t/// See QueryIntText()\n    XMLError QueryBoolText( bool* bval ) const;\n    /// See QueryIntText()\n    XMLError QueryDoubleText( double* dval ) const;\n    /// See QueryIntText()\n    XMLError QueryFloatText( float* fval ) const;\n\n\tint IntText(int defaultValue = 0) const;\n\n\t/// See QueryIntText()\n\tunsigned UnsignedText(unsigned defaultValue = 0) const;\n\t/// See QueryIntText()\n\tint64_t Int64Text(int64_t defaultValue = 0) const;\n    /// See QueryIntText()\n    uint64_t Unsigned64Text(uint64_t defaultValue = 0) const;\n\t/// See QueryIntText()\n\tbool BoolText(bool defaultValue = false) const;\n\t/// See QueryIntText()\n\tdouble DoubleText(double defaultValue = 0) const;\n\t/// See QueryIntText()\n    float FloatText(float defaultValue = 0) const;\n\n    /**\n        Convenience method to create a new XMLElement and add it as last (right)\n        child of this node. Returns the created and inserted element.\n    */\n    XMLElement* InsertNewChildElement(const char* name);\n    /// See InsertNewChildElement()\n    XMLComment* InsertNewComment(const char* comment);\n    /// See InsertNewChildElement()\n    XMLText* InsertNewText(const char* text);\n    /// See InsertNewChildElement()\n    XMLDeclaration* InsertNewDeclaration(const char* text);\n    /// See InsertNewChildElement()\n    XMLUnknown* InsertNewUnknown(const char* text);\n\n\n    // internal:\n    enum ElementClosingType {\n        OPEN,\t\t// <foo>\n        CLOSED,\t\t// <foo/>\n        CLOSING\t\t// </foo>\n    };\n    ElementClosingType ClosingType() const {\n        return _closingType;\n    }\n    virtual XMLNode* ShallowClone( XMLDocument* document ) const override;\n    virtual bool ShallowEqual( const XMLNode* compare ) const override;\n\nprotected:\n    char* ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr ) override;\n\nprivate:\n    XMLElement( XMLDocument* doc );\n    virtual ~XMLElement();\n    XMLElement( const XMLElement& );\t// not supported\n    void operator=( const XMLElement& );\t// not supported\n\n    XMLAttribute* FindOrCreateAttribute( const char* name );\n    char* ParseAttributes( char* p, int* curLineNumPtr );\n    static void DeleteAttribute( XMLAttribute* attribute );\n    XMLAttribute* CreateAttribute();\n\n    enum { BUF_SIZE = 200 };\n    ElementClosingType _closingType;\n    // The attribute list is ordered; there is no 'lastAttribute'\n    // because the list needs to be scanned for dupes before adding\n    // a new attribute.\n    XMLAttribute* _rootAttribute;\n};\n\n\nenum Whitespace {\n    PRESERVE_WHITESPACE,\n    COLLAPSE_WHITESPACE,\n    PEDANTIC_WHITESPACE\n};\n\n\n/** A Document binds together all the functionality.\n\tIt can be saved, loaded, and printed to the screen.\n\tAll Nodes are connected and allocated to a Document.\n\tIf the Document is deleted, all its Nodes are also deleted.\n*/\nclass TINYXML2_LIB XMLDocument : public XMLNode\n{\n    friend class XMLElement;\n    // Gives access to SetError and Push/PopDepth, but over-access for everything else.\n    // Wishing C++ had \"internal\" scope.\n    friend class XMLNode;\n    friend class XMLText;\n    friend class XMLComment;\n    friend class XMLDeclaration;\n    friend class XMLUnknown;\npublic:\n    /// constructor\n    XMLDocument( bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE );\n    ~XMLDocument();\n\n    virtual XMLDocument* ToDocument() override\t\t{\n        TIXMLASSERT( this == _document );\n        return this;\n    }\n    virtual const XMLDocument* ToDocument() const override {\n        TIXMLASSERT( this == _document );\n        return this;\n    }\n\n    /**\n    \tParse an XML file from a character string.\n    \tReturns XML_SUCCESS (0) on success, or\n    \tan errorID.\n\n    \tYou may optionally pass in the 'nBytes', which is\n    \tthe number of bytes which will be parsed. If not\n    \tspecified, TinyXML-2 will assume 'xml' points to a\n    \tnull terminated string.\n    */\n    XMLError Parse( const char* xml, size_t nBytes=static_cast<size_t>(-1) );\n\n    /**\n    \tLoad an XML file from disk.\n    \tReturns XML_SUCCESS (0) on success, or\n    \tan errorID.\n    */\n    XMLError LoadFile( const char* filename );\n\n    /**\n    \tLoad an XML file from disk. You are responsible\n    \tfor providing and closing the FILE*.\n\n        NOTE: The file should be opened as binary (\"rb\")\n        not text in order for TinyXML-2 to correctly\n        do newline normalization.\n\n    \tReturns XML_SUCCESS (0) on success, or\n    \tan errorID.\n    */\n    XMLError LoadFile( FILE* );\n\n    /**\n    \tSave the XML file to disk.\n    \tReturns XML_SUCCESS (0) on success, or\n    \tan errorID.\n    */\n    XMLError SaveFile( const char* filename, bool compact = false );\n\n    /**\n    \tSave the XML file to disk. You are responsible\n    \tfor providing and closing the FILE*.\n\n    \tReturns XML_SUCCESS (0) on success, or\n    \tan errorID.\n    */\n    XMLError SaveFile( FILE* fp, bool compact = false );\n\n    bool ProcessEntities() const\t\t{\n        return _processEntities;\n    }\n    Whitespace WhitespaceMode() const\t{\n        return _whitespaceMode;\n    }\n\n    /**\n    \tReturns true if this document has a leading Byte Order Mark of UTF8.\n    */\n    bool HasBOM() const {\n        return _writeBOM;\n    }\n    /** Sets whether to write the BOM when writing the file.\n    */\n    void SetBOM( bool useBOM ) {\n        _writeBOM = useBOM;\n    }\n\n    /** Return the root element of DOM. Equivalent to FirstChildElement().\n        To get the first node, use FirstChild().\n    */\n    XMLElement* RootElement()\t\t\t\t{\n        return FirstChildElement();\n    }\n    const XMLElement* RootElement() const\t{\n        return FirstChildElement();\n    }\n\n    /** Print the Document. If the Printer is not provided, it will\n        print to stdout. If you provide Printer, this can print to a file:\n    \t@verbatim\n    \tXMLPrinter printer( fp );\n    \tdoc.Print( &printer );\n    \t@endverbatim\n\n    \tOr you can use a printer to print to memory:\n    \t@verbatim\n    \tXMLPrinter printer;\n    \tdoc.Print( &printer );\n    \t// printer.CStr() has a const char* to the XML\n    \t@endverbatim\n    */\n    void Print( XMLPrinter* streamer=0 ) const;\n    virtual bool Accept( XMLVisitor* visitor ) const override;\n\n    /**\n    \tCreate a new Element associated with\n    \tthis Document. The memory for the Element\n    \tis managed by the Document.\n    */\n    XMLElement* NewElement( const char* name );\n    /**\n    \tCreate a new Comment associated with\n    \tthis Document. The memory for the Comment\n    \tis managed by the Document.\n    */\n    XMLComment* NewComment( const char* comment );\n    /**\n    \tCreate a new Text associated with\n    \tthis Document. The memory for the Text\n    \tis managed by the Document.\n    */\n    XMLText* NewText( const char* text );\n    /**\n    \tCreate a new Declaration associated with\n    \tthis Document. The memory for the object\n    \tis managed by the Document.\n\n    \tIf the 'text' param is null, the standard\n    \tdeclaration is used.:\n    \t@verbatim\n    \t\t<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n    \t@endverbatim\n    */\n    XMLDeclaration* NewDeclaration( const char* text=0 );\n    /**\n    \tCreate a new Unknown associated with\n    \tthis Document. The memory for the object\n    \tis managed by the Document.\n    */\n    XMLUnknown* NewUnknown( const char* text );\n\n    /**\n    \tDelete a node associated with this document.\n    \tIt will be unlinked from the DOM.\n    */\n    void DeleteNode( XMLNode* node );\n\n    /// Clears the error flags.\n    void ClearError();\n\n    /// Return true if there was an error parsing the document.\n    bool Error() const {\n        return _errorID != XML_SUCCESS;\n    }\n    /// Return the errorID.\n    XMLError  ErrorID() const {\n        return _errorID;\n    }\n\tconst char* ErrorName() const;\n    static const char* ErrorIDToName(XMLError errorID);\n\n    /** Returns a \"long form\" error description. A hopefully helpful\n        diagnostic with location, line number, and/or additional info.\n    */\n\tconst char* ErrorStr() const;\n\n    /// A (trivial) utility function that prints the ErrorStr() to stdout.\n    void PrintError() const;\n\n    /// Return the line where the error occurred, or zero if unknown.\n    int ErrorLineNum() const\n    {\n        return _errorLineNum;\n    }\n\n    /// Clear the document, resetting it to the initial state.\n    void Clear();\n\n\t/**\n\t\tCopies this document to a target document.\n\t\tThe target will be completely cleared before the copy.\n\t\tIf you want to copy a sub-tree, see XMLNode::DeepClone().\n\n\t\tNOTE: that the 'target' must be non-null.\n\t*/\n\tvoid DeepCopy(XMLDocument* target) const;\n\n\t// internal\n    char* Identify( char* p, XMLNode** node, bool first );\n\n\t// internal\n\tvoid MarkInUse(const XMLNode* const);\n\n    virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const override{\n        return 0;\n    }\n    virtual bool ShallowEqual( const XMLNode* /*compare*/ ) const override{\n        return false;\n    }\n\nprivate:\n    XMLDocument( const XMLDocument& );\t// not supported\n    void operator=( const XMLDocument& );\t// not supported\n\n    bool\t\t\t_writeBOM;\n    bool\t\t\t_processEntities;\n    XMLError\t\t_errorID;\n    Whitespace\t\t_whitespaceMode;\n    mutable StrPair\t_errorStr;\n    int             _errorLineNum;\n    char*\t\t\t_charBuffer;\n    int\t\t\t\t_parseCurLineNum;\n\tint\t\t\t\t_parsingDepth;\n\t// Memory tracking does add some overhead.\n\t// However, the code assumes that you don't\n\t// have a bunch of unlinked nodes around.\n\t// Therefore it takes less memory to track\n\t// in the document vs. a linked list in the XMLNode,\n\t// and the performance is the same.\n\tDynArray<XMLNode*, 10> _unlinked;\n\n    MemPoolT< sizeof(XMLElement) >\t _elementPool;\n    MemPoolT< sizeof(XMLAttribute) > _attributePool;\n    MemPoolT< sizeof(XMLText) >\t\t _textPool;\n    MemPoolT< sizeof(XMLComment) >\t _commentPool;\n\n\tstatic const char* _errorNames[XML_ERROR_COUNT];\n\n    void Parse();\n\n    void SetError( XMLError error, int lineNum, const char* format, ... );\n\n\t// Something of an obvious security hole, once it was discovered.\n\t// Either an ill-formed XML or an excessively deep one can overflow\n\t// the stack. Track stack depth, and error out if needed.\n\tclass DepthTracker {\n\tpublic:\n\t\texplicit DepthTracker(XMLDocument * document) {\n\t\t\tthis->_document = document;\n\t\t\tdocument->PushDepth();\n\t\t}\n\t\t~DepthTracker() {\n\t\t\t_document->PopDepth();\n\t\t}\n\tprivate:\n\t\tXMLDocument * _document;\n\t};\n\tvoid PushDepth();\n\tvoid PopDepth();\n\n    template<class NodeType, size_t PoolElementSize>\n    NodeType* CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool );\n};\n\ntemplate<class NodeType, size_t PoolElementSize>\ninline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& pool )\n{\n    TIXMLASSERT( sizeof( NodeType ) == PoolElementSize );\n    TIXMLASSERT( sizeof( NodeType ) == pool.ItemSize() );\n    NodeType* returnNode = new (pool.Alloc()) NodeType( this );\n    TIXMLASSERT( returnNode );\n    returnNode->_memPool = &pool;\n\n\t_unlinked.Push(returnNode);\n    return returnNode;\n}\n\n/**\n\tA XMLHandle is a class that wraps a node pointer with null checks; this is\n\tan incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2\n\tDOM structure. It is a separate utility class.\n\n\tTake an example:\n\t@verbatim\n\t<Document>\n\t\t<Element attributeA = \"valueA\">\n\t\t\t<Child attributeB = \"value1\" />\n\t\t\t<Child attributeB = \"value2\" />\n\t\t</Element>\n\t</Document>\n\t@endverbatim\n\n\tAssuming you want the value of \"attributeB\" in the 2nd \"Child\" element, it's very\n\teasy to write a *lot* of code that looks like:\n\n\t@verbatim\n\tXMLElement* root = document.FirstChildElement( \"Document\" );\n\tif ( root )\n\t{\n\t\tXMLElement* element = root->FirstChildElement( \"Element\" );\n\t\tif ( element )\n\t\t{\n\t\t\tXMLElement* child = element->FirstChildElement( \"Child\" );\n\t\t\tif ( child )\n\t\t\t{\n\t\t\t\tXMLElement* child2 = child->NextSiblingElement( \"Child\" );\n\t\t\t\tif ( child2 )\n\t\t\t\t{\n\t\t\t\t\t// Finally do something useful.\n\t@endverbatim\n\n\tAnd that doesn't even cover \"else\" cases. XMLHandle addresses the verbosity\n\tof such code. A XMLHandle checks for null pointers so it is perfectly safe\n\tand correct to use:\n\n\t@verbatim\n\tXMLHandle docHandle( &document );\n\tXMLElement* child2 = docHandle.FirstChildElement( \"Document\" ).FirstChildElement( \"Element\" ).FirstChildElement().NextSiblingElement();\n\tif ( child2 )\n\t{\n\t\t// do something useful\n\t@endverbatim\n\n\tWhich is MUCH more concise and useful.\n\n\tIt is also safe to copy handles - internally they are nothing more than node pointers.\n\t@verbatim\n\tXMLHandle handleCopy = handle;\n\t@endverbatim\n\n\tSee also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.\n*/\nclass TINYXML2_LIB XMLHandle\n{\npublic:\n    /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.\n    explicit XMLHandle( XMLNode* node ) : _node( node ) {\n    }\n    /// Create a handle from a node.\n    explicit XMLHandle( XMLNode& node ) : _node( &node ) {\n    }\n    /// Copy constructor\n    XMLHandle( const XMLHandle& ref ) : _node( ref._node ) {\n    }\n    /// Assignment\n    XMLHandle& operator=( const XMLHandle& ref )\t\t\t\t\t\t\t{\n        _node = ref._node;\n        return *this;\n    }\n\n    /// Get the first child of this handle.\n    XMLHandle FirstChild() \t\t\t\t\t\t\t\t\t\t\t\t\t{\n        return XMLHandle( _node ? _node->FirstChild() : 0 );\n    }\n    /// Get the first child element of this handle.\n    XMLHandle FirstChildElement( const char* name = 0 )\t\t\t\t\t\t{\n        return XMLHandle( _node ? _node->FirstChildElement( name ) : 0 );\n    }\n    /// Get the last child of this handle.\n    XMLHandle LastChild()\t\t\t\t\t\t\t\t\t\t\t\t\t{\n        return XMLHandle( _node ? _node->LastChild() : 0 );\n    }\n    /// Get the last child element of this handle.\n    XMLHandle LastChildElement( const char* name = 0 )\t\t\t\t\t\t{\n        return XMLHandle( _node ? _node->LastChildElement( name ) : 0 );\n    }\n    /// Get the previous sibling of this handle.\n    XMLHandle PreviousSibling()\t\t\t\t\t\t\t\t\t\t\t\t{\n        return XMLHandle( _node ? _node->PreviousSibling() : 0 );\n    }\n    /// Get the previous sibling element of this handle.\n    XMLHandle PreviousSiblingElement( const char* name = 0 )\t\t\t\t{\n        return XMLHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );\n    }\n    /// Get the next sibling of this handle.\n    XMLHandle NextSibling()\t\t\t\t\t\t\t\t\t\t\t\t\t{\n        return XMLHandle( _node ? _node->NextSibling() : 0 );\n    }\n    /// Get the next sibling element of this handle.\n    XMLHandle NextSiblingElement( const char* name = 0 )\t\t\t\t\t{\n        return XMLHandle( _node ? _node->NextSiblingElement( name ) : 0 );\n    }\n\n    /// Safe cast to XMLNode. This can return null.\n    XMLNode* ToNode()\t\t\t\t\t\t\t{\n        return _node;\n    }\n    /// Safe cast to XMLElement. This can return null.\n    XMLElement* ToElement() \t\t\t\t\t{\n        return ( _node ? _node->ToElement() : 0 );\n    }\n    /// Safe cast to XMLText. This can return null.\n    XMLText* ToText() \t\t\t\t\t\t\t{\n        return ( _node ? _node->ToText() : 0 );\n    }\n    /// Safe cast to XMLUnknown. This can return null.\n    XMLUnknown* ToUnknown() \t\t\t\t\t{\n        return ( _node ? _node->ToUnknown() : 0 );\n    }\n    /// Safe cast to XMLDeclaration. This can return null.\n    XMLDeclaration* ToDeclaration() \t\t\t{\n        return ( _node ? _node->ToDeclaration() : 0 );\n    }\n\nprivate:\n    XMLNode* _node;\n};\n\n\n/**\n\tA variant of the XMLHandle class for working with const XMLNodes and Documents. It is the\n\tsame in all regards, except for the 'const' qualifiers. See XMLHandle for API.\n*/\nclass TINYXML2_LIB XMLConstHandle\n{\npublic:\n    explicit XMLConstHandle( const XMLNode* node ) : _node( node ) {\n    }\n    explicit XMLConstHandle( const XMLNode& node ) : _node( &node ) {\n    }\n    XMLConstHandle( const XMLConstHandle& ref ) : _node( ref._node ) {\n    }\n\n    XMLConstHandle& operator=( const XMLConstHandle& ref )\t\t\t\t\t\t\t{\n        _node = ref._node;\n        return *this;\n    }\n\n    const XMLConstHandle FirstChild() const\t\t\t\t\t\t\t\t\t\t\t{\n        return XMLConstHandle( _node ? _node->FirstChild() : 0 );\n    }\n    const XMLConstHandle FirstChildElement( const char* name = 0 ) const\t\t\t\t{\n        return XMLConstHandle( _node ? _node->FirstChildElement( name ) : 0 );\n    }\n    const XMLConstHandle LastChild()\tconst\t\t\t\t\t\t\t\t\t\t{\n        return XMLConstHandle( _node ? _node->LastChild() : 0 );\n    }\n    const XMLConstHandle LastChildElement( const char* name = 0 ) const\t\t\t\t{\n        return XMLConstHandle( _node ? _node->LastChildElement( name ) : 0 );\n    }\n    const XMLConstHandle PreviousSibling() const\t\t\t\t\t\t\t\t\t{\n        return XMLConstHandle( _node ? _node->PreviousSibling() : 0 );\n    }\n    const XMLConstHandle PreviousSiblingElement( const char* name = 0 ) const\t\t{\n        return XMLConstHandle( _node ? _node->PreviousSiblingElement( name ) : 0 );\n    }\n    const XMLConstHandle NextSibling() const\t\t\t\t\t\t\t\t\t\t{\n        return XMLConstHandle( _node ? _node->NextSibling() : 0 );\n    }\n    const XMLConstHandle NextSiblingElement( const char* name = 0 ) const\t\t\t{\n        return XMLConstHandle( _node ? _node->NextSiblingElement( name ) : 0 );\n    }\n\n\n    const XMLNode* ToNode() const\t\t\t\t{\n        return _node;\n    }\n    const XMLElement* ToElement() const\t\t\t{\n        return ( _node ? _node->ToElement() : 0 );\n    }\n    const XMLText* ToText() const\t\t\t\t{\n        return ( _node ? _node->ToText() : 0 );\n    }\n    const XMLUnknown* ToUnknown() const\t\t\t{\n        return ( _node ? _node->ToUnknown() : 0 );\n    }\n    const XMLDeclaration* ToDeclaration() const\t{\n        return ( _node ? _node->ToDeclaration() : 0 );\n    }\n\nprivate:\n    const XMLNode* _node;\n};\n\n\n/**\n\tPrinting functionality. The XMLPrinter gives you more\n\toptions than the XMLDocument::Print() method.\n\n\tIt can:\n\t-# Print to memory.\n\t-# Print to a file you provide.\n\t-# Print XML without a XMLDocument.\n\n\tPrint to Memory\n\n\t@verbatim\n\tXMLPrinter printer;\n\tdoc.Print( &printer );\n\tSomeFunction( printer.CStr() );\n\t@endverbatim\n\n\tPrint to a File\n\n\tYou provide the file pointer.\n\t@verbatim\n\tXMLPrinter printer( fp );\n\tdoc.Print( &printer );\n\t@endverbatim\n\n\tPrint without a XMLDocument\n\n\tWhen loading, an XML parser is very useful. However, sometimes\n\twhen saving, it just gets in the way. The code is often set up\n\tfor streaming, and constructing the DOM is just overhead.\n\n\tThe Printer supports the streaming case. The following code\n\tprints out a trivially simple XML file without ever creating\n\tan XML document.\n\n\t@verbatim\n\tXMLPrinter printer( fp );\n\tprinter.OpenElement( \"foo\" );\n\tprinter.PushAttribute( \"foo\", \"bar\" );\n\tprinter.CloseElement();\n\t@endverbatim\n*/\nclass TINYXML2_LIB XMLPrinter : public XMLVisitor\n{\npublic:\n    /** Construct the printer. If the FILE* is specified,\n    \tthis will print to the FILE. Else it will print\n    \tto memory, and the result is available in CStr().\n    \tIf 'compact' is set to true, then output is created\n    \twith only required whitespace and newlines.\n    */\n    XMLPrinter( FILE* file=0, bool compact = false, int depth = 0 );\n    virtual ~XMLPrinter()\t{}\n\n    /** If streaming, write the BOM and declaration. */\n    void PushHeader( bool writeBOM, bool writeDeclaration );\n    /** If streaming, start writing an element.\n        The element must be closed with CloseElement()\n    */\n    void OpenElement( const char* name, bool compactMode=false );\n    /// If streaming, add an attribute to an open element.\n    void PushAttribute( const char* name, const char* value );\n    void PushAttribute( const char* name, int value );\n    void PushAttribute( const char* name, unsigned value );\n\tvoid PushAttribute( const char* name, int64_t value );\n\tvoid PushAttribute( const char* name, uint64_t value );\n\tvoid PushAttribute( const char* name, bool value );\n    void PushAttribute( const char* name, double value );\n    /// If streaming, close the Element.\n    virtual void CloseElement( bool compactMode=false );\n\n    /// Add a text node.\n    void PushText( const char* text, bool cdata=false );\n    /// Add a text node from an integer.\n    void PushText( int value );\n    /// Add a text node from an unsigned.\n    void PushText( unsigned value );\n\t/// Add a text node from a signed 64bit integer.\n\tvoid PushText( int64_t value );\n\t/// Add a text node from an unsigned 64bit integer.\n\tvoid PushText( uint64_t value );\n\t/// Add a text node from a bool.\n    void PushText( bool value );\n    /// Add a text node from a float.\n    void PushText( float value );\n    /// Add a text node from a double.\n    void PushText( double value );\n\n    /// Add a comment\n    void PushComment( const char* comment );\n\n    void PushDeclaration( const char* value );\n    void PushUnknown( const char* value );\n\n    virtual bool VisitEnter( const XMLDocument& /*doc*/ ) override;\n    virtual bool VisitExit( const XMLDocument& /*doc*/ ) override\t{\n        return true;\n    }\n\n    virtual bool VisitEnter( const XMLElement& element, const XMLAttribute* attribute ) override;\n    virtual bool VisitExit( const XMLElement& element ) override;\n\n    virtual bool Visit( const XMLText& text ) override;\n    virtual bool Visit( const XMLComment& comment ) override;\n    virtual bool Visit( const XMLDeclaration& declaration ) override;\n    virtual bool Visit( const XMLUnknown& unknown ) override;\n\n    /**\n    \tIf in print to memory mode, return a pointer to\n    \tthe XML file in memory.\n    */\n    const char* CStr() const {\n        return _buffer.Mem();\n    }\n    /**\n    \tIf in print to memory mode, return the size\n    \tof the XML file in memory. (Note the size returned\n    \tincludes the terminating null.)\n    */\n    size_t CStrSize() const {\n        return _buffer.Size();\n    }\n    /**\n    \tIf in print to memory mode, reset the buffer to the\n    \tbeginning.\n    */\n    void ClearBuffer( bool resetToFirstElement = true ) {\n        _buffer.Clear();\n        _buffer.Push(0);\n\t\t_firstElement = resetToFirstElement;\n    }\n\nprotected:\n\tvirtual bool CompactMode( const XMLElement& )\t{ return _compactMode; }\n\n\t/** Prints out the space before an element. You may override to change\n\t    the space and tabs used. A PrintSpace() override should call Print().\n\t*/\n    virtual void PrintSpace( int depth );\n    virtual void Print( const char* format, ... );\n    virtual void Write( const char* data, size_t size );\n    virtual void Putc( char ch );\n\n    inline void Write(const char* data) { Write(data, strlen(data)); }\n\n    void SealElementIfJustOpened();\n    bool _elementJustOpened;\n    DynArray< const char*, 10 > _stack;\n\nprivate:\n    /**\n       Prepares to write a new node. This includes sealing an element that was\n       just opened, and writing any whitespace necessary if not in compact mode.\n     */\n    void PrepareForNewNode( bool compactMode );\n    void PrintString( const char*, bool restrictedEntitySet );\t// prints out, after detecting entities.\n\n    bool _firstElement;\n    FILE* _fp;\n    int _depth;\n    int _textDepth;\n    bool _processEntities;\n\tbool _compactMode;\n\n    enum {\n        ENTITY_RANGE = 64,\n        BUF_SIZE = 200\n    };\n    bool _entityFlag[ENTITY_RANGE];\n    bool _restrictedEntityFlag[ENTITY_RANGE];\n\n    DynArray< char, 20 > _buffer;\n\n    // Prohibit cloning, intentionally not implemented\n    XMLPrinter( const XMLPrinter& );\n    XMLPrinter& operator=( const XMLPrinter& );\n};\n\n\n} // namespace tinyxml2\n\n#if defined(_MSC_VER)\n#   pragma warning(pop)\n#endif\n\n#endif // TINYXML2_INCLUDED\n"
  },
  {
    "path": "lib/fkYAML/include/fkYAML/fkyaml_fwd.hpp",
    "content": "//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_FKYAML_FWD_HPP\n#define FK_YAML_FKYAML_FWD_HPP\n\n#include <cstdint>\n#include <map>\n#include <string>\n#include <vector>\n\n// #include <fkYAML/detail/macros/version_macros.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n// Check version definitions if already defined.\n#if defined(FK_YAML_MAJOR_VERSION) && defined(FK_YAML_MINOR_VERSION) && defined(FK_YAML_PATCH_VERSION)\n#if FK_YAML_MAJOR_VERSION != 0 || FK_YAML_MINOR_VERSION != 4 || FK_YAML_PATCH_VERSION != 2\n#warning Already included a different version of the fkYAML library!\n#else\n// define macros to skip defining macros down below.\n#define FK_YAML_VERCHECK_SUCCEEDED\n#endif\n#endif\n\n#ifndef FK_YAML_VERCHECK_SUCCEEDED\n\n#define FK_YAML_MAJOR_VERSION 0\n#define FK_YAML_MINOR_VERSION 4\n#define FK_YAML_PATCH_VERSION 2\n\n#define FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) v##major##_##minor##_##patch\n\n#define FK_YAML_NAMESPACE_VERSION_CONCAT(major, minor, patch) FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch)\n\n#define FK_YAML_NAMESPACE_VERSION                                                                                      \\\n    FK_YAML_NAMESPACE_VERSION_CONCAT(FK_YAML_MAJOR_VERSION, FK_YAML_MINOR_VERSION, FK_YAML_PATCH_VERSION)\n\n#define FK_YAML_NAMESPACE_BEGIN                                                                                        \\\n    namespace fkyaml {                                                                                                 \\\n    inline namespace FK_YAML_NAMESPACE_VERSION {\n\n#define FK_YAML_NAMESPACE_END                                                                                          \\\n    } /* inline namespace FK_YAML_NAMESPACE_VERSION */                                                                 \\\n    } // namespace fkyaml\n\n#define FK_YAML_DETAIL_NAMESPACE_BEGIN                                                                                 \\\n    FK_YAML_NAMESPACE_BEGIN                                                                                            \\\n    namespace detail {\n\n#define FK_YAML_DETAIL_NAMESPACE_END                                                                                   \\\n    } /* namespace detail */                                                                                           \\\n    FK_YAML_NAMESPACE_END\n\n#endif // !defined(FK_YAML_VERCHECK_SUCCEEDED)\n\n\nFK_YAML_NAMESPACE_BEGIN\n\n/// @brief An ADL friendly converter between basic_node objects and native data objects.\n/// @tparam ValueType A target data type.\n/// @sa https://fktn-k.github.io/fkYAML/api/node_value_converter/\ntemplate <typename ValueType, typename = void>\nclass node_value_converter;\n\n/// @brief A class to store value of YAML nodes.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/\ntemplate <\n    template <typename, typename...> class SequenceType = std::vector,\n    template <typename, typename, typename...> class MappingType = std::map, typename BooleanType = bool,\n    typename IntegerType = std::int64_t, typename FloatNumberType = double, typename StringType = std::string,\n    template <typename, typename = void> class ConverterType = node_value_converter>\nclass basic_node;\n\n/// @brief default YAML node value container.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/node/\nusing node = basic_node<>;\n\n/// @brief A minimal map-like container which preserves insertion order.\n/// @tparam Key A type for keys.\n/// @tparam Value A type for values.\n/// @tparam IgnoredCompare A placeholder for key comparison. This will be ignored.\n/// @tparam Allocator A class for allocators.\n/// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\ntemplate <typename Key, typename Value, typename IgnoredCompare, typename Allocator>\nclass ordered_map;\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_FKYAML_FWD_HPP */\n"
  },
  {
    "path": "lib/fkYAML/include/fkYAML/node.hpp",
    "content": "//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_NODE_HPP\n#define FK_YAML_NODE_HPP\n\n#include <algorithm>\n#include <cstdint>\n#include <cstring>\n#include <initializer_list>\n#include <map>\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <vector>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP\n#define FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP\n\n// #include <fkYAML/detail/macros/version_macros.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n// Check version definitions if already defined.\n#if defined(FK_YAML_MAJOR_VERSION) && defined(FK_YAML_MINOR_VERSION) && defined(FK_YAML_PATCH_VERSION)\n#if FK_YAML_MAJOR_VERSION != 0 || FK_YAML_MINOR_VERSION != 4 || FK_YAML_PATCH_VERSION != 2\n#warning Already included a different version of the fkYAML library!\n#else\n// define macros to skip defining macros down below.\n#define FK_YAML_VERCHECK_SUCCEEDED\n#endif\n#endif\n\n#ifndef FK_YAML_VERCHECK_SUCCEEDED\n\n#define FK_YAML_MAJOR_VERSION 0\n#define FK_YAML_MINOR_VERSION 4\n#define FK_YAML_PATCH_VERSION 2\n\n#define FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch) v##major##_##minor##_##patch\n\n#define FK_YAML_NAMESPACE_VERSION_CONCAT(major, minor, patch) FK_YAML_NAMESPACE_VERSION_CONCAT_IMPL(major, minor, patch)\n\n#define FK_YAML_NAMESPACE_VERSION                                                                                      \\\n    FK_YAML_NAMESPACE_VERSION_CONCAT(FK_YAML_MAJOR_VERSION, FK_YAML_MINOR_VERSION, FK_YAML_PATCH_VERSION)\n\n#define FK_YAML_NAMESPACE_BEGIN                                                                                        \\\n    namespace fkyaml {                                                                                                 \\\n    inline namespace FK_YAML_NAMESPACE_VERSION {\n\n#define FK_YAML_NAMESPACE_END                                                                                          \\\n    } /* inline namespace FK_YAML_NAMESPACE_VERSION */                                                                 \\\n    } // namespace fkyaml\n\n#define FK_YAML_DETAIL_NAMESPACE_BEGIN                                                                                 \\\n    FK_YAML_NAMESPACE_BEGIN                                                                                            \\\n    namespace detail {\n\n#define FK_YAML_DETAIL_NAMESPACE_END                                                                                   \\\n    } /* namespace detail */                                                                                           \\\n    FK_YAML_NAMESPACE_END\n\n#endif // !defined(FK_YAML_VERCHECK_SUCCEEDED)\n\n// #include <fkYAML/detail/macros/cpp_config_macros.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP\n#define FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP\n\n// This file is assumed to be included only by version_macros.hpp file.\n// To avoid redundant inclusion, do not include version_macros.hpp file as the other files do.\n\n// With the MSVC compilers, the value of __cplusplus is by default always \"199611L\"(C++98).\n// To avoid that, the library instead references _MSVC_LANG which is always set a correct value.\n// See https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ for more details.\n#if defined(_MSVC_LANG) && !defined(__clang__)\n#define FK_YAML_CPLUSPLUS _MSVC_LANG\n#else\n#define FK_YAML_CPLUSPLUS __cplusplus\n#endif\n\n// C++ language standard detection\n// Skip detection if the definitions listed below already exist.\n#if !defined(FK_YAML_HAS_CXX_23) && !defined(FK_YAML_HAS_CXX_20) && !defined(FK_YAML_HAS_CXX_17) &&                    \\\n    !defined(FK_YAML_HAS_CXX_14) && !defined(FK_YAML_CXX_11)\n#if FK_YAML_CPLUSPLUS >= 202302L\n#define FK_YAML_HAS_CXX_23\n#define FK_YAML_HAS_CXX_20\n#define FK_YAML_HAS_CXX_17\n#define FK_YAML_HAS_CXX_14\n#elif FK_YAML_CPLUSPLUS >= 202002L\n#define FK_YAML_HAS_CXX_20\n#define FK_YAML_HAS_CXX_17\n#define FK_YAML_HAS_CXX_14\n#elif FK_YAML_CPLUSPLUS >= 201703L\n#define FK_YAML_HAS_CXX_17\n#define FK_YAML_HAS_CXX_14\n#elif FK_YAML_CPLUSPLUS >= 201402L\n#define FK_YAML_HAS_CXX_14\n#endif\n\n// C++11 is the minimum required version of the fkYAML library.\n#define FK_YAML_HAS_CXX_11\n#endif\n\n// switch usage of the deprecated attribute. [[deprecated]] is available since C++14.\n#if defined(FK_YAML_HAS_CXX_14)\n#define FK_YAML_DEPRECATED(msg) [[deprecated(msg)]]\n#else\n#if defined(_MSC_VER)\n#define FK_YAML_DEPRECATED(msg) __declspec(deprecated(msg))\n#elif defined(__GNUC__) || defined(__clang__)\n#define FK_YAML_DEPRECATED(msg) __attribute__((deprecated(msg)))\n#else\n#define FK_YAML_DEPRECATED(msg)\n#endif\n#endif\n\n// switch usage of inline variables which have been available since C++17.\n#if defined(FK_YAML_HAS_CXX_17)\n#define FK_YAML_INLINE_VAR inline\n#else\n#define FK_YAML_INLINE_VAR\n#endif\n\n// switch usage of constexpr keyward depending on active C++ standard.\n#if defined(FK_YAML_HAS_CXX_17)\n#define FK_YAML_CXX17_CONSTEXPR constexpr\n#else\n#define FK_YAML_CXX17_CONSTEXPR\n#endif\n\n// Detect __has_* macros.\n// The following macros replace redundant `defined(__has_*) && __has_*(...)`.\n\n#ifdef __has_include\n#define FK_YAML_HAS_INCLUDE(header) __has_include(header)\n#else\n#define FK_YAML_HAS_INCLUDE(header) (0)\n#endif\n\n#ifdef __has_builtin\n#define FK_YAML_HAS_BUILTIN(builtin) __has_builtin(builtin)\n#else\n#define FK_YAML_HAS_BUILTIN(builtin) (0)\n#endif\n\n#ifdef __has_cpp_attribute\n#define FK_YAML_HAS_CPP_ATTRIBUTE(attr) __has_cpp_attribute(attr)\n#else\n#define FK_YAML_HAS_CPP_ATTRIBUTE(attr) (0)\n#endif\n\n#ifdef __has_feature\n#define FK_YAML_HAS_FEATURE(feat) __has_feature(feat)\n#else\n#define FK_YAML_HAS_FEATURE(feat) (0)\n#endif\n\n// switch usage of the no_sanitize attribute only when Clang sanitizer is active.\n#if defined(__clang__) && FK_YAML_HAS_FEATURE(address_sanitizer)\n#define FK_YAML_NO_SANITIZE(...) __attribute__((no_sanitize(__VA_ARGS__)))\n#else\n#define FK_YAML_NO_SANITIZE(...)\n#endif\n\n#if FK_YAML_HAS_INCLUDE(<version>)\n// <version> is available since C++20\n#include <version>\n#endif\n\n//\n// C++ feature detections\n//\n\n// switch usages of the std::to_chars()/std::from_chars() functions which have been available since C++17.\n#if defined(FK_YAML_HAS_CXX_17) && defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L\n#define FK_YAML_HAS_TO_CHARS (1)\n#else\n#define FK_YAML_HAS_TO_CHARS (0)\n#endif\n\n// switch usage of char8_t which has been available since C++20.\n#if defined(FK_YAML_HAS_CXX_20) && defined(__cpp_char8_t) && __cpp_char8_t >= 201811L\n#define FK_YAML_HAS_CHAR8_T (1)\n#else\n#define FK_YAML_HAS_CHAR8_T (0)\n#endif\n\n//\n// utility macros\n//\n\n// switch usage of [[likely]] C++ attribute which has been available since C++20.\n#if defined(FK_YAML_HAS_CXX_20) && FK_YAML_HAS_CPP_ATTRIBUTE(likely) >= 201803L\n#define FK_YAML_LIKELY(expr) (!!(expr)) [[likely]]\n#elif FK_YAML_HAS_BUILTIN(__builtin_expect)\n#define FK_YAML_LIKELY(expr) (__builtin_expect(!!(expr), 1))\n#else\n#define FK_YAML_LIKELY(expr) (!!(expr))\n#endif\n\n// switch usage of [[unlikely]] C++ attribute which has been available since C++20.\n#if defined(FK_YAML_HAS_CXX_20) && FK_YAML_HAS_CPP_ATTRIBUTE(unlikely) >= 201803L\n#define FK_YAML_UNLIKELY(expr) (!!(expr)) [[unlikely]]\n#elif FK_YAML_HAS_BUILTIN(__builtin_expect)\n#define FK_YAML_UNLIKELY(expr) (__builtin_expect(!!(expr), 0))\n#else\n#define FK_YAML_UNLIKELY(expr) (!!(expr))\n#endif\n\n#endif /* FK_YAML_DETAIL_MACROS_CPP_CONFIG_MACROS_HPP */\n\n\n#endif /* FK_YAML_DETAIL_MACROS_DEFINE_MACROS_HPP */\n\n// #include <fkYAML/detail/assert.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ASSERT_HPP\n#define FK_YAML_DETAIL_ASSERT_HPP\n\n// if FK_YAML_ASSERT is not user-defined. apply the default assert impl.\n#ifndef FK_YAML_ASSERT\n#ifndef NDEBUG\n#include <cassert>\n#define FK_YAML_ASSERT(x) assert(x)\n#else\n#define FK_YAML_ASSERT(x)\n#endif\n#endif\n\n#endif /* FK_YAML_DETAIL_ASSERT_HPP */\n\n// #include <fkYAML/detail/document_metainfo.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP\n#define FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP\n\n#include <string>\n#include <map>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_META_NODE_TRAITS_HPP\n#define FK_YAML_DETAIL_META_NODE_TRAITS_HPP\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/detect.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_META_DETECT_HPP\n#define FK_YAML_DETAIL_META_DETECT_HPP\n\n#include <iterator>\n#include <type_traits>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP\n#define FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP\n\n#include <cstddef>\n#include <type_traits>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\n#ifdef FK_YAML_HAS_CXX_14\n#include <utility>\n#endif\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/////////////////////////////////////////////////////////////////////////////////////////////////////////\n//   For contributors:\n//     This file is for supplementing future C++ STL implementations to utilize some useful features\n//     implemented in C++14 or better.\n//     This file is needed to keep the fkYAML library requirement to C++11.\n//     **DO NOT** implement features which are not included any version of STL in this file.\n//     Such implementations must be in the type_traits.hpp file.\n/////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n#ifndef FK_YAML_HAS_CXX_14\n\n/// @brief An alias template for std::add_pointer::type with C++11.\n/// @note std::add_pointer_t is available since C++14.\n/// @sa https://en.cppreference.com/w/cpp/types/add_pointer\n/// @tparam T A type to be added a pointer.\ntemplate <typename T>\nusing add_pointer_t = typename std::add_pointer<T>::type;\n\n/// @brief An alias template for std::enable_if::type with C++11.\n/// @note std::enable_if_t is available since C++14.\n/// @sa https://en.cppreference.com/w/cpp/types/enable_if\n/// @tparam Condition A condition tested at compile time.\n/// @tparam T The type defined only if Condition is true.\ntemplate <bool Condition, typename T = void>\nusing enable_if_t = typename std::enable_if<Condition, T>::type;\n\n/// @brief A simple implementation to use std::is_null_pointer with C++11.\n/// @note std::is_null_pointer is available since C++14.\n/// @sa https://en.cppreference.com/w/cpp/types/is_null_pointer\n/// @tparam T The type to be checked if it's equal to std::nullptr_t.\ntemplate <typename T>\nstruct is_null_pointer : std::is_same<std::nullptr_t, typename std::remove_cv<T>::type> {};\n\n/// @brief An alias template for std::remove_cv::type with C++11.\n/// @note std::remove_cv_t is available since C++14.\n/// @sa https://en.cppreference.com/w/cpp/types/remove_cv\n/// @tparam T A type from which const-volatile qualifiers are removed.\ntemplate <typename T>\nusing remove_cv_t = typename std::remove_cv<T>::type;\n\n/// @brief An alias template for std::remove_pointer::type with C++11.\n/// @note std::remove_pointer_t is available since C++14.\n/// @sa https://en.cppreference.com/w/cpp/types/remove_pointer\n/// @tparam T A type from which a pointer is removed.\ntemplate <typename T>\nusing remove_pointer_t = typename std::remove_pointer<T>::type;\n\n/// @brief An alias template for std::remove_reference::type with C++11.\n/// @note std::remove_reference_t is available since C++14.\n/// @sa https://en.cppreference.com/w/cpp/types/remove_reference\n/// @tparam T A type from which a reference is removed.\ntemplate <typename T>\nusing remove_reference_t = typename std::remove_reference<T>::type;\n\ntemplate <typename T, T... I>\nstruct integer_sequence {\n    using value_type = T;\n    static constexpr std::size_t size() noexcept {\n        return sizeof...(I);\n    }\n};\n\n#if !FK_YAML_HAS_BUILTIN(__make_integer_seq) && !FK_YAML_HAS_BUILTIN(__integer_pack)\n\nnamespace make_int_seq_impl {\n\ntemplate <typename IntSeq0, typename IntSeq1>\nstruct merger;\n\ntemplate <typename T, T... Ints0, T... Ints1>\nstruct merger<integer_sequence<T, Ints0...>, integer_sequence<T, Ints1...>> {\n    using type = integer_sequence<T, Ints0..., (sizeof...(Ints0) + Ints1)...>;\n};\n\ntemplate <typename T, std::size_t Num>\nstruct generator {\n    using type =\n        typename merger<typename generator<T, Num / 2>::type, typename generator<T, Num - Num / 2>::type>::type;\n};\n\ntemplate <typename T>\nstruct generator<T, 0> {\n    using type = integer_sequence<T>;\n};\n\ntemplate <typename T>\nstruct generator<T, 1> {\n    using type = integer_sequence<T, 0>;\n};\n\n} // namespace make_int_seq_impl\n\n#endif\n\ntemplate <typename T, T Num>\nusing make_integer_sequence\n#if FK_YAML_HAS_BUILTIN(__make_integer_seq)\n    // clang defines built-in __make_integer_seq to generate an integer sequence.\n    = __make_integer_seq<integer_sequence, T, Num>;\n#elif FK_YAML_HAS_BUILTIN(__integer_pack)\n    // GCC or other compilers may implement built-in __integer_pack to generate an\n    // integer sequence.\n    = integer_sequence<T, __integer_pack(Num)...>;\n#else\n    // fallback to the library implementation of make_integer_sequence.\n    = typename make_int_seq_impl::generator<T, Num>::type;\n#endif\n\ntemplate <std::size_t... Idx>\nusing index_sequence = integer_sequence<std::size_t, Idx...>;\n\ntemplate <std::size_t Num>\nusing make_index_sequence = make_integer_sequence<std::size_t, Num>;\n\ntemplate <typename... Types>\nusing index_sequence_for = make_index_sequence<sizeof...(Types)>;\n\n#else // !defined(FK_YAML_HAS_CXX_14)\n\nusing std::add_pointer_t;\nusing std::enable_if_t;\nusing std::index_sequence;\nusing std::index_sequence_for;\nusing std::integer_sequence;\nusing std::is_null_pointer;\nusing std::make_index_sequence;\nusing std::make_integer_sequence;\nusing std::remove_cv_t;\nusing std::remove_pointer_t;\nusing std::remove_reference_t;\n\n#endif // !defined(FK_YAML_HAS_CXX_14)\n\n#ifndef FK_YAML_HAS_CXX_17\n\n/// @brief A simple implementation to use std::bool_constant with C++11/C++14.\n/// @tparam Val\ntemplate <bool Val>\nusing bool_constant = std::integral_constant<bool, Val>;\n\n/// @brief A simple implementation to use std::void_t with C++11/C++14.\n/// @note\n/// std::conjunction is available since C++17.\n/// This is applied when no traits are specified as inputs.\n/// @sa https://en.cppreference.com/w/cpp/types/conjunction\n/// @tparam Traits Type traits to be checked if their ::value are all true.\ntemplate <typename... Traits>\nstruct conjunction : std::true_type {};\n\n/// @brief A partial specialization of conjunction if only one Trait is given.\n/// @tparam Trait Type trait to be checked if its ::value is true.\ntemplate <typename Trait>\nstruct conjunction<Trait> : Trait {};\n\n/// @brief A partial specialization of conjunction if more than one traits are given.\n/// @tparam First The first type trait to be checked if its ::value is true.\n/// @tparam Rest The rest of traits passed as another conjunction template arguments if First::value is true.\ntemplate <typename First, typename... Rest>\nstruct conjunction<First, Rest...> : std::conditional<First::value, conjunction<Rest...>, First>::type {};\n\n/// @brief A simple implementation to use std::disjunction with C++11/C++14.\n/// @note\n/// std::disjunction is available since C++17.\n/// This is applied when no traits are specified as inputs.\n/// @sa https://en.cppreference.com/w/cpp/types/disjunction\n/// @tparam Traits Type traits to be checked if at least one of their ::value is true.\ntemplate <typename... Traits>\nstruct disjunction : std::false_type {};\n\n/// @brief A partial specialization of disjunction if only one Trait is given.\n/// @tparam Trait Type trait to be checked if its ::value is true.\ntemplate <typename Trait>\nstruct disjunction<Trait> : Trait {};\n\n/// @brief A partial specialization of disjunction if more than one traits are given.\n/// @tparam First The first type trait to be checked if its ::value is true.\n/// @tparam Rest The rest of traits passed as another conjunction template arguments if First::value is false.\ntemplate <typename First, typename... Rest>\nstruct disjunction<First, Rest...> : std::conditional<First::value, First, disjunction<Rest...>>::type {};\n\n/// @brief A simple implementation to use std::negation with C++11/C++14.\n/// @note std::negation is available since C++17.\n/// @sa https://en.cppreference.com/w/cpp/types/negation\n/// @tparam Trait Type trait whose ::value is negated.\ntemplate <typename Trait>\nstruct negation : std::integral_constant<bool, !Trait::value> {};\n\n/// @brief A helper for void_t.\n/// @tparam Types Any types to be transformed to void type.\ntemplate <typename... Types>\nstruct make_void {\n    using type = void;\n};\n\n/// @brief A simple implementation to use std::void_t with C++11/C++14.\n/// @note std::void_t is available since C++17.\n/// @sa https://en.cppreference.com/w/cpp/types/void_t\n/// @tparam Types Any types to be transformed to void type.\ntemplate <typename... Types>\nusing void_t = typename make_void<Types...>::type;\n\n#else // !defined(FK_YAML_HAS_CXX_17)\n\nusing std::bool_constant;\nusing std::conjunction;\nusing std::disjunction;\nusing std::negation;\nusing std::void_t;\n\n#endif // !defined(FK_YAML_HAS_CXX_17)\n\n#ifndef FK_YAML_HAS_CXX_20\n\n/// @brief A simple implementation to use std::remove_cvref_t with C++11/C++14/C++17.\n/// @note std::remove_cvref & std::remove_cvref_t are available since C++20.\n/// @sa https://en.cppreference.com/w/cpp/types/remove_cvref\n/// @tparam T A type from which cv-qualifiers and reference are removed.\ntemplate <typename T>\nusing remove_cvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n#else\n\nusing std::remove_cvref_t;\n\n#endif\n\n/// @brief A wrapper function to call std::unreachable() (since C++23) or similar compiler specific extensions.\n/// @note This function is implemented only for better code optimization against dead code and thus excluded from\n/// coverage report.\n// LCOV_EXCL_START\n[[noreturn]] inline void unreachable() {\n    // use compiler specific extensions if possible.\n    // undefined behavior should be raised by an empty function with noreturn attribute.\n\n#if defined(FK_YAML_HAS_CXX_23) || (defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L)\n    std::unreachable();\n#elif defined(_MSC_VER) && !defined(__clang__) // MSVC\n    __assume(false);\n#else\n    __builtin_unreachable();\n#endif\n}\n// LCOV_EXCL_STOP\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_META_STL_SUPPLEMENT_HPP */\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A dummy struct to represent detection failure.\nstruct nonesuch {\n    nonesuch() = delete;\n    ~nonesuch() = delete;\n    nonesuch(const nonesuch&) = delete;\n    nonesuch(nonesuch&&) = delete;\n    nonesuch& operator=(const nonesuch&) = delete;\n    nonesuch& operator=(nonesuch&&) = delete;\n};\n\n/// @brief namespace to implement detector type traits\nnamespace detector_impl {\n\n/// @brief A helper for general type detection.\n/// @tparam Default A type to represent detection failure.\n/// @tparam AlwaysVoid This must be void type.\n/// @tparam Op A type for desired operation type.\n/// @tparam Args Argument types passed to desired operation.\ntemplate <typename Default, typename AlwaysVoid, template <typename...> class Op, typename... Args>\nstruct detector : std::false_type {\n    /// @brief A type which represents detection failure.\n    using type = Default;\n};\n\n/// @brief A partial specialization of detector if desired operation type is found.\n/// @tparam Default A type to represent detection failure.\n/// @tparam Op A type for desired operation type.\n/// @tparam Args Argument types passed to desired operation.\ntemplate <typename Default, template <typename...> class Op, typename... Args>\nstruct detector<Default, void_t<Op<Args...>>, Op, Args...> : std::true_type {\n    /// @brief A detected type.\n    using type = Op<Args...>;\n};\n\n} // namespace detector_impl\n\n/// @brief Type traits to detect Op operation with Args argument types\n/// @tparam Op A desired operation type.\n/// @tparam Args Argument types passed to desired operation.\ntemplate <template <typename...> class Op, typename... Args>\nusing is_detected = detector_impl::detector<nonesuch, void, Op, Args...>;\n\n/// @brief Type traits to represent a detected type.\n/// @tparam Op A type for desired operation type.\n/// @tparam Args Argument types passed to desired operation.\ntemplate <template <typename...> class Op, typename... Args>\nusing detected_t = typename detector_impl::detector<nonesuch, void, Op, Args...>::type;\n\n/// @brief Type traits to check if Expected and a detected type are exactly the same.\n/// @tparam Expected An expected detection result type.\n/// @tparam Op A type for desired operation.\n/// @tparam Args Argument types passed to desired operation.\ntemplate <typename Expected, template <typename...> class Op, typename... Args>\nusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\n/// @brief namespace for member type detections of aliases and functions.\nnamespace detect {\n\n/// @brief The type which represents `iterator` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing iterator_t = typename T::iterator;\n\n/// @brief The type which represents `key_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing key_type_t = typename T::key_type;\n\n/// @brief The type which represents `mapped_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing mapped_type_t = typename T::mapped_type;\n\n/// @brief The type which represents `value_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing value_type_t = typename T::value_type;\n\n/// @brief The type which represents `difference_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing difference_type_t = typename T::difference_type;\n\n/// @brief The type which represents `pointer` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing pointer_t = typename T::pointer;\n\n/// @brief The type which represents `reference` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing reference_t = typename T::reference;\n\n/// @brief The type which represents `iterator_category` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing iterator_category_t = typename T::iterator_category;\n\n/// @brief The type which represents `container_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing container_type_t = typename T::container_type;\n\n/// @brief The type which represents emplace member function.\n/// @tparam T A target type.\ntemplate <typename T, typename... Args>\nusing emplace_fn_t = decltype(std::declval<T>().emplace(std::declval<Args>()...));\n\n/// @brief The type which represents reserve member function.\n/// @tparam T A target type.\ntemplate <typename T>\nusing reserve_fn_t = decltype(std::declval<T>().reserve(std::declval<typename remove_cvref_t<T>::size_type>()));\n\n/// @brief Type traits to check if T has `iterator` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing has_iterator = is_detected<iterator_t, remove_cvref_t<T>>;\n\n/// @brief Type traits to check if T has `key_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing has_key_type = is_detected<key_type_t, remove_cvref_t<T>>;\n\n/// @brief Type traits to check if T has `mapped_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing has_mapped_type = is_detected<mapped_type_t, remove_cvref_t<T>>;\n\n/// @brief Type traits to check if T has `value_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing has_value_type = is_detected<value_type_t, remove_cvref_t<T>>;\n\n/// @brief Type traits to check if T is a std::iterator_traits like type.\n/// @tparam T A target type.\ntemplate <typename T>\nstruct is_iterator_traits : conjunction<\n                                is_detected<difference_type_t, remove_cvref_t<T>>, has_value_type<remove_cvref_t<T>>,\n                                is_detected<pointer_t, remove_cvref_t<T>>, is_detected<reference_t, remove_cvref_t<T>>,\n                                is_detected<iterator_category_t, remove_cvref_t<T>>> {};\n\n/// @brief Type traits to check if T has `container_type` member type.\n/// @tparam T A target type.\ntemplate <typename T>\nusing has_container_type = is_detected<container_type_t, remove_cvref_t<T>>;\n\n/// @brief Type traits to check if T has reserve member function.\n/// @tparam T A target type.\ntemplate <typename T>\nusing has_reserve = is_detected<reserve_fn_t, T>;\n\n// fallback to these STL functions.\nusing std::begin;\nusing std::end;\n\n/// @brief Type traits to check if begin/end functions can be called on a T object.\n/// @tparam T A target type.\ntemplate <typename T, typename = void>\nstruct has_begin_end : std::false_type {};\n\n/// @brief Type traits to check if begin/end functions can be called on a T object.\n/// @tparam T A target type.\ntemplate <typename T>\nstruct has_begin_end<T, void_t<decltype(begin(std::declval<T>()), end(std::declval<T>()))>> : std::true_type {};\n\n} // namespace detect\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_META_DETECT_HPP */\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_META_TYPE_TRAITS_HPP\n#define FK_YAML_DETAIL_META_TYPE_TRAITS_HPP\n\n#include <iterator>\n#include <limits>\n#include <type_traits>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/detect.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Type trait to check if T and U are comparable types.\n/// @tparam Comparator An object type to compare T and U objects.\n/// @tparam T A type for comparison.\n/// @tparam U The other type for comparison.\n/// @tparam typename Placeholder for determining T and U are comparable types.\ntemplate <typename Comparator, typename T, typename U, typename = void>\nstruct is_comparable : std::false_type {};\n\n/// @brief A partial specialization of is_comparable if T and U are comparable types.\n/// @tparam Comparator An object type to compare T and U objects.\n/// @tparam T A type for comparison.\n/// @tparam U The other type for comparison.\ntemplate <typename Comparator, typename T, typename U>\nstruct is_comparable<\n    Comparator, T, U,\n    void_t<\n        decltype(std::declval<Comparator>()(std::declval<T>(), std::declval<U>())),\n        decltype(std::declval<Comparator>()(std::declval<U>(), std::declval<T>()))>> : std::true_type {};\n\n/// @brief Type trait to check if KeyType can be used as key type.\n/// @tparam Comparator An object type to compare T and U objects.\n/// @tparam ObjectKeyType The original key type.\n/// @tparam KeyType A type to be used as key type.\ntemplate <typename Comparator, typename ObjectKeyType, typename KeyType>\nusing is_usable_as_key_type = typename std::conditional<\n    is_comparable<Comparator, ObjectKeyType, KeyType>::value, std::true_type, std::false_type>::type;\n\n/// @brief Type trait to check if IntegralType is of non-boolean integral types.\n/// @tparam IntegralType A type to be checked.\n/// @tparam typename N/A\ntemplate <typename IntegralType, typename = void>\nstruct is_non_bool_integral : std::false_type {};\n\n/// @brief A partial specialization of is_non_bool_integral if IntegralType is of non-boolean integral types.\n/// @tparam IntegralType A type to be checked.\ntemplate <typename IntegralType>\nstruct is_non_bool_integral<\n    IntegralType,\n    enable_if_t<conjunction<std::is_integral<IntegralType>, negation<std::is_same<bool, IntegralType>>>::value>>\n    : std::true_type {};\n\n/// @brief Type traits to check if Types are all signed arithmetic types.\n/// @tparam Types Types to check if they are all signed arithmetic types.\ntemplate <typename... Types>\nusing is_all_signed = conjunction<std::is_signed<Types>...>;\n\n/// @brief Type traits to check if Types are all unsigned arithmetic types.\n/// @tparam Types Types to check if they are all unsigned arithmetic types.\ntemplate <typename... Types>\nusing is_all_unsigned = conjunction<std::is_unsigned<Types>...>;\n\n/// @brief Type trait implementation to check if TargetIntegerType and CompatibleIntegerType are compatible integer\n/// types.\n/// @tparam TargetIntegerType A target integer type.\n/// @tparam CompatibleIntegerType A compatible integer type.\n/// @tparam typename N/A\ntemplate <typename TargetIntegerType, typename CompatibleIntegerType, typename = void>\nstruct is_compatible_integer_type_impl : std::false_type {};\n\n/// @brief A partial specialization of is_compatible_integer_type_impl if TargetIntegerType and CompatibleIntegerType\n/// are compatible integer types.\n/// @tparam TargetIntegerType A target integer type.\n/// @tparam CompatibleIntegerType A compatible integer type.\ntemplate <typename TargetIntegerType, typename CompatibleIntegerType>\nstruct is_compatible_integer_type_impl<\n    TargetIntegerType, CompatibleIntegerType, enable_if_t<is_non_bool_integral<CompatibleIntegerType>::value>>\n    : std::true_type {};\n\n/// @brief Type traits to check if TargetIntegerType and CompatibleIntegerType are compatible integer types.\n/// @tparam TargetIntegerType A target integer type.\n/// @tparam CompatibleIntegerType A compatible integer type.\ntemplate <typename TargetIntegerType, typename CompatibleIntegerType>\nstruct is_compatible_integer_type : is_compatible_integer_type_impl<TargetIntegerType, CompatibleIntegerType> {};\n\n/// @brief Type traits to check if T is a complete type.\n/// @tparam T A type to be checked if a complete type.\n/// @tparam typename N/A\ntemplate <typename T, typename = void>\nstruct is_complete_type : std::false_type {};\n\n/// @brief A partial specialization of is_complete_type if T is a complete type.\n/// @tparam T\ntemplate <typename T>\nstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\n/// @brief A utility alias to test if the value type of `ItrType` is `T`.\n/// @tparam ItrType An iterator type.\n/// @tparam T The target iterator value type.\ntemplate <typename ItrType, typename T>\nusing is_iterator_of = std::is_same<remove_cv_t<typename std::iterator_traits<ItrType>::value_type>, T>;\n\n/// @brief A utility struct to generate static constant instance.\n/// @tparam T A target type for the resulting static constant instance.\ntemplate <typename T>\nstruct static_const {\n    static FK_YAML_INLINE_VAR constexpr T value {}; // NOLINT(readability-identifier-naming)\n};\n\n#ifndef FK_YAML_HAS_CXX_17\n/// @brief A instantiation of static_const::value instance.\n/// @note This is required if inline variables are not available. C++11-14 do not provide such a feature yet.\n/// @tparam T A target type for the resulting static constant instance.\ntemplate <typename T>\nconstexpr T static_const<T>::value;\n#endif\n\n/// @brief A helper structure for tag dispatch.\n/// @tparam T A tag type.\ntemplate <typename T>\nstruct type_tag {\n    /// @brief A tagged type.\n    using type = T;\n};\n\n/// @brief A utility struct to retrieve the first type in variadic template arguments.\n/// @tparam Types Types of variadic template arguments.\ntemplate <typename... Types>\nstruct get_head_type;\n\n/// @brief A specialization of get_head_type if variadic template has no arguments.\n/// @tparam  N/A\ntemplate <>\nstruct get_head_type<> {\n    /// @brief A head type\n    using type = void;\n};\n\n/// @brief A partial specialization of get_head_type if variadic template has one or more argument(s).\n/// @tparam First The first type in the arguments\n/// @tparam Rest The rest of the types in the arguments.\ntemplate <typename First, typename... Rest>\nstruct get_head_type<First, Rest...> {\n    /// @brief A head type.\n    using type = First;\n};\n\n/// @brief An alias template to retrieve the first type in variadic template arguments.\n/// @tparam Types Types of variadic template arguments.\ntemplate <typename... Types>\nusing head_type = typename get_head_type<Types...>::type;\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_META_TYPE_TRAITS_HPP */\n\n// #include <fkYAML/fkyaml_fwd.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_FKYAML_FWD_HPP\n#define FK_YAML_FKYAML_FWD_HPP\n\n#include <cstdint>\n#include <map>\n#include <string>\n#include <vector>\n\n// #include <fkYAML/detail/macros/version_macros.hpp>\n\n\nFK_YAML_NAMESPACE_BEGIN\n\n/// @brief An ADL friendly converter between basic_node objects and native data objects.\n/// @tparam ValueType A target data type.\n/// @sa https://fktn-k.github.io/fkYAML/api/node_value_converter/\ntemplate <typename ValueType, typename = void>\nclass node_value_converter;\n\n/// @brief A class to store value of YAML nodes.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/\ntemplate <\n    template <typename, typename...> class SequenceType = std::vector,\n    template <typename, typename, typename...> class MappingType = std::map, typename BooleanType = bool,\n    typename IntegerType = std::int64_t, typename FloatNumberType = double, typename StringType = std::string,\n    template <typename, typename = void> class ConverterType = node_value_converter>\nclass basic_node;\n\n/// @brief default YAML node value container.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/node/\nusing node = basic_node<>;\n\n/// @brief A minimal map-like container which preserves insertion order.\n/// @tparam Key A type for keys.\n/// @tparam Value A type for values.\n/// @tparam IgnoredCompare A placeholder for key comparison. This will be ignored.\n/// @tparam Allocator A class for allocators.\n/// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\ntemplate <typename Key, typename Value, typename IgnoredCompare, typename Allocator>\nclass ordered_map;\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_FKYAML_FWD_HPP */\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/////////////////////////////\n//   is_basic_node traits\n/////////////////////////////\n\n/// @brief A struct to check the template parameter class is a kind of basic_node template class.\n/// @tparam T A class to be checked if it's a kind of basic_node template class.\ntemplate <typename T>\nstruct is_basic_node : std::false_type {};\n\n/// @brief A partial specialization of is_basic_node for basic_node template class.\n/// @tparam SequenceType A type for sequence node value containers.\n/// @tparam MappingType A type for mapping node value containers.\n/// @tparam BooleanType A type for boolean node values.\n/// @tparam IntegerType A type for integer node values.\n/// @tparam FloatNumberType A type for float number node values.\n/// @tparam StringType A type for string node values.\n/// @tparam Converter A type for\ntemplate <\n    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,\n    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,\n    template <typename, typename> class Converter>\nstruct is_basic_node<\n    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, Converter>>\n    : std::true_type {};\n\n///////////////////////////////////\n//   is_node_ref_storage traits\n///////////////////////////////////\n\n// forward declaration for node_ref_storage<...>\ntemplate <typename>\nclass node_ref_storage;\n\n/// @brief A struct to check the template parameter class is a kind of node_ref_storage_template class.\n/// @tparam T A type to be checked if it's a kind of node_ref_storage template class.\ntemplate <typename T>\nstruct is_node_ref_storage : std::false_type {};\n\n/// @brief A partial specialization for node_ref_storage template class.\n/// @tparam T A template parameter type of node_ref_storage template class.\ntemplate <typename T>\nstruct is_node_ref_storage<node_ref_storage<T>> : std::true_type {};\n\n///////////////////////////////////////////////////////\n//   basic_node conversion API representative types\n///////////////////////////////////////////////////////\n\n/// @brief A type represent from_node function.\n/// @tparam T A type which provides from_node function.\n/// @tparam Args Argument types passed to from_node function.\ntemplate <typename T, typename... Args>\nusing from_node_function_t = decltype(T::from_node(std::declval<Args>()...));\n\n/// @brief A type which represent to_node function.\n/// @tparam T A type which provides to_node function.\n/// @tparam Args Argument types passed to to_node function.\ntemplate <typename T, typename... Args>\nusing to_node_function_t = decltype(T::to_node(std::declval<Args>()...));\n\n///////////////////////////////////////////////////\n//   basic_node conversion API detection traits\n///////////////////////////////////////////////////\n\n/// @brief Type traits to check if T is a compatible type for BasicNodeType in terms of from_node function.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A target type passed to from_node function.\n/// @tparam typename N/A\ntemplate <typename BasicNodeType, typename T, typename = void>\nstruct has_from_node : std::false_type {};\n\n/// @brief A partial specialization of has_from_node if T is not a basic_node template instance type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A target type passed to from_node function.\ntemplate <typename BasicNodeType, typename T>\nstruct has_from_node<BasicNodeType, T, enable_if_t<!is_basic_node<T>::value>> {\n    using converter = typename BasicNodeType::template value_converter_type<T, void>;\n\n    // NOLINTNEXTLINE(readability-identifier-naming)\n    static constexpr bool value =\n        is_detected_exact<void, from_node_function_t, converter, const BasicNodeType&, T&>::value;\n};\n\n/// @brief Type traits to check if T is a compatible type for BasicNodeType in terms of to_node function.\n/// @warning Do not pass basic_node type as BasicNodeType to avoid infinite type instantiation.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A target type passed to to_node function.\n/// @tparam typename N/A\ntemplate <typename BasicNodeType, typename T, typename = void>\nstruct has_to_node : std::false_type {};\n\n/// @brief A partial specialization of has_to_node if T is not a basic_node template instance type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A target type passed to to_node function.\ntemplate <typename BasicNodeType, typename T>\nstruct has_to_node<BasicNodeType, T, enable_if_t<!is_basic_node<T>::value>> {\n    using converter = typename BasicNodeType::template value_converter_type<T, void>;\n\n    // NOLINTNEXTLINE(readability-identifier-naming)\n    static constexpr bool value = is_detected_exact<void, to_node_function_t, converter, BasicNodeType&, T>::value;\n};\n\n///////////////////////////////////////\n//   is_node_compatible_type traits\n///////////////////////////////////////\n\n/// @brief Type traits implementation of is_node_compatible_type to check if CompatibleType is a compatible type for\n/// BasicNodeType.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatibleType A target type for compatibility check.\n/// @tparam typename N/A\ntemplate <typename BasicNodeType, typename CompatibleType, typename = void>\nstruct is_node_compatible_type_impl : std::false_type {};\n\n/// @brief A partial specialization of is_node_compatible_type_impl if CompatibleType is a complete type and is\n/// compatible for BasicNodeType.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatibleType A target type for compatibility check.\ntemplate <typename BasicNodeType, typename CompatibleType>\nstruct is_node_compatible_type_impl<\n    BasicNodeType, CompatibleType,\n    enable_if_t<conjunction<is_complete_type<CompatibleType>, has_to_node<BasicNodeType, CompatibleType>>::value>>\n    : std::true_type {};\n\n/// @brief Type traits to check if CompatibleType is a compatible type for BasicNodeType.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatibleType A target type for compatibility check.\ntemplate <typename BasicNodeType, typename CompatibleType>\nstruct is_node_compatible_type : is_node_compatible_type_impl<BasicNodeType, CompatibleType> {};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_META_NODE_TRAITS_HPP */\n\n// #include <fkYAML/yaml_version_type.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_YAML_VERSION_TYPE_HPP\n#define FK_YAML_YAML_VERSION_TYPE_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n\nFK_YAML_NAMESPACE_BEGIN\n\nenum class yaml_version_type : std::uint8_t {\n    VERSION_1_1, //!< YAML version 1.1\n    VERSION_1_2, //!< YAML version 1.2\n};\n\ninline const char* to_string(yaml_version_type t) noexcept {\n    switch (t) {\n    case yaml_version_type::VERSION_1_1:\n        return \"VERSION_1_1\";\n    case yaml_version_type::VERSION_1_2:\n        return \"VERSION_1_2\";\n    default:                   // LCOV_EXCL_LINE\n        detail::unreachable(); // LCOV_EXCL_LINE\n    }\n}\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_YAML_VERSION_TYPE_HPP */\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief The set of directives for a YAML document.\ntemplate <typename BasicNodeType, typename = enable_if_t<is_basic_node<BasicNodeType>::value>>\nstruct document_metainfo {\n    /// The YAML version used for the YAML document.\n    yaml_version_type version {yaml_version_type::VERSION_1_2};\n    /// Whether the YAML version has been specified.\n    bool is_version_specified {false};\n    /// The prefix of the primary handle.\n    std::string primary_handle_prefix;\n    /// The prefix of the secondary handle.\n    std::string secondary_handle_prefix;\n    /// The map of handle-prefix pairs.\n    std::map<std::string /*handle*/, std::string /*prefix*/> named_handle_map;\n    /// The map of anchor node which allows for key duplication.\n    std::multimap<std::string /*anchor name*/, BasicNodeType> anchor_table {};\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_DOCUMENT_METAINFO_HPP */\n\n// #include <fkYAML/detail/exception_safe_allocation.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_EXCEPTION_SAFE_ALLOCATION_HPP\n#define FK_YAML_DETAIL_EXCEPTION_SAFE_ALLOCATION_HPP\n\n#include <memory>\n#include <utility>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Helper struct which ensures destruction/deallocation of heap-allocated objects.\n/// @tparam ObjT Object type.\n/// @tparam AllocTraits Allocator traits type for the object.\ntemplate <typename ObjT, typename AllocTraits>\nstruct tidy_guard {\n    tidy_guard() = delete;\n\n    /// @brief Construct a tidy_guard with a pointer to the object.\n    /// @param p_obj\n    tidy_guard(ObjT* p_obj) noexcept\n        : p_obj(p_obj) {\n    }\n\n    // move-only\n    tidy_guard(const tidy_guard&) = delete;\n    tidy_guard& operator=(const tidy_guard&) = delete;\n\n    /// @brief Move constructs a tidy_guard object.\n    tidy_guard(tidy_guard&&) = default;\n\n    /// @brief Move assigns a tidy_guard object.\n    /// @return Reference to this tidy_guard object.\n    tidy_guard& operator=(tidy_guard&&) = default;\n\n    /// @brief Destroys this tidy_guard object. Destruction/deallocation happen if the pointer is not null.\n    ~tidy_guard() {\n        if FK_YAML_UNLIKELY (p_obj != nullptr) {\n            typename AllocTraits::allocator_type alloc {};\n            AllocTraits::destroy(alloc, p_obj);\n            AllocTraits::deallocate(alloc, p_obj, 1);\n            p_obj = nullptr;\n        }\n    }\n\n    /// @brief Get the pointer to the object.\n    /// @return The pointer to the object.\n    ObjT* get() const noexcept {\n        return p_obj;\n    }\n\n    /// @brief Checks if the pointer is not null.\n    explicit operator bool() const noexcept {\n        return p_obj != nullptr;\n    }\n\n    /// @brief Releases the pointer to the object. No destruction/deallocation happen after this function gets called.\n    /// @return The pointer to the object.\n    ObjT* release() noexcept {\n        ObjT* ret = p_obj;\n        p_obj = nullptr;\n        return ret;\n    }\n\n    /// @brief The pointer to the object.\n    ObjT* p_obj {nullptr};\n};\n\n/// @brief Allocates and constructs an `ObjT` object with given arguments.\n/// @tparam ObjT The object type.\n/// @tparam ...Args The argument types.\n/// @param ...args The arguments for construction.\n/// @return An address of allocated memory on the heap.\ntemplate <typename ObjT, typename... Args>\ninline ObjT* create_object(Args&&... args) {\n    using alloc_type = std::allocator<ObjT>;\n    using alloc_traits_type = std::allocator_traits<alloc_type>;\n\n    alloc_type alloc {};\n    tidy_guard<ObjT, alloc_traits_type> tg {alloc_traits_type::allocate(alloc, 1)};\n    alloc_traits_type::construct(alloc, tg.get(), std::forward<Args>(args)...);\n\n    FK_YAML_ASSERT(tg);\n    return tg.release();\n}\n\n/// @brief Destroys and deallocates an `ObjT` object.\n/// @tparam ObjT The object type.\n/// @param p_obj A pointer to the object.\ntemplate <typename ObjT>\ninline void destroy_object(ObjT* p_obj) {\n    FK_YAML_ASSERT(p_obj != nullptr);\n    std::allocator<ObjT> alloc;\n    std::allocator_traits<decltype(alloc)>::destroy(alloc, p_obj);\n    std::allocator_traits<decltype(alloc)>::deallocate(alloc, p_obj, 1);\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_EXCEPTION_SAFE_ALLOCATION_HPP */\n\n// #include <fkYAML/detail/input/deserializer.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_DESERIALIZER_HPP\n#define FK_YAML_DETAIL_INPUT_DESERIALIZER_HPP\n\n#include <algorithm>\n#include <deque>\n#include <vector>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/document_metainfo.hpp>\n\n// #include <fkYAML/detail/input/lexical_analyzer.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_LEXICAL_ANALYZER_HPP\n#define FK_YAML_DETAIL_INPUT_LEXICAL_ANALYZER_HPP\n\n#include <algorithm>\n#include <cctype>\n#include <cstdlib>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n// #include <fkYAML/detail/encodings/uri_encoding.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ENCODINGS_URI_ENCODING_HPP\n#define FK_YAML_DETAIL_ENCODINGS_URI_ENCODING_HPP\n\n#include <cctype>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A class which handles URI encodings.\nclass uri_encoding {\npublic:\n    /// @brief Validates the encoding of the given character sequence.\n    /// @param begin An iterator to the first element of the character sequence.\n    /// @param end An iterator to the past-the-end element of the character sequence.\n    /// @return true if all the characters are valid, false otherwise.\n    static bool validate(const char* begin, const char* end) noexcept {\n        if (begin == end) {\n            return true;\n        }\n\n        const char* current = begin;\n\n        for (; current != end; ++current) {\n            if (*current == '%') {\n                const bool are_valid_octets = validate_octets(++current, end);\n                if (!are_valid_octets) {\n                    return false;\n                }\n\n                continue;\n            }\n\n            const bool is_allowed_character = validate_character(*current);\n            if (!is_allowed_character) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\nprivate:\n    /// @brief Validates the given octets.\n    /// @param begin An iterator to the first octet.\n    /// @param end An iterator to the past-the-end element of the whole character sequence.\n    /// @return true if the octets are valid, false otherwise.\n    static bool validate_octets(const char*& begin, const char*& end) {\n        for (int i = 0; i < 2; i++, ++begin) {\n            if (begin == end) {\n                return false;\n            }\n\n            // Normalize a character for a-f/A-F comparison\n            const int octet = std::tolower(*begin);\n\n            if ('0' <= octet && octet <= '9') {\n                continue;\n            }\n\n            if ('a' <= octet && octet <= 'f') {\n                continue;\n            }\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /// @brief Verify if the given character is allowed as a URI character.\n    /// @param c The target character.\n    /// @return true if the given character is allowed as a URI character, false otherwise.\n    static bool validate_character(const char c) {\n        // Check if the current character is one of reserved/unreserved characters which are allowed for\n        // use. See the following links for details:\n        // * reserved characters:   https://datatracker.ietf.org/doc/html/rfc3986#section-2.2\n        // * unreserved characters: https://datatracker.ietf.org/doc/html/rfc3986#section-2.3\n\n        switch (c) {\n        // reserved characters (gen-delims)\n        case ':':\n        case '/':\n        case '?':\n        case '#':\n        case '[':\n        case ']':\n        case '@':\n        // reserved characters (sub-delims)\n        case '!':\n        case '$':\n        case '&':\n        case '\\'':\n        case '(':\n        case ')':\n        case '*':\n        case '+':\n        case ',':\n        case ';':\n        case '=':\n        // unreserved characters\n        case '-':\n        case '.':\n        case '_':\n        case '~':\n            return true;\n        default:\n            // alphabets and numbers are also allowed.\n            return static_cast<bool>(std::isalnum(c));\n        }\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_ENCODINGS_URI_ENCODING_HPP */\n\n// #include <fkYAML/detail/encodings/utf_encodings.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ENCODINGS_UTF_ENCODINGS_HPP\n#define FK_YAML_DETAIL_ENCODINGS_UTF_ENCODINGS_HPP\n\n#include <array>\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/exception.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_EXCEPTION_HPP\n#define FK_YAML_EXCEPTION_HPP\n\n#include <array>\n#include <initializer_list>\n#include <stdexcept>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/string_formatter.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_STRING_FORMATTER_HPP\n#define FK_YAML_DETAIL_STRING_FORMATTER_HPP\n\n#include <cstdarg>\n#include <cstdio>\n#include <memory>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n// NOLINTNEXTLINE(cert-dcl50-cpp)\ninline std::string format(const char* fmt, ...) {\n    // NOLINTBEGIN(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay)\n    va_list vl;\n    va_start(vl, fmt);\n    int size = std::vsnprintf(nullptr, 0, fmt, vl);\n    va_end(vl);\n\n    // LCOV_EXCL_START\n    if (size < 0) {\n        return \"\";\n    }\n    // LCOV_EXCL_STOP\n\n    const std::unique_ptr<char[]> buffer {new char[size + 1] {}};\n\n    va_start(vl, fmt);\n    size = std::vsnprintf(buffer.get(), size + 1, fmt, vl);\n    va_end(vl);\n    // NOLINTEND(cppcoreguidelines-pro-bounds-array-to-pointer-decay,hicpp-no-array-decay)\n\n    return {buffer.get(), static_cast<std::size_t>(size)};\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_STRING_FORMATTER_HPP */\n\n// #include <fkYAML/detail/types/node_t.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_TYPES_NODE_T_HPP\n#define FK_YAML_DETAIL_TYPES_NODE_T_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/node_type.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_NODE_TYPE_HPP\n#define FK_YAML_NODE_TYPE_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n\nFK_YAML_NAMESPACE_BEGIN\n\nenum class node_type : std::uint8_t {\n    SEQUENCE,    //!< sequence value type\n    MAPPING,     //!< mapping value type\n    NULL_OBJECT, //!< null value type\n    BOOLEAN,     //!< boolean value type\n    INTEGER,     //!< integer value type\n    FLOAT,       //!< float point value type\n    STRING,      //!< string value type\n};\n\ninline const char* to_string(node_type t) noexcept {\n    switch (t) {\n    case node_type::SEQUENCE:\n        return \"SEQUENCE\";\n    case node_type::MAPPING:\n        return \"MAPPING\";\n    case node_type::NULL_OBJECT:\n        return \"NULL_OBJECT\";\n    case node_type::BOOLEAN:\n        return \"BOOLEAN\";\n    case node_type::INTEGER:\n        return \"INTEGER\";\n    case node_type::FLOAT:\n        return \"FLOAT\";\n    case node_type::STRING:\n        return \"STRING\";\n    default:                   // LCOV_EXCL_LINE\n        detail::unreachable(); // LCOV_EXCL_LINE\n    }\n}\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_NODE_TYPE_HPP */\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Definition of node value types.\nenum class node_t : std::uint8_t {\n    SEQUENCE,     //!< sequence value type\n    MAPPING,      //!< mapping value type\n    NULL_OBJECT,  //!< null value type\n    BOOLEAN,      //!< boolean value type\n    INTEGER,      //!< integer value type\n    FLOAT_NUMBER, //!< float number value type\n    STRING,       //!< string value type\n};\n\ninline const char* to_string(node_t t) noexcept {\n    switch (t) {\n    case node_t::SEQUENCE:\n        return \"sequence\";\n    case node_t::MAPPING:\n        return \"mapping\";\n    case node_t::NULL_OBJECT:\n        return \"null\";\n    case node_t::BOOLEAN:\n        return \"boolean\";\n    case node_t::INTEGER:\n        return \"integer\";\n    case node_t::FLOAT_NUMBER:\n        return \"float\";\n    case node_t::STRING:\n        return \"string\";\n    default:                   // LCOV_EXCL_LINE\n        detail::unreachable(); // LCOV_EXCL_LINE\n    }\n}\n\ninline node_t convert_from_node_type(node_type t) {\n    switch (t) {\n    case node_type::SEQUENCE:\n        return node_t::SEQUENCE;\n    case node_type::MAPPING:\n        return node_t::MAPPING;\n    case node_type::NULL_OBJECT:\n        return node_t::NULL_OBJECT;\n    case node_type::BOOLEAN:\n        return node_t::BOOLEAN;\n    case node_type::INTEGER:\n        return node_t::INTEGER;\n    case node_type::FLOAT:\n        return node_t::FLOAT_NUMBER;\n    case node_type::STRING:\n        return node_t::STRING;\n    default:                   // LCOV_EXCL_LINE\n        detail::unreachable(); // LCOV_EXCL_LINE\n    }\n}\n\ninline node_type convert_to_node_type(node_t t) {\n    switch (t) {\n    case node_t::SEQUENCE:\n        return node_type::SEQUENCE;\n    case node_t::MAPPING:\n        return node_type::MAPPING;\n    case node_t::NULL_OBJECT:\n        return node_type::NULL_OBJECT;\n    case node_t::BOOLEAN:\n        return node_type::BOOLEAN;\n    case node_t::INTEGER:\n        return node_type::INTEGER;\n    case node_t::FLOAT_NUMBER:\n        return node_type::FLOAT;\n    case node_t::STRING:\n        return node_type::STRING;\n    default:                   // LCOV_EXCL_LINE\n        detail::unreachable(); // LCOV_EXCL_LINE\n    }\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_TYPES_NODE_T_HPP */\n\n\nFK_YAML_NAMESPACE_BEGIN\n\n/// @brief A base exception class used in fkYAML library.\n/// @sa https://fktn-k.github.io/fkYAML/api/exception/\nclass exception : public std::exception {\npublic:\n    /// @brief Construct a new exception object without any error messages.\n    /// @sa https://fktn-k.github.io/fkYAML/api/exception/constructor/\n    exception() = default;\n\n    /// @brief Construct a new exception object with an error message.\n    /// @param[in] msg An error message.\n    /// @sa https://fktn-k.github.io/fkYAML/api/exception/constructor/\n    explicit exception(const char* msg) noexcept {\n        if (msg) {\n            m_error_msg = msg;\n        }\n    }\n\npublic:\n    /// @brief Returns an error message internally held. If nothing, a non-null, empty string will be returned.\n    /// @return An error message internally held. The message might be empty.\n    /// @sa https://fktn-k.github.io/fkYAML/api/exception/what/\n    const char* what() const noexcept override {\n        return m_error_msg.c_str();\n    }\n\nprivate:\n    /// An error message holder.\n    std::string m_error_msg;\n};\n\n/// @brief An exception class indicating an encoding error.\n/// @sa https://fktn-k.github.io/fkYAML/api/exception/invalid_encoding/\nclass invalid_encoding : public exception {\npublic:\n    /// @brief Construct a new invalid_encoding object for UTF-8 related errors.\n    /// @param msg An error message.\n    /// @param u8 The UTF-8 character bytes.\n    explicit invalid_encoding(const char* msg, const std::initializer_list<uint8_t>& u8) noexcept\n        : exception(generate_error_message(msg, u8).c_str()) {\n    }\n\n    /// @brief Construct a new invalid_encoding object for UTF-16 related errors.\n    /// @param msg An error message.\n    /// @param u16_h The first UTF-16 encoded element used for the UTF-8 encoding.\n    /// @param u16_l The second UTF-16 encoded element used for the UTF-8 encoding.\n    explicit invalid_encoding(const char* msg, std::array<char16_t, 2> u16) noexcept\n        : exception(generate_error_message(msg, u16).c_str()) {\n    }\n\n    /// @brief Construct a new invalid_encoding object for UTF-32 related errors.\n    /// @param msg An error message.\n    /// @param u32 The UTF-32 encoded element used for the UTF-8 encoding.\n    explicit invalid_encoding(const char* msg, char32_t u32) noexcept\n        : exception(generate_error_message(msg, u32).c_str()) {\n    }\n\nprivate:\n    static std::string generate_error_message(const char* msg, const std::initializer_list<uint8_t>& u8) noexcept {\n        const auto* itr = u8.begin();\n        const auto* end_itr = u8.end();\n        std::string formatted = detail::format(\"invalid_encoding: %s in=[ 0x%02x\", msg, *itr++);\n        while (itr != end_itr) {\n            formatted += detail::format(\", 0x%02x\", *itr++);\n        }\n        formatted += \" ]\";\n        return formatted;\n    }\n\n    /// @brief Generate an error message from the given parameters for the UTF-16 encoding.\n    /// @param msg An error message.\n    /// @param h The first UTF-16 encoded element used for the UTF-8 encoding.\n    /// @param l The second UTF-16 encoded element used for the UTF-8 encoding.\n    /// @return A generated error message.\n    static std::string generate_error_message(const char* msg, std::array<char16_t, 2> u16) noexcept {\n        // uint16_t is large enough for UTF-16 encoded elements.\n        return detail::format(\n            \"invalid_encoding: %s in=[ 0x%04x, 0x%04x ]\",\n            msg,\n            static_cast<uint16_t>(u16[0]),\n            static_cast<uint16_t>(u16[1]));\n    }\n\n    /// @brief Generate an error message from the given parameters for the UTF-32 encoding.\n    /// @param msg An error message.\n    /// @param u32 The UTF-32 encoded element used for the UTF-8 encoding.\n    /// @return A genereated error message.\n    static std::string generate_error_message(const char* msg, char32_t u32) noexcept {\n        // uint32_t is large enough for UTF-32 encoded elements.\n        return detail::format(\"invalid_encoding: %s in=0x%08x\", msg, static_cast<uint32_t>(u32));\n    }\n};\n\n/// @brief An exception class indicating an error in parsing.\n/// @sa https://fktn-k.github.io/fkYAML/api/exception/parse_error/\nclass parse_error : public exception {\npublic:\n    /// @brief Constructs a new parse_error object with an error message and counts of lines and colums at the error.\n    /// @param[in] msg An error message.\n    /// @param[in] lines Count of lines.\n    /// @param[in] cols_in_line Count of colums.\n    explicit parse_error(const char* msg, uint32_t lines, uint32_t cols_in_line) noexcept\n        : exception(generate_error_message(msg, lines, cols_in_line).c_str()) {\n    }\n\nprivate:\n    static std::string generate_error_message(const char* msg, uint32_t lines, uint32_t cols_in_line) noexcept {\n        return detail::format(\"parse_error: %s (at line %u, column %u)\", msg, lines, cols_in_line);\n    }\n};\n\n/// @brief An exception class indicating an invalid type conversion.\n/// @sa https://fktn-k.github.io/fkYAML/api/exception/type_error/\nclass type_error : public exception {\npublic:\n    /// @brief Construct a new type_error object with an error message and a node type.\n    /// @param[in] msg An error message.\n    /// @param[in] type The type of a source node value.\n    explicit type_error(const char* msg, node_type type) noexcept\n        : exception(generate_error_message(msg, type).c_str()) {\n    }\n\n    /// @brief Construct a new type_error object with an error message and a node type.\n    /// @deprecated Use type_error(const char*, node_type) constructor. (since 0.3.12).\n    /// @param[in] msg An error message.\n    /// @param[in] type The type of a source node value.\n    FK_YAML_DEPRECATED(\"Since 0.3.12; Use explicit type_error(const char*, node_type)\")\n    explicit type_error(const char* msg, detail::node_t type) noexcept\n        : type_error(msg, detail::convert_to_node_type(type)) {\n    }\n\nprivate:\n    /// @brief Generate an error message from given parameters.\n    /// @param msg An error message.\n    /// @param type The type of a source node value.\n    /// @return A generated error message.\n    static std::string generate_error_message(const char* msg, node_type type) noexcept {\n        return detail::format(\"type_error: %s type=%s\", msg, to_string(type));\n    }\n};\n\n/// @brief An exception class indicating an out-of-range error.\n/// @sa https://fktn-k.github.io/fkYAML/api/exception/out_of_range/\nclass out_of_range : public exception {\npublic:\n    /// @brief Construct a new out_of_range object with an invalid index value.\n    /// @param[in] index An invalid index value.\n    explicit out_of_range(int index) noexcept\n        : exception(generate_error_message(index).c_str()) {\n    }\n\n    /// @brief Construct a new out_of_range object with invalid key contents.\n    /// @param[in] key Invalid key contents\n    explicit out_of_range(const char* key) noexcept\n        : exception(generate_error_message(key).c_str()) {\n    }\n\nprivate:\n    static std::string generate_error_message(int index) noexcept {\n        return detail::format(\"out_of_range: index %d is out of range\", index);\n    }\n\n    static std::string generate_error_message(const char* key) noexcept {\n        return detail::format(\"out_of_range: key \\'%s\\' is not found.\", key);\n    }\n};\n\n/// @brief An exception class indicating an invalid tag.\n/// @sa https://fktn-k.github.io/fkYAML/api/exception/invalid_tag/\nclass invalid_tag : public exception {\npublic:\n    /// @brief Constructs a new invalid_tag object with an error message and invalid tag contents.\n    /// @param[in] msg An error message.\n    /// @param[in] tag Invalid tag contents.\n    explicit invalid_tag(const char* msg, const char* tag)\n        : exception(generate_error_message(msg, tag).c_str()) {\n    }\n\nprivate:\n    static std::string generate_error_message(const char* msg, const char* tag) noexcept {\n        return detail::format(\"invalid_tag: %s tag=%s\", msg, tag);\n    }\n};\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_EXCEPTION_HPP */\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/////////////////////////\n//   UTF-8 Encoding   ///\n/////////////////////////\n\n/// @brief A class which handles UTF-8 encodings.\nnamespace utf8 {\n\n/// @brief Query the number of UTF-8 character bytes with the first byte.\n/// @param first_byte The first byte of a UTF-8 character.\n/// @return The number of UTF-8 character bytes.\ninline uint32_t get_num_bytes(uint8_t first_byte) {\n    // The first byte starts with 0b0XXX'XXXX -> 1-byte character\n    if FK_YAML_LIKELY (first_byte < 0x80) {\n        return 1;\n    }\n    // The first byte starts with 0b110X'XXXX -> 2-byte character\n    if ((first_byte & 0xE0) == 0xC0) {\n        return 2;\n    }\n    // The first byte starts with 0b1110'XXXX -> 3-byte character\n    if ((first_byte & 0xF0) == 0xE0) {\n        return 3;\n    }\n    // The first byte starts with 0b1111'0XXX -> 4-byte character\n    if ((first_byte & 0xF8) == 0xF0) {\n        return 4;\n    }\n\n    // The first byte starts with 0b10XX'XXXX or 0b1111'1XXX -> invalid\n    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first_byte});\n}\n\n/// @brief Checks if `byte` is a valid 1-byte UTF-8 character.\n/// @param[in] byte The byte value.\n/// @return true if `byte` is a valid 1-byte UTF-8 character, false otherwise.\ninline bool validate(uint8_t byte) noexcept {\n    // U+0000..U+007F\n    return byte <= 0x7Fu;\n}\n\n/// @brief Checks if the given bytes are a valid 2-byte UTF-8 character.\n/// @param[in] byte0 The first byte value.\n/// @param[in] byte1 The second byte value.\n/// @return true if the given bytes a valid 3-byte UTF-8 character, false otherwise.\ninline bool validate(uint8_t byte0, uint8_t byte1) noexcept {\n    // U+0080..U+07FF\n    //   1st Byte: 0xC2..0xDF\n    //   2nd Byte: 0x80..0xBF\n    if FK_YAML_LIKELY (0xC2u <= byte0 && byte0 <= 0xDFu) {\n        if FK_YAML_LIKELY (0x80u <= byte1 && byte1 <= 0xBFu) {\n            return true;\n        }\n    }\n\n    // The rest of byte combinations are invalid.\n    return false;\n}\n\n/// @brief Checks if the given bytes are a valid 3-byte UTF-8 character.\n/// @param[in] byte0 The first byte value.\n/// @param[in] byte1 The second byte value.\n/// @param[in] byte2 The third byte value.\n/// @return true if the given bytes a valid 2-byte UTF-8 character, false otherwise.\ninline bool validate(uint8_t byte0, uint8_t byte1, uint8_t byte2) noexcept {\n    // U+1000..U+CFFF:\n    //   1st Byte: 0xE0..0xEC\n    //   2nd Byte: 0x80..0xBF\n    //   3rd Byte: 0x80..0xBF\n    if (0xE0u <= byte0 && byte0 <= 0xECu) {\n        if FK_YAML_LIKELY (0x80u <= byte1 && byte1 <= 0xBFu) {\n            if FK_YAML_LIKELY (0x80u <= byte2 && byte2 <= 0xBFu) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    // U+D000..U+D7FF:\n    //   1st Byte: 0xED\n    //   2nd Byte: 0x80..0x9F\n    //   3rd Byte: 0x80..0xBF\n    if (byte0 == 0xEDu) {\n        if FK_YAML_LIKELY (0x80u <= byte1 && byte1 <= 0x9Fu) {\n            if FK_YAML_LIKELY (0x80u <= byte2 && byte2 <= 0xBFu) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    // U+E000..U+FFFF:\n    //   1st Byte: 0xEE..0xEF\n    //   2nd Byte: 0x80..0xBF\n    //   3rd Byte: 0x80..0xBF\n    if FK_YAML_LIKELY (byte0 == 0xEEu || byte0 == 0xEFu) {\n        if FK_YAML_LIKELY (0x80u <= byte1 && byte1 <= 0xBFu) {\n            if FK_YAML_LIKELY (0x80u <= byte2 && byte2 <= 0xBFu) {\n                return true;\n            }\n        }\n    }\n\n    // The rest of byte combinations are invalid.\n    return false;\n}\n\n/// @brief Checks if the given bytes are a valid 4-byte UTF-8 character.\n/// @param[in] byte0 The first byte value.\n/// @param[in] byte1 The second byte value.\n/// @param[in] byte2 The third byte value.\n/// @param[in] byte3 The fourth byte value.\n/// @return true if the given bytes a valid 4-byte UTF-8 character, false otherwise.\ninline bool validate(uint8_t byte0, uint8_t byte1, uint8_t byte2, uint8_t byte3) noexcept {\n    // U+10000..U+3FFFF:\n    //   1st Byte: 0xF0\n    //   2nd Byte: 0x90..0xBF\n    //   3rd Byte: 0x80..0xBF\n    //   4th Byte: 0x80..0xBF\n    if (byte0 == 0xF0u) {\n        if FK_YAML_LIKELY (0x90u <= byte1 && byte1 <= 0xBFu) {\n            if FK_YAML_LIKELY (0x80u <= byte2 && byte2 <= 0xBFu) {\n                if FK_YAML_LIKELY (0x80u <= byte3 && byte3 <= 0xBFu) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    // U+40000..U+FFFFF:\n    //   1st Byte: 0xF1..0xF3\n    //   2nd Byte: 0x80..0xBF\n    //   3rd Byte: 0x80..0xBF\n    //   4th Byte: 0x80..0xBF\n    if (0xF1u <= byte0 && byte0 <= 0xF3u) {\n        if FK_YAML_LIKELY (0x80u <= byte1 && byte1 <= 0xBFu) {\n            if FK_YAML_LIKELY (0x80u <= byte2 && byte2 <= 0xBFu) {\n                if FK_YAML_LIKELY (0x80u <= byte3 && byte3 <= 0xBFu) {\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    // U+100000..U+10FFFF:\n    //   1st Byte: 0xF4\n    //   2nd Byte: 0x80..0x8F\n    //   3rd Byte: 0x80..0xBF\n    //   4th Byte: 0x80..0xBF\n    if FK_YAML_LIKELY (byte0 == 0xF4u) {\n        if FK_YAML_LIKELY (0x80u <= byte1 && byte1 <= 0x8Fu) {\n            if FK_YAML_LIKELY (0x80u <= byte2 && byte2 <= 0xBFu) {\n                if FK_YAML_LIKELY (0x80u <= byte3 && byte3 <= 0xBFu) {\n                    return true;\n                }\n            }\n        }\n    }\n\n    // The rest of byte combinations are invalid.\n    return false;\n}\n\n/// @brief Converts UTF-16 encoded characters to UTF-8 encoded bytes.\n/// @param[in] utf16 UTF-16 encoded character(s).\n/// @param[out] utf8 UTF-8 encoded bytes.\n/// @param[out] consumed_size The number of UTF-16 encoded characters used for the conversion.\n/// @param[out] encoded_size The size of UTF-encoded bytes.\ninline void from_utf16(\n    std::array<char16_t, 2> utf16, std::array<uint8_t, 4>& utf8, uint32_t& consumed_size, uint32_t& encoded_size) {\n    const auto first = utf16[0];\n    const auto second = utf16[1];\n    if (first < 0x80u) {\n        utf8[0] = static_cast<uint8_t>(first & 0x7Fu);\n        consumed_size = 1;\n        encoded_size = 1;\n    }\n    else if (first <= 0x7FFu) {\n        const auto utf8_chunk = static_cast<uint16_t>(0xC080u | ((first & 0x07C0u) << 2) | (first & 0x3Fu));\n        utf8[0] = static_cast<uint8_t>(utf8_chunk >> 8);\n        utf8[1] = static_cast<uint8_t>(utf8_chunk);\n        consumed_size = 1;\n        encoded_size = 2;\n    }\n    else if (first < 0xD800u || 0xE000u <= first) {\n        const auto utf8_chunk =\n            static_cast<uint32_t>(0xE08080u | ((first & 0xF000u) << 4) | ((first & 0x0FC0u) << 2) | (first & 0x3Fu));\n        utf8[0] = static_cast<uint8_t>(utf8_chunk >> 16);\n        utf8[1] = static_cast<uint8_t>(utf8_chunk >> 8);\n        utf8[2] = static_cast<uint8_t>(utf8_chunk);\n        consumed_size = 1;\n        encoded_size = 3;\n    }\n    else if (first <= 0xDBFFu && 0xDC00u <= second && second <= 0xDFFFu) {\n        // surrogate pair\n        const uint32_t code_point = 0x10000u + ((first & 0x03FFu) << 10) + (second & 0x03FFu);\n        const auto utf8_chunk = static_cast<uint32_t>(\n            0xF0808080u | ((code_point & 0x1C0000u) << 6) | ((code_point & 0x03F000u) << 4) |\n            ((code_point & 0x0FC0u) << 2) | (code_point & 0x3Fu));\n        utf8[0] = static_cast<uint8_t>(utf8_chunk >> 24);\n        utf8[1] = static_cast<uint8_t>(utf8_chunk >> 16);\n        utf8[2] = static_cast<uint8_t>(utf8_chunk >> 8);\n        utf8[3] = static_cast<uint8_t>(utf8_chunk);\n        consumed_size = 2;\n        encoded_size = 4;\n    }\n    else {\n        throw invalid_encoding(\"Invalid UTF-16 encoding detected.\", utf16);\n    }\n}\n\n/// @brief Converts a UTF-32 encoded character to UTF-8 encoded bytes.\n/// @param[in] utf32 A UTF-32 encoded character.\n/// @param[out] utf8 UTF-8 encoded bytes.\n/// @param[in] encoded_size The size of UTF-encoded bytes.\ninline void from_utf32(const char32_t utf32, std::array<uint8_t, 4>& utf8, uint32_t& encoded_size) {\n    if (utf32 < 0x80u) {\n        utf8[0] = static_cast<uint8_t>(utf32 & 0x007F);\n        encoded_size = 1;\n    }\n    else if (utf32 <= 0x7FFu) {\n        const auto utf8_chunk = static_cast<uint16_t>(0xC080u | ((utf32 & 0x07C0u) << 2) | (utf32 & 0x3Fu));\n        utf8[0] = static_cast<uint8_t>(utf8_chunk >> 8);\n        utf8[1] = static_cast<uint8_t>(utf8_chunk);\n        encoded_size = 2;\n    }\n    else if (utf32 <= 0xFFFFu) {\n        const auto utf8_chunk =\n            static_cast<uint32_t>(0xE08080u | ((utf32 & 0xF000u) << 4) | ((utf32 & 0x0FC0u) << 2) | (utf32 & 0x3F));\n        utf8[0] = static_cast<uint8_t>(utf8_chunk >> 16);\n        utf8[1] = static_cast<uint8_t>(utf8_chunk >> 8);\n        utf8[2] = static_cast<uint8_t>(utf8_chunk);\n        encoded_size = 3;\n    }\n    else if (utf32 <= 0x10FFFFu) {\n        const auto utf8_chunk = static_cast<uint32_t>(\n            0xF0808080u | ((utf32 & 0x1C0000u) << 6) | ((utf32 & 0x03F000u) << 4) | ((utf32 & 0x0FC0u) << 2) |\n            (utf32 & 0x3Fu));\n        utf8[0] = static_cast<uint8_t>(utf8_chunk >> 24);\n        utf8[1] = static_cast<uint8_t>(utf8_chunk >> 16);\n        utf8[2] = static_cast<uint8_t>(utf8_chunk >> 8);\n        utf8[3] = static_cast<uint8_t>(utf8_chunk);\n        encoded_size = 4;\n    }\n    else {\n        throw invalid_encoding(\"Invalid UTF-32 encoding detected.\", utf32);\n    }\n}\n\n} // namespace utf8\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_ENCODINGS_UTF_ENCODINGS_HPP */\n\n// #include <fkYAML/detail/input/block_scalar_header.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_BLOCK_SCALAR_HEADER_HPP\n#define FK_YAML_DETAIL_INPUT_BLOCK_SCALAR_HEADER_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Definition of chomping indicator types.\nenum class chomping_indicator_t : std::uint8_t {\n    STRIP, //!< excludes final line breaks and trailing empty lines indicated by `-`.\n    CLIP,  //!< preserves final line breaks but excludes trailing empty lines. no indicator means this type.\n    KEEP,  //!< preserves final line breaks and trailing empty lines indicated by `+`.\n};\n\n/// @brief Block scalar header information.\nstruct block_scalar_header {\n    /// Chomping indicator type.\n    chomping_indicator_t chomp {chomping_indicator_t::CLIP};\n    /// Content indentation level of a block scalar.\n    uint32_t indent {0};\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_BLOCK_SCALAR_HEADER_HPP */\n\n// #include <fkYAML/detail/input/position_tracker.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_POSITION_TRACKER_HPP\n#define FK_YAML_DETAIL_INPUT_POSITION_TRACKER_HPP\n\n#include <algorithm>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/str_view.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_STR_VIEW_HPP\n#define FK_YAML_DETAIL_STR_VIEW_HPP\n\n#include <limits>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Non owning view into constant character sequence.\n/// @note\n/// This class is a minimal implementation of std::basic_string_view which has been available since C++17\n/// but pretty useful and efficient for referencing/investigating character sequences.\n/// @warning\n/// This class intentionally omits a lot of value checks to improve efficiency. Necessary checks should be\n/// made before calling this class' APIs for safety.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type which defaults to std::char_traits<CharT>.\ntemplate <typename CharT, typename Traits = std::char_traits<CharT>>\nclass basic_str_view {\n    static_assert(!std::is_array<CharT>::value, \"CharT must not be an array type.\");\n    static_assert(\n        std::is_trivial<CharT>::value && std::is_standard_layout<CharT>::value,\n        \"CharT must be a trivial, standard layout type.\");\n    static_assert(\n        std::is_same<CharT, typename Traits::char_type>::value, \"CharT & Traits::char_type must be the same type.\");\n\npublic:\n    /// Character traits type.\n    using traits_type = Traits;\n    /// Character type.\n    using value_type = CharT;\n    /// Pointer type to a character.\n    using pointer = value_type*;\n    /// Constant pointer type to a character.\n    using const_pointer = const value_type*;\n    /// Reference type to a character.\n    using reference = value_type&;\n    /// Constant reference type to a character.\n    using const_reference = const value_type&;\n    /// Constant iterator type to a character.\n    using const_iterator = const value_type*;\n    /// Iterator type to a character.\n    /// (Always constant since this class isn't meant to provide any mutating features.)\n    using iterator = const_iterator;\n    /// Constant reverse iterator type to a character.\n    using const_reverse_iterator = std::reverse_iterator<const_iterator>;\n    /// Reverse iterator type to a character.\n    /// (Always constant since this class isn't meant to provide any mutating features.)\n    using reverse_iterator = const_reverse_iterator;\n    /// Size type for character sequence sizes.\n    using size_type = std::size_t;\n    /// Difference type for distances between characters.\n    using difference_type = std::ptrdiff_t;\n\n    /// Invalid position value.\n    static constexpr size_type npos = static_cast<size_type>(-1);\n\n    /// Constructs a basic_str_view object.\n    constexpr basic_str_view() noexcept = default;\n\n    /// Destroys a basic_str_view object.\n    ~basic_str_view() noexcept = default;\n\n    /// @brief Copy constructs a basic_str_view object.\n    /// @param _ A basic_str_view object to copy from.\n    constexpr basic_str_view(const basic_str_view&) noexcept = default;\n\n    /// @brief Move constructs a basic_str_view object.\n    /// @param _ A basic_str_view object to move from.\n    constexpr basic_str_view(basic_str_view&&) noexcept = default;\n\n    /// @brief Constructs a basic_str_view object from a pointer to a character sequence.\n    /// @note std::char_traits::length() is constexpr from C++17.\n    /// @param p_str A pointer to a character sequence. (Must be null-terminated, or an undefined behavior.)\n    template <\n        typename CharPtrT,\n        enable_if_t<\n            conjunction<\n                negation<std::is_array<CharPtrT>>, std::is_pointer<CharPtrT>,\n                disjunction<std::is_same<CharPtrT, value_type*>, std::is_same<CharPtrT, const value_type*>>>::value,\n            int> = 0>\n    FK_YAML_CXX17_CONSTEXPR basic_str_view(CharPtrT p_str) noexcept\n        : m_len(traits_type::length(p_str)),\n          mp_str(p_str) {\n    }\n\n    /// @brief Constructs a basic_str_view object from a C-style char array.\n    /// @note\n    /// This constructor assumes the last element is the null character ('\\0'). If that's not desirable, consider using\n    /// one of the other overloads.\n    /// @tparam N The size of a C-style char array.\n    /// @param str A C-style char array. (Must be null-terminated)\n    template <std::size_t N>\n    constexpr basic_str_view(const value_type (&str)[N]) noexcept\n        : m_len(N - 1),\n          mp_str(&str[0]) {\n    }\n\n    /// @brief Construction from a null pointer is forbidden.\n    basic_str_view(std::nullptr_t) = delete;\n\n    /// @brief Constructs a basic_str_view object from a pointer to a character sequence and its size.\n    /// @param p_str A pointer to a character sequence. (May or may not be null-terminated.)\n    /// @param len The length of a character sequence.\n    constexpr basic_str_view(const value_type* p_str, size_type len) noexcept\n        : m_len(len),\n          mp_str(p_str) {\n    }\n\n    /// @brief Constructs a basic_str_view object from compatible begin/end iterators\n    /// @tparam ItrType Iterator type to a character.\n    /// @param first The iterator to the first element of a character sequence.\n    /// @param last The iterator to the past-the-end of a character sequence.\n    template <\n        typename ItrType,\n        enable_if_t<\n            conjunction<\n                is_iterator_of<ItrType, CharT>,\n                std::is_base_of<\n                    std::random_access_iterator_tag, typename std::iterator_traits<ItrType>::iterator_category>>::value,\n            int> = 0>\n    basic_str_view(ItrType first, ItrType last) noexcept\n        : m_len(last - first),\n          mp_str(&*first) {\n    }\n\n    /// @brief Constructs a basic_str_view object from a compatible std::basic_string object.\n    /// @param str A compatible character sequence container.\n    basic_str_view(const std::basic_string<CharT>& str) noexcept\n        : m_len(str.length()),\n          mp_str(str.data()) {\n    }\n\n    /// @brief Copy assignment operator for this basic_str_view class.\n    /// @param _ A basic_str_view object to copy from.\n    /// @return Reference to this basic_str_view object.\n    basic_str_view& operator=(const basic_str_view&) noexcept = default;\n\n    /// @brief Move assignment operator for this basic_str_view class.\n    /// @param _ A basic_str_view object to move from.\n    /// @return Reference to this basic_str_view object.\n    basic_str_view& operator=(basic_str_view&&) noexcept = default;\n\n    /// @brief Get the iterator to the first element. (Always constant)\n    /// @return The iterator to the first element.\n    const_iterator begin() const noexcept {\n        return mp_str;\n    }\n\n    /// @brief Get the iterator to the past-the-end element. (Always constant)\n    /// @return The iterator to the past-the-end element.\n    const_iterator end() const noexcept {\n        return mp_str + m_len;\n    }\n\n    /// @brief Get the iterator to the first element. (Always constant)\n    /// @return The iterator to the first element.\n    const_iterator cbegin() const noexcept {\n        return mp_str;\n    }\n\n    /// @brief Get the iterator to the past-the-end element. (Always constant)\n    /// @return The iterator to the past-the-end element.\n    const_iterator cend() const noexcept {\n        return mp_str + m_len;\n    }\n\n    /// @brief Get the iterator to the first element in the reverse order. (Always constant)\n    /// @return The iterator to the first element in the reverse order.\n    const_reverse_iterator rbegin() const noexcept {\n        return const_reverse_iterator(end());\n    }\n\n    /// @brief Get the iterator to the past-the-end element in the reverse order. (Always constant)\n    /// @return The iterator to the past-the-end element in the reverse order.\n    const_reverse_iterator rend() const noexcept {\n        return const_reverse_iterator(begin());\n    }\n\n    /// @brief Get the iterator to the first element in the reverse order. (Always constant)\n    /// @return The iterator to the first element in the reverse order.\n    const_reverse_iterator crbegin() const noexcept {\n        return const_reverse_iterator(end());\n    }\n\n    /// @brief Get the iterator to the past-the-end element in the reverse order. (Always constant)\n    /// @return The iterator to the past-the-end element in the reverse order.\n    const_reverse_iterator crend() const noexcept {\n        return const_reverse_iterator(begin());\n    }\n\n    /// @brief Get the size of the referenced character sequence.\n    /// @return The size of the referenced character sequence.\n    size_type size() const noexcept {\n        return m_len;\n    }\n\n    /// @brief Get the size of the referenced character sequence.\n    /// @return The size of the referenced character sequence.\n    size_type length() const noexcept {\n        return m_len;\n    }\n\n    /// @brief Get the maximum number of the character sequence size.\n    /// @return The maximum number of the character sequence size.\n    constexpr size_type max_size() const noexcept {\n        return static_cast<size_type>(std::numeric_limits<difference_type>::max());\n    }\n\n    /// @brief Checks if the referenced character sequence is empty.\n    /// @return true if empty, false otherwise.\n    bool empty() const noexcept {\n        return m_len == 0;\n    }\n\n    /// @brief Get the element at the given position.\n    /// @param pos The position of the target element.\n    /// @return The element at the given position.\n    const_reference operator[](size_type pos) const noexcept {\n        return *(mp_str + pos);\n    }\n\n    /// @brief Get the element at the given position with bounds checks.\n    /// @warning Throws an fkyaml::out_of_range exception if the position exceeds the character sequence size.\n    /// @param pos The position of the target element.\n    /// @return The element at the given position.\n    const_reference at(size_type pos) const {\n        if FK_YAML_UNLIKELY (pos >= m_len) {\n            throw fkyaml::out_of_range(static_cast<int>(pos));\n        }\n        return *(mp_str + pos);\n    }\n\n    /// @brief Get the first element.\n    /// @return The first element.\n    const_reference front() const noexcept {\n        return *mp_str;\n    }\n\n    /// @brief Get the last element.\n    /// @return The last element.\n    const_reference back() const {\n        return *(mp_str + m_len - 1);\n    }\n\n    /// @brief Get the pointer to the raw data of referenced character sequence.\n    /// @return The pointer to the raw data of referenced character sequence.\n    const_pointer data() const noexcept {\n        return mp_str;\n    }\n\n    /// @brief Moves the beginning position by `n` elements.\n    /// @param n The number of elements by which to move the beginning position.\n    void remove_prefix(size_type n) noexcept {\n        mp_str += n;\n        m_len -= n;\n    }\n\n    /// @brief Shrinks the referenced character sequence from the last by `n` elements.\n    /// @param n The number of elements by which to shrink the sequence from the last.\n    void remove_suffix(size_type n) noexcept {\n        m_len -= n;\n    }\n\n    /// @brief Swaps data with the given basic_str_view object.\n    /// @param other A basic_str_view object to swap data with.\n    void swap(basic_str_view& other) noexcept {\n        auto tmp = *this;\n        *this = other;\n        other = tmp;\n    }\n\n    /// @brief Copys the referenced character sequence values from `pos` by `n` size.\n    /// @warning Throws an fkyaml::out_of_range exception if the given `pos` is bigger than the length.\n    /// @param p_str The pointer to a character sequence buffer for output.\n    /// @param n The number of elements to write into `p_str`.\n    /// @param pos The offset of the beginning position to copy values.\n    /// @return The number of elements to be written into `p_str`.\n    size_type copy(CharT* p_str, size_type n, size_type pos = 0) const {\n        if FK_YAML_UNLIKELY (pos > m_len) {\n            throw fkyaml::out_of_range(static_cast<int>(pos));\n        }\n        const size_type rlen = std::min(n, m_len - pos);\n        traits_type::copy(p_str, mp_str + pos, rlen);\n        return rlen;\n    }\n\n    /// @brief Constructs a sub basic_str_view object from `pos` by `n` size.\n    /// @warning Throws an fkyaml::out_of_range exception if the given `pos` is bigger than the length.\n    /// @param pos The offset of the beginning position.\n    /// @param n The number of elements to the end of a new sub basic_str_view object.\n    /// @return A newly created sub basic_str_view object.\n    basic_str_view substr(size_type pos = 0, size_type n = npos) const {\n        if FK_YAML_UNLIKELY (pos > m_len) {\n            throw fkyaml::out_of_range(static_cast<int>(pos));\n        }\n        const size_type rlen = std::min(n, m_len - pos);\n        return basic_str_view(mp_str + pos, rlen);\n    }\n\n    /// @brief Compares the referenced character sequence values with the given basic_str_view object.\n    /// @param sv The basic_str_view object to compare with.\n    /// @return The lexicographical comparison result. The values are same as std::strncmp().\n    int compare(basic_str_view sv) const noexcept {\n        const size_type rlen = std::min(m_len, sv.m_len);\n        int ret = traits_type::compare(mp_str, sv.mp_str, rlen);\n\n        if (ret == 0) {\n            using int_limits = std::numeric_limits<int>;\n            const difference_type diff =\n                m_len > sv.m_len ? m_len - sv.m_len\n                                 : static_cast<difference_type>(-1) * static_cast<difference_type>(sv.m_len - m_len);\n\n            if (diff > int_limits::max()) {\n                ret = int_limits::max();\n            }\n            else if (diff < int_limits::min()) {\n                ret = int_limits::min();\n            }\n            else {\n                ret = static_cast<int>(diff);\n            }\n        }\n\n        return ret;\n    }\n\n    /// @brief Compares the referenced character sequence values from `pos1` by `n1` characters with `sv`.\n    /// @param pos1 The offset of the beginning element.\n    /// @param n1 The length of character sequence used for comparison.\n    /// @param sv A basic_str_view object to compare with.\n    /// @return The lexicographical comparison result. The values are same as std::strncmp().\n    int compare(size_type pos1, size_type n1, basic_str_view sv) const {\n        return substr(pos1, n1).compare(sv);\n    }\n\n    /// @brief Compares the referenced character sequence value from `pos1` by `n1` characters with `sv` from `pos2` by\n    /// `n2` characters.\n    /// @param pos1 The offset of the beginning element in this character sequence.\n    /// @param n1 The length of this character sequence used for comparison.\n    /// @param sv A basic_str_view object to compare with.\n    /// @param pos2 The offset of the beginning element in `sv`.\n    /// @param n2 The length of `sv` used for comparison.\n    /// @return The lexicographical comparison result. The values are same as std::strncmp().\n    int compare(size_type pos1, size_type n1, basic_str_view sv, size_type pos2, size_type n2) const {\n        return substr(pos1, n1).compare(sv.substr(pos2, n2));\n    }\n\n    /// @brief Compares the referenced character sequence with `s` character sequence.\n    /// @param s The pointer to a character sequence to compare with.\n    /// @return The lexicographical comparison result. The values are same as std::strncmp().\n    int compare(const CharT* s) const {\n        return compare(basic_str_view(s));\n    }\n\n    /// @brief Compares the referenced character sequence from `pos1` by `n1` characters with `s` character sequence.\n    /// @param pos1 The offset of the beginning element in this character sequence.\n    /// @param n1 The length of this character sequence used fo comparison.\n    /// @param s The pointer to a character sequence to compare with.\n    /// @return The lexicographical comparison result. The values are same as std::strncmp().\n    int compare(size_type pos1, size_type n1, const CharT* s) const {\n        return substr(pos1, n1).compare(basic_str_view(s));\n    }\n\n    /// @brief Compares the referenced character sequence from `pos1` by `n1` characters with `s` character sequence by\n    /// `n2` characters.\n    /// @param pos1 The offset of the beginning element in this character sequence.\n    /// @param n1 The length of this character sequence used fo comparison.\n    /// @param s The pointer to a character sequence to compare with.\n    /// @param n2 The length of `s` used fo comparison.\n    /// @return\n    int compare(size_type pos1, size_type n1, const CharT* s, size_type n2) const {\n        return substr(pos1, n1).compare(basic_str_view(s, n2));\n    }\n\n    /// @brief Checks if this character sequence starts with `sv` characters.\n    /// @param sv The character sequence to compare with.\n    /// @return true if the character sequence starts with `sv` characters, false otherwise.\n    bool starts_with(basic_str_view sv) const {\n        return substr(0, sv.size()) == sv;\n    }\n\n    /// @brief Checks if this character sequence starts with `c` character.\n    /// @param c The character to compare with.\n    /// @return true if the character sequence starts with `c` character, false otherwise.\n    bool starts_with(CharT c) const noexcept {\n        return !empty() && traits_type::eq(front(), c);\n    }\n\n    /// @brief Checks if this character sequence starts with `s` characters.\n    /// @param s The character sequence to compare with.\n    /// @return true if the character sequence starts with `s` characters, false otherwise.\n    bool starts_with(const CharT* s) const {\n        return starts_with(basic_str_view(s));\n    }\n\n    /// @brief Checks if this character sequence ends with `sv` characters.\n    /// @param sv The character sequence to compare with.\n    /// @return true if the character sequence ends with `sv` characters, false otherwise.\n    bool ends_with(basic_str_view sv) const noexcept {\n        const size_type size = m_len;\n        const size_type sv_size = sv.size();\n        return size >= sv_size && traits_type::compare(end() - sv_size, sv.data(), sv_size) == 0;\n    }\n\n    /// @brief Checks if this character sequence ends with `c` character.\n    /// @param c The character to compare with.\n    /// @return true if the character sequence ends with `c` character, false otherwise.\n    bool ends_with(CharT c) const noexcept {\n        return !empty() && traits_type::eq(back(), c);\n    }\n\n    /// @brief Checks if this character sequence ends with `s` characters.\n    /// @param s The character sequence to compare with.\n    /// @return true if the character sequence ends with `s` characters, false otherwise.\n    bool ends_with(const CharT* s) const noexcept {\n        return ends_with(basic_str_view(s));\n    }\n\n    /// @brief Checks if this character sequence contains `sv` characters.\n    /// @param sv The character sequence to compare with.\n    /// @return true if the character sequence contains `sv` characters, false otherwise.\n    bool contains(basic_str_view sv) const noexcept {\n        return find(sv) != npos;\n    }\n\n    /// @brief Checks if this character sequence contains `c` character.\n    /// @param c The character to compare with.\n    /// @return true if the character sequence contains `c` character, false otherwise.\n    bool contains(CharT c) const noexcept {\n        return find(c) != npos;\n    }\n\n    /// @brief Checks if this character sequence contains `s` characters.\n    /// @param s The character sequence to compare with.\n    /// @return true if the character sequence contains `s` characters, false otherwise.\n    bool contains(const CharT* s) const noexcept {\n        return find(s) != npos;\n    }\n\n    /// @brief Finds the beginning position of `sv` characters in this referenced character sequence.\n    /// @param sv The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `sv` characters, `npos` otherwise.\n    size_type find(basic_str_view sv, size_type pos = 0) const noexcept {\n        return find(sv.mp_str, pos, sv.m_len);\n    }\n\n    /// @brief Finds the beginning position of `c` character in this referenced character sequence.\n    /// @param sv The character to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `c` character, `npos` otherwise.\n    size_type find(CharT c, size_type pos = 0) const noexcept {\n        size_type ret = npos;\n\n        if FK_YAML_LIKELY (pos < m_len) {\n            const size_type n = m_len - pos;\n            const CharT* p_found = traits_type::find(mp_str + pos, n, c);\n            if (p_found) {\n                ret = p_found - mp_str;\n            }\n        }\n\n        return ret;\n    }\n\n    /// @brief Finds the beginning position of `s` character sequence by `n` characters in this referenced character\n    /// sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @param n The length of `s` character sequence used for comparison.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type find(const CharT* s, size_type pos, size_type n) const noexcept {\n        if FK_YAML_UNLIKELY (n == 0) {\n            return pos <= m_len ? pos : npos;\n        }\n\n        if FK_YAML_UNLIKELY (pos >= m_len) {\n            return npos;\n        }\n\n        CharT s0 = s[0];\n        const CharT* p_first = mp_str + pos;\n        const CharT* p_last = mp_str + m_len;\n        size_type len = m_len - pos;\n\n        while (len >= n) {\n            // find the first occurence of s0\n            p_first = traits_type::find(p_first, len - n + 1, s0);\n            if (!p_first) {\n                return npos;\n            }\n\n            // compare the full strings from the first occurence of s0\n            if (traits_type::compare(p_first, s, n) == 0) {\n                return p_first - mp_str;\n            }\n\n            len = p_last - (++p_first);\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the beginning position of `s` character sequence in this referenced character sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type find(const CharT* s, size_type pos = 0) const noexcept {\n        return find(basic_str_view(s), pos);\n    }\n\n    /// @brief Retrospectively finds the beginning position of `sv` characters in this referenced character sequence.\n    /// @param sv The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `sv` characters, `npos` otherwise.\n    size_type rfind(basic_str_view sv, size_type pos = npos) const noexcept {\n        return rfind(sv.mp_str, pos, sv.m_len);\n    }\n\n    /// @brief Retrospectively finds the beginning position of `c` character in this referenced character sequence.\n    /// @param sv The character to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `c` character, `npos` otherwise.\n    size_type rfind(CharT c, size_type pos = npos) const noexcept {\n        if FK_YAML_UNLIKELY (m_len == 0) {\n            return npos;\n        }\n\n        const size_type idx = std::min(m_len - 1, pos);\n\n        for (size_type i = 0; i <= idx; i++) {\n            if (traits_type::eq(mp_str[idx - i], c)) {\n                return idx - i;\n            }\n        }\n\n        return npos;\n    }\n\n    /// @brief Retrospectively finds the beginning position of `s` character sequence by `n` characters in this\n    /// referenced character sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @param n The length of `s` character sequence used for comparison.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type rfind(const CharT* s, size_type pos, size_type n) const noexcept {\n        if FK_YAML_LIKELY (n <= m_len) {\n            pos = std::min(m_len - n, pos) + 1;\n\n            do {\n                if (traits_type::compare(mp_str + --pos, s, n) == 0) {\n                    return pos;\n                }\n            } while (pos > 0);\n        }\n\n        return npos;\n    }\n\n    /// @brief Retrospectively finds the beginning position of `s` character sequence in this referenced character\n    /// sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type rfind(const CharT* s, size_type pos = npos) const noexcept {\n        return rfind(basic_str_view(s), pos);\n    }\n\n    /// @brief Finds the first occurence of `sv` character sequence in this referenced character sequence.\n    /// @param sv The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `sv` characters, `npos` otherwise.\n    size_type find_first_of(basic_str_view sv, size_type pos = 0) const noexcept {\n        return find_first_of(sv.mp_str, pos, sv.m_len);\n    }\n\n    /// @brief Finds the first occurence of `c` character in this referenced character sequence.\n    /// @param c The character to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `c` character, `npos` otherwise.\n    size_type find_first_of(CharT c, size_type pos = 0) const noexcept {\n        return find(c, pos);\n    }\n\n    /// @brief Finds the first occurence of `s` character sequence by `n` characters in this referenced character\n    /// sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @param n The length of `s` character sequence used for comparison.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type find_first_of(const CharT* s, size_type pos, size_type n) const noexcept {\n        if FK_YAML_UNLIKELY (n == 0) {\n            return npos;\n        }\n\n        for (size_type idx = pos; idx < m_len; ++idx) {\n            const CharT* p_found = traits_type::find(s, n, mp_str[idx]);\n            if (p_found) {\n                return idx;\n            }\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the first occurence of `s` character sequence in this referenced character sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type find_first_of(const CharT* s, size_type pos = 0) const noexcept {\n        return find_first_of(basic_str_view(s), pos);\n    }\n\n    /// @brief Finds the last occurence of `sv` character sequence in this referenced character sequence.\n    /// @param sv The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `sv` characters, `npos` otherwise.\n    size_type find_last_of(basic_str_view sv, size_type pos = npos) const noexcept {\n        return find_last_of(sv.mp_str, pos, sv.m_len);\n    }\n\n    /// @brief Finds the last occurence of `c` character in this referenced character sequence.\n    /// @param c The character to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `c` character, `npos` otherwise.\n    size_type find_last_of(CharT c, size_type pos = npos) const noexcept {\n        return rfind(c, pos);\n    }\n\n    /// @brief Finds the last occurence of `s` character sequence by `n` characters in this referenced character\n    /// sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @param n The length of `s` character sequence used for comparison.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type find_last_of(const CharT* s, size_type pos, size_type n) const noexcept {\n        if FK_YAML_LIKELY (n <= m_len) {\n            pos = std::min(m_len - n - 1, pos);\n\n            do {\n                const CharT* p_found = traits_type::find(s, n, mp_str[pos]);\n                if (p_found) {\n                    return pos;\n                }\n            } while (pos-- != 0);\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the last occurence of `s` character sequence in this referenced character sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of `s` characters, `npos` otherwise.\n    size_type find_last_of(const CharT* s, size_type pos = npos) const noexcept {\n        return find_last_of(basic_str_view(s), pos);\n    }\n\n    /// @brief Finds the first absence of `sv` character sequence in this referenced character sequence.\n    /// @param sv The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of non `sv` characters, `npos` otherwise.\n    size_type find_first_not_of(basic_str_view sv, size_type pos = 0) const noexcept {\n        return find_first_not_of(sv.mp_str, pos, sv.m_len);\n    }\n\n    /// @brief Finds the first absence of `c` character in this referenced character sequence.\n    /// @param c The character to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of non `c` character, `npos` otherwise.\n    size_type find_first_not_of(CharT c, size_type pos = 0) const noexcept {\n        for (; pos < m_len; ++pos) {\n            if (!traits_type::eq(mp_str[pos], c)) {\n                return pos;\n            }\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the first absence of `s` character sequence by `n` characters in this referenced character\n    /// sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @param n The length of `s` character sequence used for comparison.\n    /// @return The beginning position of non `s` characters, `npos` otherwise.\n    size_type find_first_not_of(const CharT* s, size_type pos, size_type n) const noexcept {\n        for (; pos < m_len; ++pos) {\n            const CharT* p_found = traits_type::find(s, n, mp_str[pos]);\n            if (!p_found) {\n                return pos;\n            }\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the first absence of `s` character sequence in this referenced character sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of non `s` characters, `npos` otherwise.\n    size_type find_first_not_of(const CharT* s, size_type pos = 0) const noexcept {\n        return find_first_not_of(basic_str_view(s), pos);\n    }\n\n    /// @brief Finds the last absence of `sv` character sequence in this referenced character sequence.\n    /// @param sv The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of non `sv` characters, `npos` otherwise.\n    size_type find_last_not_of(basic_str_view sv, size_type pos = npos) const noexcept {\n        return find_last_not_of(sv.mp_str, pos, sv.m_len);\n    }\n\n    /// @brief Finds the last absence of `c` character in this referenced character sequence.\n    /// @param c The character to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of non `c` character, `npos` otherwise.\n    size_type find_last_not_of(CharT c, size_type pos = npos) const noexcept {\n        if FK_YAML_LIKELY (m_len > 0) {\n            pos = std::min(m_len, pos);\n\n            do {\n                if (!traits_type::eq(mp_str[--pos], c)) {\n                    return pos;\n                }\n            } while (pos > 0);\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the last absence of `s` character sequence by `n` characters in this referenced character\n    /// sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @param n The length of `s` character sequence used for comparison.\n    /// @return The beginning position of non `s` characters, `npos` otherwise.\n    size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const noexcept {\n        if FK_YAML_UNLIKELY (n <= m_len) {\n            pos = std::min(m_len - n, pos) + 1;\n\n            do {\n                const CharT* p_found = traits_type::find(s, n, mp_str[--pos]);\n                if (!p_found) {\n                    return pos;\n                }\n            } while (pos > 0);\n        }\n\n        return npos;\n    }\n\n    /// @brief Finds the last absence of `s` character sequence in this referenced character sequence.\n    /// @param s The character sequence to compare with.\n    /// @param pos The offset of the search beginning position in this referenced character sequence.\n    /// @return The beginning position of non `s` characters, `npos` otherwise.\n    size_type find_last_not_of(const CharT* s, size_type pos = npos) const noexcept {\n        return find_last_not_of(basic_str_view(s), pos);\n    }\n\nprivate:\n    size_type m_len {0};\n    const value_type* mp_str {nullptr};\n};\n\n// Prior to C++17, a static constexpr class member needs an out-of-class definition.\n#ifndef FK_YAML_HAS_CXX_17\n\ntemplate <typename CharT, typename Traits>\nconstexpr typename basic_str_view<CharT, Traits>::size_type basic_str_view<CharT, Traits>::npos;\n\n#endif // !defined(FK_YAML_HAS_CXX_17)\n\n/// @brief An equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if the two objects are the same, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator==(basic_str_view<CharT, Traits> lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    // Comparing the lengths first will omit unnecessary value comparison in compare().\n    return lhs.size() == rhs.size() && lhs.compare(rhs) == 0;\n}\n\n/// @brief An equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_string object to compare with.\n/// @return true if the two objects are the same, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator==(basic_str_view<CharT, Traits> lhs, const std::basic_string<CharT, Traits>& rhs) noexcept {\n    return lhs == basic_str_view<CharT, Traits>(rhs);\n}\n\n/// @brief An equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_string object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if the two objects are the same, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator==(const std::basic_string<CharT, Traits>& lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return basic_str_view<CharT, Traits>(lhs) == rhs;\n}\n\n/// @brief An equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @tparam N The length of the character array.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A character array to compare with.\n/// @return true if the two objects are the same, false otherwise.\ntemplate <typename CharT, typename Traits, std::size_t N>\ninline bool operator==(basic_str_view<CharT, Traits> lhs, const CharT (&rhs)[N]) noexcept {\n    // assume `rhs` is null terminated\n    return lhs == basic_str_view<CharT, Traits>(rhs);\n}\n\n/// @brief An equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @tparam N The length of the character array.\n/// @param rhs A character array for comparison.\n/// @param lhs A basic_str_view object to compare with.\n/// @return true if the two objects are the same, false otherwise.\ntemplate <typename CharT, typename Traits, std::size_t N>\ninline bool operator==(const CharT (&lhs)[N], basic_str_view<CharT, Traits> rhs) noexcept {\n    // assume `lhs` is null terminated\n    return basic_str_view<CharT, Traits>(lhs) == rhs;\n}\n\n/// @brief An not-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if the two objects are different, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator!=(basic_str_view<CharT, Traits> lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return !(lhs == rhs);\n}\n\n/// @brief An not-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_string object to compare with.\n/// @return true if the two objects are different, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator!=(basic_str_view<CharT, Traits> lhs, const std::basic_string<CharT, Traits>& rhs) noexcept {\n    return !(lhs == basic_str_view<CharT, Traits>(rhs));\n}\n\n/// @brief An not-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_string object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if the two objects are different, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator!=(const std::basic_string<CharT, Traits>& lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return !(basic_str_view<CharT, Traits>(lhs) == rhs);\n}\n\n/// @brief An not-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @tparam N The length of the character array.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A character array to compare with.\n/// @return true if the two objects are different, false otherwise.\ntemplate <typename CharT, typename Traits, std::size_t N>\ninline bool operator!=(basic_str_view<CharT, Traits> lhs, const CharT (&rhs)[N]) noexcept {\n    // assume `rhs` is null terminated.\n    return !(lhs == basic_str_view<CharT, Traits>(rhs, N - 1));\n}\n\n/// @brief An not-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @tparam N The length of the character array.\n/// @param rhs A character array for comparison.\n/// @param lhs A basic_str_view object to compare with.\n/// @return true if the two objects are different, false otherwise.\ntemplate <typename CharT, typename Traits, std::size_t N>\ninline bool operator!=(const CharT (&lhs)[N], basic_str_view<CharT, Traits> rhs) noexcept {\n    // assume `lhs` is null terminate\n    return !(basic_str_view<CharT, Traits>(lhs, N - 1) == rhs);\n}\n\n/// @brief An less-than operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if `lhs` is less than `rhs`, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator<(basic_str_view<CharT, Traits> lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return lhs.compare(rhs) < 0;\n}\n\n/// @brief An less-than-or-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if `lhs` is less than or equal to `rhs`, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator<=(basic_str_view<CharT, Traits> lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return lhs.compare(rhs) <= 0;\n}\n\n/// @brief An greater-than operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if `lhs` is greater than `rhs`, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator>(basic_str_view<CharT, Traits> lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return lhs.compare(rhs) > 0;\n}\n\n/// @brief An greater-than-or-equal-to operator of the basic_str_view class.\n/// @tparam CharT Character type\n/// @tparam Traits Character traits type.\n/// @param lhs A basic_str_view object for comparison.\n/// @param rhs A basic_str_view object to compare with.\n/// @return true if `lhs` is greater than or equal to `rhs`, false otherwise.\ntemplate <typename CharT, typename Traits>\ninline bool operator>=(basic_str_view<CharT, Traits> lhs, basic_str_view<CharT, Traits> rhs) noexcept {\n    return lhs.compare(rhs) >= 0;\n}\n\n/// @brief Insertion operator of the basic_str_view class.\n/// @tparam CharT Character type.\n/// @tparam Traits Character traits type.\n/// @param os An output stream object.\n/// @param sv A basic_str_view object.\n/// @return Reference to the output stream object `os`.\ntemplate <typename CharT, typename Traits>\ninline std::basic_ostream<CharT, Traits>& operator<<(\n    std::basic_ostream<CharT, Traits>& os, basic_str_view<CharT, Traits> sv) {\n    return os.write(sv.data(), static_cast<std::streamsize>(sv.size()));\n}\n\n/// @brief view into `char` sequence.\nusing str_view = basic_str_view<char>;\n\n#if FK_YAML_HAS_CHAR8_T\n/// @brief view into `char8_t` sequence.\nusing u8str_view = basic_str_view<char8_t>;\n#endif\n\n/// @brief view into `char16_t` sequence.\nusing u16str_view = basic_str_view<char16_t>;\n\n/// @brief view into `char32_t` sequence.\nusing u32str_view = basic_str_view<char32_t>;\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_STR_VIEW_HPP */\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A position tracker of the target buffer.\nclass position_tracker {\npublic:\n    void set_target_buffer(str_view buffer) noexcept {\n        m_begin = m_last = buffer.begin();\n        m_end = buffer.end();\n    }\n\n    /// @brief Update the set of the current position information.\n    /// @note This function doesn't support cases where cur_pos has moved backward from the last call.\n    /// @param cur_pos The iterator to the current element of the buffer.\n    void update_position(const char* p_current) {\n        const auto diff = static_cast<uint32_t>(p_current - m_last);\n        if (diff == 0) {\n            return;\n        }\n\n        m_cur_pos += diff;\n        const uint32_t prev_lines_read = m_lines_read;\n        m_lines_read += static_cast<uint32_t>(std::count(m_last, p_current, '\\n'));\n        m_last = p_current;\n\n        if (prev_lines_read == m_lines_read) {\n            m_cur_pos_in_line += diff;\n            return;\n        }\n\n        uint32_t count = 0;\n        const char* p_begin = m_begin;\n        while (--p_current != p_begin) {\n            if (*p_current == '\\n') {\n                break;\n            }\n            count++;\n        }\n        m_cur_pos_in_line = count;\n    }\n\n    uint32_t get_cur_pos() const noexcept {\n        return m_cur_pos;\n    }\n\n    /// @brief Get the current position in the current line.\n    /// @return uint32_t The current position in the current line.\n    uint32_t get_cur_pos_in_line() const noexcept {\n        return m_cur_pos_in_line;\n    }\n\n    /// @brief Get the number of lines which have already been read.\n    /// @return uint32_t The number of lines which have already been read.\n    uint32_t get_lines_read() const noexcept {\n        return m_lines_read;\n    }\n\nprivate:\n    /// The iterator to the beginning element in the target buffer.\n    const char* m_begin {};\n    /// The iterator to the past-the-end element in the target buffer.\n    const char* m_end {};\n    /// The iterator to the last updated element in the target buffer.\n    const char* m_last {};\n    /// The current position from the beginning of an input buffer.\n    uint32_t m_cur_pos {0};\n    /// The current position in the current line.\n    uint32_t m_cur_pos_in_line {0};\n    /// The number of lines which have already been read.\n    uint32_t m_lines_read {0};\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_POSITION_TRACKER_HPP */\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/str_view.hpp>\n\n// #include <fkYAML/detail/types/lexical_token_t.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_TYPES_LEXICAL_TOKEN_T_HPP\n#define FK_YAML_DETAIL_TYPES_LEXICAL_TOKEN_T_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Definition of lexical token types.\nenum class lexical_token_t : std::uint8_t {\n    END_OF_BUFFER,         //!< the end of input buffer.\n    EXPLICIT_KEY_PREFIX,   //!< the character for explicit mapping key prefix `?`.\n    KEY_SEPARATOR,         //!< the key separator `:`\n    VALUE_SEPARATOR,       //!< the value separator `,`\n    ANCHOR_PREFIX,         //!< the character for anchor prefix `&`\n    ALIAS_PREFIX,          //!< the character for alias prefix `*`\n    YAML_VER_DIRECTIVE,    //!< a YAML version directive found. use get_yaml_version() to get a value.\n    TAG_DIRECTIVE,         //!< a TAG directive found. use GetTagInfo() to get the tag information.\n    TAG_PREFIX,            //!< the character for tag prefix `!`\n    INVALID_DIRECTIVE,     //!< an invalid directive found. do not try to get the value.\n    SEQUENCE_BLOCK_PREFIX, //!< the character for sequence block prefix `- `\n    SEQUENCE_FLOW_BEGIN,   //!< the character for sequence flow begin `[`\n    SEQUENCE_FLOW_END,     //!< the character for sequence flow end `]`\n    MAPPING_FLOW_BEGIN,    //!< the character for mapping begin `{`\n    MAPPING_FLOW_END,      //!< the character for mapping end `}`\n    PLAIN_SCALAR,          //!< plain (unquoted) scalars\n    SINGLE_QUOTED_SCALAR,  //!< single-quoted scalars\n    DOUBLE_QUOTED_SCALAR,  //!< double-quoted scalars\n    BLOCK_LITERAL_SCALAR,  //!< block literal style scalars\n    BLOCK_FOLDED_SCALAR,   //!< block folded style scalars\n    END_OF_DIRECTIVES,     //!< the end of declaration of directives specified by `---`.\n    END_OF_DOCUMENT,       //!< the end of a YAML document specified by `...`.\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_TYPES_LEXICAL_TOKEN_T_HPP */\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Lexical token information\nstruct lexical_token {\n    lexical_token() = default;\n\n    lexical_token(lexical_token_t t, str_view s) noexcept\n        : type(t),\n          str(s) {\n    }\n\n    lexical_token(lexical_token_t t) noexcept\n        : type(t) {\n    }\n\n    lexical_token(const lexical_token&) = default;\n    lexical_token& operator=(const lexical_token&) = default;\n    lexical_token(lexical_token&&) = default;\n    lexical_token& operator=(lexical_token&&) = default;\n    ~lexical_token() = default;\n\n    /// Lexical token type.\n    lexical_token_t type {lexical_token_t::END_OF_BUFFER};\n    /// Lexical token contents.\n    str_view str;\n};\n\n/// @brief A class which lexically analyzes YAML formatted inputs.\nclass lexical_analyzer {\n    // whether the current context is flow(1) or block(0)\n    static constexpr uint32_t flow_context_bit = 1u << 0u;\n    // whether the current document part is directive(1) or content(0)\n    static constexpr uint32_t document_directive_bit = 1u << 1u;\n\npublic:\n    /// @brief Construct a new lexical_analyzer object.\n    /// @param input_buffer An input buffer.\n    explicit lexical_analyzer(str_view input_buffer) noexcept\n        : m_begin_itr(input_buffer.begin()),\n          m_cur_itr(input_buffer.begin()),\n          m_end_itr(input_buffer.end()) {\n        m_pos_tracker.set_target_buffer(input_buffer);\n    }\n\n    /// @brief Get the next lexical token by scanning the left of the input buffer.\n    /// @return lexical_token The next lexical token.\n    lexical_token get_next_token() {\n        skip_white_spaces_and_newline_codes();\n\n        m_token_begin_itr = m_cur_itr;\n        m_pos_tracker.update_position(m_cur_itr);\n        m_last_token_begin_pos = m_pos_tracker.get_cur_pos_in_line();\n        m_last_token_begin_line = m_pos_tracker.get_lines_read();\n\n        if (m_cur_itr == m_end_itr) {\n            return {lexical_token_t::END_OF_BUFFER};\n        }\n\n        switch (*m_cur_itr) {\n        case '?':\n            if (++m_cur_itr == m_end_itr) {\n                return {lexical_token_t::PLAIN_SCALAR, {m_token_begin_itr, 1}};\n            }\n\n            if (*m_cur_itr == ' ') {\n                return {lexical_token_t::EXPLICIT_KEY_PREFIX};\n            }\n            break;\n        case ':': // key separator\n            if (++m_cur_itr == m_end_itr) {\n                return {lexical_token_t::KEY_SEPARATOR};\n            }\n\n            switch (*m_cur_itr) {\n            case ' ':\n            case '\\t':\n            case '\\n':\n                return {lexical_token_t::KEY_SEPARATOR};\n            default:\n                if ((m_state & flow_context_bit) == 0) {\n                    // in a block context\n                    break;\n                }\n\n                switch (*m_cur_itr) {\n                case ',':\n                case '[':\n                case ']':\n                case '{':\n                case '}':\n                    // Flow indicators are not \"safe\" to be followed in a flow context.\n                    // See https://yaml.org/spec/1.2.2/#733-plain-style for more details.\n                    return {lexical_token_t::KEY_SEPARATOR};\n                default:\n                    // At least '{' or '[' must precedes this token.\n                    FK_YAML_ASSERT(m_token_begin_itr != m_begin_itr);\n\n                    // if a key inside a flow mapping is JSON-like (surrounded by indicators, see below), YAML allows\n                    // the following value to be specified adjacent to the \":\" mapping value indicator.\n                    // ```yaml\n                    // # the following flow mapping entries are all valid.\n                    // {\n                    //   \"foo\":true,\n                    //   'bar':false,          # 'bar' is actually not JSON but allowed in YAML\n                    //                         # since its surrounded by the single quotes.\n                    //   {[1,2,3]:null}:\"baz\"\n                    // }\n                    // ```\n                    switch (*(m_token_begin_itr - 1)) {\n                    case '\\'':\n                    case '\\\"':\n                    case ']':\n                    case '}':\n                        return {lexical_token_t::KEY_SEPARATOR};\n                    default:\n                        break;\n                    }\n                    break;\n                }\n                break;\n            }\n            break;\n        case ',': // value separator\n            ++m_cur_itr;\n            return {lexical_token_t::VALUE_SEPARATOR};\n        case '&': // anchor prefix\n            return {lexical_token_t::ANCHOR_PREFIX, extract_anchor_name()};\n        case '*': // alias prefix\n            return {lexical_token_t::ALIAS_PREFIX, extract_anchor_name()};\n        case '!': // tag prefix\n            return {lexical_token_t::TAG_PREFIX, extract_tag_name()};\n        case '#': // comment prefix\n            scan_comment();\n            return get_next_token();\n        case '%': // directive prefix\n            if (m_state & document_directive_bit) {\n                return {scan_directive()};\n            }\n            // The '%' character can be safely used as the first character in document contents.\n            // See https://yaml.org/spec/1.2.2/#912-document-markers for more details.\n            break;\n        case '-': {\n            switch (*(m_cur_itr + 1)) {\n            case ' ':\n            case '\\t':\n            case '\\n':\n                // Move a cursor to the beginning of the next token.\n                m_cur_itr += 2;\n                return {lexical_token_t::SEQUENCE_BLOCK_PREFIX};\n            default:\n                break;\n            }\n\n            if (m_pos_tracker.get_cur_pos_in_line() == 0) {\n                if ((m_end_itr - m_cur_itr) > 2) {\n                    const bool is_dir_end = std::equal(m_token_begin_itr, m_cur_itr + 3, \"---\");\n                    if (is_dir_end) {\n                        m_cur_itr += 3;\n                        return {lexical_token_t::END_OF_DIRECTIVES};\n                    }\n                }\n            }\n\n            break;\n        }\n        case '[': // sequence flow begin\n            ++m_cur_itr;\n            return {lexical_token_t::SEQUENCE_FLOW_BEGIN};\n        case ']': // sequence flow end\n            ++m_cur_itr;\n            return {lexical_token_t::SEQUENCE_FLOW_END};\n        case '{': // mapping flow begin\n            ++m_cur_itr;\n            return {lexical_token_t::MAPPING_FLOW_BEGIN};\n        case '}': // mapping flow end\n            ++m_cur_itr;\n            return {lexical_token_t::MAPPING_FLOW_END};\n        case '@':\n            emit_error(\"Any token cannot start with at(@). It is a reserved indicator for YAML.\");\n        case '`':\n            emit_error(\"Any token cannot start with grave accent(`). It is a reserved indicator for YAML.\");\n        case '\\\"':\n            ++m_token_begin_itr;\n            return {lexical_token_t::DOUBLE_QUOTED_SCALAR, determine_double_quoted_scalar_range()};\n        case '\\'':\n            ++m_token_begin_itr;\n            return {lexical_token_t::SINGLE_QUOTED_SCALAR, determine_single_quoted_scalar_range()};\n        case '.': {\n            if (m_pos_tracker.get_cur_pos_in_line() == 0) {\n                const auto rem_size = m_end_itr - m_cur_itr;\n                if FK_YAML_LIKELY (rem_size > 2) {\n                    const bool is_doc_end = std::equal(m_cur_itr, m_cur_itr + 3, \"...\");\n                    if (is_doc_end) {\n                        if (rem_size > 3) {\n                            switch (*(m_cur_itr + 3)) {\n                            case ' ':\n                            case '\\t':\n                            case '\\n':\n                                m_cur_itr += 4;\n                                break;\n                            default:\n                                // See https://yaml.org/spec/1.2.2/#912-document-markers for more details.\n                                emit_error(\"The document end marker \\\"...\\\" must not be followed by non-ws char.\");\n                            }\n                        }\n                        else {\n                            m_cur_itr += 3;\n                        }\n                        return {lexical_token_t::END_OF_DOCUMENT};\n                    }\n                }\n            }\n            break;\n        }\n        case '|':\n        case '>': {\n            const str_view sv {m_token_begin_itr, m_end_itr};\n            const std::size_t header_end_pos = sv.find('\\n');\n            FK_YAML_ASSERT(header_end_pos != str_view::npos);\n            const uint32_t base_indent = get_current_indent_level(&sv[header_end_pos]);\n\n            const lexical_token_t type = *m_token_begin_itr == '|' ? lexical_token_t::BLOCK_LITERAL_SCALAR\n                                                                   : lexical_token_t::BLOCK_FOLDED_SCALAR;\n            const str_view header_line = sv.substr(1, header_end_pos - 1);\n            m_block_scalar_header = convert_to_block_scalar_header(header_line);\n\n            m_token_begin_itr = sv.begin() + (header_end_pos + 1);\n\n            return {\n                type,\n                determine_block_scalar_content_range(\n                    base_indent, m_block_scalar_header.indent, m_block_scalar_header.indent)};\n        }\n        default:\n            break;\n        }\n\n        return {lexical_token_t::PLAIN_SCALAR, determine_plain_scalar_range()};\n    }\n\n    /// @brief Get the beginning position of a last token.\n    /// @return uint32_t The beginning position of a last token.\n    uint32_t get_last_token_begin_pos() const noexcept {\n        return m_last_token_begin_pos;\n    }\n\n    /// @brief Get the number of lines already processed.\n    /// @return uint32_t The number of lines already processed.\n    uint32_t get_lines_processed() const noexcept {\n        return m_last_token_begin_line;\n    }\n\n    /// @brief Get the YAML version specification.\n    /// @return str_view A YAML version specification.\n    str_view get_yaml_version() const noexcept {\n        return m_yaml_version;\n    }\n\n    /// @brief Get the YAML tag handle defined in the TAG directive.\n    /// @return str_view A tag handle.\n    str_view get_tag_handle() const noexcept {\n        return m_tag_handle;\n    }\n\n    /// @brief Get the YAML tag prefix defined in the TAG directive.\n    /// @return str_view A tag prefix.\n    str_view get_tag_prefix() const noexcept {\n        return m_tag_prefix;\n    }\n\n    /// @brief Get block scalar header information.\n    /// @return block_scalar_header Block scalar header information.\n    block_scalar_header get_block_scalar_header() const noexcept {\n        return m_block_scalar_header;\n    }\n\n    /// @brief Toggles the context state between flow and block.\n    /// @param is_flow_context true: flow context, false: block context\n    void set_context_state(bool is_flow_context) noexcept {\n        m_state &= ~flow_context_bit;\n        if (is_flow_context) {\n            m_state |= flow_context_bit;\n        }\n    }\n\n    /// @brief Toggles the document state between directive and content.\n    /// @param is_directive true: directive, false: content\n    void set_document_state(bool is_directive) noexcept {\n        m_state &= ~document_directive_bit;\n        if (is_directive) {\n            m_state |= document_directive_bit;\n        }\n    }\n\nprivate:\n    uint32_t get_current_indent_level(const char* p_line_end) {\n        // get the beginning position of the current line.\n        std::size_t line_begin_pos = str_view(m_begin_itr, p_line_end - 1).find_last_of('\\n');\n        if (line_begin_pos == str_view::npos) {\n            line_begin_pos = 0;\n        }\n        else {\n            ++line_begin_pos;\n        }\n        const char* p_line_begin = m_begin_itr + line_begin_pos;\n        const char* cur_itr = p_line_begin;\n\n        // get the indentation of the current line.\n        uint32_t indent = 0;\n        bool indent_found = false;\n        // 0: none, 1: block seq item, 2: explicit map key, 3: explicit map value\n        uint32_t context = 0;\n        while (cur_itr != p_line_end && !indent_found) {\n            switch (*cur_itr) {\n            case ' ':\n                ++indent;\n                ++cur_itr;\n                break;\n            case '-':\n                switch (*(cur_itr + 1)) {\n                case ' ':\n                case '\\t':\n                    indent += 2;\n                    cur_itr += 2;\n                    context = 1;\n                    break;\n                default:\n                    indent_found = true;\n                    break;\n                }\n                break;\n            case '?':\n                if (*(cur_itr + 1) == ' ') {\n                    indent += 2;\n                    cur_itr += 2;\n                    context = 2;\n                    break;\n                }\n\n                indent_found = true;\n                break;\n            case ':':\n                switch (*(cur_itr + 1)) {\n                case ' ':\n                case '\\t':\n                    indent += 2;\n                    cur_itr += 2;\n                    context = 3;\n                    break;\n                default:\n                    indent_found = true;\n                    break;\n                }\n                break;\n            default:\n                indent_found = true;\n                break;\n            }\n        }\n\n        // If \"- \", \"? \" and/or \": \" occur in the first line of this plain scalar content.\n        if (context > 0) {\n            // Check if the first line contains the key separator \": \".\n            // If so, the indent value remains the current one.\n            // Otherwise, the indent value is changed based on the last ocurrence of the above 3.\n            // In any case, multiline plain scalar content must be indented more than the indent value.\n            const str_view line_content_part {p_line_begin + indent, p_line_end};\n            std::size_t key_sep_pos = line_content_part.find(\": \");\n            if (key_sep_pos == str_view::npos) {\n                key_sep_pos = line_content_part.find(\":\\t\");\n            }\n\n            if (key_sep_pos == str_view::npos) {\n                constexpr char targets[] = \"-?:\";\n                FK_YAML_ASSERT(context - 1 < sizeof(targets));\n                // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)\n                const char target_char = targets[context - 1];\n\n                // Find the position of the last ocuurence of \"- \", \"? \" or \": \".\n                const str_view line_indent_part {p_line_begin, indent};\n                const std::size_t block_seq_item_begin_pos = line_indent_part.find_last_of(target_char);\n                FK_YAML_ASSERT(block_seq_item_begin_pos != str_view::npos);\n                indent = static_cast<uint32_t>(block_seq_item_begin_pos);\n            }\n        }\n\n        return indent;\n    }\n\n    /// @brief Skip until a newline code or a null character is found.\n    void scan_comment() {\n        FK_YAML_ASSERT(*m_cur_itr == '#');\n        if FK_YAML_LIKELY (m_cur_itr != m_begin_itr) {\n            switch (*(m_cur_itr - 1)) {\n            case ' ':\n            case '\\t':\n            case '\\n':\n                break;\n            default:\n                emit_error(\"Comment must not begin right after non-break characters\");\n            }\n        }\n        skip_until_line_end();\n    }\n\n    /// @brief Scan directives starting with the prefix '%'\n    /// @note Currently, only %YAML directive is supported. If not, returns invalid or throws an exception.\n    /// @return lexical_token_t The lexical token type for directives.\n    lexical_token_t scan_directive() {\n        FK_YAML_ASSERT(*m_cur_itr == '%');\n\n        m_token_begin_itr = ++m_cur_itr;\n\n        bool ends_loop = false;\n        while (!ends_loop && m_cur_itr != m_end_itr) {\n            switch (*m_cur_itr) {\n            case ' ':\n            case '\\t':\n                ends_loop = true;\n                break;\n            case '\\n':\n                skip_until_line_end();\n                return lexical_token_t::INVALID_DIRECTIVE;\n            default:\n                ++m_cur_itr;\n                break;\n            }\n        }\n\n        const str_view dir_name(m_token_begin_itr, m_cur_itr);\n\n        if (dir_name == \"TAG\") {\n            if FK_YAML_UNLIKELY (!ends_loop) {\n                emit_error(\"There must be at least one white space between \\\"%TAG\\\" and tag info.\");\n            }\n            skip_white_spaces();\n            return scan_tag_directive();\n        }\n\n        if (dir_name == \"YAML\") {\n            if FK_YAML_UNLIKELY (!ends_loop) {\n                emit_error(\"There must be at least one white space between \\\"%YAML\\\" and version.\");\n            }\n            skip_white_spaces();\n            return scan_yaml_version_directive();\n        }\n\n        skip_until_line_end();\n        return lexical_token_t::INVALID_DIRECTIVE;\n    }\n\n    /// @brief Scan a YAML tag directive.\n    /// @return lexical_token_t The lexical token type for YAML tag directives.\n    lexical_token_t scan_tag_directive() {\n        m_token_begin_itr = m_cur_itr;\n\n        //\n        // extract a tag handle\n        //\n\n        if FK_YAML_UNLIKELY (*m_cur_itr != '!') {\n            emit_error(\"Tag handle must start with \\'!\\'.\");\n        }\n\n        if FK_YAML_UNLIKELY (++m_cur_itr == m_end_itr) {\n            emit_error(\"invalid TAG directive is found.\");\n        }\n\n        switch (*m_cur_itr) {\n        case ' ':\n        case '\\t':\n            // primary handle (!)\n            break;\n        case '!':\n            if FK_YAML_UNLIKELY (++m_cur_itr == m_end_itr) {\n                emit_error(\"invalid TAG directive is found.\");\n            }\n            if FK_YAML_UNLIKELY (*m_cur_itr != ' ' && *m_cur_itr != '\\t') {\n                emit_error(\"invalid tag handle is found.\");\n            }\n            break;\n        default: {\n            bool ends_loop = false;\n            do {\n                switch (*m_cur_itr) {\n                case ' ':\n                case '\\t':\n                    emit_error(\"invalid tag handle is found.\");\n                case '!': {\n                    if (m_cur_itr + 1 == m_end_itr) {\n                        ends_loop = true;\n                        break;\n                    }\n                    const char next = *(m_cur_itr + 1);\n                    if FK_YAML_UNLIKELY (next != ' ' && next != '\\t') {\n                        emit_error(\"invalid tag handle is found.\");\n                    }\n                    ends_loop = true;\n                    break;\n                }\n                case '-':\n                    break;\n                default:\n                    if FK_YAML_UNLIKELY (!isalnum(*m_cur_itr)) {\n                        // See https://yaml.org/spec/1.2.2/#rule-c-named-tag-handle for more details.\n                        emit_error(\"named handle can contain only numbers(0-9), alphabets(A-Z,a-z) and hyphens(-).\");\n                    }\n                    break;\n                }\n\n                if FK_YAML_UNLIKELY (++m_cur_itr == m_end_itr) {\n                    emit_error(\"invalid TAG directive is found.\");\n                }\n            } while (!ends_loop);\n            break;\n        }\n        }\n\n        m_tag_handle = str_view {m_token_begin_itr, m_cur_itr};\n\n        skip_white_spaces();\n\n        //\n        // extract a tag prefix.\n        //\n\n        m_token_begin_itr = m_cur_itr;\n        const char* p_tag_prefix_begin = m_cur_itr;\n        switch (*m_cur_itr) {\n        // a tag prefix must not start with flow indicators to avoid ambiguity.\n        // See https://yaml.org/spec/1.2.2/#rule-ns-global-tag-prefix for more details.\n        case ',':\n        case '[':\n        case ']':\n        case '{':\n        case '}':\n            emit_error(\"tag prefix must not start with flow indicators (\\',\\', [], {}).\");\n        default:\n            break;\n        }\n\n        // extract the rest of a tag prefix.\n        bool ends_loop = false;\n        do {\n            switch (*m_cur_itr) {\n            case ' ':\n            case '\\t':\n            case '\\n':\n                ends_loop = true;\n                break;\n            default:\n                break;\n            }\n        } while (!ends_loop && ++m_cur_itr != m_end_itr);\n\n        const bool is_valid = uri_encoding::validate(p_tag_prefix_begin, m_cur_itr);\n        if FK_YAML_UNLIKELY (!is_valid) {\n            emit_error(\"invalid URI character is found in a tag prefix.\");\n        }\n\n        m_tag_prefix = str_view {p_tag_prefix_begin, m_cur_itr};\n\n        return lexical_token_t::TAG_DIRECTIVE;\n    }\n\n    /// @brief Scan a YAML version directive.\n    /// @note Only 1.1 and 1.2 are supported. If not, throws an exception.\n    /// @return lexical_token_t The lexical token type for YAML version directives.\n    lexical_token_t scan_yaml_version_directive() {\n        m_token_begin_itr = m_cur_itr;\n\n        bool ends_loop = false;\n        while (!ends_loop && m_cur_itr != m_end_itr) {\n            switch (*m_cur_itr) {\n            case ' ':\n            case '\\t':\n            case '\\n':\n                ends_loop = true;\n                break;\n            default:\n                ++m_cur_itr;\n                break;\n            }\n        }\n\n        m_yaml_version = str_view {m_token_begin_itr, m_cur_itr};\n\n        if FK_YAML_UNLIKELY (m_yaml_version.compare(\"1.1\") != 0 && m_yaml_version.compare(\"1.2\") != 0) {\n            emit_error(\"Only 1.1 and 1.2 can be specified as the YAML version.\");\n        }\n\n        return lexical_token_t::YAML_VER_DIRECTIVE;\n    }\n\n    /// @brief Extracts an anchor name from the input.\n    /// @return The extracted anchor name.\n    str_view extract_anchor_name() {\n        FK_YAML_ASSERT(*m_cur_itr == '&' || *m_cur_itr == '*');\n\n        m_token_begin_itr = ++m_cur_itr;\n\n        bool ends_loop = false;\n        for (; m_cur_itr != m_end_itr; ++m_cur_itr) {\n            switch (*m_cur_itr) {\n            // anchor name must not contain white spaces, newline codes and flow indicators.\n            // See https://yaml.org/spec/1.2.2/#692-node-anchors for more details.\n            case ' ':\n            case '\\t':\n            case '\\n':\n            case '{':\n            case '}':\n            case '[':\n            case ']':\n            case ',':\n                ends_loop = true;\n                break;\n            default:\n                break;\n            }\n\n            if (ends_loop) {\n                break;\n            }\n        }\n\n        if FK_YAML_UNLIKELY (m_token_begin_itr == m_cur_itr) {\n            emit_error(\"anchor name must not be empty.\");\n        }\n\n        return {m_token_begin_itr, m_cur_itr};\n    }\n\n    /// @brief Extracts a tag name from the input.\n    /// @return A tag name.\n    str_view extract_tag_name() {\n        FK_YAML_ASSERT(*m_cur_itr == '!');\n\n        if (++m_cur_itr == m_end_itr) {\n            // Just \"!\" is a non-specific tag.\n            return {m_token_begin_itr, m_end_itr};\n        }\n\n        bool is_verbatim = false;\n        bool allows_another_tag_prefix = false;\n\n        switch (*m_cur_itr) {\n        case ' ':\n        case '\\n':\n            // Just \"!\" is a non-specific tag.\n            return {m_token_begin_itr, m_cur_itr};\n        case '!':\n            // Secondary tag handles (!!suffix)\n            break;\n        case '<':\n            // Verbatim tags (!<TAG>)\n            is_verbatim = true;\n            ++m_cur_itr;\n            break;\n        default:\n            // Either local tags (!suffix) or named handles (!tag!suffix)\n            allows_another_tag_prefix = true;\n            break;\n        }\n\n        bool is_named_handle = false;\n        bool ends_loop = false;\n        do {\n            if (++m_cur_itr == m_end_itr) {\n                break;\n            }\n\n            switch (*m_cur_itr) {\n            // Tag names must not contain spaces or newline codes.\n            case ' ':\n            case '\\t':\n            case '\\n':\n                ends_loop = true;\n                break;\n            case '!':\n                if FK_YAML_UNLIKELY (!allows_another_tag_prefix) {\n                    emit_error(\"invalid tag prefix (!) is found.\");\n                }\n\n                is_named_handle = true;\n                // tag prefix must not appear three times.\n                allows_another_tag_prefix = false;\n                break;\n            default:\n                break;\n            }\n        } while (!ends_loop);\n\n        str_view tag_name {m_token_begin_itr, m_cur_itr};\n\n        if (is_verbatim) {\n            const char last = tag_name.back();\n            if FK_YAML_UNLIKELY (last != '>') {\n                emit_error(\"verbatim tag (!<TAG>) must be ended with \\'>\\'.\");\n            }\n\n            // only the `TAG` part of the `!<TAG>` for URI validation.\n            const str_view tag_body = tag_name.substr(2, tag_name.size() - 3);\n            if FK_YAML_UNLIKELY (tag_body.empty()) {\n                emit_error(\"verbatim tag(!<TAG>) must not be empty.\");\n            }\n\n            const bool is_valid_uri = uri_encoding::validate(tag_body.begin(), tag_body.end());\n            if FK_YAML_UNLIKELY (!is_valid_uri) {\n                emit_error(\"invalid URI character is found in a verbatim tag.\");\n            }\n\n            return tag_name;\n        }\n\n        if (is_named_handle) {\n            const char last = tag_name.back();\n            if FK_YAML_UNLIKELY (last == '!') {\n                // Tag shorthand must be followed by a non-empty suffix.\n                // See the \"Tag Shorthands\" section in https://yaml.org/spec/1.2.2/#691-node-tags.\n                emit_error(\"named handle has no suffix.\");\n            }\n        }\n\n        // get the position of last tag prefix character (!) to extract body of tag shorthands.\n        // tag shorthand is either primary(!tag), secondary(!!tag) or named(!handle!tag).\n        const std::size_t last_tag_prefix_pos = tag_name.find_last_of('!');\n        FK_YAML_ASSERT(last_tag_prefix_pos != str_view::npos);\n\n        const str_view tag_uri = tag_name.substr(last_tag_prefix_pos + 1);\n        const bool is_valid_uri = uri_encoding::validate(tag_uri.begin(), tag_uri.end());\n        if FK_YAML_UNLIKELY (!is_valid_uri) {\n            emit_error(\"Invalid URI character is found in a named tag handle.\");\n        }\n\n        // Tag shorthands cannot contain flow indicators({}[],).\n        // See the \"Tag Shorthands\" section in https://yaml.org/spec/1.2.2/#691-node-tags.\n        const std::size_t invalid_char_pos = tag_uri.find_first_of(\"{}[],\");\n        if (invalid_char_pos != str_view::npos) {\n            emit_error(\"Tag shorthand cannot contain flow indicators({}[],).\");\n        }\n\n        return tag_name;\n    }\n\n    /// @brief Determines the range of single quoted scalar by scanning remaining input buffer contents.\n    /// @return A single quoted scalar.\n    str_view determine_single_quoted_scalar_range() {\n        const str_view sv {m_token_begin_itr, m_end_itr};\n\n        std::size_t pos = sv.find('\\'');\n        while (pos != str_view::npos) {\n            FK_YAML_ASSERT(pos < sv.size());\n            if FK_YAML_LIKELY (pos == sv.size() - 1 || sv[pos + 1] != '\\'') {\n                // closing single quote is found.\n                m_cur_itr = m_token_begin_itr + (pos + 1);\n                str_view single_quoted_scalar {m_token_begin_itr, pos};\n                check_scalar_content(single_quoted_scalar);\n                return single_quoted_scalar;\n            }\n\n            // If single quotation marks are repeated twice in a single quoted scalar, they are considered as an\n            // escaped single quotation mark. Skip the second one which would otherwise be detected as a closing\n            // single quotation mark in the next loop.\n            pos = sv.find('\\'', pos + 2);\n        }\n\n        m_cur_itr = m_end_itr; // update for error information\n        emit_error(\"Invalid end of input buffer in a single-quoted scalar token.\");\n    }\n\n    /// @brief Determines the range of double quoted scalar by scanning remaining input buffer contents.\n    /// @return A double quoted scalar.\n    str_view determine_double_quoted_scalar_range() {\n        const str_view sv {m_token_begin_itr, m_end_itr};\n\n        std::size_t pos = sv.find('\\\"');\n        while (pos != str_view::npos) {\n            FK_YAML_ASSERT(pos < sv.size());\n\n            bool is_closed = true;\n            if FK_YAML_LIKELY (pos > 0) {\n                // Double quotation marks can be escaped by a preceding backslash and the number of backslashes matters\n                // to determine if the found double quotation mark is escaped since the backslash itself can also be\n                // escaped:\n                // * odd number of backslashes  -> double quotation mark IS escaped (e.g., \"\\\\\\\"\")\n                // * even number of backslashes -> double quotation mark IS NOT escaped (e.g., \"\\\\\"\")\n                uint32_t backslash_counts = 0;\n                const char* p = m_token_begin_itr + (pos - 1);\n                do {\n                    if (*p-- != '\\\\') {\n                        break;\n                    }\n                    ++backslash_counts;\n                } while (p != m_token_begin_itr);\n                is_closed = ((backslash_counts & 1u) == 0); // true: even, false: odd\n            }\n\n            if (is_closed) {\n                // closing double quote is found.\n                m_cur_itr = m_token_begin_itr + (pos + 1);\n                str_view double_quoted_salar {m_token_begin_itr, pos};\n                check_scalar_content(double_quoted_salar);\n                return double_quoted_salar;\n            }\n\n            pos = sv.find('\\\"', pos + 1);\n        }\n\n        m_cur_itr = m_end_itr; // update for error information\n        emit_error(\"Invalid end of input buffer in a double-quoted scalar token.\");\n    }\n\n    /// @brief Determines the range of plain scalar by scanning remaining input buffer contents.\n    /// @return A plain scalar.\n    str_view determine_plain_scalar_range() {\n        const str_view sv {m_token_begin_itr, m_end_itr};\n\n        // flow indicators are checked only within a flow context.\n        const str_view filter = (m_state & flow_context_bit) ? \"\\n :{}[],\" : \"\\n :\";\n        std::size_t pos = sv.find_first_of(filter);\n        if FK_YAML_UNLIKELY (pos == str_view::npos) {\n            check_scalar_content(sv);\n            m_cur_itr = m_end_itr;\n            return sv;\n        }\n\n        bool ends_loop = false;\n        uint32_t indent = std::numeric_limits<uint32_t>::max();\n        do {\n            FK_YAML_ASSERT(pos < sv.size());\n            switch (sv[pos]) {\n            case '\\n': {\n                if (indent == std::numeric_limits<uint32_t>::max()) {\n                    indent = get_current_indent_level(&sv[pos]);\n                }\n\n                constexpr str_view space_filter {\" \\t\\n\"};\n                const std::size_t non_space_pos = sv.find_first_not_of(space_filter, pos);\n                const std::size_t last_newline_pos = sv.find_last_of('\\n', non_space_pos);\n                FK_YAML_ASSERT(last_newline_pos != str_view::npos);\n\n                if (non_space_pos == str_view::npos || non_space_pos - last_newline_pos - 1 <= indent) {\n                    ends_loop = true;\n                    break;\n                }\n\n                pos = non_space_pos;\n                break;\n            }\n            case ' ':\n                if FK_YAML_UNLIKELY (pos == sv.size() - 1) {\n                    // trim trailing space.\n                    ends_loop = true;\n                    break;\n                }\n\n                // Allow a space in a plain scalar only if the space is surrounded by non-space characters, but not\n                // followed by the comment prefix \" #\".\n                // Also, flow indicators are not allowed to be followed after a space in a flow context.\n                // See https://yaml.org/spec/1.2.2/#733-plain-style for more details.\n                switch (sv[pos + 1]) {\n                case ' ':\n                case '\\t':\n                case '\\n':\n                case '#':\n                    ends_loop = true;\n                    break;\n                case ':':\n                    // \" :\" is permitted in a plain style string token, but not when followed by a space.\n                    ends_loop = (pos < sv.size() - 2) && (sv[pos + 2] == ' ');\n                    break;\n                case '{':\n                case '}':\n                case '[':\n                case ']':\n                case ',':\n                    ends_loop = (m_state & flow_context_bit);\n                    break;\n                default:\n                    break;\n                }\n                break;\n            case ':':\n                if FK_YAML_LIKELY (pos + 1 < sv.size()) {\n                    switch (sv[pos + 1]) {\n                    case ' ':\n                    case '\\t':\n                    case '\\n':\n                        ends_loop = true;\n                        break;\n                    default:\n                        break;\n                    }\n                }\n                break;\n            case '{':\n            case '}':\n            case '[':\n            case ']':\n            case ',':\n                // This check is enabled only in a flow context.\n                ends_loop = true;\n                break;\n            default:                   // LCOV_EXCL_LINE\n                detail::unreachable(); // LCOV_EXCL_LINE\n            }\n\n            if (ends_loop) {\n                break;\n            }\n\n            pos = sv.find_first_of(filter, pos + 1);\n        } while (pos != str_view::npos);\n\n        str_view plain_scalar = sv.substr(0, pos);\n        check_scalar_content(plain_scalar);\n        m_cur_itr = plain_scalar.end();\n        return plain_scalar;\n    }\n\n    /// @brief Scan a block style string token either in the literal or folded style.\n    /// @param base_indent The base indent level of the block scalar.\n    /// @param indicated_indent The indicated indent level in the block scalar header. 0 means it's not indicated.\n    /// @param token Storage for the scanned block scalar range.\n    /// @return The content indentation level of the block scalar.\n    str_view determine_block_scalar_content_range(\n        uint32_t base_indent, uint32_t indicated_indent, uint32_t& content_indent) {\n        const str_view sv {m_token_begin_itr, m_end_itr};\n        const std::size_t remain_input_len = sv.size();\n\n        // Handle leading all-space lines.\n        uint32_t cur_indent = 0;\n        uint32_t max_leading_indent = 0;\n        const char* cur_itr = m_token_begin_itr;\n        bool stop_increment = false;\n\n        while (cur_itr != m_end_itr) {\n            switch (*cur_itr++) {\n            case ' ':\n                if FK_YAML_LIKELY (!stop_increment) {\n                    ++cur_indent;\n                }\n                continue;\n            case '\\t':\n                // Tabs are not counted as an indent character but still part of an empty line.\n                // See https://yaml.org/spec/1.2.2/#rule-s-indent and https://yaml.org/spec/1.2.2/#64-empty-lines.\n                stop_increment = true;\n                continue;\n            case '\\n':\n                max_leading_indent = std::max(cur_indent, max_leading_indent);\n                cur_indent = 0;\n                stop_increment = false;\n                continue;\n            default:\n                break;\n            }\n            break;\n        }\n\n        // all the block scalar contents are empty lines, and no subsequent token exists.\n        if FK_YAML_UNLIKELY (cur_itr == m_end_itr) {\n            // Without the following iterator update, lexer cannot reach the end of input buffer and causes infinite\n            // loops from the next loop. (https://github.com/fktn-k/fkYAML/pull/410)\n            m_cur_itr = m_end_itr;\n\n            // If there's no non-empty line, the content indentation level is equal to the number of spaces on the\n            // longest line. https://yaml.org/spec/1.2.2/#8111-block-indentation-indicator\n            content_indent =\n                indicated_indent == 0 ? std::max(cur_indent, max_leading_indent) : base_indent + indicated_indent;\n            return sv;\n        }\n\n        // Any leading empty line must not contain more spaces than the first non-empty line.\n        if FK_YAML_UNLIKELY (cur_indent < max_leading_indent) {\n            emit_error(\"Any leading empty line must not be more indented than the first non-empty line.\");\n        }\n\n        if (indicated_indent == 0) {\n            FK_YAML_ASSERT(base_indent < cur_indent);\n            indicated_indent = cur_indent - base_indent;\n        }\n        else if FK_YAML_UNLIKELY (cur_indent < base_indent + indicated_indent) {\n            emit_error(\"The first non-empty line in the block scalar is less indented.\");\n        }\n\n        std::size_t last_newline_pos = sv.find('\\n', cur_itr - m_token_begin_itr + 1);\n        if (last_newline_pos == str_view::npos) {\n            last_newline_pos = remain_input_len;\n        }\n\n        content_indent = base_indent + indicated_indent;\n        while (last_newline_pos < remain_input_len) {\n            std::size_t cur_line_end_pos = sv.find('\\n', last_newline_pos + 1);\n            if (cur_line_end_pos == str_view::npos) {\n                cur_line_end_pos = remain_input_len;\n            }\n\n            const std::size_t cur_line_content_begin_pos = sv.find_first_not_of(' ', last_newline_pos + 1);\n            if (cur_line_content_begin_pos == str_view::npos) {\n                last_newline_pos = cur_line_end_pos;\n                continue;\n            }\n\n            FK_YAML_ASSERT(last_newline_pos < cur_line_content_begin_pos);\n            cur_indent = static_cast<uint32_t>(cur_line_content_begin_pos - last_newline_pos - 1);\n            if (cur_indent < content_indent && sv[cur_line_content_begin_pos] != '\\n') {\n                if FK_YAML_UNLIKELY (cur_indent > base_indent) {\n                    // This path assumes an input like the following:\n                    // ```yaml\n                    // foo: |\n                    //   text\n                    //  invalid # this line is less indented than the content indent level (2)\n                    //          # but more indented than the base indent level (0)\n                    // ```\n                    // In such cases, the less indented line cannot be the start of the next token.\n                    emit_error(\"A content line of the block scalar is less indented.\");\n                }\n\n                // Interpret less indented non-space characters as the start of the next token.\n                break;\n            }\n\n            last_newline_pos = cur_line_end_pos;\n        }\n\n        // include last newline character if not all characters have been consumed yet.\n        if (last_newline_pos < remain_input_len) {\n            ++last_newline_pos;\n        }\n\n        m_cur_itr = m_token_begin_itr + last_newline_pos;\n        return sv.substr(0, last_newline_pos);\n    }\n\n    /// @brief Checks if the given scalar contains no unescaped control characters.\n    /// @param scalar Scalar contents.\n    void check_scalar_content(const str_view& scalar) const {\n        const char* p_current = scalar.begin();\n        const char* p_end = scalar.end();\n\n        while (p_current != p_end) {\n            const uint32_t num_bytes = utf8::get_num_bytes(static_cast<uint8_t>(*p_current));\n            if (num_bytes > 1) {\n                // Multibyte characters are already checked in the input_adapter module.\n                p_current += num_bytes;\n                continue;\n            }\n\n            switch (*p_current++) {\n            // 0x00(NULL) has already been handled above.\n            case 0x01:\n                emit_error(\"Control character U+0001 (SOH) must be escaped to \\\\u0001.\");\n            case 0x02:\n                emit_error(\"Control character U+0002 (STX) must be escaped to \\\\u0002.\");\n            case 0x03:\n                emit_error(\"Control character U+0003 (ETX) must be escaped to \\\\u0003.\");\n            case 0x04:\n                emit_error(\"Control character U+0004 (EOT) must be escaped to \\\\u0004.\");\n            case 0x05:\n                emit_error(\"Control character U+0005 (ENQ) must be escaped to \\\\u0005.\");\n            case 0x06:\n                emit_error(\"Control character U+0006 (ACK) must be escaped to \\\\u0006.\");\n            case 0x07:\n                emit_error(\"Control character U+0007 (BEL) must be escaped to \\\\a or \\\\u0007.\");\n            case 0x08:\n                emit_error(\"Control character U+0008 (BS) must be escaped to \\\\b or \\\\u0008.\");\n            case 0x09: // HT\n                // horizontal tabs (\\t) are safe to use without escaping.\n                break;\n            // 0x0A(LF) has already been handled above.\n            case 0x0B:\n                emit_error(\"Control character U+000B (VT) must be escaped to \\\\v or \\\\u000B.\");\n            case 0x0C:\n                emit_error(\"Control character U+000C (FF) must be escaped to \\\\f or \\\\u000C.\");\n            // 0x0D(CR) has already been handled above.\n            case 0x0E:\n                emit_error(\"Control character U+000E (SO) must be escaped to \\\\u000E.\");\n            case 0x0F:\n                emit_error(\"Control character U+000F (SI) must be escaped to \\\\u000F.\");\n            case 0x10:\n                emit_error(\"Control character U+0010 (DLE) must be escaped to \\\\u0010.\");\n            case 0x11:\n                emit_error(\"Control character U+0011 (DC1) must be escaped to \\\\u0011.\");\n            case 0x12:\n                emit_error(\"Control character U+0012 (DC2) must be escaped to \\\\u0012.\");\n            case 0x13:\n                emit_error(\"Control character U+0013 (DC3) must be escaped to \\\\u0013.\");\n            case 0x14:\n                emit_error(\"Control character U+0014 (DC4) must be escaped to \\\\u0014.\");\n            case 0x15:\n                emit_error(\"Control character U+0015 (NAK) must be escaped to \\\\u0015.\");\n            case 0x16:\n                emit_error(\"Control character U+0016 (SYN) must be escaped to \\\\u0016.\");\n            case 0x17:\n                emit_error(\"Control character U+0017 (ETB) must be escaped to \\\\u0017.\");\n            case 0x18:\n                emit_error(\"Control character U+0018 (CAN) must be escaped to \\\\u0018.\");\n            case 0x19:\n                emit_error(\"Control character U+0019 (EM) must be escaped to \\\\u0019.\");\n            case 0x1A:\n                emit_error(\"Control character U+001A (SUB) must be escaped to \\\\u001A.\");\n            case 0x1B:\n                emit_error(\"Control character U+001B (ESC) must be escaped to \\\\e or \\\\u001B.\");\n            case 0x1C:\n                emit_error(\"Control character U+001C (FS) must be escaped to \\\\u001C.\");\n            case 0x1D:\n                emit_error(\"Control character U+001D (GS) must be escaped to \\\\u001D.\");\n            case 0x1E:\n                emit_error(\"Control character U+001E (RS) must be escaped to \\\\u001E.\");\n            case 0x1F:\n                emit_error(\"Control character U+001F (US) must be escaped to \\\\u001F.\");\n            default:\n                break;\n            }\n        }\n    }\n\n    /// @brief Gets the metadata of a following block style string scalar.\n    /// @param chomp_type A variable to store the retrieved chomping style type.\n    /// @param indent A variable to store the retrieved indent size.\n    /// @return Block scalar header information converted from the header line.\n    block_scalar_header convert_to_block_scalar_header(str_view line) {\n        constexpr str_view comment_prefix {\" #\"};\n        const std::size_t comment_begin_pos = line.find(comment_prefix);\n        if (comment_begin_pos != str_view::npos) {\n            line = line.substr(0, comment_begin_pos);\n        }\n\n        if (line.empty()) {\n            return {};\n        }\n\n        block_scalar_header header {};\n        for (const char c : line) {\n            switch (c) {\n            case '-':\n                if FK_YAML_UNLIKELY (header.chomp != chomping_indicator_t::CLIP) {\n                    emit_error(\"Too many block chomping indicators specified.\");\n                }\n                header.chomp = chomping_indicator_t::STRIP;\n                break;\n            case '+':\n                if FK_YAML_UNLIKELY (header.chomp != chomping_indicator_t::CLIP) {\n                    emit_error(\"Too many block chomping indicators specified.\");\n                }\n                header.chomp = chomping_indicator_t::KEEP;\n                break;\n            case '0':\n                emit_error(\"An indentation level for a block scalar cannot be 0.\");\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                if FK_YAML_UNLIKELY (header.indent > 0) {\n                    emit_error(\"Invalid indentation level for a block scalar. It must be between 1 and 9.\");\n                }\n                header.indent = static_cast<uint32_t>(c - '0');\n                break;\n            case ' ':\n            case '\\t':\n                break;\n            default:\n                emit_error(\"Invalid character found in a block scalar header.\");\n            }\n        }\n\n        return header;\n    }\n\n    /// @brief Skip white spaces (half-width spaces and tabs) from the current position.\n    void skip_white_spaces() {\n        m_cur_itr = std::find_if_not(m_cur_itr, m_end_itr, [](char c) { return (c == ' ' || c == '\\t'); });\n    }\n\n    /// @brief Skip white spaces and newline codes (CR/LF) from the current position.\n    void skip_white_spaces_and_newline_codes() {\n        if (m_cur_itr != m_end_itr) {\n            m_cur_itr = std::find_if_not(m_cur_itr, m_end_itr, [](char c) {\n                switch (c) {\n                case ' ':\n                case '\\t':\n                case '\\n':\n                    return true;\n                default:\n                    return false;\n                }\n            });\n        }\n    }\n\n    /// @brief Skip the rest in the current line.\n    void skip_until_line_end() {\n        while (m_cur_itr != m_end_itr) {\n            switch (*m_cur_itr) {\n            case '\\n':\n                ++m_cur_itr;\n                return;\n            default:\n                ++m_cur_itr;\n                break;\n            }\n        }\n    }\n\n    /// @brief Emits an error with the given message.\n    /// @param msg A message for the resulting error.\n    [[noreturn]] void emit_error(const char* msg) const {\n        m_pos_tracker.update_position(m_cur_itr);\n        throw fkyaml::parse_error(msg, m_pos_tracker.get_lines_read(), m_pos_tracker.get_cur_pos_in_line());\n    }\n\nprivate:\n    /// The iterator to the first element in the input buffer.\n    const char* m_begin_itr {};\n    /// The iterator to the current character in the input buffer.\n    const char* m_cur_itr {};\n    /// The iterator to the beginning of the current token.\n    const char* m_token_begin_itr {};\n    /// The iterator to the past-the-end element in the input buffer.\n    const char* m_end_itr {};\n    /// The current position tracker of the input buffer.\n    mutable position_tracker m_pos_tracker {};\n    /// The last yaml version.\n    str_view m_yaml_version;\n    /// The last tag handle.\n    str_view m_tag_handle;\n    /// The last tag prefix.\n    str_view m_tag_prefix;\n    /// The last block scalar header.\n    block_scalar_header m_block_scalar_header {};\n    /// The beginning position of the last lexical token. (zero origin)\n    uint32_t m_last_token_begin_pos {0};\n    /// The beginning line of the last lexical token. (zero origin)\n    uint32_t m_last_token_begin_line {0};\n    /// The current depth of flow context.\n    uint32_t m_state {0};\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_LEXICAL_ANALYZER_HPP */\n\n// #include <fkYAML/detail/input/scalar_parser.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_SCALAR_PARSER_HPP\n#define FK_YAML_DETAIL_INPUT_SCALAR_PARSER_HPP\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n// #include <fkYAML/detail/conversions/scalar_conv.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n// **NOTE FOR LIBARARY DEVELOPERS**:\n// Implementations in this header file are intentionally optimized for conversions between YAML scalars and native C++\n// types. So, some implementations don't follow the convensions in the standard C++ functions. For example, octals must\n// begin with \"0o\" (not \"0\"), which is specified in the YAML spec 1.2.\n\n#ifndef FK_YAML_CONVERSIONS_SCALAR_CONV_HPP\n#define FK_YAML_CONVERSIONS_SCALAR_CONV_HPP\n\n#include <cmath>\n#include <cstdint>\n#include <cstring>\n#include <limits>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n\n#if FK_YAML_HAS_TO_CHARS\n// Prefer std::to_chars() and std::from_chars() functions if available.\n#include <charconv>\n#else\n// Fallback to legacy string conversion functions otherwise.\n#include <string> // std::stof(), std::stod(), std::stold()\n#endif\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n//////////////////////////\n//   conv_limits_base   //\n//////////////////////////\n\n/// @brief A structure which provides limits for conversions between scalars and integers.\n/// @note This structure contains common limits in both signed and unsigned integers.\n/// @tparam NumBytes The number of bytes for the integer type.\ntemplate <std::size_t NumBytes>\nstruct conv_limits_base {};\n\n/// @brief The specialization of conv_limits_base for 1 byte integers, e.g., int8_t, uint8_t.\ntemplate <>\nstruct conv_limits_base<1u> {\n    /// max characters for octals (0o377) without the prefix part.\n    static constexpr std::size_t max_chars_oct = 3;\n    /// max characters for hexadecimals (0xFF) without the prefix part.\n    static constexpr std::size_t max_chars_hex = 2;\n\n    /// @brief Check if the given octals are safely converted into 1 byte integer.\n    /// @param octs The pointer to octal characters\n    /// @param len The length of octal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_octs_safe(const char* octs, std::size_t len) noexcept {\n        return (len < max_chars_oct) || (len == max_chars_oct && octs[0] <= '3');\n    }\n\n    /// @brief Check if the given hexadecimals are safely converted into 1 byte integer.\n    /// @param octs The pointer to hexadecimal characters\n    /// @param len The length of hexadecimal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_hexs_safe(const char* /*unused*/, std::size_t len) noexcept {\n        return len <= max_chars_hex;\n    }\n};\n\n/// @brief The specialization of conv_limits_base for 2 byte integers, e.g., int16_t, uint16_t.\ntemplate <>\nstruct conv_limits_base<2u> {\n    /// max characters for octals (0o177777) without the prefix part.\n    static constexpr std::size_t max_chars_oct = 6;\n    /// max characters for hexadecimals (0xFFFF) without the prefix part.\n    static constexpr std::size_t max_chars_hex = 4;\n\n    /// @brief Check if the given octals are safely converted into 2 byte integer.\n    /// @param octs The pointer to octal characters\n    /// @param len The length of octal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_octs_safe(const char* octs, std::size_t len) noexcept {\n        return (len < max_chars_oct) || (len == max_chars_oct && octs[0] <= '1');\n    }\n\n    /// @brief Check if the given hexadecimals are safely converted into 2 byte integer.\n    /// @param octs The pointer to hexadecimal characters\n    /// @param len The length of hexadecimal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_hexs_safe(const char* /*unused*/, std::size_t len) noexcept {\n        return len <= max_chars_hex;\n    }\n};\n\n/// @brief The specialization of conv_limits_base for 4 byte integers, e.g., int32_t, uint32_t.\ntemplate <>\nstruct conv_limits_base<4u> {\n    /// max characters for octals (0o37777777777) without the prefix part.\n    static constexpr std::size_t max_chars_oct = 11;\n    /// max characters for hexadecimals (0xFFFFFFFF) without the prefix part.\n    static constexpr std::size_t max_chars_hex = 8;\n\n    /// @brief Check if the given octals are safely converted into 4 byte integer.\n    /// @param octs The pointer to octal characters\n    /// @param len The length of octal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_octs_safe(const char* octs, std::size_t len) noexcept {\n        return (len < max_chars_oct) || (len == max_chars_oct && octs[0] <= '3');\n    }\n\n    /// @brief Check if the given hexadecimals are safely converted into 4 byte integer.\n    /// @param octs The pointer to hexadecimal characters\n    /// @param len The length of hexadecimal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_hexs_safe(const char* /*unused*/, std::size_t len) noexcept {\n        return len <= max_chars_hex;\n    }\n};\n\n/// @brief The specialization of conv_limits_base for 8 byte integers, e.g., int64_t, uint64_t.\ntemplate <>\nstruct conv_limits_base<8u> {\n    /// max characters for octals (0o1777777777777777777777) without the prefix part.\n    static constexpr std::size_t max_chars_oct = 22;\n    /// max characters for hexadecimals (0xFFFFFFFFFFFFFFFF) without the prefix part.\n    static constexpr std::size_t max_chars_hex = 16;\n\n    /// @brief Check if the given octals are safely converted into 8 byte integer.\n    /// @param octs The pointer to octal characters\n    /// @param len The length of octal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_octs_safe(const char* octs, std::size_t len) noexcept {\n        return (len < max_chars_oct) || (len == max_chars_oct && octs[0] <= '1');\n    }\n\n    /// @brief Check if the given hexadecimals are safely converted into 8 byte integer.\n    /// @param octs The pointer to hexadecimal characters\n    /// @param len The length of hexadecimal characters\n    /// @return true is safely convertible, false otherwise.\n    static bool check_if_hexs_safe(const char* /*unused*/, std::size_t len) noexcept {\n        return len <= max_chars_hex;\n    }\n};\n\n/////////////////////\n//   conv_limits   //\n/////////////////////\n\n/// @brief A structure which provides limits for conversions between scalars and integers.\n/// @note This structure contains limits which differs based on signedness.\n/// @tparam NumBytes The number of bytes for the integer type.\n/// @tparam IsSigned Whether an integer is signed or unsigned\ntemplate <std::size_t NumBytes, bool IsSigned>\nstruct conv_limits {};\n\n/// @brief The specialization of conv_limits for 1 byte signed integers, e.g., int8_t.\ntemplate <>\nstruct conv_limits<1u, true> : conv_limits_base<1u> {\n    /// with or without sign.\n    static constexpr bool is_signed = true;\n\n    /// max characters for decimals (-128..127) without sign.\n    static constexpr std::size_t max_chars_dec = 3;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        // Making this function a static constexpr variable, a link error happens.\n        // Although the issue has been fixed since C++17, this workaround is necessary to let this functionality work\n        // with C++11 (the library's default C++ standard version).\n        // The same thing is applied to similar functions in the other specializations.\n\n        static constexpr char max_value_chars[] = \"127\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value without sign.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"128\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 1 byte unsigned integers, e.g., uint8_t.\ntemplate <>\nstruct conv_limits<1u, false> : conv_limits_base<1u> {\n    /// with or without sign.\n    static constexpr bool is_signed = false;\n\n    /// max characters for decimals (0..255) without sign.\n    static constexpr std::size_t max_chars_dec = 3;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"255\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"0\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 2 byte signed integers, e.g., int16_t.\ntemplate <>\nstruct conv_limits<2u, true> : conv_limits_base<2u> {\n    /// with or without sign.\n    static constexpr bool is_signed = true;\n\n    /// max characters for decimals (-32768..32767) without sign.\n    static constexpr std::size_t max_chars_dec = 5;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"32767\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value without sign.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"32768\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 2 byte unsigned integers, e.g., uint16_t.\ntemplate <>\nstruct conv_limits<2u, false> : conv_limits_base<2u> {\n    /// with or without sign.\n    static constexpr bool is_signed = false;\n\n    /// max characters for decimals (0..65535) without sign.\n    static constexpr std::size_t max_chars_dec = 5;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"65535\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"0\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 4 byte signed integers, e.g., int32_t.\ntemplate <>\nstruct conv_limits<4u, true> : conv_limits_base<4u> {\n    /// with or without sign.\n    static constexpr bool is_signed = true;\n\n    /// max characters for decimals (-2147483648..2147483647) without sign.\n    static constexpr std::size_t max_chars_dec = 10;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"2147483647\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value without sign.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"2147483648\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 4 byte unsigned integers, e.g., uint32_t.\ntemplate <>\nstruct conv_limits<4u, false> : conv_limits_base<4u> {\n    /// with or without sign.\n    static constexpr bool is_signed = false;\n\n    /// max characters for decimals (0..4294967295) without sign.\n    static constexpr std::size_t max_chars_dec = 10;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"4294967295\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"0\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 8 byte signed integers, e.g., int64_t.\ntemplate <>\nstruct conv_limits<8u, true> : conv_limits_base<8u> {\n    /// with or without sign.\n    static constexpr bool is_signed = true;\n\n    /// max characters for decimals (-9223372036854775808..9223372036854775807) without sign.\n    static constexpr std::size_t max_chars_dec = 19;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"9223372036854775807\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value without sign.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"9223372036854775808\";\n        return &min_value_chars[0];\n    }\n};\n\n/// @brief The specialization of conv_limits for 8 byte unsigned integers, e.g., uint64_t.\ntemplate <>\nstruct conv_limits<8u, false> : conv_limits_base<8u> {\n    /// with or without sign.\n    static constexpr bool is_signed = false;\n\n    /// max characters for decimals (0..18446744073709551615) without sign.\n    static constexpr std::size_t max_chars_dec = 20;\n\n    /// string representation of max decimal value.\n    static const char* max_value_chars_dec() noexcept {\n        static constexpr char max_value_chars[] = \"18446744073709551615\";\n        return &max_value_chars[0];\n    }\n\n    /// string representation of min decimal value.\n    static const char* min_value_chars_dec() noexcept {\n        static constexpr char min_value_chars[] = \"0\";\n        return &min_value_chars[0];\n    }\n};\n\n//////////////////////////\n//   scalar <--> null   //\n//////////////////////////\n\n/// @brief Converts a scalar into a null value\n/// @tparam CharItr Type of char iterators. Its value type must be `char` (maybe cv-qualified).\n/// @param begin The iterator to the first element of the scalar.\n/// @param end The iterator to the past-the-end element of the scalar.\n/// @param /*unused*/ The null value holder (unused since it can only have `nullptr`)\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename CharItr>\ninline bool aton(CharItr begin, CharItr end, std::nullptr_t& /*unused*/) noexcept {\n    static_assert(is_iterator_of<CharItr, char>::value, \"aton() accepts iterators for char type\");\n\n    if FK_YAML_UNLIKELY (begin == end) {\n        return false;\n    }\n\n    const auto len = static_cast<uint32_t>(std::distance(begin, end));\n\n    // This path is the most probable case, so check it first.\n    if FK_YAML_LIKELY (len == 4) {\n        const char* p_begin = &*begin;\n        return (std::strncmp(p_begin, \"null\", 4) == 0) || (std::strncmp(p_begin, \"Null\", 4) == 0) ||\n               (std::strncmp(p_begin, \"NULL\", 4) == 0);\n    }\n\n    if (len == 1) {\n        return *begin == '~';\n    }\n\n    return false;\n}\n\n/////////////////////////////\n//   scalar <--> boolean   //\n/////////////////////////////\n\n/// @brief Converts a scalar into a boolean value\n/// @tparam CharItr The type of char iterators. Its value type must be `char` (maybe cv-qualified).\n/// @tparam BoolType The output boolean type.\n/// @param begin The iterator to the first element of the scalar.\n/// @param end The iterator to the past-the-end element of the scalar.\n/// @param boolean The boolean value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename CharItr, typename BoolType>\ninline bool atob(CharItr begin, CharItr end, BoolType& boolean) noexcept {\n    static_assert(is_iterator_of<CharItr, char>::value, \"atob() accepts iterators for char type\");\n\n    if FK_YAML_UNLIKELY (begin == end) {\n        return false;\n    }\n\n    const auto len = static_cast<uint32_t>(std::distance(begin, end));\n    const char* p_begin = &*begin;\n\n    if (len == 4) {\n        const bool is_true = (std::strncmp(p_begin, \"true\", 4) == 0) || (std::strncmp(p_begin, \"True\", 4) == 0) ||\n                             (std::strncmp(p_begin, \"TRUE\", 4) == 0);\n\n        if FK_YAML_LIKELY (is_true) {\n            boolean = static_cast<BoolType>(true);\n        }\n        return is_true;\n    }\n\n    if (len == 5) {\n        const bool is_false = (std::strncmp(p_begin, \"false\", 5) == 0) || (std::strncmp(p_begin, \"False\", 5) == 0) ||\n                              (std::strncmp(p_begin, \"FALSE\", 5) == 0);\n\n        if FK_YAML_LIKELY (is_false) {\n            boolean = static_cast<BoolType>(false);\n        }\n        return is_false;\n    }\n\n    return false;\n}\n\n/////////////////////////////\n//   scalar <--> integer   //\n/////////////////////////////\n\n//\n// scalar --> decimals\n//\n\n/// @brief Converts a scalar into decimals. This is common implementation for both signed/unsigned integer types.\n/// @warning\n/// This function does NOT care about overflows if IntType is unsigned. The source string value must be validated\n/// beforehand by calling either atoi_dec_pos() or atoi_dec_neg() functions.\n/// Furthermore, `p_begin` and `p_end` must NOT be null. Validate them before calling this function.\n/// @tparam IntType The output integer type. It can be either signed or unsigned.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param i The output integer value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename IntType>\ninline bool atoi_dec_unchecked(const char* p_begin, const char* p_end, IntType& i) noexcept {\n    static_assert(\n        is_non_bool_integral<IntType>::value,\n        \"atoi_dec_unchecked() accepts non-boolean integral types as an output type\");\n\n    i = 0;\n    do {\n        const char c = *p_begin;\n        if FK_YAML_UNLIKELY (c < '0' || '9' < c) {\n            return false;\n        }\n        // Overflow is intentional when the IntType is signed.\n        i = i * static_cast<IntType>(10) + static_cast<IntType>(c - '0');\n    } while (++p_begin != p_end);\n\n    return true;\n}\n\n/// @brief Converts a scalar into positive decimals. This function executes bounds check to avoid overflow.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @tparam IntType The output integer type. It can be either signed or unsigned.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param i The output integer value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename IntType>\ninline bool atoi_dec_pos(const char* p_begin, const char* p_end, IntType& i) noexcept {\n    static_assert(\n        is_non_bool_integral<IntType>::value, \"atoi_dec_pos() accepts non-boolean integral types as an output type\");\n\n    if FK_YAML_UNLIKELY (p_begin == p_end) {\n        return false;\n    }\n\n    using conv_limits_type = conv_limits<sizeof(IntType), std::is_signed<IntType>::value>;\n\n    const auto len = static_cast<std::size_t>(p_end - p_begin);\n    if FK_YAML_UNLIKELY (len > conv_limits_type::max_chars_dec) {\n        // Overflow will happen.\n        return false;\n    }\n\n    if (len == conv_limits_type::max_chars_dec) {\n        const char* p_max_value_chars_dec = conv_limits_type::max_value_chars_dec();\n\n        for (std::size_t idx = 0; idx < conv_limits_type::max_chars_dec; idx++) {\n            if (p_begin[idx] < p_max_value_chars_dec[idx]) {\n                // No need to check the lower digits. Overflow will no longer happen.\n                break;\n            }\n\n            if FK_YAML_UNLIKELY (p_begin[idx] > p_max_value_chars_dec[idx]) {\n                // Overflow will happen.\n                return false;\n            }\n        }\n    }\n\n    return atoi_dec_unchecked(p_begin, p_end, i);\n}\n\n/// @brief Converts a scalar into negative decimals. This function executes bounds check to avoid underflow.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @tparam IntType The output integer type. It must be signed.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param i The output integer value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename IntType>\ninline bool atoi_dec_neg(const char* p_begin, const char* p_end, IntType& i) noexcept {\n    static_assert(\n        is_non_bool_integral<IntType>::value, \"atoi_dec_neg() accepts non-boolean integral types as an output type\");\n\n    if FK_YAML_UNLIKELY (p_begin == p_end) {\n        return false;\n    }\n\n    using conv_limits_type = conv_limits<sizeof(IntType), std::is_signed<IntType>::value>;\n\n    const auto len = static_cast<std::size_t>(p_end - p_begin);\n    if FK_YAML_UNLIKELY (len > conv_limits_type::max_chars_dec) {\n        // Underflow will happen.\n        return false;\n    }\n\n    if (len == conv_limits_type::max_chars_dec) {\n        const char* p_min_value_chars_dec = conv_limits_type::min_value_chars_dec();\n\n        for (std::size_t idx = 0; idx < conv_limits_type::max_chars_dec; idx++) {\n            if (p_begin[idx] < p_min_value_chars_dec[idx]) {\n                // No need to check the lower digits. Underflow will no longer happen.\n                break;\n            }\n\n            if FK_YAML_UNLIKELY (p_begin[idx] > p_min_value_chars_dec[idx]) {\n                // Underflow will happen.\n                return false;\n            }\n        }\n    }\n\n    return atoi_dec_unchecked(p_begin, p_end, i);\n}\n\n//\n// scalar --> octals\n//\n\n/// @brief Converts a scalar into octals. This function executes bounds check to avoid overflow.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @tparam IntType The output integer type. It can be either signed or unsigned.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param i The output integer value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename IntType>\ninline bool atoi_oct(const char* p_begin, const char* p_end, IntType& i) noexcept {\n    static_assert(\n        is_non_bool_integral<IntType>::value, \"atoi_oct() accepts non-boolean integral types as an output type\");\n\n    if FK_YAML_UNLIKELY (p_begin == p_end) {\n        return false;\n    }\n\n    using conv_limits_type = conv_limits<sizeof(IntType), std::is_signed<IntType>::value>;\n\n    const auto len = static_cast<std::size_t>(p_end - p_begin);\n    if FK_YAML_UNLIKELY (!conv_limits_type::check_if_octs_safe(p_begin, len)) {\n        return false;\n    }\n\n    i = 0;\n    do {\n        const char c = *p_begin;\n        if FK_YAML_UNLIKELY (c < '0' || '7' < c) {\n            return false;\n        }\n        i = i * static_cast<IntType>(8) + static_cast<IntType>(c - '0');\n    } while (++p_begin != p_end);\n\n    return true;\n}\n\n//\n// scalar --> hexadecimals\n//\n\n/// @brief Converts a scalar into hexadecimals. This function executes bounds check to avoid overflow.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @tparam IntType The output integer type. It can be either signed or unsigned.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param i The output integer value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename IntType>\ninline bool atoi_hex(const char* p_begin, const char* p_end, IntType& i) noexcept {\n    static_assert(\n        is_non_bool_integral<IntType>::value, \"atoi_hex() accepts non-boolean integral types as an output type\");\n\n    if FK_YAML_UNLIKELY (p_begin == p_end) {\n        return false;\n    }\n\n    using conv_limits_type = conv_limits<sizeof(IntType), std::is_signed<IntType>::value>;\n\n    const auto len = static_cast<std::size_t>(p_end - p_begin);\n    if FK_YAML_UNLIKELY (!conv_limits_type::check_if_hexs_safe(p_begin, len)) {\n        return false;\n    }\n\n    i = 0;\n    do {\n        // NOLINTBEGIN(bugprone-misplaced-widening-cast)\n        const char c = *p_begin;\n        IntType ci = 0;\n        if ('0' <= c && c <= '9') {\n            ci = static_cast<IntType>(c - '0');\n        }\n        else if ('A' <= c && c <= 'F') {\n            ci = static_cast<IntType>(c - 'A' + 10);\n        }\n        else if ('a' <= c && c <= 'f') {\n            ci = static_cast<IntType>(c - 'a' + 10);\n        }\n        else {\n            return false;\n        }\n        i = i * static_cast<IntType>(16) + ci;\n        // NOLINTEND(bugprone-misplaced-widening-cast)\n    } while (++p_begin != p_end);\n\n    return true;\n}\n\n//\n// atoi() & itoa()\n//\n\n/// @brief Converts a scalar into integers. This function executes bounds check to avoid overflow/underflow.\n/// @tparam CharItr The type of char iterators. Its value type must be char (maybe cv-qualified).\n/// @tparam IntType The output integer type. It can be either signed or unsigned.\n/// @param begin The iterator to the first element of the scalar.\n/// @param end The iterator to the past-the-end element of the scalar.\n/// @param i The output integer value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename CharItr, typename IntType>\ninline bool atoi(CharItr begin, CharItr end, IntType& i) noexcept {\n    static_assert(is_iterator_of<CharItr, char>::value, \"atoi() accepts iterators for char type\");\n    static_assert(is_non_bool_integral<IntType>::value, \"atoi() accepts non-boolean integral types as an output type\");\n\n    if FK_YAML_UNLIKELY (begin == end) {\n        return false;\n    }\n\n    const auto len = static_cast<uint32_t>(std::distance(begin, end));\n    const char* p_begin = &*begin;\n    const char* p_end = p_begin + len;\n\n    const char first = *begin;\n    if (first == '+') {\n        return atoi_dec_pos(p_begin + 1, p_end, i);\n    }\n\n    if (first == '-') {\n        if (!std::numeric_limits<IntType>::is_signed) {\n            return false;\n        }\n\n        const bool success = atoi_dec_neg(p_begin + 1, p_end, i);\n        if (success) {\n            i *= static_cast<IntType>(-1);\n        }\n\n        return success;\n    }\n\n    if (first != '0') {\n        return atoi_dec_pos(p_begin, p_end, i);\n    }\n\n    if (p_begin + 1 != p_end) {\n        switch (*(p_begin + 1)) {\n        case 'o':\n            return atoi_oct(p_begin + 2, p_end, i);\n        case 'x':\n            return atoi_hex(p_begin + 2, p_end, i);\n        default:\n            // The YAML spec doesn't allow decimals starting with 0.\n            return false;\n        }\n    }\n\n    i = 0;\n    return true;\n}\n\n///////////////////////////\n//   scalar <--> float   //\n///////////////////////////\n\n/// @brief Set an infinite `float` value based on the given signedness.\n/// @param f The output `float` value holder.\n/// @param sign Whether the infinite value should be positive or negative.\ninline void set_infinity(float& f, const float sign) noexcept {\n    f = std::numeric_limits<float>::infinity() * sign;\n}\n\n/// @brief Set an infinite `double` value based on the given signedness.\n/// @param f The output `double` value holder.\n/// @param sign Whether the infinite value should be positive or negative.\ninline void set_infinity(double& f, const double sign) noexcept {\n    f = std::numeric_limits<double>::infinity() * sign;\n}\n\n/// @brief Set a NaN `float` value.\n/// @param f The output `float` value holder.\ninline void set_nan(float& f) noexcept {\n    f = std::nanf(\"\");\n}\n\n/// @brief Set a NaN `double` value.\n/// @param f The output `double` value holder.\ninline void set_nan(double& f) noexcept {\n    f = std::nan(\"\");\n}\n\n#if FK_YAML_HAS_TO_CHARS\n\n/// @brief Converts a scalar into a floating point value.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param f The output floating point value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename FloatType>\ninline bool atof_impl(const char* p_begin, const char* p_end, FloatType& f) noexcept {\n    static_assert(std::is_floating_point_v<FloatType>, \"atof_impl() accepts floating point types as an output type\");\n    if (auto [ptr, ec] = std::from_chars(p_begin, p_end, f); ec == std::errc {}) {\n        return ptr == p_end;\n    }\n    return false;\n}\n\n#else\n\n/// @brief Converts a scalar into a `float` value.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param f The output `float` value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ninline bool atof_impl(const char* p_begin, const char* p_end, float& f) {\n    std::size_t idx = 0;\n    f = std::stof(std::string(p_begin, p_end), &idx);\n    return idx == static_cast<std::size_t>(p_end - p_begin);\n}\n\n/// @brief Converts a scalar into a `double` value.\n/// @warning `p_begin` and `p_end` must not be null. Validate them before calling this function.\n/// @param p_begin The pointer to the first element of the scalar.\n/// @param p_end The pointer to the past-the-end element of the scalar.\n/// @param f The output `double` value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ninline bool atof_impl(const char* p_begin, const char* p_end, double& f) {\n    std::size_t idx = 0;\n    f = std::stod(std::string(p_begin, p_end), &idx);\n    return idx == static_cast<std::size_t>(p_end - p_begin);\n}\n\n#endif // FK_YAML_HAS_TO_CHARS\n\n/// @brief Converts a scalar into a floating point value.\n/// @tparam CharItr The type of char iterators. Its value type must be char (maybe cv-qualified).\n/// @tparam FloatType The output floating point value type.\n/// @param begin The iterator to the first element of the scalar.\n/// @param end The iterator to the past-the-end element of the scalar.\n/// @param f The output floating point value holder.\n/// @return true if the conversion completes successfully, false otherwise.\ntemplate <typename CharItr, typename FloatType>\ninline bool atof(CharItr begin, CharItr end, FloatType& f) noexcept(noexcept(atof_impl(&*begin, &*begin, f))) {\n    static_assert(is_iterator_of<CharItr, char>::value, \"atof() accepts iterators for char type\");\n    static_assert(std::is_floating_point<FloatType>::value, \"atof() accepts floating point types as an output type\");\n\n    if FK_YAML_UNLIKELY (begin == end) {\n        return false;\n    }\n\n    const auto len = static_cast<uint32_t>(std::distance(begin, end));\n    const char* p_begin = &*begin;\n    const char* p_end = p_begin + len;\n\n    if (*p_begin == '-' || *p_begin == '+') {\n        if (len == 5) {\n            const char* p_from_second = p_begin + 1;\n            const bool is_inf = (std::strncmp(p_from_second, \".inf\", 4) == 0) ||\n                                (std::strncmp(p_from_second, \".Inf\", 4) == 0) ||\n                                (std::strncmp(p_from_second, \".INF\", 4) == 0);\n            if (is_inf) {\n                set_infinity(f, *p_begin == '-' ? static_cast<FloatType>(-1.) : static_cast<FloatType>(1.));\n                return true;\n            }\n        }\n\n        if (*p_begin == '+') {\n            // Skip the positive sign since it's sometimes not recognized as part of float value.\n            ++p_begin;\n        }\n    }\n    else if (len == 4) {\n        const bool is_inf = (std::strncmp(p_begin, \".inf\", 4) == 0) || (std::strncmp(p_begin, \".Inf\", 4) == 0) ||\n                            (std::strncmp(p_begin, \".INF\", 4) == 0);\n        if (is_inf) {\n            set_infinity(f, static_cast<FloatType>(1.));\n            return true;\n        }\n\n        const bool is_nan = (std::strncmp(p_begin, \".nan\", 4) == 0) || (std::strncmp(p_begin, \".NaN\", 4) == 0) ||\n                            (std::strncmp(p_begin, \".NAN\", 4) == 0);\n        if (is_nan) {\n            set_nan(f);\n            return true;\n        }\n    }\n\n#if FK_YAML_HAS_TO_CHARS\n    return atof_impl(p_begin, p_end, f);\n#else\n    bool success = false;\n    try {\n        success = atof_impl(p_begin, p_end, f);\n    }\n    catch (const std::exception& /*unused*/) {\n        success = false;\n    }\n\n    return success;\n#endif\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_CONVERSIONS_SCALAR_CONV_HPP */\n\n// #include <fkYAML/detail/encodings/yaml_escaper.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ENCODINGS_YAML_ESCAPER_HPP\n#define FK_YAML_DETAIL_ENCODINGS_YAML_ESCAPER_HPP\n\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n// #include <fkYAML/detail/encodings/utf_encodings.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\nclass yaml_escaper {\n    using iterator = ::std::string::const_iterator;\n\npublic:\n    static bool unescape(const char*& begin, const char* end, std::string& buff) {\n        FK_YAML_ASSERT(*begin == '\\\\' && std::distance(begin, end) > 0);\n        bool ret = true;\n\n        switch (*++begin) {\n        case 'a':\n            buff.push_back('\\a');\n            break;\n        case 'b':\n            buff.push_back('\\b');\n            break;\n        case 't':\n        case '\\t':\n            buff.push_back('\\t');\n            break;\n        case 'n':\n            buff.push_back('\\n');\n            break;\n        case 'v':\n            buff.push_back('\\v');\n            break;\n        case 'f':\n            buff.push_back('\\f');\n            break;\n        case 'r':\n            buff.push_back('\\r');\n            break;\n        case 'e':\n            buff.push_back(static_cast<char>(0x1B));\n            break;\n        case ' ':\n            buff.push_back(' ');\n            break;\n        case '\\\"':\n            buff.push_back('\\\"');\n            break;\n        case '/':\n            buff.push_back('/');\n            break;\n        case '\\\\':\n            buff.push_back('\\\\');\n            break;\n        case 'N': // next line\n            unescape_escaped_unicode(0x85u, buff);\n            break;\n        case '_': // non-breaking space\n            unescape_escaped_unicode(0xA0u, buff);\n            break;\n        case 'L': // line separator\n            unescape_escaped_unicode(0x2028u, buff);\n            break;\n        case 'P': // paragraph separator\n            unescape_escaped_unicode(0x2029u, buff);\n            break;\n        case 'x': {\n            char32_t codepoint {0};\n            ret = extract_codepoint(begin, end, 1, codepoint);\n            if FK_YAML_LIKELY (ret) {\n                unescape_escaped_unicode(codepoint, buff);\n            }\n            break;\n        }\n        case 'u': {\n            char32_t codepoint {0};\n            ret = extract_codepoint(begin, end, 2, codepoint);\n            if FK_YAML_LIKELY (ret) {\n                unescape_escaped_unicode(codepoint, buff);\n            }\n            break;\n        }\n        case 'U': {\n            char32_t codepoint {0};\n            ret = extract_codepoint(begin, end, 4, codepoint);\n            if FK_YAML_LIKELY (ret) {\n                unescape_escaped_unicode(codepoint, buff);\n            }\n            break;\n        }\n        default:\n            // Unsupported escape sequence is found in a string token.\n            ret = false;\n            break;\n        }\n\n        return ret;\n    }\n\n    static ::std::string escape(const char* begin, const char* end, bool& is_escaped) {\n        ::std::string escaped {};\n        escaped.reserve(std::distance(begin, end));\n        for (; begin != end; ++begin) {\n            switch (*begin) {\n            case 0x01:\n                escaped += \"\\\\u0001\";\n                is_escaped = true;\n                break;\n            case 0x02:\n                escaped += \"\\\\u0002\";\n                is_escaped = true;\n                break;\n            case 0x03:\n                escaped += \"\\\\u0003\";\n                is_escaped = true;\n                break;\n            case 0x04:\n                escaped += \"\\\\u0004\";\n                is_escaped = true;\n                break;\n            case 0x05:\n                escaped += \"\\\\u0005\";\n                is_escaped = true;\n                break;\n            case 0x06:\n                escaped += \"\\\\u0006\";\n                is_escaped = true;\n                break;\n            case '\\a':\n                escaped += \"\\\\a\";\n                is_escaped = true;\n                break;\n            case '\\b':\n                escaped += \"\\\\b\";\n                is_escaped = true;\n                break;\n            case '\\t':\n                escaped += \"\\\\t\";\n                is_escaped = true;\n                break;\n            case '\\n':\n                escaped += \"\\\\n\";\n                is_escaped = true;\n                break;\n            case '\\v':\n                escaped += \"\\\\v\";\n                is_escaped = true;\n                break;\n            case '\\f':\n                escaped += \"\\\\f\";\n                is_escaped = true;\n                break;\n            case '\\r':\n                escaped += \"\\\\r\";\n                is_escaped = true;\n                break;\n            case 0x0E:\n                escaped += \"\\\\u000E\";\n                is_escaped = true;\n                break;\n            case 0x0F:\n                escaped += \"\\\\u000F\";\n                is_escaped = true;\n                break;\n            case 0x10:\n                escaped += \"\\\\u0010\";\n                is_escaped = true;\n                break;\n            case 0x11:\n                escaped += \"\\\\u0011\";\n                is_escaped = true;\n                break;\n            case 0x12:\n                escaped += \"\\\\u0012\";\n                is_escaped = true;\n                break;\n            case 0x13:\n                escaped += \"\\\\u0013\";\n                is_escaped = true;\n                break;\n            case 0x14:\n                escaped += \"\\\\u0014\";\n                is_escaped = true;\n                break;\n            case 0x15:\n                escaped += \"\\\\u0015\";\n                is_escaped = true;\n                break;\n            case 0x16:\n                escaped += \"\\\\u0016\";\n                is_escaped = true;\n                break;\n            case 0x17:\n                escaped += \"\\\\u0017\";\n                is_escaped = true;\n                break;\n            case 0x18:\n                escaped += \"\\\\u0018\";\n                is_escaped = true;\n                break;\n            case 0x19:\n                escaped += \"\\\\u0019\";\n                is_escaped = true;\n                break;\n            case 0x1A:\n                escaped += \"\\\\u001A\";\n                is_escaped = true;\n                break;\n            case 0x1B:\n                escaped += \"\\\\e\";\n                is_escaped = true;\n                break;\n            case 0x1C:\n                escaped += \"\\\\u001C\";\n                is_escaped = true;\n                break;\n            case 0x1D:\n                escaped += \"\\\\u001D\";\n                is_escaped = true;\n                break;\n            case 0x1E:\n                escaped += \"\\\\u001E\";\n                is_escaped = true;\n                break;\n            case 0x1F:\n                escaped += \"\\\\u001F\";\n                is_escaped = true;\n                break;\n            case '\\\"':\n                escaped += \"\\\\\\\"\";\n                is_escaped = true;\n                break;\n            case '\\\\':\n                escaped += \"\\\\\\\\\";\n                is_escaped = true;\n                break;\n            default:\n                const std::ptrdiff_t diff = static_cast<int>(std::distance(begin, end));\n                if (diff > 1) {\n                    if (*begin == static_cast<char>(0xC2u) && *(begin + 1) == static_cast<char>(0x85u)) {\n                        escaped += \"\\\\N\";\n                        std::advance(begin, 1);\n                        is_escaped = true;\n                        break;\n                    }\n                    if (*begin == static_cast<char>(0xC2u) && *(begin + 1) == static_cast<char>(0xA0u)) {\n                        escaped += \"\\\\_\";\n                        std::advance(begin, 1);\n                        is_escaped = true;\n                        break;\n                    }\n\n                    if (diff > 2) {\n                        if (*begin == static_cast<char>(0xE2u) && *(begin + 1) == static_cast<char>(0x80u) &&\n                            *(begin + 2) == static_cast<char>(0xA8u)) {\n                            escaped += \"\\\\L\";\n                            std::advance(begin, 2);\n                            is_escaped = true;\n                            break;\n                        }\n                        if (*begin == static_cast<char>(0xE2u) && *(begin + 1) == static_cast<char>(0x80u) &&\n                            *(begin + 2) == static_cast<char>(0xA9u)) {\n                            escaped += \"\\\\P\";\n                            std::advance(begin, 2);\n                            is_escaped = true;\n                            break;\n                        }\n                    }\n                }\n                escaped += *begin;\n                break;\n            }\n        }\n        return escaped;\n    } // LCOV_EXCL_LINE\n\nprivate:\n    static bool convert_hexchar_to_byte(char source, uint8_t& byte) {\n        if ('0' <= source && source <= '9') {\n            // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)\n            byte = static_cast<uint8_t>(source - '0');\n            return true;\n        }\n\n        if ('A' <= source && source <= 'F') {\n            // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)\n            byte = static_cast<uint8_t>(source - 'A' + 10);\n            return true;\n        }\n\n        if ('a' <= source && source <= 'f') {\n            // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)\n            byte = static_cast<uint8_t>(source - 'a' + 10);\n            return true;\n        }\n\n        // The given character is not hexadecimal.\n        return false;\n    }\n\n    static bool extract_codepoint(const char*& begin, const char* end, int bytes_to_read, char32_t& codepoint) {\n        const bool has_enough_room = static_cast<int>(std::distance(begin, end)) >= (bytes_to_read - 1);\n        if (!has_enough_room) {\n            return false;\n        }\n\n        const int read_size = bytes_to_read * 2;\n        uint8_t byte {0};\n        codepoint = 0;\n\n        for (int i = read_size - 1; i >= 0; i--) {\n            const bool is_valid = convert_hexchar_to_byte(*++begin, byte);\n            if (!is_valid) {\n                return false;\n            }\n            // NOLINTNEXTLINE(bugprone-narrowing-conversions,cppcoreguidelines-narrowing-conversions)\n            codepoint |= static_cast<char32_t>(byte << (4 * i));\n        }\n\n        return true;\n    }\n\n    static void unescape_escaped_unicode(char32_t codepoint, std::string& buff) {\n        // the inner curly braces are necessary to build with older compilers.\n        std::array<uint8_t, 4> encode_buff {{}};\n        uint32_t encoded_size {0};\n        utf8::from_utf32(codepoint, encode_buff, encoded_size);\n        buff.append(reinterpret_cast<char*>(encode_buff.data()), encoded_size);\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_ENCODINGS_YAML_ESCAPER_HPP */\n\n// #include <fkYAML/detail/input/block_scalar_header.hpp>\n\n// #include <fkYAML/detail/input/scalar_scanner.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_SCALAR_SCANNER_HPP\n#define FK_YAML_DETAIL_INPUT_SCALAR_SCANNER_HPP\n\n#include <cstring>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n// #include <fkYAML/node_type.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief The class which detects a scalar value type by scanning contents.\nclass scalar_scanner {\npublic:\n    /// @brief Detects a scalar value type by scanning the contents ranged by the given iterators.\n    /// @param begin The iterator to the first element of the scalar.\n    /// @param end The iterator to the past-the-end element of the scalar.\n    /// @return A detected scalar value type.\n    static node_type scan(const char* begin, const char* end) noexcept {\n        if (begin == end) {\n            return node_type::STRING;\n        }\n\n        const auto len = static_cast<uint32_t>(std::distance(begin, end));\n        if (len > 5) {\n            return scan_possible_number_token(begin, len);\n        }\n\n        const char* p_begin = &*begin;\n\n        switch (len) {\n        case 1:\n            if (*p_begin == '~') {\n                return node_type::NULL_OBJECT;\n            }\n            break;\n        case 4:\n            switch (*p_begin) {\n            case 'n':\n                // no possible case of begin a number otherwise.\n                return (std::strncmp(p_begin + 1, \"ull\", 3) == 0) ? node_type::NULL_OBJECT : node_type::STRING;\n            case 'N':\n                // no possible case of begin a number otherwise.\n                return ((std::strncmp(p_begin + 1, \"ull\", 3) == 0) || (std::strncmp(p_begin + 1, \"ULL\", 3) == 0))\n                           ? node_type::NULL_OBJECT\n                           : node_type::STRING;\n            case 't':\n                // no possible case of being a number otherwise.\n                return (std::strncmp(p_begin + 1, \"rue\", 3) == 0) ? node_type::BOOLEAN : node_type::STRING;\n            case 'T':\n                // no possible case of being a number otherwise.\n                return ((std::strncmp(p_begin + 1, \"rue\", 3) == 0) || (std::strncmp(p_begin + 1, \"RUE\", 3) == 0))\n                           ? node_type::BOOLEAN\n                           : node_type::STRING;\n            case '.': {\n                const char* p_from_second = p_begin + 1;\n                const bool is_inf_or_nan_scalar =\n                    (std::strncmp(p_from_second, \"inf\", 3) == 0) || (std::strncmp(p_from_second, \"Inf\", 3) == 0) ||\n                    (std::strncmp(p_from_second, \"INF\", 3) == 0) || (std::strncmp(p_from_second, \"nan\", 3) == 0) ||\n                    (std::strncmp(p_from_second, \"NaN\", 3) == 0) || (std::strncmp(p_from_second, \"NAN\", 3) == 0);\n                if (is_inf_or_nan_scalar) {\n                    return node_type::FLOAT;\n                }\n                // maybe a number.\n                break;\n            }\n            default:\n                break;\n            }\n            break;\n        case 5:\n            switch (*p_begin) {\n            case 'f':\n                // no possible case of being a number otherwise.\n                return (std::strncmp(p_begin + 1, \"alse\", 4) == 0) ? node_type::BOOLEAN : node_type::STRING;\n            case 'F':\n                // no possible case of being a number otherwise.\n                return ((std::strncmp(p_begin + 1, \"alse\", 4) == 0) || (std::strncmp(p_begin + 1, \"ALSE\", 4) == 0))\n                           ? node_type::BOOLEAN\n                           : node_type::STRING;\n            case '+':\n            case '-':\n                if (*(p_begin + 1) == '.') {\n                    const char* p_from_third = p_begin + 2;\n                    const bool is_min_inf = (std::strncmp(p_from_third, \"inf\", 3) == 0) ||\n                                            (std::strncmp(p_from_third, \"Inf\", 3) == 0) ||\n                                            (std::strncmp(p_from_third, \"INF\", 3) == 0);\n                    if (is_min_inf) {\n                        return node_type::FLOAT;\n                    }\n                }\n                // maybe a number.\n                break;\n            default:\n                break;\n            }\n            break;\n        default:\n            break;\n        }\n\n        return scan_possible_number_token(begin, len);\n    }\n\nprivate:\n    /// @brief Detects a scalar value type from the contents (possibly an integer or a floating-point value).\n    /// @param itr The iterator to the first element of the scalar.\n    /// @param len The length of the scalar contents.\n    /// @return A detected scalar value type.\n    static node_type scan_possible_number_token(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        switch (*itr) {\n        case '-':\n            return (len > 1) ? scan_negative_number(++itr, --len) : node_type::STRING;\n        case '+':\n            return (len > 1) ? scan_decimal_number(++itr, --len) : node_type::STRING;\n        case '.':\n            // some integer(s) required after the decimal point as a floating point value.\n            return (len > 1) ? scan_after_decimal_point(++itr, --len) : node_type::STRING;\n        case '0':\n            return (len > 1) ? scan_after_zero_at_first(++itr, --len) : node_type::INTEGER;\n        case '1':\n        case '2':\n        case '3':\n        case '4':\n        case '5':\n        case '6':\n        case '7':\n        case '8':\n        case '9':\n            return (len > 1) ? scan_decimal_number(++itr, --len) : node_type::INTEGER;\n        default:\n            return node_type::STRING;\n        }\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents right after the negative sign.\n    /// @param itr The iterator to the past-the-negative-sign element of the scalar.\n    /// @param len The length of the scalar contents left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_negative_number(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        if (is_digit(*itr)) {\n            return (len > 1) ? scan_decimal_number(++itr, --len) : node_type::INTEGER;\n        }\n\n        if (*itr == '.') {\n            // some integer(s) required after \"-.\" as a floating point value.\n            return (len > 1) ? scan_after_decimal_point(++itr, --len) : node_type::STRING;\n        }\n\n        return node_type::STRING;\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents right after the beginning 0.\n    /// @param itr The iterator to the past-the-zero element of the scalar.\n    /// @param len The length of the scalar left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_after_zero_at_first(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        if (is_digit(*itr)) {\n            // a token consisting of the beginning '0' and some following numbers, e.g., `0123`, is not an integer\n            // according to https://yaml.org/spec/1.2.2/#10213-integer.\n            return node_type::STRING;\n        }\n\n        switch (*itr) {\n        case '.':\n            // 0 can be omitted after `0.`.\n            return (len > 1) ? scan_after_decimal_point(++itr, --len) : node_type::FLOAT;\n        case 'e':\n        case 'E':\n            // some integer(s) required after the exponent sign as a floating point value.\n            return (len > 1) ? scan_after_exponent(++itr, --len) : node_type::STRING;\n        case 'o':\n            return (len > 1) ? scan_octal_number(++itr, --len) : node_type::STRING;\n        case 'x':\n            return (len > 1) ? scan_hexadecimal_number(++itr, --len) : node_type::STRING;\n        default:\n            return node_type::STRING;\n        }\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents part starting with a decimal.\n    /// @param itr The iterator to the beginning decimal element of the scalar.\n    /// @param len The length of the scalar left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_decimal_number(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        if (is_digit(*itr)) {\n            return (len > 1) ? scan_decimal_number(++itr, --len) : node_type::INTEGER;\n        }\n\n        switch (*itr) {\n        case '.': {\n            // 0 can be omitted after the decimal point\n            return (len > 1) ? scan_after_decimal_point(++itr, --len) : node_type::FLOAT;\n        }\n        case 'e':\n        case 'E':\n            // some integer(s) required after the exponent\n            return (len > 1) ? scan_after_exponent(++itr, --len) : node_type::STRING;\n        default:\n            return node_type::STRING;\n        }\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents right after a decimal point.\n    /// @param itr The iterator to the past-the-decimal-point element of the scalar.\n    /// @param len The length of the scalar left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_after_decimal_point(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        for (uint32_t i = 0; i < len; i++) {\n            const char c = *itr++;\n\n            if (is_digit(c)) {\n                continue;\n            }\n\n            if (c == 'e' || c == 'E') {\n                if (i == len - 1) {\n                    // some integer(s) required after the exponent\n                    return node_type::STRING;\n                }\n                return scan_after_exponent(itr, len - i - 1);\n            }\n\n            return node_type::STRING;\n        }\n\n        return node_type::FLOAT;\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents right after the exponent prefix (\"e\" or \"E\").\n    /// @param itr The iterator to the past-the-exponent-prefix element of the scalar.\n    /// @param len The length of the scalar left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_after_exponent(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        const char c = *itr;\n        if (c == '+' || c == '-') {\n            if (len == 1) {\n                // some integer(s) required after the sign.\n                return node_type::STRING;\n            }\n            ++itr;\n            --len;\n        }\n\n        for (uint32_t i = 0; i < len; i++) {\n            if (!is_digit(*itr++)) {\n                return node_type::STRING;\n            }\n        }\n\n        return node_type::FLOAT;\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents assuming octal numbers.\n    /// @param itr The iterator to the octal-number element of the scalar.\n    /// @param len The length of the scalar left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_octal_number(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        switch (*itr) {\n        case '0':\n        case '1':\n        case '2':\n        case '3':\n        case '4':\n        case '5':\n        case '6':\n        case '7':\n            return (len > 1) ? scan_octal_number(++itr, --len) : node_type::INTEGER;\n        default:\n            return node_type::STRING;\n        }\n    }\n\n    /// @brief Detects a scalar value type by scanning the contents assuming hexadecimal numbers.\n    /// @param itr The iterator to the hexadecimal-number element of the scalar.\n    /// @param len The length of the scalar left unscanned.\n    /// @return A detected scalar value type.\n    static node_type scan_hexadecimal_number(const char* itr, uint32_t len) noexcept {\n        FK_YAML_ASSERT(len > 0);\n\n        if (is_xdigit(*itr)) {\n            return (len > 1) ? scan_hexadecimal_number(++itr, --len) : node_type::INTEGER;\n        }\n        return node_type::STRING;\n    }\n\n    /// @brief Check if the given character is a digit.\n    /// @note This function is needed to avoid assertion failures in `std::isdigit()` especially when compiled with\n    /// MSVC.\n    /// @param c A character to be checked.\n    /// @return true if the given character is a digit, false otherwise.\n    static bool is_digit(char c) {\n        return ('0' <= c && c <= '9');\n    }\n\n    /// @brief Check if the given character is a hex-digit.\n    /// @note This function is needed to avoid assertion failures in `std::isxdigit()` especially when compiled with\n    /// MSVC.\n    /// @param c A character to be checked.\n    /// @return true if the given character is a hex-digit, false otherwise.\n    static bool is_xdigit(char c) {\n        return (('0' <= c && c <= '9') || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f'));\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_SCALAR_SCANNER_HPP */\n\n// #include <fkYAML/detail/input/tag_t.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_TAG_T_HPP\n#define FK_YAML_DETAIL_INPUT_TAG_T_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Definition of YAML tag types.\nenum class tag_t : std::uint8_t {\n    NONE,            //!< Represents a non-specific tag \"?\".\n    NON_SPECIFIC,    //!< Represents a non-specific tag \"!\".\n    CUSTOM_TAG,      //!< Represents a custom tag\n    SEQUENCE,        //!< Represents a sequence tag.\n    MAPPING,         //!< Represents a mapping tag.\n    NULL_VALUE,      //!< Represents a null value tag.\n    BOOLEAN,         //!< Represents a boolean tag.\n    INTEGER,         //!< Represents an integer type\n    FLOATING_NUMBER, //!< Represents a floating point number tag.\n    STRING,          //!< Represents a string tag.\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_TAG_T_HPP */\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/str_view.hpp>\n\n// #include <fkYAML/detail/types/lexical_token_t.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n// #include <fkYAML/node_type.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A parser for YAML scalars.\n/// @tparam BasicNodeType A type of the container for parsed YAML scalars.\ntemplate <typename BasicNodeType>\nclass scalar_parser {\n    static_assert(is_basic_node<BasicNodeType>::value, \"scalar_parser only accepts basic_node<...>\");\n\npublic:\n    using basic_node_type = BasicNodeType;\n\nprivate:\n    /** A type for boolean node values. */\n    using boolean_type = typename basic_node_type::boolean_type;\n    /** A type for integer node values. */\n    using integer_type = typename basic_node_type::integer_type;\n    /** A type for floating point node values. */\n    using float_number_type = typename basic_node_type::float_number_type;\n    /** A type for string node values. */\n    using string_type = typename basic_node_type::string_type;\n\npublic:\n    /// @brief Constructs a new scalar_parser object.\n    /// @param line Current line.\n    /// @param indent Current indentation.\n    scalar_parser(uint32_t line, uint32_t indent) noexcept\n        : m_line(line),\n          m_indent(indent) {\n    }\n\n    /// @brief Destroys a scalar_parser object.\n    ~scalar_parser() noexcept = default;\n\n    // std::string's copy constructor/assignment operator may throw a exception.\n    scalar_parser(const scalar_parser&) = default;\n    scalar_parser& operator=(const scalar_parser&) = default;\n\n    scalar_parser(scalar_parser&&) noexcept = default;\n    scalar_parser& operator=(scalar_parser&&) noexcept(std::is_nothrow_move_assignable<std::string>::value) = default;\n\n    /// @brief Parses a token into a flow scalar (either plain, single quoted or double quoted)\n    /// @param lex_type Lexical token type for the scalar.\n    /// @param tag_type Tag type for the scalar.\n    /// @param token Scalar contents.\n    /// @return Parsed YAML flow scalar object.\n    basic_node_type parse_flow(lexical_token_t lex_type, tag_t tag_type, str_view token) {\n        FK_YAML_ASSERT(\n            lex_type == lexical_token_t::PLAIN_SCALAR || lex_type == lexical_token_t::SINGLE_QUOTED_SCALAR ||\n            lex_type == lexical_token_t::DOUBLE_QUOTED_SCALAR);\n        FK_YAML_ASSERT(tag_type != tag_t::SEQUENCE && tag_type != tag_t::MAPPING);\n\n        token = parse_flow_scalar_token(lex_type, token);\n        const node_type value_type = decide_value_type(lex_type, tag_type, token);\n        return create_scalar_node(value_type, tag_type, token);\n    }\n\n    /// @brief Parses a token into a block scalar (either literal or folded)\n    /// @param lex_type Lexical token type for the scalar.\n    /// @param tag_type Tag type for the scalar.\n    /// @param token Scalar contents.\n    /// @param header Block scalar header information.\n    /// @return Parsed YAML block scalar object.\n    basic_node_type parse_block(\n        lexical_token_t lex_type, tag_t tag_type, str_view token, const block_scalar_header& header) {\n        FK_YAML_ASSERT(\n            lex_type == lexical_token_t::BLOCK_LITERAL_SCALAR || lex_type == lexical_token_t::BLOCK_FOLDED_SCALAR);\n        FK_YAML_ASSERT(tag_type != tag_t::SEQUENCE && tag_type != tag_t::MAPPING);\n\n        if (lex_type == lexical_token_t::BLOCK_LITERAL_SCALAR) {\n            token = parse_block_literal_scalar(token, header);\n        }\n        else {\n            token = parse_block_folded_scalar(token, header);\n        }\n\n        const node_type value_type = decide_value_type(lex_type, tag_type, token);\n        return create_scalar_node(value_type, tag_type, token);\n    }\n\nprivate:\n    /// @brief Parses a token into a flow scalar contents.\n    /// @param lex_type Lexical token type for the scalar.\n    /// @param token Scalar contents.\n    /// @return View into the parsed scalar contents.\n    str_view parse_flow_scalar_token(lexical_token_t lex_type, str_view token) {\n        switch (lex_type) {\n        case lexical_token_t::PLAIN_SCALAR:\n            token = parse_plain_scalar(token);\n            break;\n        case lexical_token_t::SINGLE_QUOTED_SCALAR:\n            token = parse_single_quoted_scalar(token);\n            break;\n        case lexical_token_t::DOUBLE_QUOTED_SCALAR:\n            token = parse_double_quoted_scalar(token);\n            break;\n        default:           // LCOV_EXCL_LINE\n            unreachable(); // LCOV_EXCL_LINE\n        }\n\n        return token;\n    }\n\n    /// @brief Parses plain scalar contents.\n    /// @param token Scalar contents.\n    /// @return View into the parsed scalar contents.\n    str_view parse_plain_scalar(str_view token) noexcept {\n        // plain scalars cannot be empty.\n        FK_YAML_ASSERT(!token.empty());\n\n        std::size_t newline_pos = token.find('\\n');\n        if (newline_pos == str_view::npos) {\n            return token;\n        }\n\n        m_use_owned_buffer = true;\n\n        if (m_buffer.capacity() < token.size()) {\n            m_buffer.reserve(token.size());\n        }\n\n        do {\n            process_line_folding(token, newline_pos);\n            newline_pos = token.find('\\n');\n        } while (newline_pos != str_view::npos);\n\n        m_buffer.append(token.begin(), token.size());\n\n        return {m_buffer};\n    }\n\n    /// @brief Parses single quoted scalar contents.\n    /// @param token Scalar contents.\n    /// @return View into the parsed scalar contents.\n    str_view parse_single_quoted_scalar(str_view token) noexcept {\n        if (token.empty()) {\n            return token;\n        }\n\n        constexpr str_view filter {\"\\'\\n\"};\n        std::size_t pos = token.find_first_of(filter);\n        if (pos == str_view::npos) {\n            return token;\n        }\n\n        m_use_owned_buffer = true;\n\n        if (m_buffer.capacity() < token.size()) {\n            m_buffer.reserve(token.size());\n        }\n\n        do {\n            FK_YAML_ASSERT(pos < token.size());\n            FK_YAML_ASSERT(token[pos] == '\\'' || token[pos] == '\\n');\n\n            if (token[pos] == '\\'') {\n                // unescape escaped single quote. ('' -> ')\n                FK_YAML_ASSERT(pos + 1 < token.size());\n                m_buffer.append(token.begin(), token.begin() + (pos + 1));\n                token.remove_prefix(pos + 2); // move next to the escaped single quote.\n            }\n            else {\n                process_line_folding(token, pos);\n            }\n\n            pos = token.find_first_of(filter);\n        } while (pos != str_view::npos);\n\n        if (!token.empty()) {\n            m_buffer.append(token.begin(), token.size());\n        }\n\n        return {m_buffer};\n    }\n\n    /// @brief Parses double quoted scalar contents.\n    /// @param token Scalar contents.\n    /// @return View into the parsed scalar contents.\n    str_view parse_double_quoted_scalar(str_view token) {\n        if (token.empty()) {\n            return token;\n        }\n\n        constexpr str_view filter {\"\\\\\\n\"};\n        std::size_t pos = token.find_first_of(filter);\n        if (pos == str_view::npos) {\n            return token;\n        }\n\n        m_use_owned_buffer = true;\n\n        if (m_buffer.capacity() < token.size()) {\n            m_buffer.reserve(token.size());\n        }\n\n        do {\n            FK_YAML_ASSERT(pos < token.size());\n            FK_YAML_ASSERT(token[pos] == '\\\\' || token[pos] == '\\n');\n\n            if (token[pos] == '\\\\') {\n                FK_YAML_ASSERT(pos + 1 < token.size());\n                m_buffer.append(token.begin(), token.begin() + pos);\n\n                if (token[pos + 1] != '\\n') {\n                    token.remove_prefix(pos);\n                    const char* p_escape_begin = token.begin();\n                    const bool is_valid_escaping = yaml_escaper::unescape(p_escape_begin, token.end(), m_buffer);\n                    if FK_YAML_UNLIKELY (!is_valid_escaping) {\n                        throw parse_error(\n                            \"Unsupported escape sequence is found in a double quoted scalar.\", m_line, m_indent);\n                    }\n\n                    // `p_escape_begin` points to the last element of the escape sequence.\n                    token.remove_prefix((p_escape_begin - token.begin()) + 1);\n                }\n                else {\n                    std::size_t non_space_pos = token.find_first_not_of(\" \\t\", pos + 2);\n                    if (non_space_pos == str_view::npos) {\n                        non_space_pos = token.size();\n                    }\n                    token.remove_prefix(non_space_pos);\n                }\n            }\n            else {\n                process_line_folding(token, pos);\n            }\n\n            pos = token.find_first_of(filter);\n        } while (pos != str_view::npos);\n\n        if (!token.empty()) {\n            m_buffer.append(token.begin(), token.size());\n        }\n\n        return {m_buffer};\n    }\n\n    /// @brief Parses block literal scalar contents.\n    /// @param token Scalar contents.\n    /// @param header Block scalar header information.\n    /// @return View into the parsed scalar contents.\n    str_view parse_block_literal_scalar(str_view token, const block_scalar_header& header) {\n        if FK_YAML_UNLIKELY (token.empty()) {\n            return token;\n        }\n\n        m_use_owned_buffer = true;\n        m_buffer.reserve(token.size());\n\n        std::size_t cur_line_begin_pos = 0;\n        do {\n            bool has_newline_at_end = true;\n            std::size_t cur_line_end_pos = token.find('\\n', cur_line_begin_pos);\n            if (cur_line_end_pos == str_view::npos) {\n                has_newline_at_end = false;\n                cur_line_end_pos = token.size();\n            }\n\n            const std::size_t line_size = cur_line_end_pos - cur_line_begin_pos;\n            const str_view line = token.substr(cur_line_begin_pos, line_size);\n\n            if (line.size() > header.indent) {\n                m_buffer.append(line.begin() + header.indent, line.end());\n            }\n\n            if (!has_newline_at_end) {\n                break;\n            }\n\n            m_buffer.push_back('\\n');\n            cur_line_begin_pos = cur_line_end_pos + 1;\n        } while (cur_line_begin_pos < token.size());\n\n        process_chomping(header.chomp);\n\n        return {m_buffer};\n    }\n\n    /// @brief Parses block folded scalar contents.\n    /// @param token Scalar contents.\n    /// @param header Block scalar header information.\n    /// @return View into the parsed scalar contents.\n    str_view parse_block_folded_scalar(str_view token, const block_scalar_header& header) {\n        if FK_YAML_UNLIKELY (token.empty()) {\n            return token;\n        }\n\n        m_use_owned_buffer = true;\n        m_buffer.reserve(token.size());\n\n        constexpr str_view white_space_filter {\" \\t\"};\n\n        std::size_t cur_line_begin_pos = 0;\n        bool has_newline_at_end = true;\n        bool can_be_folded = false;\n        do {\n            std::size_t cur_line_end_pos = token.find('\\n', cur_line_begin_pos);\n            if (cur_line_end_pos == str_view::npos) {\n                has_newline_at_end = false;\n                cur_line_end_pos = token.size();\n            }\n\n            const std::size_t line_size = cur_line_end_pos - cur_line_begin_pos;\n            const str_view line = token.substr(cur_line_begin_pos, line_size);\n            const bool is_empty = line.find_first_not_of(white_space_filter) == str_view::npos;\n\n            if (line.size() <= header.indent) {\n                // A less-indented line is turned into a newline.\n                m_buffer.push_back('\\n');\n                can_be_folded = false;\n            }\n            else if (is_empty) {\n                // more-indented empty lines are not folded.\n                m_buffer.push_back('\\n');\n                m_buffer.append(line.begin() + header.indent, line.end());\n                m_buffer.push_back('\\n');\n            }\n            else {\n                const std::size_t non_space_pos = line.find_first_not_of(white_space_filter);\n                const bool is_more_indented = (non_space_pos != str_view::npos) && (non_space_pos > header.indent);\n\n                if (can_be_folded) {\n                    if (is_more_indented) {\n                        // The content line right before more-indented lines is not folded.\n                        m_buffer.push_back('\\n');\n                    }\n                    else {\n                        m_buffer.push_back(' ');\n                    }\n\n                    can_be_folded = false;\n                }\n\n                m_buffer.append(line.begin() + header.indent, line.end());\n\n                if (is_more_indented && has_newline_at_end) {\n                    // more-indented lines are not folded.\n                    m_buffer.push_back('\\n');\n                }\n                else {\n                    can_be_folded = true;\n                }\n            }\n\n            if (!has_newline_at_end) {\n                break;\n            }\n\n            cur_line_begin_pos = cur_line_end_pos + 1;\n        } while (cur_line_begin_pos < token.size());\n\n        if (has_newline_at_end && can_be_folded) {\n            // The final content line break are not folded.\n            m_buffer.push_back('\\n');\n        }\n\n        process_chomping(header.chomp);\n\n        return {m_buffer};\n    }\n\n    /// @brief Discards final content line break and trailing empty lines depending on the given chomping type.\n    /// @param chomp Chomping method type.\n    void process_chomping(chomping_indicator_t chomp) {\n        switch (chomp) {\n        case chomping_indicator_t::STRIP: {\n            const std::size_t content_end_pos = m_buffer.find_last_not_of('\\n');\n            if (content_end_pos == std::string::npos) {\n                // if the scalar has no content line, all lines are considered as trailing empty lines.\n                m_buffer.clear();\n                break;\n            }\n\n            if (content_end_pos == m_buffer.size() - 1) {\n                // no last content line break nor trailing empty lines.\n                break;\n            }\n\n            // remove the last content line break and all trailing empty lines.\n            m_buffer.erase(content_end_pos + 1);\n\n            break;\n        }\n        case chomping_indicator_t::CLIP: {\n            const std::size_t content_end_pos = m_buffer.find_last_not_of('\\n');\n            if (content_end_pos == std::string::npos) {\n                // if the scalar has no content line, all lines are considered as trailing empty lines.\n                m_buffer.clear();\n                break;\n            }\n\n            if (content_end_pos == m_buffer.size() - 1) {\n                // no trailing empty lines\n                break;\n            }\n\n            // remove all trailing empty lines.\n            m_buffer.erase(content_end_pos + 2);\n\n            break;\n        }\n        case chomping_indicator_t::KEEP:\n            break;\n        }\n    }\n\n    /// @brief Applies line folding to flow scalar contents.\n    /// @param token Flow scalar contents.\n    /// @param newline_pos Position of the target newline code.\n    void process_line_folding(str_view& token, std::size_t newline_pos) noexcept {\n        // discard trailing white spaces which precedes the line break in the current line.\n        const std::size_t last_non_space_pos = token.substr(0, newline_pos + 1).find_last_not_of(\" \\t\");\n        if (last_non_space_pos == str_view::npos) {\n            m_buffer.append(token.begin(), newline_pos);\n        }\n        else {\n            m_buffer.append(token.begin(), last_non_space_pos + 1);\n        }\n        token.remove_prefix(newline_pos + 1); // move next to the LF\n\n        uint32_t empty_line_counts = 0;\n        do {\n            const std::size_t non_space_pos = token.find_first_not_of(\" \\t\");\n            if (non_space_pos == str_view::npos) {\n                // Line folding ignores trailing spaces.\n                token.remove_prefix(token.size());\n                break;\n            }\n            if (token[non_space_pos] != '\\n') {\n                token.remove_prefix(non_space_pos);\n                break;\n            }\n\n            token.remove_prefix(non_space_pos + 1);\n            ++empty_line_counts;\n        } while (true);\n\n        if (empty_line_counts > 0) {\n            m_buffer.append(empty_line_counts, '\\n');\n        }\n        else {\n            m_buffer.push_back(' ');\n        }\n    }\n\n    /// @brief Decides scalar value type based on the lexical/tag types and scalar contents.\n    /// @param lex_type Lexical token type for the scalar.\n    /// @param tag_type Tag type for the scalar.\n    /// @param token Scalar contents.\n    /// @return Scalar value type.\n    node_type decide_value_type(lexical_token_t lex_type, tag_t tag_type, str_view token) const noexcept {\n        node_type value_type {node_type::STRING};\n        if (lex_type == lexical_token_t::PLAIN_SCALAR) {\n            value_type = scalar_scanner::scan(token.begin(), token.end());\n        }\n\n        switch (tag_type) {\n        case tag_t::NULL_VALUE:\n            value_type = node_type::NULL_OBJECT;\n            break;\n        case tag_t::BOOLEAN:\n            value_type = node_type::BOOLEAN;\n            break;\n        case tag_t::INTEGER:\n            value_type = node_type::INTEGER;\n            break;\n        case tag_t::FLOATING_NUMBER:\n            value_type = node_type::FLOAT;\n            break;\n        case tag_t::STRING:\n        case tag_t::NON_SPECIFIC:\n            // scalars with the non-specific tag is resolved to a string tag.\n            // See the \"Non-Specific Tags\" section in https://yaml.org/spec/1.2.2/#691-node-tags.\n            value_type = node_type::STRING;\n            break;\n        case tag_t::NONE:\n        case tag_t::CUSTOM_TAG:\n        default:\n            break;\n        }\n\n        return value_type;\n    }\n\n    /// @brief Creates YAML scalar object based on the value type and contents.\n    /// @param type Scalar value type.\n    /// @param token Scalar contents.\n    /// @return A YAML scalar object.\n    basic_node_type create_scalar_node(node_type val_type, tag_t tag_type, str_view token) {\n        switch (val_type) {\n        case node_type::NULL_OBJECT: {\n            std::nullptr_t null = nullptr;\n            const bool converted = detail::aton(token.begin(), token.end(), null);\n            if FK_YAML_UNLIKELY (!converted) {\n                throw parse_error(\"Failed to convert a scalar to a null.\", m_line, m_indent);\n            }\n            // The default basic_node object is a null scalar node.\n            return basic_node_type {};\n        }\n        case node_type::BOOLEAN: {\n            auto boolean = static_cast<boolean_type>(false);\n            const bool converted = detail::atob(token.begin(), token.end(), boolean);\n            if FK_YAML_UNLIKELY (!converted) {\n                throw parse_error(\"Failed to convert a scalar to a boolean.\", m_line, m_indent);\n            }\n            return basic_node_type(boolean);\n        }\n        case node_type::INTEGER: {\n            integer_type integer = 0;\n            const bool converted = detail::atoi(token.begin(), token.end(), integer);\n            if FK_YAML_LIKELY (converted) {\n                return basic_node_type(integer);\n            }\n            if FK_YAML_UNLIKELY (tag_type == tag_t::INTEGER) {\n                throw parse_error(\"Failed to convert a scalar to an integer.\", m_line, m_indent);\n            }\n\n            // conversion error from a scalar which is not tagged with !!int is recovered by treating it as a string\n            // scalar. See https://github.com/fktn-k/fkYAML/issues/428.\n            return basic_node_type(string_type(token.begin(), token.end()));\n        }\n        case node_type::FLOAT: {\n            float_number_type float_val = 0;\n            const bool converted = detail::atof(token.begin(), token.end(), float_val);\n            if FK_YAML_LIKELY (converted) {\n                return basic_node_type(float_val);\n            }\n            if FK_YAML_UNLIKELY (tag_type == tag_t::FLOATING_NUMBER) {\n                throw parse_error(\"Failed to convert a scalar to a floating point value\", m_line, m_indent);\n            }\n\n            // conversion error from a scalar which is not tagged with !!float is recovered by treating it as a string\n            // scalar. See https://github.com/fktn-k/fkYAML/issues/428.\n            return basic_node_type(string_type(token.begin(), token.end()));\n        }\n        case node_type::STRING:\n            if (!m_use_owned_buffer) {\n                return basic_node_type(string_type(token.begin(), token.end()));\n            }\n            m_use_owned_buffer = false;\n            return basic_node_type(std::move(m_buffer));\n        default:                   // LCOV_EXCL_LINE\n            detail::unreachable(); // LCOV_EXCL_LINE\n        }\n    }\n\n    /// Current line\n    uint32_t m_line {0};\n    /// Current indentation for the scalar\n    uint32_t m_indent {0};\n    /// Whether the parsed contents are stored in an owned buffer.\n    bool m_use_owned_buffer {false};\n    /// Owned buffer storage for parsing. This buffer is used when scalar contents need mutation.\n    std::string m_buffer;\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_SCALAR_PARSER_HPP */\n\n// #include <fkYAML/detail/input/tag_resolver.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_TAG_RESOLVER_HPP\n#define FK_YAML_DETAIL_INPUT_TAG_RESOLVER_HPP\n\n#include <memory>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n// #include <fkYAML/detail/document_metainfo.hpp>\n\n// #include <fkYAML/detail/input/tag_t.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/str_view.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\nstatic constexpr str_view default_primary_handle_prefix {\"!\"};\nstatic constexpr str_view default_secondary_handle_prefix {\"tag:yaml.org,2002:\"};\n\ntemplate <typename BasicNodeType>\nclass tag_resolver {\n    static_assert(is_basic_node<BasicNodeType>::value, \"tag_resolver only accepts basic_node<...>.\");\n    using doc_metainfo_type = document_metainfo<BasicNodeType>;\n\npublic:\n    /// @brief Resolve the input tag name into an expanded tag name prepended with a registered prefix.\n    /// @param tag The input tag name.\n    /// @return The type of a node deduced from the given tag name.\n    static tag_t resolve_tag(const str_view tag, const std::shared_ptr<doc_metainfo_type>& directives) {\n        const std::string normalized = normalize_tag_name(tag, directives);\n        return convert_to_tag_type(normalized);\n    }\n\nprivate:\n    static std::string normalize_tag_name(const str_view tag, const std::shared_ptr<doc_metainfo_type>& directives) {\n        if FK_YAML_UNLIKELY (tag.empty()) {\n            throw invalid_tag(\"tag must not be empty.\", \"\");\n        }\n        if FK_YAML_UNLIKELY (tag[0] != '!') {\n            throw invalid_tag(\"tag must start with \\'!\\'\", std::string(tag.begin(), tag.end()).c_str());\n        }\n\n        if (tag.size() == 1) {\n            // Non-specific tag (\"!\") will be interpreted as one of the following:\n            //   * tag:yaml.org,2002:seq\n            //   * tag:yaml.org,2002:map\n            //   * tag:yaml.org,2002:str\n            // See the \"Non-Specific Tags\" section in https://yaml.org/spec/1.2.2/#691-node-tags.\n            // The interpretation cannot take place here because the input lacks the corresponding value.\n            return {tag.begin(), tag.end()};\n        }\n\n        std::string normalized {\"!<\"};\n        switch (tag[1]) {\n        case '!': {\n            // handle a secondary tag handle (!!suffix -> !<[secondary][suffix]>)\n            const bool is_null_or_empty = !directives || directives->secondary_handle_prefix.empty();\n            if (is_null_or_empty) {\n                normalized.append(default_secondary_handle_prefix.begin(), default_secondary_handle_prefix.end());\n            }\n            else {\n                normalized += directives->secondary_handle_prefix;\n            }\n\n            const str_view body = tag.substr(2);\n            normalized.append(body.begin(), body.end());\n            break;\n        }\n        case '<':\n            if (tag[2] == '!') {\n                const bool is_null_or_empty = !directives || directives->primary_handle_prefix.empty();\n                if (is_null_or_empty) {\n                    normalized.append(default_primary_handle_prefix.begin(), default_primary_handle_prefix.end());\n                }\n                else {\n                    normalized += directives->primary_handle_prefix;\n                }\n\n                const str_view body = tag.substr(3);\n                return normalized.append(body.begin(), body.end());\n            }\n\n            // verbatim tags must be delivered as-is to the application.\n            // See https://yaml.org/spec/1.2.2/#691-node-tags for more details.\n            return {tag.begin(), tag.end()};\n        default: {\n            const std::size_t tag_end_pos = tag.find_first_of('!', 1);\n\n            // handle a named handle (!tag!suffix -> !<[tag][suffix]>)\n            if (tag_end_pos != std::string::npos) {\n                // there must be a non-empty suffix. (already checked by the lexer.)\n                FK_YAML_ASSERT(tag_end_pos < tag.size() - 1);\n\n                const bool is_null_or_empty = !directives || directives->named_handle_map.empty();\n                if FK_YAML_UNLIKELY (is_null_or_empty) {\n                    throw invalid_tag(\n                        \"named handle has not been registered.\", std::string(tag.begin(), tag.end()).c_str());\n                }\n\n                // find the extracted named handle in the map.\n                const str_view named_handle = tag.substr(0, tag_end_pos + 1);\n                auto named_handle_itr = directives->named_handle_map.find({named_handle.begin(), named_handle.end()});\n                auto end_itr = directives->named_handle_map.end();\n                if FK_YAML_UNLIKELY (named_handle_itr == end_itr) {\n                    throw invalid_tag(\n                        \"named handle has not been registered.\", std::string(tag.begin(), tag.end()).c_str());\n                }\n\n                // The YAML spec prohibits expanding the percent-encoded characters (%xx -> a UTF-8 byte).\n                // So no conversion takes place.\n                // See https://yaml.org/spec/1.2.2/#56-miscellaneous-characters for more details.\n\n                normalized += named_handle_itr->second;\n                const str_view body = tag.substr(tag_end_pos + 1);\n                normalized.append(body.begin(), body.end());\n                break;\n            }\n\n            // handle a primary tag handle (!suffix -> !<[primary][suffix]>)\n            const bool is_null_or_empty = !directives || directives->primary_handle_prefix.empty();\n            if (is_null_or_empty) {\n                normalized.append(default_primary_handle_prefix.begin(), default_primary_handle_prefix.end());\n            }\n            else {\n                normalized += directives->primary_handle_prefix;\n            }\n\n            const str_view body = tag.substr(1);\n            normalized.append(body.begin(), body.end());\n            break;\n        }\n        }\n\n        normalized += \">\";\n        return normalized;\n    }\n\n    static tag_t convert_to_tag_type(const std::string& normalized) {\n        if (normalized == \"!\") {\n            return tag_t::NON_SPECIFIC;\n        }\n\n        if (normalized.size() < 24 /* size of !<tag:yaml.org,2002:xxx */) {\n            return tag_t::CUSTOM_TAG;\n        }\n        if (normalized.rfind(\"!<tag:yaml.org,2002:\", 0) == std::string::npos) {\n            return tag_t::CUSTOM_TAG;\n        }\n\n        if (normalized == \"!<tag:yaml.org,2002:seq>\") {\n            return tag_t::SEQUENCE;\n        }\n        if (normalized == \"!<tag:yaml.org,2002:map>\") {\n            return tag_t::MAPPING;\n        }\n        if (normalized == \"!<tag:yaml.org,2002:null>\") {\n            return tag_t::NULL_VALUE;\n        }\n        if (normalized == \"!<tag:yaml.org,2002:bool>\") {\n            return tag_t::BOOLEAN;\n        }\n        if (normalized == \"!<tag:yaml.org,2002:int>\") {\n            return tag_t::INTEGER;\n        }\n        if (normalized == \"!<tag:yaml.org,2002:float>\") {\n            return tag_t::FLOATING_NUMBER;\n        }\n        if (normalized == \"!<tag:yaml.org,2002:str>\") {\n            return tag_t::STRING;\n        }\n\n        return tag_t::CUSTOM_TAG;\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_TAG_RESOLVER_HPP */\n\n// #include <fkYAML/detail/meta/input_adapter_traits.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_META_INPUT_ADAPTER_TRAITS_HPP\n#define FK_YAML_DETAIL_META_INPUT_ADAPTER_TRAITS_HPP\n\n#include <array>\n#include <string>\n#include <type_traits>\n#include <vector>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/detect.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n\n#if defined(FK_YAML_HAS_CXX_17) && FK_YAML_HAS_INCLUDE(<string_view>)\n#include <string_view>\n#endif\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n///////////////////////////////////////////\n//   Input Adapter API detection traits\n///////////////////////////////////////////\n\n/// @brief A type which represents get_buffer_view function.\n/// @tparam T A target type.\ntemplate <typename T>\nusing get_buffer_view_fn_t = decltype(std::declval<T>().get_buffer_view());\n\n/// @brief Type traits to check if InputAdapterType has get_buffer_view member function.\n/// @tparam InputAdapterType An input adapter type to check if it has get_buffer_view function.\n/// @tparam typename N/A\ntemplate <typename InputAdapterType, typename = void>\nstruct has_get_buffer_view : std::false_type {};\n\n/// @brief A partial specialization of has_get_buffer_view if InputAdapterType has get_buffer_view member function.\n/// @tparam InputAdapterType A type of a target input adapter.\ntemplate <typename InputAdapterType>\nstruct has_get_buffer_view<InputAdapterType, enable_if_t<is_detected<get_buffer_view_fn_t, InputAdapterType>::value>>\n    : std::true_type {};\n\n////////////////////////////////\n//   is_input_adapter traits\n////////////////////////////////\n\n/// @brief Type traits to check if T is an input adapter type.\n/// @tparam T A target type.\n/// @tparam typename N/A\ntemplate <typename T, typename = void>\nstruct is_input_adapter : std::false_type {};\n\n/// @brief A partial specialization of is_input_adapter if T is an input adapter type.\n/// @tparam InputAdapterType\ntemplate <typename InputAdapterType>\nstruct is_input_adapter<InputAdapterType, enable_if_t<has_get_buffer_view<InputAdapterType>::value>> : std::true_type {\n};\n\n/////////////////////////////////////////////////\n//   traits for contiguous iterator detection\n/////////////////////////////////////////////////\n\n/// @brief Type traits to check if T is a container which has contiguous bytes.\n/// @tparam T A target type.\ntemplate <typename T>\nstruct is_contiguous_container : std::false_type {};\n\n/// @brief A partial specialization of is_contiguous_container if T is a std::array.\n/// @tparam T Element type.\n/// @tparam N Maximum number of elements.\ntemplate <typename T, std::size_t N>\nstruct is_contiguous_container<std::array<T, N>> : std::true_type {};\n\n/// @brief A partial specialization of is_contiguous_container if T is a std::basic_string.\n/// @tparam CharT Character type.\n/// @tparam Traits Character traits type.\n/// @tparam Alloc Allocator type.\ntemplate <typename CharT, typename Traits, typename Alloc>\nstruct is_contiguous_container<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};\n\n#ifdef FK_YAML_HAS_CXX_17\n\n/// @brief A partial specialization of is_contiguous_container if T is a std::basic_string_view.\n/// @tparam CharT Character type.\n/// @tparam Traits Character traits type.\ntemplate <typename CharT, typename Traits>\nstruct is_contiguous_container<std::basic_string_view<CharT, Traits>> : std::true_type {};\n\n#endif // defined(FK_YAML_HAS_CXX_20)\n\n/// @brief A partial specialization of is_contiguous_container if T is a std::vector.\n/// @tparam T Element type.\n/// @tparam Alloc Allocator type.\ntemplate <typename T, typename Alloc>\nstruct is_contiguous_container<std::vector<T, Alloc>> : std::true_type {};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_META_INPUT_ADAPTER_TRAITS_HPP */\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/node_attrs.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_NODE_ATTRS_HPP\n#define FK_YAML_DETAIL_NODE_ATTRS_HPP\n\n#include <cstdint>\n#include <limits>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/node_type.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief The type for node attribute bits.\nusing node_attr_t = uint32_t;\n\n/// @brief The namespace to define bit masks for node attribute bits.\nnamespace node_attr_mask {\n\n/// The bit mask for node value type bits.\nconstexpr node_attr_t value = 0x0000FFFFu;\n/// The bit mask for node style type bits. (bits are not yet defined.)\nconstexpr node_attr_t style = 0x00FF0000u;\n/// The bit mask for node property related bits.\nconstexpr node_attr_t props = 0xFF000000u;\n/// The bit mask for anchor/alias node type bits.\nconstexpr node_attr_t anchoring = 0x03000000u;\n/// The bit mask for anchor offset value bits.\nconstexpr node_attr_t anchor_offset = 0xFC000000u;\n/// The bit mask for all the bits for node attributes.\nconstexpr node_attr_t all = std::numeric_limits<node_attr_t>::max();\n\n} // namespace node_attr_mask\n\n/// @brief The namespace to define bits for node attributes.\nnamespace node_attr_bits {\n\n/// The sequence node bit.\nconstexpr node_attr_t seq_bit = 1u << 0;\n/// The mapping node bit.\nconstexpr node_attr_t map_bit = 1u << 1;\n/// The null scalar node bit.\nconstexpr node_attr_t null_bit = 1u << 2;\n/// The boolean scalar node bit.\nconstexpr node_attr_t bool_bit = 1u << 3;\n/// The integer scalar node bit.\nconstexpr node_attr_t int_bit = 1u << 4;\n/// The floating point scalar node bit.\nconstexpr node_attr_t float_bit = 1u << 5;\n/// The string scalar node bit.\nconstexpr node_attr_t string_bit = 1u << 6;\n\n/// A utility bit set to filter scalar node bits.\nconstexpr node_attr_t scalar_bits = null_bit | bool_bit | int_bit | float_bit | string_bit;\n\n/// The anchor node bit.\nconstexpr node_attr_t anchor_bit = 0x01000000u;\n/// The alias node bit.\nconstexpr node_attr_t alias_bit = 0x02000000u;\n\n/// A utility bit set for initialization.\nconstexpr node_attr_t default_bits = null_bit;\n\n/// @brief Converts a node_type value to a node_attr_t value.\n/// @param t A type of node value.\n/// @return The associated node value bit.\ninline node_attr_t from_node_type(node_type t) noexcept {\n    switch (t) {\n    case node_type::SEQUENCE:\n        return seq_bit;\n    case node_type::MAPPING:\n        return map_bit;\n    case node_type::NULL_OBJECT:\n        return null_bit;\n    case node_type::BOOLEAN:\n        return bool_bit;\n    case node_type::INTEGER:\n        return int_bit;\n    case node_type::FLOAT:\n        return float_bit;\n    case node_type::STRING:\n        return string_bit;\n    default:                        // LCOV_EXCL_LINE\n        return node_attr_mask::all; // LCOV_EXCL_LINE\n    }\n}\n\n/// @brief Converts a node_attr_t value to a node_type value.\n/// @param bits node attribute bits\n/// @return An associated node value type with the given node value bit.\ninline node_type to_node_type(node_attr_t bits) noexcept {\n    switch (bits & node_attr_mask::value) {\n    case seq_bit:\n        return node_type::SEQUENCE;\n    case map_bit:\n        return node_type::MAPPING;\n    case null_bit:\n        return node_type::NULL_OBJECT;\n    case bool_bit:\n        return node_type::BOOLEAN;\n    case int_bit:\n        return node_type::INTEGER;\n    case float_bit:\n        return node_type::FLOAT;\n    case string_bit:\n        return node_type::STRING;\n    default:                   // LCOV_EXCL_LINE\n        detail::unreachable(); // LCOV_EXCL_LINE\n    }\n}\n\n/// @brief Get an anchor offset used to reference an anchor node from the given attribute bits.\n/// @param attrs node attribute bits\n/// @return An anchor offset value.\ninline uint32_t get_anchor_offset(node_attr_t attrs) noexcept {\n    return (attrs & node_attr_mask::anchor_offset) >> 26;\n}\n\n/// @brief Set an anchor offset value to the appropriate bits.\n/// @param offset An anchor offset value.\n/// @param attrs node attribute bit set into which the offset value is written.\ninline void set_anchor_offset(uint32_t offset, node_attr_t& attrs) noexcept {\n    attrs &= ~node_attr_mask::anchor_offset;\n    attrs |= (offset & 0x3Fu) << 26;\n}\n\n} // namespace node_attr_bits\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_NODE_ATTRS_HPP */\n\n// #include <fkYAML/detail/node_property.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_NODE_PROPERTY_HPP\n#define FK_YAML_DETAIL_NODE_PROPERTY_HPP\n\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\nstruct node_property {\n    /// The tag name property.\n    std::string tag {}; // NOLINT(readability-redundant-member-init) necessary for older compilers\n    /// The anchor name property.\n    std::string anchor {}; // NOLINT(readability-redundant-member-init) necessary for older compilers\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_NODE_PROPERTY_HPP */\n\n// #include <fkYAML/detail/types/lexical_token_t.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A class which provides the feature of deserializing YAML documents.\n/// @tparam BasicNodeType A type of the container for deserialized YAML values.\ntemplate <typename BasicNodeType>\nclass basic_deserializer {\n    static_assert(is_basic_node<BasicNodeType>::value, \"basic_deserializer only accepts basic_node<...>\");\n\n    /** A type for the target basic_node. */\n    using basic_node_type = BasicNodeType;\n    /** A type for the lexical analyzer. */\n    using lexer_type = lexical_analyzer;\n    /** A type for the document metainfo. */\n    using doc_metainfo_type = document_metainfo<basic_node_type>;\n    /** A type for the tag resolver. */\n    using tag_resolver_type = tag_resolver<basic_node_type>;\n    /** A type for the scalar parser. */\n    using scalar_parser_type = scalar_parser<basic_node_type>;\n    /** A type for sequence node value containers. */\n    using sequence_type = typename basic_node_type::sequence_type;\n    /** A type for mapping node value containers. */\n    using mapping_type = typename basic_node_type::mapping_type;\n\n    /// @brief Definition of state types of parse contexts.\n    enum class context_state_t : std::uint8_t {\n        BLOCK_MAPPING,                //!< The underlying node is a block mapping.\n        BLOCK_MAPPING_EXPLICIT_KEY,   //!< The underlying node is an explicit block mapping key.\n        BLOCK_MAPPING_EXPLICIT_VALUE, //!< The underlying node is an explicit block mapping value.\n        MAPPING_VALUE,                //!< The underlying node is a block mapping value.\n        BLOCK_SEQUENCE,               //!< The underlying node is a block sequence.\n        BLOCK_SEQUENCE_ENTRY,         //!< The underlying node is a block sequence entry.\n        FLOW_SEQUENCE,                //!< The underlying node is a flow sequence.\n        FLOW_SEQUENCE_KEY,            //!< The underlying node is a flow sequence as a key.\n        FLOW_MAPPING,                 //!< The underlying node is a flow mapping.\n        FLOW_MAPPING_KEY,             //!< The underlying node is a flow mapping as a key.\n    };\n\n    /// @brief Context information set for parsing.\n    struct parse_context {\n        /// @brief Construct a new parse_context object.\n        parse_context() = default;\n\n        /// @brief Construct a new parse_context object with non-default values for each parameter.\n        /// @param line The current line. (count from zero)\n        /// @param indent The indentation width in the current line. (count from zero)\n        /// @param state The parse context type.\n        /// @param p_node The underlying node associated to this context.\n        parse_context(uint32_t line, uint32_t indent, context_state_t state, basic_node_type* p_node) noexcept\n            : line(line),\n              indent(indent),\n              state(state),\n              p_node(p_node) {\n        }\n\n        parse_context(const parse_context&) noexcept = default;\n        parse_context& operator=(const parse_context&) noexcept = default;\n        parse_context(parse_context&&) noexcept = default;\n        parse_context& operator=(parse_context&&) noexcept = default;\n\n        ~parse_context() {\n            switch (state) {\n            case context_state_t::BLOCK_MAPPING_EXPLICIT_KEY:\n            case context_state_t::FLOW_SEQUENCE_KEY:\n            case context_state_t::FLOW_MAPPING_KEY:\n                delete p_node;\n                p_node = nullptr;\n                break;\n            default:\n                break;\n            }\n        }\n\n        /// The current line. (count from zero)\n        uint32_t line {0};\n        /// The indentation width in the current line. (count from zero)\n        uint32_t indent {0};\n        /// The parse context type.\n        context_state_t state {context_state_t::BLOCK_MAPPING};\n        /// The pointer to the associated node to this context.\n        basic_node_type* p_node {nullptr};\n    };\n\n    /// @brief Definitions of state types for expected flow token hints.\n    enum class flow_token_state_t : std::uint8_t {\n        NEEDS_VALUE_OR_SUFFIX,     //!< Either value or flow suffix (`]` or `}`)\n        NEEDS_SEPARATOR_OR_SUFFIX, //!< Either separator (`,`) or flow suffix (`]` or `}`)\n    };\n\npublic:\n    /// @brief Construct a new basic_deserializer object.\n    basic_deserializer() = default;\n\npublic:\n    /// @brief Deserialize a single YAML document into a YAML node.\n    /// @note\n    /// If the input consists of multiple YAML documents, this function only parses the first.\n    /// If the input may have multiple YAML documents all of which must be parsed into nodes,\n    /// prefer the `deserialize_docs()` function.\n    /// @tparam InputAdapterType The type of an input adapter object.\n    /// @param input_adapter An input adapter object for the input source buffer.\n    /// @return basic_node_type A root YAML node deserialized from the source string.\n    template <typename InputAdapterType, enable_if_t<is_input_adapter<InputAdapterType>::value, int> = 0>\n    basic_node_type deserialize(InputAdapterType&& input_adapter) { // NOLINT(cppcoreguidelines-missing-std-forward)\n        const str_view input_view = input_adapter.get_buffer_view();\n        lexer_type lexer(input_view);\n\n        lexical_token_t type {lexical_token_t::END_OF_BUFFER};\n        return deserialize_document(lexer, type);\n    }\n\n    /// @brief Deserialize multiple YAML documents into YAML nodes.\n    /// @tparam InputAdapterType The type of an adapter object.\n    /// @param input_adapter An input adapter object for the input source buffer.\n    /// @return std::vector<basic_node_type> Root YAML nodes for deserialized YAML documents.\n    template <typename InputAdapterType, enable_if_t<is_input_adapter<InputAdapterType>::value, int> = 0>\n    // NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)\n    std::vector<basic_node_type> deserialize_docs(InputAdapterType&& input_adapter) {\n        const str_view input_view = input_adapter.get_buffer_view();\n        lexer_type lexer(input_view);\n\n        std::vector<basic_node_type> nodes {};\n        lexical_token_t type {lexical_token_t::END_OF_BUFFER};\n\n        do {\n            nodes.emplace_back(deserialize_document(lexer, type));\n        } while (type != lexical_token_t::END_OF_BUFFER);\n\n        return nodes;\n    } // LCOV_EXCL_LINE\n\nprivate:\n    /// @brief Deserialize a YAML document into a YAML node.\n    /// @param lexer The lexical analyzer to be used.\n    /// @param last_type The variable to store the last lexical token type.\n    /// @return basic_node_type A root YAML node deserialized from the YAML document.\n    basic_node_type deserialize_document(lexer_type& lexer, lexical_token_t& last_type) {\n        lexical_token token {};\n\n        basic_node_type root;\n        mp_current_node = &root;\n        mp_meta = root.mp_meta;\n\n        // parse directives first.\n        deserialize_directives(lexer, token);\n\n        // parse node properties for root node if any\n        uint32_t line = lexer.get_lines_processed();\n        uint32_t indent = lexer.get_last_token_begin_pos();\n        const bool found_props = deserialize_node_properties(lexer, token, line, indent);\n\n        switch (token.type) {\n        case lexical_token_t::SEQUENCE_BLOCK_PREFIX: {\n            root = basic_node_type::sequence({basic_node_type()});\n            apply_directive_set(root);\n            if (found_props) {\n                // If node properties are found before the block sequence entry prefix, the properties belong to the\n                // root sequence node.\n                apply_node_properties(root);\n            }\n\n            parse_context context(\n                lexer.get_lines_processed(), lexer.get_last_token_begin_pos(), context_state_t::BLOCK_SEQUENCE, &root);\n            m_context_stack.emplace_back(context);\n\n            mp_current_node = &(root.template get_value_ref<sequence_type&>().back());\n            apply_directive_set(*mp_current_node);\n            context.state = context_state_t::BLOCK_SEQUENCE_ENTRY;\n            context.p_node = mp_current_node;\n            m_context_stack.emplace_back(std::move(context));\n\n            token = lexer.get_next_token();\n            line = lexer.get_lines_processed();\n            indent = lexer.get_last_token_begin_pos();\n            break;\n        }\n        case lexical_token_t::SEQUENCE_FLOW_BEGIN:\n            ++m_flow_context_depth;\n            lexer.set_context_state(true);\n            root = basic_node_type::sequence();\n            apply_directive_set(root);\n            apply_node_properties(root);\n            m_context_stack.emplace_back(\n                lexer.get_lines_processed(), lexer.get_last_token_begin_pos(), context_state_t::FLOW_SEQUENCE, &root);\n            token = lexer.get_next_token();\n            line = lexer.get_lines_processed();\n            indent = lexer.get_last_token_begin_pos();\n            break;\n        case lexical_token_t::MAPPING_FLOW_BEGIN:\n            ++m_flow_context_depth;\n            lexer.set_context_state(true);\n            root = basic_node_type::mapping();\n            apply_directive_set(root);\n            apply_node_properties(root);\n            m_context_stack.emplace_back(\n                lexer.get_lines_processed(), lexer.get_last_token_begin_pos(), context_state_t::FLOW_MAPPING, &root);\n            token = lexer.get_next_token();\n            line = lexer.get_lines_processed();\n            indent = lexer.get_last_token_begin_pos();\n            break;\n        case lexical_token_t::EXPLICIT_KEY_PREFIX: {\n            // If the explicit key prefix (? ) is detected here, the root node of current document must be a mapping.\n            // Also, tag and anchor if any are associated to the root mapping node.\n            // No get_next_token() call here to handle the token event in the deserialize_node() function.\n            root = basic_node_type::mapping();\n            apply_directive_set(root);\n            apply_node_properties(root);\n            parse_context context(\n                lexer.get_lines_processed(), lexer.get_last_token_begin_pos(), context_state_t::BLOCK_MAPPING, &root);\n            m_context_stack.emplace_back(std::move(context));\n            line = lexer.get_lines_processed();\n            indent = lexer.get_last_token_begin_pos();\n            break;\n        }\n        case lexical_token_t::BLOCK_LITERAL_SCALAR:\n        case lexical_token_t::BLOCK_FOLDED_SCALAR:\n            // If a block scalar token is detected here, current document contains single scalar.\n            // Do nothing here since the token is handled in the deserialize_node() function.\n            break;\n        case lexical_token_t::PLAIN_SCALAR:\n        case lexical_token_t::SINGLE_QUOTED_SCALAR:\n        case lexical_token_t::DOUBLE_QUOTED_SCALAR:\n        case lexical_token_t::ALIAS_PREFIX:\n            // Defer handling the above token events until the next call on the deserialize_scalar() function since the\n            // meaning depends on subsequent events.\n            if (found_props && line < lexer.get_lines_processed()) {\n                // If node properties and a followed node are on the different line, the properties belong to the root\n                // node.\n                if (m_needs_anchor_impl) {\n                    m_root_anchor_name = m_anchor_name;\n                    m_needs_anchor_impl = false;\n                    m_anchor_name = {};\n                }\n\n                if (m_needs_tag_impl) {\n                    m_root_tag_name = m_tag_name;\n                    m_needs_tag_impl = false;\n                    m_tag_name = {};\n                }\n\n                line = lexer.get_lines_processed();\n                indent = lexer.get_last_token_begin_pos();\n            }\n            break;\n        default:\n            // Do nothing since current document has no contents.\n            break;\n        }\n\n        // parse YAML nodes recursively\n        deserialize_node(lexer, token, line, indent, last_type);\n        FK_YAML_ASSERT(\n            last_type == lexical_token_t::END_OF_BUFFER || last_type == lexical_token_t::END_OF_DIRECTIVES ||\n            last_type == lexical_token_t::END_OF_DOCUMENT);\n\n        // reset parameters for the next call.\n        mp_current_node = nullptr;\n        mp_meta.reset();\n        m_needs_tag_impl = false;\n        m_needs_anchor_impl = false;\n        m_flow_context_depth = 0;\n        m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n        m_context_stack.clear();\n\n        return root;\n    }\n\n    /// @brief Deserializes the YAML directives if specified.\n    /// @param lexer The lexical analyzer to be used.\n    /// @param last_token Storage for last lexical token type.\n    void deserialize_directives(lexer_type& lexer, lexical_token& last_token) {\n        bool lacks_end_of_directives_marker = false;\n        lexer.set_document_state(true);\n\n        for (;;) {\n            const lexical_token token = lexer.get_next_token();\n\n            switch (token.type) {\n            case lexical_token_t::YAML_VER_DIRECTIVE:\n                if FK_YAML_UNLIKELY (mp_meta->is_version_specified) {\n                    throw parse_error(\n                        \"YAML version cannot be specified more than once.\",\n                        lexer.get_lines_processed(),\n                        lexer.get_last_token_begin_pos());\n                }\n\n                mp_meta->version = convert_yaml_version(lexer.get_yaml_version());\n                mp_meta->is_version_specified = true;\n                lacks_end_of_directives_marker = true;\n                break;\n            case lexical_token_t::TAG_DIRECTIVE: {\n                const str_view tag_handle_view = lexer.get_tag_handle();\n                switch (tag_handle_view.size()) {\n                case 1 /* ! */: {\n                    const bool is_already_specified = !mp_meta->primary_handle_prefix.empty();\n                    if FK_YAML_UNLIKELY (is_already_specified) {\n                        throw parse_error(\n                            \"Primary handle cannot be specified more than once.\",\n                            lexer.get_lines_processed(),\n                            lexer.get_last_token_begin_pos());\n                    }\n                    const str_view tag_prefix = lexer.get_tag_prefix();\n                    mp_meta->primary_handle_prefix.assign(tag_prefix.begin(), tag_prefix.end());\n                    lacks_end_of_directives_marker = true;\n                    break;\n                }\n                case 2 /* !! */: {\n                    const bool is_already_specified = !mp_meta->secondary_handle_prefix.empty();\n                    if FK_YAML_UNLIKELY (is_already_specified) {\n                        throw parse_error(\n                            \"Secondary handle cannot be specified more than once.\",\n                            lexer.get_lines_processed(),\n                            lexer.get_last_token_begin_pos());\n                    }\n                    const str_view tag_prefix = lexer.get_tag_prefix();\n                    mp_meta->secondary_handle_prefix.assign(tag_prefix.begin(), tag_prefix.end());\n                    lacks_end_of_directives_marker = true;\n                    break;\n                }\n                default /* !<handle>! */: {\n                    std::string tag_handle(tag_handle_view.begin(), tag_handle_view.end());\n                    const str_view tag_prefix_view = lexer.get_tag_prefix();\n                    std::string tag_prefix(tag_prefix_view.begin(), tag_prefix_view.end());\n                    const bool is_already_specified =\n                        !(mp_meta->named_handle_map.emplace(std::move(tag_handle), std::move(tag_prefix)).second);\n                    if FK_YAML_UNLIKELY (is_already_specified) {\n                        throw parse_error(\n                            \"The same named handle cannot be specified more than once.\",\n                            lexer.get_lines_processed(),\n                            lexer.get_last_token_begin_pos());\n                    }\n                    lacks_end_of_directives_marker = true;\n                    break;\n                }\n                }\n                break;\n            }\n            case lexical_token_t::INVALID_DIRECTIVE:\n                // TODO: should output a warning log. Currently just ignore this case.\n                break;\n            case lexical_token_t::END_OF_DIRECTIVES:\n                lacks_end_of_directives_marker = false;\n                break;\n            default:\n                if FK_YAML_UNLIKELY (lacks_end_of_directives_marker) {\n                    throw parse_error(\n                        \"The end of directives marker (---) is missing after directives.\",\n                        lexer.get_lines_processed(),\n                        lexer.get_last_token_begin_pos());\n                }\n                // end the parsing of directives if the other tokens are found.\n                last_token = token;\n                lexer.set_document_state(false);\n                return;\n            }\n        }\n    }\n\n    /// @brief Deserializes the YAML nodes recursively.\n    /// @param lexer The lexical analyzer to be used.\n    /// @param first_type The first lexical token.\n    /// @param last_type Storage for last lexical token type.\n    void deserialize_node(\n        lexer_type& lexer, const lexical_token& first_token, uint32_t first_line, uint32_t first_indent,\n        lexical_token_t& last_type) {\n        lexical_token token = first_token;\n        uint32_t line = first_line;\n        uint32_t indent = first_indent;\n\n        do {\n            switch (token.type) {\n            case lexical_token_t::EXPLICIT_KEY_PREFIX: {\n                const bool needs_to_move_back = indent == 0 || indent < m_context_stack.back().indent;\n                if (needs_to_move_back) {\n                    pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                        return c.state == context_state_t::BLOCK_MAPPING && indent == c.indent;\n                    });\n                }\n\n                switch (m_context_stack.back().state) {\n                case context_state_t::MAPPING_VALUE:\n                case context_state_t::BLOCK_MAPPING_EXPLICIT_KEY:\n                case context_state_t::BLOCK_MAPPING_EXPLICIT_VALUE:\n                case context_state_t::BLOCK_SEQUENCE_ENTRY:\n                    // This path is needed in case the input contains nested explicit keys.\n                    // ```yaml\n                    // foo:\n                    //   ? ? foo\n                    //     : bar\n                    //   : ? baz\n                    //     : - ? qux\n                    //         : 123\n                    // ```\n                    *mp_current_node = basic_node_type::mapping();\n                    apply_directive_set(*mp_current_node);\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                    break;\n                default:\n                    break;\n                }\n\n                token = lexer.get_next_token();\n                if (token.type == lexical_token_t::SEQUENCE_BLOCK_PREFIX) {\n                    // heap-allocated node will be freed in handling the corresponding KEY_SEPARATOR event\n                    auto* p_node = new basic_node_type(node_type::SEQUENCE);\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING_EXPLICIT_KEY, p_node);\n\n                    apply_directive_set(*p_node);\n                    parse_context context(\n                        lexer.get_lines_processed(),\n                        lexer.get_last_token_begin_pos(),\n                        context_state_t::BLOCK_SEQUENCE,\n                        p_node);\n                    m_context_stack.emplace_back(context);\n\n                    p_node->template get_value_ref<sequence_type&>().emplace_back(basic_node_type());\n                    mp_current_node = &(p_node->template get_value_ref<sequence_type&>().back());\n                    apply_directive_set(*mp_current_node);\n                    context.state = context_state_t::BLOCK_SEQUENCE_ENTRY;\n                    context.p_node = mp_current_node;\n                    m_context_stack.emplace_back(std::move(context));\n\n                    break;\n                }\n\n                // heap-allocated node will be freed in handling the corresponding KEY_SEPARATOR event\n                m_context_stack.emplace_back(\n                    line, indent, context_state_t::BLOCK_MAPPING_EXPLICIT_KEY, new basic_node_type());\n                mp_current_node = m_context_stack.back().p_node;\n                apply_directive_set(*mp_current_node);\n                indent = lexer.get_last_token_begin_pos();\n                line = lexer.get_lines_processed();\n\n                continue;\n            }\n            case lexical_token_t::KEY_SEPARATOR: {\n                FK_YAML_ASSERT(!m_context_stack.empty());\n                if FK_YAML_UNLIKELY (m_context_stack.back().state == context_state_t::BLOCK_SEQUENCE_ENTRY) {\n                    // empty mapping keys are not supported.\n                    // ```yaml\n                    // - : foo\n                    // ```\n                    throw parse_error(\"sequence key should not be empty.\", line, indent);\n                }\n\n                if (m_flow_context_depth > 0) {\n                    break;\n                }\n\n                // hold the line count of the key separator for later use.\n                const uint32_t old_indent = indent;\n                const uint32_t old_line = line;\n\n                token = lexer.get_next_token();\n                line = lexer.get_lines_processed();\n                indent = lexer.get_last_token_begin_pos();\n\n                const bool found_props = deserialize_node_properties(lexer, token, line, indent);\n                if (found_props && line == lexer.get_lines_processed()) {\n                    // defer applying node properties for the subsequent node on the same line.\n                    continue;\n                }\n\n                line = lexer.get_lines_processed();\n                indent = lexer.get_last_token_begin_pos();\n\n                const bool is_implicit_same_line =\n                    (line == old_line) && (m_context_stack.empty() || old_indent > m_context_stack.back().indent);\n                if (is_implicit_same_line) {\n                    // a key separator for an implicit key with its value on the same line.\n                    continue;\n                }\n\n                if (line > old_line) {\n                    if (m_needs_tag_impl) {\n                        const tag_t tag_type = tag_resolver_type::resolve_tag(m_tag_name, mp_meta);\n                        if (tag_type == tag_t::MAPPING || tag_type == tag_t::CUSTOM_TAG) {\n                            // set YAML node properties here to distinguish them from those for the first key node\n                            // as shown in the following snippet:\n                            //\n                            // ```yaml\n                            // foo: !!map\n                            //   !!str 123: true\n                            //   ^\n                            //   this !!str tag overwrites the preceding !!map tag.\n                            // ```\n                            *mp_current_node = basic_node_type::mapping();\n                            apply_directive_set(*mp_current_node);\n                            apply_node_properties(*mp_current_node);\n                            m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                            continue;\n                        }\n                    }\n\n                    if (token.type == lexical_token_t::SEQUENCE_BLOCK_PREFIX) {\n                        // a key separator preceding block sequence entries\n                        *mp_current_node = basic_node_type::sequence({basic_node_type()});\n                        apply_directive_set(*mp_current_node);\n                        apply_node_properties(*mp_current_node);\n                        auto& cur_context = m_context_stack.back();\n                        cur_context.line = line;\n                        cur_context.indent = indent;\n                        cur_context.state = context_state_t::BLOCK_SEQUENCE;\n\n                        mp_current_node = &(mp_current_node->template get_value_ref<sequence_type&>().back());\n                        apply_directive_set(*mp_current_node);\n                        parse_context entry_context = cur_context;\n                        entry_context.state = context_state_t::BLOCK_SEQUENCE_ENTRY;\n                        entry_context.p_node = mp_current_node;\n                        m_context_stack.emplace_back(std::move(entry_context));\n\n                        token = lexer.get_next_token();\n                        line = lexer.get_lines_processed();\n                        indent = lexer.get_last_token_begin_pos();\n\n                        const bool has_props = deserialize_node_properties(lexer, token, line, indent);\n                        if (has_props) {\n                            const uint32_t line_after_props = lexer.get_lines_processed();\n                            if (line == line_after_props) {\n                                // Skip updating the current indent to avoid stacking a wrong indentation.\n                                //\n                                // ```yaml\n                                // &foo bar: baz\n                                // ^\n                                // the correct indent width for the \"bar\" node key.\n                                // ```\n                                continue;\n                            }\n\n                            // if node properties and the followed node are on different lines (i.e., the properties are\n                            // for a container node), the application and the line advancement must happen here.\n                            // Otherwise, a false indent error will be emitted. See\n                            // https://github.com/fktn-k/fkYAML/issues/368 for more details.\n                            line = line_after_props;\n                            indent = lexer.get_last_token_begin_pos();\n                            *mp_current_node = basic_node_type::mapping();\n                            m_context_stack.emplace_back(\n                                line_after_props, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                            apply_directive_set(*mp_current_node);\n                            apply_node_properties(*mp_current_node);\n                        }\n\n                        continue;\n                    }\n\n                    if (indent <= m_context_stack.back().indent) {\n                        FK_YAML_ASSERT(m_context_stack.back().state == context_state_t::MAPPING_VALUE);\n\n                        // Mapping values can be omitted and are considered to be null.\n                        // ```yaml\n                        // foo:\n                        // bar:\n                        //   baz:\n                        // qux:\n                        // # -> {foo: null, bar: {baz: null}, qux: null}\n                        // ```\n                        pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                            return (c.state == context_state_t::BLOCK_MAPPING) && (indent == c.indent);\n                        });\n                    }\n\n                    // defer checking the existence of a key separator after the following scalar until the next\n                    // deserialize_scalar() call.\n                    continue;\n                }\n\n                // handle explicit mapping key separators.\n                FK_YAML_ASSERT(m_context_stack.back().state == context_state_t::BLOCK_MAPPING_EXPLICIT_KEY);\n\n                basic_node_type key_node = std::move(*m_context_stack.back().p_node);\n                m_context_stack.pop_back();\n                m_context_stack.back().p_node->template get_value_ref<mapping_type&>().emplace(\n                    key_node, basic_node_type());\n                mp_current_node = &(m_context_stack.back().p_node->operator[](std::move(key_node)));\n                m_context_stack.emplace_back(\n                    old_line, old_indent, context_state_t::BLOCK_MAPPING_EXPLICIT_VALUE, mp_current_node);\n\n                if (token.type == lexical_token_t::SEQUENCE_BLOCK_PREFIX) {\n                    *mp_current_node = basic_node_type::sequence({basic_node_type()});\n                    apply_directive_set(*mp_current_node);\n                    apply_node_properties(*mp_current_node);\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_SEQUENCE, mp_current_node);\n\n                    mp_current_node = &(mp_current_node->template get_value_ref<sequence_type&>().back());\n                    parse_context entry_context = m_context_stack.back();\n                    entry_context.state = context_state_t::BLOCK_SEQUENCE_ENTRY;\n                    entry_context.p_node = mp_current_node;\n                    m_context_stack.emplace_back(std::move(entry_context));\n                    break;\n                }\n\n                continue;\n            }\n            case lexical_token_t::ANCHOR_PREFIX:\n            case lexical_token_t::TAG_PREFIX:\n                deserialize_node_properties(lexer, token, line, indent);\n                // Skip updating the current indent to avoid stacking a wrong indentation.\n                // Note that node properties for block sequences as a mapping value are processed when a\n                // `lexical_token_t::KEY_SEPARATOR` token is processed.\n                //\n                // ```yaml\n                // &foo bar: baz\n                // ^\n                // the correct indent width for the \"bar\" node key.\n                // ```\n                continue;\n            case lexical_token_t::SEQUENCE_BLOCK_PREFIX: {\n                FK_YAML_ASSERT(!m_context_stack.empty());\n                const uint32_t parent_indent = m_context_stack.back().indent;\n                if (indent == parent_indent) {\n                    // If the previous block sequence entry is empty, just move to the parent context.\n                    // ```yaml\n                    // foo:\n                    //   -\n                    //   - bar\n                    // # ^ (here)\n                    // # -> {foo: [null, bar]}\n                    // ```\n                    pop_to_parent_node(line, indent, [](const parse_context& c) {\n                        return c.state == context_state_t::BLOCK_SEQUENCE;\n                    });\n                }\n                else if (indent < parent_indent) {\n                    pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                        return c.state == context_state_t::BLOCK_SEQUENCE && indent == c.indent;\n                    });\n                }\n                else /*parent_indent < indent*/ {\n                    if FK_YAML_UNLIKELY (m_context_stack.back().state == context_state_t::BLOCK_SEQUENCE) {\n                        // bad indentation like the following YAML:\n                        // ```yaml\n                        // - \"foo\"\n                        //   - bar\n                        // # ^\n                        // ```\n                        throw parse_error(\"bad indentation of a mapping entry.\", line, indent);\n                    }\n\n                    *mp_current_node = basic_node_type::sequence();\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_SEQUENCE, mp_current_node);\n                    apply_directive_set(*mp_current_node);\n                    apply_node_properties(*mp_current_node);\n                }\n\n                auto& seq = mp_current_node->template get_value_ref<sequence_type&>();\n                seq.emplace_back(basic_node_type());\n                mp_current_node = &(seq.back());\n                apply_directive_set(*mp_current_node);\n                m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_SEQUENCE_ENTRY, mp_current_node);\n                break;\n            }\n            case lexical_token_t::SEQUENCE_FLOW_BEGIN:\n                if (m_flow_context_depth == 0) {\n                    lexer.set_context_state(true);\n\n                    if (indent <= m_context_stack.back().indent) {\n                        pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                            switch (c.state) {\n                            case context_state_t::BLOCK_MAPPING:\n                            case context_state_t::MAPPING_VALUE:\n                                return indent == c.indent;\n                            default:\n                                return false;\n                            }\n                        });\n                    }\n                }\n                else if FK_YAML_UNLIKELY (m_flow_token_state == flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX) {\n                    throw parse_error(\"Flow sequence beginning is found without separated with a comma.\", line, indent);\n                }\n\n                ++m_flow_context_depth;\n\n                switch (m_context_stack.back().state) {\n                case context_state_t::BLOCK_SEQUENCE:\n                case context_state_t::FLOW_SEQUENCE:\n                    mp_current_node->template get_value_ref<sequence_type&>().emplace_back(basic_node_type::sequence());\n                    mp_current_node = &(mp_current_node->template get_value_ref<sequence_type&>().back());\n                    m_context_stack.emplace_back(line, indent, context_state_t::FLOW_SEQUENCE, mp_current_node);\n                    break;\n                case context_state_t::BLOCK_MAPPING:\n                case context_state_t::FLOW_MAPPING:\n                    // heap-allocated node will be freed in handling the corresponding SEQUENCE_FLOW_END event.\n                    m_context_stack.emplace_back(\n                        line, indent, context_state_t::FLOW_SEQUENCE_KEY, new basic_node_type(node_type::SEQUENCE));\n                    mp_current_node = m_context_stack.back().p_node;\n                    break;\n                default: {\n                    *mp_current_node = basic_node_type::sequence();\n                    parse_context& last_context = m_context_stack.back();\n                    last_context.line = line;\n                    last_context.indent = indent;\n                    last_context.state = context_state_t::FLOW_SEQUENCE;\n                    break;\n                }\n                }\n\n                apply_directive_set(*mp_current_node);\n                apply_node_properties(*mp_current_node);\n\n                m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n                break;\n            case lexical_token_t::SEQUENCE_FLOW_END: {\n                if FK_YAML_UNLIKELY (m_flow_context_depth == 0) {\n                    throw parse_error(\"Flow sequence ending is found outside the flow context.\", line, indent);\n                }\n\n                if (--m_flow_context_depth == 0) {\n                    lexer.set_context_state(false);\n                }\n\n                // find the corresponding flow sequence beginning.\n                auto itr = std::find_if( // LCOV_EXCL_LINE\n                    m_context_stack.rbegin(),\n                    m_context_stack.rend(),\n                    [](const parse_context& c) {\n                        switch (c.state) {\n                        case context_state_t::FLOW_SEQUENCE_KEY:\n                        case context_state_t::FLOW_SEQUENCE:\n                            return true;\n                        default:\n                            return false;\n                        }\n                    });\n\n                const bool is_valid = itr != m_context_stack.rend();\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw parse_error(\"No corresponding flow sequence beginning is found.\", line, indent);\n                }\n\n                // keep the last state for later processing.\n                parse_context& last_context = m_context_stack.back();\n                mp_current_node = last_context.p_node;\n                last_context.p_node = nullptr;\n                indent = last_context.indent;\n                const context_state_t state = last_context.state;\n                m_context_stack.pop_back();\n\n                // handle cases where the flow sequence is a mapping key node.\n\n                if (!m_context_stack.empty() && state == context_state_t::FLOW_SEQUENCE_KEY) {\n                    basic_node_type key_node = std::move(*mp_current_node);\n                    delete mp_current_node;\n                    mp_current_node = m_context_stack.back().p_node;\n                    m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n\n                    add_new_key(std::move(key_node), line, indent);\n                    break;\n                }\n\n                token = lexer.get_next_token();\n                if (token.type == lexical_token_t::KEY_SEPARATOR) {\n                    basic_node_type key_node = basic_node_type::mapping();\n                    apply_directive_set(key_node);\n                    mp_current_node->swap(key_node);\n\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                    m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n\n                    add_new_key(std::move(key_node), line, indent);\n                }\n                else {\n                    if (!m_context_stack.empty()) {\n                        mp_current_node = m_context_stack.back().p_node;\n                    }\n                    if (m_flow_context_depth > 0) {\n                        m_flow_token_state = flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX;\n                    }\n                }\n\n                indent = lexer.get_last_token_begin_pos();\n                line = lexer.get_lines_processed();\n                continue;\n            }\n            case lexical_token_t::MAPPING_FLOW_BEGIN:\n                if (m_flow_context_depth == 0) {\n                    lexer.set_context_state(true);\n\n                    if (indent <= m_context_stack.back().indent) {\n                        pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                            switch (c.state) {\n                            case context_state_t::BLOCK_MAPPING:\n                            case context_state_t::MAPPING_VALUE:\n                                return indent == c.indent;\n                            default:\n                                return false;\n                            }\n                        });\n                    }\n                }\n                else if FK_YAML_UNLIKELY (m_flow_token_state == flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX) {\n                    throw parse_error(\"Flow mapping beginning is found without separated with a comma.\", line, indent);\n                }\n\n                ++m_flow_context_depth;\n\n                switch (m_context_stack.back().state) {\n                case context_state_t::BLOCK_SEQUENCE:\n                case context_state_t::FLOW_SEQUENCE:\n                    mp_current_node->template get_value_ref<sequence_type&>().emplace_back(basic_node_type::mapping());\n                    mp_current_node = &(mp_current_node->template get_value_ref<sequence_type&>().back());\n                    m_context_stack.emplace_back(line, indent, context_state_t::FLOW_MAPPING, mp_current_node);\n                    break;\n                case context_state_t::BLOCK_MAPPING:\n                case context_state_t::FLOW_MAPPING:\n                    // heap-allocated node will be freed in handling the corresponding MAPPING_FLOW_END event.\n                    m_context_stack.emplace_back(\n                        line, indent, context_state_t::FLOW_MAPPING_KEY, new basic_node_type(node_type::MAPPING));\n                    mp_current_node = m_context_stack.back().p_node;\n                    break;\n                default: {\n                    *mp_current_node = basic_node_type::mapping();\n                    parse_context& last_context = m_context_stack.back();\n                    last_context.line = line;\n                    last_context.indent = indent;\n                    last_context.state = context_state_t::FLOW_MAPPING;\n                    break;\n                }\n                }\n\n                apply_directive_set(*mp_current_node);\n                apply_node_properties(*mp_current_node);\n\n                line = lexer.get_lines_processed();\n                indent = lexer.get_last_token_begin_pos();\n\n                m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n                break;\n            case lexical_token_t::MAPPING_FLOW_END: {\n                if FK_YAML_UNLIKELY (m_flow_context_depth == 0) {\n                    throw parse_error(\"Flow mapping ending is found outside the flow context.\", line, indent);\n                }\n\n                if (--m_flow_context_depth == 0) {\n                    lexer.set_context_state(false);\n                }\n\n                // find the corresponding flow mapping beginning.\n                auto itr = std::find_if( // LCOV_EXCL_LINE\n                    m_context_stack.rbegin(),\n                    m_context_stack.rend(),\n                    [](const parse_context& c) {\n                        switch (c.state) {\n                        case context_state_t::FLOW_MAPPING_KEY:\n                        case context_state_t::FLOW_MAPPING:\n                            return true;\n                        default:\n                            return false;\n                        }\n                    });\n\n                const bool is_valid = itr != m_context_stack.rend();\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw parse_error(\"No corresponding flow mapping beginning is found.\", line, indent);\n                }\n\n                // keep the last state for later processing.\n                parse_context& last_context = m_context_stack.back();\n                mp_current_node = last_context.p_node;\n                last_context.p_node = nullptr;\n                indent = last_context.indent;\n                const context_state_t state = last_context.state;\n                m_context_stack.pop_back();\n\n                // handle cases where the flow mapping is a mapping key node.\n\n                if (!m_context_stack.empty() && state == context_state_t::FLOW_MAPPING_KEY) {\n                    basic_node_type key_node = std::move(*mp_current_node);\n                    delete mp_current_node;\n                    mp_current_node = m_context_stack.back().p_node;\n                    m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n\n                    add_new_key(std::move(key_node), line, indent);\n                    break;\n                }\n\n                token = lexer.get_next_token();\n                if (token.type == lexical_token_t::KEY_SEPARATOR) {\n                    basic_node_type key_node = basic_node_type::mapping();\n                    apply_directive_set(key_node);\n                    mp_current_node->swap(key_node);\n\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                    m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n\n                    add_new_key(std::move(key_node), line, indent);\n                }\n                else {\n                    if (!m_context_stack.empty()) {\n                        mp_current_node = m_context_stack.back().p_node;\n                    }\n                    if (m_flow_context_depth > 0) {\n                        m_flow_token_state = flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX;\n                    }\n                }\n\n                indent = lexer.get_last_token_begin_pos();\n                line = lexer.get_lines_processed();\n                continue;\n            }\n            case lexical_token_t::VALUE_SEPARATOR:\n                FK_YAML_ASSERT(m_flow_context_depth > 0);\n                if FK_YAML_UNLIKELY (m_flow_token_state != flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX) {\n                    throw parse_error(\"invalid value separator is found.\", line, indent);\n                }\n                m_flow_token_state = flow_token_state_t::NEEDS_VALUE_OR_SUFFIX;\n                break;\n            case lexical_token_t::ALIAS_PREFIX: {\n                // An alias node must not specify any properties (tag, anchor).\n                // https://yaml.org/spec/1.2.2/#71-alias-nodes\n                if FK_YAML_UNLIKELY (m_needs_tag_impl) {\n                    throw parse_error(\"Tag cannot be specified to an alias node\", line, indent);\n                }\n                if FK_YAML_UNLIKELY (m_needs_anchor_impl) {\n                    throw parse_error(\"Anchor cannot be specified to an alias node.\", line, indent);\n                }\n\n                std::string token_str = std::string(token.str.begin(), token.str.end());\n\n                const auto anchor_counts = static_cast<uint32_t>(mp_meta->anchor_table.count(token_str));\n                if FK_YAML_UNLIKELY (anchor_counts == 0) {\n                    throw parse_error(\"The given anchor name must appear prior to the alias node.\", line, indent);\n                }\n\n                basic_node_type node {};\n                node.m_attrs |= detail::node_attr_bits::alias_bit;\n                node.m_prop.anchor = std::move(token_str);\n                detail::node_attr_bits::set_anchor_offset(anchor_counts - 1, node.m_attrs);\n\n                apply_directive_set(node);\n                apply_node_properties(node);\n\n                deserialize_scalar(lexer, std::move(node), indent, line, token);\n                continue;\n            }\n            case lexical_token_t::PLAIN_SCALAR:\n            case lexical_token_t::SINGLE_QUOTED_SCALAR:\n            case lexical_token_t::DOUBLE_QUOTED_SCALAR: {\n                tag_t tag_type {tag_t::NONE};\n                if (m_needs_tag_impl) {\n                    tag_type = tag_resolver_type::resolve_tag(m_tag_name, mp_meta);\n                }\n\n                basic_node_type node = scalar_parser_type(line, indent).parse_flow(token.type, tag_type, token.str);\n                apply_directive_set(node);\n                apply_node_properties(node);\n\n                deserialize_scalar(lexer, std::move(node), indent, line, token);\n                continue;\n            }\n            case lexical_token_t::BLOCK_LITERAL_SCALAR:\n            case lexical_token_t::BLOCK_FOLDED_SCALAR: {\n                tag_t tag_type {tag_t::NONE};\n                if (m_needs_tag_impl) {\n                    tag_type = tag_resolver_type::resolve_tag(m_tag_name, mp_meta);\n                }\n\n                basic_node_type node =\n                    scalar_parser_type(line, indent)\n                        .parse_block(token.type, tag_type, token.str, lexer.get_block_scalar_header());\n                apply_directive_set(node);\n                apply_node_properties(node);\n\n                deserialize_scalar(lexer, std::move(node), indent, line, token);\n                continue;\n            }\n            // these tokens end parsing the current YAML document.\n            case lexical_token_t::END_OF_BUFFER:\n                // This handles an empty input.\n                last_type = token.type;\n                return;\n            case lexical_token_t::END_OF_DIRECTIVES:\n            case lexical_token_t::END_OF_DOCUMENT:\n                if FK_YAML_UNLIKELY (m_flow_context_depth > 0) {\n                    throw parse_error(\"An invalid document marker found in a flow collection\", line, indent);\n                }\n                last_type = token.type;\n                return;\n            // no way to come here while lexically analyzing document contents.\n            case lexical_token_t::YAML_VER_DIRECTIVE: // LCOV_EXCL_LINE\n            case lexical_token_t::TAG_DIRECTIVE:      // LCOV_EXCL_LINE\n            case lexical_token_t::INVALID_DIRECTIVE:  // LCOV_EXCL_LINE\n                detail::unreachable();                // LCOV_EXCL_LINE\n            }\n\n            token = lexer.get_next_token();\n            indent = lexer.get_last_token_begin_pos();\n            line = lexer.get_lines_processed();\n        } while (token.type != lexical_token_t::END_OF_BUFFER);\n\n        last_type = token.type;\n    }\n\n    /// @brief Deserializes YAML node properties (anchor and/or tag names) if they exist\n    /// @param lexer The lexical analyzer to be used.\n    /// @param last_type The variable to store the last lexical token type.\n    /// @param line The variable to store the line of either the first property or the last non-property token.\n    /// @param indent The variable to store the indent of either the first property or the last non-property token.\n    /// @return true if any property is found, false otherwise.\n    bool deserialize_node_properties(lexer_type& lexer, lexical_token& last_token, uint32_t& line, uint32_t& indent) {\n        m_needs_anchor_impl = m_needs_tag_impl = false;\n\n        lexical_token token = last_token;\n        bool ends_loop {false};\n        do {\n            if (line < lexer.get_lines_processed()) {\n                break;\n            }\n\n            switch (token.type) {\n            case lexical_token_t::ANCHOR_PREFIX:\n                if FK_YAML_UNLIKELY (m_needs_anchor_impl) {\n                    throw parse_error(\n                        \"anchor name cannot be specified more than once to the same node.\",\n                        lexer.get_lines_processed(),\n                        lexer.get_last_token_begin_pos());\n                }\n\n                m_anchor_name = token.str;\n                m_needs_anchor_impl = true;\n\n                if (!m_needs_tag_impl) {\n                    line = lexer.get_lines_processed();\n                    indent = lexer.get_last_token_begin_pos();\n                }\n\n                token = lexer.get_next_token();\n                break;\n            case lexical_token_t::TAG_PREFIX: {\n                if FK_YAML_UNLIKELY (m_needs_tag_impl) {\n                    throw parse_error(\n                        \"tag name cannot be specified more than once to the same node.\",\n                        lexer.get_lines_processed(),\n                        lexer.get_last_token_begin_pos());\n                }\n\n                m_tag_name = token.str;\n                m_needs_tag_impl = true;\n\n                if (!m_needs_anchor_impl) {\n                    line = lexer.get_lines_processed();\n                    indent = lexer.get_last_token_begin_pos();\n                }\n\n                token = lexer.get_next_token();\n                break;\n            }\n            default:\n                ends_loop = true;\n                break;\n            }\n        } while (!ends_loop);\n\n        last_token = token;\n        const bool prop_specified = m_needs_anchor_impl || m_needs_tag_impl;\n        if (!prop_specified) {\n            line = lexer.get_lines_processed();\n            indent = lexer.get_last_token_begin_pos();\n        }\n\n        return prop_specified;\n    }\n\n    /// @brief Add new key string to the current YAML node.\n    /// @param key a key string to be added to the current YAML node.\n    /// @param line The line where the key is found.\n    /// @param indent The indentation width in the current line where the key is found.\n    void add_new_key(basic_node_type&& key, const uint32_t line, const uint32_t indent) {\n        if (m_flow_context_depth == 0) {\n            if FK_YAML_UNLIKELY (m_context_stack.back().indent < indent) {\n                // bad indentation like the following YAML:\n                // ```yaml\n                // foo: true\n                //   baz: 123\n                // # ^\n                // ```\n                throw parse_error(\"bad indentation of a mapping entry.\", line, indent);\n            }\n\n            pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                return (c.state == context_state_t::BLOCK_MAPPING) && (indent == c.indent);\n            });\n        }\n        else {\n            if FK_YAML_UNLIKELY (m_flow_token_state != flow_token_state_t::NEEDS_VALUE_OR_SUFFIX) {\n                throw parse_error(\"Flow mapping entry is found without separated with a comma.\", line, indent);\n            }\n\n            if (mp_current_node->is_sequence()) {\n                mp_current_node->template get_value_ref<sequence_type&>().emplace_back(basic_node_type::mapping());\n                mp_current_node = &(mp_current_node->operator[](mp_current_node->size() - 1));\n                m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n            }\n        }\n\n        auto itr = mp_current_node->template get_value_ref<mapping_type&>().emplace(std::move(key), basic_node_type());\n        if FK_YAML_UNLIKELY (!itr.second) {\n            throw parse_error(\"Detected duplication in mapping keys.\", line, indent);\n        }\n\n        mp_current_node = &(itr.first->second);\n        const parse_context& key_context = m_context_stack.back();\n        m_context_stack.emplace_back(\n            key_context.line, key_context.indent, context_state_t::MAPPING_VALUE, mp_current_node);\n    }\n\n    /// @brief Assign node value to the current node.\n    /// @param node_value A rvalue basic_node_type object to be assigned to the current node.\n    void assign_node_value(basic_node_type&& node_value, const uint32_t line, const uint32_t indent) {\n        if (mp_current_node->is_sequence()) {\n            FK_YAML_ASSERT(m_flow_context_depth > 0);\n\n            if FK_YAML_UNLIKELY (m_flow_token_state != flow_token_state_t::NEEDS_VALUE_OR_SUFFIX) {\n                // Flow sequence entries are not allowed to be empty.\n                // ```yaml\n                // [foo,,bar]\n                // ```\n                throw parse_error(\"flow sequence entry is found without separated with a comma.\", line, indent);\n            }\n\n            mp_current_node->template get_value_ref<sequence_type&>().emplace_back(std::move(node_value));\n            m_flow_token_state = flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX;\n            return;\n        }\n\n        // a scalar node\n        *mp_current_node = std::move(node_value);\n        if FK_YAML_UNLIKELY (m_context_stack.empty()) {\n            // single scalar document.\n            return;\n        }\n\n        if FK_YAML_LIKELY (m_context_stack.back().state != context_state_t::BLOCK_MAPPING_EXPLICIT_KEY) {\n            m_context_stack.pop_back();\n            mp_current_node = m_context_stack.back().p_node;\n\n            if (m_flow_context_depth > 0) {\n                m_flow_token_state = flow_token_state_t::NEEDS_SEPARATOR_OR_SUFFIX;\n            }\n        }\n    }\n\n    /// @brief Deserialize a detected scalar node.\n    /// @param lexer The lexical analyzer to be used.\n    /// @param node A scalar node.\n    /// @param indent The current indentation width. Can be updated in this function.\n    /// @param line The number of processed lines. Can be updated in this function.\n    /// @param token The storage for last lexical token.\n    /// @return true if next token has already been got, false otherwise.\n    void deserialize_scalar(\n        lexer_type& lexer, basic_node_type&& node, uint32_t& indent, uint32_t& line, lexical_token& token) {\n        token = lexer.get_next_token();\n        if (mp_current_node->is_mapping()) {\n            const bool is_key_sep_followed =\n                (token.type == lexical_token_t::KEY_SEPARATOR) && (line == lexer.get_lines_processed());\n            if FK_YAML_UNLIKELY (!is_key_sep_followed) {\n                throw parse_error(\n                    \"The \\\":\\\" mapping value indicator must be followed after a mapping key.\",\n                    lexer.get_lines_processed(),\n                    lexer.get_last_token_begin_pos());\n            }\n            add_new_key(std::move(node), line, indent);\n        }\n        else if (token.type == lexical_token_t::KEY_SEPARATOR) {\n            if FK_YAML_UNLIKELY (line != lexer.get_lines_processed()) {\n                // This path is for explicit mapping key separator like:\n                // ```yaml\n                //   ? foo\n                //   : bar\n                // # ^ this separator\n                // ```\n                assign_node_value(std::move(node), line, indent);\n                indent = lexer.get_last_token_begin_pos();\n                line = lexer.get_lines_processed();\n\n                if (m_context_stack.back().state != context_state_t::BLOCK_MAPPING_EXPLICIT_KEY) {\n                    pop_to_parent_node(line, indent, [indent](const parse_context& c) {\n                        return c.state == context_state_t::BLOCK_MAPPING_EXPLICIT_KEY && indent == c.indent;\n                    });\n                }\n                return;\n            }\n\n            if (mp_current_node->is_scalar()) {\n                if FK_YAML_LIKELY (!m_context_stack.empty()) {\n                    parse_context& cur_context = m_context_stack.back();\n                    switch (cur_context.state) {\n                    case context_state_t::BLOCK_MAPPING_EXPLICIT_KEY:\n                    case context_state_t::BLOCK_MAPPING_EXPLICIT_VALUE:\n                    case context_state_t::BLOCK_SEQUENCE_ENTRY:\n                        m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                        break;\n                    default:\n                        if FK_YAML_UNLIKELY (cur_context.line == line) {\n                            throw parse_error(\"Multiple mapping keys are specified on the same line.\", line, indent);\n                        }\n                        cur_context.line = line;\n                        cur_context.indent = indent;\n                        cur_context.state = context_state_t::BLOCK_MAPPING;\n                        break;\n                    }\n\n                    *mp_current_node = basic_node_type::mapping();\n                    apply_directive_set(*mp_current_node);\n                }\n                else {\n                    // root mapping node\n\n                    m_context_stack.emplace_back(line, indent, context_state_t::BLOCK_MAPPING, mp_current_node);\n                    *mp_current_node = basic_node_type::mapping();\n                    apply_directive_set(*mp_current_node);\n\n                    // apply node properties if any to the root mapping node.\n                    if (!m_root_anchor_name.empty()) {\n                        mp_current_node->add_anchor_name(\n                            std::string(m_root_anchor_name.begin(), m_root_anchor_name.end()));\n                        m_root_anchor_name = {};\n                    }\n                    if (!m_root_tag_name.empty()) {\n                        mp_current_node->add_tag_name(std::string(m_root_tag_name.begin(), m_root_tag_name.end()));\n                        m_root_tag_name = {};\n                    }\n                }\n            }\n            add_new_key(std::move(node), line, indent);\n        }\n        else {\n            assign_node_value(std::move(node), line, indent);\n        }\n\n        indent = lexer.get_last_token_begin_pos();\n        line = lexer.get_lines_processed();\n    }\n\n    /// @brief Pops parent contexts to a block mapping with the given indentation.\n    /// @tparam Pred Functor type to test parent contexts.\n    /// @param line The current line count.\n    /// @param indent The indentation level of the target parent block mapping.\n    template <typename Pred>\n    void pop_to_parent_node(uint32_t line, uint32_t indent, Pred&& pred) {\n        FK_YAML_ASSERT(!m_context_stack.empty());\n\n        // LCOV_EXCL_START\n        auto itr = std::find_if(m_context_stack.rbegin(), m_context_stack.rend(), std::forward<Pred>(pred));\n        // LCOV_EXCL_STOP\n        const bool is_indent_valid = (itr != m_context_stack.rend());\n        if FK_YAML_UNLIKELY (!is_indent_valid) {\n            throw parse_error(\"Detected invalid indentation.\", line, indent);\n        }\n\n        const auto pop_num = static_cast<uint32_t>(std::distance(m_context_stack.rbegin(), itr));\n\n        // move back to the parent block mapping.\n        for (uint32_t i = 0; i < pop_num; i++) {\n            m_context_stack.pop_back();\n        }\n        mp_current_node = m_context_stack.back().p_node;\n    }\n\n    /// @brief Set YAML directive properties to the given node.\n    /// @param node A basic_node_type object to be set YAML directive properties.\n    void apply_directive_set(basic_node_type& node) noexcept {\n        node.mp_meta = mp_meta;\n    }\n\n    /// @brief Set YAML node properties (anchor and/or tag names) to the given node.\n    /// @param node A node type object to be set YAML node properties.\n    void apply_node_properties(basic_node_type& node) {\n        if (m_needs_anchor_impl) {\n            node.add_anchor_name(std::string(m_anchor_name.begin(), m_anchor_name.end()));\n            m_needs_anchor_impl = false;\n            m_anchor_name = {};\n        }\n\n        if (m_needs_tag_impl) {\n            node.add_tag_name(std::string(m_tag_name.begin(), m_tag_name.end()));\n            m_needs_tag_impl = false;\n            m_tag_name = {};\n        }\n    }\n\n    /// @brief Update the target YAML version with an input string.\n    /// @param version_str A YAML version string.\n    yaml_version_type convert_yaml_version(str_view version_str) noexcept {\n        return (version_str.compare(\"1.1\") == 0) ? yaml_version_type::VERSION_1_1 : yaml_version_type::VERSION_1_2;\n    }\n\nprivate:\n    /// The currently focused YAML node.\n    basic_node_type* mp_current_node {nullptr};\n    /// The stack of parse contexts.\n    std::deque<parse_context> m_context_stack {};\n    /// The current depth of flow contexts.\n    uint32_t m_flow_context_depth {0};\n    /// The set of YAML directives.\n    std::shared_ptr<doc_metainfo_type> mp_meta {};\n    /// A flag to determine the need for YAML anchor node implementation.\n    bool m_needs_anchor_impl {false};\n    /// A flag to determine the need for a corresponding node with the last YAML tag.\n    bool m_needs_tag_impl {false};\n    /// A flag to determine the need for a value separator or a flow suffix to follow.\n    flow_token_state_t m_flow_token_state {flow_token_state_t::NEEDS_VALUE_OR_SUFFIX};\n    /// The last YAML anchor name.\n    str_view m_anchor_name;\n    /// The last tag name.\n    str_view m_tag_name;\n    /// The root YAML anchor name. (maybe empty and unused)\n    str_view m_root_anchor_name;\n    /// The root tag name. (maybe empty and unused)\n    str_view m_root_tag_name;\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_DESERIALIZER_HPP */\n\n// #include <fkYAML/detail/input/input_adapter.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_INPUT_INPUT_ADAPTER_HPP\n#define FK_YAML_DETAIL_INPUT_INPUT_ADAPTER_HPP\n\n#include <array>\n#include <cstdio>\n#include <cstring>\n#include <deque>\n#include <istream>\n#include <iterator>\n#include <string>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/assert.hpp>\n\n// #include <fkYAML/detail/encodings/utf_encode_detector.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_DETECTOR_HPP\n#define FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_DETECTOR_HPP\n\n#include <cstdint>\n#include <istream>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/encodings/utf_encode_t.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_T_HPP\n#define FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_T_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Definition of Unicode encoding types\n/// @note Since fkYAML doesn't treat UTF-16/UTF-32 encoded characters per byte, endians do not matter.\nenum class utf_encode_t : std::uint8_t {\n    UTF_8,    //!< UTF-8\n    UTF_16BE, //!< UTF-16 Big Endian\n    UTF_16LE, //!< UTF-16 Little Endian\n    UTF_32BE, //!< UTF-32 Big Endian\n    UTF_32LE, //!< UTF-32 Little Endian\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_T_HPP */\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Detect an encoding type for UTF-8 expected inputs.\n/// @note This function doesn't support the case where the first character is null.\n/// @param[in] bytes 4 bytes of an input character sequence.\n/// @param[out] has_bom Whether the input contains a BOM.\n/// @return A detected encoding type.\ninline utf_encode_t detect_encoding_type(const std::array<uint8_t, 4>& bytes, bool& has_bom) noexcept {\n    has_bom = false;\n\n    const uint8_t byte0 = bytes[0];\n    const uint8_t byte1 = bytes[1];\n    const uint8_t byte2 = bytes[2];\n    const uint8_t byte3 = bytes[3];\n\n    // Check if a BOM exists.\n\n    if (byte0 == static_cast<uint8_t>(0xEFu) && byte1 == static_cast<uint8_t>(0xBBu) &&\n        byte2 == static_cast<uint8_t>(0xBFu)) {\n        has_bom = true;\n        return utf_encode_t::UTF_8;\n    }\n\n    if (byte0 == 0 && byte1 == 0 && byte2 == static_cast<uint8_t>(0xFEu) && byte3 == static_cast<uint8_t>(0xFFu)) {\n        has_bom = true;\n        return utf_encode_t::UTF_32BE;\n    }\n\n    if (byte0 == static_cast<uint8_t>(0xFFu) && byte1 == static_cast<uint8_t>(0xFEu) && byte2 == 0 && byte3 == 0) {\n        has_bom = true;\n        return utf_encode_t::UTF_32LE;\n    }\n\n    if (byte0 == static_cast<uint8_t>(0xFEu) && byte1 == static_cast<uint8_t>(0xFFu)) {\n        has_bom = true;\n        return utf_encode_t::UTF_16BE;\n    }\n\n    if (byte0 == static_cast<uint8_t>(0xFFu) && byte1 == static_cast<uint8_t>(0xFEu)) {\n        has_bom = true;\n        return utf_encode_t::UTF_16LE;\n    }\n\n    // Test the first character assuming it's an ASCII character.\n\n    if (byte0 == 0 && byte1 == 0 && byte2 == 0 && 0 < byte3 && byte3 < static_cast<uint8_t>(0x80u)) {\n        return utf_encode_t::UTF_32BE;\n    }\n\n    if (0 < byte0 && byte0 < static_cast<uint8_t>(0x80u) && byte1 == 0 && byte2 == 0 && byte3 == 0) {\n        return utf_encode_t::UTF_32LE;\n    }\n\n    if (byte0 == 0 && 0 < byte1 && byte1 < static_cast<uint8_t>(0x80u)) {\n        return utf_encode_t::UTF_16BE;\n    }\n\n    if (0 < byte0 && byte0 < static_cast<uint8_t>(0x80u) && byte1 == 0) {\n        return utf_encode_t::UTF_16LE;\n    }\n\n    return utf_encode_t::UTF_8;\n}\n\n/// @brief A class which detects UTF encoding type and the existence of a BOM at the beginning.\n/// @tparam ItrType Type of iterators for the input.\ntemplate <typename ItrType, typename = void>\nstruct utf_encode_detector {};\n\n/// @brief The partial specialization of utf_encode_detector for char iterators.\n/// @tparam ItrType An iterator type.\ntemplate <typename ItrType>\nstruct utf_encode_detector<ItrType, enable_if_t<is_iterator_of<ItrType, char>::value>> {\n    /// @brief Detects the encoding type of the input, and consumes a BOM if it exists.\n    /// @param begin The iterator to the first element of an input.\n    /// @param end The iterator to the past-the end element of an input.\n    /// @return A detected encoding type.\n    static utf_encode_t detect(ItrType& begin, const ItrType& end) noexcept {\n        if FK_YAML_UNLIKELY (begin == end) {\n            return utf_encode_t::UTF_8;\n        }\n\n        // the inner curly braces are necessary for older compilers\n        std::array<uint8_t, 4> bytes {{}};\n        bytes.fill(0xFFu);\n        for (int i = 0; i < 4 && begin + i != end; i++) {\n            bytes[i] = static_cast<uint8_t>(begin[i]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)\n        }\n\n        bool has_bom = false;\n        const utf_encode_t encode_type = detect_encoding_type(bytes, has_bom);\n\n        if (has_bom) {\n            // skip reading the BOM.\n            switch (encode_type) {\n            case utf_encode_t::UTF_8:\n                std::advance(begin, 3);\n                break;\n            case utf_encode_t::UTF_16BE:\n            case utf_encode_t::UTF_16LE:\n                std::advance(begin, 2);\n                break;\n            case utf_encode_t::UTF_32BE:\n            case utf_encode_t::UTF_32LE:\n                std::advance(begin, 4);\n                break;\n            }\n        }\n\n        return encode_type;\n    }\n};\n\n#if FK_YAML_HAS_CHAR8_T\n\n/// @brief The partial specialization of utf_encode_detector for char8_t iterators.\n/// @tparam ItrType An iterator type.\ntemplate <typename ItrType>\nstruct utf_encode_detector<ItrType, enable_if_t<is_iterator_of<ItrType, char8_t>::value>> {\n    /// @brief Detects the encoding type of the input, and consumes a BOM if it exists.\n    /// @param begin The iterator to the first element of an input.\n    /// @param end The iterator to the past-the end element of an input.\n    /// @return A detected encoding type.\n    static utf_encode_t detect(ItrType& begin, const ItrType& end) {\n        if FK_YAML_UNLIKELY (begin == end) {\n            return utf_encode_t::UTF_8;\n        }\n\n        std::array<uint8_t, 4> bytes {};\n        bytes.fill(0xFFu);\n        for (int i = 0; i < 4 && begin + i != end; i++) {\n            bytes[i] = uint8_t(begin[i]); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)\n        }\n\n        bool has_bom = false;\n        const utf_encode_t encode_type = detect_encoding_type(bytes, has_bom);\n\n        if FK_YAML_UNLIKELY (encode_type != utf_encode_t::UTF_8) {\n            throw exception(\"char8_t characters must be encoded in the UTF-8 format.\");\n        }\n\n        if (has_bom) {\n            // skip reading the BOM.\n            std::advance(begin, 3);\n        }\n\n        return encode_type;\n    }\n};\n\n#endif // FK_YAML_HAS_CHAR8_T\n\n/// @brief The partial specialization of utf_encode_detector for char16_t iterators.\n/// @tparam ItrType An iterator type.\ntemplate <typename ItrType>\nstruct utf_encode_detector<ItrType, enable_if_t<is_iterator_of<ItrType, char16_t>::value>> {\n    /// @brief Detects the encoding type of the input, and consumes a BOM if it exists.\n    /// @param begin The iterator to the first element of an input.\n    /// @param end The iterator to the past-the end element of an input.\n    /// @return A detected encoding type.\n    static utf_encode_t detect(ItrType& begin, const ItrType& end) {\n        if FK_YAML_UNLIKELY (begin == end) {\n            return utf_encode_t::UTF_16BE;\n        }\n\n        // the inner curly braces are necessary for older compilers\n        std::array<uint8_t, 4> bytes {{}};\n        bytes.fill(0xFFu);\n        for (int i = 0; i < 2 && begin + i != end; i++) {\n            // NOLINTBEGIN(cppcoreguidelines-pro-bounds-constant-array-index)\n            const char16_t elem = begin[i];\n            const int idx_base = i * 2;\n            bytes[idx_base] = static_cast<uint8_t>((elem & 0xFF00u) >> 8);\n            bytes[idx_base + 1] = static_cast<uint8_t>(elem & 0xFFu);\n            // NOLINTEND(cppcoreguidelines-pro-bounds-constant-array-index)\n        }\n\n        bool has_bom = false;\n        const utf_encode_t encode_type = detect_encoding_type(bytes, has_bom);\n\n        if FK_YAML_UNLIKELY (encode_type != utf_encode_t::UTF_16BE && encode_type != utf_encode_t::UTF_16LE) {\n            throw exception(\"char16_t characters must be encoded in the UTF-16 format.\");\n        }\n\n        if (has_bom) {\n            // skip reading the BOM.\n            std::advance(begin, 1);\n        }\n\n        return encode_type;\n    }\n};\n\n/// @brief The partial specialization of utf_encode_detector for char32_t iterators.\n/// @tparam ItrType An iterator type.\ntemplate <typename ItrType>\nstruct utf_encode_detector<ItrType, enable_if_t<is_iterator_of<ItrType, char32_t>::value>> {\n    /// @brief Detects the encoding type of the input, and consumes a BOM if it exists.\n    /// @param begin The iterator to the first element of an input.\n    /// @param end The iterator to the past-the end element of an input.\n    /// @return A detected encoding type.\n    static utf_encode_t detect(ItrType& begin, const ItrType& end) {\n        if FK_YAML_UNLIKELY (begin == end) {\n            return utf_encode_t::UTF_32BE;\n        }\n\n        // the inner curly braces are necessary for older compilers\n        std::array<uint8_t, 4> bytes {{}};\n        const char32_t elem = *begin;\n        bytes[0] = static_cast<uint8_t>((elem & 0xFF000000u) >> 24);\n        bytes[1] = static_cast<uint8_t>((elem & 0x00FF0000u) >> 16);\n        bytes[2] = static_cast<uint8_t>((elem & 0x0000FF00u) >> 8);\n        bytes[3] = static_cast<uint8_t>(elem & 0x000000FFu);\n\n        bool has_bom = false;\n        const utf_encode_t encode_type = detect_encoding_type(bytes, has_bom);\n\n        if FK_YAML_UNLIKELY (encode_type != utf_encode_t::UTF_32BE && encode_type != utf_encode_t::UTF_32LE) {\n            throw exception(\"char32_t characters must be encoded in the UTF-32 format.\");\n        }\n\n        if (has_bom) {\n            // skip reading the BOM.\n            std::advance(begin, 1);\n        }\n\n        return encode_type;\n    }\n};\n\n/// @brief A class which detects UTF encoding type and the existence of a BOM from the input file.\nstruct file_utf_encode_detector {\n    /// @brief Detects the encoding type of the input, and consumes a BOM if it exists.\n    /// @param p_file The input file handle.\n    /// @return A detected encoding type.\n    static utf_encode_t detect(std::FILE* p_file) noexcept {\n        // the inner curly braces are necessary for older compilers\n        std::array<uint8_t, 4> bytes {{}};\n        bytes.fill(0xFFu);\n        for (int i = 0; i < 4; i++) {\n            char byte = 0;\n            const std::size_t size = std::fread(&byte, sizeof(char), 1, p_file);\n            if (size != sizeof(char)) {\n                break;\n            }\n            bytes[i] = static_cast<uint8_t>(byte & 0xFF); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)\n        }\n\n        bool has_bom = false;\n        const utf_encode_t encode_type = detect_encoding_type(bytes, has_bom);\n\n        // move back to the beginning if a BOM doesn't exist.\n        long offset = 0; // NOLINT(google-runtime-int)\n        if (has_bom) {\n            switch (encode_type) {\n            case utf_encode_t::UTF_8:\n                offset = 3;\n                break;\n            case utf_encode_t::UTF_16BE:\n            case utf_encode_t::UTF_16LE:\n                offset = 2;\n                break;\n            case utf_encode_t::UTF_32BE:\n            case utf_encode_t::UTF_32LE:\n                offset = 4;\n                break;\n            }\n        }\n        std::fseek(p_file, offset, SEEK_SET); // NOLINT(cert-err33-c)\n\n        return encode_type;\n    }\n};\n\n/// @brief A class which detects UTF encoding type and the existence of a BOM from the input file.\nstruct stream_utf_encode_detector {\n    /// @brief Detects the encoding type of the input, and consumes a BOM if it exists.\n    /// @param p_file The input file handle.\n    /// @return A detected encoding type.\n    static utf_encode_t detect(std::istream& is) noexcept {\n        // the inner curly braces are necessary for older compilers\n        std::array<uint8_t, 4> bytes {{}};\n        bytes.fill(0xFFu);\n        for (int i = 0; i < 4; i++) {\n            char ch = 0;\n            is.read(&ch, 1);\n            const std::streamsize size = is.gcount();\n            if (size != 1) {\n                // without this, seekg() will fail.\n                is.clear();\n                break;\n            }\n            bytes[i] = static_cast<uint8_t>(ch & 0xFF); // NOLINT(cppcoreguidelines-pro-bounds-constant-array-index)\n        }\n\n        bool has_bom = false;\n        const utf_encode_t encode_type = detect_encoding_type(bytes, has_bom);\n\n        // move back to the beginning if a BOM doesn't exist.\n        std::streamoff offset = 0;\n        if (has_bom) {\n            switch (encode_type) {\n            case utf_encode_t::UTF_8:\n                offset = 3;\n                break;\n            case utf_encode_t::UTF_16BE:\n            case utf_encode_t::UTF_16LE:\n                offset = 2;\n                break;\n            case utf_encode_t::UTF_32BE:\n            case utf_encode_t::UTF_32LE:\n                offset = 4;\n                break;\n            }\n        }\n        is.seekg(offset, std::ios_base::beg);\n\n        return encode_type;\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_ENCODINGS_UTF_ENCODE_DETECTOR_HPP */\n\n// #include <fkYAML/detail/encodings/utf_encode_t.hpp>\n\n// #include <fkYAML/detail/encodings/utf_encodings.hpp>\n\n// #include <fkYAML/detail/meta/input_adapter_traits.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/str_view.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n///////////////////////\n//   input_adapter   //\n///////////////////////\n\ntemplate <typename IterType, typename = void>\nclass iterator_input_adapter;\n\n/// @brief An input adapter for iterators of type char.\n/// @tparam IterType An iterator type.\ntemplate <typename IterType>\nclass iterator_input_adapter<IterType, enable_if_t<is_iterator_of<IterType, char>::value>> {\npublic:\n    /// @brief Construct a new iterator_input_adapter object.\n    iterator_input_adapter() = default;\n\n    /// @brief Construct a new iterator_input_adapter object.\n    /// @param begin The beginning of iterators.\n    /// @param end The end of iterators.\n    /// @param encode_type The encoding type for this input adapter.\n    /// @param is_contiguous Whether iterators are contiguous or not.\n    iterator_input_adapter(IterType begin, IterType end, utf_encode_t encode_type, bool is_contiguous) noexcept\n        : m_begin(begin),\n          m_end(end),\n          m_encode_type(encode_type),\n          m_is_contiguous(is_contiguous) {\n    }\n\n    // allow only move construct/assignment like other input adapters.\n    iterator_input_adapter(const iterator_input_adapter&) = delete;\n    iterator_input_adapter(iterator_input_adapter&& rhs) = default;\n    iterator_input_adapter& operator=(const iterator_input_adapter&) = delete;\n    iterator_input_adapter& operator=(iterator_input_adapter&&) = default;\n    ~iterator_input_adapter() = default;\n\n    /// @brief Get view into the input buffer contents.\n    /// @return View into the input buffer contents.\n    str_view get_buffer_view() {\n        if FK_YAML_UNLIKELY (m_begin == m_end) {\n            return {};\n        }\n\n        m_buffer.clear();\n\n        switch (m_encode_type) {\n        case utf_encode_t::UTF_8:\n            return get_buffer_view_utf8();\n        case utf_encode_t::UTF_16BE:\n        case utf_encode_t::UTF_16LE:\n            return get_buffer_view_utf16();\n        case utf_encode_t::UTF_32BE:\n        case utf_encode_t::UTF_32LE:\n            return get_buffer_view_utf32();\n        default:                   // LCOV_EXCL_LINE\n            detail::unreachable(); // LCOV_EXCL_LINE\n        }\n    }\n\nprivate:\n    /// @brief The concrete implementation of get_buffer_view() for UTF-8 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf8() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_8);\n\n        IterType current = m_begin;\n        std::deque<IterType> cr_itrs {};\n        while (current != m_end) {\n            const auto first = static_cast<uint8_t>(*current++);\n            const uint32_t num_bytes = utf8::get_num_bytes(first);\n\n            switch (num_bytes) {\n            case 1:\n                if FK_YAML_UNLIKELY (first == 0x0D /*CR*/) {\n                    cr_itrs.emplace_back(std::prev(current));\n                }\n                break;\n            case 2: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second});\n                }\n                break;\n            }\n            case 3: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third});\n                }\n                break;\n            }\n            case 4: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const auto fourth = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third, fourth);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third, fourth});\n                }\n                break;\n            }\n            default:           // LCOV_EXCL_LINE\n                unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n\n        const bool is_contiguous_no_cr = cr_itrs.empty() && m_is_contiguous;\n        if FK_YAML_LIKELY (is_contiguous_no_cr) {\n            // The input iterators (begin, end) can be used as-is during parsing.\n            return str_view {m_begin, m_end};\n        }\n\n        m_buffer.reserve(std::distance(m_begin, m_end) - cr_itrs.size());\n\n        current = m_begin;\n        for (const auto& cr_itr : cr_itrs) {\n            m_buffer.append(current, cr_itr);\n            current = std::next(cr_itr);\n        }\n        m_buffer.append(current, m_end);\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\n    /// @brief The concrete implementation of get_buffer_view() for UTF-16 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf16() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_16BE || m_encode_type == utf_encode_t::UTF_16LE);\n\n        // Assume the input characters are all ASCII characters.\n        // That's the most probably the case.\n        m_buffer.reserve(std::distance(m_begin, m_end) / 2);\n\n        int shift_bits[2] {0, 0};\n        if (m_encode_type == utf_encode_t::UTF_16BE) {\n            shift_bits[0] = 8;\n        }\n        else // m_encode_type == utf_encode_t::UTF_16LE\n        {\n            shift_bits[1] = 8;\n        }\n\n        std::array<char16_t, 2> encoded_buffer {{0, 0}};\n        uint32_t encoded_buf_size {0};\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        IterType current = m_begin;\n        while (current != m_end || encoded_buf_size != 0) {\n            while (current != m_end && encoded_buf_size < 2) {\n                auto utf16 = static_cast<char16_t>(static_cast<uint8_t>(*current++) << shift_bits[0]);\n                utf16 |= static_cast<char16_t>(static_cast<uint8_t>(*current++) << shift_bits[1]);\n\n                // skip appending CRs.\n                if FK_YAML_LIKELY (utf16 != char16_t(0x000Du)) {\n                    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)\n                    encoded_buffer[encoded_buf_size++] = utf16;\n                }\n            }\n\n            uint32_t consumed_size = 0;\n            utf8::from_utf16(encoded_buffer, utf8_buffer, consumed_size, utf8_buf_size);\n\n            if FK_YAML_LIKELY (consumed_size == 1) {\n                encoded_buffer[0] = encoded_buffer[1];\n            }\n            encoded_buf_size -= consumed_size;\n\n            m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\n    /// @brief The concrete implementation of get_buffer_view() for UTF-32 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf32() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_32BE || m_encode_type == utf_encode_t::UTF_32LE);\n\n        // Assume the input characters are all ASCII characters.\n        // That's the most probably the case.\n        m_buffer.reserve(std::distance(m_begin, m_end) / 4);\n\n        int shift_bits[4] {0, 0, 0, 0};\n        if (m_encode_type == utf_encode_t::UTF_32BE) {\n            shift_bits[0] = 24;\n            shift_bits[1] = 16;\n            shift_bits[2] = 8;\n        }\n        else // m_encode_type == utf_encode_t::UTF_32LE\n        {\n            shift_bits[1] = 8;\n            shift_bits[2] = 16;\n            shift_bits[3] = 24;\n        }\n\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        IterType current = m_begin;\n        while (current != m_end) {\n            auto utf32 = static_cast<char32_t>(*current++ << shift_bits[0]);\n            utf32 |= static_cast<char32_t>(*current++ << shift_bits[1]);\n            utf32 |= static_cast<char32_t>(*current++ << shift_bits[2]);\n            utf32 |= static_cast<char32_t>(*current++ << shift_bits[3]);\n\n            if FK_YAML_LIKELY (utf32 != char32_t(0x0000000Du)) {\n                utf8::from_utf32(utf32, utf8_buffer, utf8_buf_size);\n                m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n            }\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\nprivate:\n    /// The iterator at the beginning of input.\n    IterType m_begin {};\n    /// The iterator at the end of input.\n    IterType m_end {};\n    /// The encoding type for this input adapter.\n    utf_encode_t m_encode_type {utf_encode_t::UTF_8};\n    /// The normalized owned buffer.\n    std::string m_buffer;\n    /// Whether ItrType is a contiguous iterator.\n    bool m_is_contiguous {false};\n};\n\n#if FK_YAML_HAS_CHAR8_T\n\n/// @brief An input adapter for iterators of type char8_t.\n/// @tparam IterType An iterator type.\ntemplate <typename IterType>\nclass iterator_input_adapter<IterType, enable_if_t<is_iterator_of<IterType, char8_t>::value>> {\npublic:\n    /// @brief Construct a new iterator_input_adapter object.\n    iterator_input_adapter() = default;\n\n    /// @brief Construct a new iterator_input_adapter object.\n    /// @param begin The beginning of iterators.\n    /// @param end The end of iterators.\n    /// @param encode_type The encoding type for this input adapter.\n    /// @param is_contiguous Whether iterators are contiguous or not.\n    iterator_input_adapter(IterType begin, IterType end, utf_encode_t encode_type, bool is_contiguous) noexcept\n        : m_begin(begin),\n          m_end(end),\n          m_encode_type(encode_type),\n          m_is_contiguous(is_contiguous) {\n        // char8_t characters must be encoded in the UTF-8 format.\n        // See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0482r6.html.\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_8);\n    }\n\n    // allow only move construct/assignment like other input adapters.\n    iterator_input_adapter(const iterator_input_adapter&) = delete;\n    iterator_input_adapter(iterator_input_adapter&& rhs) = default;\n    iterator_input_adapter& operator=(const iterator_input_adapter&) = delete;\n    iterator_input_adapter& operator=(iterator_input_adapter&&) = default;\n    ~iterator_input_adapter() = default;\n\n    /// @brief Get view into the input buffer contents.\n    /// @return View into the input buffer contents.\n    str_view get_buffer_view() {\n        if FK_YAML_UNLIKELY (m_begin == m_end) {\n            return {};\n        }\n\n        IterType current = m_begin;\n        std::deque<IterType> cr_itrs {};\n        while (current != m_end) {\n            const auto first = static_cast<uint8_t>(*current++);\n            const uint32_t num_bytes = utf8::get_num_bytes(first);\n\n            switch (num_bytes) {\n            case 1:\n                if FK_YAML_UNLIKELY (first == 0x0D /*CR*/) {\n                    cr_itrs.emplace_back(std::prev(current));\n                }\n                break;\n            case 2: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second});\n                }\n                break;\n            }\n            case 3: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third});\n                }\n                break;\n            }\n            case 4: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const auto fourth = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third, fourth);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third, fourth});\n                }\n                break;\n            }\n            default:           // LCOV_EXCL_LINE\n                unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n\n        m_buffer.reserve(std::distance(m_begin, m_end) - cr_itrs.size());\n        current = m_begin;\n        for (const auto& cr_itr : cr_itrs) {\n            std::transform(\n                current, cr_itr, std::back_inserter(m_buffer), [](char8_t c) { return static_cast<char>(c); });\n            current = std::next(cr_itr);\n        }\n        std::transform(current, m_end, std::back_inserter(m_buffer), [](char8_t c) { return static_cast<char>(c); });\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\nprivate:\n    /// The iterator at the beginning of input.\n    IterType m_begin {};\n    /// The iterator at the end of input.\n    IterType m_end {};\n    /// The encoding type for this input adapter.\n    utf_encode_t m_encode_type {utf_encode_t::UTF_8};\n    /// The normalized owned buffer.\n    std::string m_buffer;\n    /// Whether ItrType is a contiguous iterator.\n    bool m_is_contiguous {false};\n};\n\n#endif // FK_YAML_HAS_CHAR8_T\n\n/// @brief An input adapter for iterators of type char16_t.\n/// @tparam IterType An iterator type.\ntemplate <typename IterType>\nclass iterator_input_adapter<IterType, enable_if_t<is_iterator_of<IterType, char16_t>::value>> {\npublic:\n    /// @brief Construct a new iterator_input_adapter object.\n    iterator_input_adapter() = default;\n\n    /// @brief Construct a new iterator_input_adapter object.\n    /// @param begin The beginning of iterators.\n    /// @param end The end of iterators.\n    /// @param encode_type The encoding type for this input adapter.\n    /// @param is_contiguous Whether iterators are contiguous or not.\n    iterator_input_adapter(IterType begin, IterType end, utf_encode_t encode_type, bool is_contiguous) noexcept\n        : m_begin(begin),\n          m_end(end),\n          m_encode_type(encode_type),\n          m_is_contiguous(is_contiguous) {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_16BE || m_encode_type == utf_encode_t::UTF_16LE);\n    }\n\n    // allow only move construct/assignment like other input adapters.\n    iterator_input_adapter(const iterator_input_adapter&) = delete;\n    iterator_input_adapter(iterator_input_adapter&& rhs) = default;\n    iterator_input_adapter& operator=(const iterator_input_adapter&) = delete;\n    iterator_input_adapter& operator=(iterator_input_adapter&&) = default;\n    ~iterator_input_adapter() = default;\n\n    /// @brief Get view into the input buffer contents.\n    /// @return View into the input buffer contents.\n    str_view get_buffer_view() {\n        if FK_YAML_UNLIKELY (m_begin == m_end) {\n            return {};\n        }\n\n        const int shift_bits = (m_encode_type == utf_encode_t::UTF_16BE) ? 0 : 8;\n\n        std::array<char16_t, 2> encoded_buffer {{0, 0}};\n        uint32_t encoded_buf_size {0};\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        // Assume the input characters are all ASCII characters.\n        // That's the most probably the case.\n        m_buffer.reserve(std::distance(m_begin, m_end));\n\n        IterType current = m_begin;\n        while (current != m_end || encoded_buf_size != 0) {\n            while (current != m_end && encoded_buf_size < 2) {\n                char16_t utf16 = *current++;\n                utf16 = static_cast<char16_t>(((utf16 & 0x00FFu) << shift_bits) | ((utf16 & 0xFF00u) >> shift_bits));\n\n                if FK_YAML_LIKELY (utf16 != char16_t(0x000Du)) {\n                    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)\n                    encoded_buffer[encoded_buf_size++] = utf16;\n                }\n            }\n\n            uint32_t consumed_size = 0;\n            utf8::from_utf16(encoded_buffer, utf8_buffer, consumed_size, utf8_buf_size);\n\n            if FK_YAML_LIKELY (consumed_size == 1) {\n                encoded_buffer[0] = encoded_buffer[1];\n                encoded_buffer[1] = 0;\n            }\n            encoded_buf_size -= consumed_size;\n\n            m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\nprivate:\n    /// The iterator at the beginning of input.\n    IterType m_begin {};\n    /// The iterator at the end of input.\n    IterType m_end {};\n    /// The encoding type for this input adapter.\n    utf_encode_t m_encode_type {utf_encode_t::UTF_16BE};\n    /// The normalized owned buffer.\n    std::string m_buffer;\n    /// Whether ItrType is a contiguous iterator.\n    bool m_is_contiguous {false};\n};\n\n/// @brief An input adapter for iterators of type char32_t.\n/// @tparam IterType An iterator type.\ntemplate <typename IterType>\nclass iterator_input_adapter<IterType, enable_if_t<is_iterator_of<IterType, char32_t>::value>> {\npublic:\n    /// @brief Construct a new iterator_input_adapter object.\n    iterator_input_adapter() = default;\n\n    /// @brief Construct a new iterator_input_adapter object.\n    /// @param begin The beginning of iterators.\n    /// @param end The end of iterators.\n    /// @param encode_type The encoding type for this input adapter.\n    /// @param is_contiguous Whether iterators are contiguous or not.\n    iterator_input_adapter(IterType begin, IterType end, utf_encode_t encode_type, bool is_contiguous) noexcept\n        : m_begin(begin),\n          m_end(end),\n          m_encode_type(encode_type),\n          m_is_contiguous(is_contiguous) {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_32BE || m_encode_type == utf_encode_t::UTF_32LE);\n    }\n\n    // allow only move construct/assignment like other input adapters.\n    iterator_input_adapter(const iterator_input_adapter&) = delete;\n    iterator_input_adapter(iterator_input_adapter&& rhs) = default;\n    iterator_input_adapter& operator=(const iterator_input_adapter&) = delete;\n    iterator_input_adapter& operator=(iterator_input_adapter&&) = default;\n    ~iterator_input_adapter() = default;\n\n    /// @brief Get view into the input buffer contents.\n    /// @return View into the input buffer contents.\n    str_view get_buffer_view() {\n        if FK_YAML_UNLIKELY (m_begin == m_end) {\n            return {};\n        }\n\n        int shift_bits[4] {0, 0, 0, 0};\n        if (m_encode_type == utf_encode_t::UTF_32LE) {\n            shift_bits[0] = 24;\n            shift_bits[1] = 8;\n            shift_bits[2] = 8;\n            shift_bits[3] = 24;\n        }\n\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        // Assume the input characters are all ASCII characters.\n        // That's the most probably the case.\n        m_buffer.reserve(std::distance(m_begin, m_end));\n\n        IterType current = m_begin;\n        while (current != m_end) {\n            const char32_t tmp = *current++;\n            const auto utf32 = static_cast<char32_t>(\n                ((tmp & 0xFF000000u) >> shift_bits[0]) | ((tmp & 0x00FF0000u) >> shift_bits[1]) |\n                ((tmp & 0x0000FF00u) << shift_bits[2]) | ((tmp & 0x000000FFu) << shift_bits[3]));\n\n            if FK_YAML_UNLIKELY (utf32 != static_cast<char32_t>(0x0000000Du)) {\n                utf8::from_utf32(utf32, utf8_buffer, utf8_buf_size);\n                m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n            }\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\nprivate:\n    /// The iterator at the beginning of input.\n    IterType m_begin {};\n    /// The iterator at the end of input.\n    IterType m_end {};\n    /// The encoding type for this input adapter.\n    utf_encode_t m_encode_type {utf_encode_t::UTF_32BE};\n    /// The normalized owned buffer.\n    std::string m_buffer;\n    /// Whether ItrType is a contiguous iterator.\n    bool m_is_contiguous {false};\n};\n\n/// @brief An input adapter for C-style file handles.\nclass file_input_adapter {\npublic:\n    /// @brief Construct a new file_input_adapter object.\n    file_input_adapter() = default;\n\n    /// @brief Construct a new file_input_adapter object.\n    /// @note\n    /// This class doesn't call fopen() nor fclose().\n    /// It's user's responsibility to call those functions.\n    /// @param file A file handle for this adapter. (A non-null pointer is assumed.)\n    /// @param encode_type The encoding type for this input adapter.\n    explicit file_input_adapter(std::FILE* file, utf_encode_t encode_type) noexcept\n        : m_file(file),\n          m_encode_type(encode_type) {\n    }\n\n    // allow only move construct/assignment\n    file_input_adapter(const file_input_adapter&) = delete;\n    file_input_adapter(file_input_adapter&& rhs) = default;\n    file_input_adapter& operator=(const file_input_adapter&) = delete;\n    file_input_adapter& operator=(file_input_adapter&&) = default;\n    ~file_input_adapter() = default;\n\n    /// @brief Get view into the input buffer contents.\n    /// @return View into the input buffer contents.\n    str_view get_buffer_view() {\n        switch (m_encode_type) {\n        case utf_encode_t::UTF_8:\n            return get_buffer_view_utf8();\n        case utf_encode_t::UTF_16BE:\n        case utf_encode_t::UTF_16LE:\n            return get_buffer_view_utf16();\n        case utf_encode_t::UTF_32BE:\n        case utf_encode_t::UTF_32LE:\n            return get_buffer_view_utf32();\n        default:                   // LCOV_EXCL_LINE\n            detail::unreachable(); // LCOV_EXCL_LINE\n        }\n    }\n\nprivate:\n    /// @brief The concrete implementation of get_buffer_view() for UTF-8 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf8() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_8);\n\n        m_buffer.clear();\n        char tmp_buf[256] {};\n        constexpr std::size_t buf_size = sizeof(tmp_buf) / sizeof(tmp_buf[0]);\n        std::size_t read_size = 0;\n        while ((read_size = std::fread(&tmp_buf[0], sizeof(char), buf_size, m_file)) > 0) {\n            char* p_current = &tmp_buf[0];\n            char* p_end = p_current + read_size;\n\n            // copy tmp_buf to m_buffer, dropping CRs.\n            char* p_cr = p_current;\n            do {\n                if FK_YAML_UNLIKELY (*p_cr == '\\r') {\n                    m_buffer.append(p_current, p_cr);\n                    p_current = p_cr + 1;\n                }\n                ++p_cr;\n            } while (p_cr != p_end);\n\n            m_buffer.append(p_current, p_end);\n        }\n\n        if FK_YAML_UNLIKELY (m_buffer.empty()) {\n            return {};\n        }\n\n        auto current = m_buffer.begin();\n        auto end = m_buffer.end();\n        while (current != end) {\n            const auto first = static_cast<uint8_t>(*current++);\n            const uint32_t num_bytes = utf8::get_num_bytes(first);\n\n            switch (num_bytes) {\n            case 1:\n                break;\n            case 2: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second});\n                }\n                break;\n            }\n            case 3: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third});\n                }\n                break;\n            }\n            case 4: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const auto fourth = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third, fourth);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third, fourth});\n                }\n                break;\n            }\n            default:           // LCOV_EXCL_LINE\n                unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\n    /// @brief The concrete implementation of get_buffer_view() for UTF-16 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf16() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_16BE || m_encode_type == utf_encode_t::UTF_16LE);\n\n        int shift_bits[2] {0, 0};\n        if (m_encode_type == utf_encode_t::UTF_16BE) {\n            shift_bits[0] = 8;\n        }\n        else { // m_encode_type == utf_encode_t::UTF_16LE\n            shift_bits[1] = 8;\n        }\n\n        char chars[2] = {0, 0};\n        std::array<char16_t, 2> encoded_buffer {{0, 0}};\n        uint32_t encoded_buf_size {0};\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        while (std::feof(m_file) == 0) {\n            while (encoded_buf_size < 2 && std::fread(&chars[0], sizeof(char), 2, m_file) == 2) {\n                const auto utf16 = static_cast<char16_t>(\n                    (static_cast<uint8_t>(chars[0]) << shift_bits[0]) |\n                    (static_cast<uint8_t>(chars[1]) << shift_bits[1]));\n                if FK_YAML_LIKELY (utf16 != static_cast<char16_t>(0x000Du)) {\n                    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)\n                    encoded_buffer[encoded_buf_size++] = utf16;\n                }\n            }\n\n            uint32_t consumed_size = 0;\n            utf8::from_utf16(encoded_buffer, utf8_buffer, consumed_size, utf8_buf_size);\n\n            if FK_YAML_LIKELY (consumed_size == 1) {\n                encoded_buffer[0] = encoded_buffer[1];\n            }\n            encoded_buf_size -= consumed_size;\n\n            m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\n    /// @brief The concrete implementation of get_buffer_view() for UTF-32 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf32() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_32BE || m_encode_type == utf_encode_t::UTF_32LE);\n\n        int shift_bits[4] {0, 0, 0, 0};\n        if (m_encode_type == utf_encode_t::UTF_32BE) {\n            shift_bits[0] = 24;\n            shift_bits[1] = 16;\n            shift_bits[2] = 8;\n        }\n        else { // m_encode_type == utf_encode_t::UTF_32LE\n            shift_bits[1] = 8;\n            shift_bits[2] = 16;\n            shift_bits[3] = 24;\n        }\n\n        char chars[4] = {0, 0, 0, 0};\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        while (std::feof(m_file) == 0) {\n            const std::size_t size = std::fread(&chars[0], sizeof(char), 4, m_file);\n            if (size != 4) {\n                break;\n            }\n\n            const auto utf32 = static_cast<char32_t>(\n                (static_cast<uint8_t>(chars[0]) << shift_bits[0]) | (static_cast<uint8_t>(chars[1]) << shift_bits[1]) |\n                (static_cast<uint8_t>(chars[2]) << shift_bits[2]) | (static_cast<uint8_t>(chars[3]) << shift_bits[3]));\n\n            if FK_YAML_LIKELY (utf32 != char32_t(0x0000000Du)) {\n                utf8::from_utf32(utf32, utf8_buffer, utf8_buf_size);\n                m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n            }\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\nprivate:\n    /// A pointer to the input file handle.\n    std::FILE* m_file {nullptr};\n    /// The encoding type for this input adapter.\n    utf_encode_t m_encode_type {utf_encode_t::UTF_8};\n    /// The normalized owned buffer.\n    std::string m_buffer;\n};\n\n/// @brief An input adapter for streams\nclass stream_input_adapter {\npublic:\n    /// @brief Construct a new stream_input_adapter object.\n    stream_input_adapter() = default;\n\n    /// @brief Construct a new stream_input_adapter object.\n    /// @param is A reference to the target input stream.\n    /// @param encode_type The encoding type for this input adapter.\n    explicit stream_input_adapter(std::istream& is, utf_encode_t encode_type) noexcept\n        : m_istream(&is),\n          m_encode_type(encode_type) {\n    }\n\n    // allow only move construct/assignment\n    stream_input_adapter(const stream_input_adapter&) = delete;\n    stream_input_adapter& operator=(const stream_input_adapter&) = delete;\n    stream_input_adapter(stream_input_adapter&&) = default;\n    stream_input_adapter& operator=(stream_input_adapter&&) = default;\n    ~stream_input_adapter() = default;\n\n    /// @brief Get view into the input buffer contents.\n    /// @return View into the input buffer contents.\n    str_view get_buffer_view() {\n        switch (m_encode_type) {\n        case utf_encode_t::UTF_8:\n            return get_buffer_view_utf8();\n        case utf_encode_t::UTF_16BE:\n        case utf_encode_t::UTF_16LE:\n            return get_buffer_view_utf16();\n        case utf_encode_t::UTF_32BE:\n        case utf_encode_t::UTF_32LE:\n            return get_buffer_view_utf32();\n        default:                   // LCOV_EXCL_LINE\n            detail::unreachable(); // LCOV_EXCL_LINE\n        }\n    }\n\nprivate:\n    /// @brief The concrete implementation of get_buffer_view() for UTF-8 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf8() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_8);\n\n        m_buffer.clear();\n        char tmp_buf[256] {};\n        do {\n            m_istream->read(&tmp_buf[0], 256);\n            const auto read_size = static_cast<std::size_t>(m_istream->gcount());\n            if FK_YAML_UNLIKELY (read_size == 0) {\n                break;\n            }\n\n            char* p_current = &tmp_buf[0];\n            char* p_end = p_current + read_size;\n\n            // copy tmp_buf to m_buffer, dropping CRs.\n            char* p_cr = p_current;\n            do {\n                if FK_YAML_UNLIKELY (*p_cr == '\\r') {\n                    m_buffer.append(p_current, p_cr);\n                    p_current = p_cr + 1;\n                }\n                ++p_cr;\n            } while (p_cr != p_end);\n\n            m_buffer.append(p_current, p_end);\n        } while (!m_istream->eof());\n\n        if FK_YAML_UNLIKELY (m_buffer.empty()) {\n            return {};\n        }\n\n        auto current = m_buffer.begin();\n        auto end = m_buffer.end();\n        while (current != end) {\n            const auto first = static_cast<uint8_t>(*current++);\n            const uint32_t num_bytes = utf8::get_num_bytes(first);\n\n            switch (num_bytes) {\n            case 1:\n                break;\n            case 2: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second});\n                }\n                break;\n            }\n            case 3: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third});\n                }\n                break;\n            }\n            case 4: {\n                const auto second = static_cast<uint8_t>(*current++);\n                const auto third = static_cast<uint8_t>(*current++);\n                const auto fourth = static_cast<uint8_t>(*current++);\n                const bool is_valid = utf8::validate(first, second, third, fourth);\n                if FK_YAML_UNLIKELY (!is_valid) {\n                    throw fkyaml::invalid_encoding(\"Invalid UTF-8 encoding.\", {first, second, third, fourth});\n                }\n                break;\n            }\n            default:           // LCOV_EXCL_LINE\n                unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\n    /// @brief The concrete implementation of get_buffer_view() for UTF-16 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf16() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_16BE || m_encode_type == utf_encode_t::UTF_16LE);\n\n        int shift_bits[2] {0, 0};\n        if (m_encode_type == utf_encode_t::UTF_16BE) {\n            shift_bits[0] = 8;\n        }\n        else { // m_encode_type == utf_encode_t::UTF_16LE\n            shift_bits[1] = 8;\n        }\n\n        char chars[2] = {0, 0};\n        std::array<char16_t, 2> encoded_buffer {{0, 0}};\n        uint32_t encoded_buf_size {0};\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        do {\n            while (encoded_buf_size < 2) {\n                m_istream->read(&chars[0], 2);\n                const std::streamsize size = m_istream->gcount();\n                if FK_YAML_UNLIKELY (size != 2) {\n                    break;\n                }\n\n                const auto utf16 = static_cast<char16_t>(\n                    (static_cast<uint8_t>(chars[0]) << shift_bits[0]) |\n                    (static_cast<uint8_t>(chars[1]) << shift_bits[1]));\n\n                if FK_YAML_LIKELY (utf16 != static_cast<char16_t>(0x000Du)) {\n                    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)\n                    encoded_buffer[encoded_buf_size++] = utf16;\n                }\n            }\n\n            uint32_t consumed_size = 0;\n            utf8::from_utf16(encoded_buffer, utf8_buffer, consumed_size, utf8_buf_size);\n\n            if FK_YAML_LIKELY (consumed_size == 1) {\n                encoded_buffer[0] = encoded_buffer[1];\n            }\n            encoded_buf_size -= consumed_size;\n\n            m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n        } while (!m_istream->eof());\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\n    /// @brief The concrete implementation of get_buffer_view() for UTF-32 encoded inputs.\n    /// @return View into the UTF-8 encoded input buffer contents.\n    str_view get_buffer_view_utf32() {\n        FK_YAML_ASSERT(m_encode_type == utf_encode_t::UTF_32BE || m_encode_type == utf_encode_t::UTF_32LE);\n\n        int shift_bits[4] {0, 0, 0, 0};\n        if (m_encode_type == utf_encode_t::UTF_32BE) {\n            shift_bits[0] = 24;\n            shift_bits[1] = 16;\n            shift_bits[2] = 8;\n        }\n        else { // m_encode_type == utf_encode_t::UTF_32LE\n            shift_bits[1] = 8;\n            shift_bits[2] = 16;\n            shift_bits[3] = 24;\n        }\n\n        char chars[4] = {0, 0, 0, 0};\n        std::array<uint8_t, 4> utf8_buffer {{0, 0, 0, 0}};\n        uint32_t utf8_buf_size {0};\n\n        do {\n            m_istream->read(&chars[0], 4);\n            const std::streamsize size = m_istream->gcount();\n            if FK_YAML_UNLIKELY (size != 4) {\n                break;\n            }\n\n            const auto utf32 = static_cast<char32_t>(\n                (static_cast<uint8_t>(chars[0]) << shift_bits[0]) | (static_cast<uint8_t>(chars[1]) << shift_bits[1]) |\n                (static_cast<uint8_t>(chars[2]) << shift_bits[2]) | (static_cast<uint8_t>(chars[3]) << shift_bits[3]));\n\n            if FK_YAML_LIKELY (utf32 != char32_t(0x0000000Du)) {\n                utf8::from_utf32(utf32, utf8_buffer, utf8_buf_size);\n                m_buffer.append(reinterpret_cast<const char*>(utf8_buffer.data()), utf8_buf_size);\n            }\n        } while (!m_istream->eof());\n\n        return str_view {m_buffer.begin(), m_buffer.end()};\n    }\n\nprivate:\n    /// A pointer to the input stream object.\n    std::istream* m_istream {nullptr};\n    /// The encoding type for this input adapter.\n    utf_encode_t m_encode_type {utf_encode_t::UTF_8};\n    /// The normalized owned buffer.\n    std::string m_buffer;\n};\n\n/////////////////////////////////\n//   input_adapter providers   //\n/////////////////////////////////\n\n/// @brief A concrete factory method for iterator_input_adapter objects with iterators.\n/// @tparam ItrType An iterator type.\n/// @param begin The beginning of iterators.\n/// @param end The end of iterators.\n/// @param is_contiguous Whether iterators refer to a contiguous byte array.\n/// @return An iterator_input_adapter object for the target iterator type.\ntemplate <typename ItrType>\ninline iterator_input_adapter<ItrType> create_iterator_input_adapter(ItrType begin, ItrType end, bool is_contiguous) {\n    const utf_encode_t encode_type = utf_encode_detector<ItrType>::detect(begin, end);\n    return iterator_input_adapter<ItrType>(begin, end, encode_type, is_contiguous);\n}\n\n/// @brief A factory method for iterator_input_adapter objects with iterator values.\n/// @tparam ItrType An iterator type.\n/// @param begin The beginning of iterators.\n/// @param end The end of iterators.\n/// @return iterator_input_adapter<ItrType> An iterator_input_adapter object for the target iterator type.\ntemplate <typename ItrType>\ninline iterator_input_adapter<ItrType> input_adapter(ItrType begin, ItrType end) {\n    constexpr bool is_random_access_itr =\n        std::is_same<typename std::iterator_traits<ItrType>::iterator_category, std::random_access_iterator_tag>::value;\n\n    // Check if `begin` & `end` are contiguous iterators.\n    // Getting distance between begin and (end - 1) avoids dereferencing an invalid sentinel.\n    bool is_contiguous = false;\n    if (is_random_access_itr) {\n        const auto size = static_cast<ptrdiff_t>(std::distance(begin, end - 1));\n\n        using CharPtr = remove_cvref_t<typename std::iterator_traits<ItrType>::pointer>;\n        CharPtr p_begin = &*begin;\n        CharPtr p_second_last = &*(end - 1);\n        is_contiguous = (p_second_last - p_begin == size);\n    }\n    return create_iterator_input_adapter(begin, end, is_contiguous);\n}\n\n/// @brief A factory method for iterator_input_adapter objects with C-style arrays.\n/// @tparam T A type of arrayed objects.\n/// @tparam N A size of an array.\n/// @return decltype(input_adapter(array, array + N)) An iterator_input_adapter object for the target array.\ntemplate <typename T, std::size_t N>\ninline auto input_adapter(T (&array)[N]) -> decltype(create_iterator_input_adapter(array, array + (N - 1), true)) {\n    return create_iterator_input_adapter(array, array + (N - 1), true);\n}\n\n/// @brief A namespace to implement container_input_adapter_factory for internal use.\nnamespace input_adapter_factory {\n\nusing std::begin;\nusing std::end;\n\n/// @brief A factory of input adapters for containers.\n/// @tparam ContainerType A container type.\n/// @tparam typename N/A\ntemplate <typename ContainerType, typename = void>\nstruct container_input_adapter_factory {};\n\n/// @brief A partial specialization of container_input_adapter_factory if begin()/end() are available for ContainerType.\n/// @tparam ContainerType A container type.\ntemplate <typename ContainerType>\nstruct container_input_adapter_factory<\n    ContainerType, void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>> {\n    /// Whether ContainerType is a contiguous container.\n    static constexpr bool is_contiguous = is_contiguous_container<ContainerType>::value;\n\n    /// A type for resulting input adapter object.\n    using adapter_type = decltype(create_iterator_input_adapter(\n        begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()), is_contiguous));\n\n    /// @brief A factory method of input adapter objects for the target container objects.\n    /// @param container A container-like input object.\n    /// @return adapter_type An iterator_input_adapter object.\n    static adapter_type create(const ContainerType& container) {\n        return create_iterator_input_adapter(begin(container), end(container), is_contiguous);\n    }\n};\n\n} // namespace input_adapter_factory\n\n/// @brief A factory method for iterator_input_adapter objects with containers.\n/// @tparam ContainerType A container type.\n/// @param container A container object.\n/// @return input_adapter_factory::container_input_adapter_factory<ContainerType>::adapter_type\ntemplate <typename ContainerType>\ninline typename input_adapter_factory::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(\n    const ContainerType& container) {\n    return input_adapter_factory::container_input_adapter_factory<ContainerType>::create(container);\n}\n\n/// @brief A factory method for file_input_adapter objects with C-style file handles.\n/// @param file A file handle.\n/// @return file_input_adapter A file_input_adapter object.\ninline file_input_adapter input_adapter(std::FILE* file) {\n    if FK_YAML_UNLIKELY (!file) {\n        throw fkyaml::exception(\"Invalid FILE object pointer.\");\n    }\n\n    const utf_encode_t encode_type = file_utf_encode_detector::detect(file);\n    return file_input_adapter(file, encode_type);\n}\n\n/// @brief A factory method for stream_input_adapter objects with std::istream objects.\n/// @param stream An input stream.\n/// @return stream_input_adapter A stream_input_adapter object.\ninline stream_input_adapter input_adapter(std::istream& stream) {\n    if FK_YAML_UNLIKELY (!stream.good()) {\n        throw fkyaml::exception(\"Invalid stream.\");\n    }\n\n    const utf_encode_t encode_type = stream_utf_encode_detector::detect(stream);\n    return stream_input_adapter(stream, encode_type);\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_INPUT_INPUT_ADAPTER_HPP */\n\n// #include <fkYAML/detail/iterator.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_ITERATOR_HPP\n#define FK_YAML_DETAIL_ITERATOR_HPP\n\n#include <cstddef>\n#include <iterator>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief The template definitions of type information used in @ref Iterator class\n/// @tparam ValueType The type of iterated elements.\ntemplate <typename ValueType>\nstruct iterator_traits {\n    /// A type of iterated elements.\n    using value_type = typename ValueType::value_type;\n    /// A type to represent difference between iterators.\n    using difference_type = typename ValueType::difference_type;\n    /// A type of an element pointer.\n    using pointer = typename ValueType::pointer;\n    /// A type of reference to an element.\n    using reference = typename ValueType::reference;\n};\n\n/// @brief A specialization of @ref iterator_traits for constant value types.\n/// @tparam ValueType The type of iterated elements.\ntemplate <typename ValueType>\nstruct iterator_traits<const ValueType> {\n    /// A type of iterated elements.\n    using value_type = typename ValueType::value_type;\n    /// A type to represent difference between iterators.\n    using difference_type = typename ValueType::difference_type;\n    /// A type of a constant element pointer.\n    using pointer = typename ValueType::const_pointer;\n    /// A type of constant reference to an element.\n    using reference = typename ValueType::const_reference;\n};\n\n/// @brief Definitions of iterator types for iterators internally held.\nenum class iterator_t : std::uint8_t {\n    SEQUENCE, //!< sequence iterator type.\n    MAPPING,  //!< mapping iterator type.\n};\n\n/// @brief The actual storage for iterators internally held in iterator.\ntemplate <typename BasicNodeType>\nstruct iterator_holder {\n    static_assert(\n        is_basic_node<BasicNodeType>::value,\n        \"iterator_holder class only accepts a basic_node as its template parameter.\");\n\n    /// A sequence iterator object.\n    typename BasicNodeType::sequence_type::iterator sequence_iterator {};\n    /// A mapping iterator object.\n    typename BasicNodeType::mapping_type::iterator mapping_iterator {};\n};\n\n/// @brief A class which holds iterators either of sequence or mapping type\n/// @tparam ValueType The type of iterated elements.\ntemplate <typename ValueType>\nclass iterator {\n    /// @brief The iterator type with ValueType of different const-ness.\n    using other_iterator_type = typename std::conditional<\n        std::is_const<ValueType>::value, iterator<typename std::remove_const<ValueType>::type>,\n        iterator<const ValueType>>::type;\n\n    friend other_iterator_type;\n\npublic:\n    /// A type for iterator traits of instantiated @Iterator template class.\n    using iterator_traits_type = iterator_traits<ValueType>;\n\n    /// A type for iterator category tag.\n    using iterator_category = std::bidirectional_iterator_tag;\n    /// A type of iterated element.\n    using value_type = typename iterator_traits_type::value_type;\n    /// A type to represent differences between iterators.\n    using difference_type = typename iterator_traits_type::difference_type;\n    /// A type of an element pointer.\n    using pointer = typename iterator_traits_type::pointer;\n    /// A type of reference to an element.\n    using reference = typename iterator_traits_type::reference;\n\n    static_assert(is_basic_node<value_type>::value, \"iterator class only accepts a basic_node as its value type.\");\n\n    /// @brief Constructs an iterator object.\n    iterator() = default;\n\n    /// @brief Construct a new iterator object with sequence iterator object.\n    /// @param[in] itr An sequence iterator object.\n    iterator(const typename value_type::sequence_type::iterator& itr) noexcept {\n        m_iterator_holder.sequence_iterator = itr;\n    }\n\n    /// @brief Construct a new iterator object with mapping iterator object.\n    /// @param[in] itr An mapping iterator object.\n    iterator(const typename value_type::mapping_type::iterator& itr) noexcept\n        : m_inner_iterator_type(iterator_t::MAPPING) {\n        m_iterator_holder.mapping_iterator = itr;\n    }\n\n    /// @brief Copy constructs an iterator.\n    iterator(const iterator&) = default;\n\n    /// @brief Copy constructs an iterator from another iterator with different const-ness in ValueType.\n    /// @note This copy constructor is not defined if ValueType is not const to avoid const removal from ValueType.\n    /// @tparam OtherIterator The iterator type to copy from.\n    /// @param other An iterator to copy from with different const-ness in ValueType.\n    template <\n        typename OtherIterator,\n        enable_if_t<\n            conjunction<std::is_same<OtherIterator, other_iterator_type>, std::is_const<ValueType>>::value, int> = 0>\n    iterator(const OtherIterator& other) noexcept\n        : m_inner_iterator_type(other.m_inner_iterator_type),\n          m_iterator_holder(other.m_iterator_holder) {\n    }\n\n    /// @brief A copy assignment operator of the iterator class.\n    iterator& operator=(const iterator&) = default;\n\n    template <\n        typename OtherIterator,\n        enable_if_t<\n            conjunction<std::is_same<OtherIterator, other_iterator_type>, std::is_const<ValueType>>::value, int> = 0>\n    iterator& operator=(const OtherIterator& other) noexcept {\n        m_inner_iterator_type = other.m_inner_iterator_type;\n        m_iterator_holder = other.m_iterator_holder;\n        return *this;\n    }\n\n    /// @brief Move constructs an iterator.\n    iterator(iterator&&) = default;\n\n    /// @brief A move assignment operator of the iterator class.\n    iterator& operator=(iterator&&) = default;\n\n    /// @brief Destroys an iterator.\n    ~iterator() = default;\n\n    /// @brief An arrow operator of the iterator class.\n    /// @return pointer A pointer to the BasicNodeType object internally referenced by the actual iterator object.\n    pointer operator->() noexcept {\n        if (m_inner_iterator_type == iterator_t::SEQUENCE) {\n            return &(*(m_iterator_holder.sequence_iterator));\n        }\n\n        // m_inner_iterator_type == iterator_t::MAPPING:\n        return &(m_iterator_holder.mapping_iterator->second);\n    }\n\n    /// @brief A dereference operator of the iterator class.\n    /// @return reference Reference to the Node object internally referenced by the actual iterator object.\n    reference operator*() const noexcept {\n        if (m_inner_iterator_type == iterator_t::SEQUENCE) {\n            return *(m_iterator_holder.sequence_iterator);\n        }\n\n        // m_inner_iterator_type == iterator_t::MAPPING:\n        return m_iterator_holder.mapping_iterator->second;\n    }\n\n    /// @brief A compound assignment operator by sum of the Iterator class.\n    /// @param i The difference from this Iterator object with which it moves forward.\n    /// @return Iterator& Reference to this Iterator object.\n    iterator& operator+=(difference_type i) noexcept {\n        switch (m_inner_iterator_type) {\n        case iterator_t::SEQUENCE:\n            std::advance(m_iterator_holder.sequence_iterator, i);\n            break;\n        case iterator_t::MAPPING:\n            std::advance(m_iterator_holder.mapping_iterator, i);\n            break;\n        }\n        return *this;\n    }\n\n    /// @brief A plus operator of the iterator class.\n    /// @param i The difference from this iterator object.\n    /// @return iterator An iterator object which has been added @a i.\n    iterator operator+(difference_type i) const noexcept {\n        auto result = *this;\n        result += i;\n        return result;\n    }\n\n    /// @brief An pre-increment operator of the iterator class.\n    /// @return iterator& Reference to this iterator object.\n    iterator& operator++() noexcept {\n        switch (m_inner_iterator_type) {\n        case iterator_t::SEQUENCE:\n            std::advance(m_iterator_holder.sequence_iterator, 1);\n            break;\n        case iterator_t::MAPPING:\n            std::advance(m_iterator_holder.mapping_iterator, 1);\n            break;\n        }\n        return *this;\n    }\n\n    /// @brief A post-increment operator of the iterator class.\n    /// @return iterator An iterator object which has been incremented.\n    iterator operator++(int) & noexcept {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /// @brief A compound assignment operator by difference of the iterator class.\n    /// @param i The difference from this iterator object with which it moves backward.\n    /// @return iterator& Reference to this iterator object.\n    iterator& operator-=(difference_type i) noexcept {\n        return operator+=(-i);\n    }\n\n    /// @brief A minus operator of the iterator class.\n    /// @param i The difference from this iterator object.\n    /// @return iterator An iterator object from which has been subtracted @ i.\n    iterator operator-(difference_type i) const noexcept {\n        auto result = *this;\n        result -= i;\n        return result;\n    }\n\n    /// @brief A pre-decrement operator of the iterator class.\n    /// @return iterator& Reference to this iterator object.\n    iterator& operator--() noexcept {\n        switch (m_inner_iterator_type) {\n        case iterator_t::SEQUENCE:\n            std::advance(m_iterator_holder.sequence_iterator, -1);\n            break;\n        case iterator_t::MAPPING:\n            std::advance(m_iterator_holder.mapping_iterator, -1);\n            break;\n        }\n        return *this;\n    }\n\n    /// @brief A post-decrement operator of the iterator class\n    /// @return iterator An iterator object which has been decremented.\n    iterator operator--(int) & noexcept {\n        auto result = *this;\n        --(*this);\n        return result;\n    }\n\n    /// @brief An equal-to operator of the iterator class.\n    /// @param rhs An iterator object to be compared with this iterator object.\n    /// @return true  This iterator object is equal to the other.\n    /// @return false This iterator object is not equal to the other.\n    template <\n        typename Iterator,\n        enable_if_t<\n            disjunction<std::is_same<Iterator, iterator>, std::is_same<Iterator, other_iterator_type>>::value, int> = 0>\n    bool operator==(const Iterator& rhs) const {\n        if FK_YAML_UNLIKELY (m_inner_iterator_type != rhs.m_inner_iterator_type) {\n            throw fkyaml::exception(\"Cannot compare iterators of different container types.\");\n        }\n\n        if (m_inner_iterator_type == iterator_t::SEQUENCE) {\n            return (m_iterator_holder.sequence_iterator == rhs.m_iterator_holder.sequence_iterator);\n        }\n\n        // m_inner_iterator_type == iterator_t::MAPPING\n        return (m_iterator_holder.mapping_iterator == rhs.m_iterator_holder.mapping_iterator);\n    }\n\n    /// @brief An not-equal-to operator of the iterator class.\n    /// @param rhs An iterator object to be compared with this iterator object.\n    /// @return true  This iterator object is not equal to the other.\n    /// @return false This iterator object is equal to the other.\n    template <\n        typename Iterator,\n        enable_if_t<\n            disjunction<std::is_same<Iterator, iterator>, std::is_same<Iterator, other_iterator_type>>::value, int> = 0>\n    bool operator!=(const Iterator& rhs) const {\n        return !operator==(rhs);\n    }\n\n    /// @brief A less-than operator of the iterator class.\n    /// @param rhs An iterator object to be compared with this iterator object.\n    /// @return true  This iterator object is less than the other.\n    /// @return false This iterator object is not less than the other.\n    template <\n        typename Iterator,\n        enable_if_t<\n            disjunction<std::is_same<Iterator, iterator>, std::is_same<Iterator, other_iterator_type>>::value, int> = 0>\n    bool operator<(const Iterator& rhs) const {\n        if FK_YAML_UNLIKELY (m_inner_iterator_type != rhs.m_inner_iterator_type) {\n            throw fkyaml::exception(\"Cannot compare iterators of different container types.\");\n        }\n\n        if FK_YAML_UNLIKELY (m_inner_iterator_type == iterator_t::MAPPING) {\n            throw fkyaml::exception(\"Cannot compare order of iterators of the mapping container type\");\n        }\n\n        return (m_iterator_holder.sequence_iterator < rhs.m_iterator_holder.sequence_iterator);\n    }\n\n    ///  @brief A less-than-or-equal-to operator of the iterator class.\n    ///  @param rhs An iterator object to be compared with this iterator object.\n    ///  @return true  This iterator object is either less than or equal to the other.\n    ///  @return false This iterator object is neither less than nor equal to the other.\n    template <\n        typename Iterator,\n        enable_if_t<\n            disjunction<std::is_same<Iterator, iterator>, std::is_same<Iterator, other_iterator_type>>::value, int> = 0>\n    bool operator<=(const Iterator& rhs) const {\n        return !rhs.operator<(*this);\n    }\n\n    /// @brief A greater-than operator of the iterator class.\n    /// @param rhs An iterator object to be compared with this iterator object.\n    /// @return true  This iterator object is greater than the other.\n    /// @return false This iterator object is not greater than the other.\n    template <\n        typename Iterator,\n        enable_if_t<\n            disjunction<std::is_same<Iterator, iterator>, std::is_same<Iterator, other_iterator_type>>::value, int> = 0>\n    bool operator>(const Iterator& rhs) const {\n        return !operator<=(rhs);\n    }\n\n    /// @brief A greater-than-or-equal-to operator of the iterator class.\n    /// @param rhs An iterator object to be compared with this iterator object.\n    /// @return true  This iterator object is either greater than or equal to the other.\n    /// @return false This iterator object is neither greater than nor equal to the other.\n    template <\n        typename Iterator,\n        enable_if_t<\n            disjunction<std::is_same<Iterator, iterator>, std::is_same<Iterator, other_iterator_type>>::value, int> = 0>\n    bool operator>=(const Iterator& rhs) const {\n        return !operator<(rhs);\n    }\n\npublic:\n    /// @brief Get the type of the internal iterator implementation.\n    /// @return iterator_t The type of the internal iterator implementation.\n    iterator_t type() const noexcept {\n        return m_inner_iterator_type;\n    }\n\n    /// @brief Get the mapping key node of the current iterator.\n    /// @return The mapping key node of the current iterator.\n    const typename value_type::mapping_type::key_type& key() const {\n        if FK_YAML_UNLIKELY (m_inner_iterator_type == iterator_t::SEQUENCE) {\n            throw fkyaml::exception(\"Cannot retrieve key from non-mapping iterators.\");\n        }\n\n        return m_iterator_holder.mapping_iterator->first;\n    }\n\n    /// @brief Get reference to the YAML node of the current iterator.\n    /// @return Reference to the YAML node of the current iterator.\n    reference value() const noexcept {\n        return operator*();\n    }\n\nprivate:\n    /// A type of the internally-held iterator.\n    iterator_t m_inner_iterator_type {iterator_t::SEQUENCE};\n    /// A holder of actual iterators.\n    iterator_holder<value_type> m_iterator_holder {};\n};\n\n/// @brief Get reference to a mapping key node.\n/// @tparam ValueType The iterator value type.\n/// @tparam I The element index.\n/// @param i An iterator object.\n/// @return Reference to a mapping key node.\ntemplate <std::size_t I, typename ValueType, enable_if_t<I == 0, int> = 0>\ninline auto get(const iterator<ValueType>& i) -> decltype(i.key()) {\n    return i.key();\n}\n\n/// @brief Get reference to a mapping value node.\n/// @tparam ValueType The iterator value type.\n/// @tparam I The element index\n/// @param i An iterator object.\n/// @return Reference to a mapping value node.\ntemplate <std::size_t I, typename ValueType, enable_if_t<I == 1, int> = 0>\ninline auto get(const iterator<ValueType>& i) -> decltype(i.value()) {\n    return i.value();\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\nnamespace std {\n\n#ifdef __clang__\n// clang emits warnings against mixed usage of class/struct for tuple_size/tuple_element.\n// see also: https://groups.google.com/a/isocpp.org/g/std-discussion/c/QC-AMb5oO1w\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wmismatched-tags\"\n#endif\n\n/// @brief Parcial pecialization of std::tuple_size for iterator class.\n/// @tparam ValueType The iterator value type.\ntemplate <typename ValueType>\n// NOLINTNEXTLINE(cert-dcl58-cpp)\nstruct tuple_size<::fkyaml::detail::iterator<ValueType>> : integral_constant<size_t, 2> {};\n\n/// @brief Parcial specialization of std::tuple_element for iterator class.\n/// @tparam ValueType The iterator value type.\n/// @tparam I The element index.\ntemplate <size_t I, typename ValueType>\n// NOLINTNEXTLINE(cert-dcl58-cpp)\nstruct tuple_element<I, ::fkyaml::detail::iterator<ValueType>> {\n    using type = decltype(get<I>(std::declval<::fkyaml::detail::iterator<ValueType>>()));\n};\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#endif\n\n} // namespace std\n\n#endif /* FK_YAML_DETAIL_ITERATOR_HPP */\n\n// #include <fkYAML/detail/map_range_proxy.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_MAP_RANGE_PROXY_HPP\n#define FK_YAML_DETAIL_MAP_RANGE_PROXY_HPP\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A helper iterator class which wraps a mapping iterator object.\n/// @tparam Iterator The base iterator type.\ntemplate <typename Iterator>\nclass map_iterator_proxy {\npublic:\n    /// @brief The type of the pointed-to elements by base iterators.\n    using value_type = Iterator;\n\n    /// @brief The type to represent difference between the pointed-to elements by base iterators.\n    using difference_type = std::ptrdiff_t;\n\n    /// @brief The type of the pointed-to element references by base iterators.\n    using reference = value_type&;\n\n    /// @brief The type of the pointed-to element pointers by base iterators.\n    using pointer = value_type*;\n\n    /// @brief The iterator category.\n    using iterator_category = std::forward_iterator_tag;\n\n    /// @brief Constructs a map_iterator_proxy object.\n    map_iterator_proxy() = default;\n\n    /// @brief Constructs a map_iterator_proxy object with an Iterator object.\n    /// @param i A base iterator object.\n    map_iterator_proxy(const Iterator& i) noexcept\n        : m_base_iterator(i) {\n    }\n\n    /// @brief Copy constructs a map_iterator_proxy object.\n    map_iterator_proxy(const map_iterator_proxy&) = default;\n\n    /// @brief Copy assigns a map_iterator_proxy object.\n    map_iterator_proxy& operator=(const map_iterator_proxy&) = default;\n\n    /// @brief Move constructs a map_iterator_proxy object.\n    map_iterator_proxy(map_iterator_proxy&&) = default;\n\n    /// @biref Move assigns a map_iterator_proxy object.\n    map_iterator_proxy& operator=(map_iterator_proxy&&) = default;\n\n    /// @brief Destructs a map_iterator_proxy object.\n    ~map_iterator_proxy() = default;\n\n    /// @brief Get reference to the base iterator object.\n    /// @return Reference to the base iterator object.\n    reference operator*() noexcept {\n        return m_base_iterator;\n    }\n\n    /// @brief Get pointer to the base iterator object.\n    /// @return Pointer to the base iterator object.\n    pointer operator->() noexcept {\n        return &m_base_iterator;\n    }\n\n    /// @brief Pre-increments the base iterator object.\n    /// @return Reference to this map_iterator_proxy object.\n    map_iterator_proxy& operator++() noexcept {\n        ++m_base_iterator;\n        return *this;\n    }\n\n    /// @brief Post-increments the base iterator object.\n    /// @return A map_iterator_proxy object with its base iterator incremented.\n    map_iterator_proxy operator++(int) & noexcept {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /// @brief Check equality between map_iterator_proxy objects.\n    /// @param rhs A map_iterator_proxy object to compare with.\n    /// @return true if this map_iterator_proxy object is equal to `rhs`, false otherwise.\n    bool operator==(const map_iterator_proxy& rhs) const noexcept {\n        return m_base_iterator == rhs.m_base_iterator;\n    }\n\n    /// @brief Check inequality between map_iterator_proxy objects.\n    /// @param rhs A map_iterator_proxy object to compare with.\n    /// @return true if this map_iterator_proxy object is not equal to `rhs`, false otherwise.\n    bool operator!=(const map_iterator_proxy& rhs) const noexcept {\n        return m_base_iterator != rhs.m_base_iterator;\n    }\n\n    /// @brief Get the mapping key node pointed by the base iterator.\n    /// @return Reference to the mapping key node.\n    typename Iterator::reference key() const {\n        return m_base_iterator.key();\n    }\n\n    /// @brief Get the mapping value node pointed by the base iterator.\n    /// @return Reference to the mapping value node.\n    typename Iterator::reference value() const noexcept {\n        return m_base_iterator.value();\n    }\n\nprivate:\n    /// The base iterator object.\n    Iterator m_base_iterator {};\n};\n\n/// @brief A helper struct which allows accessing node iterator member functions in range-based for loops.\n/// @tparam BasicNodeType A basic_node template instance type.\ntemplate <typename BasicNodeType>\nclass map_range_proxy {\n    static_assert(\n        is_basic_node<remove_cv_t<BasicNodeType>>::value,\n        \"map_range_proxy only accepts a basic_node type as its template parameter.\");\n\npublic:\n    /// @brief The type of non-const iterators.\n    using iterator = map_iterator_proxy<typename std::conditional<\n        std::is_const<BasicNodeType>::value, typename BasicNodeType::const_iterator,\n        typename BasicNodeType::iterator>::type>;\n\n    /// @brief The type of const iterators.\n    using const_iterator = map_iterator_proxy<typename BasicNodeType::const_iterator>;\n\n    /// @brief Constructs a map_range_proxy object with a BasicNodeType object.\n    /// @param map A mapping node object.\n    map_range_proxy(BasicNodeType& map) noexcept\n        : mp_map(&map) {\n    }\n\n    /// @brief Copy constructs a map_range_proxy object.\n    map_range_proxy(const map_range_proxy&) = default;\n\n    /// @brief Copy assigns a map_range_proxy object.\n    /// @return Reference to this map_range_proxy object.\n    map_range_proxy& operator=(const map_range_proxy&) = default;\n\n    /// @brief Move constructs a map_range_proxy object.\n    map_range_proxy(map_range_proxy&&) = default;\n\n    /// @brief Move assigns a map_range_proxy object.\n    /// @return Reference to this map_range_proxy object.\n    map_range_proxy& operator=(map_range_proxy&&) = default;\n\n    /// @brief Destructs a map_range_proxy object.\n    ~map_range_proxy() = default;\n\n    /// @brief Get an iterator to the first element.\n    /// @return An iterator to the first element.\n    iterator begin() noexcept {\n        return {mp_map->begin()};\n    }\n\n    /// @brief Get a const iterator to the first element.\n    /// @return A const iterator to the first element.\n    const_iterator begin() const noexcept {\n        return {mp_map->cbegin()};\n    }\n\n    /// @brief Get an iterator to the past-the-last element.\n    /// @return An iterator to the past-the-last element.\n    iterator end() noexcept {\n        return {mp_map->end()};\n    }\n\n    /// @brief Get a const iterator to the past-the-last element.\n    /// @return A const iterator to the past-the-last element.\n    const_iterator end() const noexcept {\n        return {mp_map->cend()};\n    }\n\nprivate:\n    /// Pointer to the mapping node object. (non-null)\n    BasicNodeType* mp_map {nullptr};\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_MAP_RANGE_PROXY_HPP */\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n// #include <fkYAML/detail/node_attrs.hpp>\n\n// #include <fkYAML/detail/node_property.hpp>\n\n// #include <fkYAML/detail/node_ref_storage.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_NODE_REF_STORAGE_HPP\n#define FK_YAML_DETAIL_NODE_REF_STORAGE_HPP\n\n#include <initializer_list>\n#include <type_traits>\n#include <utility>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A temporal storage for basic_node class objects.\n/// @note This class makes it easier to handle lvalue basic_node objects in basic_node ctor with std::initializer_list.\n/// @tparam BasicNodeType A basic_node template instance type.\ntemplate <typename BasicNodeType>\nclass node_ref_storage {\n    static_assert(is_basic_node<BasicNodeType>::value, \"node_ref_storage only accepts basic_node<...>\");\n\n    using node_type = BasicNodeType;\n\npublic:\n    /// @brief Construct a new node ref storage object with an rvalue basic_node object.\n    /// @param n An rvalue basic_node object.\n    explicit node_ref_storage(node_type&& n) noexcept(std::is_nothrow_move_constructible<node_type>::value)\n        : m_owned_value(std::move(n)) {\n    }\n\n    /// @brief Construct a new node ref storage object with an lvalue basic_node object.\n    /// @param n An lvalue basic_node object.\n    explicit node_ref_storage(const node_type& n) noexcept\n        : m_value_ref(&n) {\n    }\n\n    /// @brief Construct a new node ref storage object with a std::initializer_list object.\n    /// @param init A std::initializer_list object.\n    node_ref_storage(std::initializer_list<node_ref_storage> init)\n        : m_owned_value(init) {\n    }\n\n    /// @brief Construct a new node ref storage object with variadic template arguments\n    /// @tparam Args Types of arguments to construct a basic_node object.\n    /// @param args Arguments to construct a basic_node object.\n    template <typename... Args, enable_if_t<std::is_constructible<node_type, Args...>::value, int> = 0>\n    node_ref_storage(Args&&... args)\n        : m_owned_value(std::forward<Args>(args)...) {\n    }\n\n    // allow only move construct/assignment\n    node_ref_storage(const node_ref_storage&) = delete;\n    node_ref_storage(node_ref_storage&&) = default;\n    node_ref_storage& operator=(const node_ref_storage&) = delete;\n    node_ref_storage& operator=(node_ref_storage&&) = default;\n\n    ~node_ref_storage() = default;\n\npublic:\n    /// @brief An arrow operator for node_ref_storage objects.\n    /// @return const node_type* A constant pointer to a basic_node object.\n    const node_type* operator->() const noexcept {\n        return m_value_ref ? m_value_ref : &m_owned_value;\n    }\n\n    /// @brief Releases a basic_node object internally held.\n    /// @return node_type A basic_node object internally held.\n    node_type release() const noexcept {\n        return m_value_ref ? *m_value_ref : std::move(m_owned_value);\n    }\n\nprivate:\n    /// A storage for a basic_node object given with rvalue reference.\n    mutable node_type m_owned_value = nullptr;\n    /// A pointer to a basic_node object given with lvalue reference.\n    const node_type* m_value_ref = nullptr;\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_NODE_REF_STORAGE_HPP */\n\n// #include <fkYAML/detail/output/serializer.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_OUTPUT_SERIALIZER_HPP\n#define FK_YAML_DETAIL_OUTPUT_SERIALIZER_HPP\n\n#include <cmath>\n#include <sstream>\n#include <string>\n#include <vector>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/conversions/to_string.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_CONVERSIONS_TO_STRING_HPP\n#define FK_YAML_DETAIL_CONVERSIONS_TO_STRING_HPP\n\n#include <cmath>\n#include <limits>\n#include <string>\n#include <sstream>\n#include <type_traits>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Converts a ValueType object to a string YAML token.\n/// @tparam ValueType A source value type.\n/// @tparam CharType The type of characters for the conversion result.\n/// @param s A resulting output string.\n/// @param v A source value.\ntemplate <typename ValueType, typename CharType>\ninline void to_string(ValueType v, std::basic_string<CharType>& s) noexcept;\n\n/// @brief Specialization of to_string() for null values.\n/// @param s A resulting string YAML token.\n/// @param (unused) nullptr\ntemplate <>\ninline void to_string(std::nullptr_t /*unused*/, std::string& s) noexcept {\n    s = \"null\";\n}\n\n/// @brief Specialization of to_string() for booleans.\n/// @param s A resulting string YAML token.\n/// @param v A boolean source value.\ntemplate <>\ninline void to_string(bool v, std::string& s) noexcept {\n    s = v ? \"true\" : \"false\";\n}\n\n/// @brief Specialization of to_string() for integers.\n/// @tparam IntegerType An integer type.\n/// @param s A resulting string YAML token.\n/// @param i An integer source value.\ntemplate <typename IntegerType>\ninline enable_if_t<is_non_bool_integral<IntegerType>::value> to_string(IntegerType v, std::string& s) noexcept {\n    s = std::to_string(v);\n}\n\n/// @brief Specialization of to_string() for floating point numbers.\n/// @tparam FloatType A floating point number type.\n/// @param s A resulting string YAML token.\n/// @param f A floating point number source value.\ntemplate <typename FloatType>\ninline enable_if_t<std::is_floating_point<FloatType>::value> to_string(FloatType v, std::string& s) noexcept {\n    if (std::isnan(v)) {\n        s = \".nan\";\n        return;\n    }\n\n    if (std::isinf(v)) {\n        if (v == std::numeric_limits<FloatType>::infinity()) {\n            s = \".inf\";\n        }\n        else {\n            s = \"-.inf\";\n        }\n        return;\n    }\n\n    std::ostringstream oss;\n    oss << v;\n    s = oss.str();\n\n    // If `v` is actually an integer and no scientific notation is used for serialization, \".0\" must be appended.\n    // The result would cause a roundtrip issue otherwise. https://github.com/fktn-k/fkYAML/issues/405\n    const std::size_t pos = s.find_first_of(\".e\");\n    if (pos == std::string::npos) {\n        s += \".0\";\n    }\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_CONVERSIONS_TO_STRING_HPP */\n\n// #include <fkYAML/detail/encodings/yaml_escaper.hpp>\n\n// #include <fkYAML/detail/input/scalar_scanner.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n// #include <fkYAML/node_type.hpp>\n\n// #include <fkYAML/yaml_version_type.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief A basic implementation of serialization feature for YAML nodes.\n/// @tparam BasicNodeType A BasicNode template class instantiation.\ntemplate <typename BasicNodeType>\nclass basic_serializer {\n    static_assert(detail::is_basic_node<BasicNodeType>::value, \"basic_serializer only accepts basic_node<...>\");\n\npublic:\n    /// @brief Construct a new basic_serializer object.\n    basic_serializer() = default;\n\n    /// @brief Serialize the given Node value.\n    /// @param node A Node object to be serialized.\n    /// @return std::string A serialization result of the given Node value.\n    std::string serialize(const BasicNodeType& node) {\n        std::string str {};\n        serialize_document(node, str);\n        return str;\n    } // LCOV_EXCL_LINE\n\n    std::string serialize_docs(const std::vector<BasicNodeType>& docs) {\n        std::string str {};\n\n        const auto size = static_cast<uint32_t>(docs.size());\n        for (uint32_t i = 0; i < size; i++) {\n            serialize_document(docs[i], str);\n            if (i + 1 < size) {\n                // Append the end-of-document marker for the next document.\n                str += \"...\\n\";\n            }\n        }\n\n        return str;\n    } // LCOV_EXCL_LINE\n\nprivate:\n    void serialize_document(const BasicNodeType& node, std::string& str) {\n        const bool dirs_serialized = serialize_directives(node, str);\n\n        // the root node cannot be an alias node.\n        const bool root_has_props = node.is_anchor() || node.has_tag_name();\n\n        if (root_has_props) {\n            if (dirs_serialized) {\n                str.back() = ' '; // replace the last LF with a white space\n            }\n            bool is_anchor_appended = try_append_anchor(node, false, str);\n            try_append_tag(node, is_anchor_appended, str);\n            str += \"\\n\";\n        }\n        serialize_node(node, 0, str);\n    }\n\n    /// @brief Serialize the directives if any is applied to the node.\n    /// @param node The target node.\n    /// @param str A string to hold serialization result.\n    /// @return bool true if any directive is serialized, false otherwise.\n    bool serialize_directives(const BasicNodeType& node, std::string& str) {\n        const auto& p_meta = node.mp_meta;\n        bool needs_directive_end = false;\n\n        if (p_meta->is_version_specified) {\n            str += \"%YAML \";\n            switch (p_meta->version) {\n            case yaml_version_type::VERSION_1_1:\n                str += \"1.1\\n\";\n                break;\n            case yaml_version_type::VERSION_1_2:\n                str += \"1.2\\n\";\n                break;\n            }\n            needs_directive_end = true;\n        }\n\n        if (!p_meta->primary_handle_prefix.empty()) {\n            str += \"%TAG ! \";\n            str += p_meta->primary_handle_prefix;\n            str += \"\\n\";\n            needs_directive_end = true;\n        }\n\n        if (!p_meta->secondary_handle_prefix.empty()) {\n            str += \"%TAG !! \";\n            str += p_meta->secondary_handle_prefix;\n            str += \"\\n\";\n            needs_directive_end = true;\n        }\n\n        if (!p_meta->named_handle_map.empty()) {\n            for (const auto& itr : p_meta->named_handle_map) {\n                str += \"%TAG \";\n                str += itr.first;\n                str += \" \";\n                str += itr.second;\n                str += \"\\n\";\n            }\n            needs_directive_end = true;\n        }\n\n        if (needs_directive_end) {\n            str += \"---\\n\";\n        }\n\n        return needs_directive_end;\n    }\n\n    /// @brief Recursively serialize each Node object.\n    /// @param node A Node object to be serialized.\n    /// @param cur_indent The current indent width\n    /// @param str A string to hold serialization result.\n    void serialize_node(const BasicNodeType& node, const uint32_t cur_indent, std::string& str) {\n        switch (node.get_type()) {\n        case node_type::SEQUENCE:\n            if (node.size() == 0) {\n                str += \"[]\\n\";\n                return;\n            }\n            for (const auto& seq_item : node) {\n                insert_indentation(cur_indent, str);\n                str += \"-\";\n\n                const bool is_appended = try_append_alias(seq_item, true, str);\n                if (is_appended) {\n                    str += \"\\n\";\n                    continue;\n                }\n\n                try_append_anchor(seq_item, true, str);\n                try_append_tag(seq_item, true, str);\n\n                const bool is_scalar = seq_item.is_scalar();\n                if (is_scalar) {\n                    str += \" \";\n                    serialize_node(seq_item, cur_indent, str);\n                    str += \"\\n\";\n                    continue;\n                }\n\n                const bool is_empty = seq_item.empty();\n                if (!is_empty) {\n                    str += \"\\n\";\n                    serialize_node(seq_item, cur_indent + 2, str);\n                    continue;\n                }\n\n                // an empty sequence or mapping\n                if (seq_item.is_sequence()) {\n                    str += \" []\\n\";\n                }\n                else /*seq_item.is_mapping()*/ {\n                    str += \" {}\\n\";\n                }\n            }\n            break;\n        case node_type::MAPPING:\n            if (node.size() == 0) {\n                str += \"{}\\n\";\n                return;\n            }\n            for (auto itr : node.map_items()) {\n                insert_indentation(cur_indent, str);\n\n                // serialize a mapping key node.\n                const auto& key_node = itr.key();\n\n                bool is_appended = try_append_alias(key_node, false, str);\n                if (is_appended) {\n                    // The trailing white space is necessary since anchor names can contain a colon (:) at its end.\n                    str += \" \";\n                }\n                else {\n                    const bool is_anchor_appended = try_append_anchor(key_node, false, str);\n                    const bool is_tag_appended = try_append_tag(key_node, is_anchor_appended, str);\n                    if (is_anchor_appended || is_tag_appended) {\n                        str += \" \";\n                    }\n\n                    const bool is_container = !key_node.is_scalar();\n                    if (is_container) {\n                        str += \"? \";\n                    }\n                    const auto indent = static_cast<uint32_t>(get_cur_indent(str));\n                    serialize_node(key_node, indent, str);\n                    if (is_container) {\n                        // a newline code is already inserted in the above serialize_node() call.\n                        insert_indentation(indent - 2, str);\n                    }\n                }\n\n                str += \":\";\n\n                // serialize a mapping value node.\n                const auto& value_node = itr.value();\n\n                is_appended = try_append_alias(value_node, true, str);\n                if (is_appended) {\n                    str += \"\\n\";\n                    continue;\n                }\n\n                try_append_anchor(value_node, true, str);\n                try_append_tag(value_node, true, str);\n\n                const bool is_scalar = itr->is_scalar();\n                if (is_scalar) {\n                    str += \" \";\n                    serialize_node(value_node, cur_indent, str);\n                    str += \"\\n\";\n                    continue;\n                }\n\n                const bool is_empty = itr->empty();\n                if (is_empty) {\n                    str += \" \";\n                }\n                else {\n                    str += \"\\n\";\n                }\n                serialize_node(value_node, cur_indent + 2, str);\n            }\n            break;\n        case node_type::NULL_OBJECT:\n            to_string(nullptr, m_tmp_str_buff);\n            str += m_tmp_str_buff;\n            break;\n        case node_type::BOOLEAN:\n            to_string(node.template get_value<typename BasicNodeType::boolean_type>(), m_tmp_str_buff);\n            str += m_tmp_str_buff;\n            break;\n        case node_type::INTEGER:\n            to_string(node.template get_value<typename BasicNodeType::integer_type>(), m_tmp_str_buff);\n            str += m_tmp_str_buff;\n            break;\n        case node_type::FLOAT:\n            to_string(node.template get_value<typename BasicNodeType::float_number_type>(), m_tmp_str_buff);\n            str += m_tmp_str_buff;\n            break;\n        case node_type::STRING: {\n            bool is_escaped = false;\n            auto str_val = get_string_node_value(node, is_escaped);\n\n            if (is_escaped) {\n                // There's no other token type with escapes than strings.\n                // Also, escapes must be in double-quoted strings.\n                str += '\\\"';\n                str += str_val;\n                str += '\\\"';\n                break;\n            }\n\n            // The next line is intentionally excluded from the LCOV coverage target since the next line is somehow\n            // misrecognized as it has a binary branch. Possibly begin() or end() has some conditional branch(es)\n            // internally. Confirmed with LCOV 1.14 on Ubuntu22.04.\n            const node_type type_if_plain =\n                scalar_scanner::scan(str_val.c_str(), str_val.c_str() + str_val.size()); // LCOV_EXCL_LINE\n\n            if (type_if_plain != node_type::STRING) {\n                // Surround a string value with double quotes to keep semantic equality.\n                // Without them, serialized values will become non-string. (e.g., \"1\" -> 1)\n                str += '\\\"';\n                str += str_val;\n                str += '\\\"';\n            }\n            else {\n                str += str_val;\n            }\n            break;\n        }\n        }\n    }\n\n    /// @brief Get the current indentation width.\n    /// @param s The target string object.\n    /// @return The current indentation width.\n    std::size_t get_cur_indent(const std::string& s) const noexcept {\n        const bool is_empty = s.empty();\n        if (is_empty) {\n            return 0;\n        }\n\n        const std::size_t last_lf_pos = s.rfind('\\n');\n        return (last_lf_pos != std::string::npos) ? s.size() - last_lf_pos - 1 : s.size();\n    }\n\n    /// @brief Insert indentation to the serialization result.\n    /// @param indent The indent width to be inserted.\n    /// @param str A string to hold serialization result.\n    void insert_indentation(const uint32_t indent, std::string& str) const noexcept {\n        if (indent == 0) {\n            return;\n        }\n\n        str.append(indent - get_cur_indent(str), ' ');\n    }\n\n    /// @brief Append an anchor property if it's available. Do nothing otherwise.\n    /// @param node The target node which is possibly an anchor node.\n    /// @param prepends_space Whether to prepend a space before an anchor property.\n    /// @param str A string to hold serialization result.\n    /// @return true if an anchor property has been appended, false otherwise.\n    bool try_append_anchor(const BasicNodeType& node, bool prepends_space, std::string& str) const {\n        if (node.is_anchor()) {\n            if (prepends_space) {\n                str += \" \";\n            }\n            str += \"&\" + node.get_anchor_name();\n            return true;\n        }\n        return false;\n    }\n\n    /// @brief Append an alias property if it's available. Do nothing otherwise.\n    /// @param node The target node which is possibly an alias node.\n    /// @param prepends_space Whether to prepend a space before an alias property.\n    /// @param str A string to hold serialization result.\n    /// @return true if an alias property has been appended, false otherwise.\n    bool try_append_alias(const BasicNodeType& node, bool prepends_space, std::string& str) const {\n        if (node.is_alias()) {\n            if (prepends_space) {\n                str += \" \";\n            }\n            str += \"*\" + node.get_anchor_name();\n            return true;\n        }\n        return false;\n    }\n\n    /// @brief Append a tag name if it's available. Do nothing otherwise.\n    /// @param[in] node The target node which possibly has a tag name.\n    /// @param[out] str A string to hold serialization result.\n    /// @return true if a tag name has been appended, false otherwise.\n    bool try_append_tag(const BasicNodeType& node, bool prepends_space, std::string& str) const {\n        if (node.has_tag_name()) {\n            if (prepends_space) {\n                str += \" \";\n            }\n            str += node.get_tag_name();\n            return true;\n        }\n        return false;\n    }\n\n    /// @brief Get a string value from the given node and, if necessary, escape its contents.\n    /// @param[in] node The target string YAML node.\n    /// @param[out] is_escaped Whether the contents of an output string has been escaped.\n    /// @return The (escaped) string node value.\n    typename BasicNodeType::string_type get_string_node_value(const BasicNodeType& node, bool& is_escaped) {\n        FK_YAML_ASSERT(node.is_string());\n\n        const auto& s = node.template get_value_ref<const typename BasicNodeType::string_type&>();\n        return yaml_escaper::escape(s.c_str(), s.c_str() + s.size(), is_escaped);\n    } // LCOV_EXCL_LINE\n\nprivate:\n    /// A temporal buffer for conversion from a scalar to a string.\n    std::string m_tmp_str_buff;\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_OUTPUT_SERIALIZER_HPP */\n\n// #include <fkYAML/detail/reverse_iterator.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_REVERSE_ITERATOR_HPP\n#define FK_YAML_DETAIL_REVERSE_ITERATOR_HPP\n\n#include <iterator>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief An iterator adapter class that reverses the direction of a given node iterator.\n/// @tparam Iterator The base iterator type.\ntemplate <typename Iterator>\nclass reverse_iterator {\n    static_assert(\n        is_basic_node<typename std::remove_const<typename Iterator::value_type>::type>::value,\n        \"reverse_iterator only accepts a basic_node type as the underlying iterator's value type\");\n\npublic:\n    /// @brief The base iterator type.\n    using iterator_type = Iterator;\n\n    /// @brief The base iterator category.\n    using iterator_category = typename Iterator::iterator_category;\n\n    /// @brief The type of the pointed-to elements by base iterators.\n    using value_type = typename Iterator::value_type;\n\n    /// @brief The type to represent differences between the pointed-to elements by the base iterators.\n    using difference_type = typename Iterator::difference_type;\n\n    /// @brief The type of the pointed-to element pointers by base iterators.\n    using pointer = typename Iterator::pointer;\n\n    /// @brief The type of the pointed-to element references by base iterators.\n    using reference = typename Iterator::reference;\n\n    /// @brief Constructs a reverse_iterator object.\n    reverse_iterator() = default;\n\n    /// @brief Copy constructs a reverse_iterator object.\n    reverse_iterator(const reverse_iterator&) = default;\n\n    /// @brief Copy assignments a reverse_iterator object.\n    reverse_iterator& operator=(const reverse_iterator&) = default;\n\n    /// @brief Move constructs a reverse_iterator object.\n    reverse_iterator(reverse_iterator&&) = default;\n\n    /// @brief Move assignments a reverse_iterator object.\n    reverse_iterator& operator=(reverse_iterator&&) = default;\n\n    /// @brief Constructs a reverse_iterator object with an underlying iterator object.\n    /// @param i A base iterator object.\n    reverse_iterator(const Iterator& i) noexcept\n        : m_current(i) {\n    }\n\n    /// @brief Copy constructs a reverse_iterator object with a compatible reverse_iterator object.\n    /// @tparam U A compatible iterator type with Iterator.\n    /// @param other A compatible reverse_iterator object.\n    template <typename U, enable_if_t<negation<std::is_same<U, Iterator>>::value, int> = 0>\n    reverse_iterator(const reverse_iterator<U>& other) noexcept\n        : m_current(other.base()) {\n    }\n\n    /// @brief Copy assigns a reverse_iterator object with a compatible reverse_iterator object.\n    /// @tparam U A compatible iterator type with Iterator.\n    /// @param other A compatible reverse_iterator object.\n    /// @return Reference to this reverse_iterator object.\n    template <typename U, enable_if_t<negation<std::is_same<U, Iterator>>::value, int> = 0>\n    reverse_iterator& operator=(const reverse_iterator<U>& other) noexcept {\n        m_current = other.base();\n        return *this;\n    }\n\n    /// @brief Destructs a reverse_iterator object.\n    ~reverse_iterator() = default;\n\n    /// @brief Accesses the underlying iterator object.\n    /// @return The underlying iterator object.\n    Iterator base() const noexcept {\n        return m_current;\n    }\n\n    /// @brief Get reference to the pointed-to element.\n    /// @return Reference to the pointed-to element.\n    reference operator*() const noexcept {\n        Iterator tmp = m_current;\n        return *--tmp;\n    }\n\n    /// @brief Get pointer to the pointed-to element.\n    /// @return Pointer to the pointed-to element.\n    pointer operator->() const noexcept {\n        return &(operator*());\n    }\n\n    /// @brief Pre-increments the underlying iterator object.\n    /// @return Reference to this reverse_iterator object with its underlying iterator incremented.\n    reverse_iterator& operator++() noexcept {\n        --m_current;\n        return *this;\n    }\n\n    /// @brief Post-increments the underlying iterator object.\n    /// @return A reverse_iterator object with the underlying iterator as-is.\n    reverse_iterator operator++(int) & noexcept {\n        auto result = *this;\n        --m_current;\n        return result;\n    }\n\n    /// @brief Pre-decrements the underlying iterator object.\n    /// @return Reference to this reverse_iterator with its underlying iterator decremented.\n    reverse_iterator& operator--() noexcept {\n        ++m_current;\n        return *this;\n    }\n\n    /// @brief Post-decrements the underlying iterator object.\n    /// @return A reverse_iterator object with the underlying iterator as-is.\n    reverse_iterator operator--(int) & noexcept {\n        auto result = *this;\n        ++m_current;\n        return result;\n    }\n\n    /// @brief Advances the underlying iterator object by `n`.\n    /// @param n The distance by which the underlying iterator is advanced.\n    /// @return A reverse_iterator object with the underlying iterator advanced by `n`.\n    reverse_iterator operator+(difference_type n) const noexcept {\n        return reverse_iterator(m_current - n);\n    }\n\n    /// @brief Advances the underlying iterator object by `n`.\n    /// @param n The distance by which the underlying iterator is advanced.\n    /// @return Reference to this reverse_iterator object with the underlying iterator advanced by `n`.\n    reverse_iterator& operator+=(difference_type n) noexcept {\n        m_current -= n;\n        return *this;\n    }\n\n    /// @brief Decrements the underlying iterator object by `n`.\n    /// @param n The distance by which the underlying iterator is decremented.\n    /// @return A reverse_iterator object with the underlying iterator decremented by `n`.\n    reverse_iterator operator-(difference_type n) const noexcept {\n        return reverse_iterator(m_current + n);\n    }\n\n    /// @brief Decrements the underlying iterator object by `n`.\n    /// @param n The distance by which the underlying iterator is decremented.\n    /// @return Reference to this reverse_iterator object with the underlying iterator decremented by `n`.\n    reverse_iterator& operator-=(difference_type n) noexcept {\n        m_current += n;\n        return *this;\n    }\n\n    /// @brief Get the mapping key node of the underlying iterator.\n    /// @return The mapping key node of the underlying iterator.\n    auto key() const -> decltype(std::declval<Iterator>().key()) {\n        Iterator itr = --(base());\n        return itr.key();\n    }\n\n    /// @brief Get reference to the underlying iterator's value.\n    /// @return Reference to the underlying iterator's value.\n    reference value() noexcept {\n        Iterator itr = --(base());\n        return *itr;\n    }\n\nprivate:\n    ///\n    Iterator m_current;\n};\n\n/// @brief Check equality between reverse_iterator objects.\n/// @tparam IteratorL Base iterator type for `lhs`.\n/// @tparam IteratorR Base iterator type for `rhs`.\n/// @param lhs A reverse_iterator object.\n/// @param rhs A reverse_iterator object.\n/// @return true if the two reverse_iterator objects are equal, false otherwise.\ntemplate <typename IteratorL, typename IteratorR>\ninline bool operator==(const reverse_iterator<IteratorL>& lhs, const reverse_iterator<IteratorR>& rhs) {\n    return lhs.base() == rhs.base();\n}\n\n/// @brief Check inequality between reverse_iterator objects.\n/// @tparam IteratorL Base iterator type for `lhs`.\n/// @tparam IteratorR Base iterator type for `rhs`.\n/// @param lhs A reverse_iterator object.\n/// @param rhs A reverse_iterator object.\n/// @return true if the two reverse_iterator objects are not equal, false otherwise.\ntemplate <typename IteratorL, typename IteratorR>\ninline bool operator!=(const reverse_iterator<IteratorL>& lhs, const reverse_iterator<IteratorR>& rhs) {\n    return lhs.base() != rhs.base();\n}\n\n/// @brief Check if `lhs` is less than `rhs`.\n/// @tparam IteratorL Base iterator type for `lhs`.\n/// @tparam IteratorR Base iterator type for `rhs`.\n/// @param lhs A reverse_iterator object.\n/// @param rhs A reverse_iterator object.\n/// @return true if `lhs` is less than `rhs`, false otherwise.\ntemplate <typename IteratorL, typename IteratorR>\ninline bool operator<(const reverse_iterator<IteratorL>& lhs, const reverse_iterator<IteratorR>& rhs) {\n    return lhs.base() > rhs.base();\n}\n\n/// @brief Check if `lhs` is less than or equal to `rhs`.\n/// @tparam IteratorL Base iterator type for `lhs`.\n/// @tparam IteratorR Base iterator type for `rhs`.\n/// @param lhs A reverse_iterator object.\n/// @param rhs A reverse_iterator object.\n/// @return true if `lhs` is less than or equal to `rhs`, false otherwise.\ntemplate <typename IteratorL, typename IteratorR>\ninline bool operator<=(const reverse_iterator<IteratorL>& lhs, const reverse_iterator<IteratorR>& rhs) {\n    return lhs.base() >= rhs.base();\n}\n\n/// @brief Check if `lhs` is greater than `rhs`.\n/// @tparam IteratorL Base iterator type for `lhs`.\n/// @tparam IteratorR Base iterator type for `rhs`.\n/// @param lhs A reverse_iterator object.\n/// @param rhs A reverse_iterator object.\n/// @return true if `lhs` is greater than `rhs`, false otherwise.\ntemplate <typename IteratorL, typename IteratorR>\ninline bool operator>(const reverse_iterator<IteratorL>& lhs, const reverse_iterator<IteratorR>& rhs) {\n    return lhs.base() < rhs.base();\n}\n\n/// @brief Check if `lhs` is greater than or equal to `rhs`.\n/// @tparam IteratorL Base iterator type for `lhs`.\n/// @tparam IteratorR Base iterator type for `rhs`.\n/// @param lhs A reverse_iterator object.\n/// @param rhs A reverse_iterator object.\n/// @return true if `lhs` is greater than or equal to `rhs`, false otherwise.\ntemplate <typename IteratorL, typename IteratorR>\ninline bool operator>=(const reverse_iterator<IteratorL>& lhs, const reverse_iterator<IteratorR>& rhs) {\n    return lhs.base() <= rhs.base();\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_REVERSE_ITERATOR_HPP */\n\n// #include <fkYAML/detail/types/node_t.hpp>\n\n// #include <fkYAML/detail/types/yaml_version_t.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_TYPES_YAML_VERSION_T_HPP\n#define FK_YAML_DETAIL_TYPES_YAML_VERSION_T_HPP\n\n#include <cstdint>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/yaml_version_type.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n/// @brief Definition of YAML version types.\nenum class yaml_version_t : std::uint8_t {\n    VER_1_1, //!< YAML version 1.1\n    VER_1_2, //!< YAML version 1.2\n};\n\ninline yaml_version_t convert_from_yaml_version_type(yaml_version_type t) noexcept {\n    switch (t) {\n    case yaml_version_type::VERSION_1_1:\n        return yaml_version_t::VER_1_1;\n    case yaml_version_type::VERSION_1_2:\n    default:\n        return yaml_version_t::VER_1_2;\n    }\n}\n\ninline yaml_version_type convert_to_yaml_version_type(yaml_version_t t) noexcept {\n    switch (t) {\n    case yaml_version_t::VER_1_1:\n        return yaml_version_type::VERSION_1_1;\n    case yaml_version_t::VER_1_2:\n    default:\n        return yaml_version_type::VERSION_1_2;\n    }\n}\n\nFK_YAML_DETAIL_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_TYPES_YAML_VERSION_T_HPP */\n\n// #include <fkYAML/exception.hpp>\n\n// #include <fkYAML/node_type.hpp>\n\n// #include <fkYAML/node_value_converter.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_NODE_VALUE_CONVERTER_HPP\n#define FK_YAML_NODE_VALUE_CONVERTER_HPP\n\n#include <utility>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/conversions/from_node.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_CONVERSIONS_FROM_NODE_HPP\n#define FK_YAML_DETAIL_CONVERSIONS_FROM_NODE_HPP\n\n#include <array>\n#include <cmath>\n#include <forward_list>\n#include <limits>\n#include <utility>\n#include <valarray>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n// #include <fkYAML/detail/types/node_t.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\n#ifdef FK_YAML_HAS_CXX_17\n#include <optional>\n#endif\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n///////////////////\n//   from_node   //\n///////////////////\n\n// utility type traits and functors\n\n/// @brief Utility traits type alias to detect constructible associative container types from a mapping node, e.g.,\n/// std::map or std::unordered_map.\n/// @tparam T A target type for detection.\ntemplate <typename T>\nusing is_constructible_mapping_type =\n    conjunction<detect::has_key_type<T>, detect::has_mapped_type<T>, detect::has_value_type<T>>;\n\n/// @brief Utility traits type alias to detect constructible container types from a sequence node, e.g., std::vector or\n/// std::list.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A target type for detection.\ntemplate <typename BasicNodeType, typename T>\nusing is_constructible_sequence_type = conjunction<\n    negation<is_basic_node<T>>, detect::has_iterator<T>, detect::is_iterator_traits<typename T::iterator>,\n    detect::has_begin_end<T>, negation<std::is_same<T, typename BasicNodeType::mapping_type>>,\n    negation<is_constructible_mapping_type<T>>>;\n\n/// @brief Utility traits type alias to detect a sequence container adapter type, e.g., std::stack or std::queue.\n/// @tparam T A target type for detection.\ntemplate <typename T>\nusing is_sequence_container_adapter = conjunction<\n    negation<is_basic_node<T>>, detect::has_container_type<T>, detect::has_value_type<T>,\n    negation<detect::has_key_type<T>>>;\n\n/// @brief Helper struct for reserve() member function call switch for types which do not have reserve function.\n/// @tparam ContainerType A container type.\ntemplate <typename ContainerType, typename = void>\nstruct call_reserve_if_available {\n    /// @brief Do nothing since ContainerType does not have reserve function.\n    static void call(ContainerType& /*unused*/, typename ContainerType::size_type /*unused*/) {\n    }\n};\n\n/// @brief Helper struct for reserve() member function call switch for types which have reserve function.\n/// @tparam ContainerType A container type.\ntemplate <typename ContainerType>\nstruct call_reserve_if_available<ContainerType, enable_if_t<detect::has_reserve<ContainerType>::value>> {\n    /// @brief Call reserve function on the ContainerType object with a given size.\n    /// @param c A container object.\n    /// @param n A size to reserve.\n    static void call(ContainerType& c, typename ContainerType::size_type n) {\n        c.reserve(n);\n    }\n};\n\n// from_node() implementations\n\n/// @brief from_node function for C-style 1D arrays whose element type must be a basic_node template instance type or a\n/// compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T Element type of C-style 1D array.\n/// @tparam N Size of the array.\n/// @param n A basic_node object.\n/// @param array An array object.\ntemplate <typename BasicNodeType, typename T, std::size_t N>\ninline auto from_node(const BasicNodeType& n, T (&array)[N])\n    -> decltype(n.get_value_inplace(std::declval<T&>()), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    // call get_value_inplace(), not get_value(), since the storage to fill the result into is already created.\n    for (std::size_t i = 0; i < N; i++) {\n        n.at(i).get_value_inplace(array[i]);\n    }\n}\n\n/// @brief from_node function for C-style 2D arrays whose element type must be a basic_node template instance type or a\n/// compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T Element type of C-style 2D array.\n/// @tparam N0 Size of the outer dimension.\n/// @tparam N1 Size of the inner dimension.\n/// @param n A basic_node object.\n/// @param array An array object.\ntemplate <typename BasicNodeType, typename T, std::size_t N0, std::size_t N1>\ninline auto from_node(const BasicNodeType& n, T (&array)[N0][N1])\n    -> decltype(n.get_value_inplace(std::declval<T&>()), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    // call get_value_inplace(), not get_value(), since the storage to fill the result into is already created.\n    for (std::size_t i0 = 0; i0 < N0; i0++) {\n        for (std::size_t i1 = 0; i1 < N1; i1++) {\n            n.at(i0).at(i1).get_value_inplace(array[i0][i1]);\n        }\n    }\n}\n\n/// @brief from_node function for C-style 2D arrays whose element type must be a basic_node template instance type or a\n/// compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T Element type of C-style 2D array.\n/// @tparam N0 Size of the outermost dimension.\n/// @tparam N1 Size of the middle dimension.\n/// @tparam N2 Size of the innermost dimension.\n/// @param n A basic_node object.\n/// @param array An array object.\ntemplate <typename BasicNodeType, typename T, std::size_t N0, std::size_t N1, std::size_t N2>\ninline auto from_node(const BasicNodeType& n, T (&array)[N0][N1][N2])\n    -> decltype(n.get_value_inplace(std::declval<T&>()), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    // call get_value_inplace(), not get_value(), since the storage to fill the result into is already created.\n    for (std::size_t i0 = 0; i0 < N0; i0++) {\n        for (std::size_t i1 = 0; i1 < N1; i1++) {\n            for (std::size_t i2 = 0; i2 < N2; i2++) {\n                n.at(i0).at(i1).at(i2).get_value_inplace(array[i0][i1][i2]);\n            }\n        }\n    }\n}\n\n/// @brief from_node function for std::array objects whose element type must be a basic_node template instance type or a\n/// compatible type. This function is necessary since insert function is not implemented for std::array.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T Element type of std::array.\n/// @tparam N Size of std::array.\n/// @param n A basic_node object.\n/// @param arr A std::array object.\ntemplate <typename BasicNodeType, typename T, std::size_t N>\ninline auto from_node(const BasicNodeType& n, std::array<T, N>& arr)\n    -> decltype(n.get_value_inplace(std::declval<T&>()), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    for (std::size_t i = 0; i < N; i++) {\n        // call get_value_inplace(), not get_value(), since the storage to fill the result into is already created.\n        n.at(i).get_value_inplace(arr.at(i));\n    }\n}\n\n/// @brief from_node function for std::valarray objects whose element type must be a basic_node template instance type\n/// or a compatible type. This function is necessary since insert function is not implemented for std::valarray.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T Element type of std::valarray.\n/// @param n A basic_node object.\n/// @param va A std::valarray object.\ntemplate <typename BasicNodeType, typename T>\ninline auto from_node(const BasicNodeType& n, std::valarray<T>& va)\n    -> decltype(n.get_value_inplace(std::declval<T&>()), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    std::size_t count = n.size();\n    va.resize(count);\n    for (std::size_t i = 0; i < count; i++) {\n        // call get_value_inplace(), not get_value(), since the storage to fill the result into is already created.\n        n.at(i).get_value_inplace(va[i]);\n    }\n}\n\n/// @brief from_node function for std::forward_list objects whose element type must be a basic_node template instance\n/// type or a compatible type. This function is necessary since insert function is not implemented for\n/// std::forward_list.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T Element type of std::forward_list.\n/// @tparam Alloc Allocator type of std::forward_list.\n/// @param n A basic_node object.\n/// @param fl A std::forward_list object.\ntemplate <typename BasicNodeType, typename T, typename Alloc>\ninline auto from_node(const BasicNodeType& n, std::forward_list<T, Alloc>& fl)\n    -> decltype(n.template get_value<T>(), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value is not sequence type.\", n.get_type());\n    }\n\n    fl.clear();\n\n    // std::forward_list does not have insert function.\n    auto insert_pos_itr = fl.before_begin();\n    for (const auto& elem : n) {\n        insert_pos_itr = fl.emplace_after(insert_pos_itr, elem.template get_value<T>());\n    }\n}\n\n/// @brief from_node function for container objects of only keys or values, e.g., std::vector or std::set, whose element\n/// type must be a basic_node template instance type or a compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatSeqType A container type.\n/// @param n A basic_node object.\n/// @param s A container object.\ntemplate <\n    typename BasicNodeType, typename CompatSeqType,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>, is_constructible_sequence_type<BasicNodeType, CompatSeqType>,\n            negation<std::is_constructible<typename BasicNodeType::string_type, CompatSeqType>>>::value,\n        int> = 0>\ninline auto from_node(const BasicNodeType& n, CompatSeqType& s)\n    -> decltype(n.template get_value<typename CompatSeqType::value_type>(), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value is not sequence type.\", n.get_type());\n    }\n\n    s.clear();\n\n    // call reserve function first if it's available (like std::vector).\n    call_reserve_if_available<CompatSeqType>::call(s, n.size());\n\n    // transform a sequence node into a destination type object by calling insert function.\n    using std::end;\n    std::transform(n.begin(), n.end(), std::inserter(s, end(s)), [](const BasicNodeType& elem) {\n        return elem.template get_value<typename CompatSeqType::value_type>();\n    });\n}\n\n/// @brief from_node function for sequence container adapter objects, e.g., std::stack or std::queue, whose element type\n/// must be either a basic_node template instance type or a compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam SeqContainerAdapter A sequence container adapter type.\n/// @param n A node object.\n/// @param ca A sequence container adapter object.\ntemplate <\n    typename BasicNodeType, typename SeqContainerAdapter,\n    enable_if_t<\n        conjunction<is_basic_node<BasicNodeType>, is_sequence_container_adapter<SeqContainerAdapter>>::value, int> = 0>\ninline auto from_node(const BasicNodeType& n, SeqContainerAdapter& ca)\n    -> decltype(n.template get_value<typename SeqContainerAdapter::value_type>(), ca.push(std::declval<typename SeqContainerAdapter::value_type>()), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value is not sequence type.\", n.get_type());\n    }\n\n    // clear existing elements manually since clear function is not implemeneted for container adapter classes.\n    while (!ca.empty()) {\n        ca.pop();\n    }\n\n    for (const auto& elem : n) {\n        // container adapter classes commonly have push function.\n        // emplace function cannot be used in case SeqContainerAdapter::container_type is std::vector<bool> in C++11.\n        ca.push(elem.template get_value<typename SeqContainerAdapter::value_type>());\n    }\n}\n\n/// @brief from_node function for mappings whose key and value are of both compatible types.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatibleKeyType Mapping key type compatible with BasicNodeType.\n/// @tparam CompatibleValueType Mapping value type compatible with BasicNodeType.\n/// @tparam Compare Comparator type for mapping keys.\n/// @tparam Allocator Allocator type for destination mapping object.\n/// @param n A node object.\n/// @param m Mapping container object to store converted key/value objects.\ntemplate <typename BasicNodeType, typename CompatMapType, enable_if_t<is_constructible_mapping_type<CompatMapType>::value, int> = 0>\ninline auto from_node(const BasicNodeType& n, CompatMapType& m)\n    -> decltype(\n        std::declval<const BasicNodeType&>().template get_value<typename CompatMapType::key_type>(),\n        std::declval<const BasicNodeType&>().template get_value<typename CompatMapType::mapped_type>(),\n        m.emplace(std::declval<typename CompatMapType::key_type>(), std::declval<typename CompatMapType::mapped_type>()),\n        void()) {\n    if FK_YAML_UNLIKELY (!n.is_mapping()) {\n        throw type_error(\"The target node value type is not mapping type.\", n.get_type());\n    }\n\n    m.clear();\n    call_reserve_if_available<CompatMapType>::call(m, n.size());\n\n    for (const auto& pair : n.template get_value_ref<const typename BasicNodeType::mapping_type&>()) {\n        m.emplace(\n            pair.first.template get_value<typename CompatMapType::key_type>(),\n            pair.second.template get_value<typename CompatMapType::mapped_type>());\n    }\n}\n\n/// @brief from_node function for nullptr.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @param n A node object.\n/// @param null Storage for a null value.\ntemplate <typename BasicNodeType, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline void from_node(const BasicNodeType& n, std::nullptr_t& null) {\n    // to ensure the target node value type is null.\n    if FK_YAML_UNLIKELY (!n.is_null()) {\n        throw type_error(\"The target node value type is not null type.\", n.get_type());\n    }\n    null = nullptr;\n}\n\n/// @brief from_node function for booleans.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @param n A node object.\n/// @param b Storage for a boolean value.\ntemplate <typename BasicNodeType, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline void from_node(const BasicNodeType& n, bool& b) {\n    switch (n.get_type()) {\n    case node_type::NULL_OBJECT:\n        // nullptr is converted to false just as C++ implicitly does.\n        b = false;\n        break;\n    case node_type::BOOLEAN:\n        b = static_cast<bool>(n.template get_value_ref<const typename BasicNodeType::boolean_type&>());\n        break;\n    case node_type::INTEGER:\n        // true: non-zero, false: zero\n        b = (n.template get_value_ref<const typename BasicNodeType::integer_type&>() != 0);\n        break;\n    case node_type::FLOAT:\n        // true: non-zero, false: zero\n        using float_type = typename BasicNodeType::float_number_type;\n        b = (n.template get_value_ref<const float_type&>() != static_cast<float_type>(0.));\n        break;\n    case node_type::SEQUENCE:\n    case node_type::MAPPING:\n    case node_type::STRING:\n    default:\n        throw type_error(\"The target node value type is not compatible with boolean type.\", n.get_type());\n    }\n}\n\n/// @brief Helper struct for node-to-int conversion.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam IntType Target integer value type (same as BasicNodeType::integer_type)\ntemplate <\n    typename BasicNodeType, typename IntType, bool = std::is_same<typename BasicNodeType::integer_type, IntType>::value>\nstruct from_node_int_helper {\n    /// @brief Convert node's integer value to the target integer type.\n    /// @param n A node object.\n    /// @return An integer value converted from the node's integer value.\n    static IntType convert(const BasicNodeType& n) {\n        return n.template get_value_ref<const typename BasicNodeType::integer_type&>();\n    }\n};\n\n/// @brief Helper struct for node-to-int conversion if IntType is not the node's integer value type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam IntType Target integer value type (different from BasicNodeType::integer_type)\ntemplate <typename BasicNodeType, typename IntType>\nstruct from_node_int_helper<BasicNodeType, IntType, false> {\n    /// @brief Convert node's integer value to non-uint64_t integer types.\n    /// @param n A node object.\n    /// @return An integer value converted from the node's integer value.\n    static IntType convert(const BasicNodeType& n) {\n        using node_int_type = typename BasicNodeType::integer_type;\n        const node_int_type tmp_int = n.template get_value_ref<const node_int_type&>();\n\n        // under/overflow check.\n        if (std::is_same<IntType, uint64_t>::value) {\n            if FK_YAML_UNLIKELY (tmp_int < 0) {\n                throw exception(\"Integer value underflow detected.\");\n            }\n        }\n        else {\n            if FK_YAML_UNLIKELY (tmp_int < static_cast<node_int_type>(std::numeric_limits<IntType>::min())) {\n                throw exception(\"Integer value underflow detected.\");\n            }\n            if FK_YAML_UNLIKELY (static_cast<node_int_type>(std::numeric_limits<IntType>::max()) < tmp_int) {\n                throw exception(\"Integer value overflow detected.\");\n            }\n        }\n\n        return static_cast<IntType>(tmp_int);\n    }\n};\n\n/// @brief from_node function for integers.\n/// @note If node's value is null, boolean, or float, such a value is converted into an integer internally.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam IntegerType An integer value type.\n/// @param n A node object.\n/// @param i Storage for an integer value.\ntemplate <\n    typename BasicNodeType, typename IntegerType,\n    enable_if_t<conjunction<is_basic_node<BasicNodeType>, is_non_bool_integral<IntegerType>>::value, int> = 0>\ninline void from_node(const BasicNodeType& n, IntegerType& i) {\n    switch (n.get_type()) {\n    case node_type::NULL_OBJECT:\n        // nullptr is interpreted as 0\n        i = static_cast<IntegerType>(0);\n        break;\n    case node_type::BOOLEAN:\n        i = static_cast<bool>(n.template get_value_ref<const typename BasicNodeType::boolean_type&>())\n                ? static_cast<IntegerType>(1)\n                : static_cast<IntegerType>(0);\n        break;\n    case node_type::INTEGER:\n        i = from_node_int_helper<BasicNodeType, IntegerType>::convert(n);\n        break;\n    case node_type::FLOAT: {\n        // int64_t should be safe to express integer part values of possible floating point types.\n        const auto tmp_int =\n            static_cast<int64_t>(n.template get_value_ref<const typename BasicNodeType::float_number_type&>());\n\n        // under/overflow check.\n        if (std::is_same<IntegerType, uint64_t>::value) {\n            if FK_YAML_UNLIKELY (tmp_int < 0) {\n                throw exception(\"Integer value underflow detected.\");\n            }\n        }\n        else {\n            if FK_YAML_UNLIKELY (tmp_int < static_cast<int64_t>(std::numeric_limits<IntegerType>::min())) {\n                throw exception(\"Integer value underflow detected.\");\n            }\n            if FK_YAML_UNLIKELY (static_cast<int64_t>(std::numeric_limits<IntegerType>::max()) < tmp_int) {\n                throw exception(\"Integer value overflow detected.\");\n            }\n        }\n\n        i = static_cast<IntegerType>(tmp_int);\n        break;\n    }\n    case node_type::SEQUENCE:\n    case node_type::MAPPING:\n    case node_type::STRING:\n    default:\n        throw type_error(\"The target node value type is not compatible with integer type.\", n.get_type());\n    }\n}\n\n/// @brief Helper struct for node-to-float conversion if FloatType is the node's floating point value type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam FloatType Target floating point value type (same as the BasicNodeType::float_number_type)\ntemplate <\n    typename BasicNodeType, typename FloatType,\n    bool = std::is_same<typename BasicNodeType::float_number_type, FloatType>::value>\nstruct from_node_float_helper {\n    /// @brief Convert node's floating point value to the target floating point type.\n    /// @param n A node object.\n    /// @return A floating point value converted from the node's floating point value.\n    static FloatType convert(const BasicNodeType& n) {\n        return n.template get_value_ref<const typename BasicNodeType::float_number_type&>();\n    }\n};\n\n/// @brief Helper struct for node-to-float conversion if IntType is not the node's floating point value type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam FloatType Target floating point value type (different from BasicNodeType::float_number_type)\ntemplate <typename BasicNodeType, typename FloatType>\nstruct from_node_float_helper<BasicNodeType, FloatType, false> {\n    /// @brief Convert node's floating point value to the target floating point type.\n    /// @param n A node object.\n    /// @return A floating point value converted from the node's floating point value.\n    static FloatType convert(const BasicNodeType& n) {\n        using node_float_type = typename BasicNodeType::float_number_type;\n        auto tmp_float = n.template get_value_ref<const node_float_type&>();\n\n        // check if the value is an infinite number (either positive or negative)\n        if (std::isinf(tmp_float)) {\n            if (tmp_float == std::numeric_limits<node_float_type>::infinity()) {\n                return std::numeric_limits<FloatType>::infinity();\n            }\n\n            return static_cast<FloatType>(-1.) * std::numeric_limits<FloatType>::infinity();\n        }\n\n        // check if the value is not a number\n        if (std::isnan(tmp_float)) {\n            return std::numeric_limits<FloatType>::quiet_NaN();\n        }\n\n        // check if the value is expressible as FloatType.\n        if FK_YAML_UNLIKELY (tmp_float < std::numeric_limits<FloatType>::lowest()) {\n            throw exception(\"Floating point value underflow detected.\");\n        }\n        if FK_YAML_UNLIKELY (std::numeric_limits<FloatType>::max() < tmp_float) {\n            throw exception(\"Floating point value overflow detected.\");\n        }\n\n        return static_cast<FloatType>(tmp_float);\n    }\n};\n\n/// @brief from_node function for floating point values.\n/// @note If node's value is null, boolean, or integer, such a value is converted into a floating point internally.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam FloatType A floating point value type.\n/// @param n A node object.\n/// @param f Storage for a float point value.\ntemplate <\n    typename BasicNodeType, typename FloatType,\n    enable_if_t<conjunction<is_basic_node<BasicNodeType>, std::is_floating_point<FloatType>>::value, int> = 0>\ninline void from_node(const BasicNodeType& n, FloatType& f) {\n    switch (n.get_type()) {\n    case node_type::NULL_OBJECT:\n        // nullptr is interpreted as 0.0\n        f = static_cast<FloatType>(0.);\n        break;\n    case node_type::BOOLEAN:\n        f = static_cast<bool>(n.template get_value_ref<const typename BasicNodeType::boolean_type&>())\n                ? static_cast<FloatType>(1.)\n                : static_cast<FloatType>(0.);\n        break;\n    case node_type::INTEGER:\n        f = static_cast<FloatType>(n.template get_value_ref<const typename BasicNodeType::integer_type&>());\n        break;\n    case node_type::FLOAT:\n        f = from_node_float_helper<BasicNodeType, FloatType>::convert(n);\n        break;\n    case node_type::SEQUENCE:\n    case node_type::MAPPING:\n    case node_type::STRING:\n    default:\n        throw type_error(\"The target node value type is not compatible with float number type.\", n.get_type());\n    }\n}\n\n/// @brief from_node function for BasicNodeType::string_type objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @param n A basic_node object.\n/// @param s A string node value object.\ntemplate <typename BasicNodeType, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline void from_node(const BasicNodeType& n, typename BasicNodeType::string_type& s) {\n    if FK_YAML_UNLIKELY (!n.is_string()) {\n        throw type_error(\"The target node value type is not string type.\", n.get_type());\n    }\n    s = n.template get_value_ref<const typename BasicNodeType::string_type&>();\n}\n\n/// @brief from_node function for compatible string type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatibleStringType A compatible string type.\n/// @param n A basic_node object.\n/// @param s A compatible string object.\ntemplate <\n    typename BasicNodeType, typename CompatibleStringType,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>,\n            negation<std::is_same<CompatibleStringType, typename BasicNodeType::string_type>>,\n            disjunction<\n                std::is_constructible<CompatibleStringType, const typename BasicNodeType::string_type&>,\n                std::is_assignable<CompatibleStringType, const typename BasicNodeType::string_type&>>>::value,\n        int> = 0>\ninline void from_node(const BasicNodeType& n, CompatibleStringType& s) {\n    if FK_YAML_UNLIKELY (!n.is_string()) {\n        throw type_error(\"The target node value type is not string type.\", n.get_type());\n    }\n    s = n.template get_value_ref<const typename BasicNodeType::string_type&>();\n}\n\n/// @brief from_node function for std::pair objects whose element types must be either a basic_node template instance\n/// type or a compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T The first type of the std::pair.\n/// @tparam U The second type of the std::pair.\n/// @param n A basic_node object.\n/// @param p A std::pair object.\ntemplate <typename BasicNodeType, typename T, typename U, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline auto from_node(const BasicNodeType& n, std::pair<T, U>& p)\n    -> decltype(std::declval<const BasicNodeType&>().template get_value<T>(), std::declval<const BasicNodeType&>().template get_value<U>(), void()) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    // call get_value_inplace(), not get_value(), since the storage to fill the result into is already created.\n    n.at(0).get_value_inplace(p.first);\n    n.at(1).get_value_inplace(p.second);\n}\n\n/// @brief concrete implementation of from_node function for std::tuple objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam ...Types The value types of std::tuple.\n/// @tparam ...Idx Index sequence values for std::tuples value types.\n/// @param n A basic_node object\n/// @param _ Index sequence values (unused).\n/// @return A std::tuple object converted from the sequence node values.\ntemplate <typename BasicNodeType, typename... Types, std::size_t... Idx>\ninline std::tuple<Types...> from_node_tuple_impl(const BasicNodeType& n, index_sequence<Idx...> /*unused*/) {\n    return std::make_tuple(n.at(Idx).template get_value<Types>()...);\n}\n\n/// @brief from_node function for std::tuple objects whose value types must all be either a basic_node template instance\n/// type or a compatible type\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam ...Types Value types of std::tuple.\n/// @param n A basic_node object.\n/// @param t A std::tuple object.\ntemplate <typename BasicNodeType, typename... Types, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline void from_node(const BasicNodeType& n, std::tuple<Types...>& t) {\n    if FK_YAML_UNLIKELY (!n.is_sequence()) {\n        throw type_error(\"The target node value type is not sequence type.\", n.get_type());\n    }\n\n    // Types... must be explicitly specified; the retun type would otherwise be std::tuple with no value types.\n    t = from_node_tuple_impl<BasicNodeType, Types...>(n, index_sequence_for<Types...> {});\n}\n\n#ifdef FK_YAML_HAS_CXX_17\n\n/// @brief from_node function for std::optional objects whose value type must be either a basic_node template instance\n/// type or a compatible type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A value type of the std::optional.\n/// @param n A basic_node object.\n/// @param o A std::optional object.\ntemplate <typename BasicNodeType, typename T, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline auto from_node(const BasicNodeType& n, std::optional<T>& o) -> decltype(n.template get_value<T>(), void()) {\n    try {\n        o.emplace(n.template get_value<T>());\n    }\n    catch (const std::exception& /*unused*/) {\n        // Any exception derived from std::exception is interpreted as a conversion failure in some way\n        // since user-defined from_node function may throw a different object from a fkyaml::type_error.\n        // and std::exception is usually the base class of user-defined exception types.\n        o = std::nullopt;\n    }\n}\n\n#endif // defined(FK_YAML_HAS_CXX_17)\n\n/// @brief A function object to call from_node functions.\n/// @note User-defined specialization is available by providing implementation **OUTSIDE** fkyaml namespace.\nstruct from_node_fn {\n    /// @brief Call from_node function suitable for the given T type.\n    /// @tparam BasicNodeType A basic_node template instance type.\n    /// @tparam T A target value type assigned from the basic_node object.\n    /// @param n A basic_node object.\n    /// @param val A target object assigned from the basic_node object.\n    /// @return decltype(from_node(n, std::forward<T>(val))) void by default. User can set it to some other type.\n    template <typename BasicNodeType, typename T>\n    auto operator()(const BasicNodeType& n, T&& val) const\n        noexcept(noexcept(from_node(n, std::forward<T>(val)))) -> decltype(from_node(n, std::forward<T>(val))) {\n        return from_node(n, std::forward<T>(val));\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\nFK_YAML_NAMESPACE_BEGIN\n\n#ifndef FK_YAML_HAS_CXX_17\n// anonymous namespace to hold `from_node` functor.\n// see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html for why it's needed.\nnamespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)\n{\n#endif\n\n/// @brief A global object to represent ADL friendly from_node functor.\n// NOLINTNEXTLINE(misc-definitions-in-headers)\nFK_YAML_INLINE_VAR constexpr const auto& from_node = detail::static_const<detail::from_node_fn>::value;\n\n#ifndef FK_YAML_HAS_CXX_17\n} // namespace\n#endif\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_CONVERSIONS_FROM_NODE_HPP */\n\n// #include <fkYAML/detail/conversions/to_node.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_DETAIL_CONVERSIONS_TO_NODE_HPP\n#define FK_YAML_DETAIL_CONVERSIONS_TO_NODE_HPP\n\n#include <utility>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/exception_safe_allocation.hpp>\n\n// #include <fkYAML/detail/meta/node_traits.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n// #include <fkYAML/detail/meta/stl_supplement.hpp>\n\n// #include <fkYAML/detail/node_attrs.hpp>\n\n// #include <fkYAML/node_type.hpp>\n\n\nFK_YAML_DETAIL_NAMESPACE_BEGIN\n\n///////////////////////////////////\n//   external_node_constructor   //\n///////////////////////////////////\n\n/// @brief The external constructor template for basic_node objects.\n/// @note All the non-specialized instantiations results in compilation error since such instantiations are not\n/// supported.\n/// @warning All the specialization must call n.m_node_value.destroy() first in the construct function to avoid\n/// memory leak.\n/// @tparam node_type The resulting YAML node value type.\ntemplate <typename BasicNodeType>\nstruct external_node_constructor {\n    template <typename... Args>\n    static void sequence(BasicNodeType& n, Args&&... args) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::seq_bit;\n        n.m_node_value.p_sequence = create_object<typename BasicNodeType::sequence_type>(std::forward<Args>(args)...);\n    }\n\n    template <typename... Args>\n    static void mapping(BasicNodeType& n, Args&&... args) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::map_bit;\n        n.m_node_value.p_mapping = create_object<typename BasicNodeType::mapping_type>(std::forward<Args>(args)...);\n    }\n\n    static void null_scalar(BasicNodeType& n, std::nullptr_t) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::null_bit;\n        n.m_node_value.p_mapping = nullptr;\n    }\n\n    static void boolean_scalar(BasicNodeType& n, const typename BasicNodeType::boolean_type b) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::bool_bit;\n        n.m_node_value.boolean = b;\n    }\n\n    static void integer_scalar(BasicNodeType& n, const typename BasicNodeType::integer_type i) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::int_bit;\n        n.m_node_value.integer = i;\n    }\n\n    static void float_scalar(BasicNodeType& n, const typename BasicNodeType::float_number_type f) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::float_bit;\n        n.m_node_value.float_val = f;\n    }\n\n    template <typename... Args>\n    static void string_scalar(BasicNodeType& n, Args&&... args) {\n        destroy(n);\n        n.m_attrs |= node_attr_bits::string_bit;\n        n.m_node_value.p_string = create_object<typename BasicNodeType::string_type>(std::forward<Args>(args)...);\n    }\n\nprivate:\n    static void destroy(BasicNodeType& n) {\n        n.m_node_value.destroy(n.m_attrs & node_attr_mask::value);\n        n.m_attrs &= ~node_attr_mask::value;\n    }\n};\n\n/////////////////\n//   to_node   //\n/////////////////\n\n/// @brief to_node function for BasicNodeType::sequence_type objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A sequence node value type.\n/// @param n A basic_node object.\n/// @param s A sequence node value object.\ntemplate <\n    typename BasicNodeType, typename T,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>,\n            std::is_same<typename BasicNodeType::sequence_type, remove_cvref_t<T>>>::value,\n        int> = 0>\ninline void to_node(BasicNodeType& n, T&& s) noexcept {\n    external_node_constructor<BasicNodeType>::sequence(n, std::forward<T>(s));\n}\n\n/// @brief to_node function for compatible sequence types.\n/// @note This overload is enabled when\n/// * both begin()/end() functions are callable on a `CompatSeqType` object\n/// * CompatSeqType doesn't have `mapped_type` (mapping-like type)\n/// * BasicNodeType::string_type cannot be constructed from a CompatSeqType object (string-like type)\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatSeqType A container type.\n/// @param n A basic_node object.\n/// @param s A container object.\ntemplate <\n    typename BasicNodeType, typename CompatSeqType,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>,\n            negation<std::is_same<typename BasicNodeType::sequence_type, remove_cvref_t<CompatSeqType>>>,\n            negation<is_basic_node<remove_cvref_t<CompatSeqType>>>, detect::has_begin_end<CompatSeqType>,\n            negation<conjunction<detect::has_key_type<CompatSeqType>, detect::has_mapped_type<CompatSeqType>>>,\n            negation<std::is_constructible<typename BasicNodeType::string_type, CompatSeqType>>>::value,\n        int> = 0>\n// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)\ninline void to_node(BasicNodeType& n, CompatSeqType&& s) {\n    using std::begin;\n    using std::end;\n    external_node_constructor<BasicNodeType>::sequence(n, begin(s), end(s));\n}\n\n/// @brief to_node function for std::pair objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T The first type of std::pair.\n/// @tparam U The second type of std::pair.\n/// @param n A basic_node object.\n/// @param p A std::pair object.\ntemplate <typename BasicNodeType, typename T, typename U>\ninline void to_node(BasicNodeType& n, const std::pair<T, U>& p) {\n    n = {p.first, p.second};\n}\n\n/// @brief concrete implementation of to_node function for std::tuple objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam ...Types The value types of std::tuple.\n/// @tparam ...Idx Index sequence values for std::tuple value types.\n/// @param n A basic_node object.\n/// @param t A std::tuple object.\n/// @param _ An index sequence. (unused)\ntemplate <typename BasicNodeType, typename... Types, std::size_t... Idx>\ninline void to_node_tuple_impl(BasicNodeType& n, const std::tuple<Types...>& t, index_sequence<Idx...> /*unused*/) {\n    n = {std::get<Idx>(t)...};\n}\n\n/// @brief to_node function for std::tuple objects with no value types.\n/// @note This implementation is needed since calling `to_node_tuple_impl()` with an empty tuple creates a null node.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @param n A basic_node object.\n/// @param _ A std::tuple object. (unused)\ntemplate <typename BasicNodeType>\ninline void to_node(BasicNodeType& n, const std::tuple<>& /*unused*/) {\n    n = BasicNodeType::sequence();\n}\n\n/// @brief to_node function for std::tuple objects with at least one value type.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam ...FirstType The first value types of std::tuple.\n/// @tparam ...RestTypes The rest value types of std::tuple. (maybe empty)\n/// @param n A basic_node object.\n/// @param t A std::tuple object.\ntemplate <typename BasicNodeType, typename FirstType, typename... RestTypes>\ninline void to_node(BasicNodeType& n, const std::tuple<FirstType, RestTypes...>& t) {\n    to_node_tuple_impl(n, t, index_sequence_for<FirstType, RestTypes...> {});\n}\n\n/// @brief to_node function for BasicNodeType::mapping_type objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A mapping node value type.\n/// @param n A basic_node object.\n/// @param m A mapping node value object.\ntemplate <\n    typename BasicNodeType, typename T,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>, std::is_same<typename BasicNodeType::mapping_type, remove_cvref_t<T>>>::value,\n        int> = 0>\ninline void to_node(BasicNodeType& n, T&& m) noexcept {\n    external_node_constructor<BasicNodeType>::mapping(n, std::forward<T>(m));\n}\n\n/// @brief to_node function for compatible mapping types.\n/// @note This overload is enabled when\n/// * both begin()/end() functions are callable on a `CompatMapType` object\n/// * CompatMapType has both `key_type` and `mapped_type`\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam CompatMapType A container type.\n/// @param n A basic_node object.\n/// @param m A container object.\ntemplate <\n    typename BasicNodeType, typename CompatMapType,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>, negation<is_basic_node<remove_cvref_t<CompatMapType>>>,\n            negation<std::is_same<typename BasicNodeType::mapping_type, remove_cvref_t<CompatMapType>>>,\n            detect::has_begin_end<CompatMapType>, detect::has_key_type<CompatMapType>,\n            detect::has_mapped_type<CompatMapType>>::value,\n        int> = 0>\ninline void to_node(BasicNodeType& n, CompatMapType&& m) {\n    external_node_constructor<BasicNodeType>::mapping(n);\n    auto& map = n.template get_value_ref<typename BasicNodeType::mapping_type&>();\n    for (const auto& pair : std::forward<CompatMapType>(m)) {\n        map.emplace(pair.first, pair.second);\n    }\n}\n\n/// @brief to_node function for null objects.\n/// @tparam BasicNodeType A mapping node value type.\n/// @tparam NullType This must be std::nullptr_t type\ntemplate <typename BasicNodeType, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline void to_node(BasicNodeType& n, std::nullptr_t /*unused*/) {\n    external_node_constructor<BasicNodeType>::null_scalar(n, nullptr);\n}\n\n/// @brief to_node function for BasicNodeType::boolean_type objects.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A boolean scalar node value type.\n/// @param n A basic_node object.\n/// @param b A boolean scalar node value object.\ntemplate <typename BasicNodeType, enable_if_t<is_basic_node<BasicNodeType>::value, int> = 0>\ninline void to_node(BasicNodeType& n, typename BasicNodeType::boolean_type b) noexcept {\n    external_node_constructor<BasicNodeType>::boolean_scalar(n, b);\n}\n\n/// @brief to_node function for integers.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T An integer type.\n/// @param n A basic_node object.\n/// @param i An integer object.\ntemplate <\n    typename BasicNodeType, typename T,\n    enable_if_t<conjunction<is_basic_node<BasicNodeType>, is_non_bool_integral<T>>::value, int> = 0>\ninline void to_node(BasicNodeType& n, T i) noexcept {\n    external_node_constructor<BasicNodeType>::integer_scalar(n, i);\n}\n\n/// @brief to_node function for floating point numbers.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A floating point number type.\n/// @param n A basic_node object.\n/// @param f A floating point number object.\ntemplate <\n    typename BasicNodeType, typename T,\n    enable_if_t<conjunction<is_basic_node<BasicNodeType>, std::is_floating_point<T>>::value, int> = 0>\ninline void to_node(BasicNodeType& n, T f) noexcept {\n    external_node_constructor<BasicNodeType>::float_scalar(n, f);\n}\n\n/// @brief to_node function for compatible strings.\n/// @tparam BasicNodeType A basic_node template instance type.\n/// @tparam T A compatible string type.\n/// @param n A basic_node object.\n/// @param s A compatible string object.\ntemplate <\n    typename BasicNodeType, typename T,\n    enable_if_t<\n        conjunction<\n            is_basic_node<BasicNodeType>, negation<is_null_pointer<T>>,\n            std::is_constructible<typename BasicNodeType::string_type, T>>::value,\n        int> = 0>\ninline void to_node(BasicNodeType& n, T&& s) {\n    external_node_constructor<BasicNodeType>::string_scalar(n, std::forward<T>(s));\n}\n\n/// @brief A function object to call to_node functions.\n/// @note User-defined specialization is available by providing implementation **OUTSIDE** fkyaml namespace.\nstruct to_node_fn {\n    /// @brief Call to_node function suitable for the given T type.\n    /// @tparam BasicNodeType A basic_node template instance type.\n    /// @tparam T A target value type assigned to the basic_node object.\n    /// @param n A basic_node object.\n    /// @param val A target object assigned to the basic_node object.\n    /// @return decltype(to_node(n, std::forward<T>(val))) void by default. User can set it to some other type.\n    template <typename BasicNodeType, typename T>\n    auto operator()(BasicNodeType& n, T&& val) const\n        noexcept(noexcept(to_node(n, std::forward<T>(val)))) -> decltype(to_node(n, std::forward<T>(val))) {\n        return to_node(n, std::forward<T>(val));\n    }\n};\n\nFK_YAML_DETAIL_NAMESPACE_END\n\nFK_YAML_NAMESPACE_BEGIN\n\n#ifndef FK_YAML_HAS_CXX_17\n// anonymous namespace to hold `to_node` functor.\n// see http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html for why it's needed.\nnamespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)\n{\n#endif\n\n/// @brief A global object to represent ADL friendly to_node functor.\n// NOLINTNEXTLINE(misc-definitions-in-headers)\nFK_YAML_INLINE_VAR constexpr const auto& to_node = detail::static_const<detail::to_node_fn>::value;\n\n#ifndef FK_YAML_HAS_CXX_17\n} // namespace\n#endif\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_DETAIL_CONVERSIONS_TO_NODE_HPP */\n\n\nFK_YAML_NAMESPACE_BEGIN\n\n/// @brief An ADL friendly converter between basic_node objects and native data objects.\n/// @tparam ValueType A default target data type.\n/// @sa https://fktn-k.github.io/fkYAML/api/node_value_converter/\ntemplate <typename ValueType, typename>\nclass node_value_converter {\npublic:\n    /// @brief Convert a YAML node value into compatible native data.\n    /// @tparam BasicNodeType A basic_node template instance type.\n    /// @tparam TargetType A native data type for conversion.\n    /// @param n A basic_node object.\n    /// @param val A native data object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/node_value_converter/from_node/\n    template <typename BasicNodeType, typename TargetType = ValueType>\n    static auto from_node(BasicNodeType&& n, TargetType& val) noexcept(\n        noexcept(::fkyaml::from_node(std::forward<BasicNodeType>(n), val)))\n        -> decltype(::fkyaml::from_node(std::forward<BasicNodeType>(n), val), void()) {\n        ::fkyaml::from_node(std::forward<BasicNodeType>(n), val);\n    }\n\n    /// @brief Convert compatible native data into a YAML node.\n    /// @tparam BasicNodeType A basic_node template instance type.\n    /// @tparam TargetType A native data type for conversion.\n    /// @param n A basic_node object.\n    /// @param val A native data object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/node_value_converter/to_node/\n    template <typename BasicNodeType, typename TargetType = ValueType>\n    static auto to_node(BasicNodeType& n, TargetType&& val) noexcept(noexcept(::fkyaml::to_node(\n        n, std::forward<TargetType>(val)))) -> decltype(::fkyaml::to_node(n, std::forward<TargetType>(val))) {\n        ::fkyaml::to_node(n, std::forward<TargetType>(val));\n    }\n};\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_NODE_VALUE_CONVERTER_HPP */\n\n// #include <fkYAML/ordered_map.hpp>\n//  _______   __ __   __  _____   __  __  __\n// |   __| |_/  |  \\_/  |/  _  \\ /  \\/  \\|  |     fkYAML: A C++ header-only YAML library\n// |   __|  _  < \\_   _/|  ___  |    _   |  |___  version 0.4.2\n// |__|  |_| \\__|  |_|  |_|   |_|___||___|______| https://github.com/fktn-k/fkYAML\n//\n// SPDX-FileCopyrightText: 2023-2025 Kensuke Fukutani <fktn.dev@gmail.com>\n// SPDX-License-Identifier: MIT\n\n#ifndef FK_YAML_ORDERED_MAP_HPP\n#define FK_YAML_ORDERED_MAP_HPP\n\n#include <functional>\n#include <initializer_list>\n#include <memory>\n#include <utility>\n#include <vector>\n\n// #include <fkYAML/detail/macros/define_macros.hpp>\n\n// #include <fkYAML/detail/meta/type_traits.hpp>\n\n// #include <fkYAML/exception.hpp>\n\n\nFK_YAML_NAMESPACE_BEGIN\n\n/// @brief A minimal map-like container which preserves insertion order.\n/// @tparam Key A type for keys.\n/// @tparam Value A type for values.\n/// @tparam IgnoredCompare A placeholder for key comparison. This will be ignored.\n/// @tparam Allocator A class for allocators.\n/// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\ntemplate <\n    typename Key, typename Value, typename IgnoredCompare = std::less<Key>,\n    typename Allocator = std::allocator<std::pair<const Key, Value>>>\nclass ordered_map : public std::vector<std::pair<const Key, Value>, Allocator> {\npublic:\n    /// @brief A type for keys.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using key_type = Key;\n\n    /// @brief A type for values.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using mapped_type = Value;\n\n    /// @brief A type for internal key-value containers.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using Container = std::vector<std::pair<const Key, Value>, Allocator>;\n\n    /// @brief A type for key-value pairs.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using value_type = typename Container::value_type;\n\n    /// @brief A type for non-const iterators.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using iterator = typename Container::iterator;\n\n    /// @brief A type for const iterators.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using const_iterator = typename Container::const_iterator;\n\n    /// @brief A type for size parameters used in this class.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using size_type = typename Container::size_type;\n\n    /// @brief A type for comparison between keys.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/\n    using key_compare = std::equal_to<Key>;\n\npublic:\n    /// @brief Construct a new ordered_map object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/constructor/\n    ordered_map() noexcept(noexcept(Container()))\n        : Container() {\n    }\n\n    /// @brief Construct a new ordered_map object with an initializer list.\n    /// @param init An initializer list to construct the inner container object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/constructor/\n    ordered_map(std::initializer_list<value_type> init)\n        : Container {init} {\n    }\n\npublic:\n    /// @brief A subscript operator for ordered_map objects.\n    /// @tparam KeyType A type for the input key.\n    /// @param key A key to the target value.\n    /// @return mapped_type& Reference to a mapped_type object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/operator[]/\n    template <\n        typename KeyType,\n        detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    mapped_type& operator[](KeyType&& key) noexcept {\n        return emplace(std::forward<KeyType>(key), mapped_type()).first->second;\n    }\n\npublic:\n    /// @brief Emplace a new key-value pair if the new key does not exist.\n    /// @tparam KeyType A type for the input key.\n    /// @param key A key to be emplaced to this ordered_map object.\n    /// @param value A value to be emplaced to this ordered_map object.\n    /// @return std::pair<iterator, bool> A result of emplacement of the new key-value pair.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/emplace/\n    template <\n        typename KeyType,\n        detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    std::pair<iterator, bool> emplace(KeyType&& key, const mapped_type& value) noexcept {\n        for (auto itr = this->begin(); itr != this->end(); ++itr) {\n            if (m_compare(itr->first, key)) {\n                return {itr, false};\n            }\n        }\n        this->emplace_back(std::forward<KeyType>(key), value);\n        return {std::prev(this->end()), true};\n    }\n\n    /// @brief Find a value associated to the given key. Throws an exception if the search fails.\n    /// @tparam KeyType A type for the input key.\n    /// @param key A key to find a value with.\n    /// @return mapped_type& The value associated to the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/at/\n    template <\n        typename KeyType,\n        detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    mapped_type& at(KeyType&& key) { // NOLINT(cppcoreguidelines-missing-std-forward)\n        for (auto itr = this->begin(); itr != this->end(); ++itr) {\n            if (m_compare(itr->first, key)) {\n                return itr->second;\n            }\n        }\n        throw fkyaml::exception(\"key not found.\");\n    }\n\n    /// @brief Find a value associated to the given key. Throws an exception if the search fails.\n    /// @tparam KeyType A type for the input key.\n    /// @param key A key to find a value with.\n    /// @return const mapped_type& The value associated to the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/at/\n    template <\n        typename KeyType,\n        detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    const mapped_type& at(KeyType&& key) const { // NOLINT(cppcoreguidelines-missing-std-forward)\n        for (auto itr = this->begin(); itr != this->end(); ++itr) {\n            if (m_compare(itr->first, key)) {\n                return itr->second;\n            }\n        }\n        throw fkyaml::exception(\"key not found.\");\n    }\n\n    /// @brief Find a value with the given key.\n    /// @tparam KeyType A type for the input key.\n    /// @param key A key to find a value with.\n    /// @return iterator The iterator for the found value, or the result of end().\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/find/\n    template <\n        typename KeyType,\n        detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    iterator find(KeyType&& key) noexcept { // NOLINT(cppcoreguidelines-missing-std-forward)\n        for (auto itr = this->begin(); itr != this->end(); ++itr) {\n            if (m_compare(itr->first, key)) {\n                return itr;\n            }\n        }\n        return this->end();\n    }\n\n    /// @brief Find a value with the given key.\n    /// @tparam KeyType A type for the input key.\n    /// @param key A key to find a value with.\n    /// @return const_iterator The constant iterator for the found value, or the result of end().\n    /// @sa https://fktn-k.github.io/fkYAML/api/ordered_map/find/\n    template <\n        typename KeyType,\n        detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    const_iterator find(KeyType&& key) const noexcept { // NOLINT(cppcoreguidelines-missing-std-forward)\n        for (auto itr = this->begin(); itr != this->end(); ++itr) {\n            if (m_compare(itr->first, key)) {\n                return itr;\n            }\n        }\n        return this->end();\n    }\n\nprivate:\n    /// The object for comparing keys.\n    key_compare m_compare {};\n};\n\nFK_YAML_NAMESPACE_END\n\n#endif /* FK_YAML_ORDERED_MAP_HPP */\n\n\nFK_YAML_NAMESPACE_BEGIN\n\n/// @brief A class to store value of YAML nodes.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/\ntemplate <\n    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,\n    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,\n    template <typename, typename = void> class ConverterType>\nclass basic_node {\npublic:\n    /// @brief A type for sequence basic_node values.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence_type/\n    using sequence_type = SequenceType<basic_node, std::allocator<basic_node>>;\n\n    /// @brief A type for mapping basic_node values.\n    /// @note std::unordered_map is not supported since it does not allow incomplete types.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping_type/\n    using mapping_type = MappingType<basic_node, basic_node>;\n\n    /// @brief A type for boolean basic_node values.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/boolean_type/\n    using boolean_type = BooleanType;\n\n    /// @brief A type for integer basic_node values.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/integer_type/\n    using integer_type = IntegerType;\n\n    /// @brief A type for float number basic_node values.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/float_number_type/\n    using float_number_type = FloatNumberType;\n\n    /// @brief A type for string basic_node values.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/string_type/\n    using string_type = StringType;\n\n    /// @brief A type of elements in a basic_node container.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using value_type = basic_node;\n\n    /// @brief A type of reference to a basic_node element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using reference = value_type&;\n\n    /// @brief A type of constant reference to a basic_node element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using const_reference = const value_type&;\n\n    /// @brief A type of a pointer to a basic_node element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using pointer = value_type*;\n\n    /// @brief A type of a constant pointer to a basic_node element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using const_pointer = const value_type*;\n\n    /// @brief A type to represent basic_node container sizes.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using size_type = std::size_t;\n\n    /// @brief A type to represent differences between basic_node iterators.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/#container-types\n    using difference_type = std::ptrdiff_t;\n\n    /// @brief A type for iterators of basic_node containers.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/iterator/\n    using iterator = fkyaml::detail::iterator<basic_node>;\n\n    /// @brief A type for constant iterators of basic_node containers.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/iterator/\n    using const_iterator = fkyaml::detail::iterator<const basic_node>;\n\n    /// @brief A type for reverse iterators of basic_node containers.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/reverse_iterator/\n    using reverse_iterator = fkyaml::detail::reverse_iterator<iterator>;\n\n    /// @brief A type for constant reverse iterators of basic_node containers.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/reverse_iterator/\n    using const_reverse_iterator = fkyaml::detail::reverse_iterator<const_iterator>;\n\n    /// @brief A helper alias to determine converter type for the given target native data type.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/value_converter_type/\n    template <typename T, typename SFINAE>\n    using value_converter_type = ConverterType<T, SFINAE>;\n\n    /// @brief Definition of node value types.\n    /// @deprecated Use fkyaml::node_type enum class. (since 0.3.12)\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/node_t/\n    using node_t = detail::node_t;\n\n    /// @brief Definition of YAML version types.\n    /// @deprecated Use fkyaml::yaml_version_type enum class. (since 0.3.12)\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/yaml_version_t/\n    using yaml_version_t = detail::yaml_version_t;\n\n    /// @brief A type for mapping range objects for the map_items() function.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_range/\n    using map_range = fkyaml::detail::map_range_proxy<basic_node>;\n\n    /// @brief A type for constant mapping range objects for the map_items() function.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_range/\n    using const_map_range = fkyaml::detail::map_range_proxy<const basic_node>;\n\nprivate:\n    template <typename BasicNodeType>\n    friend struct fkyaml::detail::external_node_constructor;\n\n    template <typename BasicNodeType>\n    friend class fkyaml::detail::basic_deserializer;\n\n    template <typename BasicNodeType>\n    friend class fkyaml::detail::basic_serializer;\n\n    /// @brief A type for YAML docs deserializers.\n    using deserializer_type = detail::basic_deserializer<basic_node>;\n    /// @brief A type for YAML docs serializers.\n    using serializer_type = detail::basic_serializer<basic_node>;\n    /// @brief A helper type alias for std::initializer_list.\n    using initializer_list_t = std::initializer_list<detail::node_ref_storage<basic_node>>;\n\n    /// @brief The actual storage for a YAML node value of the @ref basic_node class.\n    /// @details This union combines the different storage types for the YAML value types defined in @ref node_t.\n    /// @note Container types are stored as pointers so that the size of this union will not exceed 64 bits by\n    /// default.\n    union node_value {\n        /// @brief Constructs a new basic_node Value object for null types.\n        node_value() = default;\n\n        /// @brief Constructs a new basic_node value object with a node type. The default value for the specified\n        /// type will be assigned.\n        /// @param[in] type A node type.\n        explicit node_value(detail::node_attr_t value_type_bit) {\n            switch (value_type_bit) {\n            case detail::node_attr_bits::seq_bit:\n                p_sequence = detail::create_object<sequence_type>();\n                break;\n            case detail::node_attr_bits::map_bit:\n                p_mapping = detail::create_object<mapping_type>();\n                break;\n            case detail::node_attr_bits::null_bit:\n                p_mapping = nullptr;\n                break;\n            case detail::node_attr_bits::bool_bit:\n                boolean = static_cast<boolean_type>(false);\n                break;\n            case detail::node_attr_bits::int_bit:\n                integer = static_cast<integer_type>(0);\n                break;\n            case detail::node_attr_bits::float_bit:\n                float_val = static_cast<float_number_type>(0.0);\n                break;\n            case detail::node_attr_bits::string_bit:\n                p_string = detail::create_object<string_type>();\n                break;\n            default:                   // LCOV_EXCL_LINE\n                detail::unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n\n        /// @brief Destroys the existing Node value. This process is recursive if the specified node type is for\n        /// containers.\n        /// @param[in] type A Node type to determine the value to be destroyed.\n        void destroy(detail::node_attr_t value_type_bit) {\n            switch (value_type_bit) {\n            case detail::node_attr_bits::seq_bit:\n                p_sequence->clear();\n                detail::destroy_object<sequence_type>(p_sequence);\n                p_sequence = nullptr;\n                break;\n            case detail::node_attr_bits::map_bit:\n                p_mapping->clear();\n                detail::destroy_object<mapping_type>(p_mapping);\n                p_mapping = nullptr;\n                break;\n            case detail::node_attr_bits::string_bit:\n                detail::destroy_object<string_type>(p_string);\n                p_string = nullptr;\n                break;\n            default:\n                break;\n            }\n        }\n\n        /// A pointer to the value of sequence type.\n        sequence_type* p_sequence;\n        /// A pointer to the value of mapping type. This pointer is also used when node type is null.\n        mapping_type* p_mapping {nullptr};\n        /// A value of boolean type.\n        boolean_type boolean;\n        /// A value of integer type.\n        integer_type integer;\n        /// A value of float number type.\n        float_number_type float_val;\n        /// A pointer to the value of string type.\n        string_type* p_string;\n    };\n\npublic:\n    /// @brief Constructs a new basic_node object of null type.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    basic_node() = default;\n\n    /// @brief Constructs a new basic_node object with a specified type.\n    /// @param[in] type A YAML node type.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    FK_YAML_DEPRECATED(\"Since 0.3.12; Use explicit basic_node(const node_type)\")\n    explicit basic_node(const node_t type)\n        : basic_node(detail::convert_to_node_type(type)) {\n    }\n\n    explicit basic_node(const node_type type)\n        : m_attrs(detail::node_attr_bits::from_node_type(type)),\n          m_node_value(m_attrs & detail::node_attr_mask::value) {\n    }\n\n    /// @brief Copy constructor of the basic_node class.\n    /// @param[in] rhs A basic_node object to be copied with.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    basic_node(const basic_node& rhs)\n        : m_attrs(rhs.m_attrs),\n          mp_meta(rhs.mp_meta),\n          m_prop(rhs.m_prop) {\n        if FK_YAML_LIKELY (!has_anchor_name()) {\n            switch (m_attrs & detail::node_attr_mask::value) {\n            case detail::node_attr_bits::seq_bit:\n                m_node_value.p_sequence = detail::create_object<sequence_type>(*(rhs.m_node_value.p_sequence));\n                break;\n            case detail::node_attr_bits::map_bit:\n                m_node_value.p_mapping = detail::create_object<mapping_type>(*(rhs.m_node_value.p_mapping));\n                break;\n            case detail::node_attr_bits::null_bit:\n                m_node_value.p_mapping = nullptr;\n                break;\n            case detail::node_attr_bits::bool_bit:\n                m_node_value.boolean = rhs.m_node_value.boolean;\n                break;\n            case detail::node_attr_bits::int_bit:\n                m_node_value.integer = rhs.m_node_value.integer;\n                break;\n            case detail::node_attr_bits::float_bit:\n                m_node_value.float_val = rhs.m_node_value.float_val;\n                break;\n            case detail::node_attr_bits::string_bit:\n                m_node_value.p_string = detail::create_object<string_type>(*(rhs.m_node_value.p_string));\n                break;\n            default:                   // LCOV_EXCL_LINE\n                detail::unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n    }\n\n    /// @brief Move constructor of the basic_node class.\n    /// @param[in] rhs A basic_node object to be moved from.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    basic_node(basic_node&& rhs) noexcept\n        : m_attrs(rhs.m_attrs),\n          mp_meta(std::move(rhs.mp_meta)),\n          m_prop(std::move(rhs.m_prop)) {\n        if FK_YAML_LIKELY (!has_anchor_name()) {\n            switch (m_attrs & detail::node_attr_mask::value) {\n            case detail::node_attr_bits::seq_bit:\n                FK_YAML_ASSERT(rhs.m_node_value.p_sequence != nullptr);\n                m_node_value.p_sequence = rhs.m_node_value.p_sequence;\n                rhs.m_node_value.p_sequence = nullptr;\n                break;\n            case detail::node_attr_bits::map_bit:\n                FK_YAML_ASSERT(rhs.m_node_value.p_mapping != nullptr);\n                m_node_value.p_mapping = rhs.m_node_value.p_mapping;\n                rhs.m_node_value.p_mapping = nullptr;\n                break;\n            case detail::node_attr_bits::null_bit:\n                FK_YAML_ASSERT(rhs.m_node_value.p_mapping == nullptr);\n                m_node_value.p_mapping = rhs.m_node_value.p_mapping;\n                break;\n            case detail::node_attr_bits::bool_bit:\n                m_node_value.boolean = rhs.m_node_value.boolean;\n                rhs.m_node_value.boolean = static_cast<boolean_type>(false);\n                break;\n            case detail::node_attr_bits::int_bit:\n                m_node_value.integer = rhs.m_node_value.integer;\n                rhs.m_node_value.integer = static_cast<integer_type>(0);\n                break;\n            case detail::node_attr_bits::float_bit:\n                m_node_value.float_val = rhs.m_node_value.float_val;\n                rhs.m_node_value.float_val = static_cast<float_number_type>(0.0);\n                break;\n            case detail::node_attr_bits::string_bit:\n                FK_YAML_ASSERT(rhs.m_node_value.p_string != nullptr);\n                m_node_value.p_string = rhs.m_node_value.p_string;\n                rhs.m_node_value.p_string = nullptr;\n                break;\n            default:                   // LCOV_EXCL_LINE\n                detail::unreachable(); // LCOV_EXCL_LINE\n            }\n        }\n\n        rhs.m_attrs = detail::node_attr_bits::default_bits;\n        rhs.m_node_value.p_mapping = nullptr;\n    }\n\n    /// @brief Construct a new basic_node object from a value of compatible types.\n    /// @tparam CompatibleType Type of native data which is compatible with node values.\n    /// @tparam U Type of compatible native data without cv-qualifiers and reference.\n    /// @param[in] val The value of a compatible type.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    template <\n        typename CompatibleType, typename U = detail::remove_cvref_t<CompatibleType>,\n        detail::enable_if_t<\n            detail::conjunction<\n                detail::negation<detail::is_basic_node<U>>,\n                detail::disjunction<detail::is_node_compatible_type<basic_node, U>>>::value,\n            int> = 0>\n    basic_node(CompatibleType&& val) noexcept(\n        noexcept(ConverterType<U, void>::to_node(std::declval<basic_node&>(), std::declval<CompatibleType>()))) {\n        ConverterType<U, void>::to_node(*this, std::forward<CompatibleType>(val));\n    }\n\n    /// @brief Construct a new basic node object with a node_ref_storage object.\n    /// @tparam NodeRefStorageType Type of basic_node with reference.\n    /// @param[in] node_ref_storage A node_ref_storage template class object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    template <\n        typename NodeRefStorageType,\n        detail::enable_if_t<detail::is_node_ref_storage<NodeRefStorageType>::value, int> = 0>\n    basic_node(const NodeRefStorageType& node_ref_storage) noexcept\n        : basic_node(node_ref_storage.release()) {\n    }\n\n    /// @brief Construct a new basic node object with std::initializer_list.\n    /// @param[in] init A initializer list of basic_node objects.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/constructor/\n    basic_node(initializer_list_t init) {\n        bool is_mapping =\n            std::all_of(init.begin(), init.end(), [](const detail::node_ref_storage<basic_node>& node_ref) {\n                return node_ref->is_sequence() && node_ref->size() == 2;\n            });\n\n        if (is_mapping) {\n            m_attrs = detail::node_attr_bits::map_bit;\n            m_node_value.p_mapping = detail::create_object<mapping_type>();\n\n            for (auto& elem_ref : init) {\n                auto elem = elem_ref.release();\n                m_node_value.p_mapping->emplace(\n                    std::move((*(elem.m_node_value.p_sequence))[0]), std::move((*(elem.m_node_value.p_sequence))[1]));\n            }\n        }\n        else {\n            m_attrs = detail::node_attr_bits::seq_bit;\n            m_node_value.p_sequence = detail::create_object<sequence_type>();\n            m_node_value.p_sequence->reserve(std::distance(init.begin(), init.end()));\n            for (auto& elem_ref : init) {\n                m_node_value.p_sequence->emplace_back(std::move(elem_ref.release()));\n            }\n        }\n    }\n\n    /// @brief Destroy the basic_node object and its value storage.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/destructor/\n    ~basic_node() noexcept // NOLINT(bugprone-exception-escape)\n    {\n        if (m_attrs & detail::node_attr_mask::anchoring) {\n            if (m_attrs & detail::node_attr_bits::anchor_bit) {\n                auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n                std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n                itr->second.m_node_value.destroy(itr->second.m_attrs & detail::node_attr_mask::value);\n                itr->second.m_attrs = detail::node_attr_bits::default_bits;\n                itr->second.mp_meta.reset();\n            }\n        }\n        else if ((m_attrs & detail::node_attr_bits::null_bit) == 0) {\n            m_node_value.destroy(m_attrs & detail::node_attr_mask::value);\n        }\n\n        m_attrs = detail::node_attr_bits::default_bits;\n        mp_meta.reset();\n    }\n\npublic:\n    /// @brief Deserialize the first YAML document in the input into a basic_node object.\n    /// @tparam InputType Type of a compatible input.\n    /// @param[in] input An input source in the YAML format.\n    /// @return The resulting basic_node object deserialized from the input source.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize/\n    template <typename InputType>\n    static basic_node deserialize(InputType&& input) {\n        return deserializer_type().deserialize(detail::input_adapter(std::forward<InputType>(input)));\n    }\n\n    /// @brief Deserialize the first YAML document in the input ranged by the iterators into a basic_node object.\n    /// @tparam ItrType Type of a compatible iterator.\n    /// @param[in] begin An iterator to the first element of an input sequence.\n    /// @param[in] end An iterator to the past-the-last element of an input sequence.\n    /// @return The resulting basic_node object deserialized from the pair of iterators.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize/\n    template <typename ItrType>\n    static basic_node deserialize(ItrType begin, ItrType end) {\n        return deserializer_type().deserialize(\n            detail::input_adapter(std::forward<ItrType>(begin), std::forward<ItrType>(end)));\n    }\n\n    /// @brief Deserialize all YAML documents in the input into basic_node objects.\n    /// @tparam InputType Type of a compatible input.\n    /// @param[in] input An input source in the YAML format.\n    /// @return The resulting basic_node objects deserialized from the input.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize_docs/\n    template <typename InputType>\n    static std::vector<basic_node> deserialize_docs(InputType&& input) {\n        return deserializer_type().deserialize_docs(detail::input_adapter(std::forward<InputType>(input)));\n    }\n\n    /// @brief Deserialize all YAML documents in the input ranged by the iterators into basic_node objects.\n    /// @tparam ItrType Type of a compatible iterator.\n    /// @param[in] begin An iterator to the first element of an input sequence.\n    /// @param[in] end An iterator to the past-the-last element of an input sequence.\n    /// @return The resulting basic_node objects deserialized from the pair of iterators.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/deserialize_docs/\n    template <typename ItrType>\n    static std::vector<basic_node> deserialize_docs(ItrType&& begin, ItrType&& end) {\n        return deserializer_type().deserialize_docs(\n            detail::input_adapter(std::forward<ItrType>(begin), std::forward<ItrType>(end)));\n    }\n\n    /// @brief Serialize a basic_node object into a string.\n    /// @param[in] node A basic_node object to be serialized.\n    /// @return The resulting string object from the serialization of the given node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/serialize/\n    static std::string serialize(const basic_node& node) {\n        return serializer_type().serialize(node);\n    }\n\n    /// @brief Serialize basic_node objects into a string.\n    /// @param docs basic_node objects to be serialized.\n    /// @return The resulting string object from the serialization of the given nodes.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/serialize_docs/\n    static std::string serialize_docs(const std::vector<basic_node>& docs) {\n        return serializer_type().serialize_docs(docs);\n    }\n\n    /// @brief A factory method for sequence basic_node objects without sequence_type objects.\n    /// @return A YAML sequence node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/\n    static basic_node sequence() {\n        basic_node node;\n        node.m_attrs = detail::node_attr_bits::seq_bit;\n        node.m_node_value.p_sequence = detail::create_object<sequence_type>();\n        return node;\n    } // LCOV_EXCL_LINE\n\n    /// @brief A factory method for sequence basic_node objects with lvalue sequence_type objects.\n    /// @param[in] seq A lvalue sequence node value.\n    /// @return A YAML sequence node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/\n    static basic_node sequence(const sequence_type& seq) {\n        basic_node node;\n        node.m_attrs = detail::node_attr_bits::seq_bit;\n        node.m_node_value.p_sequence = detail::create_object<sequence_type>(seq);\n        return node;\n    } // LCOV_EXCL_LINE\n\n    /// @brief A factory method for sequence basic_node objects with rvalue sequence_type objects.\n    /// @param[in] seq A rvalue sequence node value.\n    /// @return A YAML sequence node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/sequence/\n    static basic_node sequence(sequence_type&& seq) {\n        basic_node node;\n        node.m_attrs = detail::node_attr_bits::seq_bit;\n        node.m_node_value.p_sequence = detail::create_object<sequence_type>(std::move(seq));\n        return node;\n    } // LCOV_EXCL_LINE\n\n    /// @brief A factory method for mapping basic_node objects without mapping_type objects.\n    /// @return A YAML mapping node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/\n    static basic_node mapping() {\n        basic_node node;\n        node.m_attrs = detail::node_attr_bits::map_bit;\n        node.m_node_value.p_mapping = detail::create_object<mapping_type>();\n        return node;\n    } // LCOV_EXCL_LINE\n\n    /// @brief A factory method for mapping basic_node objects with lvalue mapping_type objects.\n    /// @param[in] map A lvalue mapping node value.\n    /// @return A YAML mapping node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/\n    static basic_node mapping(const mapping_type& map) {\n        basic_node node;\n        node.m_attrs = detail::node_attr_bits::map_bit;\n        node.m_node_value.p_mapping = detail::create_object<mapping_type>(map);\n        return node;\n    } // LCOV_EXCL_LINE\n\n    /// @brief A factory method for mapping basic_node objects with rvalue mapping_type objects.\n    /// @param[in] map A rvalue mapping node value.\n    /// @return A YAML mapping node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/mapping/\n    static basic_node mapping(mapping_type&& map) {\n        basic_node node;\n        node.m_attrs = detail::node_attr_bits::map_bit;\n        node.m_node_value.p_mapping = detail::create_object<mapping_type>(std::move(map));\n        return node;\n    } // LCOV_EXCL_LINE\n\n    /// @brief A factory method for alias basic_node objects referencing the given anchor basic_node object.\n    /// @note The given anchor basic_node must have a non-empty anchor name.\n    /// @param[in] anchor_node A basic_node object with an anchor name.\n    /// @return An alias YAML node created from the given anchor node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/alias_of/\n    static basic_node alias_of(const basic_node& anchor_node) {\n        constexpr detail::node_attr_t anchor_bit = detail::node_attr_bits::anchor_bit;\n\n        if FK_YAML_UNLIKELY (!anchor_node.has_anchor_name() || !(anchor_node.m_attrs & anchor_bit)) {\n            throw fkyaml::exception(\"Cannot create an alias without anchor name.\");\n        }\n\n        basic_node node = anchor_node;\n        node.m_attrs &= ~detail::node_attr_mask::anchoring;\n        node.m_attrs |= detail::node_attr_bits::alias_bit;\n        return node;\n    } // LCOV_EXCL_LINE\n\npublic:\n    /// @brief A copy assignment operator of the basic_node class.\n    /// @param[in] rhs A lvalue basic_node object to be copied with.\n    /// @return Reference to this basic_node object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator=/\n    basic_node& operator=(const basic_node& rhs) noexcept {\n        basic_node(rhs).swap(*this);\n        return *this;\n    }\n\n    /// @brief A move assignment operator of the basic_node class.\n    /// @param[in] rhs A rvalue basic_node object to be moved from.\n    /// @return Reference to this basic_node object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator=/\n    basic_node& operator=(basic_node&& rhs) noexcept {\n        basic_node(std::move(rhs)).swap(*this);\n        return *this;\n    }\n\n    /// @brief A subscript operator of the basic_node class with a key of a compatible type with basic_node.\n    /// @tparam KeyType A key type compatible with basic_node\n    /// @param key A key to the target value in a sequence/mapping node.\n    /// @return The value associated with the given key, or a default basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/\n    template <\n        typename KeyType, detail::enable_if_t<\n                              detail::conjunction<\n                                  detail::negation<detail::is_basic_node<KeyType>>,\n                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,\n                              int> = 0>\n    basic_node& operator[](KeyType&& key) {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"operator[] is unavailable for a scalar node.\", get_type());\n        }\n\n        basic_node n = std::forward<KeyType>(key);\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!n.is_integer()) {\n                throw fkyaml::type_error(\n                    \"An argument of operator[] for sequence nodes must be an integer.\", get_type());\n            }\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return p_node_value->p_sequence->operator[](n.get_value<int>());\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        return p_node_value->p_mapping->operator[](std::move(n));\n    }\n\n    /// @brief A subscript operator of the basic_node class with a key of a compatible type with basic_node.\n    /// @tparam KeyType A key type compatible with basic_node\n    /// @param key A key to the target value in a sequence/mapping node.\n    /// @return The value associated with the given key, or a default basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/\n    template <\n        typename KeyType, detail::enable_if_t<\n                              detail::conjunction<\n                                  detail::negation<detail::is_basic_node<KeyType>>,\n                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,\n                              int> = 0>\n    const basic_node& operator[](KeyType&& key) const {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"operator[] is unavailable for a scalar node.\", get_type());\n        }\n\n        basic_node node_key = std::forward<KeyType>(key);\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!node_key.is_integer()) {\n                throw fkyaml::type_error(\n                    \"An argument of operator[] for sequence nodes must be an integer.\", get_type());\n            }\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return p_node_value->p_sequence->operator[](node_key.get_value<int>());\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        return p_node_value->p_mapping->operator[](std::move(node_key));\n    }\n\n    /// @brief A subscript operator of the basic_node class with a basic_node key object.\n    /// @tparam KeyType A key type which is a kind of the basic_node template class.\n    /// @param key A key to the target value in a sequence/mapping node.\n    /// @return The value associated with the given key, or a default basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/\n    template <\n        typename KeyType, detail::enable_if_t<detail::is_basic_node<detail::remove_cvref_t<KeyType>>::value, int> = 0>\n    basic_node& operator[](KeyType&& key) {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"operator[] is unavailable for a scalar node.\", get_type());\n        }\n\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!key.is_integer()) {\n                throw fkyaml::type_error(\n                    \"An argument of operator[] for sequence nodes must be an integer.\", get_type());\n            }\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return p_node_value->p_sequence->operator[](key.template get_value<int>());\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        return p_node_value->p_mapping->operator[](std::forward<KeyType>(key));\n    }\n\n    /// @brief A subscript operator of the basic_node class with a basic_node key object.\n    /// @tparam KeyType A key type which is a kind of the basic_node template class.\n    /// @param key A key to the target value in a sequence/mapping node.\n    /// @return The value associated with the given key, or a default basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator[]/\n    template <\n        typename KeyType, detail::enable_if_t<detail::is_basic_node<detail::remove_cvref_t<KeyType>>::value, int> = 0>\n    const basic_node& operator[](KeyType&& key) const {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"operator[] is unavailable for a scalar node.\", get_type());\n        }\n\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!key.is_integer()) {\n                throw fkyaml::type_error(\n                    \"An argument of operator[] for sequence nodes must be an integer.\", get_type());\n            }\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return p_node_value->p_sequence->operator[](key.template get_value<int>());\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        return p_node_value->p_mapping->operator[](std::forward<KeyType>(key));\n    }\n\n    /// @brief An equal-to operator of the basic_node class.\n    /// @param rhs A basic_node object to be compared with this basic_node object.\n    /// @return true if both types and values are equal, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_eq/\n    bool operator==(const basic_node& rhs) const noexcept {\n        const detail::node_attr_t this_val_bit = get_node_attrs() & detail::node_attr_mask::value;\n        if (this_val_bit != (rhs.get_node_attrs() & detail::node_attr_mask::value)) {\n            return false;\n        }\n\n        const node_value* this_node_value_ptr = get_node_value_ptr();\n        const node_value* other_node_value_ptr = rhs.get_node_value_ptr();\n\n        bool ret = false;\n        switch (this_val_bit) {\n        case detail::node_attr_bits::seq_bit:\n            ret = (*(this_node_value_ptr->p_sequence) == *(other_node_value_ptr->p_sequence));\n            break;\n        case detail::node_attr_bits::map_bit:\n            ret = (*(this_node_value_ptr->p_mapping) == *(other_node_value_ptr->p_mapping));\n            break;\n        case detail::node_attr_bits::null_bit:\n            // Always true for comparisons between null nodes.\n            ret = true;\n            break;\n        case detail::node_attr_bits::bool_bit:\n            ret = (this_node_value_ptr->boolean == other_node_value_ptr->boolean);\n            break;\n        case detail::node_attr_bits::int_bit:\n            ret = (this_node_value_ptr->integer == other_node_value_ptr->integer);\n            break;\n        case detail::node_attr_bits::float_bit:\n            ret =\n                (std::abs(this_node_value_ptr->float_val - other_node_value_ptr->float_val) <\n                 std::numeric_limits<float_number_type>::epsilon());\n            break;\n        case detail::node_attr_bits::string_bit:\n            ret = (*(this_node_value_ptr->p_string) == *(other_node_value_ptr->p_string));\n            break;\n        default:                   // LCOV_EXCL_LINE\n            detail::unreachable(); // LCOV_EXCL_LINE\n        }\n\n        return ret;\n    }\n\n    /// @brief A not-equal-to operator of the basic_node class.\n    /// @param rhs A basic_node object to be compared with this basic_node object.\n    /// @return true if either types or values are different, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_ne/\n    bool operator!=(const basic_node& rhs) const noexcept {\n        return !operator==(rhs);\n    }\n\n    /// @brief A less-than operator of the basic_node class.\n    /// @param rhs A basic_node object to be compared with this basic_node object.\n    /// @return true this basic_node object is less than `rhs`.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_lt/\n    bool operator<(const basic_node& rhs) const noexcept {\n        if (operator==(rhs)) {\n            return false;\n        }\n\n        const detail::node_attr_t this_val_bit = get_node_attrs() & detail::node_attr_mask::value;\n        const detail::node_attr_t other_val_bit = rhs.get_node_attrs() & detail::node_attr_mask::value;\n\n        if (this_val_bit < other_val_bit) {\n            return true;\n        }\n\n        if (this_val_bit != other_val_bit) {\n            return false;\n        }\n\n        const node_value* p_this_value = get_node_value_ptr();\n        const node_value* p_other_value = rhs.get_node_value_ptr();\n\n        bool ret = false;\n        switch (this_val_bit) {\n        case detail::node_attr_bits::seq_bit:\n            ret = (*(p_this_value->p_sequence) < *(p_other_value->p_sequence));\n            break;\n        case detail::node_attr_bits::map_bit:\n            ret = (*(p_this_value->p_mapping) < *(p_other_value->p_mapping));\n            break;\n        case detail::node_attr_bits::null_bit: // LCOV_EXCL_LINE\n            // Will not come here since null nodes are always the same.\n            detail::unreachable(); // LCOV_EXCL_LINE\n        case detail::node_attr_bits::bool_bit:\n            // false < true\n            ret = (!p_this_value->boolean && p_other_value->boolean);\n            break;\n        case detail::node_attr_bits::int_bit:\n            ret = (p_this_value->integer < p_other_value->integer);\n            break;\n        case detail::node_attr_bits::float_bit:\n            ret = (p_this_value->float_val < p_other_value->float_val);\n            break;\n        case detail::node_attr_bits::string_bit:\n            ret = (*(p_this_value->p_string) < *(p_other_value->p_string));\n            break;\n        default:                   // LCOV_EXCL_LINE\n            detail::unreachable(); // LCOV_EXCL_LINE\n        }\n\n        return ret;\n    }\n\n    /// @brief A less-than-or-equal-to operator of the basic_node class.\n    /// @param rhs A basic_node object to be compared with this basic_node object.\n    /// @return true this basic_node object is less than or equal to `rhs`.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_le/\n    bool operator<=(const basic_node& rhs) const noexcept {\n        return !rhs.operator<(*this);\n    }\n\n    /// @brief A greater-than operator of the basic_node class.\n    /// @param rhs A basic_node object to be compared with this basic_node object.\n    /// @return true this basic_node object is greater than `rhs`.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_gt/\n    bool operator>(const basic_node& rhs) const noexcept {\n        return !operator<=(rhs);\n    }\n\n    /// @brief A greater-than-or-equal-to operator of the basic_node class.\n    /// @param rhs A basic_node object to be compared with this basic_node object.\n    /// @return true this basic_node object is greater than or equal to `rhs`.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/operator_ge/\n    bool operator>=(const basic_node& rhs) const noexcept {\n        return !operator<(rhs);\n    }\n\npublic:\n    /// @brief Returns the type of the current basic_node value.\n    /// @return The type of the YAML node value.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_type/\n    node_type get_type() const noexcept {\n        const detail::node_attr_t attrs = get_node_attrs();\n        return detail::node_attr_bits::to_node_type(attrs);\n    }\n\n    /// @brief Returns the type of the current basic_node value.\n    /// @deprecated Use get_type() function. (since 0.3.12)\n    /// @return The type of the YAML node value.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/type/\n    FK_YAML_DEPRECATED(\"Since 0.3.12; Use get_type()\")\n    node_t type() const noexcept {\n        node_type tmp_type = get_type();\n        return detail::convert_from_node_type(tmp_type);\n    }\n\n    /// @brief Tests whether the current basic_node value is of sequence type.\n    /// @return true if the type is sequence, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_sequence/\n    bool is_sequence() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::seq_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of mapping type.\n    /// @return true if the type is mapping, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_mapping/\n    bool is_mapping() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::map_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of null type.\n    /// @return true if the type is null, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_null/\n    bool is_null() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::null_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of boolean type.\n    /// @return true if the type is boolean, false otherwise\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_boolean/\n    bool is_boolean() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::bool_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of integer type.\n    /// @return true if the type is integer, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_integer/\n    bool is_integer() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::int_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of float number type.\n    /// @return true if the type is floating point number, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_float_number/\n    bool is_float_number() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::float_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of string type.\n    /// @return true if the type is string, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_string/\n    bool is_string() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::string_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value is of scalar types.\n    /// @return true if the type is scalar, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_scalar/\n    bool is_scalar() const noexcept {\n        return get_node_attrs() & detail::node_attr_bits::scalar_bits;\n    }\n\n    /// @brief Tests whether the current basic_node is an anchor node.\n    /// @return true if the current basic_node is an anchor node, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_anchor/\n    bool is_anchor() const noexcept {\n        return m_attrs & detail::node_attr_bits::anchor_bit;\n    }\n\n    /// @brief Tests whether the current basic_node is an alias node.\n    /// @return true if the current basic_node is an alias node, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/is_alias/\n    bool is_alias() const noexcept {\n        return m_attrs & detail::node_attr_bits::alias_bit;\n    }\n\n    /// @brief Tests whether the current basic_node value (sequence, mapping, string) is empty.\n    /// @return true if the node value is empty, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/empty/\n    bool empty() const {\n        switch (get_node_attrs() & detail::node_attr_mask::value) {\n        case detail::node_attr_bits::seq_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return p_node_value->p_sequence->empty();\n        }\n        case detail::node_attr_bits::map_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n            return p_node_value->p_mapping->empty();\n        }\n        case detail::node_attr_bits::string_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_string != nullptr);\n            return p_node_value->p_string->empty();\n        }\n        default:\n            throw fkyaml::type_error(\"The target node is not of a container type.\", get_type());\n        }\n    }\n\n    /// @brief Returns the size of the current basic_node value (sequence, mapping, string).\n    /// @return The size of a node value.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/size/\n    std::size_t size() const {\n        const node_value* p_node_value = get_node_value_ptr();\n        switch (get_node_attrs() & detail::node_attr_mask::value) {\n        case detail::node_attr_bits::seq_bit:\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return p_node_value->p_sequence->size();\n        case detail::node_attr_bits::map_bit:\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n            return p_node_value->p_mapping->size();\n        case detail::node_attr_bits::string_bit:\n            FK_YAML_ASSERT(p_node_value->p_string != nullptr);\n            return p_node_value->p_string->size();\n        default:\n            throw fkyaml::type_error(\"The target node is not of a container type.\", get_type());\n        }\n    }\n\n    /// @brief Check whether this basic_node object has a given key in its inner mapping node value.\n    /// @tparam KeyType A key type compatible with basic_node.\n    /// @param key A key to the target value in the mapping node value.\n    /// @return true if the target node is a mapping and has the given key, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/contains/\n    template <\n        typename KeyType, detail::enable_if_t<\n                              detail::conjunction<\n                                  detail::negation<detail::is_basic_node<detail::remove_cvref_t<KeyType>>>,\n                                  detail::is_node_compatible_type<basic_node, detail::remove_cvref_t<KeyType>>>::value,\n                              int> = 0>\n    bool contains(KeyType&& key) const {\n        if FK_YAML_LIKELY (get_node_attrs() & detail::node_attr_bits::map_bit) {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n\n            const mapping_type& map = *p_node_value->p_mapping;\n            basic_node node_key = std::forward<KeyType>(key);\n            return map.find(std::move(node_key)) != map.end();\n        }\n\n        return false;\n    }\n\n    /// @brief Check whether this basic_node object has a given key in its inner mapping Node value.\n    /// @tparam KeyType A key type which is a kind of basic_node template class.\n    /// @param[in] key A key to the target value in the YAML mapping node value.\n    /// @return true if the YAML node is a mapping and has the given key, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/contains/\n    template <\n        typename KeyType, detail::enable_if_t<detail::is_basic_node<detail::remove_cvref_t<KeyType>>::value, int> = 0>\n    bool contains(KeyType&& key) const {\n        if FK_YAML_LIKELY (get_node_attrs() & detail::node_attr_bits::map_bit) {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n\n            const mapping_type& map = *p_node_value->p_mapping;\n            return map.find(std::forward<KeyType>(key)) != map.end();\n        }\n\n        return false;\n    }\n\n    /// @brief Get a basic_node object with a key of a compatible type.\n    /// @tparam KeyType A key type compatible with basic_node\n    /// @param key A key to the target basic_node object in a sequence/mapping node.\n    /// @return Reference to the basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/\n    template <\n        typename KeyType, detail::enable_if_t<\n                              detail::conjunction<\n                                  detail::negation<detail::is_basic_node<KeyType>>,\n                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,\n                              int> = 0>\n    basic_node& at(KeyType&& key) {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"at() is unavailable for a scalar node.\", get_type());\n        }\n\n        basic_node node_key = std::forward<KeyType>(key);\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!node_key.is_integer()) {\n                throw fkyaml::type_error(\"An argument of at() for sequence nodes must be an integer.\", get_type());\n            }\n\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            sequence_type& seq = *p_node_value->p_sequence;\n            int index = node_key.template get_value<int>();\n            int size = static_cast<int>(seq.size());\n            if FK_YAML_UNLIKELY (index >= size) {\n                throw fkyaml::out_of_range(index);\n            }\n            return seq.at(index);\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        mapping_type& map = *p_node_value->p_mapping;\n        bool is_found = map.find(node_key) != map.end();\n        if FK_YAML_UNLIKELY (!is_found) {\n            throw fkyaml::out_of_range(serialize(node_key).c_str());\n        }\n        return map.at(node_key);\n    }\n\n    /// @brief Get a basic_node object with a key of a compatible type.\n    /// @tparam KeyType A key type compatible with basic_node\n    /// @param key A key to the target basic_node object in a sequence/mapping node.\n    /// @return Constant reference to the basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/\n    template <\n        typename KeyType, detail::enable_if_t<\n                              detail::conjunction<\n                                  detail::negation<detail::is_basic_node<KeyType>>,\n                                  detail::is_node_compatible_type<basic_node, KeyType>>::value,\n                              int> = 0>\n    const basic_node& at(KeyType&& key) const {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"at() is unavailable for a scalar node.\", get_type());\n        }\n\n        basic_node node_key = std::forward<KeyType>(key);\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!node_key.is_integer()) {\n                throw fkyaml::type_error(\"An argument of at() for sequence nodes must be an integer.\", get_type());\n            }\n\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            const sequence_type& seq = *p_node_value->p_sequence;\n            int index = node_key.template get_value<int>();\n            int size = static_cast<int>(seq.size());\n            if FK_YAML_UNLIKELY (index >= size) {\n                throw fkyaml::out_of_range(index);\n            }\n            return seq.at(index);\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        const mapping_type& map = *p_node_value->p_mapping;\n        bool is_found = map.find(node_key) != map.end();\n        if FK_YAML_UNLIKELY (!is_found) {\n            throw fkyaml::out_of_range(serialize(node_key).c_str());\n        }\n        return map.at(node_key);\n    }\n\n    /// @brief Get a basic_node object with a basic_node key object.\n    /// @tparam KeyType A key type which is a kind of the basic_node template class.\n    /// @param key A key to the target basic_node object in a sequence/mapping node.\n    /// @return Reference to the basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/\n    template <\n        typename KeyType, detail::enable_if_t<detail::is_basic_node<detail::remove_cvref_t<KeyType>>::value, int> = 0>\n    basic_node& at(KeyType&& key) {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"at() is unavailable for a scalar node.\", get_type());\n        }\n\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!key.is_integer()) {\n                throw fkyaml::type_error(\"An argument of at() for sequence nodes must be an integer.\", get_type());\n            }\n\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            sequence_type& seq = *p_node_value->p_sequence;\n            int index = std::forward<KeyType>(key).template get_value<int>();\n            int size = static_cast<int>(seq.size());\n            if FK_YAML_UNLIKELY (index >= size) {\n                throw fkyaml::out_of_range(index);\n            }\n            return seq.at(index);\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        mapping_type& map = *p_node_value->p_mapping;\n        bool is_found = map.find(key) != map.end();\n        if FK_YAML_UNLIKELY (!is_found) {\n            throw fkyaml::out_of_range(serialize(key).c_str());\n        }\n        return map.at(key);\n    }\n\n    /// @brief Get a basic_node object with a basic_node key object.\n    /// @tparam KeyType A key type which is a kind of the basic_node template class.\n    /// @param key A key to the target basic_node object in a sequence/mapping node.\n    /// @return Constant reference to the basic_node object associated with the given key.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/at/\n    template <\n        typename KeyType, detail::enable_if_t<detail::is_basic_node<detail::remove_cvref_t<KeyType>>::value, int> = 0>\n    const basic_node& at(KeyType&& key) const {\n        if FK_YAML_UNLIKELY (is_scalar()) {\n            throw fkyaml::type_error(\"at() is unavailable for a scalar node.\", get_type());\n        }\n\n        const node_value* p_node_value = get_node_value_ptr();\n\n        if (is_sequence()) {\n            if FK_YAML_UNLIKELY (!key.is_integer()) {\n                throw fkyaml::type_error(\"An argument of at() for sequence nodes must be an integer.\", get_type());\n            }\n\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            const sequence_type& seq = *p_node_value->p_sequence;\n            int index = std::forward<KeyType>(key).template get_value<int>();\n            int size = static_cast<int>(seq.size());\n            if FK_YAML_UNLIKELY (index >= size) {\n                throw fkyaml::out_of_range(index);\n            }\n            return seq.at(index);\n        }\n\n        FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n        const mapping_type& map = *p_node_value->p_mapping;\n        bool is_found = map.find(key) != map.end();\n        if FK_YAML_UNLIKELY (!is_found) {\n            throw fkyaml::out_of_range(serialize(key).c_str());\n        }\n        return map.at(key);\n    }\n\n    /// @brief Get the YAML version for this basic_node object.\n    /// @return The YAML version if already set, `yaml_version_type::VERSION_1_2` otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_yaml_version_type/\n    yaml_version_type get_yaml_version_type() const noexcept {\n        return mp_meta->is_version_specified ? mp_meta->version : yaml_version_type::VERSION_1_2;\n    }\n\n    /// @brief Set the YAML version for this basic_node object.\n    /// @param[in] version The target YAML version.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/set_yaml_version_type/\n    void set_yaml_version_type(const yaml_version_type version) noexcept {\n        mp_meta->version = version;\n        mp_meta->is_version_specified = true;\n    }\n\n    /// @brief Get the YAML version for this basic_node object.\n    /// @deprecated Use get_yaml_version_type() function. (since 0.3.12)\n    /// @return The YAML version if already set, `yaml_version_t::VER_1_2` otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_yaml_version/\n    FK_YAML_DEPRECATED(\"Since 0.3.12; Use get_yaml_version_type()\")\n    yaml_version_t get_yaml_version() const noexcept {\n        yaml_version_type tmp_type = get_yaml_version_type();\n        return detail::convert_from_yaml_version_type(tmp_type);\n    }\n\n    /// @brief Set the YAML version for this basic_node object.\n    /// @deprecated Use set_yaml_version_type(yaml_version_type) function. (since 0.3.12)\n    /// @param[in] version The target YAML version.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/set_yaml_version/\n    FK_YAML_DEPRECATED(\"Since 0.3.12; Use set_yaml_version_type(const yaml_version_type)\")\n    void set_yaml_version(const yaml_version_t version) noexcept {\n        set_yaml_version_type(detail::convert_to_yaml_version_type(version));\n    }\n\n    /// @brief Check whether this basic_node object has already had any anchor name.\n    /// @return true if ths basic_node has an anchor name, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/has_anchor_name/\n    bool has_anchor_name() const noexcept {\n        return (m_attrs & detail::node_attr_mask::anchoring) && !m_prop.anchor.empty();\n    }\n\n    /// @brief Get the anchor name associated with this basic_node object.\n    /// @note Some anchor name must be set before calling this method. Call has_anchor_name() to see if this basic_node\n    /// object has any anchor name.\n    /// @return The anchor name associated with the node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_anchor_name/\n    const std::string& get_anchor_name() const {\n        if FK_YAML_UNLIKELY (!has_anchor_name()) {\n            throw fkyaml::exception(\"No anchor name has been set.\");\n        }\n        return m_prop.anchor;\n    }\n\n    /// @brief Add an anchor name to this basic_node object.\n    /// @note If this basic_node object has already had any anchor name, the new anchor name will overwrite the old one.\n    /// @param[in] anchor_name An anchor name. This should not be empty.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_anchor_name/\n    void add_anchor_name(const std::string& anchor_name) {\n        if (is_anchor()) {\n            m_attrs &= ~detail::node_attr_mask::anchoring;\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            mp_meta.reset();\n            itr->second.swap(*this);\n            mp_meta->anchor_table.erase(itr);\n        }\n\n        auto p_meta = mp_meta;\n\n        basic_node node;\n        node.swap(*this);\n        p_meta->anchor_table.emplace(anchor_name, std::move(node));\n\n        m_attrs &= ~detail::node_attr_mask::anchoring;\n        m_attrs |= detail::node_attr_bits::anchor_bit;\n        mp_meta = p_meta;\n        auto offset = static_cast<uint32_t>(mp_meta->anchor_table.count(anchor_name) - 1);\n        detail::node_attr_bits::set_anchor_offset(offset, m_attrs);\n        m_prop.anchor = anchor_name;\n    }\n\n    /// @brief Add an anchor name to this basic_node object.\n    /// @note If this basic_node object has already had any anchor name, the new anchor name will overwrite the old one.\n    /// @param[in] anchor_name An anchor name. This should not be empty.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_anchor_name/\n    void add_anchor_name(std::string&& anchor_name) {\n        if (is_anchor()) {\n            m_attrs &= ~detail::node_attr_mask::anchoring;\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            mp_meta.reset();\n            itr->second.swap(*this);\n            mp_meta->anchor_table.erase(itr);\n        }\n\n        auto p_meta = mp_meta;\n\n        basic_node node;\n        node.swap(*this);\n        p_meta->anchor_table.emplace(anchor_name, std::move(node));\n\n        m_attrs &= ~detail::node_attr_mask::anchoring;\n        m_attrs |= detail::node_attr_bits::anchor_bit;\n        mp_meta = p_meta;\n        auto offset = static_cast<uint32_t>(mp_meta->anchor_table.count(anchor_name) - 1);\n        detail::node_attr_bits::set_anchor_offset(offset, m_attrs);\n        m_prop.anchor = std::move(anchor_name);\n    }\n\n    /// @brief Check whether this basic_node object has already had any tag name.\n    /// @return true if ths basic_node has a tag name, false otherwise.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/has_tag_name/\n    bool has_tag_name() const noexcept {\n        return !m_prop.tag.empty();\n    }\n\n    /// @brief Get the tag name associated with this basic_node object.\n    /// @note Some tag name must be set before calling this method. Call has_tag_name() to see if this basic_node\n    /// object has any tag name.\n    /// @return The tag name associated with the node. It may be empty.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_tag_name/\n    const std::string& get_tag_name() const {\n        if FK_YAML_UNLIKELY (!has_tag_name()) {\n            throw fkyaml::exception(\"No tag name has been set.\");\n        }\n        return m_prop.tag;\n    }\n\n    /// @brief Add a tag name to this basic_node object.\n    /// @note If this basic_node object has already had any tag name, the new tag name will overwrite the old one.\n    /// @param[in] tag_name A tag name to get associated with this basic_node object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_tag_name/\n    void add_tag_name(const std::string& tag_name) {\n        m_prop.tag = tag_name;\n    }\n\n    /// @brief Add a tag name to this basic_node object.\n    /// @note If this basic_node object has already had any tag name, the new tag name will overwrite the old one.\n    /// @param[in] tag_name A tag name to get associated with this basic_node object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/add_tag_name/\n    void add_tag_name(std::string&& tag_name) {\n        m_prop.tag = std::move(tag_name);\n    }\n\n    /// @brief Get the node value object converted into a given type.\n    /// @note This function requires T objects to be default constructible. Also, T cannot be either a reference,\n    /// pointer or C-style array type.\n    /// @tparam T A compatible value type which might be cv-qualified.\n    /// @tparam ValueType A compatible value type with cv-qualifiers removed by default.\n    /// @return A compatible native data value converted from the basic_node object.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value/\n    template <\n        typename T, typename ValueType = detail::remove_cv_t<T>,\n        detail::enable_if_t<std::is_default_constructible<ValueType>::value, int> = 0>\n    T get_value() const noexcept(\n        noexcept(std::declval<const basic_node&>().template get_value_impl<ValueType>(std::declval<ValueType&>()))) {\n        // emit a compile error if T is either a reference, pointer or C-style array type.\n        static_assert(\n            !std::is_reference<T>::value,\n            \"get_value() cannot be called with reference types. you might want to call get_value_ref().\");\n        static_assert(!std::is_pointer<T>::value, \"get_value() cannot be called with pointer types.\");\n        static_assert(\n            !std::is_array<T>::value,\n            \"get_value() cannot be called with C-style array types. you might want to call get_value_inplace().\");\n\n        auto ret = ValueType();\n        if (has_anchor_name()) {\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            itr->second.get_value_impl(ret);\n        }\n        else {\n            get_value_impl(ret);\n        }\n        return ret;\n    }\n\n    /// @brief Get the node value object converted into a given type. The conversion result is filled into `value_ref`.\n    /// @tparam T A compatible value type.\n    /// @param value_ref A storage into which the conversion result is filled.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_inplace/\n    template <typename T>\n    void get_value_inplace(T& value_ref) const\n        noexcept(noexcept(std::declval<const basic_node&>().template get_value_impl<T>(std::declval<T&>()))) {\n        if (has_anchor_name()) {\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            itr->second.get_value_impl(value_ref);\n        }\n        else {\n            get_value_impl(value_ref);\n        }\n    }\n\n    /// @brief Explicit reference access to the internally stored YAML node value.\n    /// @tparam ReferenceType Reference type to the target YAML node value.\n    /// @return Reference to the internally stored YAML node value.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_ref/\n    template <typename ReferenceType, detail::enable_if_t<std::is_reference<ReferenceType>::value, int> = 0>\n    ReferenceType get_value_ref() {\n        if (has_anchor_name()) {\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            return itr->second.get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));\n        }\n        return get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));\n    }\n\n    /// @brief Explicit reference access to the internally stored YAML node value.\n    /// @tparam ReferenceType Constant reference type to the target YAML node value.\n    /// @return Constant reference to the internally stored YAML node value.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/get_value_ref/\n    template <\n        typename ReferenceType,\n        detail::enable_if_t<\n            detail::conjunction<\n                std::is_reference<ReferenceType>, std::is_const<detail::remove_reference_t<ReferenceType>>>::value,\n            int> = 0>\n    ReferenceType get_value_ref() const {\n        if (has_anchor_name()) {\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            return itr->second.get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));\n        }\n        return get_value_ref_impl(static_cast<detail::add_pointer_t<ReferenceType>>(nullptr));\n    }\n\n    /// @brief Swaps the internally stored data with the specified basic_node object.\n    /// @param[in] rhs A basic_node object to be swapped with.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/swap/\n    void swap(basic_node& rhs) noexcept {\n        using std::swap;\n        swap(m_attrs, rhs.m_attrs);\n        swap(mp_meta, rhs.mp_meta);\n\n        node_value tmp {};\n        std::memcpy(&tmp, &m_node_value, sizeof(node_value));\n        std::memcpy(&m_node_value, &rhs.m_node_value, sizeof(node_value));\n        std::memcpy(&rhs.m_node_value, &tmp, sizeof(node_value));\n\n        swap(m_prop.tag, rhs.m_prop.tag);\n        swap(m_prop.anchor, rhs.m_prop.anchor);\n    }\n\n    /// @brief Returns an iterator to the first element of a container node (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return An iterator to the first element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/\n    iterator begin() {\n        switch (get_node_attrs() & detail::node_attr_mask::value) {\n        case detail::node_attr_bits::seq_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return {p_node_value->p_sequence->begin()};\n        }\n        case detail::node_attr_bits::map_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n            return {p_node_value->p_mapping->begin()};\n        }\n        default:\n            throw fkyaml::type_error(\"The target node is neither of sequence nor mapping types.\", get_type());\n        }\n    }\n\n    /// @brief Returns a const iterator to the first element of a container node (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the first element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/\n    const_iterator begin() const {\n        switch (get_node_attrs() & detail::node_attr_mask::value) {\n        case detail::node_attr_bits::seq_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return {p_node_value->p_sequence->begin()};\n        }\n        case detail::node_attr_bits::map_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n            return {p_node_value->p_mapping->begin()};\n        }\n        default:\n            throw fkyaml::type_error(\"The target node is neither of sequence nor mapping types.\", get_type());\n        }\n    }\n\n    /// @brief Returns a const iterator to the first element of a container node (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the first element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/begin/\n    const_iterator cbegin() const {\n        return begin();\n    }\n\n    /// @brief Returns an iterator to the past-the-last element of a container node (sequence or mapping).\n    /// @throw `type_error` if the basic_node value is not of container types.\n    /// @return An iterator to the past-the-last element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/\n    iterator end() {\n        switch (get_node_attrs() & detail::node_attr_mask::value) {\n        case detail::node_attr_bits::seq_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return {p_node_value->p_sequence->end()};\n        }\n        case detail::node_attr_bits::map_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n            return {p_node_value->p_mapping->end()};\n        }\n        default:\n            throw fkyaml::type_error(\"The target node is neither of sequence nor mapping types.\", get_type());\n        }\n    }\n\n    /// @brief Returns a const iterator to the past-the-last element of a container node (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the past-the-last element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/\n    const_iterator end() const {\n        switch (get_node_attrs() & detail::node_attr_mask::value) {\n        case detail::node_attr_bits::seq_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_sequence != nullptr);\n            return {p_node_value->p_sequence->end()};\n        }\n        case detail::node_attr_bits::map_bit: {\n            const node_value* p_node_value = get_node_value_ptr();\n            FK_YAML_ASSERT(p_node_value->p_mapping != nullptr);\n            return {p_node_value->p_mapping->end()};\n        }\n        default:\n            throw fkyaml::type_error(\"The target node is neither of sequence nor mapping types.\", get_type());\n        }\n    }\n\n    /// @brief Returns a const iterator to the past-the-last element of a container node (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the past-the-last element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/end/\n    const_iterator cend() const {\n        return end();\n    }\n\n    /// @brief Returns an iterator to the reverse-beginning (i.e., last) element of a container node (sequence or\n    /// mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return An iterator to the reverse-beginning element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/\n    reverse_iterator rbegin() {\n        return {end()};\n    }\n\n    /// @brief Returns a const iterator to the reverse-beginning (i.e., last) element of a container node (sequence or\n    /// mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the reverse-beginning element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/\n    const_reverse_iterator rbegin() const {\n        return {end()};\n    }\n\n    /// @brief Returns a const iterator to the reverse-beginning (i.e., last) element of a container node (sequence or\n    /// mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the reverse-beginning element of a container node.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rbegin/\n    const_reverse_iterator crbegin() const {\n        return rbegin();\n    }\n\n    /// @brief Returns an iterator to the reverse-end (i.e., one before the first) element of a container node (sequence\n    /// or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return An iterator to the reverse-end element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/\n    reverse_iterator rend() {\n        return {begin()};\n    }\n\n    /// @brief Returns a const iterator to the reverse-end (i.e., one before the first) element of a container node\n    /// (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the reverse-end element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/\n    const_reverse_iterator rend() const {\n        return {begin()};\n    }\n\n    /// @brief Returns a const iterator to the reverse-end (i.e., one before the first) element of a container node\n    /// (sequence or mapping).\n    /// @throw `type_error` if this basic_node is neither a sequence nor mapping node.\n    /// @return A const iterator to the reverse-end element.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/rend/\n    const_reverse_iterator crend() const {\n        return rend();\n    }\n\n    /// @brief Returns a range of mapping entries.\n    /// @throw `type_error` if this basic_node is not a mapping.\n    /// @return A range of mapping entries.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_items/\n    map_range map_items() {\n        if FK_YAML_UNLIKELY (!is_mapping()) {\n            throw type_error(\"map_items() cannot be called on a non-mapping node.\", get_type());\n        }\n        return {*this};\n    }\n\n    /// @brief Returns a const range of mapping entries.\n    /// @throw `type_error` if this basic_node is not a mapping.\n    /// @return A const range of mapping entries.\n    /// @sa https://fktn-k.github.io/fkYAML/api/basic_node/map_items/\n    const_map_range map_items() const {\n        if FK_YAML_UNLIKELY (!is_mapping()) {\n            throw type_error(\"map_items() cannot be called on a non-mapping node.\", get_type());\n        }\n        return {*this};\n    }\n\nprivate:\n    /// @brief Returns the pointer to the node_value object of either this node or the associated anchor node.\n    /// @return The pointer to the node_value object of either this node or the associated anchor node.\n    const node_value* get_node_value_ptr() const {\n        if (has_anchor_name()) {\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            return &(itr->second.m_node_value);\n        }\n        return &m_node_value;\n    }\n\n    detail::node_attr_t get_node_attrs() const {\n        if (has_anchor_name()) {\n            auto itr = mp_meta->anchor_table.equal_range(m_prop.anchor).first;\n            std::advance(itr, detail::node_attr_bits::get_anchor_offset(m_attrs));\n            return itr->second.m_attrs;\n        }\n        return m_attrs;\n    }\n\n    template <\n        typename ValueType, detail::enable_if_t<detail::negation<detail::is_basic_node<ValueType>>::value, int> = 0>\n    void get_value_impl(ValueType& v) const\n        noexcept(noexcept(ConverterType<ValueType, void>::from_node(std::declval<const basic_node&>(), v))) {\n        ConverterType<ValueType, void>::from_node(*this, v);\n    }\n\n    template <typename ValueType, detail::enable_if_t<detail::is_basic_node<ValueType>::value, int> = 0>\n    void get_value_impl(ValueType& v) const {\n        v = *this;\n    }\n\n    /// @brief Returns reference to the sequence node value.\n    /// @throw fkyaml::exception The node value is not a sequence.\n    /// @return Reference to the sequence node value.\n    sequence_type& get_value_ref_impl(sequence_type* /*unused*/) {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::seq_bit) {\n            return *(m_node_value.p_sequence);\n        }\n        throw fkyaml::type_error(\"The node value is not a sequence.\", get_type());\n    }\n\n    /// @brief Returns constant reference to the sequence node value.\n    /// @throw fkyaml::exception The node value is not a sequence.\n    /// @return Constant reference to the sequence node value.\n    const sequence_type& get_value_ref_impl(const sequence_type* /*unused*/) const {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::seq_bit) {\n            return *(m_node_value.p_sequence);\n        }\n        throw fkyaml::type_error(\"The node value is not a sequence.\", get_type());\n    }\n\n    /// @brief Returns reference to the mapping node value.\n    /// @throw fkyaml::exception The node value is not a mapping.\n    /// @return Reference to the mapping node value.\n    mapping_type& get_value_ref_impl(mapping_type* /*unused*/) {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::map_bit) {\n            return *(m_node_value.p_mapping);\n        }\n        throw fkyaml::type_error(\"The node value is not a mapping.\", get_type());\n    }\n\n    /// @brief Returns constant reference to the mapping node value.\n    /// @throw fkyaml::exception The node value is not a mapping.\n    /// @return Constant reference to the mapping node value.\n    const mapping_type& get_value_ref_impl(const mapping_type* /*unused*/) const {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::map_bit) {\n            return *(m_node_value.p_mapping);\n        }\n        throw fkyaml::type_error(\"The node value is not a mapping.\", get_type());\n    }\n\n    /// @brief Returns reference to the boolean node value.\n    /// @throw fkyaml::exception The node value is not a boolean.\n    /// @return Reference to the boolean node value.\n    boolean_type& get_value_ref_impl(boolean_type* /*unused*/) {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::bool_bit) {\n            return m_node_value.boolean;\n        }\n        throw fkyaml::type_error(\"The node value is not a boolean.\", get_type());\n    }\n\n    /// @brief Returns reference to the boolean node value.\n    /// @throw fkyaml::exception The node value is not a boolean.\n    /// @return Constant reference to the boolean node value.\n    const boolean_type& get_value_ref_impl(const boolean_type* /*unused*/) const {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::bool_bit) {\n            return m_node_value.boolean;\n        }\n        throw fkyaml::type_error(\"The node value is not a boolean.\", get_type());\n    }\n\n    /// @brief Returns reference to the integer node value.\n    /// @throw fkyaml::exception The node value is not an integer.\n    /// @return Reference to the integer node value.\n    integer_type& get_value_ref_impl(integer_type* /*unused*/) {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::int_bit) {\n            return m_node_value.integer;\n        }\n        throw fkyaml::type_error(\"The node value is not an integer.\", get_type());\n    }\n\n    /// @brief Returns reference to the integer node value.\n    /// @throw fkyaml::exception The node value is not an integer.\n    /// @return Constant reference to the integer node value.\n    const integer_type& get_value_ref_impl(const integer_type* /*unused*/) const {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::int_bit) {\n            return m_node_value.integer;\n        }\n        throw fkyaml::type_error(\"The node value is not an integer.\", get_type());\n    }\n\n    /// @brief Returns reference to the floating point number node value.\n    /// @throw fkyaml::exception The node value is not a floating point number.\n    /// @return Reference to the floating point number node value.\n    float_number_type& get_value_ref_impl(float_number_type* /*unused*/) {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::float_bit) {\n            return m_node_value.float_val;\n        }\n        throw fkyaml::type_error(\"The node value is not a floating point number.\", get_type());\n    }\n\n    /// @brief Returns reference to the floating point number node value.\n    /// @throw fkyaml::exception The node value is not a floating point number.\n    /// @return Constant reference to the floating point number node value.\n    const float_number_type& get_value_ref_impl(const float_number_type* /*unused*/) const {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::float_bit) {\n            return m_node_value.float_val;\n        }\n        throw fkyaml::type_error(\"The node value is not a floating point number.\", get_type());\n    }\n\n    /// @brief Returns reference to the string node value.\n    /// @throw fkyaml::exception The node value is not a string.\n    /// @return Reference to the string node value.\n    string_type& get_value_ref_impl(string_type* /*unused*/) {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::string_bit) {\n            return *(m_node_value.p_string);\n        }\n        throw fkyaml::type_error(\"The node value is not a string.\", get_type());\n    }\n\n    /// @brief Returns reference to the string node value.\n    /// @throw fkyaml::exception The node value is not a string.\n    /// @return Constant reference to the string node value.\n    const string_type& get_value_ref_impl(const string_type* /*unused*/) const {\n        if FK_YAML_LIKELY (m_attrs & detail::node_attr_bits::string_bit) {\n            return *(m_node_value.p_string);\n        }\n        throw fkyaml::type_error(\"The node value is not a string.\", get_type());\n    }\n\n    /// The current node attributes.\n    detail::node_attr_t m_attrs {detail::node_attr_bits::default_bits};\n    /// The shared set of YAML directives applied to this node.\n    mutable std::shared_ptr<detail::document_metainfo<basic_node>> mp_meta {\n        // NOLINTNEXTLINE(bugprone-unhandled-exception-at-new)\n        std::shared_ptr<detail::document_metainfo<basic_node>>(new detail::document_metainfo<basic_node>())};\n    /// The current node value.\n    node_value m_node_value {};\n    /// The property set of this node.\n    detail::node_property m_prop {};\n};\n\n/// @brief Swap function for basic_node objects.\n/// @param[in] lhs A left-side-hand basic_node object to be swapped with.\n/// @param[in] rhs A right-side-hand basic_node object to be swapped with.\n/// @sa https://fktn-k.github.io/fkYAML/api/swap/\ntemplate <\n    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,\n    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,\n    template <typename, typename = void> class ConverterType>\ninline void swap(\n    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& lhs,\n    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&\n        rhs) noexcept(noexcept(lhs.swap(rhs))) {\n    lhs.swap(rhs);\n}\n\n/// @brief Insertion operator for basic_node template class. A wrapper for the serialization feature.\n/// @param[in] os An output stream object.\n/// @param[in] n A basic_node object.\n/// @return Reference to the output stream object `os`.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/insertion_operator/\ntemplate <\n    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,\n    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,\n    template <typename, typename = void> class ConverterType>\ninline std::ostream& operator<<(\n    std::ostream& os,\n    const basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>&\n        n) {\n    os << basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>::\n            serialize(n);\n    return os;\n}\n\n/// @brief Extraction operator for basic_node template class. A wrapper for the deserialization feature with input\n/// streams.\n/// @param[in] is An input stream object.\n/// @param[in] n A basic_node object.\n/// @return Reference to the input stream object `is`.\n/// @sa https://fktn-k.github.io/fkYAML/api/basic_node/extraction_operator/\ntemplate <\n    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,\n    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,\n    template <typename, typename = void> class ConverterType>\ninline std::istream& operator>>(\n    std::istream& is,\n    basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>& n) {\n    n = basic_node<SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>::\n        deserialize(is);\n    return is;\n}\n\n/// @brief namespace for user-defined literals for the fkYAML library.\ninline namespace literals {\n/// @brief namespace for user-defined literals for YAML node objects.\ninline namespace yaml_literals {\n\n// Whitespace before the literal operator identifier is deprecated in C++23 or better but required in C++11.\n// Ignore the warning as a workaround. https://github.com/fktn-k/fkYAML/pull/417\n#if defined(__clang__)\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Wdeprecated\"\n#endif\n\n/// @brief The user-defined string literal which deserializes a `char` array into a `node` object.\n/// @param s An input `char` array.\n/// @param n The size of `s`.\n/// @return The resulting `node` object deserialized from `s`.\n/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/\ninline fkyaml::node operator\"\" _yaml(const char* s, std::size_t n) {\n    return fkyaml::node::deserialize(s, s + n);\n}\n\n/// @brief The user-defined string literal which deserializes a `char16_t` array into a `node` object.\n/// @param s An input `char16_t` array.\n/// @param n The size of `s`.\n/// @return The resulting `node` object deserialized from `s`.\n/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/\ninline fkyaml::node operator\"\" _yaml(const char16_t* s, std::size_t n) {\n    return fkyaml::node::deserialize(s, s + n);\n}\n\n/// @brief The user-defined string literal which deserializes a `char32_t` array into a `node` object.\n/// @param s An input `char32_t` array.\n/// @param n The size of `s`.\n/// @return The resulting `node` object deserialized from `s`.\n/// @sa https://fktn-k.github.io/fkYAML/api/operator_literal_yaml/\ninline fkyaml::node operator\"\" _yaml(const char32_t* s, std::size_t n) {\n    return fkyaml::node::deserialize(s, s + n);\n}\n\n#if FK_YAML_HAS_CHAR8_T\n/// @brief The user-defined string literal which deserializes a `char8_t` array into a `node` object.\n/// @param s An input `char8_t` array.\n/// @param n The size of `s`.\n/// @return The resulting `node` object deserialized from `s`.\ninline fkyaml::node operator\"\" _yaml(const char8_t* s, std::size_t n) {\n    return fkyaml::node::deserialize((const char8_t*)s, (const char8_t*)s + n);\n}\n\n#if defined(__clang__)\n#pragma clang diagnostic pop\n#endif\n\n#endif\n\n} // namespace yaml_literals\n} // namespace literals\n\nFK_YAML_NAMESPACE_END\n\nnamespace std {\n\ntemplate <\n    template <typename, typename...> class SequenceType, template <typename, typename, typename...> class MappingType,\n    typename BooleanType, typename IntegerType, typename FloatNumberType, typename StringType,\n    template <typename, typename = void> class ConverterType>\n// NOLINTNEXTLINE(cert-dcl58-cpp)\nstruct hash<fkyaml::basic_node<\n    SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>> {\n    using node_t = fkyaml::basic_node<\n        SequenceType, MappingType, BooleanType, IntegerType, FloatNumberType, StringType, ConverterType>;\n\n    std::size_t operator()(const node_t& n) const {\n        using boolean_type = typename node_t::boolean_type;\n        using integer_type = typename node_t::integer_type;\n        using float_number_type = typename node_t::float_number_type;\n        using string_type = typename node_t::string_type;\n\n        const auto type = n.get_type();\n\n        std::size_t seed = 0;\n        hash_combine(seed, std::hash<uint8_t>()(static_cast<uint8_t>(type)));\n\n        switch (type) {\n        case fkyaml::node_type::SEQUENCE:\n            hash_combine(seed, n.size());\n            for (const auto& elem : n) {\n                hash_combine(seed, operator()(elem));\n            }\n            return seed;\n\n        case fkyaml::node_type::MAPPING:\n            hash_combine(seed, n.size());\n            for (auto itr = n.begin(), end_itr = n.end(); itr != end_itr; ++itr) {\n                hash_combine(seed, operator()(itr.key()));\n                hash_combine(seed, operator()(itr.value()));\n            }\n            return seed;\n\n        case fkyaml::node_type::NULL_OBJECT:\n            hash_combine(seed, 0);\n            return seed;\n        case fkyaml::node_type::BOOLEAN:\n            hash_combine(seed, std::hash<boolean_type>()(n.template get_value<boolean_type>()));\n            return seed;\n        case fkyaml::node_type::INTEGER:\n            hash_combine(seed, std::hash<integer_type>()(n.template get_value<integer_type>()));\n            return seed;\n        case fkyaml::node_type::FLOAT:\n            hash_combine(seed, std::hash<float_number_type>()(n.template get_value<float_number_type>()));\n            return seed;\n        case fkyaml::node_type::STRING:\n            hash_combine(seed, std::hash<string_type>()(n.template get_value<string_type>()));\n            return seed;\n        default:                           // LCOV_EXCL_LINE\n            fkyaml::detail::unreachable(); // LCOV_EXCL_LINE\n        }\n    }\n\nprivate:\n    // taken from boost::hash_combine\n    FK_YAML_NO_SANITIZE(\"unsigned-shift-base\", \"unsigned-integer-overflow\")\n    static void hash_combine(std::size_t& seed, std::size_t v) {\n        seed ^= v + 0x9e3779b9 + (seed << 6u) + (seed >> 2u);\n    }\n};\n\n} // namespace std\n\n#endif /* FK_YAML_NODE_HPP */\n"
  },
  {
    "path": "lib/gli/clear.hpp",
    "content": "/// @brief Include to copy textures or a subset of either textures. These operations are performed without memory allocations.\n/// @file gli/clear.hpp\n\n#pragma once\n\nnamespace gli\n{\n\t/// Clear a complete texture\n\ttemplate <typename texture_type>\n\tvoid clear(texture_type& Texture);\n\n\t/// Clear a complete texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear(texture_type& Texture, gen_type const& BlockData);\n\n\t/// Clear a specific image of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear(texture_type& Texture, size_t Layer, size_t Face, size_t Level, gen_type const& BlockData);\n\n\t// Clear an entire level of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear_level(texture_type& Texture, size_t BaseLevel, gen_type const& BlockData);\n\n\t// Clear multiple levels of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear_level(texture_type& Texture, size_t BaseLevel, size_t LevelCount, gen_type const& BlockData);\n\n\t// Clear an entire face of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear_face(texture_type& Texture, size_t BaseFace, gen_type const& BlockData);\n\n\t// Clear multiple faces of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear_face(texture_type& Texture, size_t BaseFace, size_t FaceCount, gen_type const& BlockData);\n\n\t// Clear an entire layer of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear_layer(texture_type& Texture, size_t BaseLayer, gen_type const& BlockData);\n\n\t// Clear multiple layers of a texture\n\ttemplate <typename texture_type, typename gen_type>\n\tvoid clear_layer(texture_type& Texture, size_t BaseLayer, size_t LayerCount, gen_type const& BlockData);\n}//namespace gli\n\n#include \"./core/clear.inl\"\n\n"
  },
  {
    "path": "lib/gli/comparison.hpp",
    "content": "/// @brief Include to use operators to compare whether two textures or images are equal\n/// @file gli/comparison.hpp\n\n#pragma once\n\n#include \"image.hpp\"\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\nnamespace gli\n{\n\t/// Compare two images. Two images are equal when the date is the same.\n\tbool operator==(image const& ImageA, image const& ImageB);\n\n\t/// Compare two images. Two images are equal when the date is the same.\n\tbool operator!=(image const& ImageA, image const& ImageB);\n\n\t/// Compare two textures. Two textures are the same when the data, the format and the targets are the same.\n\tbool operator==(texture const& A, texture const& B);\n\n\t/// Compare two textures. Two textures are the same when the data, the format and the targets are the same.\n\tbool operator!=(texture const& A, texture const& B);\n}//namespace gli\n\n#include \"./core/comparison.inl\"\n"
  },
  {
    "path": "lib/gli/convert.hpp",
    "content": "/// @brief Include to copy textures, images or a subset of either textures or an images. These operations will cause memory allocations.\n/// @file gli/convert.hpp\n\n#pragma once\n\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\nnamespace gli\n{\n\t/// Convert texture data to a new format\n\t///\n\t/// @param Texture Source texture, the format must be uncompressed.\n\t/// @param Format Destination Texture format, it must be uncompressed.\n\ttemplate <typename texture_type>\n\ttexture_type convert(texture_type const& Texture, format Format);\n}//namespace gli\n\n#include \"./core/convert.inl\"\n"
  },
  {
    "path": "lib/gli/copy.hpp",
    "content": "/// @brief Include to copy textures or a subset of either textures. These operations are performed without memory allocations.\n/// @file gli/copy.hpp\n\n#pragma once\n\n#include \"type.hpp\"\n\nnamespace gli\n{\n\t/// Copy a specific image of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy(\n\t\ttexture_src_type const& TextureSrc, size_t LayerSrc, size_t FaceSrc, size_t LevelSrc,\n\t\ttexture_dst_type& TextureDst, size_t LayerDst, size_t FaceDst, size_t LevelDst);\n\n\t/// Copy a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy(\n\t\ttexture_src_type const& TextureSrc,\n\t\ttexture_dst_type& TextureDst);\n\n\t// Copy an entire level of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_level(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLevelSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLevelDst);\n\n\t// Copy multiple levels of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_level(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLevelSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLevelDst,\n\t\tsize_t LevelCount);\n\n\t// Copy an entire face of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_face(\n\t\ttexture_src_type const& TextureSrc, size_t BaseFaceSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseFaceDst);\n\n\t// Copy multiple faces of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_face(\n\t\ttexture_src_type const& TextureSrc, size_t BaseFaceSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseFaceDst,\n\t\tsize_t FaceCount);\n\n\t// Copy an entire layer of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_layer(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLayerSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLayerDst);\n\n\t// Copy multiple layers of a texture\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_layer(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLayerSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLayerDst,\n\t\tsize_t LayerCount);\n}//namespace gli\n\n#include \"./core/copy.inl\"\n"
  },
  {
    "path": "lib/gli/core/bc.hpp",
    "content": "/// @brief Include to compress and decompress the BC compression scheme\n/// @file gli/bc.hpp\n\n#pragma once\n\n#include \"./s3tc.hpp\"\n\nnamespace gli\n{\n\tnamespace detail\n\t{\n\t\ttypedef dxt1_block bc1_block;\n\t\ttypedef dxt3_block bc2_block;\n\t\ttypedef dxt5_block bc3_block;\n\n\t\tstruct bc4_block {\n\t\t\tglm::uint8 Red0;\n\t\t\tglm::uint8 Red1;\n\t\t\tglm::uint8 Bitmap[6];\n\t\t};\n\n\t\tstruct bc5_block {\n\t\t\tglm::uint8 Red0;\n\t\t\tglm::uint8 Red1;\n\t\t\tglm::uint8 RedBitmap[6];\n\t\t\tglm::uint8 Green0;\n\t\t\tglm::uint8 Green1;\n\t\t\tglm::uint8 GreenBitmap[6];\n\t\t};\n\n\t\tglm::vec4 decompress_bc1(const bc1_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_dxt1_block(const dxt1_block &Block);\n\n\t\tglm::vec4 decompress_bc2(const bc2_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_dxt3_block(const bc2_block &Block);\n\n\t\tglm::vec4 decompress_bc3(const bc3_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_bc3_block(const dxt5_block &Block);\n\n\t\tglm::vec4 decompress_bc4unorm(const bc4_block &Block, const extent2d &BlockTexelCoord);\n\t\tglm::vec4 decompress_bc4snorm(const bc4_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_bc4unorm_block(const bc4_block &Block);\n\t\ttexel_block4x4 decompress_bc4snorm_block(const bc4_block &Block);\n\n\t\tglm::vec4 decompress_bc5unorm(const bc5_block &Block, const extent2d &BlockTexelCoord);\n\t\tglm::vec4 decompress_bc5snorm(const bc5_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_bc5unorm_block(const bc5_block &Block);\n\t\ttexel_block4x4 decompress_bc5snorm_block(const bc5_block &Block);\n\t}//namespace detail\n}//namespace gli\n\n#include \"./bc.inl\"\n"
  },
  {
    "path": "lib/gli/core/bc.inl",
    "content": "#include <glm/ext/vector_packing.hpp>\n#include <glm/ext/scalar_uint_sized.hpp>\n\nnamespace gli\n{\n\tnamespace detail\n\t{\n\t\tinline glm::vec4 decompress_bc1(const bc1_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\treturn decompress_dxt1(Block, BlockTexelCoord);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc1_block(const bc1_block &Block)\n\t\t{\n\t\t\treturn decompress_dxt1_block(Block);\n\t\t}\n\n\t\tinline glm::vec4 decompress_bc2(const bc2_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\treturn decompress_dxt3(Block, BlockTexelCoord);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc2_block(const bc2_block &Block)\n\t\t{\n\t\t\treturn decompress_dxt3_block(Block);\n\t\t}\n\n\t\tinline glm::vec4 decompress_bc3(const bc3_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\treturn decompress_dxt5(Block, BlockTexelCoord);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc3_block(const bc3_block &Block)\n\t\t{\n\t\t\treturn decompress_dxt5_block(Block);\n\t\t}\n\n\t\tinline void create_single_channel_lookup_table(bool Interpolate6, float Min, float *LookupTable)\n\t\t{\n\t\t\tif(Interpolate6)\n\t\t\t{\n\t\t\t\tLookupTable[2] = (6.0f / 7.0f) * LookupTable[0] + (1.0f / 7.0f) * LookupTable[1];\n\t\t\t\tLookupTable[3] = (5.0f / 7.0f) * LookupTable[0] + (2.0f / 7.0f) * LookupTable[1];\n\t\t\t\tLookupTable[4] = (4.0f / 7.0f) * LookupTable[0] + (3.0f / 7.0f) * LookupTable[1];\n\t\t\t\tLookupTable[5] = (3.0f / 7.0f) * LookupTable[0] + (4.0f / 7.0f) * LookupTable[1];\n\t\t\t\tLookupTable[6] = (2.0f / 7.0f) * LookupTable[0] + (5.0f / 7.0f) * LookupTable[1];\n\t\t\t\tLookupTable[7] = (1.0f / 7.0f) * LookupTable[0] + (6.0f / 7.0f) * LookupTable[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tLookupTable[2] = (4.0f / 5.0f) * LookupTable[0] + (1.0f / 5.0f) * LookupTable[1];\n\t\t\t\tLookupTable[3] = (3.0f / 5.0f) * LookupTable[0] + (2.0f / 5.0f) * LookupTable[1];\n\t\t\t\tLookupTable[4] = (2.0f / 5.0f) * LookupTable[0] + (3.0f / 5.0f) * LookupTable[1];\n\t\t\t\tLookupTable[5] = (1.0f / 5.0f) * LookupTable[0] + (4.0f / 5.0f) * LookupTable[1];\n\t\t\t\tLookupTable[6] = Min;\n\t\t\t\tLookupTable[7] = 1.0f;\n\t\t\t}\n\t\t}\n\n\t\tinline void single_channel_bitmap_data_unorm(glm::uint8 Channel0, glm::uint8 Channel1, const glm::uint8 *ChannelBitmap, float *LookupTable, glm::uint64 &ContiguousBitmap)\n\t\t{\n\t\t\tLookupTable[0] = Channel0 / 255.0f;\n\t\t\tLookupTable[1] = Channel1 / 255.0f;\n\n\t\t\tcreate_single_channel_lookup_table(Channel0 > Channel1, 0.0f, LookupTable);\n\n\t\t\tContiguousBitmap = ChannelBitmap[0] | (ChannelBitmap[1] << 8) | (ChannelBitmap[2] << 16);\n\t\t\tContiguousBitmap |= glm::uint64(ChannelBitmap[3] | (ChannelBitmap[4] << 8) | (ChannelBitmap[5] << 16)) << 24;\n\t\t}\n\n\t\tinline void single_channel_bitmap_data_snorm(glm::uint8 Channel0, glm::uint8 Channel1, const glm::uint8 *ChannelBitmap, float *LookupTable, glm::uint64 &ContiguousBitmap)\n\t\t{\n\t\t\tLookupTable[0] = (Channel0 / 255.0f) * 2.0f - 1.0f;\n\t\t\tLookupTable[1] = (Channel1 / 255.0f) * 2.0f - 1.0f;\n\n\t\t\tcreate_single_channel_lookup_table(Channel0 > Channel1, -1.0f, LookupTable);\n\n\t\t\tContiguousBitmap = ChannelBitmap[0] | (ChannelBitmap[1] << 8) | (ChannelBitmap[2] << 16);\n\t\t\tContiguousBitmap |= glm::uint64(ChannelBitmap[3] | (ChannelBitmap[4] << 8) | (ChannelBitmap[5] << 16)) << 24;\n\t\t}\n\n\t\tinline void single_channel_bitmap_data_snorm(glm::uint8 Channel0, glm::uint32 Channel1, bool Interpolate6, const glm::uint8 *ChannelBitmap, float *LookupTable, glm::uint64 &ContiguousBitmap)\n\t\t{\n\t\t\tLookupTable[0] = (Channel0 / 255.0f) * 2.0f - 1.0f;\n\t\t\tLookupTable[1] = (Channel1 / 255.0f) * 2.0f - 1.0f;\n\n\t\t\tcreate_single_channel_lookup_table(Interpolate6, -1.0f, LookupTable);\n\n\t\t\tContiguousBitmap = ChannelBitmap[0] | (ChannelBitmap[1] << 8) | (ChannelBitmap[2] << 16);\n\t\t\tContiguousBitmap |= glm::uint64(ChannelBitmap[3] | (ChannelBitmap[4] << 8) | (ChannelBitmap[5] << 16)) << 24;\n\t\t}\n\n\t\tinline glm::vec4 decompress_bc4unorm(const bc4_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 Bitmap;\n\n\t\t\tsingle_channel_bitmap_data_unorm(Block.Red0, Block.Red1, Block.Bitmap, RedLUT, Bitmap);\n\n\t\t\tglm::uint8 RedIndex = (Bitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\t\t\treturn glm::vec4(RedLUT[RedIndex], 0.0f, 0.0f, 1.0f);\n\t\t}\n\n\t\tinline glm::vec4 decompress_bc4snorm(const bc4_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 Bitmap;\n\n\t\t\tsingle_channel_bitmap_data_snorm(Block.Red0, Block.Red1, Block.Bitmap, RedLUT, Bitmap);\n\n\t\t\tglm::uint8 RedIndex = (Bitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\t\t\treturn glm::vec4(RedLUT[RedIndex], 0.0f, 0.0f, 1.0f);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc4unorm_block(const bc4_block &Block)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 Bitmap;\n\n\t\t\tsingle_channel_bitmap_data_unorm(Block.Red0, Block.Red1, Block.Bitmap, RedLUT, Bitmap);\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 RedIndex = (Bitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = glm::vec4(RedLUT[RedIndex], 0.0f, 0.0f, 1.0f);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn TexelBlock;\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc4snorm_block(const bc4_block &Block)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 Bitmap;\n\n\t\t\tsingle_channel_bitmap_data_snorm(Block.Red0, Block.Red1, Block.Bitmap, RedLUT, Bitmap);\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 RedIndex = (Bitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = glm::vec4(RedLUT[RedIndex], 0.0f, 0.0f, 1.0f);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn TexelBlock;\n\t\t}\n\n\t\tinline glm::vec4 decompress_bc5unorm(const bc5_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 RedBitmap;\n\n\t\t\tsingle_channel_bitmap_data_unorm(Block.Red0, Block.Red1, Block.RedBitmap, RedLUT, RedBitmap);\n\t\t\tglm::uint8 RedIndex = (RedBitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\t\t\t\n\t\t\tfloat GreenLUT[8];\n\t\t\tglm::uint64 GreenBitmap;\n\n\t\t\tsingle_channel_bitmap_data_unorm(Block.Green0, Block.Green1, Block.GreenBitmap, GreenLUT, GreenBitmap);\n\t\t\tglm::uint8 GreenIndex = (GreenBitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\n\t\t\treturn glm::vec4(RedLUT[RedIndex], GreenLUT[GreenIndex], 0.0f, 1.0f);\n\t\t}\n\n\t\tinline glm::vec4 decompress_bc5snorm(const bc5_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 RedBitmap;\n\n\t\t\tsingle_channel_bitmap_data_snorm(Block.Red0, Block.Red1, Block.RedBitmap, RedLUT, RedBitmap);\n\t\t\tglm::uint8 RedIndex = (RedBitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\n\t\t\tfloat GreenLUT[8];\n\t\t\tglm::uint64 GreenBitmap;\n\n\t\t\tsingle_channel_bitmap_data_snorm(Block.Green0, Block.Green1, Block.GreenBitmap, GreenLUT, GreenBitmap);\n\t\t\tglm::uint8 GreenIndex = (GreenBitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\n\t\t\treturn glm::vec4(RedLUT[RedIndex], GreenLUT[GreenIndex], 0.0f, 1.0f);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc5unorm_block(const bc5_block &Block)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 RedBitmap;\n\n\t\t\tsingle_channel_bitmap_data_unorm(Block.Red0, Block.Red1, Block.RedBitmap, RedLUT, RedBitmap);\n\t\t\t\n\t\t\tfloat GreenLUT[8];\n\t\t\tglm::uint64 GreenBitmap;\n\n\t\t\tsingle_channel_bitmap_data_unorm(Block.Green0, Block.Green1, Block.GreenBitmap, GreenLUT, GreenBitmap);\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 RedIndex = (RedBitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tglm::uint8 GreenIndex = (GreenBitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = glm::vec4(RedLUT[RedIndex], GreenLUT[GreenIndex], 0.0f, 1.0f);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn TexelBlock;\n\t\t}\n\n\t\tinline texel_block4x4 decompress_bc5snorm_block(const bc5_block &Block)\n\t\t{\n\t\t\tfloat RedLUT[8];\n\t\t\tglm::uint64 RedBitmap;\n\n\t\t\tsingle_channel_bitmap_data_snorm(Block.Red0, Block.Red1, Block.RedBitmap, RedLUT, RedBitmap);\n\n\t\t\tfloat GreenLUT[8];\n\t\t\tglm::uint64 GreenBitmap;\n\n\t\t\tsingle_channel_bitmap_data_snorm(Block.Green0, Block.Green1, Block.Red0 > Block.Red1, Block.GreenBitmap, GreenLUT, GreenBitmap);\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 RedIndex = (RedBitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tglm::uint8 GreenIndex = (GreenBitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = glm::vec4(RedLUT[RedIndex], GreenLUT[GreenIndex], 0.0f, 1.0f);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn TexelBlock;\n\t\t}\n\n\t}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/clear.hpp",
    "content": "#pragma once\n\n#include \"convert_func.hpp\"\n\nnamespace gli{\nnamespace detail\n{\n\ttemplate <typename textureType, typename T, qualifier P>\n\tstruct clear\n\t{\n\t\tstatic void call(textureType & Texture, typename convert<textureType, T, P>::writeFunc Write, vec<4, T, P> const& Color)\n\t\t{\n\t\t\tGLI_ASSERT(Write);\n\n\t\t\ttexture const ConvertTexel(Texture.target(), Texture.format(), texture::extent_type(1), 1, 1, 1);\n\t\t\ttextureType Texel(ConvertTexel);\n\t\t\tWrite(Texel, typename textureType::extent_type(0), 0, 0, 0, Color);\n\n\t\t\tsize_t const BlockSize(block_size(Texture.format()));\n\t\t\tfor(size_t BlockIndex = 0, BlockCount = Texture.size() / BlockSize; BlockIndex < BlockCount; ++BlockIndex)\n\t\t\t\tmemcpy(static_cast<std::uint8_t*>(Texture.data()) + BlockSize * BlockIndex, Texel.data(), BlockSize);\n\t\t}\n\t};\n}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/clear.inl",
    "content": "namespace gli\n{\n\ttemplate <typename texture_type>\n\tinline void clear(texture_type& Texture)\n\t{\n\t\tTexture.clear();\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear(texture_type& Texture, gen_type const& BlockData)\n\t{\n\t\tTexture.clear(BlockData);\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear(texture_type& Texture, size_t Layer, size_t Face, size_t Level, gen_type const& BlockData)\n\t{\n\t\tTexture.clear(Layer, Face, Level, BlockData);\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear_level(texture_type& Texture, size_t BaseLevel, size_t LevelCount, gen_type const& BlockData)\n\t{\n\t\tfor(size_t LayerIndex = 0, LayerCount = Texture.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(size_t FaceIndex = 0, FaceCount = Texture.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(size_t LevelIndex = 0; LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tTexture.template clear<gen_type>(LayerIndex, FaceIndex, BaseLevel + LevelIndex, BlockData);\n\t\t}\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear_level(texture_type& Texture, size_t BaseLevel, gen_type const& BlockData)\n\t{\n\t\tclear_level(Texture, BaseLevel, 1, BlockData);\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear_face(texture_type& Texture, size_t BaseFace, size_t FaceCount, gen_type const& BlockData)\n\t{\n\t\tfor(size_t LayerIndex = 0, LayerCount = Texture.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(size_t FaceIndex = 0; FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(size_t LevelIndex = 0, LevelCount = Texture.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tTexture.template clear<gen_type>(LayerIndex, BaseFace + FaceIndex, LevelIndex, BlockData);\n\t\t}\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear_face(texture_type& Texture, size_t BaseFace, gen_type const& BlockData)\n\t{\n\t\tclear_face(Texture, BaseFace, 1, BlockData);\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear_layer(texture_type& Texture, size_t BaseLayer, size_t LayerCount, gen_type const& BlockData)\n\t{\n\t\tfor(size_t LayerIndex = 0; LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(size_t FaceIndex = 0, FaceCount = Texture.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(size_t LevelIndex = 0, LevelCount = Texture.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tTexture.template clear<gen_type>(LayerIndex + BaseLayer, FaceIndex, LevelIndex, BlockData);\n\t\t}\n\t}\n\n\ttemplate <typename texture_type, typename gen_type>\n\tinline void clear_layer(texture_type& Texture, size_t BaseLayer, gen_type const& BlockData)\n\t{\n\t\tclear_layer(Texture, BaseLayer, 1, BlockData);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/comparison.inl",
    "content": "#include <cstring>\n\nnamespace gli{\nnamespace detail\n{\n\tinline bool equalData(texture const & TextureA, texture const & TextureB)\n\t{\n\t\tGLI_ASSERT(TextureA.size() == TextureB.size());\n\n\t\tif(TextureA.data() == TextureB.data())\n\t\t\treturn true;\n\n\t\tfor(texture::size_type LayerIndex = 0, LayerCount = TextureA.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(texture::size_type FaceIndex = 0, FaceCount = TextureA.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(texture::size_type LevelIndex = 0, LevelCount = TextureA.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tvoid const* PointerA = TextureA.data(LayerIndex, FaceIndex, LevelIndex);\n\t\t\tvoid const* PointerB = TextureB.data(LayerIndex, FaceIndex, LevelIndex);\n\t\t\tGLI_ASSERT(TextureA.size(LevelIndex) == TextureB.size(LevelIndex));\n\t\t\tif(std::memcmp(PointerA, PointerB, TextureA.size(LevelIndex)) != 0)\n\t\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n}//namespace detail\n\n\tinline bool operator==(image const & ImageA, image const & ImageB)\n\t{\n\t\tif(!glm::all(glm::equal(ImageA.extent(), ImageB.extent())))\n\t\t\treturn false;\n\t\tif(ImageA.size() != ImageB.size())\n\t\t\treturn false;\n\n\t\treturn std::memcmp(ImageA.data(), ImageB.data(), ImageA.size()) == 0;\n\t}\n\n\tinline bool operator!=(image const & ImageA, image const & ImageB)\n\t{\n\t\tif(!glm::all(glm::equal(ImageA.extent(), ImageB.extent())))\n\t\t\treturn true;\n\t\tif(ImageA.size() != ImageB.size())\n\t\t\treturn true;\n\n\t\treturn std::memcmp(ImageA.data(), ImageB.data(), ImageA.size()) != 0;\n\t}\n\n\tinline bool equal(texture const & TextureA, texture const & TextureB)\n\t{\n\t\tif(TextureA.empty() && TextureB.empty())\n\t\t\treturn true;\n\t\tif(TextureA.empty() != TextureB.empty())\n\t\t\treturn false;\n\t\tif(TextureA.target() != TextureB.target())\n\t\t\treturn false;\n\t\tif(TextureA.layers() != TextureB.layers())\n\t\t\treturn false;\n\t\tif(TextureA.faces() != TextureB.faces())\n\t\t\treturn false;\n\t\tif(TextureA.levels() != TextureB.levels())\n\t\t\treturn false;\n\t\tif(TextureA.format() != TextureB.format())\n\t\t\treturn false;\n\t\tif(TextureA.size() != TextureB.size())\n\t\t\treturn false;\n\n\t\treturn detail::equalData(TextureA, TextureB);\n\t}\n\n\tinline bool notEqual(texture const & TextureA, texture const & TextureB)\n\t{\n\t\tif(TextureA.empty() && TextureB.empty())\n\t\t\treturn false;\n\t\tif(TextureA.empty() != TextureB.empty())\n\t\t\treturn true;\n\t\tif(TextureA.target() != TextureB.target())\n\t\t\treturn true;\n\t\tif(TextureA.layers() != TextureB.layers())\n\t\t\treturn true;\n\t\tif(TextureA.faces() != TextureB.faces())\n\t\t\treturn true;\n\t\tif(TextureA.levels() != TextureB.levels())\n\t\t\treturn true;\n\t\tif(TextureA.format() != TextureB.format())\n\t\t\treturn true;\n\t\tif(TextureA.size() != TextureB.size())\n\t\t\treturn true;\n\n\t\treturn !detail::equalData(TextureA, TextureB);\n\t}\n\n\tinline bool operator==(texture const & A, texture const & B)\n\t{\n\t\treturn gli::equal(A, B);\n\t}\n\n\tinline bool operator!=(texture const & A, texture const & B)\n\t{\n\t\treturn gli::notEqual(A, B);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/convert.inl",
    "content": "#include \"../core/convert_func.hpp\"\n\nnamespace gli\n{\n\ttemplate <typename texture_type>\n\tinline texture_type convert(texture_type const& Texture, format Format)\n\t{\n\t\ttypedef float T;\n\t\ttypedef typename texture::extent_type extent_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename extent_type::value_type component_type;\n\t\ttypedef typename detail::convert<texture_type, T, defaultp>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, defaultp>::writeFunc write_type;\n\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(has_decoder(Texture.format()) || !is_compressed(Texture.format()));\n\t\tGLI_ASSERT(!is_compressed(Format));\n\n\t\tfetch_type Fetch = detail::convert<texture_type, T, defaultp>::call(Texture.format()).Fetch;\n\t\twrite_type Write = detail::convert<texture_type, T, defaultp>::call(Format).Write;\n\n\t\ttexture Storage(Texture.target(), Format, Texture.texture::extent(), Texture.layers(), Texture.faces(), Texture.levels(), Texture.swizzles());\n\t\ttexture_type Copy(Storage);\n\n\t\tfor(size_type Layer = 0; Layer < Texture.layers(); ++Layer)\n\t\tfor(size_type Face = 0; Face < Texture.faces(); ++Face)\n\t\tfor(size_type Level = 0; Level < Texture.levels(); ++Level)\n\t\t{\n\t\t\textent_type const& Dimensions = Texture.texture::extent(Level);\n\n\t\t\tfor(component_type k = 0; k < Dimensions.z; ++k)\n\t\t\tfor(component_type j = 0; j < Dimensions.y; ++j)\n\t\t\tfor(component_type i = 0; i < Dimensions.x; ++i)\n\t\t\t{\n\t\t\t\ttypename texture_type::extent_type const Texelcoord(extent_type(i, j, k));\n\t\t\t\tWrite(\n\t\t\t\t\tCopy, Texelcoord, Layer, Face, Level,\n\t\t\t\t\tFetch(Texture, Texelcoord, Layer, Face, Level));\n\t\t\t}\n\t\t}\n\n\t\treturn texture_type(Copy);\n\t}\n\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/convert_func.hpp",
    "content": "#pragma once\n\n#include \"../type.hpp\"\n#include \"../texture1d.hpp\"\n#include \"../texture1d_array.hpp\"\n#include \"../texture2d.hpp\"\n#include \"../texture2d_array.hpp\"\n#include \"../texture3d.hpp\"\n#include \"../texture_cube.hpp\"\n#include \"../texture_cube_array.hpp\"\n#include \"./s3tc.hpp\"\n#include \"./bc.hpp\"\n#include <glm/gtc/packing.hpp>\n#include <glm/gtc/color_space.hpp>\n#include <limits>\n\nnamespace gli{\nnamespace detail\n{\n\tenum convertMode\n\t{\n\t\tCONVERT_MODE_DEFAULT,\n\t\tCONVERT_MODE_CAST,\n\t\tCONVERT_MODE_NORM,\n\t\tCONVERT_MODE_SRGB,\n\t\tCONVERT_MODE_HALF,\n\t\tCONVERT_MODE_RGB9E5,\n\t\tCONVERT_MODE_RG11B10F,\n\t\tCONVERT_MODE_RGB10A2UNORM,\n\t\tCONVERT_MODE_RGB10A2SNORM,\n\t\tCONVERT_MODE_RGB10A2USCALE,\n\t\tCONVERT_MODE_RGB10A2SSCALE,\n\t\tCONVERT_MODE_RGB10A2UINT,\n\t\tCONVERT_MODE_RGB10A2SINT,\n\t\tCONVERT_MODE_44UNORM,\n\t\tCONVERT_MODE_44SCALED,\n\t\tCONVERT_MODE_4444UNORM,\n\t\tCONVERT_MODE_4444SCALED,\n\t\tCONVERT_MODE_565UNORM,\n\t\tCONVERT_MODE_565SCALED,\n\t\tCONVERT_MODE_5551UNORM,\n\t\tCONVERT_MODE_5551SCALED,\n\t\tCONVERT_MODE_332UNORM,\n\t\tCONVERT_MODE_DXT1UNORM,\n\t\tCONVERT_MODE_DXT3UNORM,\n\t\tCONVERT_MODE_DXT5UNORM,\n\t\tCONVERT_MODE_BC1UNORM = CONVERT_MODE_DXT1UNORM,\n\t\tCONVERT_MODE_BC2UNORM = CONVERT_MODE_DXT3UNORM,\n\t\tCONVERT_MODE_BC3UNORM = CONVERT_MODE_DXT5UNORM,\n\t\tCONVERT_MODE_BC4UNORM,\n\t\tCONVERT_MODE_BC4SNORM,\n\t\tCONVERT_MODE_BC5UNORM,\n\t\tCONVERT_MODE_BC5SNORM\n\t};\n\n\ttemplate <typename textureType, typename genType>\n\tstruct accessFunc\n\t{};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture1d, genType>\n\t{\n\t\tstatic genType load(texture1d const & Texture, texture1d::extent_type const & TexelCoord, texture1d::size_type Layer, texture1d::size_type Face, texture1d::size_type Level)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0 && Face == 0);\n\t\t\treturn Texture.load<genType>(TexelCoord, Level);\n\t\t}\n\n\t\tstatic void store(texture1d & Texture, texture1d::extent_type const & TexelCoord, texture1d::size_type Layer, texture1d::size_type Face, texture1d::size_type Level, genType const & Texel)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0 && Face == 0);\n\t\t\tTexture.store<genType>(TexelCoord, Level, Texel);\n\t\t}\n\t};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture1d_array, genType>\n\t{\n\t\tstatic genType load(texture1d_array const& Texture, texture1d_array::extent_type const& TexelCoord, texture1d_array::size_type Layer, texture1d_array::size_type Face, texture1d_array::size_type Level)\n\t\t{\n\t\t\tGLI_ASSERT(Face == 0);\n\t\t\treturn Texture.load<genType>(TexelCoord, Layer, Level);\n\t\t}\n\n\t\tstatic void store(texture1d_array& Texture, texture1d_array::extent_type const& TexelCoord, texture1d_array::size_type Layer, texture1d_array::size_type Face, texture1d_array::size_type Level, genType const& Texel)\n\t\t{\n\t\t\tGLI_ASSERT(Face == 0);\n\t\t\tTexture.store<genType>(TexelCoord, Layer, Level, Texel);\n\t\t}\n\t};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture2d, genType>\n\t{\n\t\tstatic genType load(texture2d const & Texture, texture2d::extent_type const & TexelCoord, texture2d::size_type Layer, texture2d::size_type Face, texture2d::size_type Level)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0 && Face == 0);\n\t\t\treturn Texture.load<genType>(TexelCoord, Level);\n\t\t}\n\n\t\tstatic void store(texture2d & Texture, texture2d::extent_type const & TexelCoord, texture2d::size_type Layer, texture2d::size_type Face, texture2d::size_type Level, genType const & Texel)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0 && Face == 0);\n\t\t\tTexture.store<genType>(TexelCoord, Level, Texel);\n\t\t}\n\t};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture2d_array, genType>\n\t{\n\t\tstatic genType load(texture2d_array const & Texture, texture2d_array::extent_type const & TexelCoord, texture2d_array::size_type Layer, texture2d_array::size_type Face, texture2d_array::size_type Level)\n\t\t{\n\t\t\tGLI_ASSERT(Face == 0);\n\t\t\treturn Texture.load<genType>(TexelCoord, Layer, Level);\n\t\t}\n\n\t\tstatic void store(texture2d_array & Texture, texture2d_array::extent_type const & TexelCoord, texture2d_array::size_type Layer, texture2d_array::size_type Face, texture2d_array::size_type Level, genType const & Texel)\n\t\t{\n\t\t\tGLI_ASSERT(Face == 0);\n\t\t\tTexture.store<genType>(TexelCoord, Layer, Level, Texel);\n\t\t}\n\t};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture3d, genType>\n\t{\n\t\tstatic genType load(texture3d const & Texture, texture3d::extent_type const & TexelCoord, texture3d::size_type Layer, texture3d::size_type Face, texture3d::size_type Level)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0 && Face == 0);\n\t\t\treturn Texture.load<genType>(TexelCoord, Level);\n\t\t}\n\n\t\tstatic void store(texture3d & Texture, texture3d::extent_type const & TexelCoord, texture3d::size_type Layer, texture3d::size_type Face, texture3d::size_type Level, genType const & Texel)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0 && Face == 0);\n\t\t\tTexture.store<genType>(TexelCoord, Level, Texel);\n\t\t}\n\t};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture_cube, genType>\n\t{\n\t\tstatic genType load(texture_cube const& Texture, texture_cube::extent_type const& TexelCoord, texture_cube::size_type Layer, texture_cube::size_type Face, texture_cube::size_type Level)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0);\n\t\t\treturn Texture.load<genType>(TexelCoord, Face, Level);\n\t\t}\n\n\t\tstatic void store(texture_cube& Texture, texture_cube::extent_type const& TexelCoord, texture_cube::size_type Layer, texture_cube::size_type Face, texture_cube::size_type Level, genType const& Texel)\n\t\t{\n\t\t\tGLI_ASSERT(Layer == 0);\n\t\t\tTexture.store<genType>(TexelCoord, Face, Level, Texel);\n\t\t}\n\t};\n\n\ttemplate <typename genType>\n\tstruct accessFunc<texture_cube_array, genType>\n\t{\n\t\tstatic genType load(texture_cube_array const & Texture, texture_cube_array::extent_type const & TexelCoord, texture_cube_array::size_type Layer, texture_cube_array::size_type Face, texture_cube_array::size_type Level)\n\t\t{\n\t\t\treturn Texture.load<genType>(TexelCoord, Layer, Face, Level);\n\t\t}\n\n\t\tstatic void store(texture_cube_array & Texture, texture_cube_array::extent_type const & TexelCoord, texture_cube_array::size_type Layer, texture_cube_array::size_type Face, texture_cube_array::size_type Level, genType const & Texel)\n\t\t{\n\t\t\tTexture.store<genType>(TexelCoord, Layer, Face, Level, Texel);\n\t\t}\n\t};\n\n\t// convertFunc class\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P, convertMode mode = CONVERT_MODE_CAST, bool isSamplerFloat = false>\n\tstruct convertFunc\n\t{\n\t\ttypedef accessFunc<textureType, vec<L, T, P> > access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn make_vec4<retType, P>(vec<L, retType, P>(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, vec<L, T, P>(Texel));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P, bool isSamplerFloat>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_DEFAULT, isSamplerFloat>\n\t{\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_NORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, vec<L, T, P> > access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_NORM requires a float sampler\");\n\t\t\treturn make_vec4<retType, P>(compNormalize<retType>(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_NORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, compScale<T>(vec<L, retType, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_SRGB, true>\n\t{\n\t\ttypedef accessFunc<textureType, vec<L, T, P> > access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_SRGB requires a float sampler\");\n\t\t\treturn make_vec4<retType, P>(convertSRGBToLinear(compNormalize<retType>(access::load(Texture, TexelCoord, Layer, Face, Level))));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_SRGB requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, gli::compScale<T>(convertLinearToSRGB(vec<L, retType, P>(Texel))));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB9E5, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB9E5 requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackF3x9_E1x5(access::load(Texture, TexelCoord, Layer, Face, Level)), static_cast<retType>(1));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB9E5 requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packF3x9_E1x5(vec<3, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RG11B10F, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RG11B10F requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackF2x11_1x10(access::load(Texture, TexelCoord, Layer, Face, Level)), static_cast<retType>(1));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RG11B10F requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packF2x11_1x10(vec<3, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_HALF, true>\n\t{\n\t\ttypedef accessFunc<textureType, vec<L, uint16, P> > access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_HALF requires a float sampler\");\n\t\t\treturn make_vec4<retType, P>(vec<L, retType, P>(unpackHalf(access::load(Texture, TexelCoord, Layer, Face, Level))));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_HALF requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packHalf(vec<L, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_44UNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint8> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_44UNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(vec<2, retType, P>(unpackUnorm2x4(access::load(Texture, TexelCoord, Layer, Face, Level))), static_cast<retType>(0), static_cast<retType>(1));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_44UNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packUnorm2x4(vec<2, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_4444UNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint16> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_4444UNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackUnorm4x4(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_4444UNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packUnorm4x4(vec<4, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_565UNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint16> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_565UNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackUnorm1x5_1x6_1x5(access::load(Texture, TexelCoord, Layer, Face, Level)), static_cast<retType>(1));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_565UNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packUnorm1x5_1x6_1x5(vec<3, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_5551UNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint16> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_5551UNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackUnorm3x5_1x1(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_5551UNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packUnorm3x5_1x1(vec<4, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_332UNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint8> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_332UNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackUnorm2x3_1x2(access::load(Texture, TexelCoord, Layer, Face, Level)), static_cast<retType>(1));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_332UNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packUnorm2x3_1x2(vec<3, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB10A2UNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2UNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackUnorm3x10_1x2(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2UNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packUnorm3x10_1x2(vec<4, float, P>(Texel)));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB10A2SNORM, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2SNORM requires a float sampler\");\n\t\t\treturn vec<4, retType, P>(unpackSnorm3x10_1x2(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2SNORM requires a float sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packSnorm3x10_1x2(Texel));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB10A2USCALE, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2USCALE requires a float sampler\");\n\t\t\tglm::detail::u10u10u10u2 Unpack;\n\t\t\tUnpack.pack = access::load(Texture, TexelCoord, Layer, Face, Level);\n\t\t\treturn vec<4, retType, P>(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w);\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2USCALE requires a float sampler\");\n\t\t\tglm::detail::u10u10u10u2 Unpack;\n\t\t\tUnpack.data.x = static_cast<uint>(Texel.x);\n\t\t\tUnpack.data.y = static_cast<uint>(Texel.y);\n\t\t\tUnpack.data.z = static_cast<uint>(Texel.z);\n\t\t\tUnpack.data.w = static_cast<uint>(Texel.w);\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, Unpack.pack);\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB10A2SSCALE, true>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2SSCALE requires a float sampler\");\n\t\t\tglm::detail::i10i10i10i2 Unpack;\n\t\t\tUnpack.pack = access::load(Texture, TexelCoord, Layer, Face, Level);\n\t\t\treturn vec<4, retType, P>(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w);\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_RGB10A2SSCALE requires a float sampler\");\n\t\t\tglm::detail::i10i10i10i2 Unpack;\n\t\t\tUnpack.data.x = static_cast<int>(Texel.x);\n\t\t\tUnpack.data.y = static_cast<int>(Texel.y);\n\t\t\tUnpack.data.z = static_cast<int>(Texel.z);\n\t\t\tUnpack.data.w = static_cast<int>(Texel.w);\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, Unpack.pack);\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB10A2UINT, false>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_integer, \"CONVERT_MODE_RGB10A2UINT requires an integer sampler\");\n\t\t\treturn vec<4, retType, P>(unpackU3x10_1x2(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_integer, \"CONVERT_MODE_RGB10A2UINT requires an integer sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packU3x10_1x2(Texel));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_RGB10A2SINT, false>\n\t{\n\t\ttypedef accessFunc<textureType, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_integer, \"CONVERT_MODE_RGB10A2SINT requires an integer sampler\");\n\t\t\treturn vec<4, retType, P>(unpackI3x10_1x2(access::load(Texture, TexelCoord, Layer, Face, Level)));\n\t\t}\n\n\t\tstatic void write(textureType & Texture, typename textureType::extent_type const & TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_integer, \"CONVERT_MODE_RGB10A2SINT requires an integer sampler\");\n\t\t\taccess::store(Texture, TexelCoord, Layer, Face, Level, packI3x10_1x2(Texel));\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_DXT1UNORM, true>\n\t{\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_DXT1UNORM requires an float sampler\");\n\t\t\t\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\t\t\t\n\t\t\tconst dxt1_block *Data = Texture.template data<dxt1_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\t\t\t\n\t\t\tconst dxt1_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\n\t\t\treturn decompress_dxt1(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_DXT1UNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a DXT1 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_DXT3UNORM, true> {\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_DXT3UNORM requires an float sampler\");\n\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\n\t\t\tconst dxt3_block *Data = Texture.template data<dxt3_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\n\t\t\tconst dxt3_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\n\t\t\treturn decompress_dxt3(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_DXT3UNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a DXT3 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_DXT5UNORM, true> {\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_DXT5UNORM requires an float sampler\");\n\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\n\t\t\tconst dxt5_block *Data = Texture.template data<dxt5_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\n\t\t\tconst dxt5_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\n\t\t\treturn decompress_dxt5(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_DXT5UNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a DXT5 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_BC4UNORM, true> {\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC4UNORM requires an float sampler\");\n\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\n\t\t\tconst bc4_block *Data = Texture.template data<bc4_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\n\t\t\tconst bc4_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\t\t\t\n\t\t\treturn decompress_bc4unorm(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC4UNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a BC4 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_BC4SNORM, true> {\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC4SNORM requires an float sampler\");\n\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\n\t\t\tconst bc4_block *Data = Texture.template data<bc4_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\n\t\t\tconst bc4_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\n\t\t\treturn decompress_bc4snorm(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC4SNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a BC4 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_BC5UNORM, true> {\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC5UNORM requires an float sampler\");\n\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\n\t\t\tconst bc5_block *Data = Texture.template data<bc5_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\n\t\t\tconst bc5_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\n\t\t\treturn decompress_bc5unorm(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC5UNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a BC5 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename retType, length_t L, typename T, qualifier P>\n\tstruct convertFunc<textureType, retType, L, T, P, CONVERT_MODE_BC5SNORM, true> {\n\t\ttypedef accessFunc<gli::texture2d, uint32> access;\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent1d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent2d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tgli::extent3d TexelCoord3d(TexelCoord, 0);\n\t\t\treturn fetch(Texture, TexelCoord3d, Layer, Face, Level);\n\t\t}\n\n\t\tstatic vec<4, retType, P> fetch(textureType const& Texture, gli::extent3d const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC5SNORM requires an float sampler\");\n\n\t\t\tif(Texture.target() == gli::TARGET_1D || Texture.target() == gli::TARGET_1D_ARRAY)\n\t\t\t{\n\t\t\t\treturn glm::vec<4, retType, P>(0, 0, 0, 1);\n\t\t\t}\n\n\t\t\tconst bc5_block *Data = Texture.template data<bc5_block>(Layer, Face, Level);\n\t\t\tconst gli::extent3d &BlockExtent = block_extent(Texture.format());\n\t\t\tint WidthInBlocks = glm::max(1, Texture.extent(Level).x / BlockExtent.x);\n\t\t\tint BlocksInSlice = glm::max(1, Texture.extent(Level).y / BlockExtent.y) * WidthInBlocks;\n\t\t\tgli::extent3d BlockCoord(TexelCoord / BlockExtent);\n\t\t\tglm::ivec2 TexelCoordInBlock(TexelCoord.x - (BlockCoord.x * BlockExtent.x), TexelCoord.y - (BlockCoord.y * BlockExtent.y));\n\n\t\t\tconst bc5_block &Block = Data[BlockCoord.z * BlocksInSlice + (BlockCoord.y * WidthInBlocks + BlockCoord.x)];\n\n\t\t\treturn decompress_bc5snorm(Block, TexelCoordInBlock);\n\t\t}\n\n\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, retType, P> const & Texel)\n\t\t{\n\t\t\tstatic_assert(std::numeric_limits<retType>::is_iec559, \"CONVERT_MODE_BC5SNORM requires an float sampler\");\n\n\t\t\tGLI_ASSERT(\"Writing to single texel of a BC5 compressed image is not supported\");\n\t\t}\n\t};\n\n\ttemplate <typename textureType, typename samplerValType, qualifier P>\n\tstruct convert\n\t{\n\t\ttypedef vec<4, samplerValType, P>(*fetchFunc)(textureType const& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level);\n\t\ttypedef void(*writeFunc)(textureType & Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, samplerValType, P> const & Texel);\n\n\t\ttemplate <length_t L, typename T, convertMode mode>\n\t\tstruct conv\n\t\t{\n\t\t\tstatic vec<4, samplerValType, P> fetch(textureType const& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level)\n\t\t\t{\n\t\t\t\treturn convertFunc<textureType, samplerValType, L, T, P, mode, std::numeric_limits<samplerValType>::is_iec559>::fetch(Texture, TexelCoord, Layer, Face, Level);\n\t\t\t}\n\n\t\t\tstatic void write(textureType& Texture, typename textureType::extent_type const& TexelCoord, typename textureType::size_type Layer, typename textureType::size_type Face, typename textureType::size_type Level, vec<4, samplerValType, P> const & Texel)\n\t\t\t{\n\t\t\t\tconvertFunc<textureType, samplerValType, L, T, P, mode, std::numeric_limits<samplerValType>::is_iec559>::write(Texture, TexelCoord, Layer, Face, Level, Texel);\n\t\t\t}\n\t\t};\n\n\t\tstruct func\n\t\t{\n\t\t\tfetchFunc Fetch;\n\t\t\twriteFunc Write;\n\t\t};\n\n\t\tstatic func call(format Format)\n\t\t{\n\t\t\tstatic func Table[] =\n\t\t\t{\n\t\t\t\t{conv<2, u8, CONVERT_MODE_44UNORM>::fetch, conv<2, u8, CONVERT_MODE_44UNORM>::write},\t\t\t\t// FORMAT_RG4_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_4444UNORM>::fetch, conv<4, u8, CONVERT_MODE_4444UNORM>::write},\t\t\t// FORMAT_RGBA4_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_4444UNORM>::fetch, conv<4, u8, CONVERT_MODE_4444UNORM>::write},\t\t\t// FORMAT_BGRA4_UNORM\n\t\t\t\t{conv<3, u8, CONVERT_MODE_565UNORM>::fetch, conv<3, u8, CONVERT_MODE_565UNORM>::write},\t\t\t\t// FORMAT_R5G6B5_UNORM\n\t\t\t\t{conv<3, u8, CONVERT_MODE_565UNORM>::fetch, conv<3, u8, CONVERT_MODE_565UNORM>::write},\t\t\t\t// FORMAT_B5G6R5_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_5551UNORM>::fetch, conv<4, u8, CONVERT_MODE_5551UNORM>::write},\t\t\t// FORMAT_RGB5A1_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_5551UNORM>::fetch, conv<4, u8, CONVERT_MODE_5551UNORM>::write},\t\t\t// FORMAT_BGR5A1_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_5551UNORM>::fetch, conv<4, u8, CONVERT_MODE_5551UNORM>::write},\t\t\t// FORMAT_A1RGB5_UNORM\n\n\t\t\t\t{conv<1, u8, CONVERT_MODE_NORM>::fetch, conv<1, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_R8_UNORM\n\t\t\t\t{conv<1, i8, CONVERT_MODE_NORM>::fetch, conv<1, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_R8_SNORM\n\t\t\t\t{conv<1, u8, CONVERT_MODE_CAST>::fetch, conv<1, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_R8_USCALED\n\t\t\t\t{conv<1, i8, CONVERT_MODE_CAST>::fetch, conv<1, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_R8_SSCALED\n\t\t\t\t{conv<1, u8, CONVERT_MODE_CAST>::fetch, conv<1, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_R8_UINT\n\t\t\t\t{conv<1, i8, CONVERT_MODE_CAST>::fetch, conv<1, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_R8_SINT\n\t\t\t\t{conv<1, u8, CONVERT_MODE_SRGB>::fetch, conv<1, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_R8_SRGB\n\n\t\t\t\t{conv<2, u8, CONVERT_MODE_NORM>::fetch, conv<2, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_RG8_UNORM\n\t\t\t\t{conv<2, i8, CONVERT_MODE_NORM>::fetch, conv<2, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_RG8_SNORM\n\t\t\t\t{conv<2, u8, CONVERT_MODE_CAST>::fetch, conv<2, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RG8_USCALED\n\t\t\t\t{conv<2, i8, CONVERT_MODE_CAST>::fetch, conv<2, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RG8_SSCALED\n\t\t\t\t{conv<2, u8, CONVERT_MODE_CAST>::fetch, conv<2, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RG8_UINT\n\t\t\t\t{conv<2, i8, CONVERT_MODE_CAST>::fetch, conv<2, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RG8_SINT\n\t\t\t\t{conv<2, u8, CONVERT_MODE_SRGB>::fetch, conv<2, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_RG8_SRGB\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_NORM>::fetch, conv<3, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_RGB8_UNORM\n\t\t\t\t{conv<3, i8, CONVERT_MODE_NORM>::fetch, conv<3, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_RGB8_SNORM\n\t\t\t\t{conv<3, u8, CONVERT_MODE_CAST>::fetch, conv<3, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGB8_USCALED\n\t\t\t\t{conv<3, i8, CONVERT_MODE_CAST>::fetch, conv<3, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGB8_SSCALED\n\t\t\t\t{conv<3, u8, CONVERT_MODE_CAST>::fetch, conv<3, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGB8_UINT\n\t\t\t\t{conv<3, i8, CONVERT_MODE_CAST>::fetch, conv<3, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGB8_SINT\n\t\t\t\t{conv<3, u8, CONVERT_MODE_SRGB>::fetch, conv<3, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_RGB8_SRGB\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_NORM>::fetch, conv<3, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_BGR8_UNORM\n\t\t\t\t{conv<3, i8, CONVERT_MODE_NORM>::fetch, conv<3, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_BGR8_SNORM\n\t\t\t\t{conv<3, u8, CONVERT_MODE_CAST>::fetch, conv<3, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_BGR8_USCALED\n\t\t\t\t{conv<3, i8, CONVERT_MODE_CAST>::fetch, conv<3, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_BGR8_SSCALED\n\t\t\t\t{conv<3, u32, CONVERT_MODE_CAST>::fetch, conv<3, u32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_BGR8_UINT\n\t\t\t\t{conv<3, i32, CONVERT_MODE_CAST>::fetch, conv<3, i32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_BGR8_SINT\n\t\t\t\t{conv<3, u8, CONVERT_MODE_SRGB>::fetch, conv<3, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_BGR8_SRGB\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_NORM>::fetch, conv<4, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_RGBA8_UNORM\n\t\t\t\t{conv<4, i8, CONVERT_MODE_NORM>::fetch, conv<4, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_RGBA8_SNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_CAST>::fetch, conv<4, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGBA8_USCALED\n\t\t\t\t{conv<4, i8, CONVERT_MODE_CAST>::fetch, conv<4, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGBA8_SSCALED\n\t\t\t\t{conv<4, u8, CONVERT_MODE_CAST>::fetch, conv<4, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGBA8_UINT\n\t\t\t\t{conv<4, i8, CONVERT_MODE_CAST>::fetch, conv<4, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_RGBA8_SINT\n\t\t\t\t{conv<4, u8, CONVERT_MODE_SRGB>::fetch, conv<4, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_RGBA8_SRGB\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_NORM>::fetch, conv<4, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_BGRA8_UNORM\n\t\t\t\t{conv<4, i8, CONVERT_MODE_NORM>::fetch, conv<4, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_BGRA8_SNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_CAST>::fetch, conv<4, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_BGRA8_USCALED\n\t\t\t\t{conv<4, i8, CONVERT_MODE_CAST>::fetch, conv<4, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_BGRA8_SSCALED\n\t\t\t\t{conv<4, u8, CONVERT_MODE_CAST>::fetch, conv<4, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_BGRA8_UINT\n\t\t\t\t{conv<4, i8, CONVERT_MODE_CAST>::fetch, conv<4, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_BGRA8_SINT\n\t\t\t\t{conv<4, u8, CONVERT_MODE_SRGB>::fetch, conv<4, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_BGRA8_SRGB\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_NORM>::fetch, conv<4, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_ABGR8_UNORM\n\t\t\t\t{conv<4, i8, CONVERT_MODE_NORM>::fetch, conv<4, i8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_ABGR8_SNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_CAST>::fetch, conv<4, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_ABGR8_USCALED\n\t\t\t\t{conv<4, i8, CONVERT_MODE_CAST>::fetch, conv<4, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_ABGR8_SSCALED\n\t\t\t\t{conv<4, u8, CONVERT_MODE_CAST>::fetch, conv<4, u8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_ABGR8_UINT\n\t\t\t\t{conv<4, i8, CONVERT_MODE_CAST>::fetch, conv<4, i8, CONVERT_MODE_CAST>::write},\t\t\t\t\t\t// FORMAT_ABGR8_SINT\n\t\t\t\t{conv<4, u8, CONVERT_MODE_SRGB>::fetch, conv<4, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_ABGR8_SRGB\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_RGB10A2UNORM>::fetch, conv<4, u8, CONVERT_MODE_RGB10A2UNORM>::write},\t\t// FORMAT_RGB10A2_UNORM\n\t\t\t\t{conv<4, i8, CONVERT_MODE_RGB10A2SNORM>::fetch, conv<4, i8, CONVERT_MODE_RGB10A2SNORM>::write},\t\t// FORMAT_RGB10A2_SNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_RGB10A2USCALE>::fetch, conv<4, u8, CONVERT_MODE_RGB10A2USCALE>::write},\t// FORMAT_RGB10A2_USCALED\n\t\t\t\t{conv<4, i8, CONVERT_MODE_RGB10A2SSCALE>::fetch, conv<4, i8, CONVERT_MODE_RGB10A2SSCALE>::write},\t// FORMAT_RGB10A2_SSCALED\n\t\t\t\t{conv<4, u8, CONVERT_MODE_RGB10A2UINT>::fetch, conv<4, u8, CONVERT_MODE_RGB10A2UINT>::write},\t\t// FORMAT_RGB10A2_UINT\n\t\t\t\t{conv<4, i8, CONVERT_MODE_RGB10A2SINT>::fetch, conv<4, i8, CONVERT_MODE_RGB10A2SINT>::write},\t\t// FORMAT_RGB10A2_SINT\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_RGB10A2UNORM>::fetch, conv<4, u8, CONVERT_MODE_RGB10A2UNORM>::write},\t\t// FORMAT_BGR10A2_UNORM\n\t\t\t\t{conv<4, i8, CONVERT_MODE_RGB10A2SNORM>::fetch, conv<4, i8, CONVERT_MODE_RGB10A2SNORM>::write},\t\t// FORMAT_BGR10A2_SNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_RGB10A2USCALE>::fetch, conv<4, u8, CONVERT_MODE_RGB10A2USCALE>::write},\t// FORMAT_BGR10A2_USCALED\n\t\t\t\t{conv<4, i8, CONVERT_MODE_RGB10A2SSCALE>::fetch, conv<4, i8, CONVERT_MODE_RGB10A2SSCALE>::write},\t// FORMAT_BGR10A2_SSCALED\n\t\t\t\t{conv<4, u8, CONVERT_MODE_RGB10A2UINT>::fetch, conv<4, u8, CONVERT_MODE_RGB10A2UINT>::write},\t\t// FORMAT_BGR10A2_UINT\n\t\t\t\t{conv<4, i8, CONVERT_MODE_RGB10A2SINT>::fetch, conv<4, i8, CONVERT_MODE_RGB10A2SINT>::write},\t\t// FORMAT_BGR10A2_SINT\n\n\t\t\t\t{conv<1, u16, CONVERT_MODE_NORM>::fetch, conv<1, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_R16_UNORM_PACK16\n\t\t\t\t{conv<1, i16, CONVERT_MODE_NORM>::fetch, conv<1, i16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_R16_SNORM_PACK16\n\t\t\t\t{conv<1, u16, CONVERT_MODE_CAST>::fetch, conv<1, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R16_USCALED_PACK16\n\t\t\t\t{conv<1, i16, CONVERT_MODE_CAST>::fetch, conv<1, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R16_SSCALED_PACK16\n\t\t\t\t{conv<1, u16, CONVERT_MODE_CAST>::fetch, conv<1, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R16_UINT_PACK16\n\t\t\t\t{conv<1, i16, CONVERT_MODE_CAST>::fetch, conv<1, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R16_SINT_PACK16\n\t\t\t\t{conv<1, u16, CONVERT_MODE_HALF>::fetch, conv<1, u16, CONVERT_MODE_HALF>::write},\t\t\t\t\t// FORMAT_R16_SFLOAT_PACK16\n\n\t\t\t\t{conv<2, u16, CONVERT_MODE_NORM>::fetch, conv<2, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_RG16_UNORM_PACK16\n\t\t\t\t{conv<2, i16, CONVERT_MODE_NORM>::fetch, conv<2, i16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_RG16_SNORM_PACK16\n\t\t\t\t{conv<2, u16, CONVERT_MODE_CAST>::fetch, conv<2, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG16_USCALED_PACK16\n\t\t\t\t{conv<2, i16, CONVERT_MODE_CAST>::fetch, conv<2, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG16_SSCALED_PACK16\n\t\t\t\t{conv<2, u16, CONVERT_MODE_CAST>::fetch, conv<2, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG16_UINT_PACK16\n\t\t\t\t{conv<2, i16, CONVERT_MODE_CAST>::fetch, conv<2, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG16_SINT_PACK16\n\t\t\t\t{conv<2, u16, CONVERT_MODE_HALF>::fetch, conv<2, u16, CONVERT_MODE_HALF>::write},\t\t\t\t\t// FORMAT_RG16_SFLOAT_PACK16\n\n\t\t\t\t{conv<3, u16, CONVERT_MODE_NORM>::fetch, conv<3, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_RGB16_UNORM_PACK16\n\t\t\t\t{conv<3, i16, CONVERT_MODE_NORM>::fetch, conv<3, i16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_RGB16_SNORM_PACK16\n\t\t\t\t{conv<3, u16, CONVERT_MODE_CAST>::fetch, conv<3, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB16_USCALED_PACK16\n\t\t\t\t{conv<3, i16, CONVERT_MODE_CAST>::fetch, conv<3, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB16_SSCALED_PACK16\n\t\t\t\t{conv<3, u16, CONVERT_MODE_CAST>::fetch, conv<3, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB16_UINT_PACK16\n\t\t\t\t{conv<3, i16, CONVERT_MODE_CAST>::fetch, conv<3, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB16_SINT_PACK16\n\t\t\t\t{conv<3, u16, CONVERT_MODE_HALF>::fetch, conv<3, u16, CONVERT_MODE_HALF>::write},\t\t\t\t\t// FORMAT_RGB16_SFLOAT_PACK16\n\n\t\t\t\t{conv<4, u16, CONVERT_MODE_NORM>::fetch, conv<4, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_RGBA16_UNORM_PACK16\n\t\t\t\t{conv<4, i16, CONVERT_MODE_NORM>::fetch, conv<4, i16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_RGBA16_SNORM_PACK16\n\t\t\t\t{conv<4, u16, CONVERT_MODE_CAST>::fetch, conv<4, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA16_USCALED_PACK16\n\t\t\t\t{conv<4, i16, CONVERT_MODE_CAST>::fetch, conv<4, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA16_SSCALED_PACK16\n\t\t\t\t{conv<4, u16, CONVERT_MODE_CAST>::fetch, conv<4, u16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA16_UINT_PACK16\n\t\t\t\t{conv<4, i16, CONVERT_MODE_CAST>::fetch, conv<4, i16, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA16_SINT_PACK16\n\t\t\t\t{conv<4, u16, CONVERT_MODE_HALF>::fetch, conv<4, u16, CONVERT_MODE_HALF>::write},\t\t\t\t\t// FORMAT_RGBA16_SFLOAT_PACK16\n\n\t\t\t\t{conv<1, u32, CONVERT_MODE_CAST>::fetch, conv<1, u32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R32_UINT_PACK32\n\t\t\t\t{conv<1, i32, CONVERT_MODE_CAST>::fetch, conv<1, i32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R32_SINT_PACK32\n\t\t\t\t{conv<1, f32, CONVERT_MODE_CAST>::fetch, conv<1, f32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R32_SFLOAT_PACK32\n\n\t\t\t\t{conv<2, u32, CONVERT_MODE_CAST>::fetch, conv<2, u32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG32_UINT_PACK32\n\t\t\t\t{conv<2, i32, CONVERT_MODE_CAST>::fetch, conv<2, i32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG32_SINT_PACK32\n\t\t\t\t{conv<2, f32, CONVERT_MODE_CAST>::fetch, conv<2, f32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG32_SFLOAT_PACK32\n\n\t\t\t\t{conv<3, u32, CONVERT_MODE_CAST>::fetch, conv<3, u32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB32_UINT_PACK32\n\t\t\t\t{conv<3, i32, CONVERT_MODE_CAST>::fetch, conv<3, i32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB32_SINT_PACK32\n\t\t\t\t{conv<3, f32, CONVERT_MODE_CAST>::fetch, conv<3, f32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB32_SFLOAT_PACK32\n\n\t\t\t\t{conv<4, u32, CONVERT_MODE_CAST>::fetch, conv<4, u32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA32_UINT_PACK32\n\t\t\t\t{conv<4, i32, CONVERT_MODE_CAST>::fetch, conv<4, i32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA32_SINT_PACK32\n\t\t\t\t{conv<4, f32, CONVERT_MODE_CAST>::fetch, conv<4, f32, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA32_SFLOAT_PACK32\n\n\t\t\t\t{conv<1, u64, CONVERT_MODE_CAST>::fetch, conv<1, u64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R64_UINT_PACK64\n\t\t\t\t{conv<1, i64, CONVERT_MODE_CAST>::fetch, conv<1, i64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R64_SINT_PACK64\n\t\t\t\t{conv<1, f64, CONVERT_MODE_CAST>::fetch, conv<1, f64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_R64_SFLOAT_PACK64\n\n\t\t\t\t{conv<2, u64, CONVERT_MODE_CAST>::fetch, conv<2, u64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG64_UINT_PACK64\n\t\t\t\t{conv<2, i64, CONVERT_MODE_CAST>::fetch, conv<2, i64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG64_SINT_PACK64\n\t\t\t\t{conv<2, f64, CONVERT_MODE_CAST>::fetch, conv<2, f64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RG64_SFLOAT_PACK64\n\n\t\t\t\t{conv<3, u64, CONVERT_MODE_CAST>::fetch, conv<3, u64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB64_UINT_PACK64\n\t\t\t\t{conv<3, i64, CONVERT_MODE_CAST>::fetch, conv<3, i64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB64_SINT_PACK64\n\t\t\t\t{conv<3, f64, CONVERT_MODE_CAST>::fetch, conv<3, f64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGB64_SFLOAT_PACK64\n\n\t\t\t\t{conv<4, u64, CONVERT_MODE_CAST>::fetch, conv<4, u64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA64_UINT_PACK64\n\t\t\t\t{conv<4, i64, CONVERT_MODE_CAST>::fetch, conv<4, i64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA64_SINT_PACK64\n\t\t\t\t{conv<4, f64, CONVERT_MODE_CAST>::fetch, conv<4, f64, CONVERT_MODE_CAST>::write},\t\t\t\t\t// FORMAT_RGBA64_SFLOAT_PACK64\n\n\t\t\t\t{conv<1, u32, CONVERT_MODE_RG11B10F>::fetch, conv<1, u32, CONVERT_MODE_RG11B10F>::write},\t\t\t// FORMAT_RG11B10_UFLOAT\n\t\t\t\t{conv<1, u32, CONVERT_MODE_RGB9E5>::fetch, conv<1, u32, CONVERT_MODE_RGB9E5>::write},\t\t\t\t// FORMAT_RGB9E5_UFLOAT\n\n\t\t\t\t{conv<1, u16, CONVERT_MODE_DEFAULT>::fetch, conv<1, u16, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_D16_UNORM_PACK16\n\t\t\t\t{conv<1, u32, CONVERT_MODE_DEFAULT>::fetch, conv<1, u32, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_D24_UNORM\n\t\t\t\t{conv<1, f32, CONVERT_MODE_DEFAULT>::fetch, conv<1, f32, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_D32_SFLOAT_PACK32\n\t\t\t\t{conv<1, u8, CONVERT_MODE_DEFAULT>::fetch, conv<1, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_S8_UINT_PACK8\n\t\t\t\t{conv<2, u16, CONVERT_MODE_DEFAULT>::fetch, conv<2, u16, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_D16_UNORM_S8_UINT_PACK32\n\t\t\t\t{conv<2, u32, CONVERT_MODE_DEFAULT>::fetch, conv<2, u32, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_D24_UNORM_S8_UINT_PACK32\n\t\t\t\t{conv<2, u32, CONVERT_MODE_DEFAULT>::fetch, conv<2, u32, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_D32_SFLOAT_S8_UINT_PACK64\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DXT1UNORM>::fetch, conv<3, u8, CONVERT_MODE_DXT1UNORM>::write},\t\t\t// FORMAT_RGB_DXT1_UNORM_BLOCK8\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DXT1UNORM>::fetch, conv<3, u8, CONVERT_MODE_DXT1UNORM>::write},\t\t\t// FORMAT_RGB_DXT1_SRGB_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DXT1UNORM>::fetch, conv<4, u8, CONVERT_MODE_DXT1UNORM>::write},\t\t\t// FORMAT_RGBA_DXT1_UNORM_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DXT1UNORM>::fetch, conv<4, u8, CONVERT_MODE_DXT1UNORM>::write},\t\t\t// FORMAT_RGBA_DXT1_SRGB_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DXT3UNORM>::fetch, conv<4, u8, CONVERT_MODE_DXT3UNORM>::write},\t\t\t// FORMAT_RGBA_DXT3_UNORM_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DXT3UNORM>::fetch, conv<4, u8, CONVERT_MODE_DXT3UNORM>::write},\t\t\t// FORMAT_RGBA_DXT3_SRGB_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DXT5UNORM>::fetch, conv<4, u8, CONVERT_MODE_DXT5UNORM>::write},\t\t\t// FORMAT_RGBA_DXT5_UNORM_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DXT5UNORM>::fetch, conv<4, u8, CONVERT_MODE_DXT5UNORM>::write},\t\t\t// FORMAT_RGBA_DXT5_SRGB_BLOCK16\n\t\t\t\t{conv<1, u8, CONVERT_MODE_BC4UNORM>::fetch, conv<1, u8, CONVERT_MODE_BC4UNORM>::write},\t\t\t\t// FORMAT_R_ATI1N_UNORM_BLOCK8\n\t\t\t\t{conv<1, u8, CONVERT_MODE_BC4SNORM>::fetch, conv<1, i8, CONVERT_MODE_BC4SNORM>::write},\t\t\t\t// FORMAT_R_ATI1N_SNORM_BLOCK8\n\t\t\t\t{conv<2, u8, CONVERT_MODE_BC5UNORM>::fetch, conv<2, u8, CONVERT_MODE_BC5UNORM>::write},\t\t\t\t// FORMAT_RG_ATI2N_UNORM_BLOCK16\n\t\t\t\t{conv<2, u8, CONVERT_MODE_BC5SNORM>::fetch, conv<2, i8, CONVERT_MODE_BC5SNORM>::write},\t\t\t\t// FORMAT_RG_ATI2N_SNORM_BLOCK16\n\t\t\t\t{conv<3, f32, CONVERT_MODE_DEFAULT>::fetch, conv<3, f32, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_BP_UFLOAT_BLOCK16\n\t\t\t\t{conv<3, f32, CONVERT_MODE_DEFAULT>::fetch, conv<3, f32, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_BP_SFLOAT_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_BP_UNORM_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_BP_SRGB_BLOCK16\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_ETC2_UNORM_BLOCK8\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_ETC2_SRGB_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_ETC2_A1_UNORM_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_ETC2_A1_SRGB_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_ETC2_UNORM_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_ETC2_SRGB_BLOCK16\n\t\t\t\t{conv<1, u8, CONVERT_MODE_DEFAULT>::fetch, conv<1, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_R_EAC_UNORM_BLOCK8\n\t\t\t\t{conv<1, u8, CONVERT_MODE_DEFAULT>::fetch, conv<1, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_R_EAC_SNORM_BLOCK8\n\t\t\t\t{conv<2, u8, CONVERT_MODE_DEFAULT>::fetch, conv<2, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RG_EAC_UNORM_BLOCK16\n\t\t\t\t{conv<2, u8, CONVERT_MODE_DEFAULT>::fetch, conv<2, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RG_EAC_SNORM_BLOCK16\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_4x4_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_4x4_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_5x4_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_5x4_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_5x5_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_5x5_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_6x5_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_6x5_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_6x6_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_6x6_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_8x5_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_8x5_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_8x6_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_8x6_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_8x8_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_8x8_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x5_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x5_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x6_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x6_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x8_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x8_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x10_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_10x10_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_12x10_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_12x10_SRGB\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_12x12_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_ASTC_12x12_SRGB\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_PVRTC1_8X8_UNORM_BLOCK32\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_PVRTC1_8X8_SRGB_BLOCK32\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_PVRTC1_16X8_UNORM_BLOCK32\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_PVRTC1_16X8_SRGB_BLOCK32\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC1_8X8_UNORM_BLOCK32\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC1_8X8_SRGB_BLOCK32\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC1_16X8_UNORM_BLOCK32\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC1_16X8_SRGB_BLOCK32\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC2_4X4_UNORM_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC2_4X4_SRGB_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC2_8X4_UNORM_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_PVRTC2_8X4_SRGB_BLOCK8\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_ETC_UNORM_BLOCK8\n\t\t\t\t{conv<3, u8, CONVERT_MODE_DEFAULT>::fetch, conv<3, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGB_ATC_UNORM_BLOCK8\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_ATCA_UNORM_BLOCK16\n\t\t\t\t{conv<4, u8, CONVERT_MODE_DEFAULT>::fetch, conv<4, u8, CONVERT_MODE_DEFAULT>::write},\t\t\t\t// FORMAT_RGBA_ATCI_UNORM_BLOCK16\n\n\t\t\t\t{conv<1, u8, CONVERT_MODE_NORM>::fetch, conv<1, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_L8_UNORM_PACK8\n\t\t\t\t{conv<1, u8, CONVERT_MODE_NORM>::fetch, conv<1, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_A8_UNORM_PACK8\n\t\t\t\t{conv<2, u8, CONVERT_MODE_NORM>::fetch, conv<2, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_LA8_UNORM_PACK8\n\t\t\t\t{conv<1, u16, CONVERT_MODE_NORM>::fetch, conv<1, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_L16_UNORM_PACK16\n\t\t\t\t{conv<1, u16, CONVERT_MODE_NORM>::fetch, conv<1, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_A16_UNORM_PACK16\n\t\t\t\t{conv<2, u16, CONVERT_MODE_NORM>::fetch, conv<2, u16, CONVERT_MODE_NORM>::write},\t\t\t\t\t// FORMAT_LA16_UNORM_PACK16\n\n\t\t\t\t{conv<4, u8, CONVERT_MODE_NORM>::fetch, conv<4, u8, CONVERT_MODE_NORM>::write},\t\t\t\t\t\t// FORMAT_BGRX8_UNORM\n\t\t\t\t{conv<4, u8, CONVERT_MODE_SRGB>::fetch, conv<4, u8, CONVERT_MODE_SRGB>::write},\t\t\t\t\t\t// FORMAT_BGRX8_SRGB\n\n\t\t\t\t{conv<3, u8, CONVERT_MODE_332UNORM>::fetch, conv<3, u8, CONVERT_MODE_332UNORM>::write}\t\t\t\t// FORMAT_RG3B2_UNORM\n\t\t\t};\n\t\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == FORMAT_COUNT, \"Texel functions need to be updated\");\n\n\t\t\treturn Table[Format - FORMAT_FIRST];\n\t\t}\n\t};\n}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/coord.hpp",
    "content": "#pragma once\n\n#include \"../type.hpp\"\n\nnamespace gli{\nnamespace detail\n{\n\ttemplate <length_t L, typename T, qualifier Q>\n\tinline vec<L, bool, Q> in_interval(vec<L, T, Q> const& Value, vec<L, T, Q> const& Min, vec<L, T, Q> const& Max)\n\t{\n\t\treturn greaterThanEqual(Value, Min) && lessThanEqual(Value, Max);\n\t}\n\n\ttemplate <typename extent_type, typename normalized_type>\n\tstruct coord_nearest\n\t{\n\t\textent_type Texel;\n\t\ttypename extent_type::bool_type UseTexel;\n\t};\n\n\ttemplate <typename extent_type, typename normalized_type>\n\tinline coord_nearest<extent_type, normalized_type> make_coord_nearest(extent_type const& TexelExtent, normalized_type const& SampleCoord)\n\t{\n\t\tnormalized_type const TexelLast(normalized_type(TexelExtent) - normalized_type(1));\n\n\t\tcoord_nearest<extent_type, normalized_type> Coord;\n\t\tCoord.Texel = extent_type(round(SampleCoord * TexelLast));\n\t\tCoord.UseTexel = in_interval(Coord.Texel, extent_type(0), TexelExtent - 1);\n\t\treturn Coord;\n\t}\n\n\ttemplate <typename extent_type, typename normalized_type>\n\tstruct coord_linear\n\t{\n\t\textent_type TexelFloor;\n\t\textent_type TexelCeil;\n\t\tnormalized_type Blend;\n\t};\n\n\ttemplate <typename extent_type, typename normalized_type>\n\tstruct coord_linear_border : public coord_linear<extent_type, normalized_type>\n\t{\n\t\ttypename extent_type::bool_type UseTexelFloor;\n\t\ttypename extent_type::bool_type UseTexelCeil;\n\t};\n\n\ttemplate <typename extent_type, typename normalized_type>\n\tGLI_FORCE_INLINE coord_linear<extent_type, normalized_type> make_coord_linear(extent_type const& TexelExtent, normalized_type const& SampleCoord)\n\t{\n\t\tcoord_linear<extent_type, normalized_type> Coord;\n\n\t\tnormalized_type const TexelExtentF(TexelExtent);\n\t\tnormalized_type const TexelLast = TexelExtentF - normalized_type(1);\n\t\tnormalized_type const ScaledCoord(SampleCoord * TexelLast);\n\t\tnormalized_type const ScaledCoordFloor = normalized_type(extent_type(ScaledCoord));\n\t\tnormalized_type const ScaledCoordCeil = normalized_type(extent_type(ScaledCoord + normalized_type(0.5)));\n\t\t//normalized_type const ScaledCoordFloor(floor(ScaledCoord));\n\t\t//normalized_type const ScaledCoordCeil(ceil(ScaledCoord));\n\n\t\tCoord.Blend = ScaledCoord - ScaledCoordFloor;\n\t\tCoord.TexelFloor = extent_type(ScaledCoordFloor);\n\t\tCoord.TexelCeil = extent_type(ScaledCoordCeil);\n\n\t\treturn Coord;\n\t}\n\n\ttemplate <typename extent_type, typename normalized_type>\n\tGLI_FORCE_INLINE coord_linear_border<extent_type, normalized_type> make_coord_linear_border(extent_type const& TexelExtent, normalized_type const& SampleCoord)\n\t{\n\t\tcoord_linear_border<extent_type, normalized_type> Coord;\n\n\t\tnormalized_type const TexelExtentF(TexelExtent);\n\t\tnormalized_type const TexelLast = TexelExtentF - normalized_type(1);\n\t\tnormalized_type const ScaledCoord(SampleCoord * TexelLast);\n\t\tnormalized_type const ScaledCoordFloor(floor(ScaledCoord));\n\t\tnormalized_type const ScaledCoordCeil(ceil(ScaledCoord));\n\n\t\tCoord.Blend = ScaledCoord - ScaledCoordFloor;\n\t\tCoord.TexelFloor = extent_type(ScaledCoordFloor);\n\t\tCoord.TexelCeil = extent_type(ScaledCoordCeil);\n\t\tCoord.UseTexelFloor = in_interval(Coord.TexelFloor, extent_type(0), TexelExtent - 1);\n\t\tCoord.UseTexelCeil = in_interval(Coord.TexelCeil, extent_type(0), TexelExtent - 1);\n\n\t\treturn Coord;\n\t}\n}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/copy.inl",
    "content": "#include \"../type.hpp\"\n#include <cstring>\n\nnamespace gli\n{\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t LayerSrc, size_t FaceSrc, size_t LevelSrc,\n\t\ttexture_dst_type& TextureDst, size_t LayerDst, size_t FaceDst, size_t LevelDst\n\t)\n\t{\n\t\tTextureDst.copy(TextureSrc, LayerSrc, FaceSrc, LevelSrc, LayerDst, FaceDst, LevelDst);\n\t}\n\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy\n\t(\n\t\ttexture_src_type const& TextureSrc,\n\t\ttexture_dst_type& TextureDst\n\t)\n\t{\n\t\tcopy_layer(TextureSrc, 0, TextureDst, 0, TextureDst.layers());\n\t}\n\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_level\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLevelSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLevelDst,\n\t\tsize_t LevelCount\n\t)\n\t{\n\t\tfor(size_t LayerIndex = 0, LayerCount = TextureSrc.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(size_t FaceIndex = 0, FaceCount = TextureSrc.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(size_t LevelIndex = 0; LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tTextureDst.copy(\n\t\t\t\tTextureSrc,\n\t\t\t\tLayerIndex, FaceIndex, BaseLevelSrc + LevelIndex,\n\t\t\t\tLayerIndex, FaceIndex, BaseLevelDst + LevelIndex);\n\t\t}\n\t}\n\t\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_level\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLevelSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLevelDst\n\t)\n\t{\n\t\tcopy_level(TextureSrc, BaseLevelSrc, TextureDst, BaseLevelDst, 1);\n\t}\n\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_face\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t BaseFaceSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseFaceDst,\n\t\tsize_t FaceCount\n\t)\n\t{\n\t\tfor(size_t LayerIndex = 0, LayerCount = TextureSrc.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(size_t FaceIndex = 0; FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(size_t LevelIndex = 0, LevelCount = TextureSrc.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tTextureDst.copy(\n\t\t\t\tTextureSrc,\n\t\t\t\tLayerIndex, BaseFaceSrc + FaceIndex, LevelIndex,\n\t\t\t\tLayerIndex, BaseFaceDst + FaceIndex, LevelIndex);\n\t\t}\n\t}\n\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_face\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t BaseFaceSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseFaceDst\n\t)\n\t{\n\t\tcopy_face(TextureSrc, BaseFaceSrc, TextureDst, BaseFaceDst, 1);\n\t}\n\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_layer\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLayerSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLayerDst,\n\t\tsize_t LayerCount\n\t)\n\t{\n\t\tfor(size_t LayerIndex = 0; LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(size_t FaceIndex = 0, FaceCount = TextureSrc.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\tfor(size_t LevelIndex = 0, LevelCount = TextureSrc.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t{\n\t\t\tTextureDst.copy(\n\t\t\t\tTextureSrc,\n\t\t\t\tBaseLayerSrc + LayerIndex, FaceIndex, LevelIndex,\n\t\t\t\tBaseLayerDst + LayerIndex, FaceIndex, LevelIndex);\n\t\t}\n\t}\n\n\ttemplate <typename texture_src_type, typename texture_dst_type>\n\tvoid copy_layer\n\t(\n\t\ttexture_src_type const& TextureSrc, size_t BaseLayerSrc,\n\t\ttexture_dst_type& TextureDst, size_t BaseLayerDst\n\t)\n\t{\n\t\tcopy_layer(TextureSrc, BaseLayerSrc, TextureDst, BaseLayerDst, 1);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/dummy.cpp",
    "content": "int main()\n{\n\n}\n"
  },
  {
    "path": "lib/gli/core/duplicate.inl",
    "content": "namespace gli{\nnamespace detail\n{\n\tinline void duplicate_images\n\t(\n\t\ttexture const & Src, texture & Dst,\n\t\ttexture::size_type BaseLayer, texture::size_type MaxLayer,\n\t\ttexture::size_type BaseFace, texture::size_type MaxFace,\n\t\ttexture::size_type BaseLevel, texture::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLayer >= 0 && BaseLayer <= MaxLayer && MaxLayer < Src.layers());\n\t\tGLI_ASSERT(BaseFace >= 0 && BaseFace <= MaxFace && MaxFace < Src.faces());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel <= MaxLevel && MaxLevel < Src.levels());\n\n\t\ttexture::size_type LevelsSize = 0;\n\t\tfor(texture::size_type LevelIndex = 0; LevelIndex < MaxLevel - BaseLevel + 1; ++LevelIndex)\n\t\t{\n\t\t\tGLI_ASSERT(Dst.size(LevelIndex) == Src.size(LevelIndex));\n\t\t\tLevelsSize += Dst.size(LevelIndex);\n\t\t}\n\n\t\tfor(texture::size_type LayerIndex = 0, LayerCount = MaxLayer - BaseLayer + 1; LayerIndex < LayerCount; ++LayerIndex)\n\t\tfor(texture::size_type FaceIndex = 0, FaceCount = MaxFace - BaseFace + 1; FaceIndex < FaceCount; ++FaceIndex)\n\t\t{\n\t\t\tmemcpy(Dst.data(LayerIndex, FaceIndex, BaseLevel), Src.data(BaseLayer + LayerIndex, BaseFace + FaceIndex, BaseLevel), LevelsSize);\n\t\t}\n\t}\n}//namespace detail\n\n\tinline image duplicate(image const & Image)\n\t{\n\t\timage Result(Image.format(), Image.extent());\n\n\t\tmemcpy(Result.data(), Image.data(), Image.size());\n\t\t\n\t\treturn Result;\n\t}\n\n\ttemplate <>\n\tinline texture duplicate(texture const & Texture)\n\t{\n\t\ttexture Duplicate(\n\t\t\tTexture.target(),\n\t\t\tTexture.format(),\n\t\t\tTexture.extent(),\n\t\t\tTexture.layers(),\n\t\t\tTexture.faces(),\n\t\t\tTexture.levels());\n\n\t\tdetail::duplicate_images(\n\t\t\tTexture, Duplicate,\n\t\t\t0, Texture.layers() - 1,\n\t\t\t0, Texture.faces() - 1,\n\t\t\t0, Texture.levels() - 1);\n\n\t\treturn Duplicate;\n\t}\n\n\ttemplate <typename texType>\n\tinline texture duplicate(texType const & Texture)\n\t{\n\t\ttexture Duplicate(\n\t\t\tTexture.target(),\n\t\t\tTexture.format(),\n\t\t\tTexture.texture::extent(),\n\t\t\tTexture.layers(),\n\t\t\tTexture.faces(),\n\t\t\tTexture.levels());\n\n\t\tdetail::duplicate_images(\n\t\t\tTexture, Duplicate,\n\t\t\t0, Texture.layers() - 1,\n\t\t\t0, Texture.faces() - 1,\n\t\t\t0, Texture.levels() - 1);\n\n\t\treturn Duplicate;\n\t}\n\n\ttemplate <typename texType>\n\tinline texture duplicate(texType const & Texture, typename texType::format_type Format)\n\t{\n\t\tGLI_ASSERT(block_size(Texture.format()) == block_size(Format));\n\n\t\ttexture Duplicate(\n\t\t\tTexture.target(),\n\t\t\tFormat,\n\t\t\tTexture.extent(),\n\t\t\tTexture.layers(),\n\t\t\tTexture.faces(),\n\t\t\tTexture.levels());\n\n\t\tdetail::duplicate_images(\n\t\t\tTexture, Duplicate,\n\t\t\t0, Texture.layers() - 1,\n\t\t\t0, Texture.faces() - 1,\n\t\t\t0, Texture.levels() - 1);\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture1d const & Texture,\n\t\ttexture1d::size_type BaseLevel, texture1d::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLevel < Texture.levels());\n\t\tGLI_ASSERT(MaxLevel < Texture.levels());\n\t\n\t\ttexture1d Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture.extent(BaseLevel),\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tmemcpy(Duplicate.data(), Texture.data(0, 0, BaseLevel), Duplicate.size());\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture1d_array const & Texture,\n\t\ttexture1d_array::size_type BaseLayer, texture1d_array::size_type MaxLayer,\n\t\ttexture1d_array::size_type BaseLevel, texture1d_array::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLevel < Texture.levels());\n\t\tGLI_ASSERT(MaxLevel < Texture.levels());\n\t\tGLI_ASSERT(BaseLayer <= MaxLayer);\n\t\tGLI_ASSERT(BaseLayer < Texture.layers());\n\t\tGLI_ASSERT(MaxLayer < Texture.layers());\n\n\t\ttexture1d_array Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture[BaseLayer].extent(BaseLevel),\n\t\t\tMaxLayer - BaseLayer + 1,\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tfor(texture1d_array::size_type Layer = 0; Layer < Duplicate.layers(); ++Layer)\n\t\t\tmemcpy(Duplicate.data(Layer, 0, 0), Texture.data(Layer + BaseLayer, 0, BaseLevel), Duplicate[Layer].size());\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture2d const & Texture,\n\t\ttexture2d::size_type BaseLevel, texture2d::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLevel < Texture.levels());\n\t\tGLI_ASSERT(MaxLevel < Texture.levels());\n\t\n\t\ttexture2d Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture.extent(BaseLevel),\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tmemcpy(Duplicate.data(), Texture.data(0, 0, BaseLevel), Duplicate.size());\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture2d_array const & Texture,\n\t\ttexture2d_array::size_type BaseLayer, texture2d_array::size_type MaxLayer,\n\t\ttexture2d_array::size_type BaseLevel, texture2d_array::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLevel < Texture.levels());\n\t\tGLI_ASSERT(MaxLevel < Texture.levels());\n\t\tGLI_ASSERT(BaseLayer <= MaxLayer);\n\t\tGLI_ASSERT(BaseLayer < Texture.layers());\n\t\tGLI_ASSERT(MaxLayer < Texture.layers());\n\n\t\ttexture2d_array Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture.extent(BaseLevel),\n\t\t\tMaxLayer - BaseLayer + 1,\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tfor(texture2d_array::size_type Layer = 0; Layer < Duplicate.layers(); ++Layer)\n\t\t\tmemcpy(Duplicate.data(Layer, 0, 0), Texture.data(Layer + BaseLayer, 0, BaseLevel), Duplicate[Layer].size());\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture3d const & Texture,\n\t\ttexture3d::size_type BaseLevel, texture3d::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLevel < Texture.levels());\n\t\tGLI_ASSERT(MaxLevel < Texture.levels());\n\n\t\ttexture3d Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture.extent(BaseLevel),\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tmemcpy(Duplicate.data(), Texture.data(0, 0, BaseLevel), Duplicate.size());\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture_cube const & Texture,\n\t\ttexture_cube::size_type BaseFace, texture_cube::size_type MaxFace,\n\t\ttexture_cube::size_type BaseLevel, texture_cube::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && BaseLevel <= MaxLevel && MaxLevel < Texture.levels());\n\t\tGLI_ASSERT(BaseFace <= MaxFace);\n\t\tGLI_ASSERT(BaseFace < Texture.faces());\n\t\tGLI_ASSERT(MaxFace < Texture.faces());\n\n\t\ttexture_cube Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture[BaseFace].extent(BaseLevel),\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tfor(texture_cube::size_type Face = 0; Face < Duplicate.faces(); ++Face)\n\t\t\tmemcpy(Duplicate[Face].data(), Texture[Face + BaseFace][BaseLevel].data(), Duplicate[Face].size());\n\n\t\treturn Duplicate;\n\t}\n\n\tinline texture duplicate\n\t(\n\t\ttexture_cube_array const & Texture,\n\t\ttexture_cube_array::size_type BaseLayer, texture_cube_array::size_type MaxLayer,\n\t\ttexture_cube_array::size_type BaseFace, texture_cube_array::size_type MaxFace,\n\t\ttexture_cube_array::size_type BaseLevel, texture_cube_array::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLevel < Texture.levels());\n\t\tGLI_ASSERT(MaxLevel < Texture.levels());\n\t\tGLI_ASSERT(BaseFace <= MaxFace);\n\t\tGLI_ASSERT(BaseFace < Texture.faces());\n\t\tGLI_ASSERT(MaxFace < Texture.faces());\n\t\tGLI_ASSERT(BaseLayer <= MaxLayer);\n\t\tGLI_ASSERT(BaseLayer < Texture.layers());\n\t\tGLI_ASSERT(MaxLayer < Texture.layers());\n\n\t\ttexture_cube_array Duplicate(\n\t\t\tTexture.format(),\n\t\t\tTexture[BaseLayer][BaseFace].extent(BaseLevel),\n\t\t\tMaxLayer - BaseLayer + 1,\n\t\t\tMaxLevel - BaseLevel + 1);\n\n\t\tfor(texture_cube_array::size_type Layer = 0; Layer < Duplicate.layers(); ++Layer)\n\t\tfor(texture_cube_array::size_type Face = 0; Face < Duplicate[Layer].faces(); ++Face)\n\t\t\tmemcpy(Duplicate[Layer][Face].data(), Texture[Layer + BaseLayer][Face + BaseFace][BaseLevel].data(), Duplicate[Layer][Face].size());\n\n\t\treturn Duplicate;\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/dx.inl",
    "content": "#include <functional>\n\nnamespace gli\n{\n\tinline dx::dx()\n\t{\n\t\tstatic format const Table[] =\n\t\t{\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RG4_UNORM_GLI, glm::u32vec4(0x000F, 0x00F0, 0x0000, 0x0000)},\t\t\t\t\t\t//FORMAT_RG4_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA4_UNORM_GLI, glm::u32vec4(0x000F, 0x00F0, 0x0F00, 0xF000)},\t\t\t\t\t\t//FORMAT_RGBA4_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_A4R4G4B4, DXGI_FORMAT_B4G4R4A4_UNORM, glm::u32vec4(0x0F00, 0x00F0, 0x000F, 0xF000)},\t\t\t\t\t//FORMAT_BGRA4_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R5G6B5_UNORM_GLI, glm::u32vec4(0x001f, 0x07e0, 0xf800, 0x0000)},\t\t\t\t\t\t//FORMAT_R5G6B5_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_R5G6B5, DXGI_FORMAT_B5G6R5_UNORM, glm::u32vec4(0xf800, 0x07e0, 0x001f, 0x0000)},\t\t\t\t\t\t//FORMAT_B5G6R5_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R5G5B5A1_UNORM_GLI, glm::u32vec4(0x001f, 0x03e0, 0x7c00, 0x8000)},\t\t\t\t\t//FORMAT_RGB5A1_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_A1R5G5B5, DXGI_FORMAT_B5G5R5A1_UNORM, glm::u32vec4(0x7c00, 0x03e0, 0x001f, 0x8000)},\t\t\t\t\t//FORMAT_BGR5A1_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_A1B5G5R5_UNORM_GLI, glm::u32vec4(0x7c00, 0x03e0, 0x001f, 0x8000)},\t\t\t\t\t//FORMAT_A1RGB5_UNORM,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8_UNORM, glm::u32vec4(0x00FF0000, 0x00000000, 0x00000000, 0x00000000)},\t\t\t\t//FORMAT_R8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8_SNORM, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8_USCALED_GLI, glm::u32vec4(0x00FF0000, 0x00000000, 0x00000000, 0x00000000)},\t\t//FORMAT_R8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SRGB,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8_UNORM, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x00000000, 0x00000000)},\t\t\t//FORMAT_RG8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8_SNORM, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8_USCALED_GLI, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x00000000, 0x00000000)},\t\t//FORMAT_RG8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SRGB,\n\n\t\t\t{DDPF_RGB, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_UNORM_GLI, glm::u32vec4(0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)},\t\t//FORMAT_RGB8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_SNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SRGB,\n\n\t\t\t{DDPF_RGB, D3DFMT_R8G8B8, DXGI_FORMAT_B8G8R8_UNORM_GLI, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)},\t\t//FORMAT_BGR8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8_SNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SRGB,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8B8A8_UNORM, glm::u32vec4(0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)},\t\t//FORMAT_RGBA8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8B8A8_SNORM, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8B8A8_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8B8A8_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SRGB,\n\n\t\t\t{DDPF_RGBA, D3DFMT_A8R8G8B8, DXGI_FORMAT_B8G8R8A8_UNORM, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)},\t//FORMAT_BGRA8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8A8_SNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGRA8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8A8_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGRA8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8A8_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGRA8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8A8_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGRA8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B8G8R8A8_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGRA8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)},\t//FORMAT_BGRA8_SRGB,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_UNORM_GLI, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)},\t\t\t\t//FORMAT_ABGR8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_SNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_ABGR8_SNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_ABGR8_USCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_ABGR8_SSCALED,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_ABGR8_UINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_ABGR8_SINT,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R8G8B8A8_PACK_SRGB_GLI, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)},\t\t\t\t//FORMAT_ABGR8_SRGB,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R10G10B10A2_UNORM, glm::u32vec4(0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000)},\t\t//FORMAT_RGB10A2_UNORM_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R10G10B10A2_SNORM_GLI, glm::u32vec4(0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000)},\t//FORMAT_RGB10A2_SNORM_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R10G10B10A2_USCALED_GLI, glm::u32vec4(0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000)},\t//FORMAT_RGB10A2_USCALED_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R10G10B10A2_SSCALED_GLI, glm::u32vec4(0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000)},\t//FORMAT_RGB10A2_SSCALED_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R10G10B10A2_UINT, glm::u32vec4(0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000)},\t\t\t//FORMAT_RGB10A2_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R10G10B10A2_SINT_GLI, glm::u32vec4(0x000003FF, 0x000FFC00, 0x3FF00000, 0xC0000000)},\t\t//FORMAT_RGB10A2_SINT_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B10G10R10A2_UNORM_GLI, glm::u32vec4(0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)},\t//FORMAT_BGR10A2_UNORM_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B10G10R10A2_SNORM_GLI, glm::u32vec4(0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)},\t//FORMAT_BGR10A2_SNORM_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B10G10R10A2_USCALED_GLI, glm::u32vec4(0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)},\t//FORMAT_BGR10A2_USCALED_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B10G10R10A2_SSCALED_GLI, glm::u32vec4(0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)},\t//FORMAT_BGR10A2_SSCALED_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B10G10R10A2_UINT_GLI, glm::u32vec4(0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)},\t\t//FORMAT_BGR10A2_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_B10G10R10A2_SINT_GLI, glm::u32vec4(0x3FF00000, 0x000FFC00, 0x000003FF, 0xC0000000)},\t\t//FORMAT_BGR10A2_SINT_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16_UNORM, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x00000000)},\t\t\t//FORMAT_R16_UNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16_SNORM, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x00000000)},\t\t\t//FORMAT_R16_SNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16_USCALED_GLI, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x00000000)},\t\t//FORMAT_R16_USCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16_SSCALED_GLI, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x00000000)},\t\t//FORMAT_R16_SSCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16_UINT, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x0000000)},\t\t\t\t//FORMAT_R16_UINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16_SINT, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x0000000)},\t\t\t\t//FORMAT_R16_SINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_R16F, DXGI_FORMAT_R16_FLOAT, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x0000000)},\t\t\t\t//FORMAT_R16_SFLOAT_PACK16,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_G16R16, DXGI_FORMAT_R16G16_UNORM, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t\t//FORMAT_RG16_UNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16G16_SNORM, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t\t\t//FORMAT_RG16_SNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16_USCALED_GLI, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t//FORMAT_RG16_USCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16_SSCALED_GLI, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t//FORMAT_RG16_SSCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16G16_UINT, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t\t\t//FORMAT_RG16_UINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16G16_SINT, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t\t\t//FORMAT_RG16_SINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_G16R16F, DXGI_FORMAT_R16G16_FLOAT, glm::u32vec4(0x0000FFFF, 0xFFFF0000, 0x00000000, 0x00000000)},\t\t//FORMAT_RG16_SFLOAT_PACK16,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_UNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_SNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_SNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_USCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_SSCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_UINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_SINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16_FLOAT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB16_SFLOAT_PACK16,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_A16B16G16R16, DXGI_FORMAT_R16G16B16A16_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_UNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16G16B16A16_SNORM, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16A16_USCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_USCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R16G16B16A16_SSCALED_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SSCALED_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16G16B16A16_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_UINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R16G16B16A16_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SINT_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_A16B16G16R16F, DXGI_FORMAT_R16G16B16A16_FLOAT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SFLOAT_PACK16,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R32_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R32_SINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_R32F, DXGI_FORMAT_R32_FLOAT, glm::u32vec4(0xFFFFFFFF, 0x0000000, 0x0000000, 0x0000000)},\t\t\t\t//FORMAT_R32_SFLOAT_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG32_UINT_PACK32\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG32_SINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_G32R32F, DXGI_FORMAT_R32G32_FLOAT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG32_SFLOAT_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32B32_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB32_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32B32_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB32_SINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32B32_FLOAT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB32_SFLOAT_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32B32A32_UINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA32_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R32G32B32A32_SINT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA32_SINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_A32B32G32R32F, DXGI_FORMAT_R32G32B32A32_FLOAT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA32_SFLOAT_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R64_UINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R64_SINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64_FLOAT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R64_SFLOAT_PACK64,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG64_UINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG64_SINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64_FLOAT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG64_SFLOAT_PACK64,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64B64_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB64_UINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64B64_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB64_SINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64B64_FLOAT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB64_SFLOAT_PACK64,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64B64A64_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA64_UINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64B64A64_SINT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA64_SINT_PACK64,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R64G64B64A64_FLOAT_GLI, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA64_SFLOAT_PACK64,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R11G11B10_FLOAT, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG11B10_UFLOAT,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_R9G9B9E5_SHAREDEXP, glm::u32vec4(0)},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB9E5_UFLOAT,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_D16_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_D16_UNORM_PACK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_D24_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t//FORMAT_D24_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_D32_FLOAT, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_D32_SFLOAT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_S8_UINT_GLI, glm::u32vec4(0)},\t\t\t\t\t//FORMAT_S8_UINT_PACK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_D16_UNORM_S8_UINT_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_D16_UNORM_S8_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_D24_UNORM_S8_UINT, glm::u32vec4(0)},\t\t\t\t//FORMAT_D24_UNORM_S8_UINT_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_D32_FLOAT_S8X24_UINT, glm::u32vec4(0)},\t\t\t//FORMAT_D32_SFLOAT_S8_UINT_PACK64,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_BC1_RGB_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGB_DXT1_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_BC1_RGB_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGB_DXT1_SRGB_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DXT1, DXGI_FORMAT_BC1_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGBA_DXT1_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC1_UNORM_SRGB, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_DXT1_SRGB_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DXT3, DXGI_FORMAT_BC2_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGBA_DXT3_UNORM_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC2_UNORM_SRGB, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_DXT3_SRGB_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DXT5, DXGI_FORMAT_BC3_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGBA_DXT5_UNORM_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC3_UNORM_SRGB, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_DXT5_SRGB_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_ATI1, DXGI_FORMAT_BC4_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_R_ATI1N_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_AT1N, DXGI_FORMAT_BC4_SNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_R_ATI1N_SNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_ATI2, DXGI_FORMAT_BC5_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RG_ATI2N_UNORM_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_AT2N, DXGI_FORMAT_BC5_SNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RG_ATI2N_SNORM_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC6H_UF16, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGB_BP_UFLOAT_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC6H_SF16, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGB_BP_SFLOAT_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC7_UNORM, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGB_BP_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_BC7_UNORM_SRGB, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGB_BP_SRGB,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGB_ETC2_UNORM_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RGB_ETC2_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGB_ETC2_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGB_ETC2_SRGB_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_ETC2_A1_UNORM_GLI, glm::u32vec4(0)},\t\t//FORMAT_RGBA_ETC2_A1_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_ETC2_A1_SRGB_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RGBA_ETC2_A1_SRGB_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_ETC2_UNORM_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RGBA_ETC2_UNORM_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_ETC2_SRGB_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RGBA_ETC2_SRGB_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R11_EAC_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_R_EAC_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R11_EAC_SNORM_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_R_EAC_SNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RG11_EAC_UNORM_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RG_EAC_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RG11_EAC_SNORM_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RG_EAC_SNORM_BLOCK8,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_4X4_UNORM, glm::u32vec4(0)},\t\t\t\t//FORMAT_ASTC_4x4_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_4X4_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//FORMAT_ASTC_4x4_SRGB,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_5X4_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_5x4,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_5X4_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_5x4,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_5X5_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_5x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_5X5_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_5x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_6X5_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_6x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_6X5_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_6x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_6X6_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_6x6,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_6X6_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_6x6,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_8X5_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_8x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_8X5_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_8x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_8X6_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_8x6,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_8X6_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_8x6,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_8X8_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_8x8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_8X8_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_8x8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X5_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_10x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X5_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_10x5,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X6_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_10x6,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X6_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_10x6,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X8_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_10x8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X8_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_10x8,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X10_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_10x10,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_10X10_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_10x10,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_12X10_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_12x10,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_12X10_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_12x10,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_12X12_UNORM, glm::u32vec4(0)},\t\t\t\t//RGBA_ASTC_12x12,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_ASTC_12X12_UNORM_SRGB, glm::u32vec4(0)},\t\t\t//SRGB_ALPHA_ASTC_12x12,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_POWERVR_4BPP, DXGI_FORMAT_RGB_PVRTC1_8X8_UNORM_GLI, glm::u32vec4(0)},\t\t//FORMAT_RGB_PVRTC1_8X8_UNORM_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGB_PVRTC1_8X8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGB_PVRTC1_8X8_SRGB_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_POWERVR_2BPP, DXGI_FORMAT_RGB_PVRTC1_16X8_UNORM_GLI, glm::u32vec4(0)},\t\t//FORMAT_RGB_PVRTC1_16X8_UNORM_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGB_PVRTC1_16X8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGB_PVRTC1_16X8_SRGB_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC1_8X8_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_PVRTC1_8X8_UNORM_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC1_8X8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_PVRTC1_8X8_SRGB_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC1_16X8_UNORM_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RGBA_PVRTC1_16X8_UNORM_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC1_16X8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_PVRTC1_16X8_SRGB_BLOCK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC2_8X8_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_PVRTC2_8X8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC2_8X8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_PVRTC2_8X8_SRGB,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC2_16X8_UNORM_GLI, glm::u32vec4(0)},\t\t\t//FORMAT_RGBA_PVRTC2_16X8_UNORM,\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_RGBA_PVRTC2_16X8_SRGB_GLI, glm::u32vec4(0)},\t\t\t\t//FORMAT_RGBA_PVRTC2_16X8_SRGB,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_ETC, DXGI_FORMAT_RGB_ETC_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGB_ETC_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_ATC, DXGI_FORMAT_RGB_ATC_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t\t//FORMAT_RGB_ATC_UNORM_BLOCK8,\n\t\t\t{DDPF_FOURCC, D3DFMT_ATCA, DXGI_FORMAT_RGBA_ATCA_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t//FORMAT_RGBA_ATCA_UNORM_BLOCK16,\n\t\t\t{DDPF_FOURCC, D3DFMT_ATCI, DXGI_FORMAT_RGBA_ATCI_UNORM_GLI, glm::u32vec4(0)},\t\t\t\t\t//FORMAT_RGBA_ATCI_UNORM_BLOCK16,\n\n\t\t\t{DDPF_LUMINANCE, D3DFMT_L8, DXGI_FORMAT_L8_UNORM_GLI, glm::u32vec4(0x000000FF, 0x00000000, 0x00000000, 0x00000000)},\t\t\t//L8_UNORM,\n\t\t\t{DDPF_ALPHA, D3DFMT_A8, DXGI_FORMAT_A8_UNORM_GLI, glm::u32vec4(0x00000000, 0x00000000, 0x00000000, 0x000000FF)},\t\t\t\t//A8_UNORM,\n\t\t\t{DDPF_LUMINANCE_ALPHA, D3DFMT_A8L8, DXGI_FORMAT_LA8_UNORM_GLI, glm::u32vec4(0x000000FF, 0x00000000, 0x00000000, 0x0000FF00)},\t//LA8_UNORM,\n\t\t\t{DDPF_LUMINANCE, D3DFMT_L16, DXGI_FORMAT_L16_UNORM_GLI, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0x00000000)},\t\t\t//L16_UNORM,\n\t\t\t{DDPF_ALPHA, D3DFMT_GLI1, DXGI_FORMAT_A16_UNORM_GLI, glm::u32vec4(0x00000000, 0x00000000, 0x00000000, 0x0000FFFF)},\t\t\t\t//A16_UNORM,\n\t\t\t{DDPF_LUMINANCE_ALPHA, D3DFMT_GLI1, DXGI_FORMAT_LA16_UNORM_GLI, glm::u32vec4(0x0000FFFF, 0x00000000, 0x00000000, 0xFFFF0000)},\t//LA16_UNORM,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_B8G8R8X8_UNORM, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)},\t\t\t//FORMAT_BGR8_UNORM_PACK32,\n\t\t\t{DDPF_FOURCC, D3DFMT_DX10, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, glm::u32vec4(0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)},\t\t//FORMAT_BGR8_SRGB_PACK32,\n\n\t\t\t{DDPF_FOURCC, D3DFMT_GLI1, DXGI_FORMAT_R3G3B2_UNORM_GLI, glm::u32vec4(0x70, 0x38, 0xC0, 0x00)},\t\t\t\t\t\t\t\t\t//FORMAT_RG3B2_UNORM,\n\t\t};\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == FORMAT_COUNT, \"GLI error: format descriptor list doesn't match number of supported formats\");\n\n\t\tstd::copy(&Table[0], &Table[0] + FORMAT_COUNT, this->Translation.begin());\n\t}\n\n\tinline dx::format const& dx::translate(gli::format Format) const\n\t{\n\t\tGLI_ASSERT(Format >= FORMAT_FIRST && Format <= FORMAT_LAST);\n\t\treturn Translation[Format - FORMAT_FIRST];\n\t}\n\n\tinline gli::format dx::find(dx::d3dfmt FourCC) const\n\t{\n\t\tgli::format FormatResult = gli::FORMAT_UNDEFINED;\n\t\tfor(int FormatIndex = FORMAT_FIRST; FormatIndex <= FORMAT_LAST; ++FormatIndex)\n\t\t{\n\t\t\tif(this->Translation[FormatIndex - FORMAT_FIRST].D3DFormat != FourCC)\n\t\t\t\tcontinue;\n\n\t\t\tFormatResult = static_cast<gli::format>(FormatIndex);\n\t\t\tbreak;\n\t\t}\n\t\treturn FormatResult;\n\t}\n\n\tinline gli::format dx::find(dx::d3dfmt FourCC, dx::dxgiFormat Format) const\n\t{\n\t\tGLI_ASSERT(FourCC == D3DFMT_DX10 || FourCC == D3DFMT_GLI1);\n\n\t\tgli::format FormatResult = gli::FORMAT_UNDEFINED;\n\t\tfor(int FormatIndex = FORMAT_FIRST; FormatIndex <= FORMAT_LAST; ++FormatIndex)\n\t\t{\n\t\t\tgli::format CurrentFormat = static_cast<gli::format>(FormatIndex);\n\t\t\tdetail::formatInfo const & FormatInfo = detail::get_format_info(CurrentFormat);\n\n\t\t\tdx::format const & DXFormat = this->Translation[FormatIndex - FORMAT_FIRST];\n\n\t\t\tif(FourCC == D3DFMT_GLI1 && (FormatInfo.Flags & detail::CAP_DDS_GLI_EXT_BIT) && DXFormat.DXGIFormat.GLI == Format.GLI)\n\t\t\t{\n\t\t\t\tFormatResult = static_cast<gli::format>(FormatIndex);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif(FourCC == D3DFMT_DX10 && !(FormatInfo.Flags & detail::CAP_DDS_GLI_EXT_BIT) && DXFormat.DXGIFormat.DDS == Format.DDS)\n\t\t\t{\n\t\t\t\tFormatResult = static_cast<gli::format>(FormatIndex);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn FormatResult;\n\t}\n\n\tinline bool is_dds_ext(target Target, format Format)\n\t{\n\t\tdx DX;\n\t\tdx::format const & DXFormat = DX.translate(Format);\n\n\t\tbool const UseDDSExt = detail::get_format_info(Format).Flags & detail::CAP_DDS_GLI_EXT_BIT ? true : false;\n\n\t\treturn ((DXFormat.DDPixelFormat & dx::DDPF_FOURCC) && DXFormat.D3DFormat == dx::D3DFMT_GLI1) || ((is_target_array(Target) || is_target_1d(Target)) && UseDDSExt);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/file.hpp",
    "content": "/// @brief File helper functions\n/// @file gli/core/file.hpp\n\n#pragma once\n\n#include <cstdio>\n\nnamespace gli{\nnamespace detail\n{\n\tFILE* open_file(const char *Filename, const char *mode);\n}//namespace detail\n}//namespace gli\n\n#include \"./file.inl\"\n"
  },
  {
    "path": "lib/gli/core/file.inl",
    "content": "#pragma once\n\n#include <glm/simd/platform.h>\n\nnamespace gli{\nnamespace detail\n{\n\tinline FILE* open_file(const char *Filename, const char *Mode)\n\t{\n#\t\tif GLM_COMPILER & GLM_COMPILER_VC\n\t\t\tFILE *File = nullptr;\n\t\t\tfopen_s(&File, Filename, Mode);\n\t\t\treturn File;\n#\t\telse\n\t\t\treturn std::fopen(Filename, Mode);\n#\t\tendif\n\t}\n}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/filter.hpp",
    "content": "/// @brief Include to use filter enum, to select filtering methods.\n/// @file gli/core/filter.hpp\n\n#pragma once\n\nnamespace gli\n{\n\t/// Texture filtring modes\n\tenum filter\n\t{\n\t\tFILTER_NONE = 0,\n\t\tFILTER_NEAREST, FILTER_FIRST = FILTER_NEAREST,\n\t\tFILTER_LINEAR, FILTER_LAST = FILTER_LINEAR\n\t};\n\n\tenum\n\t{\n\t\tFILTER_COUNT = FILTER_LAST - FILTER_FIRST + 1,\n\t\tFILTER_INVALID = -1\n\t};\n}//namespace gli\n\n#include \"filter.inl\"\n"
  },
  {
    "path": "lib/gli/core/filter.inl",
    "content": "#pragma once\n\nnamespace gli{\nnamespace detail\n{\n\n}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/filter_compute.hpp",
    "content": "#pragma once\n\n#include \"filter.hpp\"\n#include \"coord.hpp\"\n#include <glm/gtc/integer.hpp>\n\nnamespace gli{\nnamespace detail\n{\n\tenum dimension\n\t{\n\t\tDIMENSION_1D,\n\t\tDIMENSION_2D,\n\t\tDIMENSION_3D\n\t};\n\n\ttemplate <typename T>\n\tstruct interpolate\n\t{\n\t\ttypedef float type;\n\t};\n\n\ttemplate <>\n\tstruct interpolate<double>\n\t{\n\t\ttypedef double type;\n\t};\n\n\ttemplate <>\n\tstruct interpolate<long double>\n\t{\n\t\ttypedef long double type;\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct filterBase\n\t{\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\n\t\ttypedef texel_type(*filterFunc)(\n\t\t\ttexture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap,\n\t\t\tsize_type Layer, size_type Face, interpolate_type Level,\n\t\t\ttexel_type const & BorderColor);\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, bool is_float = true, bool support_border = true>\n\tstruct nearest : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_nearest<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\textent_type const TexelDim(Texture.extent(Level));\n\t\t\tnormalized_type const TexelLast(normalized_type(TexelDim) - normalized_type(1));\n\n\t\t\t//extent_type const TexelCoord(SampleCoordWrap * TexelLast + interpolate_type(0.5));\n\t\t\textent_type const TexelCoord = extent_type(round(SampleCoordWrap * TexelLast));\n\t\t\ttypename extent_type::bool_type const UseTexelCoord = in_interval(TexelCoord, extent_type(0), TexelDim - 1);\n\n\t\t\ttexel_type Texel(BorderColor);\n\t\t\tif(all(UseTexelCoord))\n\t\t\t\tTexel = Fetch(Texture, TexelCoord, Layer, Face, Level);\n\n\t\t\treturn Texel;\n\t\t}\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct nearest<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, false> : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_nearest<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\tnormalized_type const TexelLast(normalized_type(Texture.extent(Level)) - normalized_type(1));\n\t\t\textent_type const TexelCoord(SampleCoordWrap * TexelLast + interpolate_type(0.5));\n\t\t\t//extent_type const TexelCoord = extent_type(round(SampleCoordWrap * TexelLast));\n\n\t\t\treturn Fetch(Texture, TexelCoord, Layer, Face, Level);\n\t\t}\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, bool is_float = true, bool support_border = true>\n\tstruct linear : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const& BorderColor)\n\t\t{\n\t\t\treturn texel_type(0);\n\t\t}\n\t};\n\n\ttemplate <typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct linear<DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, true> : public filterBase<DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\tcoord_type const& Coord = make_coord_linear_border(Texture.extent(Level), SampleCoordWrap);\n\n\t\t\ttexel_type Texel0(BorderColor);\n\t\t\tif(Coord.UseTexelFloor.s)\n\t\t\t\tTexel0 = Fetch(Texture, extent_type(Coord.TexelFloor.s), Layer, Face, Level);\n\n\t\t\ttexel_type Texel1(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s)\n\t\t\t\tTexel1 = Fetch(Texture, extent_type(Coord.TexelCeil.s), Layer, Face, Level);\n\n\t\t\treturn mix(Texel0, Texel1, Coord.Blend.s);\n\t\t}\n\t};\n\n\ttemplate <typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct linear<DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, false> : public filterBase<DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\tcoord_type const& Coord = make_coord_linear(Texture.extent(Level), SampleCoordWrap);\n\n\t\t\ttexel_type const Texel0 = Fetch(Texture, extent_type(Coord.TexelFloor.s), Layer, Face, Level);\n\t\t\ttexel_type const Texel1 = Fetch(Texture, extent_type(Coord.TexelCeil.s), Layer, Face, Level);\n\n\t\t\treturn mix(Texel0, Texel1, Coord.Blend.s);\n\t\t}\n\t};\n\n\ttemplate <typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct linear<DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, true> : public filterBase<DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const& Texture, fetch_type Fetch, normalized_type const& SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const& BorderColor)\n\t\t{\n\t\t\tcoord_type const& Coord = make_coord_linear_border(Texture.extent(Level), SampleCoordWrap);\n\n\t\t\ttexel_type Texel00(BorderColor);\n\t\t\tif(Coord.UseTexelFloor.s && Coord.UseTexelFloor.t)\n\t\t\t\tTexel00 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelFloor.t), Layer, Face, Level);\n\n\t\t\ttexel_type Texel10(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s && Coord.UseTexelFloor.t)\n\t\t\t\tTexel10 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelFloor.t), Layer, Face, Level);\n\n\t\t\ttexel_type Texel11(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s && Coord.UseTexelCeil.t)\n\t\t\t\tTexel11 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelCeil.t), Layer, Face, Level);\n\n\t\t\ttexel_type Texel01(BorderColor);\n\t\t\tif(Coord.UseTexelFloor.s && Coord.UseTexelCeil.t)\n\t\t\t\tTexel01 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelCeil.t), Layer, Face, Level);\n\n\t\t\ttexel_type const ValueA(mix(Texel00, Texel10, Coord.Blend.s));\n\t\t\ttexel_type const ValueB(mix(Texel01, Texel11, Coord.Blend.s));\n\t\t\treturn mix(ValueA, ValueB, Coord.Blend.t);\n\t\t}\n\t};\n\n\ttemplate <typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct linear<DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, false> : public filterBase<DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const& Texture, fetch_type Fetch, normalized_type const& SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const& BorderColor)\n\t\t{\n\t\t\tcoord_type const& Coord = make_coord_linear(Texture.extent(Level), SampleCoordWrap);\n\n\t\t\ttexel_type const& Texel00 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelFloor.t), Layer, Face, Level);\n\t\t\ttexel_type const& Texel10 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelFloor.t), Layer, Face, Level);\n\t\t\ttexel_type const& Texel11 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelCeil.t), Layer, Face, Level);\n\t\t\ttexel_type const& Texel01 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelCeil.t), Layer, Face, Level);\n\n\t\t\ttexel_type const ValueA(mix(Texel00, Texel10, Coord.Blend.s));\n\t\t\ttexel_type const ValueB(mix(Texel01, Texel11, Coord.Blend.s));\n\t\t\treturn mix(ValueA, ValueB, Coord.Blend.t);\n\t\t}\n\t};\n\n\ttemplate <typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct linear<DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, true> : public filterBase<DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const& Texture, fetch_type Fetch, normalized_type const& SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const& BorderColor)\n\t\t{\n\t\t\tcoord_type const& Coord = make_coord_linear_border(Texture.extent(Level), SampleCoordWrap);\n\n\t\t\ttexel_type Texel000(BorderColor);\n\t\t\tif(Coord.UseTexelFloor.s && Coord.UseTexelFloor.t && Coord.UseTexelFloor.p)\n\t\t\t\tTexel000 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelFloor.t, Coord.TexelFloor.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel100(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s && Coord.UseTexelFloor.t && Coord.UseTexelFloor.p)\n\t\t\t\tTexel100 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelFloor.t, Coord.TexelFloor.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel110(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s && Coord.UseTexelCeil.t && Coord.UseTexelFloor.p)\n\t\t\t\tTexel110 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelCeil.t, Coord.TexelFloor.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel010(BorderColor);\n\t\t\tif(Coord.UseTexelFloor.s && Coord.UseTexelCeil.t && Coord.UseTexelFloor.p)\n\t\t\t\tTexel010 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelCeil.t, Coord.TexelFloor.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel001(BorderColor);\n\t\t\tif (Coord.UseTexelFloor.s && Coord.UseTexelFloor.t && Coord.UseTexelCeil.p)\n\t\t\t\tTexel001 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelFloor.t, Coord.TexelCeil.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel101(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s && Coord.UseTexelFloor.t && Coord.UseTexelCeil.p)\n\t\t\t\tTexel101 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelFloor.t, Coord.TexelCeil.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel111(BorderColor);\n\t\t\tif(Coord.UseTexelCeil.s && Coord.UseTexelCeil.t && Coord.UseTexelCeil.p)\n\t\t\t\tTexel111 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelCeil.t, Coord.TexelCeil.p), Layer, Face, Level);\n\n\t\t\ttexel_type Texel011(BorderColor);\n\t\t\tif(Coord.UseTexelFloor.s && Coord.UseTexelCeil.t && Coord.UseTexelCeil.p)\n\t\t\t\tTexel011 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelCeil.t, Coord.TexelCeil.p), Layer, Face, Level);\n\n\t\t\ttexel_type const ValueA(mix(Texel000, Texel100, Coord.Blend.s));\n\t\t\ttexel_type const ValueB(mix(Texel010, Texel110, Coord.Blend.s));\n\n\t\t\ttexel_type const ValueC(mix(Texel001, Texel101, Coord.Blend.s));\n\t\t\ttexel_type const ValueD(mix(Texel011, Texel111, Coord.Blend.s));\n\n\t\t\ttexel_type const ValueE(mix(ValueA, ValueB, Coord.Blend.t));\n\t\t\ttexel_type const ValueF(mix(ValueC, ValueD, Coord.Blend.t));\n\n\t\t\treturn mix(ValueE, ValueF, Coord.Blend.p);\n\t\t}\n\t};\n\n\ttemplate <typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type>\n\tstruct linear<DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, true, false> : public filterBase<DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, size_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\tcoord_type const & Coord = make_coord_linear(Texture.extent(Level), SampleCoordWrap);\n\n\t\t\ttexel_type const & Texel000 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelFloor.t, Coord.TexelFloor.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel100 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelFloor.t, Coord.TexelFloor.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel110 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelCeil.t, Coord.TexelFloor.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel010 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelCeil.t, Coord.TexelFloor.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel001 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelFloor.t, Coord.TexelCeil.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel101 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelFloor.t, Coord.TexelCeil.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel111 = Fetch(Texture, extent_type(Coord.TexelCeil.s, Coord.TexelCeil.t, Coord.TexelCeil.p), Layer, Face, Level);\n\t\t\ttexel_type const & Texel011 = Fetch(Texture, extent_type(Coord.TexelFloor.s, Coord.TexelCeil.t, Coord.TexelCeil.p), Layer, Face, Level);\n\n\t\t\ttexel_type const ValueA(mix(Texel000, Texel100, Coord.Blend.s));\n\t\t\ttexel_type const ValueB(mix(Texel010, Texel110, Coord.Blend.s));\n\n\t\t\ttexel_type const ValueC(mix(Texel001, Texel101, Coord.Blend.s));\n\t\t\ttexel_type const ValueD(mix(Texel011, Texel111, Coord.Blend.s));\n\n\t\t\ttexel_type const ValueE(mix(ValueA, ValueB, Coord.Blend.t));\n\t\t\ttexel_type const ValueF(mix(ValueC, ValueD, Coord.Blend.t));\n\n\t\t\treturn mix(ValueE, ValueF, Coord.Blend.p);\n\t\t}\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, bool is_float, bool support_border>\n\tstruct nearest_mipmap_nearest : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, interpolate_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\treturn nearest<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, is_float, support_border>::call(Texture, Fetch, SampleCoordWrap, Layer, Face, glm::iround(Level), BorderColor);\n\t\t}\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, bool is_float, bool support_border>\n\tstruct nearest_mipmap_linear : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, interpolate_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\ttexel_type const MinTexel = nearest<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, is_float, support_border>::call(Texture, Fetch, SampleCoordWrap, Layer, Face, static_cast<size_type>(floor(Level)), BorderColor);\n\t\t\ttexel_type const MaxTexel = nearest<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, is_float, support_border>::call(Texture, Fetch, SampleCoordWrap, Layer, Face, static_cast<size_type>(ceil(Level)), BorderColor);\n\t\t\treturn mix(MinTexel, MaxTexel, fract(Level));\n\t\t}\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, bool is_float, bool support_border>\n\tstruct linear_mipmap_nearest : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, interpolate_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\treturn linear<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, is_float, support_border>::call(Texture, Fetch, SampleCoordWrap, Layer, Face, glm::iround(Level), BorderColor);\n\t\t}\n\t};\n\n\ttemplate <dimension Dimension, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, bool is_float, bool support_border>\n\tstruct linear_mipmap_linear : public filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>\n\t{\n\t\ttypedef filterBase<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type> base_type;\n\t\ttypedef typename base_type::size_type size_type;\n\t\ttypedef typename base_type::extent_type extent_type;\n\t\ttypedef coord_linear_border<extent_type, normalized_type> coord_type;\n\n\t\tstatic texel_type call(texture_type const & Texture, fetch_type Fetch, normalized_type const & SampleCoordWrap, size_type Layer, size_type Face, interpolate_type Level, texel_type const & BorderColor)\n\t\t{\n\t\t\tsize_type const FloorLevel = static_cast<size_type>(floor(Level));\n\t\t\tsize_type const CeilLevel = static_cast<size_type>(ceil(Level));\n\t\t\ttexel_type const MinTexel = linear<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, is_float, support_border>::call(Texture, Fetch, SampleCoordWrap, Layer, Face, FloorLevel, BorderColor);\n\t\t\ttexel_type const MaxTexel = linear<Dimension, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, is_float, support_border>::call(Texture, Fetch, SampleCoordWrap, Layer, Face, CeilLevel, BorderColor);\n\t\t\treturn mix(MinTexel, MaxTexel, fract(Level));\n\t\t}\n\t};\n\n\ttemplate <typename filter_type, dimension Dimensions, typename texture_type, typename interpolate_type, typename normalized_type, typename fetch_type, typename texel_type, typename T>\n\tinline filter_type get_filter(filter Mip, filter Min, bool Border)\n\t{\n\t\tstatic filter_type Table[][FILTER_COUNT][2] =\n\t\t{\n\t\t\t{\n\t\t\t\t{\n\t\t\t\t\tnearest_mipmap_nearest<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, false>::call,\n\t\t\t\t\tnearest_mipmap_nearest<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, true>::call\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlinear_mipmap_nearest<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, false>::call,\n\t\t\t\t\tlinear_mipmap_nearest<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, true>::call\n\t\t\t\t}\n\t\t\t},\n\t\t\t{\n\t\t\t\t{\n\t\t\t\t\tnearest_mipmap_linear<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, false>::call,\n\t\t\t\t\tnearest_mipmap_linear<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, true>::call\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlinear_mipmap_linear<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, false>::call,\n\t\t\t\t\tlinear_mipmap_linear<Dimensions, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, std::numeric_limits<T>::is_iec559, true>::call\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == FILTER_COUNT, \"GLI ERROR: 'Table' doesn't match the number of supported filters\");\n\n\t\tGLI_ASSERT(Table[Mip - FILTER_FIRST][Min - FILTER_FIRST][Border ? 1 : 0]);\n\n\t\treturn Table[Mip - FILTER_FIRST][Min - FILTER_FIRST][Border ? 1 : 0];\n\t}\n}//namespace detail\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/flip.hpp",
    "content": "#pragma once\n\n#include <array>\n\n#include \"../texture2d.hpp\"\n#include \"../texture2d_array.hpp\"\n#include \"../texture_cube.hpp\"\n#include \"../texture_cube_array.hpp\"\n\nnamespace gli\n{\n\ttemplate <typename texture>\n\ttexture flip(texture const & Texture);\n\n}//namespace gli\n\n#include \"flip.inl\"\n"
  },
  {
    "path": "lib/gli/core/flip.inl",
    "content": "#include \"./s3tc.hpp\"\n\nnamespace gli{\nnamespace detail\n{\n\tinline void flip(image ImageDst, image ImageSrc, size_t BlockSize)\n\t{\n\t\tsize_t const LineSize = BlockSize * ImageDst.extent().x;\n\n\t\tfor(int y = 0; y < ImageDst.extent().y; ++y)\n\t\t{\n\t\t\tsize_t OffsetDst = LineSize * y;\n\t\t\tsize_t OffsetSrc = ImageSrc.size() - (LineSize * (y + 1));\n\n\t\t\tmemcpy(\n\t\t\t\tImageDst.data<gli::byte>() + OffsetDst,\n\t\t\t\tImageSrc.data<gli::byte>() + OffsetSrc,\n\t\t\t\tLineSize);\n\t\t}\n\t}\n\n\tinline void flip_block_s3tc(uint8* BlockDst, uint8* BlockSrc, format Format, bool HeightTwo)\n\t{\n\t\t// There is no distinction between RGB and RGBA in DXT-compressed textures,\n\t\t// it is used only to tell OpenGL how to interpret the data.\n\t\t// Moreover, in DXT1 (which does not contain an alpha channel), transparency can be emulated\n\t\t// using Color0 and Color1 on a per-compression-block basis.\n\t\t// There is no difference in how textures with and without transparency are laid out in the file,\n\t\t// so they can be flipped using the same method.\n\t\tif(Format == FORMAT_RGB_DXT1_UNORM_BLOCK8 || Format == FORMAT_RGB_DXT1_SRGB_BLOCK8\n\t\t|| Format == FORMAT_RGBA_DXT1_UNORM_BLOCK8 || Format == FORMAT_RGBA_DXT1_SRGB_BLOCK8)\n\t\t{\n\t\t\tdxt1_block* Src = reinterpret_cast<dxt1_block*>(BlockSrc);\n\t\t\tdxt1_block* Dst = reinterpret_cast<dxt1_block*>(BlockDst);\n\n\t\t\tif(HeightTwo)\n\t\t\t{\n\t\t\t\tDst->Color0 = Src->Color0;\n\t\t\t\tDst->Color1 = Src->Color1;\n\t\t\t\tDst->Row[0] = Src->Row[1];\n\t\t\t\tDst->Row[1] = Src->Row[0];\n\t\t\t\tDst->Row[2] = Src->Row[2];\n\t\t\t\tDst->Row[3] = Src->Row[3];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDst->Color0 = Src->Color0;\n\t\t\tDst->Color1 = Src->Color1;\n\t\t\tDst->Row[0] = Src->Row[3];\n\t\t\tDst->Row[1] = Src->Row[2];\n\t\t\tDst->Row[2] = Src->Row[1];\n\t\t\tDst->Row[3] = Src->Row[0];\n\n\t\t\treturn;\n\t\t}\n\n\t\t// DXT3\n\t\tif(Format == FORMAT_RGBA_DXT3_UNORM_BLOCK16 || Format == FORMAT_RGBA_DXT3_SRGB_BLOCK16)\n\t\t{\n\t\t\tdxt3_block* Src = reinterpret_cast<dxt3_block*>(BlockSrc);\n\t\t\tdxt3_block* Dst = reinterpret_cast<dxt3_block*>(BlockDst);\n\n\t\t\tif(HeightTwo)\n\t\t\t{\n\t\t\t\tDst->AlphaRow[0] = Src->AlphaRow[1];\n\t\t\t\tDst->AlphaRow[1] = Src->AlphaRow[0];\n\t\t\t\tDst->AlphaRow[2] = Src->AlphaRow[2];\n\t\t\t\tDst->AlphaRow[3] = Src->AlphaRow[3];\n\t\t\t\tDst->Color0 = Src->Color0;\n\t\t\t\tDst->Color1 = Src->Color1;\n\t\t\t\tDst->Row[0] = Src->Row[1];\n\t\t\t\tDst->Row[1] = Src->Row[0];\n\t\t\t\tDst->Row[2] = Src->Row[2];\n\t\t\t\tDst->Row[3] = Src->Row[3];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDst->AlphaRow[0] = Src->AlphaRow[3];\n\t\t\tDst->AlphaRow[1] = Src->AlphaRow[2];\n\t\t\tDst->AlphaRow[2] = Src->AlphaRow[1];\n\t\t\tDst->AlphaRow[3] = Src->AlphaRow[0];\n\t\t\tDst->Color0 = Src->Color0;\n\t\t\tDst->Color1 = Src->Color1;\n\t\t\tDst->Row[0] = Src->Row[3];\n\t\t\tDst->Row[1] = Src->Row[2];\n\t\t\tDst->Row[2] = Src->Row[1];\n\t\t\tDst->Row[3] = Src->Row[0];\n\n\t\t\treturn;\n\t\t}\n\n\t\t// DXT5\n\t\tif(Format == FORMAT_RGBA_DXT5_UNORM_BLOCK16 || Format == FORMAT_RGBA_DXT5_SRGB_BLOCK16)\n\t\t{\n\t\t\tdxt5_block* Src = reinterpret_cast<dxt5_block*>(BlockSrc);\n\t\t\tdxt5_block* Dst = reinterpret_cast<dxt5_block*>(BlockDst);\n\n\t\t\tif(HeightTwo)\n\t\t\t{\n\t\t\t\tDst->Alpha[0] = Src->Alpha[0];\n\t\t\t\tDst->Alpha[1] = Src->Alpha[1];\n\t\t\t\t// operator+ has precedence over operator>> and operator<<, hence the parentheses. very important!\n\t\t\t\t// the values below are bitmasks used to retrieve alpha values according to the DXT specification\n\t\t\t\t// 0xF0 == 0b11110000 and 0xF == 0b1111\n\t\t\t\tDst->AlphaBitmap[0] = ((Src->AlphaBitmap[1] & 0xF0) >> 4) + ((Src->AlphaBitmap[2] & 0xF) << 4);\n\t\t\t\tDst->AlphaBitmap[1] = ((Src->AlphaBitmap[2] & 0xF0) >> 4) + ((Src->AlphaBitmap[0] & 0xF) << 4);\n\t\t\t\tDst->AlphaBitmap[2] = ((Src->AlphaBitmap[0] & 0xF0) >> 4) + ((Src->AlphaBitmap[1] & 0xF) << 4);\n\t\t\t\tDst->AlphaBitmap[3] = Src->AlphaBitmap[3];\n\t\t\t\tDst->AlphaBitmap[4] = Src->AlphaBitmap[4];\n\t\t\t\tDst->AlphaBitmap[5] = Src->AlphaBitmap[5];\n\t\t\t\tDst->Color0 = Src->Color0;\n\t\t\t\tDst->Color1 = Src->Color1;\n\t\t\t\tDst->Row[0] = Src->Row[1];\n\t\t\t\tDst->Row[1] = Src->Row[0];\n\t\t\t\tDst->Row[2] = Src->Row[2];\n\t\t\t\tDst->Row[3] = Src->Row[3];\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tDst->Alpha[0] = Src->Alpha[0];\n\t\t\tDst->Alpha[1] = Src->Alpha[1];\n\t\t\t// operator+ has precedence over operator>> and operator<<, hence the parentheses. very important!\n\t\t\t// the values below are bitmasks used to retrieve alpha values according to the DXT specification\n\t\t\t// 0xF0 == 0b11110000 and 0xF == 0b1111\n\t\t\tDst->AlphaBitmap[0] = ((Src->AlphaBitmap[4] & 0xF0) >> 4) + ((Src->AlphaBitmap[5] & 0xF) << 4);\n\t\t\tDst->AlphaBitmap[1] = ((Src->AlphaBitmap[5] & 0xF0) >> 4) + ((Src->AlphaBitmap[3] & 0xF) << 4);\n\t\t\tDst->AlphaBitmap[2] = ((Src->AlphaBitmap[3] & 0xF0) >> 4) + ((Src->AlphaBitmap[4] & 0xF) << 4);\n\t\t\tDst->AlphaBitmap[3] = ((Src->AlphaBitmap[1] & 0xF0) >> 4) + ((Src->AlphaBitmap[2] & 0xF) << 4);\n\t\t\tDst->AlphaBitmap[4] = ((Src->AlphaBitmap[2] & 0xF0) >> 4) + ((Src->AlphaBitmap[0] & 0xF) << 4);\n\t\t\tDst->AlphaBitmap[5] = ((Src->AlphaBitmap[0] & 0xF0) >> 4) + ((Src->AlphaBitmap[1] & 0xF) << 4);\n\t\t\tDst->Color0 = Src->Color0;\n\t\t\tDst->Color1 = Src->Color1;\n\t\t\tDst->Row[0] = Src->Row[3];\n\t\t\tDst->Row[1] = Src->Row[2];\n\t\t\tDst->Row[2] = Src->Row[1];\n\t\t\tDst->Row[3] = Src->Row[0];\n\n\t\t\treturn;\n\t\t}\n\n\t\t// invalid format specified (unknown S3TC format?)\n\t\tassert(false);\n\t}\n\n\tinline void flip_s3tc(image ImageDst, image ImageSrc, format Format)\n\t{\n\t\tif(ImageSrc.extent().y == 1)\n\t\t{\n\t\t\tmemcpy(ImageDst.data(),\n\t\t\t\t   ImageSrc.data(),\n\t\t\t\t   ImageSrc.size());\n\t\t\treturn;\n\t\t}\n\n\t\tstd::size_t const XBlocks = ImageSrc.extent().x <= 4 ? 1 : ImageSrc.extent().x / 4;\n\t\tif(ImageSrc.extent().y == 2)\n\t\t{\n\t\t\tfor(std::size_t i_block = 0; i_block < XBlocks; ++i_block)\n\t\t\t\tflip_block_s3tc(ImageDst.data<uint8>() + i_block * block_size(Format), ImageSrc.data<uint8>() + i_block * block_size(Format), Format, true);\n\n\t\t\treturn;\n\t\t}\n\n\t\tstd::size_t const MaxYBlock = ImageSrc.extent().y / 4 - 1;\n\t\tfor(std::size_t i_row = 0; i_row <= MaxYBlock; ++i_row)\n\t\t\tfor(std::size_t i_block = 0; i_block < XBlocks; ++i_block)\n\t\t\t\tflip_block_s3tc(ImageDst.data<uint8>() + (MaxYBlock - i_row) * block_size(Format) * XBlocks + i_block * block_size(Format), ImageSrc.data<uint8>() + i_row * block_size(Format) * XBlocks + i_block * block_size(Format), Format, false);\n\t}\n\n}//namespace detail\n\n/*\ntemplate <>\ninline image flip(image const & Image)\n{\n\n}\n*/\n\ntemplate <>\ninline texture2d flip(texture2d const& Texture)\n{\n\tGLI_ASSERT(!gli::is_compressed(Texture.format()) || gli::is_s3tc_compressed(Texture.format()));\n\n\ttexture2d Flip(Texture.format(), Texture.extent(), Texture.levels());\n\n\tif(!is_compressed(Texture.format()))\n\t{\n\t\ttexture2d::size_type const BlockSize = block_size(Texture.format());\n\n\t\tfor(texture2d::size_type Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip(Flip[Level], Texture[Level], BlockSize);\n\t}\n\telse\n\t\tfor(texture2d::size_type Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip_s3tc(Flip[Level], Texture[Level], Texture.format());\n\n\treturn Flip;\n}\n\ntemplate <>\ninline texture2d_array flip(texture2d_array const& Texture)\n{\n\tGLI_ASSERT(!gli::is_compressed(Texture.format()) || gli::is_s3tc_compressed(Texture.format()));\n\n\ttexture2d_array Flip(Texture.format(), Texture.extent(), Texture.layers(), Texture.levels());\n\n\tif(!gli::is_compressed(Texture.format()))\n\t{\n\t\ttexture2d_array::size_type const BlockSize = block_size(Texture.format());\n\n\t\tfor(texture2d_array::size_type Layer = 0; Layer < Flip.layers(); ++Layer)\n\t\tfor(texture2d_array::size_type Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip(Flip[Layer][Level], Texture[Layer][Level], BlockSize);\n\t}\n\telse\n\t\tfor(texture2d_array::size_type Layer = 0; Layer < Flip.layers(); ++Layer)\n\t\tfor(texture2d_array::size_type Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip_s3tc(Flip[Layer][Level], Texture[Layer][Level], Texture.format());\n\n\treturn Flip;\n}\n\ntemplate <>\ninline texture_cube flip(texture_cube const & Texture)\n{\n\tGLI_ASSERT(!gli::is_compressed(Texture.format()) || gli::is_s3tc_compressed(Texture.format()));\n\n\ttexture_cube Flip(Texture.format(), Texture.extent(), Texture.levels());\n\n\tif(!gli::is_compressed(Texture.format()))\n\t{\n\t\ttexture_cube::size_type const BlockSize = block_size(Texture.format());\n\n\t\tfor(texture_cube::size_type Face = 0; Face < Flip.faces(); ++Face)\n\t\tfor(texture_cube::size_type Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip(Flip[Face][Level], Texture[Face][Level], BlockSize);\n\t}\n\telse\n\t\tfor(texture_cube::size_type Face = 0; Face < Flip.faces(); ++Face)\n\t\tfor(texture_cube::size_type Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip_s3tc(Flip[Face][Level], Texture[Face][Level], Texture.format());\n\n\treturn Flip;\n}\n\ntemplate <>\ninline texture_cube_array flip(texture_cube_array const & Texture)\n{\n\tassert(!is_compressed(Texture.format()) || is_s3tc_compressed(Texture.format()));\n\n\ttexture_cube_array Flip(Texture.format(), Texture.extent(), Texture.layers(), Texture.levels());\n\n\tif(!is_compressed(Texture.format()))\n\t{\n\t\tgli::size_t const BlockSize = block_size(Texture.format());\n\n\t\tfor(std::size_t Layer = 0; Layer < Flip.layers(); ++Layer)\n\t\tfor(std::size_t Face = 0; Face < Flip.faces(); ++Face)\n\t\tfor(std::size_t Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip(Flip[Layer][Face][Level], Texture[Layer][Face][Level], BlockSize);\n\t}\n\telse\n\t\tfor(std::size_t Layer = 0; Layer < Flip.layers(); ++Layer)\n\t\tfor(std::size_t Face = 0; Face < Flip.faces(); ++Face)\n\t\tfor(std::size_t Level = 0; Level < Flip.levels(); ++Level)\n\t\t\tdetail::flip_s3tc(Flip[Layer][Face][Level], Texture[Layer][Face][Level], Texture.format());\n\n\treturn Flip;\n}\n\ntemplate <>\ninline texture flip(texture const & Texture)\n{\n\tswitch(Texture.target())\n\t{\n\tcase TARGET_2D:\n\t\treturn flip(texture2d(Texture));\n\n\tcase TARGET_2D_ARRAY:\n\t\treturn flip(texture2d_array(Texture));\n\n\tcase TARGET_CUBE:\n\t\treturn flip(texture_cube(Texture));\n\n\tcase TARGET_CUBE_ARRAY:\n\t\treturn flip(texture_cube_array(Texture));\n\n\tdefault:\n\t\tassert(false && \"Texture target does not support flipping.\");\n\t\treturn Texture;\n\t}\n}\n\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/format.inl",
    "content": "namespace gli{\nnamespace detail\n{\n\tenum\n\t{\n\t\tCAP_COMPRESSED_BIT = (1 << 0),\n\t\tCAP_COLORSPACE_SRGB_BIT = (1 << 1),\n\t\tCAP_NORMALIZED_BIT = (1 << 2),\n\t\tCAP_SCALED_BIT = (1 << 3),\n\t\tCAP_UNSIGNED_BIT = (1 << 4),\n\t\tCAP_SIGNED_BIT = (1 << 5),\n\t\tCAP_INTEGER_BIT = (1 << 6),\n\t\tCAP_FLOAT_BIT = (1 << 7),\n\t\tCAP_DEPTH_BIT = (1 << 8),\n\t\tCAP_STENCIL_BIT = (1 << 9),\n\t\tCAP_SWIZZLE_BIT = (1 << 10),\n\t\tCAP_LUMINANCE_ALPHA_BIT = (1 << 11),\n\t\tCAP_PACKED8_BIT = (1 << 12),\n\t\tCAP_PACKED16_BIT = (1 << 13),\n\t\tCAP_PACKED32_BIT = (1 << 14),\n\t\tCAP_DDS_GLI_EXT_BIT = (1 << 15),\n\t\tCAP_DECODER_BIT = (1 << 16)\n\t};\n\n\tstruct formatInfo\n\t{\n\t\tglm::uint8 BlockSize;\n\t\tglm::u8vec3 BlockExtent;\n\t\tglm::uint8 Component;\n\t\tswizzles Swizzles;\n\t\tglm::uint32 Flags;\n\t};\n\n\tinline formatInfo const & get_format_info(format Format)\n\t{\n\t\tGLI_ASSERT(Format >= FORMAT_FIRST && Format <= FORMAT_LAST);\n\n\t\tstatic formatInfo const Table[] =\n\t\t{\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_PACKED8_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_R4G4_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA4_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_BGRA4_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_R5G6B5_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_B5G6R5_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB5A1_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_BGR5A1_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_ALPHA, SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE), CAP_PACKED16_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_A1RGB5_UNORM,\n\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_UNORM,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SNORM,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_R8_USCALED,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SSCALED,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_UINT,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R8_SINT,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_R8_SRGB,\n\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_UNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SNORM,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RG8_USCALED,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SSCALED,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_UINT,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG8_SINT,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RG8_SRGB,\n\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGB8_UNORM,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SNORM,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_USCALED,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SSCALED,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_UINT,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGB8_SINT,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGB8_SRGB,\n\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t//FORMAT_BGR8_UNORM,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t//FORMAT_BGR8_SNORM,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_USCALED,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SSCALED,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t//FORMAT_BGR8_UINT,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SINT,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t//FORMAT_BGR8_SRGB,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_UNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_USCALED,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SSCALED,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_UINT,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA8_SINT,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_COLORSPACE_SRGB_BIT},\t\t\t\t\t\t\t//FORMAT_RGBA8_SRGB,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_BGRA8_UNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_BGRA8_SNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_BGRA8_USCALED,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t//FORMAT_BGRA8_SSCALED,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_BGRA8_UINT,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_BGRA8_SINT,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_SWIZZLE_BIT},\t\t//FORMAT_BGRA8_SRGB,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t//FORMAT_RGBA8_UNORM_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGBA8_SNORM_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGBA8_USCALED_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA8_SSCALED_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGBA8_UINT_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA8_SINT_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_SWIZZLE_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t//FORMAT_RGBA8_SRGB_PACK32,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_PACKED32_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB10A2_UNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t//FORMAT_RGB10A2_SNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t//FORMAT_RGB10A2_USCALE,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t//FORMAT_RGB10A2_SSCALE,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_PACKED32_BIT},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB10A2_UINT,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_PACKED32_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t//FORMAT_RGB10A2_SINT,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_PACKED32_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t//FORMAT_BGR10A2_UNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_PACKED32_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_BGR10A2_SNORM,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_PACKED32_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_BGR10A2_USCALE,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_PACKED32_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_BGR10A2_SSCALE,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_PACKED32_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_BGR10A2_UINT,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_PACKED32_BIT | CAP_SWIZZLE_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_BGR10A2_SINT,\n\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_R16_UNORM_PACK16,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_R16_SNORM_PACK16,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_R16_USCALE,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t//FORMAT_R16_SSCALE,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_R16_UINT_PACK16,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_R16_SINT_PACK16,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R16_SFLOAT_PACK16,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RG16_UNORM_PACK16,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RG16_SNORM_PACK16,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_RG16_USCALE,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t//FORMAT_RG16_SSCALE,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RG16_UINT_PACK16,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RG16_SINT_PACK16,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RG16_SFLOAT_PACK16,\n\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGB16_UNORM_PACK16,\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB16_SNORM_PACK16,\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB16_USCALE,\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_RGB16_SSCALE,\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB16_UINT_PACK16,\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB16_SINT_PACK16,\n\t\t\t{  6, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_RGB16_SFLOAT_PACK16,\n\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t//FORMAT_RGBA16_UNORM_PACK16,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SNORM_PACK16,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA16_USCALE,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_SCALED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA16_SSCALE,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA16_UINT_PACK16,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SINT_PACK16,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA16_SFLOAT_PACK16,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t\t//FORMAT_R32_UINT_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t//FORMAT_R32_SINT_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t\t//FORMAT_R32_SFLOAT_PACK32,\n\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RG32_UINT_PACK32,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t//FORMAT_RG32_SINT_PACK32,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t//FORMAT_RG32_SFLOAT_PACK32,\n\n\t\t\t{ 12, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGB32_UINT_PACK32,\n\t\t\t{ 12, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t\t//FORMAT_RGB32_SINT_PACK32,\n\t\t\t{ 12, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t//FORMAT_RGB32_SFLOAT_PACK32,\n\n\t\t\t{ 16, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA32_UINT_PACK32,\n\t\t\t{ 16, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT},\t\t//FORMAT_RGBA32_SINT_PACK32,\n\t\t\t{ 16, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t//FORMAT_RGBA32_SFLOAT_PACK32,\n\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_R64_UINT_PACK64,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_R64_SINT_PACK64,\n\t\t\t{  8, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_R64_SFLOAT_PACK64,\n\n\t\t\t{ 16, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RG64_UINT_PACK64,\n\t\t\t{ 16, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RG64_SINT_PACK64,\n\t\t\t{ 16, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_RG64_SFLOAT_PACK64,\n\n\t\t\t{ 24, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB64_UINT_PACK64,\n\t\t\t{ 24, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB64_SINT_PACK64,\n\t\t\t{ 24, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_FLOAT_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t//FORMAT_RGB64_SFLOAT_PACK64,\n\n\t\t\t{ 32, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGBA64_UINT_PACK64,\n\t\t\t{ 32, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_INTEGER_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA64_SINT_PACK64,\n\t\t\t{ 32, glm::u8vec3(1, 1, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_FLOAT_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA64_SFLOAT_PACK64,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_PACKED32_BIT | CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t\t\t//FORMAT_RG11B10_UFLOAT_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_PACKED32_BIT | CAP_FLOAT_BIT | CAP_UNSIGNED_BIT},\t\t\t\t//FORMAT_RGB9E5_UFLOAT_PACK32,\n\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_INTEGER_BIT},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_D16_UNORM_PACK16,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_INTEGER_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t//FORMAT_D24_UNORM_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_FLOAT_BIT},\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_D32_UFLOAT_PACK32,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_STENCIL_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t//FORMAT_S8_UNORM_PACK8,\n\t\t\t{  3, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_INTEGER_BIT | CAP_STENCIL_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_D16_UNORM_S8_UINT_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_INTEGER_BIT | CAP_STENCIL_BIT},\t\t\t\t\t\t\t//FORMAT_D24_UNORM_S8_UINT_PACK32,\n\t\t\t{  5, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_DEPTH_BIT | CAP_FLOAT_BIT | CAP_STENCIL_BIT},\t\t\t\t\t\t\t\t//FORMAT_D32_SFLOAT_S8_UINT_PACK64,\n\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGB_DXT1_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB_DXT1_SRGB_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_DXT1_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t//FORMAT_RGBA_DXT1_SRGB_BLOCK8,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_DXT3_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t//FORMAT_RGBA_DXT3_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_DXT5_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t//FORMAT_RGBA_DXT5_SRGB_BLOCK16,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_R_ATI1N_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_R_ATI1N_SNORM_BLOCK8,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RG_ATI2N_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_DECODER_BIT | CAP_NORMALIZED_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RG_ATI2N_SNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_FLOAT_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB_BP_UFLOAT_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_FLOAT_BIT | CAP_SIGNED_BIT},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB_BP_SFLOAT_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_BP_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_BP_SRGB_BLOCK16,\n\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGB_ETC2_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGB_ETC2_SRGB_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA_ETC2_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGBA_ETC2_SRGB_BLOCK8,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA_ETC2_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t//FORMAT_RGBA_ETC2_SRGB_BLOCK16,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_R_EAC_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_R_EAC_SNORM_BLOCK8,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RG_EAC_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_ZERO, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_SIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RG_EAC_SNORM_BLOCK16,\n\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_4X4_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_4X4_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(5, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_5X4_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(5, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_5X4_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(5, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_5X5_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(5, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_5X5_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(6, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_6X5_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(6, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_6X5_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(6, 6, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_6X6_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(6, 6, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_6X6_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(8, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_8X5_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(8, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_8X5_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(8, 6, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_8X6_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(8, 6, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_8X6_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(8, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_8X8_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(8, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_8X8_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_10X5_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 5, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_10X5_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 6, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_10X6_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 6, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_10X6_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_10X8_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_10X8_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 10, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_10X10_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(10, 10, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_10X10_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(12, 10, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_12X10_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(12, 10, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_12X10_SRGB_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(12, 12, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t\t\t\t\t\t\t//FORMAT_RGBA_ASTC_12X12_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(12, 12, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT},\t\t//FORMAT_RGBA_ASTC_12X12_SRGB_BLOCK16,\n\n\t\t\t{ 32, glm::u8vec3(8, 8, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB_PVRTC1_8X8_UNORM_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(8, 8, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB_PVRTC1_8X8_SRGB_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(16, 8, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB_PVRTC1_16X8_UNORM_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(16, 8, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGB_PVRTC1_16X8_SRGB_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(8, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_PVRTC1_8X8_UNORM_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(8, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA_PVRTC1_8X8_SRGB_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(16, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_PVRTC1_16X8_UNORM_BLOCK32,\n\t\t\t{ 32, glm::u8vec3(16, 8, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA_PVRTC1_16X8_SRGB_BLOCK32,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_PVRTC2_4X4_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA_PVRTC2_4X4_SRGB_BLOCK8,\n\t\t\t{  8, glm::u8vec3(8, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_PVRTC2_8X4_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(8, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_COLORSPACE_SRGB_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t//FORMAT_RGBA_PVRTC2_8X4_SRGB_BLOCK8,\n\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB_ETC_UNORM_BLOCK8,\n\t\t\t{  8, glm::u8vec3(4, 4, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGB_ATC_UNORM_BLOCK8,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ATCA_UNORM_BLOCK16,\n\t\t\t{ 16, glm::u8vec3(4, 4, 1), 4, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA), CAP_COMPRESSED_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_RGBA_ATCI_UNORM_BLOCK16,\n\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_LUMINANCE_ALPHA_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_L8_UNORM_PACK8,\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_RED), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_LUMINANCE_ALPHA_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_A8_UNORM_PACK8,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_GREEN), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_LUMINANCE_ALPHA_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_LA8_UNORM_PACK8,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_LUMINANCE_ALPHA_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_L16_UNORM_PACK16,\n\t\t\t{  2, glm::u8vec3(1, 1, 1), 1, swizzles(SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_ZERO, SWIZZLE_RED), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_LUMINANCE_ALPHA_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_A16_UNORM_PACK16,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 2, swizzles(SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_RED, SWIZZLE_GREEN), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_LUMINANCE_ALPHA_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t//FORMAT_LA16_UNORM_PACK16,\n\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT},\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_UNORM_PACK32,\n\t\t\t{  4, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_BLUE, SWIZZLE_GREEN, SWIZZLE_RED, SWIZZLE_ONE), CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_SWIZZLE_BIT | CAP_COLORSPACE_SRGB_BIT},\t\t\t\t\t\t\t\t\t\t//FORMAT_BGR8_SRGB_PACK32,\n\n\t\t\t{  1, glm::u8vec3(1, 1, 1), 3, swizzles(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ONE), CAP_PACKED8_BIT | CAP_NORMALIZED_BIT | CAP_UNSIGNED_BIT | CAP_DDS_GLI_EXT_BIT},\t\t\t\t\t\t\t\t\t\t\t//FORMAT_RG3B2_UNORM_PACK8,\n\t\t};\n\n\t\tGLM_STATIC_ASSERT(sizeof(Table) / sizeof(Table[0]) == FORMAT_COUNT, \"GLI error: format descriptor list doesn't match number of supported formats\");\n\t\tGLI_ASSERT(Format != FORMAT_UNDEFINED);\n\n\t\treturn Table[Format - FORMAT_FIRST];\n\t};\n\n\tinline std::uint32_t bits_per_pixel(format Format)\n\t{\n\t\tdetail::formatInfo const & Info = detail::get_format_info(Format);\n\n\t\treturn Info.BlockSize * 8 / (Info.BlockExtent.x * Info.BlockExtent.y * Info.BlockExtent.z);\n\t}\n}//namespace detail\n\n\tinline bool has_decoder(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_DECODER_BIT ? true : false;\n\t}\n\n\tinline bool is_compressed(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_COMPRESSED_BIT ? true : false;\n\t}\n\n\tinline bool is_s3tc_compressed(format Format)\n\t{\n\t\treturn Format >= FORMAT_RGB_DXT1_UNORM_BLOCK8 && Format <= FORMAT_RGBA_DXT5_SRGB_BLOCK16;\n\t}\n\n\tinline bool is_srgb(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_COLORSPACE_SRGB_BIT ? true : false;\n\t}\n\n\tinline size_t block_size(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).BlockSize;\n\t}\n\n\tinline ivec3 block_extent(format Format)\n\t{\n\t\treturn gli::ivec3(detail::get_format_info(Format).BlockExtent);\n\t}\n\n\tinline size_t component_count(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Component;\n\t}\n\n\tinline bool is_unsigned(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_UNSIGNED_BIT ? true : false;\n\t}\n\n\tinline bool is_signed(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_SIGNED_BIT ? true : false;\n\t}\n\n\tinline bool is_integer(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_INTEGER_BIT ? true : false;\n\t}\n\n\tinline bool is_signed_integer(format Format)\n\t{\n\t\treturn is_integer(Format) && is_signed(Format);\n\t}\n\n\tinline bool is_unsigned_integer(format Format)\n\t{\n\t\treturn is_integer(Format) && is_unsigned(Format);\n\t}\n\n\tinline bool is_float(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_FLOAT_BIT ? true : false;\n\t}\n\n\tinline bool is_normalized(format Format)\n\t{\n\t\treturn detail::get_format_info(Format).Flags & detail::CAP_NORMALIZED_BIT ? true : false;\n\t}\n\n\tinline bool is_unorm(format Format)\n\t{\n\t\treturn is_normalized(Format) && is_unsigned(Format);\n\t}\n\n\tinline bool is_snorm(format Format)\n\t{\n\t\treturn is_normalized(Format) && is_signed(Format);\n\t}\n\n\tinline bool is_packed(format Format)\n\t{\n\t\tgli::uint16 flags = detail::get_format_info(Format).Flags;\n\n\t\treturn (flags & detail::CAP_PACKED8_BIT) != 0 || (flags & detail::CAP_PACKED16_BIT) != 0 || (flags & detail::CAP_PACKED32_BIT) != 0;\n\t}\n\n\tinline bool is_depth(format Format)\n\t{\n\t\treturn (detail::get_format_info(Format).Flags & detail::CAP_DEPTH_BIT) ? true : false;\n\t}\n\n\tinline bool is_stencil(format Format)\n\t{\n\t\treturn (detail::get_format_info(Format).Flags & detail::CAP_STENCIL_BIT) ? true : false;\n\t}\n\n\tinline bool is_depth_stencil(format Format)\n\t{\n\t\treturn is_depth(Format) && is_stencil(Format);\n\t}\n\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/generate_mipmaps.inl",
    "content": "#include \"../sampler1d.hpp\"\n#include \"../sampler1d_array.hpp\"\n#include \"../sampler2d.hpp\"\n#include \"../sampler2d_array.hpp\"\n#include \"../sampler3d.hpp\"\n#include \"../sampler_cube.hpp\"\n#include \"../sampler_cube_array.hpp\"\n\nnamespace gli\n{\n\tinline texture1d generate_mipmaps(\n\t\ttexture1d const& Texture,\n\t\ttexture1d::size_type BaseLevel, texture1d::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsampler1D Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\tinline texture1d_array generate_mipmaps(\n\t\ttexture1d_array const& Texture,\n\t\ttexture1d_array::size_type BaseLayer, texture1d_array::size_type MaxLayer,\n\t\ttexture1d_array::size_type BaseLevel, texture1d_array::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsampler1DArray Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseLayer, MaxLayer, BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\tinline texture2d generate_mipmaps(\n\t\ttexture2d const& Texture,\n\t\ttexture2d::size_type BaseLevel, texture2d::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsampler2D Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\tinline texture2d_array generate_mipmaps(\n\t\ttexture2d_array const& Texture,\n\t\ttexture2d_array::size_type BaseLayer, texture2d_array::size_type MaxLayer,\n\t\ttexture2d_array::size_type BaseLevel, texture2d_array::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsampler2DArray Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseLayer, MaxLayer, BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\tinline texture3d generate_mipmaps(\n\t\ttexture3d const& Texture,\n\t\ttexture3d::size_type BaseLevel, texture3d::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsampler3D Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\tinline texture_cube generate_mipmaps(\n\t\ttexture_cube const& Texture,\n\t\ttexture_cube::size_type BaseFace, texture_cube::size_type MaxFace,\n\t\ttexture_cube::size_type BaseLevel, texture_cube::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsamplerCube Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseFace, MaxFace, BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\tinline texture_cube_array generate_mipmaps(\n\t\ttexture_cube_array const& Texture,\n\t\ttexture_cube_array::size_type BaseLayer, texture_cube_array::size_type MaxLayer,\n\t\ttexture_cube_array::size_type BaseFace, texture_cube_array::size_type MaxFace,\n\t\ttexture_cube_array::size_type BaseLevel, texture_cube_array::size_type MaxLevel,\n\t\tfilter Minification)\n\t{\n\t\tfsamplerCubeArray Sampler(Texture, WRAP_CLAMP_TO_EDGE);\n\t\tSampler.generate_mipmaps(BaseLayer, MaxLayer, BaseFace, MaxFace, BaseLevel, MaxLevel, Minification);\n\t\treturn Sampler();\n\t}\n\n\ttemplate <>\n\tinline texture1d generate_mipmaps<texture1d>(texture1d const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_level(), Texture.max_level(), Minification);\n\t}\n\n\ttemplate <>\n\tinline texture1d_array generate_mipmaps<texture1d_array>(texture1d_array const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_layer(), Texture.max_layer(), Texture.base_level(), Texture.max_level(), Minification);\n\t}\n\n\ttemplate <>\n\tinline texture2d generate_mipmaps<texture2d>(texture2d const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_level(), Texture.max_level(), Minification);\n\t}\n\n\ttemplate <>\n\tinline texture2d_array generate_mipmaps<texture2d_array>(texture2d_array const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_layer(), Texture.max_layer(), Texture.base_level(), Texture.max_level(), Minification);\n\t}\n\n\ttemplate <>\n\tinline texture3d generate_mipmaps<texture3d>(texture3d const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_level(), Texture.max_level(), Minification);\n\t}\n\n\ttemplate <>\n\tinline texture_cube generate_mipmaps<texture_cube>(texture_cube const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_face(), Texture.max_face(), Texture.base_level(), Texture.max_level(), Minification);\n\t}\n\n\ttemplate <>\n\tinline texture_cube_array generate_mipmaps<texture_cube_array>(texture_cube_array const& Texture, filter Minification)\n\t{\n\t\treturn generate_mipmaps(Texture, Texture.base_layer(), Texture.max_layer(), Texture.base_face(), Texture.max_face(), Texture.base_level(), Texture.max_level(), Minification);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/gl.inl",
    "content": "#include <algorithm>\n\nnamespace gli{\nnamespace detail\n{\n\tinline gl::swizzles translate(gli::swizzles const& Swizzles)\n\t{\n\t\tstatic gl::swizzle const Table[] =\n\t\t{\n\t\t\tgl::SWIZZLE_RED,\n\t\t\tgl::SWIZZLE_GREEN,\n\t\t\tgl::SWIZZLE_BLUE,\n\t\t\tgl::SWIZZLE_ALPHA,\n\t\t\tgl::SWIZZLE_ZERO,\n\t\t\tgl::SWIZZLE_ONE\n\t\t};\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == SWIZZLE_COUNT, \"GLI error: swizzle descriptor list doesn't match number of supported swizzles\");\n\n\t\treturn gl::swizzles(Table[Swizzles.r], Table[Swizzles.g], Table[Swizzles.b], Table[Swizzles.a]);\n\t}\n\n\tenum format_property\n\t{\n\t\tFORMAT_PROPERTY_BGRA_FORMAT_BIT = (1 << 0),\n\t\tFORMAT_PROPERTY_BGRA_TYPE_BIT = (1 << 1)\n\t};\n}//namespace detail\n\n\tinline gl::gl(profile Profile)\n\t\t: Profile(Profile)\n\t{\n\t\tbool const HasSwizzle = has_swizzle(Profile);\n\t\texternal_format const ExternalBGR = HasSwizzle ? EXTERNAL_RGB : EXTERNAL_BGR;\n\t\texternal_format const ExternalBGRA = HasSwizzle ? EXTERNAL_RGBA : EXTERNAL_BGRA;\n\t\texternal_format const ExternalBGRInt = HasSwizzle ? EXTERNAL_RGB_INTEGER : EXTERNAL_BGR_INTEGER;\n\t\texternal_format const ExternalBGRAInt = HasSwizzle ? EXTERNAL_RGBA_INTEGER : EXTERNAL_BGRA_INTEGER;\n\n\t\texternal_format const ExternalSRGB8 = Profile != PROFILE_ES20 ? EXTERNAL_RGB : EXTERNAL_SRGB_EXT;\n\t\texternal_format const ExternalSRGB8_A8 = Profile != PROFILE_ES20 ? EXTERNAL_RGBA : EXTERNAL_SRGB_ALPHA_EXT;\n\n\t\tinternal_format const InternalBGRA = Profile == PROFILE_ES20 ? INTERNAL_BGRA8_UNORM : INTERNAL_RGBA8_UNORM;\n\t\tinternal_format const InternalRGBETC = Profile == PROFILE_ES20 ? INTERNAL_RGB_ETC : INTERNAL_RGB_ETC2;\n\n\t\tinternal_format const InternalLuminance8 = HasSwizzle ? INTERNAL_R8_UNORM : INTERNAL_LUMINANCE8;\n\t\tinternal_format const InternalAlpha8 = HasSwizzle ? INTERNAL_R8_UNORM : INTERNAL_ALPHA8;\n\t\tinternal_format const InternalLuminanceAlpha8 = HasSwizzle ? INTERNAL_RG8_UNORM : INTERNAL_LUMINANCE8_ALPHA8;\n\n\t\tinternal_format const InternalLuminance16 = HasSwizzle ? INTERNAL_R16_UNORM : INTERNAL_LUMINANCE16;\n\t\tinternal_format const InternalAlpha16 = HasSwizzle ? INTERNAL_R16_UNORM : INTERNAL_ALPHA16;\n\t\tinternal_format const InternalLuminanceAlpha16 = HasSwizzle ? INTERNAL_RG16_UNORM : INTERNAL_LUMINANCE16_ALPHA16;\n\n\t\texternal_format const ExternalLuminance = HasSwizzle ? EXTERNAL_RED : EXTERNAL_LUMINANCE;\n\t\texternal_format const ExternalAlpha = HasSwizzle ? EXTERNAL_RED : EXTERNAL_ALPHA;\n\t\texternal_format const ExternalLuminanceAlpha = HasSwizzle ? EXTERNAL_RG : EXTERNAL_LUMINANCE_ALPHA;\n\n\t\ttype_format const TypeF16 = Profile == PROFILE_ES20 ? TYPE_F16_OES : TYPE_F16;\n\n\t\tformat_desc const Table[] =\n\t\t{\n\t\t\t{INTERNAL_RG4_EXT, EXTERNAL_RG, TYPE_UINT8_RG4_REV_GTC, 0},\t\t\t\t\t\t\t\t\t\t//FORMAT_R4G4_UNORM,\n\t\t\t{INTERNAL_RGBA4, EXTERNAL_RGBA, TYPE_UINT16_RGBA4_REV, 0},\t\t\t\t\t\t\t\t\t\t//FORMAT_RGBA4_UNORM,\n\t\t\t{INTERNAL_RGBA4, EXTERNAL_RGBA, TYPE_UINT16_RGBA4, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t//FORMAT_BGRA4_UNORM,\n\t\t\t{INTERNAL_R5G6B5, EXTERNAL_RGB, TYPE_UINT16_R5G6B5_REV, 0},\t\t\t\t\t\t\t\t\t\t//FORMAT_R5G6B5_UNORM,\n\t\t\t{INTERNAL_R5G6B5, EXTERNAL_RGB, TYPE_UINT16_R5G6B5, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t//FORMAT_B5G6R5_UNORM,\n\t\t\t{INTERNAL_RGB5A1, EXTERNAL_RGBA, TYPE_UINT16_RGB5A1_REV, 0},\t\t\t\t\t\t\t\t\t//FORMAT_RGB5A1_UNORM,\n\t\t\t{INTERNAL_RGB5A1, EXTERNAL_RGBA, TYPE_UINT16_RGB5A1, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t//FORMAT_BGR5A1_UNORM,\n\t\t\t{INTERNAL_RGB5A1, EXTERNAL_RGBA, TYPE_UINT16_A1RGB5_GTC, 0},\t\t\t\t\t\t\t\t\t//FORMAT_A1RGB5_UNORM,\n\n\t\t\t{INTERNAL_R8_UNORM, EXTERNAL_RED, TYPE_U8, 0},\t\t\t\t\t//FORMAT_R8_UNORM,\n\t\t\t{INTERNAL_R8_SNORM, EXTERNAL_RED, TYPE_I8, 0},\t\t\t\t\t//FORMAT_R8_SNORM,\n\t\t\t{INTERNAL_R8_USCALED_GTC, EXTERNAL_RED, TYPE_U8, 0},\t\t\t//FORMAT_R8_USCALED,\n\t\t\t{INTERNAL_R8_SSCALED_GTC, EXTERNAL_RED, TYPE_I8, 0},\t\t\t//FORMAT_R8_SSCALED,\n\t\t\t{INTERNAL_R8U, EXTERNAL_RED_INTEGER, TYPE_U8, 0},\t\t\t\t//FORMAT_R8_UINT,\n\t\t\t{INTERNAL_R8I, EXTERNAL_RED_INTEGER, TYPE_I8, 0},\t\t\t\t//FORMAT_R8_SINT,\n\t\t\t{INTERNAL_SR8, EXTERNAL_RED, TYPE_U8, 0},\t\t\t\t\t\t//FORMAT_R8_SRGB,\n\n\t\t\t{INTERNAL_RG8_UNORM, EXTERNAL_RG, TYPE_U8, 0},\t\t\t\t\t//FORMAT_RG8_UNORM,\n\t\t\t{INTERNAL_RG8_SNORM, EXTERNAL_RG, TYPE_I8, 0},\t\t\t\t\t//FORMAT_RG8_SNORM,\n\t\t\t{INTERNAL_RG8_USCALED_GTC, EXTERNAL_RG, TYPE_U8, 0},\t\t\t//FORMAT_RG8_USCALED,\n\t\t\t{INTERNAL_RG8_SSCALED_GTC, EXTERNAL_RG, TYPE_I8, 0},\t\t\t//FORMAT_RG8_SSCALED,\n\t\t\t{INTERNAL_RG8U, EXTERNAL_RG_INTEGER, TYPE_U8, 0},\t\t\t\t//FORMAT_RG8_UINT,\n\t\t\t{INTERNAL_RG8I, EXTERNAL_RG_INTEGER, TYPE_I8, 0},\t\t\t\t//FORMAT_RG8_SINT,\n\t\t\t{INTERNAL_SRG8, EXTERNAL_RG, TYPE_U8, 0},\t\t\t\t\t\t//FORMAT_RG8_SRGB,\n\n\t\t\t{INTERNAL_RGB8_UNORM, EXTERNAL_RGB, TYPE_U8, 0},\t\t\t\t//FORMAT_RGB8_UNORM,\n\t\t\t{INTERNAL_RGB8_SNORM, EXTERNAL_RGB, TYPE_I8, 0},\t\t\t\t//FORMAT_RGB8_SNORM,\n\t\t\t{INTERNAL_RGB8_USCALED_GTC, EXTERNAL_RGB, TYPE_U8, 0},\t\t\t//FORMAT_RGB8_USCALED,\n\t\t\t{INTERNAL_RGB8_SSCALED_GTC, EXTERNAL_RGB, TYPE_I8, 0},\t\t\t//FORMAT_RGB8_SSCALED,\n\t\t\t{INTERNAL_RGB8U, EXTERNAL_RGB_INTEGER, TYPE_U8, 0},\t\t\t\t//FORMAT_RGB8_UINT,\n\t\t\t{INTERNAL_RGB8I, EXTERNAL_RGB_INTEGER, TYPE_I8, 0},\t\t\t\t//FORMAT_RGB8_SINT,\n\t\t\t{INTERNAL_SRGB8, ExternalSRGB8, TYPE_U8, 0},\t\t\t\t\t//FORMAT_RGB8_SRGB,\n\n\t\t\t{INTERNAL_RGB8_UNORM, ExternalBGR, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t//FORMAT_BGR8_UNORM_PACK8,\n\t\t\t{INTERNAL_RGB8_SNORM, ExternalBGR, TYPE_I8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t//FORMAT_BGR8_SNORM_PACK8,\n\t\t\t{INTERNAL_RGB8_USCALED_GTC, ExternalBGR, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t//FORMAT_BGR8_USCALED_PACK8,\n\t\t\t{INTERNAL_RGB8_SSCALED_GTC, ExternalBGR, TYPE_I8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t//FORMAT_BGR8_SSCALED_PACK8,\n\t\t\t{INTERNAL_RGB8U, ExternalBGRInt, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t//FORMAT_BGR8_UINT_PACK8,\n\t\t\t{INTERNAL_RGB8I, ExternalBGRInt, TYPE_I8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t//FORMAT_BGR8_SINT_PACK8,\n\t\t\t{INTERNAL_SRGB8, ExternalBGR, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t//FORMAT_BGR8_SRGB_PACK8,\n\n\t\t\t{INTERNAL_RGBA8_UNORM, EXTERNAL_RGBA, TYPE_U8, 0},\t\t\t\t//FORMAT_RGBA8_UNORM_PACK8,\n\t\t\t{INTERNAL_RGBA8_SNORM, EXTERNAL_RGBA, TYPE_I8, 0},\t\t\t\t//FORMAT_RGBA8_SNORM_PACK8,\n\t\t\t{INTERNAL_RGBA8_USCALED_GTC, EXTERNAL_RGBA, TYPE_U8, 0},\t\t//FORMAT_RGBA8_USCALED_PACK8,\n\t\t\t{INTERNAL_RGBA8_SSCALED_GTC, EXTERNAL_RGBA, TYPE_I8, 0},\t\t//FORMAT_RGBA8_SSCALED_PACK8,\n\t\t\t{INTERNAL_RGBA8U, EXTERNAL_RGBA_INTEGER, TYPE_U8, 0},\t\t\t//FORMAT_RGBA8_UINT_PACK8,\n\t\t\t{INTERNAL_RGBA8I, EXTERNAL_RGBA_INTEGER, TYPE_I8, 0},\t\t\t//FORMAT_RGBA8_SINT_PACK8,\n\t\t\t{INTERNAL_SRGB8_ALPHA8, ExternalSRGB8_A8, TYPE_U8, 0},\t\t\t//FORMAT_RGBA8_SRGB_PACK8,\n\n\t\t\t{InternalBGRA, ExternalBGRA, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t\t\t//FORMAT_BGRA8_UNORM_PACK8,\n\t\t\t{INTERNAL_RGBA8_SNORM, ExternalBGRA, TYPE_I8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t//FORMAT_BGRA8_SNORM_PACK8,\n\t\t\t{INTERNAL_RGBA8_USCALED_GTC, ExternalBGRA, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t//FORMAT_BGRA8_USCALED_PACK8,\n\t\t\t{INTERNAL_RGBA8_SSCALED_GTC, ExternalBGRA, TYPE_I8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t//FORMAT_BGRA8_SSCALED_PACK8,\n\t\t\t{INTERNAL_RGBA8U, ExternalBGRAInt, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t//FORMAT_BGRA8_UINT_PACK8,\n\t\t\t{INTERNAL_RGBA8I, ExternalBGRAInt, TYPE_I8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t\t//FORMAT_BGRA8_SINT_PACK8,\n\t\t\t{INTERNAL_SRGB8_ALPHA8, ExternalBGRA, TYPE_U8, detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT},\t\t\t//FORMAT_BGRA8_SRGB_PACK8,\n\n\t\t\t{INTERNAL_RGBA8_UNORM, EXTERNAL_RGBA, TYPE_UINT32_RGBA8_REV, 0},\t\t\t//FORMAT_ABGR8_UNORM_PACK32,\n\t\t\t{INTERNAL_RGBA8_SNORM, EXTERNAL_RGBA, TYPE_UINT32_RGBA8_REV, 0},\t\t\t//FORMAT_ABGR8_SNORM_PACK32,\n\t\t\t{INTERNAL_RGBA8_USCALED_GTC, EXTERNAL_RGBA, TYPE_UINT32_RGBA8_REV, 0},\t\t//FORMAT_ABGR8_USCALED_PACK32,\n\t\t\t{INTERNAL_RGBA8_SSCALED_GTC, EXTERNAL_RGBA, TYPE_UINT32_RGBA8_REV, 0},\t\t//FORMAT_ABGR8_SSCALED_PACK32,\n\t\t\t{INTERNAL_RGBA8U, EXTERNAL_RGBA_INTEGER, TYPE_UINT32_RGBA8_REV, 0},\t\t\t//FORMAT_ABGR8_UINT_PACK32,\n\t\t\t{INTERNAL_RGBA8I, EXTERNAL_RGBA_INTEGER, TYPE_UINT32_RGBA8_REV, 0},\t\t\t//FORMAT_ABGR8_SINT_PACK32,\n\t\t\t{INTERNAL_SRGB8_ALPHA8, EXTERNAL_RGBA, TYPE_UINT32_RGBA8_REV, 0},\t\t\t//FORMAT_ABGR8_SRGB_PACK32,\n\n\t\t\t{INTERNAL_RGB10A2_UNORM, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV, 0},\t\t\t//FORMAT_RGB10A2_UNORM_PACK32,\n\t\t\t{INTERNAL_RGB10A2_SNORM_EXT, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV, 0},\t\t//FORMAT_RGB10A2_SNORM_PACK32,\n\t\t\t{INTERNAL_RGB10A2_USCALED_GTC, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV, 0},\t\t//FORMAT_RGB10A2_USCALE_PACK32,\n\t\t\t{INTERNAL_RGB10A2_SSCALED_GTC, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2_REV, 0},\t\t//FORMAT_RGB10A2_SSCALE_PACK32,\n\t\t\t{INTERNAL_RGB10A2U, EXTERNAL_RGBA_INTEGER, TYPE_UINT32_RGB10A2_REV, 0},\t\t\t//FORMAT_RGB10A2_UINT_PACK32,\n\t\t\t{INTERNAL_RGB10A2I_EXT, EXTERNAL_RGBA_INTEGER, TYPE_UINT32_RGB10A2_REV, 0},\t\t//FORMAT_RGB10A2_SINT_PACK32,\n\n\t\t\t{INTERNAL_RGB10A2_UNORM, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t\t//FORMAT_BGR10A2_UNORM_PACK32,\n\t\t\t{INTERNAL_RGB10A2_SNORM_EXT, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t//FORMAT_BGR10A2_SNORM_PACK32,\n\t\t\t{INTERNAL_RGB10A2_USCALED_GTC, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t//FORMAT_BGR10A2_USCALE_PACK32,\n\t\t\t{INTERNAL_RGB10A2_SSCALED_GTC, EXTERNAL_RGBA, TYPE_UINT32_RGB10A2, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t//FORMAT_BGR10A2_SSCALE_PACK32,\n\t\t\t{INTERNAL_RGB10A2U, EXTERNAL_RGBA_INTEGER, TYPE_UINT32_RGB10A2, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t\t//FORMAT_BGR10A2_UINT_PACK32,\n\t\t\t{INTERNAL_RGB10A2I_EXT, EXTERNAL_RGBA_INTEGER, TYPE_UINT32_RGB10A2, detail::FORMAT_PROPERTY_BGRA_TYPE_BIT},\t\t//FORMAT_BGR10A2_SINT_PACK32,\n\n\t\t\t{INTERNAL_R16_UNORM, EXTERNAL_RED, TYPE_U16, 0},\t\t\t\t\t//FORMAT_R16_UNORM_PACK16,\n\t\t\t{INTERNAL_R16_SNORM, EXTERNAL_RED, TYPE_I16, 0},\t\t\t\t\t//FORMAT_R16_SNORM_PACK16,\n\t\t\t{INTERNAL_R16_USCALED_GTC, EXTERNAL_RED, TYPE_U16, 0},\t\t\t\t//FORMAT_R16_USCALED_PACK16,\n\t\t\t{INTERNAL_R16_SSCALED_GTC, EXTERNAL_RED, TYPE_I16, 0},\t\t\t\t//FORMAT_R16_SSCALED_PACK16,\n\t\t\t{INTERNAL_R16U, EXTERNAL_RED_INTEGER, TYPE_U16, 0},\t\t\t\t\t//FORMAT_R16_UINT_PACK16,\n\t\t\t{INTERNAL_R16I, EXTERNAL_RED_INTEGER, TYPE_I16, 0},\t\t\t\t\t//FORMAT_R16_SINT_PACK16,\n\t\t\t{INTERNAL_R16F, EXTERNAL_RED, TypeF16, 0},\t\t\t\t\t\t\t//FORMAT_R16_SFLOAT_PACK16,\n\n\t\t\t{INTERNAL_RG16_UNORM, EXTERNAL_RG, TYPE_U16, 0},\t\t\t\t\t//FORMAT_RG16_UNORM_PACK16,\n\t\t\t{INTERNAL_RG16_SNORM, EXTERNAL_RG, TYPE_I16, 0},\t\t\t\t\t//FORMAT_RG16_SNORM_PACK16,\n\t\t\t{INTERNAL_RG16_USCALED_GTC, EXTERNAL_RG, TYPE_U16, 0},\t\t\t\t//FORMAT_RG16_USCALED_PACK16,\n\t\t\t{INTERNAL_RG16_SSCALED_GTC, EXTERNAL_RG, TYPE_I16, 0},\t\t\t\t//FORMAT_RG16_SSCALED_PACK16,\n\t\t\t{INTERNAL_RG16U, EXTERNAL_RG_INTEGER, TYPE_U16, 0},\t\t\t\t\t//FORMAT_RG16_UINT_PACK16,\n\t\t\t{INTERNAL_RG16I, EXTERNAL_RG_INTEGER, TYPE_I16, 0},\t\t\t\t\t//FORMAT_RG16_SINT_PACK16,\n\t\t\t{INTERNAL_RG16F, EXTERNAL_RG, TypeF16, 0},\t\t\t\t\t\t\t//FORMAT_RG16_SFLOAT_PACK16,\n\n\t\t\t{INTERNAL_RGB16_UNORM, EXTERNAL_RGB, TYPE_U16, 0},\t\t\t\t\t//FORMAT_RGB16_UNORM_PACK16,\n\t\t\t{INTERNAL_RGB16_SNORM, EXTERNAL_RGB, TYPE_I16, 0},\t\t\t\t\t//FORMAT_RGB16_SNORM_PACK16,\n\t\t\t{INTERNAL_RGB16_USCALED_GTC, EXTERNAL_RGB, TYPE_U16, 0},\t\t\t//FORMAT_RGB16_USCALED_PACK16,\n\t\t\t{INTERNAL_RGB16_SSCALED_GTC, EXTERNAL_RGB, TYPE_I16, 0},\t\t\t//FORMAT_RGB16_USCALED_PACK16,\n\t\t\t{INTERNAL_RGB16U, EXTERNAL_RGB_INTEGER, TYPE_U16, 0},\t\t\t\t//FORMAT_RGB16_UINT_PACK16,\n\t\t\t{INTERNAL_RGB16I, EXTERNAL_RGB_INTEGER, TYPE_I16, 0},\t\t\t\t//FORMAT_RGB16_SINT_PACK16,\n\t\t\t{INTERNAL_RGB16F, EXTERNAL_RGB, TypeF16, 0},\t\t\t\t\t\t//FORMAT_RGB16_SFLOAT_PACK16,\n\n\t\t\t{INTERNAL_RGBA16_UNORM, EXTERNAL_RGBA, TYPE_U16, 0},\t\t\t\t//FORMAT_RGBA16_UNORM_PACK16,\n\t\t\t{INTERNAL_RGBA16_SNORM, EXTERNAL_RGBA, TYPE_I16, 0},\t\t\t\t//FORMAT_RGBA16_SNORM_PACK16,\n\t\t\t{INTERNAL_RGBA16_USCALED_GTC, EXTERNAL_RGBA, TYPE_U16, 0},\t\t\t//FORMAT_RGBA16_USCALED_PACK16,\n\t\t\t{INTERNAL_RGBA16_SSCALED_GTC, EXTERNAL_RGBA, TYPE_I16, 0},\t\t\t//FORMAT_RGBA16_SSCALED_PACK16,\n\t\t\t{INTERNAL_RGBA16U, EXTERNAL_RGBA_INTEGER, TYPE_U16, 0},\t\t\t\t//FORMAT_RGBA16_UINT_PACK16,\n\t\t\t{INTERNAL_RGBA16I, EXTERNAL_RGBA_INTEGER, TYPE_I16, 0},\t\t\t\t//FORMAT_RGBA16_SINT_PACK16,\n\t\t\t{INTERNAL_RGBA16F, EXTERNAL_RGBA, TypeF16, 0},\t\t\t\t\t\t//FORMAT_RGBA16_SFLOAT_PACK16,\n\n\t\t\t{INTERNAL_R32U, EXTERNAL_RED_INTEGER, TYPE_U32, 0},\t\t\t\t\t//FORMAT_R32_UINT_PACK32,\n\t\t\t{INTERNAL_R32I, EXTERNAL_RED_INTEGER, TYPE_I32, 0},\t\t\t\t\t//FORMAT_R32_SINT_PACK32,\n\t\t\t{INTERNAL_R32F, EXTERNAL_RED, TYPE_F32, 0},\t\t\t\t\t\t\t//FORMAT_R32_SFLOAT_PACK32,\n\n\t\t\t{INTERNAL_RG32U, EXTERNAL_RG_INTEGER, TYPE_U32, 0},\t\t\t\t\t//FORMAT_RG32_UINT_PACK32,\n\t\t\t{INTERNAL_RG32I, EXTERNAL_RG_INTEGER, TYPE_I32, 0},\t\t\t\t\t//FORMAT_RG32_SINT_PACK32,\n\t\t\t{INTERNAL_RG32F, EXTERNAL_RG, TYPE_F32, 0},\t\t\t\t\t\t\t//FORMAT_RG32_SFLOAT_PACK32,\n\n\t\t\t{INTERNAL_RGB32U, EXTERNAL_RGB_INTEGER, TYPE_U32, 0},\t\t\t\t//FORMAT_RGB32_UINT_PACK32,\n\t\t\t{INTERNAL_RGB32I, EXTERNAL_RGB_INTEGER, TYPE_I32, 0},\t\t\t\t//FORMAT_RGB32_SINT_PACK32,\n\t\t\t{INTERNAL_RGB32F, EXTERNAL_RGB, TYPE_F32, 0},\t\t\t\t\t\t//FORMAT_RGB32_SFLOAT_PACK32,\n\n\t\t\t{INTERNAL_RGBA32U, EXTERNAL_RGBA_INTEGER, TYPE_U32, 0},\t\t\t\t//FORMAT_RGBA32_UINT_PACK32,\n\t\t\t{INTERNAL_RGBA32I, EXTERNAL_RGBA_INTEGER, TYPE_I32, 0},\t\t\t\t//FORMAT_RGBA32_SINT_PACK32,\n\t\t\t{INTERNAL_RGBA32F, EXTERNAL_RGBA, TYPE_F32, 0},\t\t\t\t\t\t//FORMAT_RGBA32_SFLOAT_PACK32,\n\n\t\t\t{INTERNAL_R64F_EXT, EXTERNAL_RED, TYPE_U64, 0},\t\t\t\t\t\t//FORMAT_R64_UINT_PACK64,\n\t\t\t{INTERNAL_R64F_EXT, EXTERNAL_RED, TYPE_I64, 0},\t\t\t\t\t\t//FORMAT_R64_SINT_PACK64,\n\t\t\t{INTERNAL_R64F_EXT, EXTERNAL_RED, TYPE_F64, 0},\t\t\t\t\t\t//FORMAT_R64_SFLOAT_PACK64,\n\n\t\t\t{INTERNAL_RG64F_EXT, EXTERNAL_RG, TYPE_U64, 0},\t\t\t\t\t\t//FORMAT_RG64_UINT_PACK64,\n\t\t\t{INTERNAL_RG64F_EXT, EXTERNAL_RG, TYPE_I64, 0},\t\t\t\t\t\t//FORMAT_RG64_SINT_PACK64,\n\t\t\t{INTERNAL_RG64F_EXT, EXTERNAL_RG, TYPE_F64, 0},\t\t\t\t\t\t//FORMAT_RG64_SFLOAT_PACK64,\n\n\t\t\t{INTERNAL_RGB64F_EXT, EXTERNAL_RGB, TYPE_U64, 0},\t\t\t\t\t//FORMAT_RGB64_UINT_PACK64,\n\t\t\t{INTERNAL_RGB64F_EXT, EXTERNAL_RGB, TYPE_I64, 0},\t\t\t\t\t//FORMAT_RGB64_SINT_PACK64,\n\t\t\t{INTERNAL_RGB64F_EXT, EXTERNAL_RGB, TYPE_F64, 0},\t\t\t\t\t//FORMAT_RGB64_SFLOAT_PACK64,\n\n\t\t\t{INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, TYPE_U64, 0},\t\t\t\t\t//FORMAT_RGBA64_UINT_PACK64,\n\t\t\t{INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, TYPE_I64, 0},\t\t\t\t\t//FORMAT_RGBA64_SINT_PACK64,\n\t\t\t{INTERNAL_RGBA64F_EXT, EXTERNAL_RGBA, TYPE_F64, 0},\t\t\t\t\t//FORMAT_RGBA64_SFLOAT_PACK64,\n\n\t\t\t{INTERNAL_RG11B10F, EXTERNAL_RGB, TYPE_UINT32_RG11B10F_REV, 0},\t\t//FORMAT_RG11B10_UFLOAT_PACK32,\n\t\t\t{INTERNAL_RGB9E5, EXTERNAL_RGB, TYPE_UINT32_RGB9_E5_REV, 0},\t\t//FORMAT_RGB9E5_UFLOAT_PACK32,\n\n\t\t\t{INTERNAL_D16, EXTERNAL_DEPTH, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_D16_UNORM_PACK16,\n\t\t\t{INTERNAL_D24, EXTERNAL_DEPTH, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_D24_UNORM,\n\t\t\t{INTERNAL_D32F, EXTERNAL_DEPTH, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_D32_UFLOAT,\n\t\t\t{INTERNAL_S8_EXT, EXTERNAL_STENCIL, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_S8_UNORM,\n\t\t\t{INTERNAL_D16S8_EXT, EXTERNAL_DEPTH, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_D16_UNORM_S8_UINT_PACK32,\n\t\t\t{INTERNAL_D24S8, EXTERNAL_DEPTH_STENCIL, TYPE_NONE, 0},\t\t\t\t//FORMAT_D24_UNORM_S8_UINT_PACK32,\n\t\t\t{INTERNAL_D32FS8X24, EXTERNAL_DEPTH_STENCIL, TYPE_NONE, 0},\t\t\t//FORMAT_D32_SFLOAT_S8_UINT_PACK64,\n\n\t\t\t{INTERNAL_RGB_DXT1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGB_DXT1_UNORM_BLOCK8,\n\t\t\t{INTERNAL_SRGB_DXT1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGB_DXT1_SRGB_BLOCK8,\n\t\t\t{INTERNAL_RGBA_DXT1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_DXT1_UNORM_BLOCK8,\n\t\t\t{INTERNAL_SRGB_ALPHA_DXT1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_DXT1_SRGB_BLOCK8,\n\t\t\t{INTERNAL_RGBA_DXT3, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_DXT3_UNORM_BLOCK16,\n\t\t\t{INTERNAL_SRGB_ALPHA_DXT3, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_DXT3_SRGB_BLOCK16,\n\t\t\t{INTERNAL_RGBA_DXT5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_DXT5_UNORM_BLOCK16,\n\t\t\t{INTERNAL_SRGB_ALPHA_DXT5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_DXT5_SRGB_BLOCK16,\n\t\t\t{INTERNAL_R_ATI1N_UNORM, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_R_ATI1N_UNORM_BLOCK8,\n\t\t\t{INTERNAL_R_ATI1N_SNORM, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_R_ATI1N_SNORM_BLOCK8,\n\t\t\t{INTERNAL_RG_ATI2N_UNORM, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RG_ATI2N_UNORM_BLOCK16,\n\t\t\t{INTERNAL_RG_ATI2N_SNORM, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RG_ATI2N_SNORM_BLOCK16,\n\t\t\t{INTERNAL_RGB_BP_UNSIGNED_FLOAT, EXTERNAL_NONE, TYPE_NONE, 0},\t\t//FORMAT_RGB_BP_UFLOAT_BLOCK16,\n\t\t\t{INTERNAL_RGB_BP_SIGNED_FLOAT, EXTERNAL_NONE, TYPE_NONE, 0},\t\t//FORMAT_RGB_BP_SFLOAT_BLOCK16,\n\t\t\t{INTERNAL_RGB_BP_UNORM, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGB_BP_UNORM,\n\t\t\t{INTERNAL_SRGB_BP_UNORM, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGB_BP_SRGB,\n\n\t\t\t{InternalRGBETC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t\t//FORMAT_RGB_ETC2_UNORM_BLOCK8,\n\t\t\t{INTERNAL_SRGB8_ETC2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGB_ETC2_SRGB_BLOCK8,\n\t\t\t{INTERNAL_RGBA_PUNCHTHROUGH_ETC2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_ETC2_PUNCHTHROUGH_UNORM,\n\t\t\t{INTERNAL_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2, EXTERNAL_NONE, TYPE_NONE, 0},\t//FORMAT_RGBA_ETC2_PUNCHTHROUGH_SRGB,\n\t\t\t{INTERNAL_RGBA_ETC2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ETC2_UNORM_BLOCK16,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ETC2_EAC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_ETC2_SRGB_BLOCK16,\n\t\t\t{INTERNAL_R11_EAC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_R11_EAC_UNORM,\n\t\t\t{INTERNAL_SIGNED_R11_EAC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_R11_EAC_SNORM,\n\t\t\t{INTERNAL_RG11_EAC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RG11_EAC_UNORM,\n\t\t\t{INTERNAL_SIGNED_RG11_EAC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RG11_EAC_SNORM,\n\n\t\t\t{INTERNAL_RGBA_ASTC_4x4, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC4X4_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_4x4, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC4X4_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_5x4, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC5X4_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_5x4, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC5X4_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_5x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC5X5_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_5x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC5X5_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_6x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC6X5_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_6x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC6X5_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_6x6, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC6X6_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_6x6, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC6X6_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_8x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC8X5_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_8x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC8X5_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_8x6, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC8X6_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_8x6, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC8X6_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_8x8, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC8X8_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_8x8, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC8X8_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_10x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC10X5_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_10x5, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC10X5_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_10x6, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC10X6_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_10x6, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC10X6_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_10x8, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t//FORMAT_RGBA_ASTC10X8_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_10x8, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t//FORMAT_RGBA_ASTC10X8_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_10x10, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_ASTC10X10_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_10x10, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_ASTC10X10_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_12x10, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_ASTC12X10_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_12x10, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_ASTC12X10_SRGB,\n\t\t\t{INTERNAL_RGBA_ASTC_12x12, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_ASTC12X12_UNORM,\n\t\t\t{INTERNAL_SRGB8_ALPHA8_ASTC_12x12, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_ASTC12X12_SRGB,\n\n\t\t\t{INTERNAL_RGB_PVRTC_4BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGB_PVRTC1_8X8_UNORM_BLOCK32,\n\t\t\t{INTERNAL_SRGB_PVRTC_2BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGB_PVRTC1_8X8_SRGB_BLOCK32,\n\t\t\t{INTERNAL_RGB_PVRTC_2BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGB_PVRTC1_16X8_UNORM_BLOCK32,\n\t\t\t{INTERNAL_SRGB_PVRTC_4BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGB_PVRTC1_16X8_SRGB_BLOCK32,\n\t\t\t{INTERNAL_RGBA_PVRTC_4BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_PVRTC1_8X8_UNORM_BLOCK32,\n\t\t\t{INTERNAL_SRGB_ALPHA_PVRTC_2BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_PVRTC1_8X8_SRGB_BLOCK32,\n\t\t\t{INTERNAL_RGBA_PVRTC_2BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_PVRTC1_16X8_UNORM_BLOCK32,\n\t\t\t{INTERNAL_SRGB_ALPHA_PVRTC_4BPPV1, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_PVRTC1_16X8_SRGB_BLOCK32,\n\t\t\t{INTERNAL_RGBA_PVRTC_4BPPV2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_PVRTC2_4X4_UNORM_BLOCK8,\n\t\t\t{INTERNAL_SRGB_ALPHA_PVRTC_4BPPV2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_PVRTC2_4X4_SRGB_BLOCK8,\n\t\t\t{INTERNAL_RGBA_PVRTC_2BPPV2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t//FORMAT_RGBA_PVRTC2_8X4_UNORM_BLOCK8,\n\t\t\t{INTERNAL_SRGB_ALPHA_PVRTC_2BPPV2, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_PVRTC2_8X4_SRGB_BLOCK8,\n\n\t\t\t{INTERNAL_RGB_ETC, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t\t//FORMAT_RGB_ETC_UNORM_BLOCK8,\n\t\t\t{INTERNAL_ATC_RGB, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t\t\t\t\t//FORMAT_RGB_ATC_UNORM_BLOCK8,\n\t\t\t{INTERNAL_ATC_RGBA_EXPLICIT_ALPHA, EXTERNAL_NONE, TYPE_NONE, 0},\t\t\t//FORMAT_RGBA_ATCA_UNORM_BLOCK16,\n\t\t\t{INTERNAL_ATC_RGBA_INTERPOLATED_ALPHA, EXTERNAL_NONE, TYPE_NONE, 0},\t\t//FORMAT_RGBA_ATCI_UNORM_BLOCK16,\n\n\t\t\t{InternalLuminance8, ExternalLuminance, TYPE_U8, 0},\t\t\t\t\t\t//FORMAT_L8_UNORM_PACK8,\n\t\t\t{InternalAlpha8, ExternalAlpha, TYPE_U8, 0},\t\t\t\t\t\t\t\t//FORMAT_A8_UNORM_PACK8,\n\t\t\t{InternalLuminanceAlpha8, ExternalLuminanceAlpha, TYPE_U8, 0},\t\t\t\t//FORMAT_LA8_UNORM_PACK8,\n\t\t\t{InternalLuminance16, ExternalLuminance, TYPE_U16, 0},\t\t\t\t\t\t//FORMAT_L16_UNORM_PACK16,\n\t\t\t{InternalAlpha16, ExternalAlpha, TYPE_U16, 0},\t\t\t\t\t\t\t\t//FORMAT_A16_UNORM_PACK16,\n\t\t\t{InternalLuminanceAlpha16, ExternalLuminanceAlpha, TYPE_U16, 0},\t\t\t//FORMAT_LA16_UNORM_PACK16,\n\n\t\t\t{INTERNAL_RGB8_UNORM, ExternalBGRA, TYPE_U8, 0},\t\t\t\t\t\t\t//FORMAT_BGRX8_UNORM,\n\t\t\t{INTERNAL_SRGB8, ExternalBGRA, TYPE_U8, 0},\t\t\t\t\t\t\t\t\t//FORMAT_BGRX8_SRGB,\n\n\t\t\t{INTERNAL_RG3B2, EXTERNAL_RGB, TYPE_UINT8_RG3B2_REV, 0},\t\t\t\t\t//FORMAT_RG3B2_UNORM,\n\t\t};\n\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == FORMAT_COUNT, \"GLI error: format descriptor list doesn't match number of supported formats\");\n\n\t\tstd::copy(&Table[0], &Table[0] + FORMAT_COUNT, this->FormatDesc.begin());\n\t}\n\n\tinline gl::target const& gl::translate(gli::target Target) const\n\t{\n\t\tstatic gl::target const Table[] =\n\t\t{\n\t\t\tgl::TARGET_1D,\n\t\t\tgl::TARGET_1D_ARRAY,\n\t\t\tgl::TARGET_2D,\n\t\t\tgl::TARGET_2D_ARRAY,\n\t\t\tgl::TARGET_3D,\n\t\t\tgl::TARGET_RECT,\n\t\t\tgl::TARGET_RECT_ARRAY,\n\t\t\tgl::TARGET_CUBE,\n\t\t\tgl::TARGET_CUBE_ARRAY\n\t\t};\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == TARGET_COUNT, \"GLI error: target descriptor list doesn't match number of supported targets\");\n\n\t\treturn Table[Target];\n\t}\n\n\tinline gl::format gl::translate(gli::format Format, gli::swizzles const& Swizzles) const\n\t{\n\t\tGLI_ASSERT(Format >= FORMAT_FIRST && Format <= FORMAT_LAST);\n\n\t\tgl::format_desc const& FormatDesc = this->FormatDesc[Format - FORMAT_FIRST];\n\n\t\tgl::format FormatGL;\n\t\tFormatGL.Internal = FormatDesc.Internal;\n\t\tFormatGL.External = FormatDesc.External;\n\t\tFormatGL.Type = FormatDesc.Type;\n\t\tFormatGL.Swizzles = this->compute_swizzle(FormatDesc, Swizzles);\n\t\treturn FormatGL;\n\t}\n\n\tinline gli::format gl::find(gl::internal_format InternalFormat, gl::external_format ExternalFormat, gl::type_format Type)\n\t{\n\t\tfor(int FormatIndex = FORMAT_FIRST; FormatIndex <= FORMAT_LAST; ++FormatIndex)\n\t\t{\n\t\t\tstd::size_t const Index = FormatIndex - FORMAT_FIRST;\n\t\t\tif (this->FormatDesc[Index].Internal != InternalFormat)\n\t\t\t\tcontinue;\n\t\t\tif (this->FormatDesc[Index].External != ExternalFormat)\n\t\t\t\tcontinue;\n\t\t\tif (this->FormatDesc[Index].Type != Type)\n\t\t\t\tcontinue;\n\n\t\t\treturn static_cast<gli::format>(FormatIndex);\n\t\t}\n\t\treturn gli::FORMAT_UNDEFINED;\n\t}\n\n\tinline gl::swizzles gl::compute_swizzle(format_desc const& FormatDesc, gli::swizzles const& Swizzles) const\n\t{\n\t\tif (!this->has_swizzle(this->Profile))\n\t\t\treturn swizzles(gl::SWIZZLE_RED, gl::SWIZZLE_GREEN, gl::SWIZZLE_BLUE, gl::SWIZZLE_ALPHA);\n\n\t\tbool const IsExternalBGRA = ((FormatDesc.Properties & detail::FORMAT_PROPERTY_BGRA_FORMAT_BIT) && !has_swizzle(this->Profile)) || (FormatDesc.Properties & detail::FORMAT_PROPERTY_BGRA_TYPE_BIT);\n\n\t\treturn detail::translate(IsExternalBGRA ? gli::swizzles(Swizzles.b, Swizzles.g, Swizzles.r, Swizzles.a) : Swizzles);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/image.inl",
    "content": "namespace gli{\nnamespace detail\n{\n\tinline size_t texel_linear_addressing\n\t(\n\t\textent1d const& Extent,\n\t\textent1d const& TexelCoord\n\t)\n\t{\n\t\tGLI_ASSERT(glm::all(glm::lessThan(TexelCoord, Extent)));\n\n\t\treturn static_cast<size_t>(TexelCoord.x);\n\t}\n\n\tinline size_t texel_linear_addressing\n\t(\n\t\textent2d const& Extent,\n\t\textent2d const& TexelCoord\n\t)\n\t{\n\t\tGLI_ASSERT(TexelCoord.x < Extent.x);\n\t\tGLI_ASSERT(TexelCoord.y < Extent.y);\n\n\t\treturn static_cast<size_t>(TexelCoord.x + Extent.x * TexelCoord.y);\n\t}\n\n\tinline size_t texel_linear_addressing\n\t(\n\t\textent3d const& Extent,\n\t\textent3d const& TexelCoord\n\t)\n\t{\n\t\tGLI_ASSERT(TexelCoord.x < Extent.x);\n\t\tGLI_ASSERT(TexelCoord.y < Extent.y);\n\t\tGLI_ASSERT(TexelCoord.z < Extent.z);\n\n\t\treturn static_cast<size_t>(TexelCoord.x + Extent.x * (TexelCoord.y + Extent.y * TexelCoord.z));\n\t}\n\n\tinline size_t texel_morton_addressing\n\t(\n\t\textent1d const& Extent,\n\t\textent1d const& TexelCoord\n\t)\n\t{\n\t\tGLI_ASSERT(TexelCoord.x < Extent.x);\n\n\t\treturn TexelCoord.x;\n\t}\n\n\tinline size_t texel_morton_addressing\n\t(\n\t\textent2d const& Extent,\n\t\textent2d const& TexelCoord\n\t)\n\t{\n\t\tGLI_ASSERT(TexelCoord.x < Extent.x && TexelCoord.x >= 0 && TexelCoord.x < std::numeric_limits<extent2d::value_type>::max());\n\t\tGLI_ASSERT(TexelCoord.y < Extent.y && TexelCoord.y >= 0 && TexelCoord.y < std::numeric_limits<extent2d::value_type>::max());\n\n\t\tglm::u32vec2 const Input(TexelCoord);\n\n\t\treturn static_cast<size_t>(glm::bitfieldInterleave(Input.x, Input.y));\n\t}\n\n\tinline size_t texel_morton_addressing\n\t(\n\t\textent3d const& Extent,\n\t\textent3d const& TexelCoord\n\t)\n\t{\n\t\tGLI_ASSERT(TexelCoord.x < Extent.x);\n\t\tGLI_ASSERT(TexelCoord.y < Extent.y);\n\t\tGLI_ASSERT(TexelCoord.z < Extent.z);\n\n\t\tglm::u32vec3 const Input(TexelCoord);\n\n\t\treturn static_cast<size_t>(glm::bitfieldInterleave(Input.x, Input.y, Input.z));\n\t}\n}//namespace detail\n\n\tinline image::image()\n\t\t: Format(gli::FORMAT_UNDEFINED)\n\t\t, BaseLevel(0)\n\t\t, Data(nullptr)\n\t\t, Size(0)\n\t{}\n\n\tinline image::image\n\t(\n\t\tformat_type Format,\n\t\textent_type const& Extent\n\t)\n\t\t: Storage(std::make_shared<storage_linear>(Format, Extent, 1, 1, 1))\n\t\t, Format(Format)\n\t\t, BaseLevel(0)\n\t\t, Data(Storage->data())\n\t\t, Size(compute_size(0))\n\t{}\n\n\tinline image::image\n\t(\n\t\tstd::shared_ptr<storage_linear> Storage,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer,\n\t\tsize_type BaseFace,\n\t\tsize_type BaseLevel\n\t)\n\t\t: Storage(Storage)\n\t\t, Format(Format)\n\t\t, BaseLevel(BaseLevel)\n\t\t, Data(compute_data(BaseLayer, BaseFace, BaseLevel))\n\t\t, Size(compute_size(BaseLevel))\n\t{}\n\n\tinline image::image\n\t(\n\t\timage const & Image,\n\t\tformat_type Format\n\t)\n\t\t: Storage(Image.Storage)\n\t\t, Format(Format)\n\t\t, BaseLevel(Image.BaseLevel)\n\t\t, Data(Image.Data)\n\t\t, Size(Image.Size)\n\t{\n\t\tGLI_ASSERT(block_size(Format) == block_size(Image.format()));\n\t}\n\n\tinline bool image::empty() const\n\t{\n\t\tif(this->Storage.get() == nullptr)\n\t\t\treturn true;\n\n\t\treturn this->Storage->empty();\n\t}\n\n\tinline image::size_type image::size() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Size;\n\t}\n\n\ttemplate <typename genType>\n\tinline image::size_type image::size() const\n\t{\n\t\tGLI_ASSERT(sizeof(genType) <= this->Storage->block_size());\n\n\t\treturn this->size() / sizeof(genType);\n\t}\n\n\tinline image::format_type image::format() const\n\t{\n\t\treturn this->Format;\n\t}\n\n\tinline image::extent_type image::extent() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\tstorage_linear::extent_type const& SrcExtent = this->Storage->extent(this->BaseLevel);\n\t\tstorage_linear::extent_type const& DstExtent = SrcExtent * block_extent(this->format()) / this->Storage->block_extent();\n\n\t\treturn glm::max(DstExtent, storage_linear::extent_type(1));\n\t}\n\n\tinline void* image::data()\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Data;\n\t}\n\n\tinline void const* image::data() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Data;\n\t}\n\n\ttemplate <typename genType>\n\tinline genType* image::data()\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(this->Storage->block_size() >= sizeof(genType));\n\n\t\treturn reinterpret_cast<genType *>(this->data());\n\t}\n\n\ttemplate <typename genType>\n\tinline genType const* image::data() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(this->Storage->block_size() >= sizeof(genType));\n\n\t\treturn reinterpret_cast<genType const *>(this->data());\n\t}\n\n\tinline void image::clear()\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\tmemset(this->data<gli::byte>(), 0, this->size<gli::byte>());\n\t}\n\n\ttemplate <typename genType>\n\tinline void image::clear(genType const& Texel)\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(this->Storage->block_size() == sizeof(genType));\n\n\t\tfor(size_type TexelIndex = 0; TexelIndex < this->size<genType>(); ++TexelIndex)\n\t\t\t*(this->data<genType>() + TexelIndex) = Texel;\n\t}\n\n\tinline image::data_type* image::compute_data(size_type BaseLayer, size_type BaseFace, size_type BaseLevel)\n\t{\n\t\tsize_type const BaseOffset = this->Storage->base_offset(BaseLayer, BaseFace, BaseLevel);\n\n\t\treturn this->Storage->data() + BaseOffset;\n\t}\n\n\tinline image::size_type image::compute_size(size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Storage->level_size(Level);\n\t}\n\n\ttemplate <typename genType>\n\tgenType image::load(extent_type const& TexelCoord)\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(!is_compressed(this->format()));\n\t\tGLI_ASSERT(this->Storage->block_size() == sizeof(genType));\n\t\tGLI_ASSERT(glm::all(glm::lessThan(TexelCoord, this->extent())));\n\n\t\treturn *(this->data<genType>() + detail::texel_linear_addressing(this->extent(), TexelCoord));\n\t}\n\n\ttemplate <typename genType>\n\tvoid image::store(extent_type const& TexelCoord, genType const& Data)\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(!is_compressed(this->format()));\n\t\tGLI_ASSERT(this->Storage->block_size() == sizeof(genType));\n\t\tGLI_ASSERT(glm::all(glm::lessThan(TexelCoord, this->extent())));\n\n\t\t*(this->data<genType>() + detail::texel_linear_addressing(this->extent(), TexelCoord)) = Data;\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/levels.inl",
    "content": "#include <glm/gtc/integer.hpp>\n#define GLM_ENABLE_EXPERIMENTAL\n#include <glm/gtx/component_wise.hpp>\n\nnamespace gli\n{\n\ttemplate <length_t L, typename T, qualifier Q>\n\tinline T levels(vec<L, T, Q> const& Extent)\n\t{\n\t\treturn glm::log2(compMax(Extent)) + static_cast<T>(1);\n\t}\n\n\ttemplate <typename T>\n\tinline T levels(T Extent)\n\t{\n\t\treturn static_cast<T>(glm::log2(Extent) + static_cast<size_t>(1));\n\t}\n/*\n\tinline int levels(int Extent)\n\t{\n\t\treturn glm::log2(Extent) + static_cast<int>(1);\n\t}\n*/\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/load.inl",
    "content": "#include \"../load_dds.hpp\"\n#include \"../load_kmg.hpp\"\n#include \"../load_ktx.hpp\"\n#include \"file.hpp\"\n\nnamespace gli\n{\n\t/// Load a texture (DDS, KTX or KMG) from memory\n\tinline texture load(char const * Data, std::size_t Size)\n\t{\n\t\t{\n\t\t\ttexture Texture = load_dds(Data, Size);\n\t\t\tif(!Texture.empty())\n\t\t\t\treturn Texture;\n\t\t}\n\t\t{\n\t\t\ttexture Texture = load_kmg(Data, Size);\n\t\t\tif(!Texture.empty())\n\t\t\t\treturn Texture;\n\t\t}\n\t\t{\n\t\t\ttexture Texture = load_ktx(Data, Size);\n\t\t\tif(!Texture.empty())\n\t\t\t\treturn Texture;\n\t\t}\n\n\t\treturn texture();\n\t}\n\n\t/// Load a texture (DDS, KTX or KMG) from file\n\tinline texture load(char const * Filename)\n\t{\n\t\tFILE* File = detail::open_file(Filename, \"rb\");\n\t\tif(!File)\n\t\t\treturn texture();\n\n\t\tlong Beg = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_END);\n\t\tlong End = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_SET);\n\n\t\tstd::vector<char> Data(static_cast<std::size_t>(End - Beg));\n\n\t\tstd::fread(&Data[0], 1, Data.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn load(&Data[0], Data.size());\n\t}\n\n\t/// Load a texture (DDS, KTX or KMG) from file\n\tinline texture load(std::string const & Filename)\n\t{\n\t\treturn load(Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/load_dds.inl",
    "content": "#include \"../dx.hpp\"\n#include \"file.hpp\"\n#include <cstdio>\n#include <cassert>\n\nnamespace gli{\nnamespace detail\n{\n\tstatic char const FOURCC_DDS[] = {'D', 'D', 'S', ' '};\n\n\tenum dds_cubemap_flag\n\t{\n\t\tDDSCAPS2_CUBEMAP\t\t\t\t= 0x00000200,\n\t\tDDSCAPS2_CUBEMAP_POSITIVEX\t\t= 0x00000400,\n\t\tDDSCAPS2_CUBEMAP_NEGATIVEX\t\t= 0x00000800,\n\t\tDDSCAPS2_CUBEMAP_POSITIVEY\t\t= 0x00001000,\n\t\tDDSCAPS2_CUBEMAP_NEGATIVEY\t\t= 0x00002000,\n\t\tDDSCAPS2_CUBEMAP_POSITIVEZ\t\t= 0x00004000,\n\t\tDDSCAPS2_CUBEMAP_NEGATIVEZ\t\t= 0x00008000,\n\t\tDDSCAPS2_VOLUME\t\t\t\t\t= 0x00200000\n\t};\n\n\tenum\n\t{\n\t\tDDSCAPS2_CUBEMAP_ALLFACES = DDSCAPS2_CUBEMAP_POSITIVEX | DDSCAPS2_CUBEMAP_NEGATIVEX | DDSCAPS2_CUBEMAP_POSITIVEY | DDSCAPS2_CUBEMAP_NEGATIVEY | DDSCAPS2_CUBEMAP_POSITIVEZ | DDSCAPS2_CUBEMAP_NEGATIVEZ\n\t};\n\n\tenum dds_flag\n\t{\n\t\tDDSD_CAPS\t\t\t= 0x00000001,\n\t\tDDSD_HEIGHT\t\t\t= 0x00000002,\n\t\tDDSD_WIDTH\t\t\t= 0x00000004,\n\t\tDDSD_PITCH\t\t\t= 0x00000008,\n\t\tDDSD_PIXELFORMAT\t= 0x00001000,\n\t\tDDSD_MIPMAPCOUNT\t= 0x00020000,\n\t\tDDSD_LINEARSIZE\t\t= 0x00080000,\n\t\tDDSD_DEPTH\t\t\t= 0x00800000\n\t};\n\n\tenum dds_surface_flag\n\t{\n\t\tDDSCAPS_COMPLEX\t\t\t\t= 0x00000008,\n\t\tDDSCAPS_MIPMAP\t\t\t\t= 0x00400000,\n\t\tDDSCAPS_TEXTURE\t\t\t\t= 0x00001000\n\t};\n\n\tstruct dds_pixel_format\n\t{\n\t\tstd::uint32_t size; // 32\n\t\tdx::ddpf flags;\n\t\tdx::d3dfmt fourCC;\n\t\tstd::uint32_t bpp;\n\t\tglm::u32vec4 Mask;\n\t};\n\n\tstruct dds_header\n\t{\n\t\tstd::uint32_t Size;\n\t\tstd::uint32_t Flags;\n\t\tstd::uint32_t Height;\n\t\tstd::uint32_t Width;\n\t\tstd::uint32_t Pitch;\n\t\tstd::uint32_t Depth;\n\t\tstd::uint32_t MipMapLevels;\n\t\tstd::uint32_t Reserved1[11];\n\t\tdds_pixel_format Format;\n\t\tstd::uint32_t SurfaceFlags;\n\t\tstd::uint32_t CubemapFlags;\n\t\tstd::uint32_t Reserved2[3];\n\t};\n\n\tstatic_assert(sizeof(dds_header) == 124, \"DDS Header size mismatch\");\n\n\tenum d3d10_resource_dimension\n\t{\n\t\tD3D10_RESOURCE_DIMENSION_UNKNOWN     = 0,\n\t\tD3D10_RESOURCE_DIMENSION_BUFFER      = 1,\n\t\tD3D10_RESOURCE_DIMENSION_TEXTURE1D   = 2,\n\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D   = 3,\n\t\tD3D10_RESOURCE_DIMENSION_TEXTURE3D   = 4\n\t};\n\n\tenum d3d10_resource_misc_flag\n\t{\n\t\tD3D10_RESOURCE_MISC_GENERATE_MIPS\t\t= 0x01,\n\t\tD3D10_RESOURCE_MISC_SHARED\t\t\t\t= 0x02,\n\t\tD3D10_RESOURCE_MISC_TEXTURECUBE\t\t\t= 0x04,\n\t\tD3D10_RESOURCE_MISC_SHARED_KEYEDMUTEX\t= 0x10,\n\t\tD3D10_RESOURCE_MISC_GDI_COMPATIBLE\t\t= 0x20,\n\t};\n\n\tenum dds_alpha_mode\n\t{\n\t\tDDS_ALPHA_MODE_UNKNOWN\t\t\t\t\t= 0x0,\n\t\tDDS_ALPHA_MODE_STRAIGHT\t\t\t\t\t= 0x1,\n\t\tDDS_ALPHA_MODE_PREMULTIPLIED\t\t\t= 0x2,\n\t\tDDS_ALPHA_MODE_OPAQUE\t\t\t\t\t= 0x3,\n\t\tDDS_ALPHA_MODE_CUSTOM\t\t\t\t\t= 0x4\n\t};\n\n\tstruct dds_header10\n\t{\n\t\tdds_header10() :\n\t\t\tFormat(dx::DXGI_FORMAT_UNKNOWN),\n\t\t\tResourceDimension(D3D10_RESOURCE_DIMENSION_UNKNOWN),\n\t\t\tMiscFlag(0),\n\t\t\tArraySize(0),\n\t\t\tAlphaFlags(DDS_ALPHA_MODE_UNKNOWN)\n\t\t{}\n\n\t\tdx::dxgiFormat\t\t\t\tFormat;\n\t\td3d10_resource_dimension\tResourceDimension;\n\t\tstd::uint32_t\t\t\t\tMiscFlag; // D3D10_RESOURCE_MISC_GENERATE_MIPS\n\t\tstd::uint32_t\t\t\t\tArraySize;\n\t\tdds_alpha_mode\t\t\t\tAlphaFlags; // Should be 0 whenever possible to avoid D3D utility library to fail\n\t};\n\n\tstatic_assert(sizeof(dds_header10) == 20, \"DDS DX10 Extended Header size mismatch\");\n\n\tinline target get_target(dds_header const& Header, dds_header10 const& Header10)\n\t{\n\t\tif((Header.CubemapFlags & detail::DDSCAPS2_CUBEMAP) || (Header10.MiscFlag & detail::D3D10_RESOURCE_MISC_TEXTURECUBE))\n\t\t{\n\t\t\tif(Header10.ArraySize > 1)\n\t\t\t\treturn TARGET_CUBE_ARRAY;\n\t\t\telse\n\t\t\t\treturn TARGET_CUBE;\n\t\t}\n\t\telse if(Header10.ArraySize > 1)\n\t\t{\n\t\t\tif(Header.Flags & detail::DDSD_HEIGHT)\n\t\t\t\treturn TARGET_2D_ARRAY;\n\t\t\telse\n\t\t\t\treturn TARGET_1D_ARRAY;\n\t\t}\n\t\telse if(Header10.ResourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE1D)\n\t\t\treturn TARGET_1D;\n\t\telse if(Header10.ResourceDimension == D3D10_RESOURCE_DIMENSION_TEXTURE3D || Header.Flags & detail::DDSD_DEPTH || Header.CubemapFlags & detail::DDSCAPS2_VOLUME)\n\t\t\treturn TARGET_3D;\n\t\telse\n\t\t\treturn TARGET_2D;\n\t}\n\n\t// Some formats have multiple fourcc values. This function allows remapping to the default fourcc value of a format\n\tinline dx::d3dfmt remap_four_cc(dx::d3dfmt FourCC)\n\t{\n\t\tswitch(FourCC)\n\t\t{\n\t\tdefault:\n\t\t\treturn FourCC;\n\t\tcase dx::D3DFMT_BC4U:\n\t\t\treturn dx::D3DFMT_ATI1;\n\t\tcase dx::D3DFMT_BC4S:\n\t\t\treturn dx::D3DFMT_AT1N;\n\t\tcase dx::D3DFMT_BC5U:\n\t\t\treturn dx::D3DFMT_ATI2;\n\t\tcase dx::D3DFMT_BC5S:\n\t\t\treturn dx::D3DFMT_AT2N;\n\t\t}\n\t}\n}//namespace detail\n\n\tinline texture load_dds(char const * Data, std::size_t Size)\n\t{\n\t\tGLI_ASSERT(Data && (Size >= sizeof(detail::FOURCC_DDS)));\n\n\t\tif(strncmp(Data, detail::FOURCC_DDS, 4) != 0)\n\t\t\treturn texture();\n\t\tstd::size_t Offset = sizeof(detail::FOURCC_DDS);\n\n\t\tGLI_ASSERT(Size >= sizeof(detail::dds_header));\n\n\t\tdetail::dds_header const & Header(*reinterpret_cast<detail::dds_header const *>(Data + Offset));\n\t\tOffset += sizeof(detail::dds_header);\n\n\t\tdetail::dds_header10 Header10;\n\t\tif((Header.Format.flags & dx::DDPF_FOURCC) && (Header.Format.fourCC == dx::D3DFMT_DX10 || Header.Format.fourCC == dx::D3DFMT_GLI1))\n\t\t{\n\t\t\tstd::memcpy(&Header10, Data + Offset, sizeof(Header10));\n\t\t\tOffset += sizeof(detail::dds_header10);\n\t\t}\n\n\t\tdx DX;\n\n\t\tgli::format Format(gli::FORMAT_UNDEFINED);\n\t\tif((Header.Format.flags & (dx::DDPF_RGB | dx::DDPF_ALPHAPIXELS | dx::DDPF_ALPHA | dx::DDPF_YUV | dx::DDPF_LUMINANCE)) && Format == gli::FORMAT_UNDEFINED && Header.Format.bpp > 0 && Header.Format.bpp < 64)\n\t\t{\n\t\t\tswitch(Header.Format.bpp)\n\t\t\t{\n\t\t\t\tdefault:\n\t\t\t\t\tGLI_ASSERT(0);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 8:\n\t\t\t\t{\n\t\t\t\t\tif(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG4_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RG4_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_L8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_L8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_A8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_A8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_R8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG3B2_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RG3B2_UNORM_PACK8;\n\t\t\t\t\telse\n\t\t\t\t\t\tGLI_ASSERT(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 16:\n\t\t\t\t{\n\t\t\t\t\tif(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGBA4_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RGBA4_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGRA4_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_BGRA4_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R5G6B5_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_R5G6B5_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_B5G6R5_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_B5G6R5_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGB5A1_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RGB5A1_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGR5A1_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_BGR5A1_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_LA8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_LA8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RG8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_L16_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_L16_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_A16_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_A16_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R16_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_R16_UNORM_PACK16;\n\t\t\t\t\telse\n\t\t\t\t\t\tGLI_ASSERT(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 24:\n\t\t\t\t{\n\t\t\t\t\tif(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGB8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RGB8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGR8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_BGR8_UNORM_PACK8;\n\t\t\t\t\telse\n\t\t\t\t\t\tGLI_ASSERT(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 32:\n\t\t\t\t{\n\t\t\t\t\tif(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGR8_UNORM_PACK32).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_BGR8_UNORM_PACK32;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_BGRA8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_BGRA8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGBA8_UNORM_PACK8).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RGBA8_UNORM_PACK8;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RGB10A2_UNORM_PACK32).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RGB10A2_UNORM_PACK32;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_LA16_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_LA16_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_RG16_UNORM_PACK16).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_RG16_UNORM_PACK16;\n\t\t\t\t\telse if(glm::all(glm::equal(Header.Format.Mask, DX.translate(FORMAT_R32_SFLOAT_PACK32).Mask)))\n\t\t\t\t\t\tFormat = FORMAT_R32_SFLOAT_PACK32;\n\t\t\t\t\telse\n\t\t\t\t\t\tGLI_ASSERT(0);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if((Header.Format.flags & dx::DDPF_FOURCC) && (Header.Format.fourCC != dx::D3DFMT_DX10) && (Header.Format.fourCC != dx::D3DFMT_GLI1) && (Format == gli::FORMAT_UNDEFINED))\n\t\t{\n\t\t\tdx::d3dfmt const FourCC = detail::remap_four_cc(Header.Format.fourCC);\n\t\t\tFormat = DX.find(FourCC);\n\t\t}\n\t\telse if(Header.Format.fourCC == dx::D3DFMT_DX10 || Header.Format.fourCC == dx::D3DFMT_GLI1)\n\t\t\tFormat = DX.find(Header.Format.fourCC, Header10.Format);\n\n\t\tGLI_ASSERT(Format != gli::FORMAT_UNDEFINED);\n\n\t\tsize_t const MipMapCount = (Header.Flags & detail::DDSD_MIPMAPCOUNT) ? Header.MipMapLevels : 1;\n\t\tsize_t FaceCount = 1;\n\t\tif(Header.CubemapFlags & detail::DDSCAPS2_CUBEMAP)\n\t\t\tFaceCount = int(glm::bitCount(Header.CubemapFlags & detail::DDSCAPS2_CUBEMAP_ALLFACES));\n\t\telse if(Header10.MiscFlag & detail::D3D10_RESOURCE_MISC_TEXTURECUBE)\n\t\t\tFaceCount = 6;\n\n\t\tsize_t DepthCount = 1;\n\t\tif(Header.CubemapFlags & detail::DDSCAPS2_VOLUME)\n\t\t\tDepthCount = Header.Depth;\n\n\t\ttexture Texture(\n\t\t\tget_target(Header, Header10), Format,\n\t\t\ttexture::extent_type(Header.Width, Header.Height, DepthCount),\n\t\t\tstd::max<texture::size_type>(Header10.ArraySize, 1), FaceCount, MipMapCount);\n\n\t\tstd::size_t const SourceSize = Offset + Texture.size();\n\t\tGLI_ASSERT(SourceSize == Size);\n\n\t\tstd::memcpy(Texture.data(), Data + Offset, Texture.size());\n\n\t\treturn Texture;\n\t}\n\n\tinline texture load_dds(char const * Filename)\n\t{\n\t\tFILE* File = detail::open_file(Filename, \"rb\");\n\t\tif(!File)\n\t\t\treturn texture();\n\n\t\tlong Beg = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_END);\n\t\tlong End = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_SET);\n\n\t\tstd::vector<char> Data(static_cast<std::size_t>(End - Beg));\n\n\t\tstd::fread(&Data[0], 1, Data.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn load_dds(&Data[0], Data.size());\n\t}\n\n\tinline texture load_dds(std::string const & Filename)\n\t{\n\t\treturn load_dds(Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/load_kmg.inl",
    "content": "#include \"file.hpp\"\n#include <cstdio>\n#include <cassert>\n\nnamespace gli{\nnamespace detail\n{\n\tstatic unsigned char const FOURCC_KMG100[] = {0xAB, 0x4B, 0x49, 0x4D, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};\n\n\tstruct kmgHeader10\n\t{\n\t\tstd::uint32_t Endianness;\n\t\tstd::uint32_t Format;\n\t\tstd::uint32_t Target;\n\t\tstd::uint32_t SwizzleRed;\n\t\tstd::uint32_t SwizzleGreen;\n\t\tstd::uint32_t SwizzleBlue;\n\t\tstd::uint32_t SwizzleAlpha;\n\t\tstd::uint32_t PixelWidth;\n\t\tstd::uint32_t PixelHeight;\n\t\tstd::uint32_t PixelDepth;\n\t\tstd::uint32_t Layers;\n\t\tstd::uint32_t Levels;\n\t\tstd::uint32_t Faces;\n\t\tstd::uint32_t GenerateMipmaps;\n\t\tstd::uint32_t BaseLevel;\n\t\tstd::uint32_t MaxLevel;\n\t};\n\n\tinline texture load_kmg100(char const * Data, std::size_t Size)\n\t{\n\t\tdetail::kmgHeader10 const & Header(*reinterpret_cast<detail::kmgHeader10 const *>(Data));\n\n\t\tsize_t Offset = sizeof(detail::kmgHeader10);\n\n\t\ttexture Texture(\n\t\t\tstatic_cast<target>(Header.Target),\n\t\t\tstatic_cast<format>(Header.Format),\n\t\t\ttexture::extent_type(Header.PixelWidth, Header.PixelHeight, Header.PixelDepth),\n\t\t\tHeader.Layers,\n\t\t\tHeader.Faces,\n\t\t\tHeader.Levels,\n\t\t\ttexture::swizzles_type(Header.SwizzleRed, Header.SwizzleGreen, Header.SwizzleBlue, Header.SwizzleAlpha));\n\n\t\tfor(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer)\n\t\tfor(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level)\n\t\t{\n\t\t\ttexture::size_type const FaceSize = static_cast<texture::size_type>(Texture.size(Level));\n\t\t\tfor(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face)\n\t\t\t{\n\t\t\t\tstd::memcpy(Texture.data(Layer, Face, Level), Data + Offset, FaceSize);\n\n\t\t\t\tOffset += FaceSize;\n\t\t\t\tGLI_ASSERT(Offset <= Size);\n\t\t\t}\n\t\t}\n\n\t\treturn texture(\n\t\t\tTexture, Texture.target(), Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tHeader.BaseLevel, Header.MaxLevel, \n\t\t\tTexture.swizzles());\n\t}\n}//namespace detail\n\n\tinline texture load_kmg(char const * Data, std::size_t Size)\n\t{\n\t\tGLI_ASSERT(Data && (Size >= sizeof(detail::kmgHeader10)));\n\n\t\t// KMG100\n\t\t{\n\t\t\tif(memcmp(Data, detail::FOURCC_KMG100, sizeof(detail::FOURCC_KMG100)) == 0)\n\t\t\t\treturn detail::load_kmg100(Data + sizeof(detail::FOURCC_KMG100), Size - sizeof(detail::FOURCC_KMG100));\n\t\t}\n\n\t\treturn texture();\n\t}\n\n\tinline texture load_kmg(char const * Filename)\n\t{\n\t\tFILE* File = detail::open_file(Filename, \"rb\");\n\t\tif(!File)\n\t\t\treturn texture();\n\n\t\tlong Beg = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_END);\n\t\tlong End = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_SET);\n\n\t\tstd::vector<char> Data(static_cast<std::size_t>(End - Beg));\n\n\t\tstd::fread(&Data[0], 1, Data.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn load_kmg(&Data[0], Data.size());\n\t}\n\n\tinline texture load_kmg(std::string const & Filename)\n\t{\n\t\treturn load_kmg(Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/load_ktx.inl",
    "content": "#include \"../gl.hpp\"\n#include \"file.hpp\"\n#include <cstdio>\n#include <cassert>\n\nnamespace gli{\nnamespace detail\n{\n\tstatic unsigned char const FOURCC_KTX10[] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};\n\tstatic unsigned char const FOURCC_KTX20[] = {0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A};\n\n\tstruct ktx_header10\n\t{\n\t\tstd::uint32_t Endianness;\n\t\tstd::uint32_t GLType;\n\t\tstd::uint32_t GLTypeSize;\n\t\tstd::uint32_t GLFormat;\n\t\tstd::uint32_t GLInternalFormat;\n\t\tstd::uint32_t GLBaseInternalFormat;\n\t\tstd::uint32_t PixelWidth;\n\t\tstd::uint32_t PixelHeight;\n\t\tstd::uint32_t PixelDepth;\n\t\tstd::uint32_t NumberOfArrayElements;\n\t\tstd::uint32_t NumberOfFaces;\n\t\tstd::uint32_t NumberOfMipmapLevels;\n\t\tstd::uint32_t BytesOfKeyValueData;\n\t};\n\n\tinline target get_target(ktx_header10 const& Header)\n\t{\n\t\tif(Header.NumberOfFaces > 1)\n\t\t{\n\t\t\tif(Header.NumberOfArrayElements > 0)\n\t\t\t\treturn TARGET_CUBE_ARRAY;\n\t\t\telse\n\t\t\t\treturn TARGET_CUBE;\n\t\t}\n\t\telse if(Header.NumberOfArrayElements > 0)\n\t\t{\n\t\t\tif(Header.PixelHeight == 0)\n\t\t\t\treturn TARGET_1D_ARRAY;\n\t\t\telse\n\t\t\t\treturn TARGET_2D_ARRAY;\n\t\t}\n\t\telse if(Header.PixelHeight == 0)\n\t\t\treturn TARGET_1D;\n\t\telse if(Header.PixelDepth > 0)\n\t\t\treturn TARGET_3D;\n\t\telse\n\t\t\treturn TARGET_2D;\n\t}\n\n\tinline texture load_ktx10(char const* Data, std::size_t Size)\n\t{\n\t\tdetail::ktx_header10 const & Header(*reinterpret_cast<detail::ktx_header10 const*>(Data));\n\n\t\tsize_t Offset = sizeof(detail::ktx_header10);\n\n\t\t// Skip key value data\n\t\tOffset += Header.BytesOfKeyValueData;\n\n\t\tgl GL(gl::PROFILE_KTX);\n\t\tgli::format const Format = GL.find(\n\t\t\tstatic_cast<gli::gl::internal_format>(Header.GLInternalFormat),\n\t\t\tstatic_cast<gli::gl::external_format>(Header.GLFormat),\n\t\t\tstatic_cast<gli::gl::type_format>(Header.GLType));\n\t\tGLI_ASSERT(Format != gli::FORMAT_UNDEFINED);\n\n\t\ttexture::size_type const BlockSize = block_size(Format);\n\n\t\ttexture Texture(\n\t\t\tdetail::get_target(Header),\n\t\t\tFormat,\n\t\t\ttexture::extent_type(\n\t\t\t\tHeader.PixelWidth,\n\t\t\t\tstd::max<texture::size_type>(Header.PixelHeight, 1),\n\t\t\t\tstd::max<texture::size_type>(Header.PixelDepth, 1)),\n\t\t\tstd::max<texture::size_type>(Header.NumberOfArrayElements, 1),\n\t\t\tstd::max<texture::size_type>(Header.NumberOfFaces, 1),\n\t\t\tstd::max<texture::size_type>(Header.NumberOfMipmapLevels, 1));\n\n\t\tfor(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level)\n\t\t{\n\t\t\tOffset += sizeof(std::uint32_t);\n\n\t\t\tfor(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer)\n\t\t\tfor(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face)\n\t\t\t{\n\t\t\t\ttexture::size_type const FaceSize = Texture.size(Level);\n\n\t\t\t\tstd::memcpy(Texture.data(Layer, Face, Level), Data + Offset, FaceSize);\n\n\t\t\t\tOffset += std::max(BlockSize, glm::ceilMultiple(FaceSize, static_cast<texture::size_type>(4)));\n\t\t\t}\n\t\t}\n\n\t\treturn Texture;\n\t}\n}//namespace detail\n\n\tinline texture load_ktx(char const* Data, std::size_t Size)\n\t{\n\t\tGLI_ASSERT(Data && (Size >= sizeof(detail::ktx_header10)));\n\n\t\t// KTX10\n\t\t{\n\t\t\tif(memcmp(Data, detail::FOURCC_KTX10, sizeof(detail::FOURCC_KTX10)) == 0)\n\t\t\t\treturn detail::load_ktx10(Data + sizeof(detail::FOURCC_KTX10), Size - sizeof(detail::FOURCC_KTX10));\n\t\t}\n\n\t\treturn texture();\n\t}\n\n\tinline texture load_ktx(char const* Filename)\n\t{\n\t\tFILE* File = detail::open_file(Filename, \"rb\");\n\t\tif(!File)\n\t\t\treturn texture();\n\n\t\tlong Beg = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_END);\n\t\tlong End = std::ftell(File);\n\t\tstd::fseek(File, 0, SEEK_SET);\n\n\t\tstd::vector<char> Data(static_cast<std::size_t>(End - Beg));\n\n\t\tstd::fread(&Data[0], 1, Data.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn load_ktx(&Data[0], Data.size());\n\t}\n\n\tinline texture load_ktx(std::string const& Filename)\n\t{\n\t\treturn load_ktx(Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/make_texture.inl",
    "content": "namespace gli\n{\n\tinline gli::texture make_texture1d(format Format, extent1d const& Extent, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_1D, Format, texture::extent_type(Extent.x, 1, 1), 1, 1, Levels);\n\t}\n\n\tinline gli::texture make_texture1d(format Format, extent1d const& Extent)\n\t{\n\t\treturn gli::texture(TARGET_1D, Format, texture::extent_type(Extent.x, 1, 1), 1, 1, gli::levels(texture::extent_type(Extent.x, 1, 1)));\n\t}\n\n\tinline gli::texture make_texture1d_array(format Format, extent1d const& Extent, size_t Layers, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_1D_ARRAY, Format, texture::extent_type(Extent.x, 1, 1), Layers, 1, Levels);\n\t}\n\n\tinline gli::texture make_texture1d_array(format Format, extent1d const& Extent, size_t Layers)\n\t{\n\t\treturn gli::texture(TARGET_1D_ARRAY, Format, texture::extent_type(Extent.x, 1, 1), Layers, 1, gli::levels(texture::extent_type(Extent.x, 1, 1)));\n\t}\n\n\tinline gli::texture make_texture2d(format Format, extent2d const& Extent, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_2D, Format, texture::extent_type(Extent, 1), 1, 1, Levels);\n\t}\n\n\tinline gli::texture make_texture2d(format Format, extent2d const& Extent)\n\t{\n\t\treturn gli::texture(TARGET_2D, Format, texture::extent_type(Extent, 1), 1, 1, gli::levels(texture::extent_type(Extent, 1)));\n\t}\n\n\tinline gli::texture make_texture2d_array(format Format, extent2d const& Extent, size_t Layer, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_2D_ARRAY, Format, texture::extent_type(Extent, 1), Layer, 1, Levels);\n\t}\n\n\tinline gli::texture make_texture2d_array(format Format, extent2d const& Extent, size_t Layer)\n\t{\n\t\treturn gli::texture(TARGET_2D_ARRAY, Format, texture::extent_type(Extent, 1), Layer, 1, gli::levels(texture::extent_type(Extent, 1)));\n\t}\n\n\tinline gli::texture make_texture3d(format Format, extent3d const& Extent, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_3D, Format, texture::extent_type(Extent), 1, 1, Levels);\n\t}\n\n\tinline gli::texture make_texture3d(format Format, extent3d const& Extent)\n\t{\n\t\treturn gli::texture(TARGET_3D, Format, texture::extent_type(Extent), 1, 1, gli::levels(texture::extent_type(Extent)));\n\t}\n\n\tinline gli::texture make_texture_cube(format Format, extent2d const& Extent, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_CUBE, Format, texture::extent_type(Extent, 1), 1, 6, Levels);\n\t}\n\n\tinline gli::texture make_texture_cube(format Format, extent2d const& Extent)\n\t{\n\t\treturn gli::texture(TARGET_CUBE, Format, texture::extent_type(Extent, 1), 1, 6, gli::levels(texture::extent_type(Extent, 1)));\n\t}\n\n\tinline gli::texture make_texture_cube_array(format Format, extent2d const& Extent, size_t Layer, size_t Levels)\n\t{\n\t\treturn gli::texture(TARGET_CUBE_ARRAY, Format, texture::extent_type(Extent, 1), Layer, 6, Levels);\n\t}\n\n\tinline gli::texture make_texture_cube_array(format Format, extent2d const& Extent, size_t Layer)\n\t{\n\t\treturn gli::texture(TARGET_CUBE_ARRAY, Format, texture::extent_type(Extent, 1), Layer, 6, gli::levels(texture::extent_type(Extent, 1)));\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/mipmaps_compute.hpp",
    "content": "#pragma once\n\n#include \"filter_compute.hpp\"\n\nnamespace gli{\nnamespace detail\n{\n\ttemplate <typename texture_type, typename sampler_value_type, typename fetch_func, typename write_func, typename normalized_type, typename texel_type>\n\tinline void generate_mipmaps_1d\n\t(\n\t\ttexture_type & Texture, fetch_func Fetch, write_func Write,\n\t\ttypename texture_type::size_type BaseLayer, typename texture_type::size_type MaxLayer,\n\t\ttypename texture_type::size_type BaseFace, typename texture_type::size_type MaxFace,\n\t\ttypename texture_type::size_type BaseLevel, typename texture_type::size_type MaxLevel,\n\t\tfilter Min\n\t)\n\t{\n\t\ttypedef typename detail::interpolate<sampler_value_type>::type interpolate_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename extent_type::value_type component_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_func, texel_type>::filterFunc filter_func;\n\n\t\tfilter_func const Filter = detail::get_filter<filter_func, detail::DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_func, texel_type, sampler_value_type>(FILTER_NEAREST, Min, false);\n\t\tGLI_ASSERT(Filter);\n\n\t\tfor(size_type Layer = BaseLayer; Layer <= MaxLayer; ++Layer)\n\t\tfor(size_type Face = BaseFace; Face <= MaxFace; ++Face)\n\t\tfor(size_type Level = BaseLevel; Level < MaxLevel; ++Level)\n\t\t{\n\t\t\textent_type const& ExtentDst = Texture.extent(Level + 1);\n\t\t\tnormalized_type const& Scale = normalized_type(1) / normalized_type(max(ExtentDst - extent_type(1), extent_type(1)));\n\n\t\t\tfor(component_type i = 0; i < ExtentDst.x; ++i)\n\t\t\t{\n\t\t\t\tnormalized_type const& SamplePosition(normalized_type(static_cast<typename normalized_type::value_type>(i)) * Scale);\n\t\t\t\ttexel_type const& Texel = Filter(Texture, Fetch, SamplePosition, Layer, Face, static_cast<sampler_value_type>(Level), texel_type(0));\n\t\t\t\tWrite(Texture, extent_type(i), Layer, Face, Level + 1, Texel);\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate <typename texture_type, typename sampler_value_type, typename fetch_func, typename write_func, typename normalized_type, typename texel_type>\n\tinline void generate_mipmaps_2d\n\t(\n\t\ttexture_type & Texture, fetch_func Fetch, write_func Write,\n\t\ttypename texture_type::size_type BaseLayer, typename texture_type::size_type MaxLayer,\n\t\ttypename texture_type::size_type BaseFace, typename texture_type::size_type MaxFace,\n\t\ttypename texture_type::size_type BaseLevel, typename texture_type::size_type MaxLevel,\n\t\tfilter Min\n\t)\n\t{\n\t\ttypedef typename detail::interpolate<sampler_value_type>::type interpolate_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename extent_type::value_type component_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_func, texel_type>::filterFunc filter_func;\n\n\t\tfilter_func const Filter = detail::get_filter<filter_func, detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_func, texel_type, sampler_value_type>(FILTER_NEAREST, Min, false);\n\t\tGLI_ASSERT(Filter);\n\n\t\tfor(size_type Layer = BaseLayer; Layer <= MaxLayer; ++Layer)\n\t\tfor(size_type Face = BaseFace; Face <= MaxFace; ++Face)\n\t\tfor(size_type Level = BaseLevel; Level < MaxLevel; ++Level)\n\t\t{\n\t\t\textent_type const& ExtentDst = Texture.extent(Level + 1);\n\t\t\tnormalized_type const& Scale = normalized_type(1) / normalized_type(max(ExtentDst - extent_type(1), extent_type(1)));\n\n\t\t\tfor(component_type j = 0; j < ExtentDst.y; ++j)\n\t\t\tfor(component_type i = 0; i < ExtentDst.x; ++i)\n\t\t\t{\n\t\t\t\tnormalized_type const& SamplePosition(normalized_type(i, j) * Scale);\n\t\t\t\ttexel_type const& Texel = Filter(Texture, Fetch, SamplePosition, Layer, Face, static_cast<sampler_value_type>(Level), texel_type(0));\n\t\t\t\tWrite(Texture, extent_type(i, j), Layer, Face, Level + 1, Texel);\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate <typename texture_type, typename sampler_value_type, typename fetch_func, typename write_func, typename normalized_type, typename texel_type>\n\tinline void generate_mipmaps_3d\n\t(\n\t\ttexture_type & Texture, fetch_func Fetch, write_func Write,\n\t\ttypename texture_type::size_type BaseLayer, typename texture_type::size_type MaxLayer,\n\t\ttypename texture_type::size_type BaseFace, typename texture_type::size_type MaxFace,\n\t\ttypename texture_type::size_type BaseLevel, typename texture_type::size_type MaxLevel,\n\t\tfilter Min\n\t)\n\t{\n\t\ttypedef typename detail::interpolate<sampler_value_type>::type interpolate_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename extent_type::value_type component_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_func, texel_type>::filterFunc filter_func;\n\n\t\tfilter_func const Filter = detail::get_filter<filter_func, detail::DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_func, texel_type, sampler_value_type>(FILTER_NEAREST, Min, false);\n\t\tGLI_ASSERT(Filter);\n\n\t\tfor(size_type Layer = BaseLayer; Layer <= MaxLayer; ++Layer)\n\t\tfor(size_type Face = BaseFace; Face <= MaxFace; ++Face)\n\t\tfor(size_type Level = BaseLevel; Level < MaxLevel; ++Level)\n\t\t{\n\t\t\textent_type const& ExtentDst = Texture.extent(Level + 1);\n\t\t\tnormalized_type const& Scale = normalized_type(1) / normalized_type(max(ExtentDst - extent_type(1), extent_type(1)));\n\n\t\t\tfor(component_type k = 0; k < ExtentDst.z; ++k)\n\t\t\tfor(component_type j = 0; j < ExtentDst.y; ++j)\n\t\t\tfor(component_type i = 0; i < ExtentDst.x; ++i)\n\t\t\t{\n\t\t\t\tnormalized_type const& SamplePosition(normalized_type(i, j, k) * Scale);\n\t\t\t\ttexel_type const& Texel = Filter(Texture, Fetch, SamplePosition, Layer, Face, static_cast<sampler_value_type>(Level), texel_type(0));\n\t\t\t\tWrite(Texture, extent_type(i, j, k), Layer, Face, Level + 1, Texel);\n\t\t\t}\n\t\t}\n\t}\n}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/reduce.inl",
    "content": "#include \"../sampler1d.hpp\"\n#include \"../sampler1d_array.hpp\"\n#include \"../sampler2d.hpp\"\n#include \"../sampler2d_array.hpp\"\n#include \"../sampler3d.hpp\"\n#include \"../sampler_cube.hpp\"\n#include \"../sampler_cube_array.hpp\"\n\nnamespace gli\n{\n\ttemplate <typename val_type>\n\tstruct binary_func\n\t{\n\t\ttypedef vec<4, val_type>(*type)(vec<4, val_type> const& A, vec<4, val_type> const& B);\n\t};\n\nnamespace detail\n{\n\tinline bool are_compatible(texture const& A, texture const& B)\n\t{\n\t\treturn all(equal(A.extent(), B.extent())) && A.levels() == B.levels() && A.faces() == B.faces() && A.layers() == B.layers();\n\t}\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_1d\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture1d::size_type size_type;\n\t\ttypedef texture1d::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture1d const& A, texture1d const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler1d<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0), SamplerB.template fetch(TexelIndex, 0)));\n\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_1d_array\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture1d_array::size_type size_type;\n\t\ttypedef texture1d_array::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture1d_array const& A, texture1d_array const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler1d_array<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0, 0), SamplerB.template fetch(TexelIndex, 0, 0)));\n\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, LayerIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, LayerIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_2d\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture2d::size_type size_type;\n\t\ttypedef texture2d::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture2d const& A, texture2d const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler2d<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0), SamplerB.template fetch(TexelIndex, 0)));\n\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_2d_array\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture2d_array::size_type size_type;\n\t\ttypedef texture2d_array::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture2d_array const& A, texture2d_array const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler2d_array<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0, 0), SamplerB.template fetch(TexelIndex, 0, 0)));\n\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, LayerIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, LayerIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_3d\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture3d::size_type size_type;\n\t\ttypedef texture3d::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture3d const& A, texture3d const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler3d<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0), SamplerB.template fetch(TexelIndex, 0)));\n\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.z = 0; TexelIndex.z < TexelCount.z; ++TexelIndex.z)\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_cube\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture_cube::size_type size_type;\n\t\ttypedef texture_cube::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture_cube const& A, texture_cube const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler_cube<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0, 0), SamplerB.template fetch(TexelIndex, 0, 0)));\n\n\t\t\tfor(size_type FaceIndex = 0, FaceCount = A.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, FaceIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, FaceIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate <typename val_type>\n\tstruct compute_sampler_reduce_cube_array\n\t{\n\t\ttypedef typename binary_func<val_type>::type func_type;\n\t\ttypedef texture_cube_array::size_type size_type;\n\t\ttypedef texture_cube_array::extent_type extent_type;\n\n\t\tstatic vec<4, val_type> call(texture_cube_array const& A, texture_cube_array const& B, binary_func<val_type> TexelFunc, binary_func<val_type> ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(are_compatible(A, B));\n\n\t\t\tsampler_cube_array<val_type> const SamplerA(A, gli::WRAP_CLAMP_TO_EDGE), SamplerB(B, gli::WRAP_CLAMP_TO_EDGE);\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec<4, val_type> Result(TexelFunc(SamplerA.template fetch(TexelIndex, 0, 0, 0), SamplerB.template fetch(TexelIndex, 0, 0, 0)));\n\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type FaceIndex = 0, FaceCount = A.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tSamplerA.template fetch(TexelIndex, LayerIndex, FaceIndex, LevelIndex),\n\t\t\t\t\t\tSamplerB.template fetch(TexelIndex, LayerIndex, FaceIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n\nnamespace detail\n{\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_1d\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture1d::size_type size_type;\n\t\ttypedef texture1d::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture1d const& A, texture1d const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.template load<vec_type>(TexelIndex, 0),\n\t\t\t\tB.template load<vec_type>(TexelIndex, 0)));\n\t\t\t\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_1d_array\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture1d_array::size_type size_type;\n\t\ttypedef texture1d_array::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture1d_array const& A, texture1d_array const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.template load<vec_type>(TexelIndex, 0),\n\t\t\t\tB.template load<vec_type>(TexelIndex, 0)));\n\t\t\t\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, LayerIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, LayerIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_2d\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture2d::size_type size_type;\n\t\ttypedef texture2d::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture2d const& A, texture2d const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.template load<vec_type>(TexelIndex, 0),\n\t\t\t\tB.template load<vec_type>(TexelIndex, 0)));\n\t\t\t\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_2d_array\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture2d_array::size_type size_type;\n\t\ttypedef texture2d_array::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture2d_array const& A, texture2d_array const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.template load<vec_type>(TexelIndex, 0, 0),\n\t\t\t\tB.template load<vec_type>(TexelIndex, 0, 0)));\n\t\t\t\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, LayerIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, LayerIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_3d\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture3d::size_type size_type;\n\t\ttypedef texture3d::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture3d const& A, texture3d const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.template load<vec_type>(TexelIndex, 0),\n\t\t\t\tB.template load<vec_type>(TexelIndex, 0)));\n\t\t\t\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.z = 0; TexelIndex.z < TexelCount.z; ++TexelIndex.z)\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_cube\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture_cube::size_type size_type;\n\t\ttypedef texture_cube::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture_cube const& A, texture_cube const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.load<vec_type>(TexelIndex, 0, 0),\n\t\t\t\tB.load<vec_type>(TexelIndex, 0, 0)));\n\t\t\t\n\t\t\tfor(size_type FaceIndex = 0, FaceCount = A.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, FaceIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, FaceIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_reduce_cube_array\n\t{\n\t\ttypedef typename reduce_func<vec_type>::type func_type;\n\t\ttypedef texture_cube_array::size_type size_type;\n\t\ttypedef texture_cube_array::extent_type extent_type;\n\t\t\n\t\tstatic vec_type call(texture_cube_array const& A, texture_cube_array const& B, func_type TexelFunc, func_type ReduceFunc)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\textent_type TexelIndex(0);\n\t\t\tvec_type Result(TexelFunc(\n\t\t\t\tA.load<vec_type>(TexelIndex, 0, 0, 0),\n\t\t\t\tB.load<vec_type>(TexelIndex, 0, 0 ,0)));\n\t\t\t\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type FaceIndex = 0, FaceCount = A.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tResult = ReduceFunc(Result, TexelFunc(\n\t\t\t\t\t\tA.template load<vec_type>(TexelIndex, LayerIndex, FaceIndex, LevelIndex),\n\t\t\t\t\t\tB.template load<vec_type>(TexelIndex, LayerIndex, FaceIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namepsace detail\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture1d const& In0, texture1d const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_1d<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture1d_array const& In0, texture1d_array const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_1d_array<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture2d const& In0, texture2d const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_2d<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture2d_array const& In0, texture2d_array const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_2d_array<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture3d const& In0, texture3d const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_3d<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture_cube const& In0, texture_cube const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_cube<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n\ntemplate <typename vec_type>\ninline vec_type reduce(texture_cube_array const& In0, texture_cube_array const& In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc)\n{\n\treturn detail::compute_reduce_cube_array<vec_type>::call(In0, In1, TexelFunc, ReduceFunc);\n}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/s3tc.hpp",
    "content": "/// @brief Include to compress and decompress s3tc blocks\n/// @file gli/s3tc.hpp\n\n#pragma once\n\n#include <glm/ext/scalar_uint_sized.hpp>\n\nnamespace gli\n{\n\tnamespace detail\n\t{\n\t\tstruct dxt1_block {\n\t\t\tglm::uint16 Color0;\n\t\t\tglm::uint16 Color1;\n\t\t\tglm::uint8 Row[4];\n\t\t};\n\n\t\tstruct dxt3_block {\n\t\t\tglm::uint16 AlphaRow[4];\n\t\t\tglm::uint16 Color0;\n\t\t\tglm::uint16 Color1;\n\t\t\tglm::uint8 Row[4];\n\t\t};\n\n\t\tstruct dxt5_block {\n\t\t\tglm::uint8 Alpha[2];\n\t\t\tglm::uint8 AlphaBitmap[6];\n\t\t\tglm::uint16 Color0;\n\t\t\tglm::uint16 Color1;\n\t\t\tglm::uint8 Row[4];\n\t\t};\n\n\t\tstruct texel_block4x4 {\n\t\t\t// row x col\n\t\t\tglm::vec4 Texel[4][4];\n\t\t};\n\t\t\n\t\tglm::vec4 decompress_dxt1(const dxt1_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_dxt1_block(const dxt1_block &Block);\n\n\t\tglm::vec4 decompress_dxt3(const dxt3_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_dxt3_block(const dxt3_block &Block);\n\n\t\tglm::vec4 decompress_dxt5(const dxt5_block &Block, const extent2d &BlockTexelCoord);\n\t\ttexel_block4x4 decompress_dxt5_block(const dxt5_block &Block);\n\n\t}//namespace detail\n}//namespace gli\n\n#include \"./s3tc.inl\"\n"
  },
  {
    "path": "lib/gli/core/s3tc.inl",
    "content": "#include <glm/ext/vector_packing.hpp>\n#include <glm/gtc/packing.hpp>\n\nnamespace gli\n{\n\tnamespace detail\n\t{\n\t\tinline glm::vec4 decompress_dxt1(const dxt1_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tglm::vec4 Color[4];\n\n\t\t\tColor[0] = glm::vec4(unpackUnorm1x5_1x6_1x5(Block.Color0), 1.0f);\n\t\t\tstd::swap(Color[0].r, Color[0].b);\n\t\t\tColor[1] = glm::vec4(unpackUnorm1x5_1x6_1x5(Block.Color1), 1.0f);\n\t\t\tstd::swap(Color[1].r, Color[1].b);\n\n\t\t\tif(Block.Color0 > Block.Color1)\n\t\t\t{\n\t\t\t\tColor[2] = (2.0f / 3.0f) * Color[0] + (1.0f / 3.0f) * Color[1];\n\t\t\t\tColor[3] = (1.0f / 3.0f) * Color[0] + (2.0f / 3.0f) * Color[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tColor[2] = (Color[0] + Color[1]) / 2.0f;\n\t\t\t\tColor[3] = glm::vec4(0.0f);\n\t\t\t}\n\n\t\t\tglm::uint8 ColorIndex = (Block.Row[BlockTexelCoord.y] >> (BlockTexelCoord.x * 2)) & 0x3;\n\t\t\treturn Color[ColorIndex];\n\t\t}\n\n\t\tinline texel_block4x4 decompress_dxt1_block(const dxt1_block &Block)\n\t\t{\n\t\t\tglm::vec4 Color[4];\n\n\t\t\tColor[0] = glm::vec4(unpackUnorm1x5_1x6_1x5(Block.Color0), 1.0f);\n\t\t\tstd::swap(Color[0].r, Color[0].b);\n\t\t\tColor[1] = glm::vec4(unpackUnorm1x5_1x6_1x5(Block.Color1), 1.0f);\n\t\t\tstd::swap(Color[1].r, Color[1].b);\n\n\t\t\tif(Block.Color0 > Block.Color1)\n\t\t\t{\n\t\t\t\tColor[2] = (2.0f / 3.0f) * Color[0] + (1.0f / 3.0f) * Color[1];\n\t\t\t\tColor[3] = (1.0f / 3.0f) * Color[0] + (2.0f / 3.0f) * Color[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tColor[2] = (Color[0] + Color[1]) / 2.0f;\n\t\t\t\tColor[3] = glm::vec4(0.0f);\n\t\t\t}\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 ColorIndex = (Block.Row[Row] >> (Col * 2)) & 0x3;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = Color[ColorIndex];\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\treturn TexelBlock;\n\t\t}\n\n\t\tinline glm::vec4 decompress_dxt3(const dxt3_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tglm::vec3 Color[4];\n\n\t\t\tColor[0] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color0));\n\t\t\tstd::swap(Color[0].r, Color[0].b);\n\t\t\tColor[1] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color1));\n\t\t\tstd::swap(Color[1].r, Color[1].b);\n\n\t\t\tColor[2] = (2.0f / 3.0f) * Color[0] + (1.0f / 3.0f) * Color[1];\n\t\t\tColor[3] = (1.0f / 3.0f) * Color[0] + (2.0f / 3.0f) * Color[1];\n\n\t\t\tglm::uint8 ColorIndex = (Block.Row[BlockTexelCoord.y] >> (BlockTexelCoord.x * 2)) & 0x3;\n\t\t\tfloat Alpha = ((Block.AlphaRow[BlockTexelCoord.y] >> (BlockTexelCoord.x * 4)) & 0xF) / 15.0f;\n\n\t\t\treturn glm::vec4(Color[ColorIndex], Alpha);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_dxt3_block(const dxt3_block &Block)\n\t\t{\n\t\t\tglm::vec3 Color[4];\n\n\t\t\tColor[0] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color0));\n\t\t\tstd::swap(Color[0].r, Color[0].b);\n\t\t\tColor[1] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color1));\n\t\t\tstd::swap(Color[1].r, Color[1].b);\n\n\t\t\tColor[2] = (2.0f / 3.0f) * Color[0] + (1.0f / 3.0f) * Color[1];\n\t\t\tColor[3] = (1.0f / 3.0f) * Color[0] + (2.0f / 3.0f) * Color[1];\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 ColorIndex = (Block.Row[Row] >> (Col * 2)) & 0x3;\n\t\t\t\t\tfloat Alpha = ((Block.AlphaRow[Row] >> (Col * 4)) & 0xF) / 15.0f;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = glm::vec4(Color[ColorIndex], Alpha);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn TexelBlock;\n\t\t}\n\n\t\tinline glm::vec4 decompress_dxt5(const dxt5_block &Block, const extent2d &BlockTexelCoord)\n\t\t{\n\t\t\tglm::vec3 Color[4];\n\t\t\tfloat Alpha[8];\n\n\t\t\tColor[0] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color0));\n\t\t\tstd::swap(Color[0].r, Color[0].b);\n\t\t\tColor[1] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color1));\n\t\t\tstd::swap(Color[1].r, Color[1].b);\n\n\t\t\tColor[2] = (2.0f / 3.0f) * Color[0] + (1.0f / 3.0f) * Color[1];\n\t\t\tColor[3] = (1.0f / 3.0f) * Color[0] + (2.0f / 3.0f) * Color[1];\n\n\t\t\tglm::uint8 ColorIndex = (Block.Row[BlockTexelCoord.y] >> (BlockTexelCoord.x * 2)) & 0x3;\n\n\t\t\tAlpha[0] = Block.Alpha[0] / 255.0f;\n\t\t\tAlpha[1] = Block.Alpha[1] / 255.0f;\n\n\t\t\tif(Alpha[0] > Alpha[1])\n\t\t\t{\n\t\t\t\tAlpha[2] = (6.0f / 7.0f) * Alpha[0] + (1.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[3] = (5.0f / 7.0f) * Alpha[0] + (2.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[4] = (4.0f / 7.0f) * Alpha[0] + (3.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[5] = (3.0f / 7.0f) * Alpha[0] + (4.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[6] = (2.0f / 7.0f) * Alpha[0] + (5.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[7] = (1.0f / 7.0f) * Alpha[0] + (6.0f / 7.0f) * Alpha[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tAlpha[2] = (4.0f / 5.0f) * Alpha[0] + (1.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[3] = (3.0f / 5.0f) * Alpha[0] + (2.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[4] = (2.0f / 5.0f) * Alpha[0] + (3.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[5] = (1.0f / 5.0f) * Alpha[0] + (4.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[6] = 0.0f;\n\t\t\t\tAlpha[7] = 1.0f;\n\t\t\t}\n\n\t\t\tglm::uint64 Bitmap;\n\t\t\tBitmap = Block.AlphaBitmap[0] | (Block.AlphaBitmap[1] << 8) | (Block.AlphaBitmap[2] << 16);\n\t\t\tBitmap |= glm::uint64(Block.AlphaBitmap[3] | (Block.AlphaBitmap[4] << 8) | (Block.AlphaBitmap[5] << 16)) << 24;\n\n\t\t\tglm::uint8 AlphaIndex = (Bitmap >> ((BlockTexelCoord.y * 4 + BlockTexelCoord.x) * 3)) & 0x7;\n\n\t\t\treturn glm::vec4(Color[ColorIndex], Alpha[AlphaIndex]);\n\t\t}\n\n\t\tinline texel_block4x4 decompress_dxt5_block(const dxt5_block &Block)\n\t\t{\n\t\t\tglm::vec3 Color[4];\n\t\t\tfloat Alpha[8];\n\n\t\t\tColor[0] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color0));\n\t\t\tstd::swap(Color[0].r, Color[0].b);\n\t\t\tColor[1] = glm::vec3(unpackUnorm1x5_1x6_1x5(Block.Color1));\n\t\t\tstd::swap(Color[1].r, Color[1].b);\n\n\t\t\tColor[2] = (2.0f / 3.0f) * Color[0] + (1.0f / 3.0f) * Color[1];\n\t\t\tColor[3] = (1.0f / 3.0f) * Color[0] + (2.0f / 3.0f) * Color[1];\n\n\t\t\tAlpha[0] = Block.Alpha[0] / 255.0f;\n\t\t\tAlpha[1] = Block.Alpha[1] / 255.0f;\n\n\t\t\tif(Alpha[0] > Alpha[1])\n\t\t\t{\n\t\t\t\tAlpha[2] = (6.0f / 7.0f) * Alpha[0] + (1.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[3] = (5.0f / 7.0f) * Alpha[0] + (2.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[4] = (4.0f / 7.0f) * Alpha[0] + (3.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[5] = (3.0f / 7.0f) * Alpha[0] + (4.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[6] = (2.0f / 7.0f) * Alpha[0] + (5.0f / 7.0f) * Alpha[1];\n\t\t\t\tAlpha[7] = (1.0f / 7.0f) * Alpha[0] + (6.0f / 7.0f) * Alpha[1];\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tAlpha[2] = (4.0f / 5.0f) * Alpha[0] + (1.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[3] = (3.0f / 5.0f) * Alpha[0] + (2.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[4] = (2.0f / 5.0f) * Alpha[0] + (3.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[5] = (1.0f / 5.0f) * Alpha[0] + (4.0f / 5.0f) * Alpha[1];\n\t\t\t\tAlpha[6] = 0.0f;\n\t\t\t\tAlpha[7] = 1.0f;\n\t\t\t}\n\n\t\t\tglm::uint64 Bitmap;\n\t\t\tBitmap = Block.AlphaBitmap[0] | (Block.AlphaBitmap[1] << 8) | (Block.AlphaBitmap[2] << 16);\n\t\t\tBitmap |= glm::uint64(Block.AlphaBitmap[3] | (Block.AlphaBitmap[4] << 8) | (Block.AlphaBitmap[5] << 16)) << 24;\n\n\t\t\ttexel_block4x4 TexelBlock;\n\t\t\tfor(glm::uint8 Row = 0; Row < 4; ++Row)\n\t\t\t{\n\t\t\t\tfor(glm::uint8 Col = 0; Col < 4; ++Col)\n\t\t\t\t{\n\t\t\t\t\tglm::uint8 ColorIndex = (Block.Row[Row] >> (Col * 2)) & 0x3;\n\t\t\t\t\tglm::uint8 AlphaIndex = (Bitmap >> ((Row * 4 + Col) * 3)) & 0x7;\n\t\t\t\t\tTexelBlock.Texel[Row][Col] = glm::vec4(Color[ColorIndex], Alpha[AlphaIndex]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn TexelBlock;\n\t\t}\n\t}//namespace detail\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/sampler.inl",
    "content": "#define GLM_ENABLE_EXPERIMENTAL\n#include <glm/gtx/wrap.hpp>\n\nnamespace gli{\nnamespace detail\n{\n\ttemplate <typename T>\n\tinline T passThrought(T const & SampleCoord)\n\t{\n\t\treturn SampleCoord;\n\t}\n}//namespace detail\n\n\tinline sampler::sampler(wrap Wrap, filter Mip, filter Min)\n\t\t: Wrap(get_func(Wrap))\n\t\t, Mip(Mip)\n\t\t, Min(Min)\n\t{}\n\n\tinline sampler::wrap_type sampler::get_func(wrap WrapMode) const\n\t{\n\t\tstatic wrap_type Table[] =\n\t\t{\n\t\t\tglm::clamp,\n\t\t\tdetail::passThrought,\n\t\t\tglm::repeat,\n\t\t\tglm::mirrorRepeat,\n\t\t\tglm::mirrorClamp,\n\t\t\tglm::mirrorClamp\n\t\t};\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == WRAP_COUNT, \"Table needs to be updated\");\n\n\t\treturn Table[WrapMode];\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/sampler1d.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler1d<T, P>::sampler1d(texture_type const & Texture, wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_type, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(Texture.format()));\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler1d<T, P>::texture_type const & sampler1d<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler1d<T, P>::texel_type sampler1d<T, P>::texel_fetch(extent_type const & TexelCoord, size_type const & Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, 0, 0, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d<T, P>::texel_write(extent_type const & TexelCoord, size_type const & Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, 0, 0, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler1d<T, P>::texel_type sampler1d<T, P>::texture_lod(normalized_type const & SampleCoord, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x));\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, size_type(0), size_type(0), Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d<T, P>::generate_mipmaps(size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_1d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, 0, 0, 0, 0, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/sampler1d_array.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler1d_array<T, P>::sampler1d_array(texture_type const & Texture, gli::wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_type, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(Texture.format()));\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler1d_array<T, P>::texture_type const & sampler1d_array<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler1d_array<T, P>::texel_type sampler1d_array<T, P>::texel_fetch(extent_type const & TexelCoord, size_type layer, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, layer, 0, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d_array<T, P>::texel_write(extent_type const & TexelCoord, size_type layer, size_type Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, layer, 0, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d_array<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler1d_array<T, P>::texel_type sampler1d_array<T, P>::texture_lod(normalized_type const & SampleCoord, size_type Layer, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x));\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, Layer, size_type(0), Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d_array<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_layer(), this->Texture.max_layer(), this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler1d_array<T, P>::generate_mipmaps(size_type BaseLayer, size_type MaxLayer, size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_layer() <= BaseLayer && BaseLayer <= MaxLayer && MaxLayer <= this->Texture.max_layer());\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_1d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, BaseLayer, MaxLayer, 0, 0, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/sampler2d.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/gtc/integer.hpp>\n#include <glm/exponential.hpp>\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler2d<T, P>::sampler2d(texture_type const & Texture, wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_type, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d<T, P>::texture_type const & sampler2d<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d<T, P>::texel_type sampler2d<T, P>::texel_fetch(extent_type const & TexelCoord, size_type const & Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, 0, 0, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d<T, P>::texel_write(extent_type const & TexelCoord, size_type const & Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, 0, 0, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d<T, P>::texel_type sampler2d<T, P>::texture_lod(normalized_type const & SampleCoord, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x), this->Wrap(SampleCoord.y));\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, size_type(0), size_type(0), Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d<T, P>::texel_type sampler2d<T, P>::texture_grad(normalized_type const & SampleCoord, normalized_type const& dPdx, normalized_type const& dPdy) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x), this->Wrap(SampleCoord.y));\n\n\t\textent_type const TextureSize = this->Texture.extent(0);\n\n\t\tint const LevelCount = glm::log2<int>(max(TextureSize.x, TextureSize.y));\n\t\tT const d = max(dot(dPdx, dPdx), dot(dPdy, dPdy));\n\t\tT const Clamped = clamp(d, static_cast<T>(1), static_cast<T>(pow(2, (LevelCount - 1) * 2)));\n\n\t\tT const Level = static_cast<T>(0.5) * glm::log2<T>(Clamped);\n\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, size_type(0), size_type(0), Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d<T, P>::generate_mipmaps(size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_2d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, 0, 0, 0, 0, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/sampler2d_array.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler2d_array<T, P>::sampler2d_array(texture_type const & Texture, gli::wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_type, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(Texture.format()));\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d_array<T, P>::texture_type const & sampler2d_array<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d_array<T, P>::texel_type sampler2d_array<T, P>::texel_fetch(extent_type const & TexelCoord, size_type layer, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, layer, 0, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d_array<T, P>::texel_write(extent_type const & TexelCoord, size_type layer, size_type Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, layer, 0, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d_array<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler2d_array<T, P>::texel_type sampler2d_array<T, P>::texture_lod(normalized_type const & SampleCoord, size_type Layer, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x), this->Wrap(SampleCoord.y));\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, Layer, size_type(0), Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d_array<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_layer(), this->Texture.max_layer(), this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler2d_array<T, P>::generate_mipmaps(size_type BaseLayer, size_type MaxLayer, size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_layer() <= BaseLayer && BaseLayer <= MaxLayer && MaxLayer <= this->Texture.max_layer());\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_2d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, BaseLayer, MaxLayer, 0, 0, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/sampler3d.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler3d<T, P>::sampler3d(texture_type const & Texture, wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_type, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(Texture.format()));\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler3d<T, P>::texture_type const & sampler3d<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler3d<T, P>::texel_type sampler3d<T, P>::texel_fetch(extent_type const & TexelCoord, size_type const & Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, 0, 0, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler3d<T, P>::texel_write(extent_type const & TexelCoord, size_type const & Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, 0, 0, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler3d<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tGLI_FORCE_INLINE typename sampler3d<T, P>::texel_type sampler3d<T, P>::texture_lod(normalized_type const & SampleCoord, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x), this->Wrap(SampleCoord.y), this->Wrap(SampleCoord.z));\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, size_type(0), size_type(0), Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler3d<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler3d<T, P>::generate_mipmaps(size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_3d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, 0, 0, 0, 0, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/sampler_cube.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler_cube<T, P>::sampler_cube(texture_cube const & Texture, gli::wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_cube, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(Texture.format()));\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline texture_cube const & sampler_cube<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler_cube<T, P>::texel_type sampler_cube<T, P>::texel_fetch(extent_type const & TexelCoord, size_type Face, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, 0, Face, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube<T, P>::texel_write(extent_type const & TexelCoord, size_type Face, size_type Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, 0, Face, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler_cube<T, P>::texel_type sampler_cube<T, P>::texture_lod(normalized_type const & SampleCoord, size_type Face, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x), this->Wrap(SampleCoord.y));\n\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, size_type(0), Face, Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_face(), this->Texture.max_face(), this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube<T, P>::generate_mipmaps(size_type BaseFace, size_type MaxFace, size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_face() <= BaseFace && BaseFace <= MaxFace && MaxFace <= this->Texture.max_face());\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_2d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, 0, 0, BaseFace, MaxFace, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/sampler_cube_array.inl",
    "content": "#include \"clear.hpp\"\n#include <glm/vector_relational.hpp>\n\nnamespace gli\n{\n\ttemplate <typename T, qualifier P>\n\tinline sampler_cube_array<T, P>::sampler_cube_array(texture_type const & Texture, gli::wrap Wrap, filter Mip, filter Min, texel_type const & BorderColor)\n\t\t: sampler(Wrap, Texture.levels() > 1 ? Mip : FILTER_NEAREST, Min)\n\t\t, Texture(Texture)\n\t\t, Convert(detail::convert<texture_type, T, P>::call(this->Texture.format()))\n\t\t, BorderColor(BorderColor)\n\t\t, Filter(detail::get_filter<filter_type, detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type, T>(Mip, Min, is_border(Wrap)))\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(Texture.format()));\n\t\tGLI_ASSERT((!std::numeric_limits<T>::is_iec559 && Mip == FILTER_NEAREST && Min == FILTER_NEAREST) || std::numeric_limits<T>::is_iec559);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler_cube_array<T, P>::texture_type const & sampler_cube_array<T, P>::operator()() const\n\t{\n\t\treturn this->Texture;\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler_cube_array<T, P>::texel_type sampler_cube_array<T, P>::texel_fetch(extent_type const & TexelCoord, size_type layer, size_type Face, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Fetch);\n\n\t\treturn this->Convert.Fetch(this->Texture, TexelCoord, layer, Face, Level);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube_array<T, P>::texel_write(extent_type const & TexelCoord, size_type layer, size_type Face, size_type Level, texel_type const & Texel)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tthis->Convert.Write(this->Texture, TexelCoord, layer, Face, Level, Texel);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube_array<T, P>::clear(texel_type const & Color)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(this->Convert.Write);\n\n\t\tdetail::clear<texture_type, T, P>::call(this->Texture, this->Convert.Write, Color);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline typename sampler_cube_array<T, P>::texel_type sampler_cube_array<T, P>::texture_lod(normalized_type const & SampleCoord, size_type Layer, size_type Face, level_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(std::numeric_limits<T>::is_iec559);\n\t\tGLI_ASSERT(this->Filter && this->Convert.Fetch);\n\n\t\tnormalized_type const SampleCoordWrap(this->Wrap(SampleCoord.x), this->Wrap(SampleCoord.y));\n\t\treturn this->Filter(this->Texture, this->Convert.Fetch, SampleCoordWrap, Layer, Face, Level, this->BorderColor);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube_array<T, P>::generate_mipmaps(filter Minification)\n\t{\n\t\tthis->generate_mipmaps(this->Texture.base_layer(), this->Texture.max_layer(), this->Texture.base_face(), this->Texture.max_face(), this->Texture.base_level(), this->Texture.max_level(), Minification);\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline void sampler_cube_array<T, P>::generate_mipmaps(size_type BaseLayer, size_type MaxLayer, size_type BaseFace, size_type MaxFace, size_type BaseLevel, size_type MaxLevel, filter Minification)\n\t{\n\t\tGLI_ASSERT(!this->Texture.empty());\n\t\tGLI_ASSERT(!is_compressed(this->Texture.format()));\n\t\tGLI_ASSERT(this->Texture.base_layer() <= BaseLayer && BaseLayer <= MaxLayer && MaxLayer <= this->Texture.max_layer());\n\t\tGLI_ASSERT(this->Texture.base_face() <= BaseFace && BaseFace <= MaxFace && MaxFace <= this->Texture.max_face());\n\t\tGLI_ASSERT(this->Texture.base_level() <= BaseLevel && BaseLevel <= MaxLevel && MaxLevel <= this->Texture.max_level());\n\t\tGLI_ASSERT(this->Convert.Fetch && this->Convert.Write);\n\t\tGLI_ASSERT(Minification >= FILTER_FIRST && Minification <= FILTER_LAST);\n\n\t\tdetail::generate_mipmaps_2d<texture_type, T, fetch_type, write_type, normalized_type, texel_type>(\n\t\t\tthis->Texture, this->Convert.Fetch, this->Convert.Write, BaseLayer, MaxLayer, BaseFace, MaxFace, BaseLevel, MaxLevel, Minification);\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/save.inl",
    "content": "#include \"../save_dds.hpp\"\n#include \"../save_kmg.hpp\"\n#include \"../save_ktx.hpp\"\n\nnamespace gli\n{\n\tinline bool save(texture const & Texture, char const * Path)\n\t{\n\t\treturn save(Texture, std::string(Path));\n\t}\n\n\tinline bool save(texture const & Texture, std::string const & Path)\n\t{\n\t\tif(Path.rfind(\".dds\") != std::string::npos)\n\t\t\treturn save_dds(Texture, Path);\n\t\tif(Path.rfind(\".kmg\") != std::string::npos)\n\t\t\treturn save_kmg(Texture, Path);\n\t\tif(Path.rfind(\".ktx\") != std::string::npos)\n\t\t\treturn save_ktx(Texture, Path);\n\t\treturn false;\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/save_dds.inl",
    "content": "#include <cstdio>\n#include \"../load_dds.hpp\"\n#include \"file.hpp\"\n\nnamespace gli{\nnamespace detail\n{\n\tinline d3d10_resource_dimension get_dimension(gli::target Target)\n\t{\n\t\tstatic d3d10_resource_dimension Table[] = //TARGET_COUNT\n\t\t{\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE1D,\t\t//TARGET_1D,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE1D,\t\t//TARGET_1D_ARRAY,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D,\t\t//TARGET_2D,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D,\t\t//TARGET_2D_ARRAY,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE3D,\t\t//TARGET_3D,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D,\t\t//TARGET_RECT,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D,\t\t//TARGET_RECT_ARRAY,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D,\t\t//TARGET_CUBE,\n\t\t\tD3D10_RESOURCE_DIMENSION_TEXTURE2D\t\t//TARGET_CUBE_ARRAY\n\t\t};\n\t\tstatic_assert(sizeof(Table) / sizeof(Table[0]) == TARGET_COUNT, \"Table needs to be updated\");\n\n\t\treturn Table[Target];\n\t}\n\t\n\tinline dx::d3dfmt get_fourcc(bool RequireDX10Header, gli::format Format, dx::format const& DXFormat)\n\t{\n\t\tif(RequireDX10Header)\n\t\t{\n\t\t\tdetail::formatInfo const & FormatInfo = detail::get_format_info(Format);\n\t\t\t\n\t\t\tif(FormatInfo.Flags & detail::CAP_DDS_GLI_EXT_BIT)\n\t\t\t\treturn dx::D3DFMT_GLI1;\n\t\t\telse\n\t\t\t\treturn dx::D3DFMT_DX10;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn (DXFormat.DDPixelFormat & dx::DDPF_FOURCC) ? DXFormat.D3DFormat : dx::D3DFMT_UNKNOWN;\n\t\t}\n\t}\n}//namespace detail\n\n\tinline bool save_dds(texture const& Texture, std::vector<char>& Memory)\n\t{\n\t\tif(Texture.empty())\n\t\t\treturn false;\n\n\t\tdx DX;\n\t\tdx::format const& DXFormat = DX.translate(Texture.format());\n\n\t\tbool const RequireDX10Header = DXFormat.D3DFormat == dx::D3DFMT_GLI1 || DXFormat.D3DFormat == dx::D3DFMT_DX10 || is_target_array(Texture.target()) || is_target_1d(Texture.target());\n\n\t\tMemory.resize(Texture.size() + sizeof(detail::FOURCC_DDS) + sizeof(detail::dds_header) + (RequireDX10Header ? sizeof(detail::dds_header10) : 0));\n\n\t\tmemcpy(&Memory[0], detail::FOURCC_DDS, sizeof(detail::FOURCC_DDS));\n\t\tstd::size_t Offset = sizeof(detail::FOURCC_DDS);\n\n\t\tdetail::dds_header& Header = *reinterpret_cast<detail::dds_header*>(&Memory[0] + Offset);\n\t\tOffset += sizeof(detail::dds_header);\n\n\t\tdetail::formatInfo const& Desc = detail::get_format_info(Texture.format());\n\n\t\tstd::uint32_t Caps = detail::DDSD_CAPS | detail::DDSD_WIDTH | detail::DDSD_PIXELFORMAT | detail::DDSD_MIPMAPCOUNT;\n\t\tCaps |= !is_target_1d(Texture.target()) ? detail::DDSD_HEIGHT : 0;\n\t\tCaps |= Texture.target() == TARGET_3D ? detail::DDSD_DEPTH : 0;\n\t\t//Caps |= Storage.levels() > 1 ? detail::DDSD_MIPMAPCOUNT : 0;\n\t\tCaps |= (Desc.Flags & detail::CAP_COMPRESSED_BIT) ? detail::DDSD_LINEARSIZE : detail::DDSD_PITCH;\n\n\t\tstd::uint32_t PitchInBytes = 0u;\n\t\tif( ( Desc.Flags & detail::CAP_COMPRESSED_BIT ) )\n\t\t{\n\t\t\tPitchInBytes = static_cast<std::uint32_t>(Texture.size() / Texture.faces());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tconst texture::extent_type& TextureExtent = Texture.extent();\n\t\t\tconst std::uint32_t BitsPerPixel = detail::bits_per_pixel( Texture.format() );\n\t\t\tPitchInBytes = ( TextureExtent.x * BitsPerPixel ) / 8u;\n\t\t}\n\n\t\tmemset(Header.Reserved1, 0, sizeof(Header.Reserved1));\n\t\tmemset(Header.Reserved2, 0, sizeof(Header.Reserved2));\n\t\tHeader.Size = sizeof(detail::dds_header);\n\t\tHeader.Flags = Caps;\n\t\tHeader.Width = static_cast<std::uint32_t>(Texture.extent().x);\n\t\tHeader.Height = static_cast<std::uint32_t>(Texture.extent().y);\n\t\tHeader.Pitch = PitchInBytes;\n\t\tHeader.Depth = static_cast<std::uint32_t>(Texture.extent().z > 1 ? Texture.extent().z : 0);\n\t\tHeader.MipMapLevels = static_cast<std::uint32_t>(Texture.levels());\n\t\tHeader.Format.size = sizeof(detail::dds_pixel_format);\n\t\tHeader.Format.flags = RequireDX10Header ? dx::DDPF_FOURCC : DXFormat.DDPixelFormat;\n\t\tHeader.Format.fourCC = detail::get_fourcc(RequireDX10Header, Texture.format(), DXFormat);\n\t\tHeader.Format.bpp = static_cast<std::uint32_t>(detail::bits_per_pixel(Texture.format()));\n\t\tHeader.Format.Mask = DXFormat.Mask;\n\t\t//Header.surfaceFlags = detail::DDSCAPS_TEXTURE | (Storage.levels() > 1 ? detail::DDSCAPS_MIPMAP : 0);\n\t\tHeader.SurfaceFlags = detail::DDSCAPS_TEXTURE | detail::DDSCAPS_MIPMAP;\n\t\tHeader.CubemapFlags = 0;\n\n\t\t// Cubemap\n\t\tif(Texture.faces() > 1)\n\t\t{\n\t\t\tGLI_ASSERT(Texture.faces() == 6);\n\t\t\tHeader.CubemapFlags |= detail::DDSCAPS2_CUBEMAP_ALLFACES | detail::DDSCAPS2_CUBEMAP;\n\t\t}\n\n\t\t// Texture3D\n\t\tif(Texture.extent().z > 1)\n\t\t\tHeader.CubemapFlags |= detail::DDSCAPS2_VOLUME;\n\n\t\tif(RequireDX10Header)\n\t\t{\n\t\t\tdetail::dds_header10& Header10 = *reinterpret_cast<detail::dds_header10*>(&Memory[0] + Offset);\n\t\t\tOffset += sizeof(detail::dds_header10);\n\n\t\t\tHeader10.ArraySize = static_cast<std::uint32_t>(Texture.layers());\n\t\t\tHeader10.ResourceDimension = detail::get_dimension(Texture.target());\n\t\t\tHeader10.MiscFlag = Texture.faces() > 1 ? detail::D3D10_RESOURCE_MISC_TEXTURECUBE : 0;//Storage.levels() > 0 ? detail::D3D10_RESOURCE_MISC_GENERATE_MIPS : 0;\n\t\t\tHeader10.Format = DXFormat.DXGIFormat;\n\t\t\tHeader10.AlphaFlags = detail::DDS_ALPHA_MODE_UNKNOWN;\n\t\t}\n\n\t\tstd::memcpy(&Memory[0] + Offset, Texture.data(), Texture.size());\n\n\t\treturn true;\n\t}\n\n\tinline bool save_dds(texture const& Texture, char const* Filename)\n\t{\n\t\tif(Texture.empty())\n\t\t\treturn false;\n\n\t\tFILE* File = detail::open_file(Filename, \"wb\");\n\t\tif(!File)\n\t\t\treturn false;\n\n\t\tstd::vector<char> Memory;\n\t\tbool const Result = save_dds(Texture, Memory);\n\n\t\tstd::fwrite(&Memory[0], 1, Memory.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn Result;\n\t}\n\n\tinline bool save_dds(texture const& Texture, std::string const& Filename)\n\t{\n\t\treturn save_dds(Texture, Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/save_kmg.inl",
    "content": "#include <cstdio>\n#include <glm/gtc/round.hpp>\n#include \"../load_kmg.hpp\"\n#include \"filter.hpp\"\n#include \"file.hpp\"\n\nnamespace gli\n{\n\tinline bool save_kmg(texture const & Texture, std::vector<char> & Memory)\n\t{\n\t\tif(Texture.empty())\n\t\t\treturn false;\n\n\t\tMemory.resize(sizeof(detail::FOURCC_KMG100) + sizeof(detail::kmgHeader10) + Texture.size());\n\n\t\tstd::memcpy(&Memory[0], detail::FOURCC_KMG100, sizeof(detail::FOURCC_KMG100));\n\n\t\tstd::size_t Offset = sizeof(detail::FOURCC_KMG100);\n\n\t\ttexture::swizzles_type Swizzle = Texture.swizzles();\n\n\t\tdetail::kmgHeader10 & Header = *reinterpret_cast<detail::kmgHeader10*>(&Memory[0] + Offset);\n\t\tHeader.Endianness = 0x04030201;\n\t\tHeader.Format = Texture.format();\n\t\tHeader.Target = Texture.target();\n\t\tHeader.SwizzleRed = Swizzle[0];\n\t\tHeader.SwizzleGreen = Swizzle[1];\n\t\tHeader.SwizzleBlue = Swizzle[2];\n\t\tHeader.SwizzleAlpha = Swizzle[3];\n\t\tHeader.PixelWidth = static_cast<std::uint32_t>(Texture.extent().x);\n\t\tHeader.PixelHeight = static_cast<std::uint32_t>(Texture.extent().y);\n\t\tHeader.PixelDepth = static_cast<std::uint32_t>(Texture.extent().z);\n\t\tHeader.Layers = static_cast<std::uint32_t>(Texture.layers());\n\t\tHeader.Levels = static_cast<std::uint32_t>(Texture.levels());\n\t\tHeader.Faces = static_cast<std::uint32_t>(Texture.faces());\n\t\tHeader.GenerateMipmaps = FILTER_NONE;\n\t\tHeader.BaseLevel = static_cast<std::uint32_t>(Texture.base_level());\n\t\tHeader.MaxLevel = static_cast<std::uint32_t>(Texture.max_level());\n\n\t\tOffset += sizeof(detail::kmgHeader10);\n\n\t\tfor(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer)\n\t\tfor(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level)\n\t\t{\n\t\t\ttexture::size_type const FaceSize = Texture.size(Level);\n\t\t\tfor(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face)\n\t\t\t{\n\t\t\t\tstd::memcpy(&Memory[0] + Offset, Texture.data(Layer, Face, Level), FaceSize);\n\n\t\t\t\tOffset += FaceSize;\n\t\t\t\tGLI_ASSERT(Offset <= Memory.size());\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tinline bool save_kmg(texture const & Texture, char const * Filename)\n\t{\n\t\tif(Texture.empty())\n\t\t\treturn false;\n\n\t\tFILE* File = detail::open_file(Filename, \"wb\");\n\t\tif(!File)\n\t\t\treturn false;\n\n\t\tstd::vector<char> Memory;\n\t\tbool const Result = save_kmg(Texture, Memory);\n\n\t\tstd::fwrite(&Memory[0], 1, Memory.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn Result;\n\t}\n\n\tinline bool save_kmg(texture const & Texture, std::string const & Filename)\n\t{\n\t\treturn save_kmg(Texture, Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/save_ktx.inl",
    "content": "#include <cstdio>\n#include <glm/gtc/round.hpp>\n#include \"../load_ktx.hpp\"\n#include \"file.hpp\"\n\nnamespace gli{\nnamespace detail\n{\n\tinline texture::size_type compute_ktx_storage_size(texture const & Texture)\n\t{\n\t\ttexture::size_type const BlockSize = block_size(Texture.format());\n\t\ttexture::size_type TotalSize = sizeof(detail::FOURCC_KTX10) + sizeof(detail::ktx_header10);\n\n\t\tfor(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level)\n\t\t{\n\t\t\tTotalSize += sizeof(std::uint32_t);\n\n\t\t\tfor(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer)\n\t\t\tfor(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face)\n\t\t\t{\n\t\t\t\ttexture::size_type const FaceSize = Texture.size(Level);\n\t\t\t\ttexture::size_type const PaddedSize = std::max(BlockSize, glm::ceilMultiple(FaceSize, static_cast<texture::size_type>(4)));\n\n\t\t\t\tTotalSize += PaddedSize;\n\t\t\t}\n\t\t}\n\n\t\treturn TotalSize;\n\t}\n}//namespace detail\n\n\tinline bool save_ktx(texture const& Texture, std::vector<char>& Memory)\n\t{\n\t\tif(Texture.empty())\n\t\t\treturn false;\n\n\t\tgl GL(gl::PROFILE_KTX);\n\t\tgl::format const& Format = GL.translate(Texture.format(), Texture.swizzles());\n\t\ttarget const Target = Texture.target();\n\n\t\tdetail::formatInfo const& Desc = detail::get_format_info(Texture.format());\n\n\t\tMemory.resize(detail::compute_ktx_storage_size(Texture));\n\n\t\tstd::memcpy(&Memory[0], detail::FOURCC_KTX10, sizeof(detail::FOURCC_KTX10));\n\n\t\tstd::size_t Offset = sizeof(detail::FOURCC_KTX10);\n\n\t\tdetail::ktx_header10& Header = *reinterpret_cast<detail::ktx_header10*>(&Memory[0] + Offset);\n\t\tHeader.Endianness = 0x04030201;\n\t\tHeader.GLType = Format.Type;\n\t\tHeader.GLTypeSize = Format.Type == gl::TYPE_NONE ? 1 : Desc.BlockSize;\n\t\tHeader.GLFormat = Format.External;\n\t\tHeader.GLInternalFormat = Format.Internal;\n\t\tHeader.GLBaseInternalFormat = Format.External;\n\t\tHeader.PixelWidth = static_cast<std::uint32_t>(Texture.extent().x);\n\t\tHeader.PixelHeight = !is_target_1d(Target) ? static_cast<std::uint32_t>(Texture.extent().y) : 0;\n\t\tHeader.PixelDepth = Target == TARGET_3D ? static_cast<std::uint32_t>(Texture.extent().z) : 0;\n\t\tHeader.NumberOfArrayElements = is_target_array(Target) ? static_cast<std::uint32_t>(Texture.layers()) : 0;\n\t\tHeader.NumberOfFaces = is_target_cube(Target) ? static_cast<std::uint32_t>(Texture.faces()) : 1;\n\t\tHeader.NumberOfMipmapLevels = static_cast<std::uint32_t>(Texture.levels());\n\t\tHeader.BytesOfKeyValueData = 0;\n\n\t\tOffset += sizeof(detail::ktx_header10);\n\n\t\tfor(texture::size_type Level = 0, Levels = Texture.levels(); Level < Levels; ++Level)\n\t\t{\n\t\t\tstd::uint32_t& ImageSize = *reinterpret_cast<std::uint32_t*>(&Memory[0] + Offset);\n\t\t\tOffset += sizeof(std::uint32_t);\n\n\t\t\tfor(texture::size_type Layer = 0, Layers = Texture.layers(); Layer < Layers; ++Layer)\n\t\t\tfor(texture::size_type Face = 0, Faces = Texture.faces(); Face < Faces; ++Face)\n\t\t\t{\n\t\t\t\ttexture::size_type const FaceSize = Texture.size(Level);\n\n\t\t\t\tstd::memcpy(&Memory[0] + Offset, Texture.data(Layer, Face, Level), FaceSize);\n\n\t\t\t\ttexture::size_type const PaddedSize = glm::ceilMultiple(FaceSize, static_cast<texture::size_type>(4));\n\n\t\t\t\tImageSize += static_cast<std::uint32_t>(PaddedSize);\n\t\t\t\tOffset += PaddedSize;\n\n\t\t\t\tGLI_ASSERT(Offset <= Memory.size());\n\t\t\t}\n\n\t\t\tImageSize = glm::ceilMultiple(ImageSize, static_cast<std::uint32_t>(4));\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tinline bool save_ktx(texture const& Texture, char const* Filename)\n\t{\n\t\tif(Texture.empty())\n\t\t\treturn false;\n\n\t\tFILE* File = detail::open_file(Filename, \"wb\");\n\t\tif(!File)\n\t\t\treturn false;\n\n\t\tstd::vector<char> Memory;\n\t\tbool const Result = save_ktx(Texture, Memory);\n\n\t\tstd::fwrite(&Memory[0], 1, Memory.size(), File);\n\t\tstd::fclose(File);\n\n\t\treturn Result;\n\t}\n\n\tinline bool save_ktx(texture const& Texture, std::string const& Filename)\n\t{\n\t\treturn save_ktx(Texture, Filename.c_str());\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/storage_linear.hpp",
    "content": "#pragma once\n\n// STD\n#include <vector>\n#include <queue>\n#include <string>\n#include <cassert>\n#include <cmath>\n#include <cstring>\n#include <memory>\n\n#include \"../type.hpp\"\n#include \"../format.hpp\"\n\n// GLM\n#include <glm/gtc/round.hpp>\n#include <glm/gtc/bitfield.hpp>\n#include <glm/gtx/component_wise.hpp>\n\nstatic_assert(GLM_VERSION >= 99, \"GLI requires at least GLM 0.9.9\");\n\nnamespace gli\n{\n\tclass storage_linear\n\t{\n\tpublic:\n\t\ttypedef extent3d extent_type;\n\t\ttypedef size_t size_type;\n\t\ttypedef gli::format format_type;\n\t\ttypedef gli::byte data_type;\n\n\tpublic:\n\t\tstorage_linear();\n\n\t\tstorage_linear(\n\t\t\tformat_type Format,\n\t\t\textent_type const & Extent,\n\t\t\tsize_type Layers,\n\t\t\tsize_type Faces,\n\t\t\tsize_type Levels);\n\n\t\tbool empty() const;\n\t\tsize_type size() const; // Express is bytes\n\t\tsize_type layers() const;\n\t\tsize_type levels() const;\n\t\tsize_type faces() const;\n\n\t\tsize_type block_size() const;\n\t\textent_type block_extent() const;\n\t\textent_type block_count(size_type Level) const;\n\t\textent_type extent(size_type Level) const;\n\n\t\tdata_type* data();\n\t\tdata_type const* const data() const;\n\n\t\t/// Compute the relative memory offset to access the data for a specific layer, face and level\n\t\tsize_type base_offset(\n\t\t\tsize_type Layer,\n\t\t\tsize_type Face,\n\t\t\tsize_type Level) const;\n\n\t\tsize_type image_offset(extent1d const& Coord, extent1d const& Extent) const;\n\n\t\tsize_type image_offset(extent2d const& Coord, extent2d const& Extent) const;\n\n\t\tsize_type image_offset(extent3d const& Coord, extent3d const& Extent) const;\n\n\t\t/// Copy a subset of a specific image of a texture \n\t\tvoid copy(\n\t\t\tstorage_linear const& StorageSrc,\n\t\t\tsize_t LayerSrc, size_t FaceSrc, size_t LevelSrc, extent_type const& BlockIndexSrc,\n\t\t\tsize_t LayerDst, size_t FaceDst, size_t LevelDst, extent_type const& BlockIndexDst,\n\t\t\textent_type const& BlockCount);\n\n\t\tsize_type level_size(\n\t\t\tsize_type Level) const;\n\t\tsize_type face_size(\n\t\t\tsize_type BaseLevel, size_type MaxLevel) const;\n\t\tsize_type layer_size(\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel) const;\n\n\tprivate:\n\t\tsize_type const Layers;\n\t\tsize_type const Faces;\n\t\tsize_type const Levels;\n\t\tsize_type const BlockSize;\n\t\textent_type const BlockCount;\n\t\textent_type const BlockExtent;\n\t\textent_type const Extent;\n\t\tstd::vector<data_type> Data;\n\t};\n}//namespace gli\n\n#include \"storage_linear.inl\"\n"
  },
  {
    "path": "lib/gli/core/storage_linear.inl",
    "content": "namespace gli\n{\n\tinline storage_linear::storage_linear()\n\t\t: Layers(0)\n\t\t, Faces(0)\n\t\t, Levels(0)\n\t\t, BlockSize(0)\n\t\t, BlockCount(0)\n\t\t, BlockExtent(0)\n\t\t, Extent(0)\n\t{}\n\n\tinline storage_linear::storage_linear(format_type Format, extent_type const& Extent, size_type Layers, size_type Faces, size_type Levels)\n\t\t: Layers(Layers)\n\t\t, Faces(Faces)\n\t\t, Levels(Levels)\n\t\t, BlockSize(gli::block_size(Format))\n\t\t, BlockCount(glm::ceilMultiple(Extent, gli::block_extent(Format)) / gli::block_extent(Format))\n\t\t, BlockExtent(gli::block_extent(Format))\n\t\t, Extent(Extent)\n\t{\n\t\tGLI_ASSERT(Layers > 0);\n\t\tGLI_ASSERT(Faces > 0);\n\t\tGLI_ASSERT(Levels > 0);\n\t\tGLI_ASSERT(glm::all(glm::greaterThan(Extent, extent_type(0))));\n\n\t\tthis->Data.resize(this->layer_size(0, Faces - 1, 0, Levels - 1) * Layers, 0);\n\t}\n\n\tinline bool storage_linear::empty() const\n\t{\n\t\treturn this->Data.empty();\n\t}\n\n\tinline storage_linear::size_type storage_linear::layers() const\n\t{\n\t\treturn this->Layers;\n\t}\n\n\tinline storage_linear::size_type storage_linear::faces() const\n\t{\n\t\treturn this->Faces;\n\t}\n\n\tinline storage_linear::size_type storage_linear::levels() const\n\t{\n\t\treturn this->Levels;\n\t}\n\n\tinline storage_linear::size_type storage_linear::block_size() const\n\t{\n\t\treturn this->BlockSize;\n\t}\n\n\tinline storage_linear::extent_type storage_linear::block_extent() const\n\t{\n\t\treturn this->BlockExtent;\n\t}\n\n\tinline storage_linear::extent_type storage_linear::block_count(size_type Level) const\n\t{\n\t\tGLI_ASSERT(Level >= 0 && Level < this->Levels);\n\n\t\treturn glm::ceilMultiple(this->extent(Level), BlockExtent) / BlockExtent;\n\t}\n\n\tinline storage_linear::extent_type storage_linear::extent(size_type Level) const\n\t{\n\t\tGLI_ASSERT(Level >= 0 && Level < this->Levels);\n\n\t\treturn glm::max(this->Extent >> storage_linear::extent_type(static_cast<storage_linear::extent_type::value_type>(Level)), storage_linear::extent_type(1));\n\t}\n\n\tinline storage_linear::size_type storage_linear::size() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn static_cast<size_type>(this->Data.size());\n\t}\n\n\tinline storage_linear::data_type* storage_linear::data()\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn &this->Data[0];\n\t}\n\n\tinline storage_linear::data_type const* const storage_linear::data() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn &this->Data[0];\n\t}\n\n\tinline storage_linear::size_type storage_linear::base_offset(size_type Layer, size_type Face, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(Layer >= 0 && Layer < this->layers() && Face >= 0 && Face < this->faces() && Level >= 0 && Level < this->levels());\n\n\t\tsize_type const LayerSize = this->layer_size(0, this->faces() - 1, 0, this->levels() - 1);\n\t\tsize_type const FaceSize = this->face_size(0, this->levels() - 1);\n\t\tsize_type BaseOffset = LayerSize * Layer + FaceSize * Face;\n\n\t\tfor(size_type LevelIndex = 0, LevelCount = Level; LevelIndex < LevelCount; ++LevelIndex)\n\t\t\tBaseOffset += this->level_size(LevelIndex);\n\n\t\treturn BaseOffset;\n\t}\n\n\tinline storage_linear::size_type storage_linear::image_offset(extent1d const& Coord, extent1d const& Extent) const\n\t{\n\t\tGLI_ASSERT(glm::all(glm::lessThan(Coord, Extent)));\n\t\treturn static_cast<size_t>(Coord.x);\n\t}\n\n\tinline storage_linear::size_type storage_linear::image_offset(extent2d const& Coord, extent2d const& Extent) const\n\t{\n\t\tGLI_ASSERT(glm::all(glm::lessThan(Coord, Extent)));\n\t\treturn static_cast<size_t>(Coord.x + Coord.y * Extent.x);\n\t}\n\n\tinline storage_linear::size_type storage_linear::image_offset(extent3d const& Coord, extent3d const& Extent) const\n\t{\n\t\tGLI_ASSERT(glm::all(glm::lessThan(Coord, Extent)));\n\t\treturn static_cast<storage_linear::size_type>(Coord.x + Coord.y * Extent.x + Coord.z * Extent.x * Extent.y);\n\t}\n\n\tinline void storage_linear::copy(\n\t\tstorage_linear const& StorageSrc,\n\t\tsize_t LayerSrc, size_t FaceSrc, size_t LevelSrc, extent_type const& BlockIndexSrc,\n\t\tsize_t LayerDst, size_t FaceDst, size_t LevelDst, extent_type const& BlockIndexDst,\n\t\textent_type const& BlockCount)\n\t{\n\t\tstorage_linear::size_type const BaseOffsetSrc = StorageSrc.base_offset(LayerSrc, FaceSrc, LevelSrc);\n\t\tstorage_linear::size_type const BaseOffsetDst = this->base_offset(LayerDst, FaceDst, LevelDst);\n\t\tstorage_linear::data_type const* const ImageSrc = StorageSrc.data() + BaseOffsetSrc;\n\t\tstorage_linear::data_type* const ImageDst = this->data() + BaseOffsetDst;\n\n\t\tfor(size_t BlockIndexZ = 0, BlockCountZ = BlockCount.z; BlockIndexZ < BlockCountZ; ++BlockIndexZ)\n\t\tfor(size_t BlockIndexY = 0, BlockCountY = BlockCount.y; BlockIndexY < BlockCountY; ++BlockIndexY)\n\t\t{\n\t\t\textent_type const BlockIndex(0, BlockIndexY, BlockIndexZ);\n\t\t\tgli::size_t const OffsetSrc = StorageSrc.image_offset(BlockIndexSrc + BlockIndex, StorageSrc.extent(LevelSrc)) * StorageSrc.block_size();\n\t\t\tgli::size_t const OffsetDst = this->image_offset(BlockIndexDst + BlockIndex, this->extent(LevelDst)) * this->block_size();\n\t\t\tstorage_linear::data_type const* const DataSrc = ImageSrc + OffsetSrc;\n\t\t\tstorage_linear::data_type* DataDst = ImageDst + OffsetDst;\n\t\t\tmemcpy(DataDst, DataSrc, this->block_size() * BlockCount.x);\n\t\t}\n\t}\n\n\tinline storage_linear::size_type storage_linear::level_size(size_type Level) const\n\t{\n\t\tGLI_ASSERT(Level >= 0 && Level < this->levels());\n\n\t\treturn this->BlockSize * glm::compMul(this->block_count(Level));\n\t}\n\n\tinline storage_linear::size_type storage_linear::face_size(size_type BaseLevel, size_type MaxLevel) const\n\t{\n\t\tGLI_ASSERT(MaxLevel >= 0 && MaxLevel < this->levels());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < this->levels());\n\t\tGLI_ASSERT(BaseLevel <= MaxLevel);\n\n\t\tsize_type FaceSize(0);\n\n\t\t// The size of a face is the sum of the size of each level.\n\t\tfor(storage_linear::size_type Level(BaseLevel); Level <= MaxLevel; ++Level)\n\t\t\tFaceSize += this->level_size(Level);\n\n\t\treturn FaceSize;\n\t}\n\n\tinline storage_linear::size_type storage_linear::layer_size(\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel) const\n\t{\n\t\tGLI_ASSERT(MaxFace >= 0 && MaxFace < this->faces());\n\t\tGLI_ASSERT(BaseFace >= 0 && BaseFace < this->faces());\n\t\tGLI_ASSERT(MaxLevel >= 0 && MaxLevel < this->levels());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < this->levels());\n\n\t\t// The size of a layer is the sum of the size of each face.\n\t\t// All the faces have the same size.\n\t\treturn this->face_size(BaseLevel, MaxLevel) * (MaxFace - BaseFace + 1);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/texture.inl",
    "content": "#include <cstring>\n\nnamespace gli\n{\n\tinline texture::texture()\n\t\t: Storage(nullptr)\n\t\t, Target(static_cast<gli::target>(TARGET_INVALID))\n\t\t, Format(gli::FORMAT_UNDEFINED)\n\t\t, BaseLayer(0), MaxLayer(0)\n\t\t, BaseFace(0), MaxFace(0)\n\t\t, BaseLevel(0), MaxLevel(0)\n\t\t, Swizzles(SWIZZLE_ZERO)\n\t\t, Cache(cache::DEFAULT)\n\t{}\n\n\tinline texture::texture\n\t(\n\t\ttarget_type Target,\n\t\tformat_type Format,\n\t\textent_type const& Extent,\n\t\tsize_type Layers,\n\t\tsize_type Faces,\n\t\tsize_type Levels,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: Storage(std::make_shared<storage_type>(Format, Extent, Layers, Faces, Levels))\n\t\t, Target(Target)\n\t\t, Format(Format)\n\t\t, BaseLayer(0), MaxLayer(Layers - 1)\n\t\t, BaseFace(0), MaxFace(Faces - 1)\n\t\t, BaseLevel(0), MaxLevel(Levels - 1)\n\t\t, Swizzles(Swizzles)\n\t\t, Cache(*Storage, Format, this->base_layer(), this->layers(), this->base_face(), this->max_face(), this->base_level(), this->max_level())\n\t{\n\t\tGLI_ASSERT(Target != TARGET_CUBE || (Target == TARGET_CUBE && Extent.x == Extent.y));\n\t\tGLI_ASSERT(Target != TARGET_CUBE_ARRAY || (Target == TARGET_CUBE_ARRAY && Extent.x == Extent.y));\n\t}\n\n\tinline texture::texture\n\t(\n\t\ttexture const& Texture,\n\t\ttarget_type Target,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: Storage(Texture.Storage)\n\t\t, Target(Target)\n\t\t, Format(Format)\n\t\t, BaseLayer(BaseLayer), MaxLayer(MaxLayer)\n\t\t, BaseFace(BaseFace), MaxFace(MaxFace)\n\t\t, BaseLevel(BaseLevel), MaxLevel(MaxLevel)\n\t\t, Swizzles(Swizzles)\n\t\t, Cache(*Storage, Format, this->base_layer(), this->layers(), this->base_face(), this->max_face(), this->base_level(), this->max_level())\n\t{\n\t\tGLI_ASSERT(block_size(Format) == block_size(Texture.format()));\n\t\tGLI_ASSERT(Target != TARGET_1D || (Target == TARGET_1D && this->layers() == 1 && this->faces() == 1 && this->extent().y == 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_1D_ARRAY || (Target == TARGET_1D_ARRAY && this->layers() >= 1 && this->faces() == 1 && this->extent().y == 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_2D || (Target == TARGET_2D && this->layers() == 1 && this->faces() == 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_2D_ARRAY || (Target == TARGET_2D_ARRAY && this->layers() >= 1 && this->faces() == 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_3D || (Target == TARGET_3D && this->layers() == 1 && this->faces() == 1 && this->extent().y >= 1 && this->extent().z >= 1));\n\t\tGLI_ASSERT(Target != TARGET_CUBE || (Target == TARGET_CUBE && this->layers() == 1 && this->faces() >= 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_CUBE_ARRAY || (Target == TARGET_CUBE_ARRAY && this->layers() >= 1 && this->faces() >= 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t}\n\n\tinline texture::texture\n\t(\n\t\ttexture const& Texture,\n\t\ttarget_type Target,\n\t\tformat_type Format,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: Storage(Texture.Storage)\n\t\t, Target(Target)\n\t\t, Format(Format)\n\t\t, BaseLayer(Texture.base_layer()), MaxLayer(Texture.max_layer())\n\t\t, BaseFace(Texture.base_face()), MaxFace(Texture.max_face())\n\t\t, BaseLevel(Texture.base_level()), MaxLevel(Texture.max_level())\n\t\t, Swizzles(Swizzles)\n\t\t, Cache(*Storage, Format, this->base_layer(), this->layers(), this->base_face(), this->max_face(), this->base_level(), this->max_level())\n\t{\n\t\tif(this->empty())\n\t\t\treturn;\n\n\t\tGLI_ASSERT(Target != TARGET_1D || (Target == TARGET_1D && this->layers() == 1 && this->faces() == 1 && this->extent().y == 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_1D_ARRAY || (Target == TARGET_1D_ARRAY && this->layers() >= 1 && this->faces() == 1 && this->extent().y == 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_2D || (Target == TARGET_2D && this->layers() == 1 && this->faces() == 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_2D_ARRAY || (Target == TARGET_2D_ARRAY && this->layers() >= 1 && this->faces() == 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_3D || (Target == TARGET_3D && this->layers() == 1 && this->faces() == 1 && this->extent().y >= 1 && this->extent().z >= 1));\n\t\tGLI_ASSERT(Target != TARGET_CUBE || (Target == TARGET_CUBE && this->layers() == 1 && this->faces() >= 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t\tGLI_ASSERT(Target != TARGET_CUBE_ARRAY || (Target == TARGET_CUBE_ARRAY && this->layers() >= 1 && this->faces() >= 1 && this->extent().y >= 1 && this->extent().z == 1));\n\t}\n\n\tinline bool texture::empty() const\n\t{\n\t\tif(this->Storage.get() == nullptr)\n\t\t\treturn true;\n\n\t\treturn this->Storage->empty();\n\t}\n\n\tinline texture::format_type texture::format() const\n\t{\n\t\treturn this->Format;\n\t}\n\n\tinline texture::swizzles_type texture::swizzles() const\n\t{\n\t\tswizzles_type const FormatSwizzle = detail::get_format_info(this->format()).Swizzles;\n\t\tswizzles_type const CustomSwizzle = this->Swizzles;\n\n\t\tswizzles_type ResultSwizzle(SWIZZLE_ZERO);\n\t\tResultSwizzle.r = is_channel(CustomSwizzle.r) ? FormatSwizzle[CustomSwizzle.r] : CustomSwizzle.r;\n\t\tResultSwizzle.g = is_channel(CustomSwizzle.g) ? FormatSwizzle[CustomSwizzle.g] : CustomSwizzle.g;\n\t\tResultSwizzle.b = is_channel(CustomSwizzle.b) ? FormatSwizzle[CustomSwizzle.b] : CustomSwizzle.b;\n\t\tResultSwizzle.a = is_channel(CustomSwizzle.a) ? FormatSwizzle[CustomSwizzle.a] : CustomSwizzle.a;\n\t\treturn ResultSwizzle;\n\t}\n\n\tinline texture::size_type texture::base_layer() const\n\t{\n\t\treturn this->BaseLayer;\n\t}\n\n\tinline texture::size_type texture::max_layer() const\n\t{\n\t\treturn this->MaxLayer;\n\t}\n\n\tinline texture::size_type texture::layers() const\n\t{\n\t\tif(this->empty())\n\t\t\treturn 0;\n\t\treturn this->max_layer() - this->base_layer() + 1;\n\t}\n\n\tinline texture::size_type texture::base_face() const\n\t{\n\t\treturn this->BaseFace;\n\t}\n\n\tinline texture::size_type texture::max_face() const\n\t{\n\t\treturn this->MaxFace;\n\t}\n\n\tinline texture::size_type texture::faces() const\n\t{\n\t\tif(this->empty())\n\t\t\treturn 0;\n\t\treturn this->max_face() - this->base_face() + 1;\n\t}\n\n\tinline texture::size_type texture::base_level() const\n\t{\n\t\treturn this->BaseLevel;\n\t}\n\n\tinline texture::size_type texture::max_level() const\n\t{\n\t\treturn this->MaxLevel;\n\t}\n\n\tinline texture::size_type texture::levels() const\n\t{\n\t\tif(this->empty())\n\t\t\treturn 0;\n\t\treturn this->max_level() - this->base_level() + 1;\n\t}\n\n\tinline texture::size_type texture::size() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Cache.get_memory_size();\n\t}\n\n\ttemplate <typename gen_type>\n\tinline texture::size_type texture::size() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(block_size(this->format()) == sizeof(gen_type));\n\n\t\treturn this->size() / sizeof(gen_type);\n\t}\n\n\tinline texture::size_type texture::size(size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(Level >= 0 && Level < this->levels());\n\n\t\treturn this->Cache.get_memory_size(Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline texture::size_type texture::size(size_type Level) const\n\t{\n\t\tGLI_ASSERT(block_size(this->format()) == sizeof(gen_type));\n\n\t\treturn this->size(Level) / sizeof(gen_type);\n\t}\n\n\tinline void* texture::data()\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Cache.get_base_address(0, 0, 0);\n\t}\n\n\tinline void const* texture::data() const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\treturn this->Cache.get_base_address(0, 0, 0);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type* texture::data()\n\t{\n\t\tGLI_ASSERT(block_size(this->format()) >= sizeof(gen_type));\n\n\t\treturn reinterpret_cast<gen_type*>(this->data());\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type const* texture::data() const\n\t{\n\t\tGLI_ASSERT(block_size(this->format()) >= sizeof(gen_type));\n\n\t\treturn reinterpret_cast<gen_type const*>(this->data());\n\t}\n\n\tinline void* texture::data(size_type Layer, size_type Face, size_type Level)\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(Layer >= 0 && Layer < this->layers() && Face >= 0 && Face < this->faces() && Level >= 0 && Level < this->levels());\n\n\t\treturn this->Cache.get_base_address(Layer, Face, Level);\n\t}\n\n\tinline void const* const texture::data(size_type Layer, size_type Face, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(Layer >= 0 && Layer < this->layers() && Face >= 0 && Face < this->faces() && Level >= 0 && Level < this->levels());\n\n\t\treturn this->Cache.get_base_address(Layer, Face, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type* texture::data(size_type Layer, size_type Face, size_type Level)\n\t{\n\t\tGLI_ASSERT(block_size(this->format()) >= sizeof(gen_type));\n\n\t\treturn reinterpret_cast<gen_type*>(this->data(Layer, Face, Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type const* const texture::data(size_type Layer, size_type Face, size_type Level) const\n\t{\n\t\tGLI_ASSERT(block_size(this->format()) >= sizeof(gen_type));\n\n\t\treturn reinterpret_cast<gen_type const* const>(this->data(Layer, Face, Level));\n\t}\n\n\tinline texture::extent_type texture::extent(size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(Level >= 0 && Level < this->levels());\n\n\t\treturn this->Cache.get_extent(Level);\n\t}\n\n\tinline void texture::clear()\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\n\t\tmemset(this->data(), 0, this->size());\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture::clear(gen_type const& Texel)\n\t{\n\t\tGLI_ASSERT(!gli::is_compressed(this->format()));\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(block_size(this->format()) == sizeof(gen_type));\n\n\t\tgen_type* Data = this->data<gen_type>();\n\t\tsize_type const BlockCount = this->size<gen_type>();\n\n\t\tfor(size_type BlockIndex = 0; BlockIndex < BlockCount; ++BlockIndex)\n\t\t\t*(Data + BlockIndex) = Texel;\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture::clear(size_type Layer, size_type Face, size_type Level, gen_type const& BlockData)\n\t{\n\t\tGLI_ASSERT(!gli::is_compressed(this->format()));\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(block_size(this->format()) == sizeof(gen_type));\n\t\tGLI_ASSERT(Layer >= 0 && Layer < this->layers() && Face >= 0 && Face < this->faces() && Level >= 0 && Level < this->levels());\n\n\t\tsize_type const BlockCount = this->Storage->level_size(Level) / sizeof(gen_type);\n\t\tgen_type* Data = this->data<gen_type>(Layer, Face, Level);\n\t\tfor(size_type BlockIndex = 0; BlockIndex < BlockCount; ++BlockIndex)\n\t\t\t*(Data + BlockIndex) = BlockData;\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture::clear\n\t(\n\t\tsize_type Layer, size_type Face, size_type Level,\n\t\textent_type const& TexelOffset, extent_type const& TexelExtent,\n\t\tgen_type const& BlockData\n\t)\n\t{\n\t\tstorage_type::size_type const BaseOffset = this->Storage->base_offset(Layer, Face, Level);\n\t\tstorage_type::data_type* const BaseAddress = this->Storage->data() + BaseOffset;\n\n\t\textent_type BlockOffset(TexelOffset / this->Storage->block_extent());\n\t\textent_type const BlockExtent(TexelExtent / this->Storage->block_extent() + BlockOffset);\n\t\tfor(; BlockOffset.z < BlockExtent.z; ++BlockOffset.z)\n\t\tfor(; BlockOffset.y < BlockExtent.y; ++BlockOffset.y)\n\t\tfor(; BlockOffset.x < BlockExtent.x; ++BlockOffset.x)\n\t\t{\n\t\t\tgli::size_t const Offset = this->Storage->image_offset(BlockOffset, this->extent(Level)) * this->Storage->block_size();\n\t\t\tgen_type* const BlockAddress = reinterpret_cast<gen_type* const>(BaseAddress + Offset);\n\t\t\t*BlockAddress = BlockData;\n\t\t}\n\t}\n\n\tinline void texture::copy\n\t(\n\t\ttexture const& TextureSrc,\n\t\tsize_t LayerSrc, size_t FaceSrc, size_t LevelSrc,\n\t\tsize_t LayerDst, size_t FaceDst, size_t LevelDst\n\t)\n\t{\n\t\tGLI_ASSERT(this->size(LevelDst) == TextureSrc.size(LevelSrc));\n\t\tGLI_ASSERT(LayerSrc < TextureSrc.layers());\n\t\tGLI_ASSERT(LayerDst < this->layers());\n\t\tGLI_ASSERT(FaceSrc < TextureSrc.faces());\n\t\tGLI_ASSERT(FaceDst < this->faces());\n\t\tGLI_ASSERT(LevelSrc < TextureSrc.levels());\n\t\tGLI_ASSERT(LevelDst < this->levels());\n\n\t\tmemcpy(\n\t\t\tthis->data(LayerDst, FaceDst, LevelDst),\n\t\t\tTextureSrc.data(LayerSrc, FaceSrc, LevelSrc),\n\t\t\tthis->size(LevelDst));\n\t}\n\n\tinline void texture::copy\n\t(\n\t\ttexture const& TextureSrc,\n\t\tsize_t LayerSrc, size_t FaceSrc, size_t LevelSrc, texture::extent_type const& OffsetSrc,\n\t\tsize_t LayerDst, size_t FaceDst, size_t LevelDst, texture::extent_type const& OffsetDst,\n\t\ttexture::extent_type const& Extent\n\t)\n\t{\n\t\tstorage_type::extent_type const BlockExtent = this->Storage->block_extent();\n\t\tthis->Storage->copy(\n\t\t\t*TextureSrc.Storage,\n\t\t\tLayerSrc, FaceSrc, LevelSrc, OffsetSrc / BlockExtent,\n\t\t\tLayerDst, FaceDst, LevelDst, OffsetDst / BlockExtent,\n\t\t\tExtent / BlockExtent);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture::swizzle(gli::swizzles const& Swizzles)\n\t{\n\t\tfor(size_type TexelIndex = 0, TexelCount = this->size<gen_type>(); TexelIndex < TexelCount; ++TexelIndex)\n\t\t{\n\t\t\tgen_type& TexelDst = *(this->data<gen_type>() + TexelIndex);\n\t\t\tgen_type const TexelSrc = TexelDst;\n\t\t\tfor(typename gen_type::length_type Component = 0; Component < TexelDst.length(); ++Component)\n\t\t\t{\n\t\t\t\tGLI_ASSERT(static_cast<typename gen_type::length_type>(Swizzles[Component]) < TexelDst.length());\n\t\t\t\tTexelDst[Component] = TexelSrc[Swizzles[Component]];\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture::load(extent_type const& TexelCoord, size_type Layer,  size_type Face, size_type Level) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(!is_compressed(this->format()));\n\t\tGLI_ASSERT(block_size(this->format()) == sizeof(gen_type));\n\n\t\tsize_type const ImageOffset = this->Storage->image_offset(TexelCoord, this->extent(Level));\n\t\tGLI_ASSERT(ImageOffset < this->size<gen_type>(Level));\n\n\t\treturn *(this->data<gen_type>(Layer, Face, Level) + ImageOffset);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture::store(extent_type const& TexelCoord, size_type Layer,  size_type Face, size_type Level, gen_type const& Texel)\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(!is_compressed(this->format()));\n\t\tGLI_ASSERT(block_size(this->format()) == sizeof(gen_type));\n\t\tGLI_ASSERT(glm::all(glm::lessThan(TexelCoord, this->extent(Level))));\n\n\t\tsize_type const ImageOffset = this->Storage->image_offset(TexelCoord, this->extent(Level));\n\t\tGLI_ASSERT(ImageOffset < this->size<gen_type>(Level));\n\n\t\t*(this->data<gen_type>(Layer, Face, Level) + ImageOffset) = Texel;\n\t}\n}//namespace gli\n\n"
  },
  {
    "path": "lib/gli/core/texture1d.inl",
    "content": "#include \"../levels.hpp\"\n\nnamespace gli\n{\n\tinline texture1d::texture1d()\n\t{}\n\n\tinline texture1d::texture1d(format_type Format, extent_type const& Extent, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_1D, Format, texture::extent_type(Extent.x, 1, 1), 1, 1, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture1d::texture1d(format_type Format, extent_type const& Extent, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_1D, Format, texture::extent_type(Extent.x, 1, 1), 1, 1, Levels, Swizzles)\n\t{}\n\n\tinline texture1d::texture1d(texture const& Texture)\n\t\t: texture(Texture, TARGET_1D, Texture.format())\n\t{}\n\n\tinline texture1d::texture1d\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_1D,\n\t\t\tFormat,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\tSwizzles)\n\t{}\n \n\tinline texture1d::texture1d\n\t(\n\t\ttexture1d const& Texture,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_1D,\n\t\t\tTexture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline image texture1d::operator[](texture1d::size_type Level) const\n\t{\n\t\tGLI_ASSERT(Level < this->levels());\n\n\t\treturn image(\n\t\t\tthis->Storage,\n\t\t\tthis->format(),\n\t\t\tthis->base_layer(),\n\t\t\tthis->base_face(),\n\t\t\tthis->base_level() + Level);\n\t}\n\n\tinline texture1d::extent_type texture1d::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture1d::load(extent_type const& TexelCoord, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord.x, 0, 0), 0, 0, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture1d::store(extent_type const& TexelCoord, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord.x, 0, 0), 0, 0, Level, Texel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/texture1d_array.inl",
    "content": "#include \"../levels.hpp\"\n\nnamespace gli\n{\n\tinline texture1d_array::texture1d_array()\n\t{}\n\n\tinline texture1d_array::texture1d_array(format_type Format, extent_type const& Extent, size_type Layers, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_1D_ARRAY, Format, texture::extent_type(Extent.x, 1, 1), Layers, 1, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture1d_array::texture1d_array(format_type Format, extent_type const& Extent, size_type Layers, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_1D_ARRAY, Format, texture::extent_type(Extent.x, 1, 1), Layers, 1, Levels, Swizzles)\n\t{}\n\n\tinline texture1d_array::texture1d_array(texture const& Texture)\n\t\t: texture(Texture, TARGET_1D_ARRAY, Texture.format())\n\t{}\n\n\tinline texture1d_array::texture1d_array\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_1D_ARRAY, Format,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\t\tSwizzles)\n\t{}\n\n\tinline texture1d_array::texture1d_array\n\t(\n\t\ttexture1d_array const& Texture,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_1D_ARRAY,\n\t\t\tTexture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline texture1d texture1d_array::operator[](size_type Layer) const\n\t{\n\t\tGLI_ASSERT(!this->empty());\n\t\tGLI_ASSERT(Layer < this->layers());\n\n\t\treturn texture1d(\n\t\t\t*this, this->format(),\n\t\t\tthis->base_layer() + Layer, this->base_layer() + Layer,\n\t\t\tthis->base_face(), this->max_face(),\n\t\t\tthis->base_level(), this->max_level());\n\t}\n\n\tinline texture1d_array::extent_type texture1d_array::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture1d_array::load(extent_type const& TexelCoord, size_type Layer, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord.x, 0, 0), Layer, 0, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture1d_array::store(extent_type const& TexelCoord, size_type Layer, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord.x, 0, 0), Layer, 0, Level, Texel);\n\t}\n}//namespace gli\n\n\n"
  },
  {
    "path": "lib/gli/core/texture2d.inl",
    "content": "#include \"../levels.hpp\"\n\nnamespace gli\n{\n\tinline texture2d::texture2d()\n\t{}\n\n\tinline texture2d::texture2d(format_type Format, extent_type const& Extent, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_2D, Format, texture::extent_type(Extent, 1), 1, 1, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture2d::texture2d(format_type Format, extent_type const& Extent, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_2D, Format, texture::extent_type(Extent, 1), 1, 1, Levels, Swizzles)\n\t{}\n\n\tinline texture2d::texture2d(texture const& Texture)\n\t\t: texture(Texture, TARGET_2D, Texture.format())\n\t{}\n\n\tinline texture2d::texture2d\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_2D, Format,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\t\tSwizzles)\n\t{}\n\n\tinline texture2d::texture2d\n\t(\n\t\ttexture2d const& Texture,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_2D, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline image texture2d::operator[](size_type Level) const\n\t{\n\t\tGLI_ASSERT(Level < this->levels());\n\n\t\treturn image(\n\t\t\tthis->Storage,\n\t\t\tthis->format(),\n\t\t\tthis->base_layer(),\n\t\t\tthis->base_face(),\n\t\t\tthis->base_level() + Level);\n\t}\n\n\tinline texture2d::extent_type texture2d::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture2d::load(extent_type const& TexelCoord, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord, 0), 0, 0, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture2d::store(extent_type const& TexelCoord, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord, 0), 0, 0, Level, Texel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/texture2d_array.inl",
    "content": "#include \"../levels.hpp\"\n\nnamespace gli\n{\n\tinline texture2d_array::texture2d_array()\n\t{}\n\n\tinline texture2d_array::texture2d_array(format_type Format, extent_type const& Extent, size_type Layers, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_2D_ARRAY, Format, texture::extent_type(Extent, 1), Layers, 1, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture2d_array::texture2d_array(format_type Format, extent_type const& Extent, size_type Layers, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_2D_ARRAY, Format, texture::extent_type(Extent, 1), Layers, 1, Levels, Swizzles)\n\t{}\n\n\tinline texture2d_array::texture2d_array(texture const& Texture)\n\t\t: texture(Texture, TARGET_2D_ARRAY, Texture.format())\n\t{}\n\n\tinline texture2d_array::texture2d_array\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_2D_ARRAY,\n\t\t\tFormat,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\t\tSwizzles)\n\t{}\n\n\tinline texture2d_array::texture2d_array\n\t(\n\t\ttexture2d_array const& Texture,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_2D_ARRAY,\n\t\t\tTexture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline texture2d texture2d_array::operator[](size_type Layer) const\n\t{\n\t\tGLI_ASSERT(Layer < this->layers());\n\n\t\treturn texture2d(\n\t\t\t*this, this->format(),\n\t\t\tthis->base_layer() + Layer, this->base_layer() + Layer,\n\t\t\tthis->base_face(), this->max_face(),\n\t\t\tthis->base_level(), this->max_level());\n\t}\n\n\tinline texture2d_array::extent_type texture2d_array::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture2d_array::load(extent_type const& TexelCoord, size_type Layer, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord, 0), Layer, 0, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture2d_array::store(extent_type const& TexelCoord, size_type Layer, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord, 0), Layer, 0, Level, Texel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/texture3d.inl",
    "content": "#include \"../levels.hpp\"\n\nnamespace gli\n{\n\tinline texture3d::texture3d()\n\t{}\n\n\tinline texture3d::texture3d(format_type Format, extent_type const& Extent, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_3D, Format, Extent, 1, 1, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture3d::texture3d(format_type Format, extent_type const& Extent, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_3D, Format, Extent, 1, 1, Levels, Swizzles)\n\t{}\n\n\tinline texture3d::texture3d(texture const& Texture)\n\t\t: texture(Texture, TARGET_3D, Texture.format())\n\t{}\n\n\tinline texture3d::texture3d\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_3D, Format,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\t\tSwizzles)\n\t{}\n \n\tinline texture3d::texture3d\n\t(\n\t\ttexture3d const& Texture,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_3D, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline image texture3d::operator[](size_type Level) const\n\t{\n\t\tGLI_ASSERT(Level < this->levels());\n\n\t\treturn image(\n\t\t\tthis->Storage,\n\t\t\tthis->format(),\n\t\t\tthis->base_layer(),\n\t\t\tthis->base_face(),\n\t\t\tthis->base_level() + Level);\n\t}\n\n\tinline texture3d::extent_type texture3d::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture3d::load(extent_type const& TexelCoord, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord), 0, 0, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture3d::store(extent_type const& TexelCoord, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord), 0, 0, Level, Texel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/texture_cube.inl",
    "content": "namespace gli\n{\n\tinline texture_cube::texture_cube()\n\t{}\n\n\tinline texture_cube::texture_cube(format_type Format, extent_type const& Extent, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_CUBE, Format, texture::extent_type(Extent, 1), 1, 6, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture_cube::texture_cube(format_type Format, extent_type const& Extent, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_CUBE, Format, texture::extent_type(Extent, 1), 1, 6, Levels, Swizzles)\n\t{}\n\n\tinline texture_cube::texture_cube(texture const& Texture)\n\t\t: texture(Texture, TARGET_CUBE, Texture.format())\n\t{}\n\n\tinline texture_cube::texture_cube\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_CUBE, Format,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\t\tSwizzles)\n\t{}\n\n\tinline texture_cube::texture_cube\n\t(\n\t\ttexture_cube const& Texture,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_CUBE, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face() + BaseFace, Texture.base_face() + MaxFace,\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline texture2d texture_cube::operator[](size_type Face) const\n\t{\n\t\tGLI_ASSERT(Face < this->faces());\n\n\t\treturn texture2d(\n\t\t\t*this, this->format(),\n\t\t\tthis->base_layer(), this->max_layer(),\n\t\t\tthis->base_face() + Face, this->base_face() + Face,\n\t\t\tthis->base_level(), this->max_level());\n\t}\n\n\tinline texture_cube::extent_type texture_cube::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture_cube::load(extent_type const& TexelCoord, size_type Face, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord, 0), 0, Face, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture_cube::store(extent_type const& TexelCoord, size_type Face, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord, 0), 0, Face, Level, Texel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/texture_cube_array.inl",
    "content": "namespace gli\n{\n\tinline texture_cube_array::texture_cube_array()\n\t{}\n\n\tinline texture_cube_array::texture_cube_array(format_type Format, extent_type const& Extent, size_type Layers, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_CUBE_ARRAY, Format, texture::extent_type(Extent, 1), Layers, 6, gli::levels(Extent), Swizzles)\n\t{}\n\n\tinline texture_cube_array::texture_cube_array(format_type Format, extent_type const& Extent, size_type Layers, size_type Levels, swizzles_type const& Swizzles)\n\t\t: texture(TARGET_CUBE_ARRAY, Format, texture::extent_type(Extent, 1), Layers, 6, Levels, Swizzles)\n\t{}\n\n\tinline texture_cube_array::texture_cube_array(texture const& Texture)\n\t\t: texture(Texture, gli::TARGET_CUBE_ARRAY, Texture.format())\n\t{}\n\n\tinline texture_cube_array::texture_cube_array\n\t(\n\t\ttexture const& Texture,\n\t\tformat_type Format,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\tswizzles_type const& Swizzles\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_CUBE_ARRAY,\n\t\t\tFormat,\n\t\t\tBaseLayer, MaxLayer,\n\t\t\tBaseFace, MaxFace,\n\t\t\tBaseLevel, MaxLevel,\n\t\t\tSwizzles)\n\t{}\n\n\tinline texture_cube_array::texture_cube_array\n\t(\n\t\ttexture_cube_array const& Texture,\n\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\tsize_type BaseFace, size_type MaxFace,\n\t\tsize_type BaseLevel, size_type MaxLevel\n\t)\n\t\t: texture(\n\t\t\tTexture, TARGET_CUBE_ARRAY, Texture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face() + BaseFace, Texture.base_face() + MaxFace,\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel)\n\t{}\n\n\tinline texture_cube texture_cube_array::operator[](size_type Layer) const\n\t{\n\t\tGLI_ASSERT(Layer < this->layers());\n\n\t\treturn texture_cube(\n\t\t\t*this, this->format(),\n\t\t\tthis->base_layer() + Layer, this->base_layer() + Layer,\n\t\t\tthis->base_face(), this->max_face(),\n\t\t\tthis->base_level(), this->max_level());\n\t}\n\n\tinline texture_cube_array::extent_type texture_cube_array::extent(size_type Level) const\n\t{\n\t\treturn extent_type(this->texture::extent(Level));\n\t}\n\n\ttemplate <typename gen_type>\n\tinline gen_type texture_cube_array::load(extent_type const& TexelCoord, size_type Layer, size_type Face, size_type Level) const\n\t{\n\t\treturn this->texture::load<gen_type>(texture::extent_type(TexelCoord, 0), Layer, Face, Level);\n\t}\n\n\ttemplate <typename gen_type>\n\tinline void texture_cube_array::store(extent_type const& TexelCoord, size_type Layer, size_type Face, size_type Level, gen_type const& Texel)\n\t{\n\t\tthis->texture::store<gen_type>(texture::extent_type(TexelCoord, 0), Layer, Face, Level, Texel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/transform.inl",
    "content": "namespace gli{\nnamespace detail\n{\n\ttemplate <typename vec_type>\n\tstruct compute_transform_1d\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture1d::size_type size_type;\n\t\ttypedef texture1d::extent_type extent_type;\n\t\t\n\t\tstatic void call(texture1d& Output, texture1d const& A, texture1d const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_transform_1d_array\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture1d_array::size_type size_type;\n\t\ttypedef texture1d_array::extent_type extent_type;\n\t\t\n\t\tstatic void call(texture1d_array& Output, texture1d_array const& A, texture1d_array const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.layers() == B.layers());\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, LayerIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, LayerIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, LayerIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t\n\ttemplate <typename vec_type>\n\tstruct compute_transform_2d\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture2d::size_type size_type;\n\t\ttypedef texture2d::extent_type extent_type;\n\t\t\t\n\t\tstatic void call(texture2d& Output, texture2d const& A, texture2d const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\t\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t\t\n\ttemplate <typename vec_type>\n\tstruct compute_transform_2d_array\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture2d_array::size_type size_type;\n\t\ttypedef texture2d_array::extent_type extent_type;\n\t\t\n\t\tstatic void call(texture2d_array& Output, texture2d_array const& A, texture2d_array const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.layers() == B.layers());\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\t\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, LayerIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, LayerIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, LayerIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename vec_type>\n\tstruct compute_transform_3d\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture3d::size_type size_type;\n\t\ttypedef texture3d::extent_type extent_type;\n\t\n\t\tstatic void call(texture3d& Output, texture3d const& A, texture3d const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.z = 0; TexelIndex.z < TexelCount.z; ++TexelIndex.z)\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate <typename vec_type>\n\tstruct compute_transform_cube\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture_cube::size_type size_type;\n\t\ttypedef texture_cube::extent_type extent_type;\n\t\t\t\n\t\tstatic void call(texture_cube& Output, texture_cube const& A, texture_cube const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.faces() == B.faces());\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\t\n\t\t\tfor(size_type FaceIndex = 0, FaceCount = A.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, FaceIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, FaceIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, FaceIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t\t\n\ttemplate <typename vec_type>\n\tstruct compute_transform_cube_array\n\t{\n\t\ttypedef typename transform_func<vec_type>::type func_type;\n\t\ttypedef texture_cube_array::size_type size_type;\n\t\ttypedef texture_cube_array::extent_type extent_type;\n\t\t\t\n\t\tstatic void call(texture_cube_array& Output, texture_cube_array const& A, texture_cube_array const& B, func_type Func)\n\t\t{\n\t\t\tGLI_ASSERT(all(equal(A.extent(), B.extent())));\n\t\t\tGLI_ASSERT(A.layers() == B.layers());\n\t\t\tGLI_ASSERT(A.levels() == B.levels());\n\t\t\tGLI_ASSERT(A.size() == B.size());\n\t\t\t\t\n\t\t\tfor(size_type LayerIndex = 0, LayerCount = A.layers(); LayerIndex < LayerCount; ++LayerIndex)\n\t\t\tfor(size_type FaceIndex = 0, FaceCount = A.faces(); FaceIndex < FaceCount; ++FaceIndex)\n\t\t\tfor(size_type LevelIndex = 0, LevelCount = A.levels(); LevelIndex < LevelCount; ++LevelIndex)\n\t\t\t{\n\t\t\t\textent_type const TexelCount(A.extent(LevelIndex));\n\t\t\t\textent_type TexelIndex(0);\n\t\t\t\t\n\t\t\t\tfor(TexelIndex.y = 0; TexelIndex.y < TexelCount.y; ++TexelIndex.y)\n\t\t\t\tfor(TexelIndex.x = 0; TexelIndex.x < TexelCount.x; ++TexelIndex.x)\n\t\t\t\t{\n\t\t\t\t\tOutput.store<vec_type>(TexelIndex, LayerIndex, FaceIndex, LevelIndex, Func(\n\t\t\t\t\t\tA.load<vec_type>(TexelIndex, LayerIndex, FaceIndex, LevelIndex),\n\t\t\t\t\t\tB.load<vec_type>(TexelIndex, LayerIndex, FaceIndex, LevelIndex)));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}//namepsace detail\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture1d& Out, texture1d const& In0, texture1d const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_1d<vec_type>::call(Out, In0, In1, Func);\n\t}\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture1d_array& Out, texture1d_array const& In0, texture1d_array const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_1d_array<vec_type>::call(Out, In0, In1, Func);\n\t}\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture2d& Out, texture2d const& In0, texture2d const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_2d<vec_type>::call(Out, In0, In1, Func);\n\t}\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture2d_array& Out, texture2d_array const& In0, texture2d_array const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_2d_array<vec_type>::call(Out, In0, In1, Func);\n\t}\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture3d& Out, texture3d const& In0, texture3d const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_3d<vec_type>::call(Out, In0, In1, Func);\n\t}\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture_cube& Out, texture_cube const& In0, texture_cube const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_cube<vec_type>::call(Out, In0, In1, Func);\n\t}\n\t\n\ttemplate <typename vec_type>\n\tinline void transform(texture_cube_array& Out, texture_cube_array const& In0, texture_cube_array const& In1, typename transform_func<vec_type>::type Func)\n\t{\n\t\tdetail::compute_transform_cube_array<vec_type>::call(Out, In0, In1, Func);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/core/view.inl",
    "content": "namespace gli\n{\n\tinline image view(image const& Image)\n\t{\n\t\treturn Image;\n\t}\n\n\tinline texture view(texture const& Texture)\n\t{\n\t\treturn Texture;\n\t}\n\n\ttemplate <typename texType>\n\tinline texture view(texType const& Texture)\n\t{\n\t\treturn Texture;\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture const& Texture,\n\t\ttexture::size_type BaseLayer, texture::size_type MaxLayer,\n\t\ttexture::size_type BaseFace, texture::size_type MaxFace,\n\t\ttexture::size_type BaseLevel, texture::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseFace >= 0 && BaseFace < Texture.faces() && MaxFace >= 0 && MaxFace < Texture.faces() && BaseFace <= MaxFace);\n\t\tGLI_ASSERT(BaseLayer >= 0 && BaseLayer < Texture.layers() && MaxLayer >= 0 && MaxLayer < Texture.layers() && BaseLayer <= MaxLayer);\n\n\t\treturn texture(\n\t\t\tTexture, Texture.target(), Texture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face() + BaseFace, Texture.base_face() + MaxFace,\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\ttemplate <typename texType>\n\tinline texture view(texType const& Texture, format Format)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(block_size(Texture.format()) == block_size(Format));\n\n\t\treturn texture(Texture, Texture.target(), Format);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture1d const& Texture,\n\t\ttexture1d::size_type BaseLevel, texture1d::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_1D, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture1d_array const & Texture,\n\t\ttexture1d_array::size_type BaseLayer, texture1d_array::size_type MaxLayer,\n\t\ttexture1d_array::size_type BaseLevel, texture1d_array::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLayer >= 0 && BaseLayer < Texture.layers() && MaxLayer >= 0 && MaxLayer < Texture.layers() && BaseLayer <= MaxLayer);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_1D_ARRAY, Texture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture2d const & Texture,\n\t\ttexture2d::size_type BaseLevel, texture2d::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_2D, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture2d_array const & Texture,\n\t\ttexture2d_array::size_type BaseLayer, texture2d_array::size_type MaxLayer,\n\t\ttexture2d_array::size_type BaseLevel, texture2d_array::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseLayer >= 0 && BaseLayer < Texture.layers() && MaxLayer >= 0 && MaxLayer < Texture.layers() && BaseLayer <= MaxLayer);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_2D_ARRAY, Texture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture3d const & Texture,\n\t\ttexture3d::size_type BaseLevel, texture3d::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_3D, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.max_face(),\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture_cube const & Texture,\n\t\ttexture_cube::size_type BaseFace, texture_cube::size_type MaxFace,\n\t\ttexture_cube::size_type BaseLevel, texture_cube::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseFace >= 0 && BaseFace < Texture.faces() && MaxFace >= 0 && MaxFace < Texture.faces() && BaseFace <= MaxFace);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_CUBE, Texture.format(),\n\t\t\tTexture.base_layer(), Texture.max_layer(),\n\t\t\tTexture.base_face(), Texture.base_face() + MaxFace,\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n\n\tinline texture view\n\t(\n\t\ttexture_cube_array const & Texture,\n\t\ttexture_cube_array::size_type BaseLayer, texture_cube_array::size_type MaxLayer,\n\t\ttexture_cube_array::size_type BaseFace, texture_cube_array::size_type MaxFace,\n\t\ttexture_cube_array::size_type BaseLevel, texture_cube_array::size_type MaxLevel\n\t)\n\t{\n\t\tGLI_ASSERT(!Texture.empty());\n\t\tGLI_ASSERT(BaseLevel >= 0 && BaseLevel < Texture.levels() && MaxLevel >= 0 && MaxLevel < Texture.levels() && BaseLevel <= MaxLevel);\n\t\tGLI_ASSERT(BaseFace >= 0 && BaseFace < Texture.faces() && MaxFace >= 0 && MaxFace < Texture.faces() && BaseFace <= MaxFace);\n\t\tGLI_ASSERT(BaseLayer >= 0 && BaseLayer < Texture.layers() && MaxLayer >= 0 && MaxLayer < Texture.layers() && BaseLayer <= MaxLayer);\n\n\t\treturn texture(\n\t\t\tTexture, TARGET_CUBE_ARRAY, Texture.format(),\n\t\t\tTexture.base_layer() + BaseLayer, Texture.base_layer() + MaxLayer,\n\t\t\tTexture.base_face() + BaseFace, Texture.base_face() + MaxFace,\n\t\t\tTexture.base_level() + BaseLevel, Texture.base_level() + MaxLevel);\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/duplicate.hpp",
    "content": "/// @brief Include to duplicate textures, images or a subset of either textures or an image. These operations will cause memory allocations.\n/// @file gli/duplicate.hpp\n\n#pragma once\n\n#include \"image.hpp\"\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\nnamespace gli\n{\n\t/// Duplicate an image and create a new image with a new storage_linear allocation.\n\timage duplicate(image const & Image);\n\n\t/// Duplicate a texture and create a new texture with a new storage_linear allocation.\n\ttemplate <typename texType>\n\ttexture duplicate(texType const& Texture);\n\n\t/// Duplicate a texture and create a new texture with a new storage_linear allocation but a different format.\n\t/// The format must be a compatible format, a format which block size match the original format. \n\ttemplate <typename texType>\n\ttexture duplicate(texType const& Texture, format Format);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture1d const& Texture,\n\t\ttexture1d::size_type BaseLevel, texture1d::size_type MaxLevel);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture1d_array const& Texture,\n\t\ttexture1d_array::size_type BaseLayer, texture1d_array::size_type MaxLayer,\n\t\ttexture1d_array::size_type BaseLevel, texture1d_array::size_type MaxLevel);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture2d const& Texture,\n\t\ttexture2d::size_type BaseLevel, texture2d::size_type MaxLevel);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture2d_array const& Texture,\n\t\ttexture2d_array::size_type BaseLayer, texture2d_array::size_type MaxLayer,\n\t\ttexture2d_array::size_type BaseLevel, texture2d_array::size_type MaxLevel);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture3d const& Texture,\n\t\ttexture3d::size_type BaseLevel, texture3d::size_type MaxLevel);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture_cube const& Texture,\n\t\ttexture_cube::size_type BaseFace, texture_cube::size_type MaxFace,\n\t\ttexture_cube::size_type BaseLevel, texture_cube::size_type MaxLevel);\n\n\t/// Duplicate a subset of a texture and create a new texture with a new storage_linear allocation.\n\ttexture duplicate(\n\t\ttexture_cube_array const& Texture,\n\t\ttexture_cube_array::size_type BaseLayer, texture_cube_array::size_type MaxLayer,\n\t\ttexture_cube_array::size_type BaseFace, texture_cube_array::size_type MaxFace,\n\t\ttexture_cube_array::size_type BaseLevel, texture_cube_array::size_type MaxLevel);\n}//namespace gli\n\n#include \"./core/duplicate.inl\"\n"
  },
  {
    "path": "lib/gli/dx.hpp",
    "content": "/// @brief Include to translate GLI enums to DirectX enums\n/// @file gli/dx.hpp\n\n#pragma once\n\n#include \"format.hpp\"\n#include \"target.hpp\"\n#include <array>\n\nnamespace gli\n{\n\t/// Translation class to convert GLI enums into DirectX enums\n\tclass dx\n\t{\n\tpublic:\n\t\t#define GLI_MAKEFOURCC(ch0, ch1, ch2, ch3) \\\n\t\t\t(std::uint32_t)( \\\n\t\t\t(((std::uint32_t)(std::uint8_t)(ch3) << 24) & 0xFF000000) | \\\n\t\t\t(((std::uint32_t)(std::uint8_t)(ch2) << 16) & 0x00FF0000) | \\\n\t\t\t(((std::uint32_t)(std::uint8_t)(ch1) <<  8) & 0x0000FF00) | \\\n\t\t\t((std::uint32_t)(std::uint8_t)(ch0)        & 0x000000FF) )\n\n\t\tenum d3dfmt\n\t\t{\n\t\t\tD3DFMT_UNKNOWN\t\t\t\t=  0,\n\n\t\t\tD3DFMT_R8G8B8\t\t\t\t= 20,\n\t\t\tD3DFMT_A8R8G8B8\t\t\t\t= 21,\n\t\t\tD3DFMT_X8R8G8B8\t\t\t\t= 22,\n\t\t\tD3DFMT_R5G6B5\t\t\t\t= 23,\n\t\t\tD3DFMT_X1R5G5B5\t\t\t\t= 24,\n\t\t\tD3DFMT_A1R5G5B5\t\t\t\t= 25,\n\t\t\tD3DFMT_A4R4G4B4\t\t\t\t= 26,\n\t\t\tD3DFMT_R3G3B2\t\t\t\t= 27,\n\t\t\tD3DFMT_A8\t\t\t\t\t= 28,\n\t\t\tD3DFMT_A8R3G3B2\t\t\t\t= 29,\n\t\t\tD3DFMT_X4R4G4B4\t\t\t\t= 30,\n\t\t\tD3DFMT_A2B10G10R10\t\t\t= 31,\n\t\t\tD3DFMT_A8B8G8R8\t\t\t\t= 32,\n\t\t\tD3DFMT_X8B8G8R8\t\t\t\t= 33,\n\t\t\tD3DFMT_G16R16\t\t\t\t= 34,\n\t\t\tD3DFMT_A2R10G10B10\t\t\t= 35,\n\t\t\tD3DFMT_A16B16G16R16\t\t\t= 36,\n\n\t\t\tD3DFMT_A8P8\t\t\t\t\t= 40,\n\t\t\tD3DFMT_P8\t\t\t\t\t= 41,\n\n\t\t\tD3DFMT_L8\t\t\t\t\t= 50,\n\t\t\tD3DFMT_A8L8\t\t\t\t\t= 51,\n\t\t\tD3DFMT_A4L4\t\t\t\t\t= 52,\n\n\t\t\tD3DFMT_V8U8\t\t\t\t\t= 60,\n\t\t\tD3DFMT_L6V5U5\t\t\t\t= 61,\n\t\t\tD3DFMT_X8L8V8U8\t\t\t\t= 62,\n\t\t\tD3DFMT_Q8W8V8U8\t\t\t\t= 63,\n\t\t\tD3DFMT_V16U16\t\t\t\t= 64,\n\t\t\tD3DFMT_A2W10V10U10\t\t\t= 67,\n\n\t\t\tD3DFMT_UYVY\t\t\t\t\t= GLI_MAKEFOURCC('U', 'Y', 'V', 'Y'),\n\t\t\tD3DFMT_R8G8_B8G8\t\t\t= GLI_MAKEFOURCC('R', 'G', 'B', 'G'),\n\t\t\tD3DFMT_YUY2\t\t\t\t\t= GLI_MAKEFOURCC('Y', 'U', 'Y', '2'),\n\t\t\tD3DFMT_G8R8_G8B8\t\t\t= GLI_MAKEFOURCC('G', 'R', 'G', 'B'),\n\t\t\tD3DFMT_DXT1\t\t\t\t\t= GLI_MAKEFOURCC('D', 'X', 'T', '1'),\n\t\t\tD3DFMT_DXT2\t\t\t\t\t= GLI_MAKEFOURCC('D', 'X', 'T', '2'),\n\t\t\tD3DFMT_DXT3\t\t\t\t\t= GLI_MAKEFOURCC('D', 'X', 'T', '3'),\n\t\t\tD3DFMT_DXT4\t\t\t\t\t= GLI_MAKEFOURCC('D', 'X', 'T', '4'),\n\t\t\tD3DFMT_DXT5\t\t\t\t\t= GLI_MAKEFOURCC('D', 'X', 'T', '5'),\n\n\t\t\tD3DFMT_ATI1\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', 'I', '1'),\n\t\t\tD3DFMT_AT1N\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', '1', 'N'),\n\t\t\tD3DFMT_ATI2\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', 'I', '2'),\n\t\t\tD3DFMT_AT2N\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', '2', 'N'),\n\n\t\t\tD3DFMT_BC4U\t\t\t\t\t= GLI_MAKEFOURCC('B', 'C', '4', 'U'),\n\t\t\tD3DFMT_BC4S\t\t\t\t\t= GLI_MAKEFOURCC('B', 'C', '4', 'S'),\n\t\t\tD3DFMT_BC5U\t\t\t\t\t= GLI_MAKEFOURCC('B', 'C', '5', 'U'),\n\t\t\tD3DFMT_BC5S\t\t\t\t\t= GLI_MAKEFOURCC('B', 'C', '5', 'S'),\n\n\t\t\tD3DFMT_ETC\t\t\t\t\t= GLI_MAKEFOURCC('E', 'T', 'C', ' '),\n\t\t\tD3DFMT_ETC1\t\t\t\t\t= GLI_MAKEFOURCC('E', 'T', 'C', '1'),\n\t\t\tD3DFMT_ATC\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', 'C', ' '),\n\t\t\tD3DFMT_ATCA\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', 'C', 'A'),\n\t\t\tD3DFMT_ATCI\t\t\t\t\t= GLI_MAKEFOURCC('A', 'T', 'C', 'I'),\n\n\t\t\tD3DFMT_POWERVR_2BPP\t\t\t= GLI_MAKEFOURCC('P', 'T', 'C', '2'),\n\t\t\tD3DFMT_POWERVR_4BPP\t\t\t= GLI_MAKEFOURCC('P', 'T', 'C', '4'),\n\n\t\t\tD3DFMT_D16_LOCKABLE\t\t\t= 70,\n\t\t\tD3DFMT_D32\t\t\t\t\t= 71,\n\t\t\tD3DFMT_D15S1\t\t\t\t= 73,\n\t\t\tD3DFMT_D24S8\t\t\t\t= 75,\n\t\t\tD3DFMT_D24X8\t\t\t\t= 77,\n\t\t\tD3DFMT_D24X4S4\t\t\t\t= 79,\n\t\t\tD3DFMT_D16\t\t\t\t\t= 80,\n\n\t\t\tD3DFMT_D32F_LOCKABLE\t\t= 82,\n\t\t\tD3DFMT_D24FS8\t\t\t\t= 83,\n\n\t\t\tD3DFMT_L16\t\t\t\t\t= 81,\n\n\t\t\tD3DFMT_VERTEXDATA\t\t\t= 100,\n\t\t\tD3DFMT_INDEX16\t\t\t\t= 101,\n\t\t\tD3DFMT_INDEX32\t\t\t\t= 102,\n\n\t\t\tD3DFMT_Q16W16V16U16\t\t\t= 110,\n\n\t\t\tD3DFMT_MULTI2_ARGB8\t\t\t= GLI_MAKEFOURCC('M','E','T','1'),\n\n\t\t\tD3DFMT_R16F\t\t\t\t\t= 111,\n\t\t\tD3DFMT_G16R16F\t\t\t\t= 112,\n\t\t\tD3DFMT_A16B16G16R16F\t\t= 113,\n\n\t\t\tD3DFMT_R32F\t\t\t\t\t= 114,\n\t\t\tD3DFMT_G32R32F\t\t\t\t= 115,\n\t\t\tD3DFMT_A32B32G32R32F\t\t= 116,\n\n\t\t\tD3DFMT_CxV8U8\t\t\t\t= 117,\n\n\t\t\tD3DFMT_DX10\t\t\t\t\t= GLI_MAKEFOURCC('D', 'X', '1', '0'),\n\n\t\t\tD3DFMT_GLI1\t\t\t\t\t= GLI_MAKEFOURCC('G', 'L', 'I', '1'),\n\n\t\t\tD3DFMT_FORCE_DWORD\t\t\t= 0x7fffffff\n\t\t};\n\t\t\n\t\tenum dxgi_format_dds\n\t\t{\n\t\t\tDXGI_FORMAT_UNKNOWN\t\t\t\t\t\t\t= 0,\n\t\t\tDXGI_FORMAT_R32G32B32A32_TYPELESS\t\t\t= 1,\n\t\t\tDXGI_FORMAT_R32G32B32A32_FLOAT\t\t\t\t= 2,\n\t\t\tDXGI_FORMAT_R32G32B32A32_UINT\t\t\t\t= 3,\n\t\t\tDXGI_FORMAT_R32G32B32A32_SINT\t\t\t\t= 4,\n\t\t\tDXGI_FORMAT_R32G32B32_TYPELESS\t\t\t\t= 5,\n\t\t\tDXGI_FORMAT_R32G32B32_FLOAT\t\t\t\t\t= 6,\n\t\t\tDXGI_FORMAT_R32G32B32_UINT\t\t\t\t\t= 7,\n\t\t\tDXGI_FORMAT_R32G32B32_SINT\t\t\t\t\t= 8,\n\t\t\tDXGI_FORMAT_R16G16B16A16_TYPELESS\t\t\t= 9,\n\t\t\tDXGI_FORMAT_R16G16B16A16_FLOAT\t\t\t\t= 10,\n\t\t\tDXGI_FORMAT_R16G16B16A16_UNORM\t\t\t\t= 11,\n\t\t\tDXGI_FORMAT_R16G16B16A16_UINT\t\t\t\t= 12,\n\t\t\tDXGI_FORMAT_R16G16B16A16_SNORM\t\t\t\t= 13,\n\t\t\tDXGI_FORMAT_R16G16B16A16_SINT\t\t\t\t= 14,\n\t\t\tDXGI_FORMAT_R32G32_TYPELESS\t\t\t\t\t= 15,\n\t\t\tDXGI_FORMAT_R32G32_FLOAT\t\t\t\t\t= 16,\n\t\t\tDXGI_FORMAT_R32G32_UINT\t\t\t\t\t\t= 17,\n\t\t\tDXGI_FORMAT_R32G32_SINT\t\t\t\t\t\t= 18,\n\t\t\tDXGI_FORMAT_R32G8X24_TYPELESS\t\t\t\t= 19,\n\t\t\tDXGI_FORMAT_D32_FLOAT_S8X24_UINT\t\t\t= 20,\n\t\t\tDXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS\t\t= 21,\n\t\t\tDXGI_FORMAT_X32_TYPELESS_G8X24_UINT\t\t\t= 22,\n\t\t\tDXGI_FORMAT_R10G10B10A2_TYPELESS\t\t\t= 23,\n\t\t\tDXGI_FORMAT_R10G10B10A2_UNORM\t\t\t\t= 24,\n\t\t\tDXGI_FORMAT_R10G10B10A2_UINT\t\t\t\t= 25,\n\t\t\tDXGI_FORMAT_R11G11B10_FLOAT\t\t\t\t\t= 26,\n\t\t\tDXGI_FORMAT_R8G8B8A8_TYPELESS\t\t\t\t= 27,\n\t\t\tDXGI_FORMAT_R8G8B8A8_UNORM\t\t\t\t\t= 28,\n\t\t\tDXGI_FORMAT_R8G8B8A8_UNORM_SRGB\t\t\t\t= 29,\n\t\t\tDXGI_FORMAT_R8G8B8A8_UINT\t\t\t\t\t= 30,\n\t\t\tDXGI_FORMAT_R8G8B8A8_SNORM\t\t\t\t\t= 31,\n\t\t\tDXGI_FORMAT_R8G8B8A8_SINT\t\t\t\t\t= 32,\n\t\t\tDXGI_FORMAT_R16G16_TYPELESS\t\t\t\t\t= 33,\n\t\t\tDXGI_FORMAT_R16G16_FLOAT\t\t\t\t\t= 34,\n\t\t\tDXGI_FORMAT_R16G16_UNORM\t\t\t\t\t= 35,\n\t\t\tDXGI_FORMAT_R16G16_UINT\t\t\t\t\t\t= 36,\n\t\t\tDXGI_FORMAT_R16G16_SNORM\t\t\t\t\t= 37,\n\t\t\tDXGI_FORMAT_R16G16_SINT\t\t\t\t\t\t= 38,\n\t\t\tDXGI_FORMAT_R32_TYPELESS\t\t\t\t\t= 39,\n\t\t\tDXGI_FORMAT_D32_FLOAT\t\t\t\t\t\t= 40,\n\t\t\tDXGI_FORMAT_R32_FLOAT\t\t\t\t\t\t= 41,\n\t\t\tDXGI_FORMAT_R32_UINT\t\t\t\t\t\t= 42,\n\t\t\tDXGI_FORMAT_R32_SINT\t\t\t\t\t\t= 43,\n\t\t\tDXGI_FORMAT_R24G8_TYPELESS\t\t\t\t\t= 44,\n\t\t\tDXGI_FORMAT_D24_UNORM_S8_UINT\t\t\t\t= 45,\n\t\t\tDXGI_FORMAT_R24_UNORM_X8_TYPELESS\t\t\t= 46,\n\t\t\tDXGI_FORMAT_X24_TYPELESS_G8_UINT\t\t\t= 47,\n\t\t\tDXGI_FORMAT_R8G8_TYPELESS\t\t\t\t\t= 48,\n\t\t\tDXGI_FORMAT_R8G8_UNORM\t\t\t\t\t\t= 49,\n\t\t\tDXGI_FORMAT_R8G8_UINT\t\t\t\t\t\t= 50,\n\t\t\tDXGI_FORMAT_R8G8_SNORM\t\t\t\t\t\t= 51,\n\t\t\tDXGI_FORMAT_R8G8_SINT\t\t\t\t\t\t= 52,\n\t\t\tDXGI_FORMAT_R16_TYPELESS\t\t\t\t\t= 53,\n\t\t\tDXGI_FORMAT_R16_FLOAT\t\t\t\t\t\t= 54,\n\t\t\tDXGI_FORMAT_D16_UNORM\t\t\t\t\t\t= 55,\n\t\t\tDXGI_FORMAT_R16_UNORM\t\t\t\t\t\t= 56,\n\t\t\tDXGI_FORMAT_R16_UINT\t\t\t\t\t\t= 57,\n\t\t\tDXGI_FORMAT_R16_SNORM\t\t\t\t\t\t= 58,\n\t\t\tDXGI_FORMAT_R16_SINT\t\t\t\t\t\t= 59,\n\t\t\tDXGI_FORMAT_R8_TYPELESS\t\t\t\t\t\t= 60,\n\t\t\tDXGI_FORMAT_R8_UNORM\t\t\t\t\t\t= 61,\n\t\t\tDXGI_FORMAT_R8_UINT\t\t\t\t\t\t\t= 62,\n\t\t\tDXGI_FORMAT_R8_SNORM\t\t\t\t\t\t= 63,\n\t\t\tDXGI_FORMAT_R8_SINT\t\t\t\t\t\t\t= 64,\n\t\t\tDXGI_FORMAT_A8_UNORM\t\t\t\t\t\t= 65,\n\t\t\tDXGI_FORMAT_R1_UNORM\t\t\t\t\t\t= 66,\n\t\t\tDXGI_FORMAT_R9G9B9E5_SHAREDEXP\t\t\t\t= 67,\n\t\t\tDXGI_FORMAT_R8G8_B8G8_UNORM\t\t\t\t\t= 68,\n\t\t\tDXGI_FORMAT_G8R8_G8B8_UNORM\t\t\t\t\t= 69,\n\t\t\tDXGI_FORMAT_BC1_TYPELESS\t\t\t\t\t= 70,\n\t\t\tDXGI_FORMAT_BC1_UNORM\t\t\t\t\t\t= 71,\n\t\t\tDXGI_FORMAT_BC1_UNORM_SRGB\t\t\t\t\t= 72,\n\t\t\tDXGI_FORMAT_BC2_TYPELESS\t\t\t\t\t= 73,\n\t\t\tDXGI_FORMAT_BC2_UNORM\t\t\t\t\t\t= 74,\n\t\t\tDXGI_FORMAT_BC2_UNORM_SRGB\t\t\t\t\t= 75,\n\t\t\tDXGI_FORMAT_BC3_TYPELESS\t\t\t\t\t= 76,\n\t\t\tDXGI_FORMAT_BC3_UNORM\t\t\t\t\t\t= 77,\n\t\t\tDXGI_FORMAT_BC3_UNORM_SRGB\t\t\t\t\t= 78,\n\t\t\tDXGI_FORMAT_BC4_TYPELESS\t\t\t\t\t= 79,\n\t\t\tDXGI_FORMAT_BC4_UNORM\t\t\t\t\t\t= 80,\n\t\t\tDXGI_FORMAT_BC4_SNORM\t\t\t\t\t\t= 81,\n\t\t\tDXGI_FORMAT_BC5_TYPELESS\t\t\t\t\t= 82,\n\t\t\tDXGI_FORMAT_BC5_UNORM\t\t\t\t\t\t= 83,\n\t\t\tDXGI_FORMAT_BC5_SNORM\t\t\t\t\t\t= 84,\n\t\t\tDXGI_FORMAT_B5G6R5_UNORM\t\t\t\t\t= 85,\n\t\t\tDXGI_FORMAT_B5G5R5A1_UNORM\t\t\t\t\t= 86,\n\t\t\tDXGI_FORMAT_B8G8R8A8_UNORM\t\t\t\t\t= 87,\n\t\t\tDXGI_FORMAT_B8G8R8X8_UNORM\t\t\t\t\t= 88,\n\t\t\tDXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM\t\t= 89,\n\t\t\tDXGI_FORMAT_B8G8R8A8_TYPELESS\t\t\t\t= 90,\n\t\t\tDXGI_FORMAT_B8G8R8A8_UNORM_SRGB\t\t\t\t= 91,\n\t\t\tDXGI_FORMAT_B8G8R8X8_TYPELESS\t\t\t\t= 92,\n\t\t\tDXGI_FORMAT_B8G8R8X8_UNORM_SRGB\t\t\t\t= 93,\n\t\t\tDXGI_FORMAT_BC6H_TYPELESS\t\t\t\t\t= 94,\n\t\t\tDXGI_FORMAT_BC6H_UF16\t\t\t\t\t\t= 95,\n\t\t\tDXGI_FORMAT_BC6H_SF16\t\t\t\t\t\t= 96,\n\t\t\tDXGI_FORMAT_BC7_TYPELESS\t\t\t\t\t= 97,\n\t\t\tDXGI_FORMAT_BC7_UNORM\t\t\t\t\t\t= 98,\n\t\t\tDXGI_FORMAT_BC7_UNORM_SRGB\t\t\t\t\t= 99,\n\t\t\tDXGI_FORMAT_AYUV\t\t\t\t\t\t\t= 100,\n\t\t\tDXGI_FORMAT_Y410\t\t\t\t\t\t\t= 101,\n\t\t\tDXGI_FORMAT_Y416\t\t\t\t\t\t\t= 102,\n\t\t\tDXGI_FORMAT_NV12\t\t\t\t\t\t\t= 103,\n\t\t\tDXGI_FORMAT_P010\t\t\t\t\t\t\t= 104,\n\t\t\tDXGI_FORMAT_P016\t\t\t\t\t\t\t= 105,\n\t\t\tDXGI_FORMAT_420_OPAQUE\t\t\t\t\t\t= 106,\n\t\t\tDXGI_FORMAT_YUY2\t\t\t\t\t\t\t= 107,\n\t\t\tDXGI_FORMAT_Y210\t\t\t\t\t\t\t= 108,\n\t\t\tDXGI_FORMAT_Y216\t\t\t\t\t\t\t= 109,\n\t\t\tDXGI_FORMAT_NV11\t\t\t\t\t\t\t= 110,\n\t\t\tDXGI_FORMAT_AI44\t\t\t\t\t\t\t= 111,\n\t\t\tDXGI_FORMAT_IA44\t\t\t\t\t\t\t= 112,\n\t\t\tDXGI_FORMAT_P8\t\t\t\t\t\t\t\t= 113,\n\t\t\tDXGI_FORMAT_A8P8\t\t\t\t\t\t\t= 114,\n\t\t\tDXGI_FORMAT_B4G4R4A4_UNORM\t\t\t\t\t= 115,\n\n\t\t\tDXGI_FORMAT_P208\t\t\t\t\t\t\t= 130,\n\t\t\tDXGI_FORMAT_V208\t\t\t\t\t\t\t= 131,\n\t\t\tDXGI_FORMAT_V408\t\t\t\t\t\t\t= 132,\n\t\t\tDXGI_FORMAT_ASTC_4X4_TYPELESS\t\t\t\t= 133,\n\t\t\tDXGI_FORMAT_ASTC_4X4_UNORM\t\t\t\t\t= 134,\n\t\t\tDXGI_FORMAT_ASTC_4X4_UNORM_SRGB\t\t\t\t= 135,\n\t\t\tDXGI_FORMAT_ASTC_5X4_TYPELESS\t\t\t\t= 137,\n\t\t\tDXGI_FORMAT_ASTC_5X4_UNORM\t\t\t\t\t= 138,\n\t\t\tDXGI_FORMAT_ASTC_5X4_UNORM_SRGB\t\t\t\t= 139,\n\t\t\tDXGI_FORMAT_ASTC_5X5_TYPELESS\t\t\t\t= 141,\n\t\t\tDXGI_FORMAT_ASTC_5X5_UNORM\t\t\t\t\t= 142,\n\t\t\tDXGI_FORMAT_ASTC_5X5_UNORM_SRGB\t\t\t\t= 143,\n\t\t\tDXGI_FORMAT_ASTC_6X5_TYPELESS\t\t\t\t= 145,\n\t\t\tDXGI_FORMAT_ASTC_6X5_UNORM\t\t\t\t\t= 146,\n\t\t\tDXGI_FORMAT_ASTC_6X5_UNORM_SRGB\t\t\t\t= 147,\n\t\t\tDXGI_FORMAT_ASTC_6X6_TYPELESS\t\t\t\t= 149,\n\t\t\tDXGI_FORMAT_ASTC_6X6_UNORM\t\t\t\t\t= 150,\n\t\t\tDXGI_FORMAT_ASTC_6X6_UNORM_SRGB\t\t\t\t= 151,\n\t\t\tDXGI_FORMAT_ASTC_8X5_TYPELESS\t\t\t\t= 153,\n\t\t\tDXGI_FORMAT_ASTC_8X5_UNORM\t\t\t\t\t= 154,\n\t\t\tDXGI_FORMAT_ASTC_8X5_UNORM_SRGB\t\t\t\t= 155,\n\t\t\tDXGI_FORMAT_ASTC_8X6_TYPELESS\t\t\t\t= 157,\n\t\t\tDXGI_FORMAT_ASTC_8X6_UNORM\t\t\t\t\t= 158,\n\t\t\tDXGI_FORMAT_ASTC_8X6_UNORM_SRGB\t\t\t\t= 159,\n\t\t\tDXGI_FORMAT_ASTC_8X8_TYPELESS\t\t\t\t= 161,\n\t\t\tDXGI_FORMAT_ASTC_8X8_UNORM\t\t\t\t\t= 162,\n\t\t\tDXGI_FORMAT_ASTC_8X8_UNORM_SRGB\t\t\t\t= 163,\n\t\t\tDXGI_FORMAT_ASTC_10X5_TYPELESS\t\t\t\t= 165,\n\t\t\tDXGI_FORMAT_ASTC_10X5_UNORM\t\t\t\t\t= 166,\n\t\t\tDXGI_FORMAT_ASTC_10X5_UNORM_SRGB\t\t\t= 167,\n\t\t\tDXGI_FORMAT_ASTC_10X6_TYPELESS\t\t\t\t= 169,\n\t\t\tDXGI_FORMAT_ASTC_10X6_UNORM\t\t\t\t\t= 170,\n\t\t\tDXGI_FORMAT_ASTC_10X6_UNORM_SRGB\t\t\t= 171,\n\t\t\tDXGI_FORMAT_ASTC_10X8_TYPELESS\t\t\t\t= 173,\n\t\t\tDXGI_FORMAT_ASTC_10X8_UNORM\t\t\t\t\t= 174,\n\t\t\tDXGI_FORMAT_ASTC_10X8_UNORM_SRGB\t\t\t= 175,\n\t\t\tDXGI_FORMAT_ASTC_10X10_TYPELESS\t\t\t\t= 177,\n\t\t\tDXGI_FORMAT_ASTC_10X10_UNORM\t\t\t\t= 178,\n\t\t\tDXGI_FORMAT_ASTC_10X10_UNORM_SRGB\t\t\t= 179,\n\t\t\tDXGI_FORMAT_ASTC_12X10_TYPELESS\t\t\t\t= 181,\n\t\t\tDXGI_FORMAT_ASTC_12X10_UNORM\t\t\t\t= 182,\n\t\t\tDXGI_FORMAT_ASTC_12X10_UNORM_SRGB\t\t\t= 183,\n\t\t\tDXGI_FORMAT_ASTC_12X12_TYPELESS\t\t\t\t= 185,\n\t\t\tDXGI_FORMAT_ASTC_12X12_UNORM\t\t\t\t= 186,\n\t\t\tDXGI_FORMAT_ASTC_12X12_UNORM_SRGB\t\t\t= 187,\n\n\t\t\tDXGI_FORMAT_FORCE_UINT\t\t\t\t\t\t= 0xffffffffUL\n\t\t};\n\n\t\tenum dxgi_format_gli\n\t\t{\n\t\t\tDXGI_FORMAT_R64_UINT_GLI = 1,\n\t\t\tDXGI_FORMAT_R64_SINT_GLI,\n\t\t\tDXGI_FORMAT_R64_FLOAT_GLI,\n\t\t\tDXGI_FORMAT_R64G64_UINT_GLI,\n\t\t\tDXGI_FORMAT_R64G64_SINT_GLI,\n\t\t\tDXGI_FORMAT_R64G64_FLOAT_GLI,\n\t\t\tDXGI_FORMAT_R64G64B64_UINT_GLI,\n\t\t\tDXGI_FORMAT_R64G64B64_SINT_GLI,\n\t\t\tDXGI_FORMAT_R64G64B64_FLOAT_GLI,\n\t\t\tDXGI_FORMAT_R64G64B64A64_UINT_GLI,\n\t\t\tDXGI_FORMAT_R64G64B64A64_SINT_GLI,\n\t\t\tDXGI_FORMAT_R64G64B64A64_FLOAT_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_RG4_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA4_UNORM_GLI,\n\t\t\tDXGI_FORMAT_R5G6B5_UNORM_GLI,\n\t\t\tDXGI_FORMAT_R5G5B5A1_UNORM_GLI,\n\t\t\tDXGI_FORMAT_A1B5G5R5_UNORM_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_R8_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R8_SSCALED_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R8G8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_R8G8_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R8G8_SSCALED_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R8G8B8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8_SNORM_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8_UINT_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8_SINT_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8_SRGB_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_B8G8R8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8_SNORM_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8_USCALED_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8_UINT_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8_SINT_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8_SRGB_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R8G8B8A8_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_SSCALED_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_B8G8R8A8_SNORM_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8A8_USCALED_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8A8_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8A8_UINT_GLI,\n\t\t\tDXGI_FORMAT_B8G8R8A8_SINT_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_UNORM_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_SNORM_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_UINT_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_SINT_GLI,\n\t\t\tDXGI_FORMAT_R8G8B8A8_PACK_SRGB_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R10G10B10A2_SNORM_GLI,\n\t\t\tDXGI_FORMAT_R10G10B10A2_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R10G10B10A2_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_R10G10B10A2_SINT_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_B10G10R10A2_UNORM_GLI,\n\t\t\tDXGI_FORMAT_B10G10R10A2_SNORM_GLI,\n\t\t\tDXGI_FORMAT_B10G10R10A2_USCALED_GLI,\n\t\t\tDXGI_FORMAT_B10G10R10A2_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_B10G10R10A2_UINT_GLI,\n\t\t\tDXGI_FORMAT_B10G10R10A2_SINT_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R16_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R16_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_R16G16_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R16G16_SSCALED_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R16G16B16_UNORM_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16_SNORM_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16_SSCALED_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16_UINT_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16_SINT_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16_FLOAT_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R16G16B16A16_USCALED_GLI,\n\t\t\tDXGI_FORMAT_R16G16B16A16_SSCALED_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_S8_UINT_GLI,\n\t\t\tDXGI_FORMAT_D16_UNORM_S8_UINT_GLI,\n\t\t\tDXGI_FORMAT_D24_UNORM_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_L8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_A8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_LA8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_L16_UNORM_GLI,\n\t\t\tDXGI_FORMAT_A16_UNORM_GLI,\n\t\t\tDXGI_FORMAT_LA16_UNORM_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_R3G3B2_UNORM_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_BC1_RGB_UNORM_GLI,\n\t\t\tDXGI_FORMAT_BC1_RGB_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGB_ETC2_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGB_ETC2_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGBA_ETC2_A1_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_ETC2_A1_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGBA_ETC2_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_ETC2_SRGB_GLI,\n\t\t\tDXGI_FORMAT_R11_EAC_UNORM_GLI,\n\t\t\tDXGI_FORMAT_R11_EAC_SNORM_GLI,\n\t\t\tDXGI_FORMAT_RG11_EAC_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RG11_EAC_SNORM_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_RGB_PVRTC1_8X8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGB_PVRTC1_8X8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGB_PVRTC1_16X8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGB_PVRTC1_16X8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC1_8X8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC1_8X8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC1_16X8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC1_16X8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC2_8X8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC2_8X8_SRGB_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC2_16X8_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_PVRTC2_16X8_SRGB_GLI,\n\t\t\t\n\t\t\tDXGI_FORMAT_RGB_ETC_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGB_ATC_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_ATCA_UNORM_GLI,\n\t\t\tDXGI_FORMAT_RGBA_ATCI_UNORM_GLI,\n\t\t};\n\t\t\n\t\tunion dxgiFormat\n\t\t{\n\t\t\tdxgiFormat()\n\t\t\t\t: DDS(DXGI_FORMAT_UNKNOWN)\n\t\t\t{}\n\t\t\t\n\t\t\tdxgiFormat(dxgi_format_dds DDS)\n\t\t\t\t: DDS(DDS)\n\t\t\t{}\n\n\t\t\tdxgiFormat(dxgi_format_gli GLI)\n\t\t\t\t: GLI(GLI)\n\t\t\t{}\n\t\t\t\n\t\t\tdxgi_format_dds DDS;\n\t\t\tdxgi_format_gli GLI;\n\t\t};\n\t\t\n\t\tenum ddpf\n\t\t{\n\t\t\tDDPF_ALPHAPIXELS = 0x1,\n\t\t\tDDPF_ALPHA = 0x2,\n\t\t\tDDPF_FOURCC = 0x4,\n\t\t\tDDPF_RGB = 0x40,\n\t\t\tDDPF_YUV = 0x200,\n\t\t\tDDPF_LUMINANCE = 0x20000,\n\t\t\tDDPF_LUMINANCE_ALPHA = DDPF_LUMINANCE | DDPF_ALPHA,\n\t\t\tDDPF_RGBAPIXELS = DDPF_RGB | DDPF_ALPHAPIXELS,\n\t\t\tDDPF_RGBA = DDPF_RGB | DDPF_ALPHA,\n\t\t\tDDPF_LUMINANCE_ALPHAPIXELS = DDPF_LUMINANCE | DDPF_ALPHAPIXELS,\n\n\t\t};\n\n\t\tstruct format\n\t\t{\n\t\t\tddpf DDPixelFormat;\n\t\t\td3dfmt D3DFormat;\n\t\t\tdxgiFormat DXGIFormat;\n\t\t\tglm::u32vec4 Mask;\n\t\t};\n\n\tpublic:\n\t\tdx();\n\n\t\t/// Convert GLI formats into Direct3D formats\n\t\tformat const& translate(gli::format Format) const;\n\n\t\t/// Convert a Direct3D 9 format into a GLI format\n\t\tgli::format find(d3dfmt FourCC) const;\n\n\t\t/// Convert a Direct3D 10 format into a GLI format\n\t\tgli::format find(d3dfmt FourCC, dxgiFormat Format) const;\n\n\tprivate:\n\t\tstd::array<format, FORMAT_COUNT> Translation;\n\t};\n\n\t/// Evaluate whether a target and format combinaison is only supported by the DDS container through GLI DDS extension.\n\tbool is_dds_ext(target Target, format Format);\n}//namespace gli\n\n#include \"./core/dx.inl\"\n"
  },
  {
    "path": "lib/gli/format.hpp",
    "content": "/// @brief Include to use the format enum and query properties of formats.\n/// @file gli/format.hpp\n\n#pragma once\n\n#include \"type.hpp\"\n#include <cstdint>\n\nnamespace gli\n{\n\t/// Texture data format\n\tenum format\n\t{\n\t\tFORMAT_UNDEFINED = 0,\n\n\t\tFORMAT_RG4_UNORM_PACK8, FORMAT_FIRST = FORMAT_RG4_UNORM_PACK8,\n\t\tFORMAT_RGBA4_UNORM_PACK16,\n\t\tFORMAT_BGRA4_UNORM_PACK16,\n\t\tFORMAT_R5G6B5_UNORM_PACK16,\n\t\tFORMAT_B5G6R5_UNORM_PACK16,\n\t\tFORMAT_RGB5A1_UNORM_PACK16,\n\t\tFORMAT_BGR5A1_UNORM_PACK16,\n\t\tFORMAT_A1RGB5_UNORM_PACK16,\n\n\t\tFORMAT_R8_UNORM_PACK8,\n\t\tFORMAT_R8_SNORM_PACK8,\n\t\tFORMAT_R8_USCALED_PACK8,\n\t\tFORMAT_R8_SSCALED_PACK8,\n\t\tFORMAT_R8_UINT_PACK8,\n\t\tFORMAT_R8_SINT_PACK8,\n\t\tFORMAT_R8_SRGB_PACK8,\n\n\t\tFORMAT_RG8_UNORM_PACK8,\n\t\tFORMAT_RG8_SNORM_PACK8,\n\t\tFORMAT_RG8_USCALED_PACK8,\n\t\tFORMAT_RG8_SSCALED_PACK8,\n\t\tFORMAT_RG8_UINT_PACK8,\n\t\tFORMAT_RG8_SINT_PACK8,\n\t\tFORMAT_RG8_SRGB_PACK8,\n\n\t\tFORMAT_RGB8_UNORM_PACK8,\n\t\tFORMAT_RGB8_SNORM_PACK8,\n\t\tFORMAT_RGB8_USCALED_PACK8,\n\t\tFORMAT_RGB8_SSCALED_PACK8,\n\t\tFORMAT_RGB8_UINT_PACK8,\n\t\tFORMAT_RGB8_SINT_PACK8,\n\t\tFORMAT_RGB8_SRGB_PACK8,\n\n\t\tFORMAT_BGR8_UNORM_PACK8,\n\t\tFORMAT_BGR8_SNORM_PACK8,\n\t\tFORMAT_BGR8_USCALED_PACK8,\n\t\tFORMAT_BGR8_SSCALED_PACK8,\n\t\tFORMAT_BGR8_UINT_PACK8,\n\t\tFORMAT_BGR8_SINT_PACK8,\n\t\tFORMAT_BGR8_SRGB_PACK8,\n\n\t\tFORMAT_RGBA8_UNORM_PACK8,\n\t\tFORMAT_RGBA8_SNORM_PACK8,\n\t\tFORMAT_RGBA8_USCALED_PACK8,\n\t\tFORMAT_RGBA8_SSCALED_PACK8,\n\t\tFORMAT_RGBA8_UINT_PACK8,\n\t\tFORMAT_RGBA8_SINT_PACK8,\n\t\tFORMAT_RGBA8_SRGB_PACK8,\n\n\t\tFORMAT_BGRA8_UNORM_PACK8,\n\t\tFORMAT_BGRA8_SNORM_PACK8,\n\t\tFORMAT_BGRA8_USCALED_PACK8,\n\t\tFORMAT_BGRA8_SSCALED_PACK8,\n\t\tFORMAT_BGRA8_UINT_PACK8,\n\t\tFORMAT_BGRA8_SINT_PACK8,\n\t\tFORMAT_BGRA8_SRGB_PACK8,\n\n\t\tFORMAT_RGBA8_UNORM_PACK32,\n\t\tFORMAT_RGBA8_SNORM_PACK32,\n\t\tFORMAT_RGBA8_USCALED_PACK32,\n\t\tFORMAT_RGBA8_SSCALED_PACK32,\n\t\tFORMAT_RGBA8_UINT_PACK32,\n\t\tFORMAT_RGBA8_SINT_PACK32,\n\t\tFORMAT_RGBA8_SRGB_PACK32,\n\n\t\tFORMAT_RGB10A2_UNORM_PACK32,\n\t\tFORMAT_RGB10A2_SNORM_PACK32,\n\t\tFORMAT_RGB10A2_USCALED_PACK32,\n\t\tFORMAT_RGB10A2_SSCALED_PACK32,\n\t\tFORMAT_RGB10A2_UINT_PACK32,\n\t\tFORMAT_RGB10A2_SINT_PACK32,\n\n\t\tFORMAT_BGR10A2_UNORM_PACK32,\n\t\tFORMAT_BGR10A2_SNORM_PACK32,\n\t\tFORMAT_BGR10A2_USCALED_PACK32,\n\t\tFORMAT_BGR10A2_SSCALED_PACK32,\n\t\tFORMAT_BGR10A2_UINT_PACK32,\n\t\tFORMAT_BGR10A2_SINT_PACK32,\n\n\t\tFORMAT_R16_UNORM_PACK16,\n\t\tFORMAT_R16_SNORM_PACK16,\n\t\tFORMAT_R16_USCALED_PACK16,\n\t\tFORMAT_R16_SSCALED_PACK16,\n\t\tFORMAT_R16_UINT_PACK16,\n\t\tFORMAT_R16_SINT_PACK16,\n\t\tFORMAT_R16_SFLOAT_PACK16,\n\n\t\tFORMAT_RG16_UNORM_PACK16,\n\t\tFORMAT_RG16_SNORM_PACK16,\n\t\tFORMAT_RG16_USCALED_PACK16,\n\t\tFORMAT_RG16_SSCALED_PACK16,\n\t\tFORMAT_RG16_UINT_PACK16,\n\t\tFORMAT_RG16_SINT_PACK16,\n\t\tFORMAT_RG16_SFLOAT_PACK16,\n\n\t\tFORMAT_RGB16_UNORM_PACK16,\n\t\tFORMAT_RGB16_SNORM_PACK16,\n\t\tFORMAT_RGB16_USCALED_PACK16,\n\t\tFORMAT_RGB16_SSCALED_PACK16,\n\t\tFORMAT_RGB16_UINT_PACK16,\n\t\tFORMAT_RGB16_SINT_PACK16,\n\t\tFORMAT_RGB16_SFLOAT_PACK16,\n\n\t\tFORMAT_RGBA16_UNORM_PACK16,\n\t\tFORMAT_RGBA16_SNORM_PACK16,\n\t\tFORMAT_RGBA16_USCALED_PACK16,\n\t\tFORMAT_RGBA16_SSCALED_PACK16,\n\t\tFORMAT_RGBA16_UINT_PACK16,\n\t\tFORMAT_RGBA16_SINT_PACK16,\n\t\tFORMAT_RGBA16_SFLOAT_PACK16,\n\n\t\tFORMAT_R32_UINT_PACK32,\n\t\tFORMAT_R32_SINT_PACK32,\n\t\tFORMAT_R32_SFLOAT_PACK32,\n\n\t\tFORMAT_RG32_UINT_PACK32,\n\t\tFORMAT_RG32_SINT_PACK32,\n\t\tFORMAT_RG32_SFLOAT_PACK32,\n\n\t\tFORMAT_RGB32_UINT_PACK32,\n\t\tFORMAT_RGB32_SINT_PACK32,\n\t\tFORMAT_RGB32_SFLOAT_PACK32,\n\n\t\tFORMAT_RGBA32_UINT_PACK32,\n\t\tFORMAT_RGBA32_SINT_PACK32,\n\t\tFORMAT_RGBA32_SFLOAT_PACK32,\n\n\t\tFORMAT_R64_UINT_PACK64,\n\t\tFORMAT_R64_SINT_PACK64,\n\t\tFORMAT_R64_SFLOAT_PACK64,\n\n\t\tFORMAT_RG64_UINT_PACK64,\n\t\tFORMAT_RG64_SINT_PACK64,\n\t\tFORMAT_RG64_SFLOAT_PACK64,\n\n\t\tFORMAT_RGB64_UINT_PACK64,\n\t\tFORMAT_RGB64_SINT_PACK64,\n\t\tFORMAT_RGB64_SFLOAT_PACK64,\n\n\t\tFORMAT_RGBA64_UINT_PACK64,\n\t\tFORMAT_RGBA64_SINT_PACK64,\n\t\tFORMAT_RGBA64_SFLOAT_PACK64,\n\n\t\tFORMAT_RG11B10_UFLOAT_PACK32,\n\t\tFORMAT_RGB9E5_UFLOAT_PACK32,\n\n\t\tFORMAT_D16_UNORM_PACK16,\n\t\tFORMAT_D24_UNORM_PACK32,\n\t\tFORMAT_D32_SFLOAT_PACK32,\n\t\tFORMAT_S8_UINT_PACK8,\n\t\tFORMAT_D16_UNORM_S8_UINT_PACK32,\n\t\tFORMAT_D24_UNORM_S8_UINT_PACK32,\n\t\tFORMAT_D32_SFLOAT_S8_UINT_PACK64,\n\n\t\tFORMAT_RGB_DXT1_UNORM_BLOCK8,\n\t\tFORMAT_RGB_DXT1_SRGB_BLOCK8,\n\t\tFORMAT_RGBA_DXT1_UNORM_BLOCK8,\n\t\tFORMAT_RGBA_DXT1_SRGB_BLOCK8,\n\t\tFORMAT_RGBA_DXT3_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_DXT3_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_DXT5_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_DXT5_SRGB_BLOCK16,\n\t\tFORMAT_R_ATI1N_UNORM_BLOCK8,\n\t\tFORMAT_R_ATI1N_SNORM_BLOCK8,\n\t\tFORMAT_RG_ATI2N_UNORM_BLOCK16,\n\t\tFORMAT_RG_ATI2N_SNORM_BLOCK16,\n\t\tFORMAT_RGB_BP_UFLOAT_BLOCK16,\n\t\tFORMAT_RGB_BP_SFLOAT_BLOCK16,\n\t\tFORMAT_RGBA_BP_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_BP_SRGB_BLOCK16,\n\n\t\tFORMAT_RGB_ETC2_UNORM_BLOCK8,\n\t\tFORMAT_RGB_ETC2_SRGB_BLOCK8,\n\t\tFORMAT_RGBA_ETC2_UNORM_BLOCK8,\n\t\tFORMAT_RGBA_ETC2_SRGB_BLOCK8,\n\t\tFORMAT_RGBA_ETC2_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ETC2_SRGB_BLOCK16,\n\t\tFORMAT_R_EAC_UNORM_BLOCK8,\n\t\tFORMAT_R_EAC_SNORM_BLOCK8,\n\t\tFORMAT_RG_EAC_UNORM_BLOCK16,\n\t\tFORMAT_RG_EAC_SNORM_BLOCK16,\n\n\t\tFORMAT_RGBA_ASTC_4X4_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_4X4_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_5X4_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_5X4_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_5X5_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_5X5_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_6X5_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_6X5_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_6X6_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_6X6_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_8X5_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_8X5_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_8X6_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_8X6_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_8X8_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_8X8_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X5_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X5_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X6_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X6_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X8_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X8_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X10_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_10X10_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_12X10_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_12X10_SRGB_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_12X12_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ASTC_12X12_SRGB_BLOCK16,\n\n\t\tFORMAT_RGB_PVRTC1_8X8_UNORM_BLOCK32,\n\t\tFORMAT_RGB_PVRTC1_8X8_SRGB_BLOCK32,\n\t\tFORMAT_RGB_PVRTC1_16X8_UNORM_BLOCK32,\n\t\tFORMAT_RGB_PVRTC1_16X8_SRGB_BLOCK32,\n\t\tFORMAT_RGBA_PVRTC1_8X8_UNORM_BLOCK32,\n\t\tFORMAT_RGBA_PVRTC1_8X8_SRGB_BLOCK32,\n\t\tFORMAT_RGBA_PVRTC1_16X8_UNORM_BLOCK32,\n\t\tFORMAT_RGBA_PVRTC1_16X8_SRGB_BLOCK32,\n\t\tFORMAT_RGBA_PVRTC2_4X4_UNORM_BLOCK8,\n\t\tFORMAT_RGBA_PVRTC2_4X4_SRGB_BLOCK8,\n\t\tFORMAT_RGBA_PVRTC2_8X4_UNORM_BLOCK8,\n\t\tFORMAT_RGBA_PVRTC2_8X4_SRGB_BLOCK8,\n\n\t\tFORMAT_RGB_ETC_UNORM_BLOCK8,\n\t\tFORMAT_RGB_ATC_UNORM_BLOCK8,\n\t\tFORMAT_RGBA_ATCA_UNORM_BLOCK16,\n\t\tFORMAT_RGBA_ATCI_UNORM_BLOCK16,\n\n\t\tFORMAT_L8_UNORM_PACK8,\n\t\tFORMAT_A8_UNORM_PACK8,\n\t\tFORMAT_LA8_UNORM_PACK8,\n\t\tFORMAT_L16_UNORM_PACK16,\n\t\tFORMAT_A16_UNORM_PACK16,\n\t\tFORMAT_LA16_UNORM_PACK16,\n\n\t\tFORMAT_BGR8_UNORM_PACK32,\n\t\tFORMAT_BGR8_SRGB_PACK32,\n\n\t\tFORMAT_RG3B2_UNORM_PACK8, FORMAT_LAST = FORMAT_RG3B2_UNORM_PACK8\n\t};\n\n\t/// Represent the source of a channel\n\tenum swizzle\n\t{\n\t\tSWIZZLE_RED, SWIZZLE_FIRST = SWIZZLE_RED, SWIZZLE_CHANNEL_FIRST = SWIZZLE_RED,\n\t\tSWIZZLE_GREEN,\n\t\tSWIZZLE_BLUE,\n\t\tSWIZZLE_ALPHA, SWIZZLE_CHANNEL_LAST = SWIZZLE_ALPHA,\n\t\tSWIZZLE_ZERO,\n\t\tSWIZZLE_ONE, SWIZZLE_LAST = SWIZZLE_ONE\n\t};\n\n\t/// Determine whether the Swizzle value represent a channel\n\tinline bool is_channel(swizzle Swizzle)\n\t{\n\t\treturn Swizzle >= SWIZZLE_CHANNEL_FIRST && Swizzle <= SWIZZLE_CHANNEL_LAST;\n\t}\n\n\tenum\n\t{\n\t\tFORMAT_COUNT = FORMAT_LAST - FORMAT_FIRST + 1,\n\t\tSWIZZLE_COUNT = SWIZZLE_LAST - SWIZZLE_FIRST + 1\n\t};\n\n\t/// Evaluate whether a format value is value or not\n\tinline bool is_valid(format Format)\n\t{\n\t\treturn Format >= FORMAT_FIRST && Format <= FORMAT_LAST;\n\t}\n\n\ttypedef glm::vec<4, swizzle> swizzles;\n\n\t/// Evaluate whether a format is compressed\n\tbool is_compressed(format Format);\n\n\t/// Evaluate whether a format is compressed with an S3TC algorithm.\n\tbool is_s3tc_compressed(format Format);\n\n\t/// Evaluate whether a format stores sRGB color space values\n\tbool is_srgb(format Format);\n\n\t/// Return the size in bytes of a block for a format.\n\tsize_t block_size(format Format);\n\n\t/// Return the dimensions in texels of the block for a format\n\tivec3 block_extent(format Format);\n\n\t/// Return the number of components of a format\n\tsize_t component_count(format Format);\n\n\t/// Evaluate whether a format is unsigned\n\tbool is_unsigned(format Format);\n\n\t/// Evaluate whether a format is signed\n\tbool is_signed(format Format);\n\n\t/// Evaluate whether the format is an integer format\n\tbool is_integer(format Format);\n\n\t/// Evaluate whether the format is a signed integer format\n\tbool is_signed_integer(format Format);\n\n\t/// Evaluate whether the format is an unsigned integer format\n\tbool is_unsigned_integer(format Format);\n\n\t/// Evaluate whether the format is an float format\n\tbool is_float(format Format);\n\n\t/// Evaluate whether the format is normalized\n\tbool is_normalized(format Format);\n\n\t/// Evaluate whether the format is an unsigned normalized format\n\tbool is_unorm(format Format);\n\n\t/// Evaluate whether the format is a signed normalized format\n\tbool is_snorm(format Format);\n\n\t/// Evaluate whether the format is packed\n\tbool is_packed(format Format);\n\n\t/// Evaluate whether the format is a depth format\n\tbool is_depth(format Format);\n\n\t/// Evaluate whether the format has a stencil component\n\tbool is_stencil(format Format);\n\n\t/// Evaluate whether the format has depth and stencil components\n\tbool is_depth_stencil(format Format);\n\n}//namespace gli\n\n#include \"./core/format.inl\"\n"
  },
  {
    "path": "lib/gli/generate_mipmaps.hpp",
    "content": "/// @brief Include to generate mipmaps of textures.\n/// @file gli/generate_mipmaps.hpp\n\n#pragma once\n\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n#include \"sampler.hpp\"\n\nnamespace gli\n{\n\t/// Allocate a texture and generate all the mipmaps of the texture using the Minification filter.\n\ttemplate <typename texture_type>\n\ttexture_type generate_mipmaps(texture_type const& Texture, filter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLevel to the MaxLevel included using the Minification filter.\n\ttexture1d generate_mipmaps(\n\t\ttexture1d const& Texture,\n\t\ttexture1d::size_type BaseLevel, texture1d::size_type MaxLevel,\n\t\tfilter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLayer to the MaxLayer and from the BaseLevel to the MaxLevel included levels using the Minification filter.\n\ttexture1d_array generate_mipmaps(\n\t\ttexture1d_array const& Texture,\n\t\ttexture1d_array::size_type BaseLayer, texture1d_array::size_type MaxLayer,\n\t\ttexture1d_array::size_type BaseLevel, texture1d_array::size_type MaxLevel,\n\t\tfilter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLevel to the MaxLevel included using the Minification filter.\n\ttexture2d generate_mipmaps(\n\t\ttexture2d const& Texture,\n\t\ttexture2d::size_type BaseLevel, texture2d::size_type MaxLevel,\n\t\tfilter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLayer to the MaxLayer and from the BaseLevel to the MaxLevel included levels using the Minification filter.\n\ttexture2d_array generate_mipmaps(\n\t\ttexture2d_array const& Texture,\n\t\ttexture2d_array::size_type BaseLayer, texture2d_array::size_type MaxLayer,\n\t\ttexture2d_array::size_type BaseLevel, texture2d_array::size_type MaxLevel,\n\t\tfilter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLevel to the MaxLevel included using the Minification filter.\n\ttexture3d generate_mipmaps(\n\t\ttexture3d const& Texture,\n\t\ttexture3d::size_type BaseLevel, texture3d::size_type MaxLevel,\n\t\tfilter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLayer to the MaxLayer, from the BaseFace to the MaxFace and from the BaseLevel to the MaxLevel included levels using the Minification filter.\n\ttexture_cube generate_mipmaps(\n\t\ttexture_cube const& Texture,\n\t\ttexture_cube::size_type BaseFace, texture_cube::size_type MaxFace,\n\t\ttexture_cube::size_type BaseLevel, texture_cube::size_type MaxLevel,\n\t\tfilter Minification);\n\n\t/// Allocate a texture and generate the mipmaps of the texture from the BaseLayer to the MaxLayer and from the BaseLevel to the MaxLevel included levels using the Minification filter.\n\ttexture_cube_array generate_mipmaps(\n\t\ttexture_cube_array const& Texture,\n\t\ttexture_cube_array::size_type BaseLayer, texture_cube_array::size_type MaxLayer,\n\t\ttexture_cube_array::size_type BaseFace, texture_cube_array::size_type MaxFace,\n\t\ttexture_cube_array::size_type BaseLevel, texture_cube_array::size_type MaxLevel,\n\t\tfilter Minification);\n}//namespace gli\n\n#include \"./core/generate_mipmaps.inl\"\n"
  },
  {
    "path": "lib/gli/gl.hpp",
    "content": "/// @brief Include to translate GLI enums to OpenGL enums\n/// @file gli/gl.hpp\n\n#pragma once\n\n#include \"format.hpp\"\n#include \"target.hpp\"\n#include <array>\n\nnamespace gli\n{\n\t/// Translation class to convert GLI enums into OpenGL values\n\tclass gl\n\t{\n\tpublic:\n\t\tenum internal_format\n\t\t{\n\t\t\tINTERNAL_RGB_UNORM= 0x1907,\t\t\t//GL_RGB\n\t\t\tINTERNAL_BGR_UNORM = 0x80E0,\t\t//GL_BGR\n\t\t\tINTERNAL_RGBA_UNORM = 0x1908,\t\t//GL_RGBA\n\t\t\tINTERNAL_BGRA_UNORM = 0x80E1,\t\t//GL_BGRA\n\t\t\tINTERNAL_BGRA8_UNORM = 0x93A1,\t\t//GL_BGRA8_EXT\n\n\t\t\t// unorm formats\n\t\t\tINTERNAL_R8_UNORM = 0x8229,\t\t\t//GL_R8\n\t\t\tINTERNAL_RG8_UNORM = 0x822B,\t\t//GL_RG8\n\t\t\tINTERNAL_RGB8_UNORM = 0x8051,\t\t//GL_RGB8\n\t\t\tINTERNAL_RGBA8_UNORM = 0x8058,\t\t//GL_RGBA8\n\n\t\t\tINTERNAL_R16_UNORM = 0x822A,\t\t//GL_R16\n\t\t\tINTERNAL_RG16_UNORM = 0x822C,\t\t//GL_RG16\n\t\t\tINTERNAL_RGB16_UNORM = 0x8054,\t\t//GL_RGB16\n\t\t\tINTERNAL_RGBA16_UNORM = 0x805B,\t\t//GL_RGBA16\n\n\t\t\tINTERNAL_RGB10A2_UNORM = 0x8059,\t//GL_RGB10_A2\n\t\t\tINTERNAL_RGB10A2_SNORM_EXT = 0xFFFC,\n\n\t\t\t// snorm formats\n\t\t\tINTERNAL_R8_SNORM = 0x8F94,\t\t\t//GL_R8_SNORM\n\t\t\tINTERNAL_RG8_SNORM = 0x8F95,\t\t//GL_RG8_SNORM\n\t\t\tINTERNAL_RGB8_SNORM = 0x8F96,\t\t//GL_RGB8_SNORM\n\t\t\tINTERNAL_RGBA8_SNORM = 0x8F97,\t\t//GL_RGBA8_SNORM\n\n\t\t\tINTERNAL_R16_SNORM = 0x8F98,\t\t//GL_R16_SNORM\n\t\t\tINTERNAL_RG16_SNORM= 0x8F99,\t\t//GL_RG16_SNORM\n\t\t\tINTERNAL_RGB16_SNORM= 0x8F9A,\t\t//GL_RGB16_SNORM\n\t\t\tINTERNAL_RGBA16_SNORM = 0x8F9B,\t\t//GL_RGBA16_SNORM\n\n\t\t\t// unsigned integer formats\n\t\t\tINTERNAL_R8U = 0x8232,\t\t\t\t//GL_R8UI\n\t\t\tINTERNAL_RG8U = 0x8238,\t\t\t\t//GL_RG8UI\n\t\t\tINTERNAL_RGB8U = 0x8D7D,\t\t\t//GL_RGB8UI\n\t\t\tINTERNAL_RGBA8U = 0x8D7C,\t\t\t//GL_RGBA8UI\n\n\t\t\tINTERNAL_R16U = 0x8234,\t\t\t\t//GL_R16UI\n\t\t\tINTERNAL_RG16U = 0x823A,\t\t\t//GL_RG16UI\n\t\t\tINTERNAL_RGB16U = 0x8D77,\t\t\t//GL_RGB16UI\n\t\t\tINTERNAL_RGBA16U = 0x8D76,\t\t\t//GL_RGBA16UI\n\n\t\t\tINTERNAL_R32U = 0x8236,\t\t\t\t//GL_R32UI\n\t\t\tINTERNAL_RG32U = 0x823C,\t\t\t//GL_RG32UI\n\t\t\tINTERNAL_RGB32U = 0x8D71,\t\t\t//GL_RGB32UI\n\t\t\tINTERNAL_RGBA32U = 0x8D70,\t\t\t//GL_RGBA32UI\n\n\t\t\tINTERNAL_RGB10A2U = 0x906F,\t\t\t//GL_RGB10_A2UI\n\t\t\tINTERNAL_RGB10A2I_EXT = 0xFFFB,\n\n\t\t\t// signed integer formats\n\t\t\tINTERNAL_R8I = 0x8231,\t\t\t\t//GL_R8I\n\t\t\tINTERNAL_RG8I = 0x8237,\t\t\t\t//GL_RG8I\n\t\t\tINTERNAL_RGB8I = 0x8D8F,\t\t\t//GL_RGB8I\n\t\t\tINTERNAL_RGBA8I = 0x8D8E,\t\t\t//GL_RGBA8I\n\n\t\t\tINTERNAL_R16I = 0x8233,\t\t\t\t//GL_R16I\n\t\t\tINTERNAL_RG16I = 0x8239,\t\t\t//GL_RG16I\n\t\t\tINTERNAL_RGB16I = 0x8D89,\t\t\t//GL_RGB16I\n\t\t\tINTERNAL_RGBA16I = 0x8D88,\t\t\t//GL_RGBA16I\n\n\t\t\tINTERNAL_R32I = 0x8235,\t\t\t\t//GL_R32I\n\t\t\tINTERNAL_RG32I = 0x823B,\t\t\t//GL_RG32I\n\t\t\tINTERNAL_RGB32I = 0x8D83,\t\t\t//GL_RGB32I\n\t\t\tINTERNAL_RGBA32I = 0x8D82,\t\t\t//GL_RGBA32I\n\n\t\t\t// Floating formats\n\t\t\tINTERNAL_R16F = 0x822D,\t\t\t\t//GL_R16F\n\t\t\tINTERNAL_RG16F = 0x822F,\t\t\t//GL_RG16F\n\t\t\tINTERNAL_RGB16F = 0x881B,\t\t\t//GL_RGB16F\n\t\t\tINTERNAL_RGBA16F = 0x881A,\t\t\t//GL_RGBA16F\n\n\t\t\tINTERNAL_R32F = 0x822E,\t\t\t\t//GL_R32F\n\t\t\tINTERNAL_RG32F = 0x8230,\t\t\t//GL_RG32F\n\t\t\tINTERNAL_RGB32F = 0x8815,\t\t\t//GL_RGB32F\n\t\t\tINTERNAL_RGBA32F = 0x8814,\t\t\t//GL_RGBA32F\n\n\t\t\tINTERNAL_R64F_EXT = 0xFFFA,\t\t\t//GL_R64F\n\t\t\tINTERNAL_RG64F_EXT = 0xFFF9,\t\t//GL_RG64F\n\t\t\tINTERNAL_RGB64F_EXT = 0xFFF8,\t\t//GL_RGB64F\n\t\t\tINTERNAL_RGBA64F_EXT = 0xFFF7,\t\t//GL_RGBA64F\n\n\t\t\t// sRGB formats\n\t\t\tINTERNAL_SR8 = 0x8FBD,\t\t\t\t//GL_SR8_EXT\n\t\t\tINTERNAL_SRG8 = 0x8FBE,\t\t\t\t//GL_SRG8_EXT\n\t\t\tINTERNAL_SRGB8 = 0x8C41,\t\t\t//GL_SRGB8\n\t\t\tINTERNAL_SRGB8_ALPHA8 = 0x8C43,\t\t//GL_SRGB8_ALPHA8\n\n\t\t\t// Packed formats\n\t\t\tINTERNAL_RGB9E5 = 0x8C3D,\t\t\t//GL_RGB9_E5\n\t\t\tINTERNAL_RG11B10F = 0x8C3A,\t\t\t//GL_R11F_G11F_B10F\n\t\t\tINTERNAL_RG3B2 = 0x2A10,\t\t\t//GL_R3_G3_B2\n\t\t\tINTERNAL_R5G6B5 = 0x8D62,\t\t\t//GL_RGB565\n\t\t\tINTERNAL_RGB5A1 = 0x8057,\t\t\t//GL_RGB5_A1\n\t\t\tINTERNAL_RGBA4 = 0x8056,\t\t\t//GL_RGBA4\n\n\t\t\tINTERNAL_RG4_EXT = 0xFFFE,\n\n\t\t\t// Luminance Alpha formats\n\t\t\tINTERNAL_LA4 = 0x8043,\t\t\t\t//GL_LUMINANCE4_ALPHA4\n\t\t\tINTERNAL_L8 = 0x8040,\t\t\t\t//GL_LUMINANCE8\n\t\t\tINTERNAL_A8 = 0x803C,\t\t\t\t//GL_ALPHA8\n\t\t\tINTERNAL_LA8 = 0x8045,\t\t\t\t//GL_LUMINANCE8_ALPHA8\n\t\t\tINTERNAL_L16 = 0x8042,\t\t\t\t//GL_LUMINANCE16\n\t\t\tINTERNAL_A16 = 0x803E,\t\t\t\t//GL_ALPHA16\n\t\t\tINTERNAL_LA16 = 0x8048,\t\t\t\t//GL_LUMINANCE16_ALPHA16\n\n\t\t\t// Depth formats\n\t\t\tINTERNAL_D16 = 0x81A5,\t\t\t\t//GL_DEPTH_COMPONENT16\n\t\t\tINTERNAL_D24 = 0x81A6,\t\t\t\t//GL_DEPTH_COMPONENT24\n\t\t\tINTERNAL_D16S8_EXT = 0xFFF6,\n\t\t\tINTERNAL_D24S8 = 0x88F0,\t\t\t//GL_DEPTH24_STENCIL8\n\t\t\tINTERNAL_D32 = 0x81A7,\t\t\t\t//GL_DEPTH_COMPONENT32\n\t\t\tINTERNAL_D32F = 0x8CAC,\t\t\t\t//GL_DEPTH_COMPONENT32F\n\t\t\tINTERNAL_D32FS8X24 = 0x8CAD,\t\t//GL_DEPTH32F_STENCIL8\n\t\t\tINTERNAL_S8_EXT = 0x8D48,\t\t\t//GL_STENCIL_INDEX8\n\n\t\t\t// Compressed formats\n\t\t\tINTERNAL_RGB_DXT1 = 0x83F0,\t\t\t\t\t\t//GL_COMPRESSED_RGB_S3TC_DXT1_EXT\n\t\t\tINTERNAL_RGBA_DXT1 = 0x83F1,\t\t\t\t\t//GL_COMPRESSED_RGBA_S3TC_DXT1_EXT\n\t\t\tINTERNAL_RGBA_DXT3 = 0x83F2,\t\t\t\t\t//GL_COMPRESSED_RGBA_S3TC_DXT3_EXT\n\t\t\tINTERNAL_RGBA_DXT5 = 0x83F3,\t\t\t\t\t//GL_COMPRESSED_RGBA_S3TC_DXT5_EXT\n\t\t\tINTERNAL_R_ATI1N_UNORM = 0x8DBB,\t\t\t\t//GL_COMPRESSED_RED_RGTC1\n\t\t\tINTERNAL_R_ATI1N_SNORM = 0x8DBC,\t\t\t\t//GL_COMPRESSED_SIGNED_RED_RGTC1\n\t\t\tINTERNAL_RG_ATI2N_UNORM = 0x8DBD,\t\t\t\t//GL_COMPRESSED_RG_RGTC2\n\t\t\tINTERNAL_RG_ATI2N_SNORM = 0x8DBE,\t\t\t\t//GL_COMPRESSED_SIGNED_RG_RGTC2\n\t\t\tINTERNAL_RGB_BP_UNSIGNED_FLOAT = 0x8E8F,\t\t//GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT\n\t\t\tINTERNAL_RGB_BP_SIGNED_FLOAT = 0x8E8E,\t\t\t//GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT\n\t\t\tINTERNAL_RGB_BP_UNORM = 0x8E8C,\t\t\t\t\t//GL_COMPRESSED_RGBA_BPTC_UNORM\n\t\t\tINTERNAL_RGB_PVRTC_4BPPV1 = 0x8C00,\t\t\t\t//GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG\n\t\t\tINTERNAL_RGB_PVRTC_2BPPV1 = 0x8C01,\t\t\t\t//GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG\n\t\t\tINTERNAL_RGBA_PVRTC_4BPPV1 = 0x8C02,\t\t\t//GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG\n\t\t\tINTERNAL_RGBA_PVRTC_2BPPV1 = 0x8C03,\t\t\t//GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG\n\t\t\tINTERNAL_RGBA_PVRTC_4BPPV2 = 0x9137,\t\t\t//GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG\n\t\t\tINTERNAL_RGBA_PVRTC_2BPPV2 = 0x9138,\t\t\t//GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG\n\t\t\tINTERNAL_ATC_RGB = 0x8C92,\t\t\t\t\t\t//GL_ATC_RGB_AMD\n\t\t\tINTERNAL_ATC_RGBA_EXPLICIT_ALPHA = 0x8C93,\t\t//GL_ATC_RGBA_EXPLICIT_ALPHA_AMD\n\t\t\tINTERNAL_ATC_RGBA_INTERPOLATED_ALPHA = 0x87EE,\t//GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD\n\n\t\t\tINTERNAL_RGB_ETC = 0x8D64,\t\t\t\t\t\t//GL_COMPRESSED_RGB8_ETC1\n\t\t\tINTERNAL_RGB_ETC2 = 0x9274,\t\t\t\t\t\t//GL_COMPRESSED_RGB8_ETC2\n\t\t\tINTERNAL_RGBA_PUNCHTHROUGH_ETC2 = 0x9276,\t\t//GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2\n\t\t\tINTERNAL_RGBA_ETC2 = 0x9278,\t\t\t\t\t//GL_COMPRESSED_RGBA8_ETC2_EAC\n\t\t\tINTERNAL_R11_EAC = 0x9270,\t\t\t\t\t\t//GL_COMPRESSED_R11_EAC\n\t\t\tINTERNAL_SIGNED_R11_EAC = 0x9271,\t\t\t\t//GL_COMPRESSED_SIGNED_R11_EAC\n\t\t\tINTERNAL_RG11_EAC = 0x9272,\t\t\t\t\t\t//GL_COMPRESSED_RG11_EAC\n\t\t\tINTERNAL_SIGNED_RG11_EAC = 0x9273,\t\t\t\t//GL_COMPRESSED_SIGNED_RG11_EAC\n\n\t\t\tINTERNAL_RGBA_ASTC_4x4 = 0x93B0,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_4x4_KHR\n\t\t\tINTERNAL_RGBA_ASTC_5x4 = 0x93B1,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_5x4_KHR\n\t\t\tINTERNAL_RGBA_ASTC_5x5 = 0x93B2,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_5x5_KHR\n\t\t\tINTERNAL_RGBA_ASTC_6x5 = 0x93B3,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_6x5_KHR\n\t\t\tINTERNAL_RGBA_ASTC_6x6 = 0x93B4,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_6x6_KHR\n\t\t\tINTERNAL_RGBA_ASTC_8x5 = 0x93B5,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_8x5_KHR\n\t\t\tINTERNAL_RGBA_ASTC_8x6 = 0x93B6,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_8x6_KHR\n\t\t\tINTERNAL_RGBA_ASTC_8x8 = 0x93B7,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_8x8_KHR\n\t\t\tINTERNAL_RGBA_ASTC_10x5 = 0x93B8,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_10x5_KHR\n\t\t\tINTERNAL_RGBA_ASTC_10x6 = 0x93B9,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_10x6_KHR\n\t\t\tINTERNAL_RGBA_ASTC_10x8 = 0x93BA,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_10x8_KHR\n\t\t\tINTERNAL_RGBA_ASTC_10x10 = 0x93BB,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_10x10_KHR\n\t\t\tINTERNAL_RGBA_ASTC_12x10 = 0x93BC,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_12x10_KHR\n\t\t\tINTERNAL_RGBA_ASTC_12x12 = 0x93BD,\t\t\t\t//GL_COMPRESSED_RGBA_ASTC_12x12_KHR\n\n\t\t\t// sRGB formats\n\t\t\tINTERNAL_SRGB_DXT1 = 0x8C4C,\t\t\t\t\t//GL_COMPRESSED_SRGB_S3TC_DXT1_EXT\n\t\t\tINTERNAL_SRGB_ALPHA_DXT1 = 0x8C4D,\t\t\t\t//GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT\n\t\t\tINTERNAL_SRGB_ALPHA_DXT3 = 0x8C4E,\t\t\t\t//GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT\n\t\t\tINTERNAL_SRGB_ALPHA_DXT5 = 0x8C4F,\t\t\t\t//GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT\n\t\t\tINTERNAL_SRGB_BP_UNORM = 0x8E8D,\t\t\t\t//GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM\n\t\t\tINTERNAL_SRGB_PVRTC_2BPPV1 = 0x8A54,\t\t\t//GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT\n\t\t\tINTERNAL_SRGB_PVRTC_4BPPV1 = 0x8A55,\t\t\t//GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT\n\t\t\tINTERNAL_SRGB_ALPHA_PVRTC_2BPPV1 = 0x8A56,\t\t//GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT\n\t\t\tINTERNAL_SRGB_ALPHA_PVRTC_4BPPV1 = 0x8A57,\t\t//GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT\n\t\t\tINTERNAL_SRGB_ALPHA_PVRTC_2BPPV2 = 0x93F0,\t\t//COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG\n\t\t\tINTERNAL_SRGB_ALPHA_PVRTC_4BPPV2 = 0x93F1,\t\t//GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG\n\t\t\tINTERNAL_SRGB8_ETC2 = 0x9275,\t\t\t\t\t\t//GL_COMPRESSED_SRGB8_ETC2\n\t\t\tINTERNAL_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,\t//GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2\n\t\t\tINTERNAL_SRGB8_ALPHA8_ETC2_EAC = 0x9279,\t\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_4x4 = 0x93D0,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_5x4 = 0x93D1,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_5x5 = 0x93D2,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_6x5 = 0x93D3,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_6x6 = 0x93D4,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_8x5 = 0x93D5,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_8x6 = 0x93D6,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_8x8 = 0x93D7,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_10x5 = 0x93D8,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_10x6 = 0x93D9,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_10x8 = 0x93DA,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_10x10 = 0x93DB,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_12x10 = 0x93DC,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR\n\t\t\tINTERNAL_SRGB8_ALPHA8_ASTC_12x12 = 0x93DD,\t\t//GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR\n\t\t\t\n\t\t\tINTERNAL_ALPHA8 = 0x803C,\n\t\t\tINTERNAL_ALPHA16 = 0x803E,\n\t\t\tINTERNAL_LUMINANCE8 = 0x8040,\n\t\t\tINTERNAL_LUMINANCE16 = 0x8042,\n\t\t\tINTERNAL_LUMINANCE8_ALPHA8 = 0x8045,\n\t\t\tINTERNAL_LUMINANCE16_ALPHA16 = 0x8048,\n\t\t\t\n\t\t\tINTERNAL_R8_USCALED_GTC = 0xF000,\n\t\t\tINTERNAL_R8_SSCALED_GTC,\n\t\t\tINTERNAL_RG8_USCALED_GTC,\n\t\t\tINTERNAL_RG8_SSCALED_GTC,\n\t\t\tINTERNAL_RGB8_USCALED_GTC,\n\t\t\tINTERNAL_RGB8_SSCALED_GTC,\n\t\t\tINTERNAL_RGBA8_USCALED_GTC,\n\t\t\tINTERNAL_RGBA8_SSCALED_GTC,\n\t\t\tINTERNAL_RGB10A2_USCALED_GTC,\n\t\t\tINTERNAL_RGB10A2_SSCALED_GTC,\n\t\t\tINTERNAL_R16_USCALED_GTC,\n\t\t\tINTERNAL_R16_SSCALED_GTC,\n\t\t\tINTERNAL_RG16_USCALED_GTC,\n\t\t\tINTERNAL_RG16_SSCALED_GTC,\n\t\t\tINTERNAL_RGB16_USCALED_GTC,\n\t\t\tINTERNAL_RGB16_SSCALED_GTC,\n\t\t\tINTERNAL_RGBA16_USCALED_GTC,\n\t\t\tINTERNAL_RGBA16_SSCALED_GTC,\n\t\t};\n\n\t\tenum external_format\n\t\t{\n\t\t\tEXTERNAL_NONE = 0,\t\t\t\t\t//GL_NONE\n\t\t\tEXTERNAL_RED = 0x1903,\t\t\t\t//GL_RED\n\t\t\tEXTERNAL_RG = 0x8227,\t\t\t\t//GL_RG\n\t\t\tEXTERNAL_RGB= 0x1907,\t\t\t\t//GL_RGB\n\t\t\tEXTERNAL_BGR = 0x80E0,\t\t\t\t//GL_BGR\n\t\t\tEXTERNAL_RGBA = 0x1908,\t\t\t\t//GL_RGBA\n\t\t\tEXTERNAL_BGRA = 0x80E1,\t\t\t\t//GL_BGRA\n\t\t\tEXTERNAL_RED_INTEGER = 0x8D94,\t\t//GL_RED_INTEGER\n\t\t\tEXTERNAL_RG_INTEGER = 0x8228,\t\t//GL_RG_INTEGER\n\t\t\tEXTERNAL_RGB_INTEGER = 0x8D98,\t\t//GL_RGB_INTEGER\n\t\t\tEXTERNAL_BGR_INTEGER = 0x8D9A,\t\t//GL_BGR_INTEGER\n\t\t\tEXTERNAL_RGBA_INTEGER = 0x8D99,\t\t//GL_RGBA_INTEGER\n\t\t\tEXTERNAL_BGRA_INTEGER = 0x8D9B,\t\t//GL_BGRA_INTEGER\n\t\t\tEXTERNAL_DEPTH = 0x1902,\t\t\t//GL_DEPTH_COMPONENT\n\t\t\tEXTERNAL_DEPTH_STENCIL = 0x84F9,\t//GL_DEPTH_STENCIL\n\t\t\tEXTERNAL_STENCIL = 0x1901,\t\t\t//GL_STENCIL_INDEX\n\n\t\t\tEXTERNAL_LUMINANCE = 0x1909,\t\t\t\t//GL_LUMINANCE\n\t\t\tEXTERNAL_ALPHA = 0x1906,\t\t\t\t\t//GL_ALPHA\n\t\t\tEXTERNAL_LUMINANCE_ALPHA = 0x190A,\t\t\t//GL_LUMINANCE_ALPHA\n\n\t\t\tEXTERNAL_SRGB_EXT = 0x8C40,\t\t\t\t\t//SRGB_EXT\n\t\t\tEXTERNAL_SRGB_ALPHA_EXT = 0x8C42\t\t\t//SRGB_ALPHA_EXT\n\t\t};\n\n\t\tenum type_format\n\t\t{\n\t\t\tTYPE_NONE = 0,\t\t\t\t\t\t//GL_NONE\n\t\t\tTYPE_I8 = 0x1400,\t\t\t\t\t//GL_BYTE\n\t\t\tTYPE_U8 = 0x1401,\t\t\t\t\t//GL_UNSIGNED_BYTE\n\t\t\tTYPE_I16 = 0x1402,\t\t\t\t\t//GL_SHORT\n\t\t\tTYPE_U16 = 0x1403,\t\t\t\t\t//GL_UNSIGNED_SHORT\n\t\t\tTYPE_I32 = 0x1404,\t\t\t\t\t//GL_INT\n\t\t\tTYPE_U32 = 0x1405,\t\t\t\t\t//GL_UNSIGNED_INT\n\t\t\tTYPE_I64 = 0x140E,\t\t\t\t\t//GL_INT64_ARB\n\t\t\tTYPE_U64 = 0x140F,\t\t\t\t\t//GL_UNSIGNED_INT64_ARB\n\t\t\tTYPE_F16 = 0x140B,\t\t\t\t\t//GL_HALF_FLOAT\n\t\t\tTYPE_F16_OES = 0x8D61,\t\t\t\t//GL_HALF_FLOAT_OES\n\t\t\tTYPE_F32 = 0x1406,\t\t\t\t\t//GL_FLOAT\n\t\t\tTYPE_F64 = 0x140A,\t\t\t\t\t//GL_DOUBLE\n\t\t\tTYPE_UINT32_RGB9_E5_REV = 0x8C3E,\t//GL_UNSIGNED_INT_5_9_9_9_REV\n\t\t\tTYPE_UINT32_RG11B10F_REV = 0x8C3B,\t//GL_UNSIGNED_INT_10F_11F_11F_REV\n\t\t\tTYPE_UINT8_RG3B2 = 0x8032,\t\t\t//GL_UNSIGNED_BYTE_3_3_2\n\t\t\tTYPE_UINT8_RG3B2_REV = 0x8362,\t\t//GL_UNSIGNED_BYTE_2_3_3_REV\n\t\t\tTYPE_UINT16_RGB5A1 = 0x8034,\t\t//GL_UNSIGNED_SHORT_5_5_5_1\n\t\t\tTYPE_UINT16_RGB5A1_REV = 0x8366,\t//GL_UNSIGNED_SHORT_1_5_5_5_REV\n\t\t\tTYPE_UINT16_R5G6B5 = 0x8363,\t\t//GL_UNSIGNED_SHORT_5_6_5\n\t\t\tTYPE_UINT16_R5G6B5_REV = 0x8364,\t//GL_UNSIGNED_SHORT_5_6_5_REV\n\t\t\tTYPE_UINT16_RGBA4 = 0x8033,\t\t\t//GL_UNSIGNED_SHORT_4_4_4_4\n\t\t\tTYPE_UINT16_RGBA4_REV = 0x8365,\t\t//GL_UNSIGNED_SHORT_4_4_4_4_REV\n\t\t\tTYPE_UINT32_RGBA8 = 0x8035,\t\t\t//GL_UNSIGNED_SHORT_8_8_8_8\n\t\t\tTYPE_UINT32_RGBA8_REV = 0x8367,\t\t//GL_UNSIGNED_SHORT_8_8_8_8_REV\n\t\t\tTYPE_UINT32_RGB10A2 = 0x8036,\t\t//GL_UNSIGNED_INT_10_10_10_2\n\t\t\tTYPE_UINT32_RGB10A2_REV = 0x8368,\t//GL_UNSIGNED_INT_2_10_10_10_REV\n\n\t\t\tTYPE_UINT8_RG4_REV_GTC = 0xFFFD,\n\t\t\tTYPE_UINT16_A1RGB5_GTC = 0xFFFC\n\t\t};\n\n\t\tenum target\n\t\t{\n\t\t\tTARGET_1D\t\t\t= 0x0DE0,\n\t\t\tTARGET_1D_ARRAY\t\t= 0x8C18,\n\t\t\tTARGET_2D\t\t\t= 0x0DE1,\n\t\t\tTARGET_2D_ARRAY\t\t= 0x8C1A,\n\t\t\tTARGET_3D\t\t\t= 0x806F,\n\t\t\tTARGET_RECT\t\t\t= 0x84F5,\n\t\t\tTARGET_RECT_ARRAY\t= 0x84F5, // Not supported by OpenGL\n\t\t\tTARGET_CUBE\t\t\t= 0x8513,\n\t\t\tTARGET_CUBE_ARRAY\t= 0x9009\n\t\t};\n\n\t\tenum swizzle\n\t\t{\n\t\t\tSWIZZLE_RED = 0x1903,\t\t//GL_RED\n\t\t\tSWIZZLE_GREEN = 0x1904,\t\t//GL_GREEN\n\t\t\tSWIZZLE_BLUE = 0x1905,\t\t//GL_BLUE\n\t\t\tSWIZZLE_ALPHA = 0x1906,\t\t//GL_ALPHA\n\t\t\tSWIZZLE_ZERO = 0x0000,\t\t//GL_ZERO\n\t\t\tSWIZZLE_ONE = 0x0001,\t\t//GL_ONE\n\t\t};\n\n\t\tenum profile\n\t\t{\n\t\t\tPROFILE_ES20,\n\t\t\tPROFILE_ES30,\n\t\t\tPROFILE_GL32,\n\t\t\tPROFILE_GL33,\n\t\t\tPROFILE_KTX\n\t\t};\n\n\t\ttypedef glm::vec<4, int> swizzles;\n\n\t\tstruct format\n\t\t{\n\t\t\tinternal_format Internal;\n\t\t\texternal_format External;\n\t\t\ttype_format Type;\n\t\t\tswizzles Swizzles;\n\t\t};\n\n\t\tgl(profile Profile);\n\n\t\t/// Convert GLI targets into OpenGL texture targets\n\t\ttarget const& translate(gli::target Target) const;\n\n\t\t/// Convert GLI formats into OpenGL texture formats\n\t\tformat translate(gli::format Format, gli::swizzles const& Swizzle) const;\n\n\t\t/// Convert an OpenGL format into a GLI format\n\t\tgli::format find(internal_format InternalFormat, external_format ExternalFormat, type_format Type);\n\n\tprivate:\n\t\tstruct format_desc\n\t\t{\n\t\t\tinternal_format Internal;\n\t\t\texternal_format External;\n\t\t\ttype_format Type;\n\t\t\tunsigned int Properties;\n\t\t};\n\n\t\tbool has_swizzle(profile Profile) const\n\t\t{\n\t\t\treturn Profile == PROFILE_ES30 || Profile == PROFILE_GL33;\n\t\t}\n\n\t\tgl::swizzles compute_swizzle(format_desc const& FormatDesc, gli::swizzles const& Swizzle) const;\n\n\t\tstd::array<format_desc, FORMAT_COUNT> FormatDesc;\n\t\tprofile Profile;\n\t};\n}//namespace gli\n\n#include \"./core/gl.inl\"\n"
  },
  {
    "path": "lib/gli/gli.hpp",
    "content": "/// @brief Include to include everything in GLI which is not recommendated due to compilation time cost.\n/// @file gli/gli.hpp\n/// @mainpage OpenGL Image (GLI)\n///\n/// [OpenGL Image](http://gli.g-truc.net/) (*GLI*) is a header only C++ image library for graphics software.\n/// (*GLI*) provides classes and functions to load image files ([KTX](https://www.khronos.org/opengles/sdk/tools/KTX/) and [DDS](https://msdn.microsoft.com/en-us/library/windows/desktop/bb943990%28v=vs.85%29.aspx)),\n/// facilitate graphics APIs texture creation, compare textures, access texture texels, sample textures, convert textures, generate mipmaps, etc.\n///\n/// This library works perfectly with [OpenGL](https://www.opengl.org) or [Vulkan](https://www.khronos.org/vulkan) but it also ensures interoperability with other third party libraries and SDK.\n/// It is a good candidate for software rendering (raytracing / rasterisation), image processing, image based software testing or any development context that requires a simple and convenient image library.\n///\n/// *GLI* is written in C++11. It is a platform independent library with no dependence and it supports the following compilers:\n/// - [Apple Clang 4.0](https://developer.apple.com/library/mac/documentation/CompilerTools/Conceptual/LLVMCompilerOverview/index.html) and higher\n/// - [GCC](http://gcc.gnu.org/) 4.6 and higher\n/// - [Intel C++ Composer](https://software.intel.com/en-us/intel-compilers) XE 2013 and higher\n/// - [LLVM](http://llvm.org/) 3.2 and higher\n/// - [Visual C++](http://www.visualstudio.com/) 2010 and higher\n/// - Any conform C++11 compiler\n///\n/// For more information about *GLI*, please have a look at the [API reference documentation](http://gli.g-truc.net/0.8.0/api/index.html).\n/// The source code and the documentation are licensed under the [Happy Bunny License (Modified MIT) or the MIT License](copying.md).\n///\n/// Thanks for contributing to the project by [submitting issues](https://github.com/g-truc/gli/issues) for bug reports and feature requests. Any feedback is welcome at [gli@g-truc.net](mailto://gli@g-truc.net).\n\n#pragma once\n\n#define GLI_VERSION\t\t\t\t\t84\n#define GLI_VERSION_MAJOR\t\t\t0\n#define GLI_VERSION_MINOR\t\t\t8\n#define GLI_VERSION_PATCH\t\t\t4\n#define GLI_VERSION_REVISION\t\t0\n\n/// Namespace where all the classes and functions provided by GLI are exposed\nnamespace gli\n{\n\n}//namespace gli\n\n#include \"format.hpp\"\n#include \"target.hpp\"\n#include \"levels.hpp\"\n\n#include \"image.hpp\"\n#include \"texture.hpp\"\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\n#include \"sampler1d.hpp\"\n#include \"sampler1d_array.hpp\"\n#include \"sampler2d.hpp\"\n#include \"sampler2d_array.hpp\"\n#include \"sampler3d.hpp\"\n#include \"sampler_cube.hpp\"\n#include \"sampler_cube_array.hpp\"\n\n#include \"duplicate.hpp\"\n#include \"convert.hpp\"\n#include \"view.hpp\"\n#include \"comparison.hpp\"\n\n#include \"reduce.hpp\"\n#include \"transform.hpp\"\n\n#include \"load.hpp\"\n#include \"save.hpp\"\n\n#include \"gl.hpp\"\n#include \"dx.hpp\"\n\n#include \"./core/flip.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/common.hpp",
    "content": "/// @ref core\n/// @file glm/common.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n///\n/// @defgroup core_func_common Common functions\n/// @ingroup core\n///\n/// Provides GLSL common functions\n///\n/// These all operate component-wise. The description is per component.\n///\n/// Include <glm/common.hpp> to use these core features.\n\n#pragma once\n\n#include \"detail/qualifier.hpp\"\n#include \"detail/_fixes.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_func_common\n\t/// @{\n\n\t/// Returns x if x >= 0; otherwise, it returns -x.\n\t///\n\t/// @tparam genType floating-point or signed integer; scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/abs.xml\">GLSL abs man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType abs(genType x);\n\n\t/// Returns x if x >= 0; otherwise, it returns -x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or signed integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/abs.xml\">GLSL abs man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> abs(vec<L, T, Q> const& x);\n\n\t/// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/sign.xml\">GLSL sign man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> sign(vec<L, T, Q> const& x);\n\n\t/// Returns a value equal to the nearest integer that is less then or equal to x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/floor.xml\">GLSL floor man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> floor(vec<L, T, Q> const& x);\n\n\t/// Returns a value equal to the nearest integer to x\n\t/// whose absolute value is not larger than the absolute value of x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/trunc.xml\">GLSL trunc man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> trunc(vec<L, T, Q> const& x);\n\n\t/// Returns a value equal to the nearest integer to x.\n\t/// The fraction 0.5 will round in a direction chosen by the\n\t/// implementation, presumably the direction that is fastest.\n\t/// This includes the possibility that round(x) returns the\n\t/// same value as roundEven(x) for all values of x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/round.xml\">GLSL round man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> round(vec<L, T, Q> const& x);\n\n\t/// Returns a value equal to the nearest integer to x.\n\t/// A fractional part of 0.5 will round toward the nearest even\n\t/// integer. (Both 3.5 and 4.5 for x will return 4.0.)\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/roundEven.xml\">GLSL roundEven man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\t/// @see <a href=\"http://developer.amd.com/documentation/articles/pages/New-Round-to-Even-Technique.aspx\">New round to even technique</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> roundEven(vec<L, T, Q> const& x);\n\n\t/// Returns a value equal to the nearest integer\n\t/// that is greater than or equal to x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/ceil.xml\">GLSL ceil man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> ceil(vec<L, T, Q> const& x);\n\n\t/// Return x - floor(x).\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/fract.xml\">GLSL fract man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fract(genType x);\n\n\t/// Return x - floor(x).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/fract.xml\">GLSL fract man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fract(vec<L, T, Q> const& x);\n\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType mod(genType x, genType y);\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mod(vec<L, T, Q> const& x, T y);\n\n\t/// Modulus. Returns x - y * floor(x / y)\n\t/// for each component in x using the floating point value y.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types, include glm/gtc/integer for integer scalar types support\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml\">GLSL mod man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mod(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the fractional part of x and sets i to the integer\n\t/// part (as a whole number floating point value). Both the\n\t/// return value and the output parameter will have the same\n\t/// sign as x.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/modf.xml\">GLSL modf man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType modf(genType x, genType& i);\n\n\t/// Returns y if y < x; otherwise, it returns x.\n\t///\n\t/// @tparam genType Floating-point or integer; scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/min.xml\">GLSL min man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType min(genType x, genType y);\n\n\t/// Returns y if y < x; otherwise, it returns x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/min.xml\">GLSL min man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& x, T y);\n\n\t/// Returns y if y < x; otherwise, it returns x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/min.xml\">GLSL min man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns y if x < y; otherwise, it returns x.\n\t///\n\t/// @tparam genType Floating-point or integer; scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/max.xml\">GLSL max man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType max(genType x, genType y);\n\n\t/// Returns y if x < y; otherwise, it returns x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/max.xml\">GLSL max man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& x, T y);\n\n\t/// Returns y if x < y; otherwise, it returns x.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/max.xml\">GLSL max man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns min(max(x, minVal), maxVal) for each component in x\n\t/// using the floating-point values minVal and maxVal.\n\t///\n\t/// @tparam genType Floating-point or integer; scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/clamp.xml\">GLSL clamp man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal);\n\n\t/// Returns min(max(x, minVal), maxVal) for each component in x\n\t/// using the floating-point values minVal and maxVal.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/clamp.xml\">GLSL clamp man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> clamp(vec<L, T, Q> const& x, T minVal, T maxVal);\n\n\t/// Returns min(max(x, minVal), maxVal) for each component in x\n\t/// using the floating-point values minVal and maxVal.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/clamp.xml\">GLSL clamp man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> clamp(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal);\n\n\t/// If genTypeU is a floating scalar or vector:\n\t/// Returns x * (1.0 - a) + y * a, i.e., the linear blend of\n\t/// x and y using the floating-point value a.\n\t/// The value for a is not restricted to the range [0, 1].\n\t///\n\t/// If genTypeU is a boolean scalar or vector:\n\t/// Selects which vector each returned component comes\n\t/// from. For a component of 'a' that is false, the\n\t/// corresponding component of 'x' is returned. For a\n\t/// component of 'a' that is true, the corresponding\n\t/// component of 'y' is returned. Components of 'x' and 'y' that\n\t/// are not selected are allowed to be invalid floating point\n\t/// values and will have no effect on the results. Thus, this\n\t/// provides different functionality than\n\t/// genType mix(genType x, genType y, genType(a))\n\t/// where a is a Boolean vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/mix.xml\">GLSL mix man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\t///\n\t/// @param[in]  x Value to interpolate.\n\t/// @param[in]  y Value to interpolate.\n\t/// @param[in]  a Interpolant.\n\t///\n\t/// @tparam\tgenTypeT Floating point scalar or vector.\n\t/// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT.\n\t///\n\t/// @code\n\t/// #include <glm/glm.hpp>\n\t/// ...\n\t/// float a;\n\t/// bool b;\n\t/// glm::dvec3 e;\n\t/// glm::dvec3 f;\n\t/// glm::vec4 g;\n\t/// glm::vec4 h;\n\t/// ...\n\t/// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors.\n\t/// glm::vec4 s = glm::mix(g, h, b); // Returns g or h;\n\t/// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second.\n\t/// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter.\n\t/// @endcode\n\ttemplate<typename genTypeT, typename genTypeU>\n\tGLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a);\n\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mix(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, U, Q> const& a);\n\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mix(vec<L, T, Q> const& x, vec<L, T, Q> const& y, U a);\n\n\t/// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/step.xml\">GLSL step man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType step(genType edge, genType x);\n\n\t/// Returns 0.0 if x < edge, otherwise it returns 1.0.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/step.xml\">GLSL step man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> step(T edge, vec<L, T, Q> const& x);\n\n\t/// Returns 0.0 if x < edge, otherwise it returns 1.0.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/step.xml\">GLSL step man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> step(vec<L, T, Q> const& edge, vec<L, T, Q> const& x);\n\n\t/// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and\n\t/// performs smooth Hermite interpolation between 0 and 1\n\t/// when edge0 < x < edge1. This is useful in cases where\n\t/// you would want a threshold function with a smooth\n\t/// transition. This is equivalent to:\n\t/// genType t;\n\t/// t = clamp ((x - edge0) / (edge1 - edge0), 0, 1);\n\t/// return t * t * (3 - 2 * t);\n\t/// Results are undefined if edge0 >= edge1.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/smoothstep.xml\">GLSL smoothstep man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType smoothstep(genType edge0, genType edge1, genType x);\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> smoothstep(T edge0, T edge1, vec<L, T, Q> const& x);\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> smoothstep(vec<L, T, Q> const& edge0, vec<L, T, Q> const& edge1, vec<L, T, Q> const& x);\n\n\t/// Returns true if x holds a NaN (not a number)\n\t/// representation in the underlying implementation's set of\n\t/// floating point representations. Returns false otherwise,\n\t/// including for implementations with no NaN\n\t/// representations.\n\t///\n\t/// /!\\ When using compiler fast math, this function may fail.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/isnan.xml\">GLSL isnan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> isnan(vec<L, T, Q> const& x);\n\n\t/// Returns true if x holds a positive infinity or negative\n\t/// infinity representation in the underlying implementation's\n\t/// set of floating point representations. Returns false\n\t/// otherwise, including for implementations with no infinity\n\t/// representations.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/isinf.xml\">GLSL isinf man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> isinf(vec<L, T, Q> const& x);\n\n\t/// Returns a signed integer value representing\n\t/// the encoding of a floating-point value. The floating-point\n\t/// value's bit-level representation is preserved.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToInt.xml\">GLSL floatBitsToInt man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\tGLM_FUNC_DECL int floatBitsToInt(float const& v);\n\n\t/// Returns a signed integer value representing\n\t/// the encoding of a floating-point value. The floatingpoint\n\t/// value's bit-level representation is preserved.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToInt.xml\">GLSL floatBitsToInt man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> floatBitsToInt(vec<L, float, Q> const& v);\n\n\t/// Returns a unsigned integer value representing\n\t/// the encoding of a floating-point value. The floatingpoint\n\t/// value's bit-level representation is preserved.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToUint.xml\">GLSL floatBitsToUint man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\tGLM_FUNC_DECL uint floatBitsToUint(float const& v);\n\n\t/// Returns a unsigned integer value representing\n\t/// the encoding of a floating-point value. The floatingpoint\n\t/// value's bit-level representation is preserved.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToUint.xml\">GLSL floatBitsToUint man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, uint, Q> floatBitsToUint(vec<L, float, Q> const& v);\n\n\t/// Returns a floating-point value corresponding to a signed\n\t/// integer encoding of a floating-point value.\n\t/// If an inf or NaN is passed in, it will not signal, and the\n\t/// resulting floating point value is unspecified. Otherwise,\n\t/// the bit-level representation is preserved.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/intBitsToFloat.xml\">GLSL intBitsToFloat man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\tGLM_FUNC_DECL float intBitsToFloat(int const& v);\n\n\t/// Returns a floating-point value corresponding to a signed\n\t/// integer encoding of a floating-point value.\n\t/// If an inf or NaN is passed in, it will not signal, and the\n\t/// resulting floating point value is unspecified. Otherwise,\n\t/// the bit-level representation is preserved.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/intBitsToFloat.xml\">GLSL intBitsToFloat man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, float, Q> intBitsToFloat(vec<L, int, Q> const& v);\n\n\t/// Returns a floating-point value corresponding to a\n\t/// unsigned integer encoding of a floating-point value.\n\t/// If an inf or NaN is passed in, it will not signal, and the\n\t/// resulting floating point value is unspecified. Otherwise,\n\t/// the bit-level representation is preserved.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/uintBitsToFloat.xml\">GLSL uintBitsToFloat man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\tGLM_FUNC_DECL float uintBitsToFloat(uint const& v);\n\n\t/// Returns a floating-point value corresponding to a\n\t/// unsigned integer encoding of a floating-point value.\n\t/// If an inf or NaN is passed in, it will not signal, and the\n\t/// resulting floating point value is unspecified. Otherwise,\n\t/// the bit-level representation is preserved.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/uintBitsToFloat.xml\">GLSL uintBitsToFloat man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, float, Q> uintBitsToFloat(vec<L, uint, Q> const& v);\n\n\t/// Computes and returns a * b + c.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/fma.xml\">GLSL fma man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fma(genType const& a, genType const& b, genType const& c);\n\n\t/// Splits x into a floating-point significand in the range\n\t/// [0.5, 1.0) and an integral exponent of two, such that:\n\t/// x = significand * exp(2, exponent)\n\t///\n\t/// The significand is returned by the function and the\n\t/// exponent is returned in the parameter exp. For a\n\t/// floating-point value of zero, the significant and exponent\n\t/// are both zero. For a floating-point value that is an\n\t/// infinity or is not a number, the results are undefined.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/frexp.xml\">GLSL frexp man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType frexp(genType x, int& exp);\n\t\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> frexp(vec<L, T, Q> const& v, vec<L, int, Q>& exp);\n\n\t/// Builds a floating-point number from x and the\n\t/// corresponding integral exponent of two in exp, returning:\n\t/// significand * exp(2, exponent)\n\t///\n\t/// If this product is too large to be represented in the\n\t/// floating-point type, the result is undefined.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/ldexp.xml\">GLSL ldexp man page</a>;\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType ldexp(genType const& x, int const& exp);\n\t\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> ldexp(vec<L, T, Q> const& v, vec<L, int, Q> const& exp);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_common.inl\"\n\n"
  },
  {
    "path": "lib/gli/glm/detail/_features.hpp",
    "content": "#pragma once\n\n// #define GLM_CXX98_EXCEPTIONS\n// #define GLM_CXX98_RTTI\n\n// #define GLM_CXX11_RVALUE_REFERENCES\n// Rvalue references - GCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html\n\n// GLM_CXX11_TRAILING_RETURN\n// Rvalue references for *this - GCC not supported\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm\n\n// GLM_CXX11_NONSTATIC_MEMBER_INIT\n// Initialization of class objects by rvalues - GCC any\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html\n\n// GLM_CXX11_NONSTATIC_MEMBER_INIT\n// Non-static data member initializers - GCC 4.7\n// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm\n\n// #define GLM_CXX11_VARIADIC_TEMPLATE\n// Variadic templates - GCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf\n\n//\n// Extending variadic template template parameters - GCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf\n\n// #define GLM_CXX11_GENERALIZED_INITIALIZERS\n// Initializer lists - GCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm\n\n// #define GLM_CXX11_STATIC_ASSERT\n// Static assertions - GCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html\n\n// #define GLM_CXX11_AUTO_TYPE\n// auto-typed variables - GCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf\n\n// #define GLM_CXX11_AUTO_TYPE\n// Multi-declarator auto - GCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf\n\n// #define GLM_CXX11_AUTO_TYPE\n// Removal of auto as a storage-class specifier - GCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm\n\n// #define GLM_CXX11_AUTO_TYPE\n// New function declarator syntax - GCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm\n\n// #define GLM_CXX11_LAMBDAS\n// New wording for C++0x lambdas - GCC 4.5\n// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf\n\n// #define GLM_CXX11_DECLTYPE\n// Declared type of an expression - GCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf\n\n//\n// Right angle brackets - GCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html\n\n//\n// Default template arguments for function templates\tDR226\tGCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226\n\n//\n// Solving the SFINAE problem for expressions\tDR339\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html\n\n// #define GLM_CXX11_ALIAS_TEMPLATE\n// Template aliases\tN2258\tGCC 4.7\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf\n\n//\n// Extern templates\tN1987\tYes\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm\n\n// #define GLM_CXX11_NULLPTR\n// Null pointer constant\tN2431\tGCC 4.6\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf\n\n// #define GLM_CXX11_STRONG_ENUMS\n// Strongly-typed enums\tN2347\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf\n\n//\n// Forward declarations for enums\tN2764\tGCC 4.6\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf\n\n//\n// Generalized attributes\tN2761\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf\n\n//\n// Generalized constant expressions\tN2235\tGCC 4.6\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf\n\n//\n// Alignment support\tN2341\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf\n\n// #define GLM_CXX11_DELEGATING_CONSTRUCTORS\n// Delegating constructors\tN1986\tGCC 4.7\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf\n\n//\n// Inheriting constructors\tN2540\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm\n\n// #define GLM_CXX11_EXPLICIT_CONVERSIONS\n// Explicit conversion operators\tN2437\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf\n\n//\n// New character types\tN2249\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html\n\n//\n// Unicode string literals\tN2442\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm\n\n//\n// Raw string literals\tN2442\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm\n\n//\n// Universal character name literals\tN2170\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html\n\n// #define GLM_CXX11_USER_LITERALS\n// User-defined literals\t\tN2765\tGCC 4.7\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf\n\n//\n// Standard Layout Types\tN2342\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm\n\n// #define GLM_CXX11_DEFAULTED_FUNCTIONS\n// #define GLM_CXX11_DELETED_FUNCTIONS\n// Defaulted and deleted functions\tN2346\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm\n\n//\n// Extended friend declarations\tN1791\tGCC 4.7\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf\n\n//\n// Extending sizeof\tN2253\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html\n\n// #define GLM_CXX11_INLINE_NAMESPACES\n// Inline namespaces\tN2535\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm\n\n// #define GLM_CXX11_UNRESTRICTED_UNIONS\n// Unrestricted unions\tN2544\tGCC 4.6\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf\n\n// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS\n// Local and unnamed types as template arguments\tN2657\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm\n\n// #define GLM_CXX11_RANGE_FOR\n// Range-based for\tN2930\tGCC 4.6\n// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html\n\n// #define GLM_CXX11_OVERRIDE_CONTROL\n// Explicit virtual overrides\tN2928 N3206 N3272\tGCC 4.7\n// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm\n\n//\n// Minimal support for garbage collection and reachability-based leak detection\tN2670\tNo\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm\n\n// #define GLM_CXX11_NOEXCEPT\n// Allowing move constructors to throw [noexcept]\tN3050\tGCC 4.6 (core language only)\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html\n\n//\n// Defining move special member functions\tN3053\tGCC 4.6\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html\n\n//\n// Sequence points\tN2239\tYes\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html\n\n//\n// Atomic operations\tN2427\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html\n\n//\n// Strong Compare and Exchange\tN2748\tGCC 4.5\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html\n\n//\n// Bidirectional Fences\tN2752\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm\n\n//\n// Memory model\tN2429\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm\n\n//\n// Data-dependency ordering: atomics and memory model\tN2664\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm\n\n//\n// Propagating exceptions\tN2179\tGCC 4.4\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html\n\n//\n// Abandoning a process and at_quick_exit\tN2440\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm\n\n//\n// Allow atomics use in signal handlers\tN2547\tYes\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm\n\n//\n// Thread-local storage\tN2659\tGCC 4.8\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm\n\n//\n// Dynamic initialization and destruction with concurrency\tN2660\tGCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm\n\n//\n// __func__ predefined identifier\tN2340\tGCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm\n\n//\n// C99 preprocessor\tN1653\tGCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm\n\n//\n// long long\tN1811\tGCC 4.3\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf\n\n//\n// Extended integral types\tN1988\tYes\n// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf\n\n#if(GLM_COMPILER & GLM_COMPILER_GCC)\n\n#\tdefine GLM_CXX11_STATIC_ASSERT\n\n#elif(GLM_COMPILER & GLM_COMPILER_CLANG)\n#\tif(__has_feature(cxx_exceptions))\n#\t\tdefine GLM_CXX98_EXCEPTIONS\n#\tendif\n\n#\tif(__has_feature(cxx_rtti))\n#\t\tdefine GLM_CXX98_RTTI\n#\tendif\n\n#\tif(__has_feature(cxx_access_control_sfinae))\n#\t\tdefine GLM_CXX11_ACCESS_CONTROL_SFINAE\n#\tendif\n\n#\tif(__has_feature(cxx_alias_templates))\n#\t\tdefine GLM_CXX11_ALIAS_TEMPLATE\n#\tendif\n\n#\tif(__has_feature(cxx_alignas))\n#\t\tdefine GLM_CXX11_ALIGNAS\n#\tendif\n\n#\tif(__has_feature(cxx_attributes))\n#\t\tdefine GLM_CXX11_ATTRIBUTES\n#\tendif\n\n#\tif(__has_feature(cxx_constexpr))\n#\t\tdefine GLM_CXX11_CONSTEXPR\n#\tendif\n\n#\tif(__has_feature(cxx_decltype))\n#\t\tdefine GLM_CXX11_DECLTYPE\n#\tendif\n\n#\tif(__has_feature(cxx_default_function_template_args))\n#\t\tdefine GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS\n#\tendif\n\n#\tif(__has_feature(cxx_defaulted_functions))\n#\t\tdefine GLM_CXX11_DEFAULTED_FUNCTIONS\n#\tendif\n\n#\tif(__has_feature(cxx_delegating_constructors))\n#\t\tdefine GLM_CXX11_DELEGATING_CONSTRUCTORS\n#\tendif\n\n#\tif(__has_feature(cxx_deleted_functions))\n#\t\tdefine GLM_CXX11_DELETED_FUNCTIONS\n#\tendif\n\n#\tif(__has_feature(cxx_explicit_conversions))\n#\t\tdefine GLM_CXX11_EXPLICIT_CONVERSIONS\n#\tendif\n\n#\tif(__has_feature(cxx_generalized_initializers))\n#\t\tdefine GLM_CXX11_GENERALIZED_INITIALIZERS\n#\tendif\n\n#\tif(__has_feature(cxx_implicit_moves))\n#\t\tdefine GLM_CXX11_IMPLICIT_MOVES\n#\tendif\n\n#\tif(__has_feature(cxx_inheriting_constructors))\n#\t\tdefine GLM_CXX11_INHERITING_CONSTRUCTORS\n#\tendif\n\n#\tif(__has_feature(cxx_inline_namespaces))\n#\t\tdefine GLM_CXX11_INLINE_NAMESPACES\n#\tendif\n\n#\tif(__has_feature(cxx_lambdas))\n#\t\tdefine GLM_CXX11_LAMBDAS\n#\tendif\n\n#\tif(__has_feature(cxx_local_type_template_args))\n#\t\tdefine GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS\n#\tendif\n\n#\tif(__has_feature(cxx_noexcept))\n#\t\tdefine GLM_CXX11_NOEXCEPT\n#\tendif\n\n#\tif(__has_feature(cxx_nonstatic_member_init))\n#\t\tdefine GLM_CXX11_NONSTATIC_MEMBER_INIT\n#\tendif\n\n#\tif(__has_feature(cxx_nullptr))\n#\t\tdefine GLM_CXX11_NULLPTR\n#\tendif\n\n#\tif(__has_feature(cxx_override_control))\n#\t\tdefine GLM_CXX11_OVERRIDE_CONTROL\n#\tendif\n\n#\tif(__has_feature(cxx_reference_qualified_functions))\n#\t\tdefine GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS\n#\tendif\n\n#\tif(__has_feature(cxx_range_for))\n#\t\tdefine GLM_CXX11_RANGE_FOR\n#\tendif\n\n#\tif(__has_feature(cxx_raw_string_literals))\n#\t\tdefine GLM_CXX11_RAW_STRING_LITERALS\n#\tendif\n\n#\tif(__has_feature(cxx_rvalue_references))\n#\t\tdefine GLM_CXX11_RVALUE_REFERENCES\n#\tendif\n\n#\tif(__has_feature(cxx_static_assert))\n#\t\tdefine GLM_CXX11_STATIC_ASSERT\n#\tendif\n\n#\tif(__has_feature(cxx_auto_type))\n#\t\tdefine GLM_CXX11_AUTO_TYPE\n#\tendif\n\n#\tif(__has_feature(cxx_strong_enums))\n#\t\tdefine GLM_CXX11_STRONG_ENUMS\n#\tendif\n\n#\tif(__has_feature(cxx_trailing_return))\n#\t\tdefine GLM_CXX11_TRAILING_RETURN\n#\tendif\n\n#\tif(__has_feature(cxx_unicode_literals))\n#\t\tdefine GLM_CXX11_UNICODE_LITERALS\n#\tendif\n\n#\tif(__has_feature(cxx_unrestricted_unions))\n#\t\tdefine GLM_CXX11_UNRESTRICTED_UNIONS\n#\tendif\n\n#\tif(__has_feature(cxx_user_literals))\n#\t\tdefine GLM_CXX11_USER_LITERALS\n#\tendif\n\n#\tif(__has_feature(cxx_variadic_templates))\n#\t\tdefine GLM_CXX11_VARIADIC_TEMPLATES\n#\tendif\n\n#endif//(GLM_COMPILER & GLM_COMPILER_CLANG)\n"
  },
  {
    "path": "lib/gli/glm/detail/_fixes.hpp",
    "content": "#include <cmath>\n\n//! Workaround for compatibility with other libraries\n#ifdef max\n#undef max\n#endif\n\n//! Workaround for compatibility with other libraries\n#ifdef min\n#undef min\n#endif\n\n//! Workaround for Android\n#ifdef isnan\n#undef isnan\n#endif\n\n//! Workaround for Android\n#ifdef isinf\n#undef isinf\n#endif\n\n//! Workaround for Chrone Native Client\n#ifdef log2\n#undef log2\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/_noise.hpp",
    "content": "#pragma once\n\n#include \"../common.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T mod289(T const& x)\n\t{\n\t\treturn x - floor(x * (static_cast<T>(1.0) / static_cast<T>(289.0))) * static_cast<T>(289.0);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T permute(T const& x)\n\t{\n\t\treturn mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> permute(vec<2, T, Q> const& x)\n\t{\n\t\treturn mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> permute(vec<3, T, Q> const& x)\n\t{\n\t\treturn mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> permute(vec<4, T, Q> const& x)\n\t{\n\t\treturn mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T taylorInvSqrt(T const& r)\n\t{\n\t\treturn static_cast<T>(1.79284291400159) - static_cast<T>(0.85373472095314) * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> taylorInvSqrt(vec<2, T, Q> const& r)\n\t{\n\t\treturn static_cast<T>(1.79284291400159) - static_cast<T>(0.85373472095314) * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> taylorInvSqrt(vec<3, T, Q> const& r)\n\t{\n\t\treturn static_cast<T>(1.79284291400159) - static_cast<T>(0.85373472095314) * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> taylorInvSqrt(vec<4, T, Q> const& r)\n\t{\n\t\treturn static_cast<T>(1.79284291400159) - static_cast<T>(0.85373472095314) * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> fade(vec<2, T, Q> const& t)\n\t{\n\t\treturn (t * t * t) * (t * (t * static_cast<T>(6) - static_cast<T>(15)) + static_cast<T>(10));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> fade(vec<3, T, Q> const& t)\n\t{\n\t\treturn (t * t * t) * (t * (t * static_cast<T>(6) - static_cast<T>(15)) + static_cast<T>(10));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> fade(vec<4, T, Q> const& t)\n\t{\n\t\treturn (t * t * t) * (t * (t * static_cast<T>(6) - static_cast<T>(15)) + static_cast<T>(10));\n\t}\n}//namespace detail\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/detail/_swizzle.hpp",
    "content": "#pragma once\n\nnamespace glm{\nnamespace detail\n{\n\t// Internal class for implementing swizzle operators\n\ttemplate<typename T, int N>\n\tstruct _swizzle_base0\n\t{\n\tprotected:\n\t\tGLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast<T*>(_buffer))[i]; }\n\t\tGLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast<const T*>(_buffer))[i]; }\n\n\t\t// Use an opaque buffer to *ensure* the compiler doesn't call a constructor.\n\t\t// The size 1 buffer is assumed to aligned to the actual members so that the\n\t\t// elem()\n\t\tchar    _buffer[1];\n\t};\n\n\ttemplate<int N, typename T, qualifier Q, int E0, int E1, int E2, int E3, bool Aligned>\n\tstruct _swizzle_base1 : public _swizzle_base0<T, N>\n\t{\n\t};\n\n\ttemplate<typename T, qualifier Q, int E0, int E1, bool Aligned>\n\tstruct _swizzle_base1<2, T, Q, E0,E1,-1,-2, Aligned> : public _swizzle_base0<T, 2>\n\t{\n\t\tGLM_FUNC_QUALIFIER vec<2, T, Q> operator ()()  const { return vec<2, T, Q>(this->elem(E0), this->elem(E1)); }\n\t};\n\n\ttemplate<typename T, qualifier Q, int E0, int E1, int E2, bool Aligned>\n\tstruct _swizzle_base1<3, T, Q, E0,E1,E2,-1, Aligned> : public _swizzle_base0<T, 3>\n\t{\n\t\tGLM_FUNC_QUALIFIER vec<3, T, Q> operator ()()  const { return vec<3, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2)); }\n\t};\n\n\ttemplate<typename T, qualifier Q, int E0, int E1, int E2, int E3, bool Aligned>\n\tstruct _swizzle_base1<4, T, Q, E0,E1,E2,E3, Aligned> : public _swizzle_base0<T, 4>\n\t{\n\t\tGLM_FUNC_QUALIFIER vec<4, T, Q> operator ()()  const { return vec<4, T, Q>(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); }\n\t};\n\n\t// Internal class for implementing swizzle operators\n\t/*\n\t\tTemplate parameters:\n\n\t\tT\t\t\t= type of scalar values (e.g. float, double)\n\t\tN\t\t\t= number of components in the vector (e.g. 3)\n\t\tE0...3\t\t= what index the n-th element of this swizzle refers to in the unswizzled vec\n\n\t\tDUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles\n\t\t\tcontaining duplicate elements so that they cannot be used as r-values).\n\t*/\n\ttemplate<int N, typename T, qualifier Q, int E0, int E1, int E2, int E3, int DUPLICATE_ELEMENTS>\n\tstruct _swizzle_base2 : public _swizzle_base1<N, T, Q, E0,E1,E2,E3, detail::is_aligned<Q>::value>\n\t{\n\t\tstruct op_equal\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e = t; }\n\t\t};\n\n\t\tstruct op_minus\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e -= t; }\n\t\t};\n\n\t\tstruct op_plus\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e += t; }\n\t\t};\n\n\t\tstruct op_mul\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e *= t; }\n\t\t};\n\n\t\tstruct op_div\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER void operator() (T& e, T& t) const{ e /= t; }\n\t\t};\n\n\tpublic:\n\t\tGLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t)\n\t\t{\n\t\t\tfor (int i = 0; i < N; ++i)\n\t\t\t\t(*this)[i] = t;\n\t\t\treturn *this;\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER _swizzle_base2& operator= (vec<N, T, Q> const& that)\n\t\t{\n\t\t\t_apply_op(that, op_equal());\n\t\t\treturn *this;\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER void operator -= (vec<N, T, Q> const& that)\n\t\t{\n\t\t\t_apply_op(that, op_minus());\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER void operator += (vec<N, T, Q> const& that)\n\t\t{\n\t\t\t_apply_op(that, op_plus());\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER void operator *= (vec<N, T, Q> const& that)\n\t\t{\n\t\t\t_apply_op(that, op_mul());\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER void operator /= (vec<N, T, Q> const& that)\n\t\t{\n\t\t\t_apply_op(that, op_div());\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER T& operator[](size_t i)\n\t\t{\n\t\t\tconst int offset_dst[4] = { E0, E1, E2, E3 };\n\t\t\treturn this->elem(offset_dst[i]);\n\t\t}\n\t\tGLM_FUNC_QUALIFIER T operator[](size_t i) const\n\t\t{\n\t\t\tconst int offset_dst[4] = { E0, E1, E2, E3 };\n\t\t\treturn this->elem(offset_dst[i]);\n\t\t}\n\n\tprotected:\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_QUALIFIER void _apply_op(vec<N, T, Q> const& that, const U& op)\n\t\t{\n\t\t\t// Make a copy of the data in this == &that.\n\t\t\t// The copier should optimize out the copy in cases where the function is\n\t\t\t// properly inlined and the copy is not necessary.\n\t\t\tT t[N];\n\t\t\tfor (int i = 0; i < N; ++i)\n\t\t\t\tt[i] = that[i];\n\t\t\tfor (int i = 0; i < N; ++i)\n\t\t\t\top( (*this)[i], t[i] );\n\t\t}\n\t};\n\n\t// Specialization for swizzles containing duplicate elements.  These cannot be modified.\n\ttemplate<int N, typename T, qualifier Q, int E0, int E1, int E2, int E3>\n\tstruct _swizzle_base2<N, T, Q, E0,E1,E2,E3, 1> : public _swizzle_base1<N, T, Q, E0,E1,E2,E3, detail::is_aligned<Q>::value>\n\t{\n\t\tstruct Stub {};\n\n\t\tGLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const&) { return *this; }\n\n\t\tGLM_FUNC_QUALIFIER T operator[]  (size_t i) const\n\t\t{\n\t\t\tconst int offset_dst[4] = { E0, E1, E2, E3 };\n\t\t\treturn this->elem(offset_dst[i]);\n\t\t}\n\t};\n\n\ttemplate<int N, typename T, qualifier Q, int E0, int E1, int E2, int E3>\n\tstruct _swizzle : public _swizzle_base2<N, T, Q, E0, E1, E2, E3, (E0 == E1 || E0 == E2 || E0 == E3 || E1 == E2 || E1 == E3 || E2 == E3)>\n\t{\n\t\ttypedef _swizzle_base2<N, T, Q, E0, E1, E2, E3, (E0 == E1 || E0 == E2 || E0 == E3 || E1 == E2 || E1 == E3 || E2 == E3)> base_type;\n\n\t\tusing base_type::operator=;\n\n\t\tGLM_FUNC_QUALIFIER operator vec<N, T, Q> () const { return (*this)(); }\n\t};\n\n//\n// To prevent the C++ syntax from getting entirely overwhelming, define some alias macros\n//\n#define GLM_SWIZZLE_TEMPLATE1   template<int N, typename T, qualifier Q, int E0, int E1, int E2, int E3>\n#define GLM_SWIZZLE_TEMPLATE2   template<int N, typename T, qualifier Q, int E0, int E1, int E2, int E3, int F0, int F1, int F2, int F3>\n#define GLM_SWIZZLE_TYPE1       _swizzle<N, T, Q, E0, E1, E2, E3>\n#define GLM_SWIZZLE_TYPE2       _swizzle<N, T, Q, F0, F1, F2, F3>\n\n//\n// Wrapper for a binary operator (e.g. u.yy + v.zy)\n//\n#define GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND)                 \\\n\tGLM_SWIZZLE_TEMPLATE2                                                          \\\n\tGLM_FUNC_QUALIFIER vec<N, T, Q> operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b)  \\\n\t{                                                                               \\\n\t\treturn a() OPERAND b();                                                     \\\n\t}                                                                               \\\n\tGLM_SWIZZLE_TEMPLATE1                                                          \\\n\tGLM_FUNC_QUALIFIER vec<N, T, Q> operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const vec<N, T, Q>& b)                   \\\n\t{                                                                               \\\n\t\treturn a() OPERAND b;                                                       \\\n\t}                                                                               \\\n\tGLM_SWIZZLE_TEMPLATE1                                                          \\\n\tGLM_FUNC_QUALIFIER vec<N, T, Q> operator OPERAND ( const vec<N, T, Q>& a, const GLM_SWIZZLE_TYPE1& b)                   \\\n\t{                                                                               \\\n\t\treturn a OPERAND b();                                                       \\\n\t}\n\n//\n// Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz)\n//\n#define GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND)\t\t\t\t\t\t\t\t\\\n\tGLM_SWIZZLE_TEMPLATE1\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tGLM_FUNC_QUALIFIER vec<N, T, Q> operator OPERAND ( const GLM_SWIZZLE_TYPE1& a, const T& b)\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn a() OPERAND b;\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tGLM_SWIZZLE_TEMPLATE1\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tGLM_FUNC_QUALIFIER vec<N, T, Q> operator OPERAND ( const T& a, const GLM_SWIZZLE_TYPE1& b)\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn a OPERAND b();\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\n\n//\n// Macro for wrapping a function taking one argument (e.g. abs())\n//\n#define GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION)\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tGLM_SWIZZLE_TEMPLATE1\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a)\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn FUNCTION(a());\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t}\n\n//\n// Macro for wrapping a function taking two vector arguments (e.g. dot()).\n//\n#define GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION)                                                       \\\n\tGLM_SWIZZLE_TEMPLATE2                                                                                       \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b) \\\n\t{                                                                                                           \\\n\t\treturn FUNCTION(a(), b());                                                                              \\\n\t}                                                                                                           \\\n\tGLM_SWIZZLE_TEMPLATE1                                                                                       \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b) \\\n\t{                                                                                                           \\\n\t\treturn FUNCTION(a(), b());                                                                              \\\n\t}                                                                                                           \\\n\tGLM_SWIZZLE_TEMPLATE1                                                                                       \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename V& b)         \\\n\t{                                                                                                           \\\n\t\treturn FUNCTION(a(), b);                                                                                \\\n\t}                                                                                                           \\\n\tGLM_SWIZZLE_TEMPLATE1                                                                                       \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const GLM_SWIZZLE_TYPE1& b)                  \\\n\t{                                                                                                           \\\n\t\treturn FUNCTION(a, b());                                                                                \\\n\t}\n\n//\n// Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()).\n//\n#define GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION)                                                             \\\n\tGLM_SWIZZLE_TEMPLATE2                                                                                                    \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE2& b, const T& c)   \\\n\t{                                                                                                                         \\\n\t\treturn FUNCTION(a(), b(), c);                                                                                         \\\n\t}                                                                                                                         \\\n\tGLM_SWIZZLE_TEMPLATE1                                                                                                    \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const GLM_SWIZZLE_TYPE1& b, const T& c)   \\\n\t{                                                                                                                         \\\n\t\treturn FUNCTION(a(), b(), c);                                                                                         \\\n\t}                                                                                                                         \\\n\tGLM_SWIZZLE_TEMPLATE1                                                                                                    \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\\\n\t{                                                                                                                         \\\n\t\treturn FUNCTION(a(), b, c);                                                                                           \\\n\t}                                                                                                                         \\\n\tGLM_SWIZZLE_TEMPLATE1                                                                                                    \\\n\tGLM_FUNC_QUALIFIER typename GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const GLM_SWIZZLE_TYPE1& b, const T& c)           \\\n\t{                                                                                                                         \\\n\t\treturn FUNCTION(a, b(), c);                                                                                           \\\n\t}\n\n}//namespace detail\n}//namespace glm\n\nnamespace glm\n{\n\tnamespace detail\n\t{\n\t\tGLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-)\n\t\tGLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*)\n\t\tGLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+)\n\t\tGLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-)\n\t\tGLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*)\n\t\tGLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/)\n\t}\n\n\t//\n\t// Swizzles are distinct types from the unswizzled type.  The below macros will\n\t// provide template specializations for the swizzle types for the given functions\n\t// so that the compiler does not have any ambiguity to choosing how to handle\n\t// the function.\n\t//\n\t// The alternative is to use the operator()() when calling the function in order\n\t// to explicitly convert the swizzled type to the unswizzled type.\n\t//\n\n\t//GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    abs);\n\t//GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    acos);\n\t//GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    acosh);\n\t//GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    all);\n\t//GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    any);\n\n\t//GLM_SWIZZLE_FUNCTION_2_ARGS(value_type,  dot);\n\t//GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type,    cross);\n\t//GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type,    step);\n\t//GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix);\n}\n\n#define GLM_SWIZZLE2_2_MEMBERS(T, Q, E0,E1) \\\n\tstruct { detail::_swizzle<2, T, Q, 0,0,-1,-2> E0 ## E0; }; \\\n\tstruct { detail::_swizzle<2, T, Q, 0,1,-1,-2> E0 ## E1; }; \\\n\tstruct { detail::_swizzle<2, T, Q, 1,0,-1,-2> E1 ## E0; }; \\\n\tstruct { detail::_swizzle<2, T, Q, 1,1,-1,-2> E1 ## E1; };\n\n#define GLM_SWIZZLE2_3_MEMBERS(T, Q, E0,E1) \\\n\tstruct { detail::_swizzle<3,T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3,T, Q, 1,1,1,-1> E1 ## E1 ## E1; };\n\n#define GLM_SWIZZLE2_4_MEMBERS(T, Q, E0,E1) \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; };\n\n#define GLM_SWIZZLE3_2_MEMBERS(T, Q, E0,E1,E2) \\\n\tstruct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; };\n\n#define GLM_SWIZZLE3_3_MEMBERS(T, Q ,E0,E1,E2) \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; };\n\n#define GLM_SWIZZLE3_4_MEMBERS(T, Q, E0,E1,E2) \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4,T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; };\n\n#define GLM_SWIZZLE4_2_MEMBERS(T, Q, E0,E1,E2,E3) \\\n\tstruct { detail::_swizzle<2,T, Q, 0,0,-1,-2> E0 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 0,1,-1,-2> E0 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 0,2,-1,-2> E0 ## E2; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 0,3,-1,-2> E0 ## E3; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,0,-1,-2> E1 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,1,-1,-2> E1 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,2,-1,-2> E1 ## E2; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 1,3,-1,-2> E1 ## E3; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,0,-1,-2> E2 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,1,-1,-2> E2 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,2,-1,-2> E2 ## E2; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 2,3,-1,-2> E2 ## E3; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 3,0,-1,-2> E3 ## E0; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 3,1,-1,-2> E3 ## E1; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 3,2,-1,-2> E3 ## E2; }; \\\n\tstruct { detail::_swizzle<2,T, Q, 3,3,-1,-2> E3 ## E3; };\n\n#define GLM_SWIZZLE4_3_MEMBERS(T, Q, E0,E1,E2,E3) \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,0,-1> E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,1,-1> E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,2,-1> E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,0,3,-1> E0 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,0,-1> E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,1,-1> E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,2,-1> E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,1,3,-1> E0 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,0,-1> E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,1,-1> E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,2,-1> E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,2,3,-1> E0 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,3,0,-1> E0 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,3,1,-1> E0 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,3,2,-1> E0 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 0,3,3,-1> E0 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,0,-1> E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,1,-1> E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,2,-1> E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,0,3,-1> E1 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,0,-1> E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,1,-1> E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,2,-1> E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,1,3,-1> E1 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,0,-1> E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,1,-1> E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,2,-1> E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,2,3,-1> E1 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,3,0,-1> E1 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,3,1,-1> E1 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,3,2,-1> E1 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 1,3,3,-1> E1 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,0,-1> E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,1,-1> E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,2,-1> E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,0,3,-1> E2 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,0,-1> E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,1,-1> E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,2,-1> E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,1,3,-1> E2 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,0,-1> E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,1,-1> E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,2,-1> E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,2,3,-1> E2 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,3,0,-1> E2 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,3,1,-1> E2 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,3,2,-1> E2 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 2,3,3,-1> E2 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,0,0,-1> E3 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,0,1,-1> E3 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,0,2,-1> E3 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,0,3,-1> E3 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,1,0,-1> E3 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,1,1,-1> E3 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,1,2,-1> E3 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,1,3,-1> E3 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,2,0,-1> E3 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,2,1,-1> E3 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,2,2,-1> E3 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,2,3,-1> E3 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,3,0,-1> E3 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,3,1,-1> E3 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,3,2,-1> E3 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<3, T, Q, 3,3,3,-1> E3 ## E3 ## E3; };\n\n#define GLM_SWIZZLE4_4_MEMBERS(T, Q, E0,E1,E2,E3) \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \\\n\tstruct { detail::_swizzle<4, T, Q, 3,3,3,3> E3 ## E3 ## E3 ## E3; };\n"
  },
  {
    "path": "lib/gli/glm/detail/_swizzle_func.hpp",
    "content": "#pragma once\n\n#define GLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, CONST, A, B)\t\\\n\tvec<2, T, Q> A ## B() CONST\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn vec<2, T, Q>(this->A, this->B);\t\t\t\\\n\t}\n\n#define GLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, CONST, A, B, C)\t\t\\\n\tvec<3, T, Q> A ## B ## C() CONST\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn vec<3, T, Q>(this->A, this->B, this->C);\t\t\t\\\n\t}\n\n#define GLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, CONST, A, B, C, D)\t\t\t\t\t\\\n\tvec<4, T, Q> A ## B ## C ## D() CONST\t\t\t\t\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn vec<4, T, Q>(this->A, this->B, this->C, this->D);\t\t\t\\\n\t}\n\n#define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(T, P, L, CONST, A, B)\t\\\n\ttemplate<typename T>\t\t\t\t\t\t\t\t\t\t\\\n\tvec<L, T, Q> vec<L, T, Q>::A ## B() CONST\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn vec<2, T, Q>(this->A, this->B);\t\t\t\t\t\\\n\t}\n\n#define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(T, P, L, CONST, A, B, C)\t\t\\\n\ttemplate<typename T>\t\t\t\t\t\t\t\t\t\t\t\\\n\tvec<3, T, Q> vec<L, T, Q>::A ## B ## C() CONST\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn vec<3, T, Q>(this->A, this->B, this->C);\t\t\t\t\\\n\t}\n\n#define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(T, P, L, CONST, A, B, C, D)\t\t\\\n\ttemplate<typename T>\t\t\t\t\t\t\t\t\t\t\t\t\\\n\tvec<4, T, Q> vec<L, T, Q>::A ## B ## C ## D() CONST\t\t\t\t\t\\\n\t{\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\\\n\t\treturn vec<4, T, Q>(this->A, this->B, this->C, this->D);\t\t\\\n\t}\n\n#define GLM_MUTABLE\n\n#define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, 2, GLM_MUTABLE, B, A)\n\n#define GLM_SWIZZLE_GEN_REF_FROM_VEC2(T, P) \\\n\tGLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, x, y) \\\n\tGLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, r, g) \\\n\tGLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(T, P, s, t)\n\n#define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B)\n\n#define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, GLM_MUTABLE, C, B, A)\n\n#define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(T, P, A, B, C)\n\n#define GLM_SWIZZLE_GEN_REF_FROM_VEC3(T, P) \\\n\tGLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, x, y, z) \\\n\tGLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, r, g, b) \\\n\tGLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(T, P, s, t, p)\n\n#define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, GLM_MUTABLE, D, C)\n\n#define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, , D, C, B)\n\n#define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, D, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , B, A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , C, A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, , D, B, C, A)\n\n#define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D)\n\n#define GLM_SWIZZLE_GEN_REF_FROM_VEC4(T, P) \\\n\tGLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, x, y, z, w) \\\n\tGLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, r, g, b, a) \\\n\tGLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(T, P, s, t, p, q)\n\n#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B)\n\n#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B)\n\n#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B)\n\n#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(T, P, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(T, P, A, B)\n\n#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, P)\t\t\t\\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, x, y)\t\\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, r, g)\t\\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(T, P, s, t)\n\n#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C)\n\n#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C)\n\n#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C)\n\n#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(T, P, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(T, P, A, B, C)\n\n#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, P) \\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, x, y, z) \\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, r, g, b) \\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(T, P, s, t, p)\n\n#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC2_ENTRY(T, P, const, D, D)\n\n#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, A, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, B, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, C, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC3_ENTRY(T, P, const, D, D, D)\n\n#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, A, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, B, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, C, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, A, D, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, A, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, B, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, C, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, B, D, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, A, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, B, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, C, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, C, D, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, A, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, B, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, C, D, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, A, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, B, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, A) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, B) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, C) \\\n\tGLM_SWIZZLE_GEN_VEC4_ENTRY(T, P, const, D, D, D, D)\n\n#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(T, P, A, B, C, D) \\\n\tGLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(T, P, A, B, C, D)\n\n#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, P) \\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, x, y, z, w) \\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, r, g, b, a) \\\n\tGLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(T, P, s, t, p, q)\n\n"
  },
  {
    "path": "lib/gli/glm/detail/_vectorize.hpp",
    "content": "#pragma once\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, length_t L, typename R, typename T, qualifier Q>\n\tstruct functor1{};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename R, typename T, qualifier Q>\n\tstruct functor1<vec, 1, R, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<1, R, Q> call(R (*Func) (T x), vec<1, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<1, R, Q>(Func(v.x));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename R, typename T, qualifier Q>\n\tstruct functor1<vec, 2, R, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<2, R, Q> call(R (*Func) (T x), vec<2, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<2, R, Q>(Func(v.x), Func(v.y));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename R, typename T, qualifier Q>\n\tstruct functor1<vec, 3, R, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<3, R, Q> call(R (*Func) (T x), vec<3, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<3, R, Q>(Func(v.x), Func(v.y), Func(v.z));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename R, typename T, qualifier Q>\n\tstruct functor1<vec, 4, R, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, R, Q> call(R (*Func) (T x), vec<4, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<4, R, Q>(Func(v.x), Func(v.y), Func(v.z), Func(v.w));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, length_t L, typename T, qualifier Q>\n\tstruct functor2{};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2<vec, 1, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, vec<1, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<1, T, Q>(Func(a.x, b.x));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2<vec, 2, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, vec<2, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<2, T, Q>(Func(a.x, b.x), Func(a.y, b.y));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2<vec, 3, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, vec<3, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<3, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2<vec, 4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, length_t L, typename T, qualifier Q>\n\tstruct functor2_vec_sca{};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2_vec_sca<vec, 1, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<1, T, Q> call(T (*Func) (T x, T y), vec<1, T, Q> const& a, T b)\n\t\t{\n\t\t\treturn vec<1, T, Q>(Func(a.x, b));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2_vec_sca<vec, 2, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<2, T, Q> call(T (*Func) (T x, T y), vec<2, T, Q> const& a, T b)\n\t\t{\n\t\t\treturn vec<2, T, Q>(Func(a.x, b), Func(a.y, b));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2_vec_sca<vec, 3, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, T, Q> call(T (*Func) (T x, T y), vec<3, T, Q> const& a, T b)\n\t\t{\n\t\t\treturn vec<3, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b));\n\t\t}\n\t};\n\n\ttemplate<template<length_t L, typename T, qualifier Q> class vec, typename T, qualifier Q>\n\tstruct functor2_vec_sca<vec, 4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, T, Q> call(T (*Func) (T x, T y), vec<4, T, Q> const& a, T b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b));\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct functor2_vec_int {};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct functor2_vec_int<1, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<1, int, Q> call(int (*Func) (T x, int y), vec<1, T, Q> const& a, vec<1, int, Q> const& b)\n\t\t{\n\t\t\treturn vec<1, int, Q>(Func(a.x, b.x));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct functor2_vec_int<2, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<2, int, Q> call(int (*Func) (T x, int y), vec<2, T, Q> const& a, vec<2, int, Q> const& b)\n\t\t{\n\t\t\treturn vec<2, int, Q>(Func(a.x, b.x), Func(a.y, b.y));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct functor2_vec_int<3, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, int, Q> call(int (*Func) (T x, int y), vec<3, T, Q> const& a, vec<3, int, Q> const& b)\n\t\t{\n\t\t\treturn vec<3, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct functor2_vec_int<4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, int, Q> call(int (*Func) (T x, int y), vec<4, T, Q> const& a, vec<4, int, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, int, Q>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w));\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/compute_common.hpp",
    "content": "#pragma once\n\n#include \"setup.hpp\"\n#include <limits>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename genFIType, bool /*signed*/>\n\tstruct compute_abs\n\t{};\n\n\ttemplate<typename genFIType>\n\tstruct compute_abs<genFIType, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(\n\t\t\t\tstd::numeric_limits<genFIType>::is_iec559 || std::numeric_limits<genFIType>::is_signed,\n\t\t\t\t\"'abs' only accept floating-point and integer scalar or vector inputs\");\n\n\t\t\treturn x >= genFIType(0) ? x : -x;\n\t\t\t// TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff;\n\t\t}\n\t};\n\n#if GLM_COMPILER & GLM_COMPILER_CUDA\n\ttemplate<>\n\tstruct compute_abs<float, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static float call(float x)\n\t\t{\n\t\t\treturn fabsf(x);\n\t\t}\n\t};\n#endif\n\n\ttemplate<typename genFIType>\n\tstruct compute_abs<genFIType, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static genFIType call(genFIType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(\n\t\t\t\t(!std::numeric_limits<genFIType>::is_signed && std::numeric_limits<genFIType>::is_integer),\n\t\t\t\t\"'abs' only accept floating-point and integer scalar or vector inputs\");\n\t\t\treturn x;\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/compute_vector_relational.hpp",
    "content": "#pragma once\n\n//#include \"compute_common.hpp\"\n#include \"setup.hpp\"\n#include <limits>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate <typename T, bool isFloat>\n\tstruct compute_equal\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b)\n\t\t{\n\t\t\treturn a == b;\n\t\t}\n\t};\n/*\n\ttemplate <typename T>\n\tstruct compute_equal<T, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(T a, T b)\n\t\t{\n\t\t\treturn detail::compute_abs<T, std::numeric_limits<T>::is_signed>::call(b - a) <= static_cast<T>(0);\n\t\t\t//return std::memcmp(&a, &b, sizeof(T)) == 0;\n\t\t}\n\t};\n*/\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/func_common.inl",
    "content": "/// @ref core\n/// @file glm/detail/func_common.inl\n\n#include \"../vector_relational.hpp\"\n#include \"compute_common.hpp\"\n#include \"type_vec1.hpp\"\n#include \"type_vec2.hpp\"\n#include \"type_vec3.hpp\"\n#include \"type_vec4.hpp\"\n#include \"_vectorize.hpp\"\n#include <limits>\n\nnamespace glm\n{\n\t// min\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType min(genType x, genType y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer, \"'min' only accept floating-point or integer inputs\");\n\t\treturn (y < x) ? y : x;\n\t}\n\n\t// max\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType max(genType x, genType y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer, \"'max' only accept floating-point or integer inputs\");\n\n\t\treturn (x < y) ? y : x;\n\t}\n\n\t// abs\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR int abs(int x)\n\t{\n\t\tint const y = x >> (sizeof(int) * 8 - 1);\n\t\treturn (x ^ y) - y;\n\t}\n\n\t// round\n#\tif GLM_HAS_CXX11_STL\n\t\tusing ::std::round;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER genType round(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'round' only accept floating-point inputs\");\n\n\t\t\treturn x < static_cast<genType>(0) ? static_cast<genType>(int(x - static_cast<genType>(0.5))) : static_cast<genType>(int(x + static_cast<genType>(0.5)));\n\t\t}\n#\tendif\n\n\t// trunc\n#\tif GLM_HAS_CXX11_STL\n\t\tusing ::std::trunc;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER genType trunc(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'trunc' only accept floating-point inputs\");\n\n\t\t\treturn x < static_cast<genType>(0) ? -std::floor(-x) : std::floor(x);\n\t\t}\n#\tendif\n\n}//namespace glm\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_abs_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(abs, x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename U, qualifier Q, bool Aligned>\n\tstruct compute_mix_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, U, Q> const& a)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'mix' only accept floating-point inputs for the interpolator a\");\n\n\t\t\treturn vec<L, T, Q>(vec<L, U, Q>(x) * (static_cast<U>(1) - a) + vec<L, U, Q>(y) * a);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_mix_vector<L, T, bool, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, bool, Q> const& a)\n\t\t{\n\t\t\tvec<L, T, Q> Result;\n\t\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\t\tResult[i] = a[i] ? y[i] : x[i];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename U, qualifier Q, bool Aligned>\n\tstruct compute_mix_scalar\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& y, U const& a)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'mix' only accept floating-point inputs for the interpolator a\");\n\n\t\t\treturn vec<L, T, Q>(vec<L, U, Q>(x) * (static_cast<U>(1) - a) + vec<L, U, Q>(y) * a);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_mix_scalar<L, T, bool, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& y, bool const& a)\n\t\t{\n\t\t\treturn a ? y : x;\n\t\t}\n\t};\n\n\ttemplate<typename T, typename U>\n\tstruct compute_mix\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(T const& x, T const& y, U const& a)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'mix' only accept floating-point inputs for the interpolator a\");\n\n\t\t\treturn static_cast<T>(static_cast<U>(x) * (static_cast<U>(1) - a) + static_cast<U>(y) * a);\n\t\t}\n\t};\n\n\ttemplate<typename T>\n\tstruct compute_mix<T, bool>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(T const& x, T const& y, bool const& a)\n\t\t{\n\t\t\treturn a ? y : x;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool isFloat, bool Aligned>\n\tstruct compute_sign\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn vec<L, T, Q>(glm::lessThan(vec<L, T, Q>(0), x)) - vec<L, T, Q>(glm::lessThan(x, vec<L, T, Q>(0)));\n\t\t}\n\t};\n\n#\tif GLM_ARCH == GLM_ARCH_X86\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_sign<L, T, Q, false, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\tT const Shift(static_cast<T>(sizeof(T) * 8 - 1));\n\t\t\tvec<L, T, Q> const y(vec<L, typename detail::make_unsigned<T>::type, Q>(-x) >> typename detail::make_unsigned<T>::type(Shift));\n\n\t\t\treturn (x >> Shift) | y;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_floor\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(std::floor, x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_ceil\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(std::ceil, x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_fract\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn x - floor(x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_trunc\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(trunc, x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_round\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(round, x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_mod\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'mod' only accept floating-point inputs. Include <glm/gtc/integer.hpp> for integer inputs.\");\n\t\t\treturn a - b * floor(a / b);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_min_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t\t{\n\t\t\treturn detail::functor2<vec, L, T, Q>::call(min, x, y);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_max_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t\t{\n\t\t\treturn detail::functor2<vec, L, T, Q>::call(max, x, y);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_clamp_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal)\n\t\t{\n\t\t\treturn min(max(x, minVal), maxVal);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_step_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& edge, vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn mix(vec<L, T, Q>(1), vec<L, T, Q>(0), glm::lessThan(x, edge));\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_smoothstep_vector\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& edge0, vec<L, T, Q> const& edge1, vec<L, T, Q> const& x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'smoothstep' only accept floating-point inputs\");\n\t\t\tvec<L, T, Q> const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast<T>(0), static_cast<T>(1)));\n\t\t\treturn tmp * tmp * (static_cast<T>(3) - static_cast<T>(2) * tmp);\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename genFIType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genFIType abs(genFIType x)\n\t{\n\t\treturn detail::compute_abs<genFIType, std::numeric_limits<genFIType>::is_signed>::call(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> abs(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_abs_vector<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// sign\n\t// fast and works for any type\n\ttemplate<typename genFIType>\n\tGLM_FUNC_QUALIFIER genFIType sign(genFIType x)\n\t{\n\t\tGLM_STATIC_ASSERT(\n\t\t\tstd::numeric_limits<genFIType>::is_iec559 || (std::numeric_limits<genFIType>::is_signed && std::numeric_limits<genFIType>::is_integer),\n\t\t\t\"'sign' only accept signed inputs\");\n\n\t\treturn detail::compute_sign<1, genFIType, defaultp,\n                                    std::numeric_limits<genFIType>::is_iec559, detail::is_aligned<highp>::value>::call(vec<1, genFIType>(x)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> sign(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(\n\t\t\tstd::numeric_limits<T>::is_iec559 || (std::numeric_limits<T>::is_signed && std::numeric_limits<T>::is_integer),\n\t\t\t\"'sign' only accept signed inputs\");\n\n\t\treturn detail::compute_sign<L, T, Q, std::numeric_limits<T>::is_iec559, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// floor\n\tusing ::std::floor;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> floor(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'floor' only accept floating-point inputs.\");\n\t\treturn detail::compute_floor<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> trunc(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'trunc' only accept floating-point inputs\");\n\t\treturn detail::compute_trunc<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> round(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'round' only accept floating-point inputs\");\n\t\treturn detail::compute_round<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n/*\n\t// roundEven\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType roundEven(genType const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'roundEven' only accept floating-point inputs\");\n\n\t\treturn genType(int(x + genType(int(x) % 2)));\n\t}\n*/\n\n\t// roundEven\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType roundEven(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'roundEven' only accept floating-point inputs\");\n\n\t\tint Integer = static_cast<int>(x);\n\t\tgenType IntegerPart = static_cast<genType>(Integer);\n\t\tgenType FractionalPart = fract(x);\n\n\t\tif(FractionalPart > static_cast<genType>(0.5) || FractionalPart < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn round(x);\n\t\t}\n\t\telse if((Integer % 2) == 0)\n\t\t{\n\t\t\treturn IntegerPart;\n\t\t}\n\t\telse if(x <= static_cast<genType>(0)) // Work around...\n\t\t{\n\t\t\treturn IntegerPart - static_cast<genType>(1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn IntegerPart + static_cast<genType>(1);\n\t\t}\n\t\t//else // Bug on MinGW 4.5.2\n\t\t//{\n\t\t//\treturn mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0));\n\t\t//}\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> roundEven(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'roundEven' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(roundEven, x);\n\t}\n\n\t// ceil\n\tusing ::std::ceil;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> ceil(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'ceil' only accept floating-point inputs\");\n\t\treturn detail::compute_ceil<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// fract\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fract(genType x)\n\t{\n\t\treturn fract(vec<1, genType>(x)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fract(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fract' only accept floating-point inputs\");\n\t\treturn detail::compute_fract<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// mod\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType mod(genType x, genType y)\n\t{\n#\t\tif GLM_COMPILER & GLM_COMPILER_CUDA\n\t\t\t// Another Cuda compiler bug https://github.com/g-truc/glm/issues/530\n\t\t\tvec<1, genType, defaultp> Result(mod(vec<1, genType, defaultp>(x), y));\n\t\t\treturn Result.x;\n#\t\telse\n\t\t\treturn mod(vec<1, genType, defaultp>(x), y).x;\n#\t\tendif\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mod(vec<L, T, Q> const& x, T y)\n\t{\n\t\treturn detail::compute_mod<L, T, Q, detail::is_aligned<Q>::value>::call(x, vec<L, T, Q>(y));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mod(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\treturn detail::compute_mod<L, T, Q, detail::is_aligned<Q>::value>::call(x, y);\n\t}\n\n\t// modf\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType modf(genType x, genType & i)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'modf' only accept floating-point inputs\");\n\t\treturn std::modf(x, &i);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<1, T, Q> modf(vec<1, T, Q> const& x, vec<1, T, Q> & i)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tmodf(x.x, i.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> modf(vec<2, T, Q> const& x, vec<2, T, Q> & i)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tmodf(x.x, i.x),\n\t\t\tmodf(x.y, i.y));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> modf(vec<3, T, Q> const& x, vec<3, T, Q> & i)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tmodf(x.x, i.x),\n\t\t\tmodf(x.y, i.y),\n\t\t\tmodf(x.z, i.z));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> modf(vec<4, T, Q> const& x, vec<4, T, Q> & i)\n\t{\n\t\treturn vec<4, T, Q>(\n\t\t\tmodf(x.x, i.x),\n\t\t\tmodf(x.y, i.y),\n\t\t\tmodf(x.z, i.z),\n\t\t\tmodf(x.w, i.w));\n\t}\n\n\t//// Only valid if (INT_MIN <= x-y <= INT_MAX)\n\t//// min(x,y)\n\t//r = y + ((x - y) & ((x - y) >> (sizeof(int) *\n\t//CHAR_BIT - 1)));\n\t//// max(x,y)\n\t//r = x - ((x - y) & ((x - y) >> (sizeof(int) *\n\t//CHAR_BIT - 1)));\n\n\t// min\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& a, T b)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'min' only accept floating-point or integer inputs\");\n\t\treturn detail::compute_min_vector<L, T, Q, detail::is_aligned<Q>::value>::call(a, vec<L, T, Q>(b));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t{\n\t\treturn detail::compute_min_vector<L, T, Q, detail::is_aligned<Q>::value>::call(a, b);\n\t}\n\n\t// max\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& a, T b)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'max' only accept floating-point or integer inputs\");\n\t\treturn detail::compute_max_vector<L, T, Q, detail::is_aligned<Q>::value>::call(a, vec<L, T, Q>(b));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t{\n\t\treturn detail::compute_max_vector<L, T, Q, detail::is_aligned<Q>::value>::call(a, b);\n\t}\n\n\t// clamp\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType clamp(genType x, genType minVal, genType maxVal)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer, \"'clamp' only accept floating-point or integer inputs\");\n\t\treturn min(max(x, minVal), maxVal);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> clamp(vec<L, T, Q> const& x, T minVal, T maxVal)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'clamp' only accept floating-point or integer inputs\");\n\t\treturn detail::compute_clamp_vector<L, T, Q, detail::is_aligned<Q>::value>::call(x, vec<L, T, Q>(minVal), vec<L, T, Q>(maxVal));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> clamp(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'clamp' only accept floating-point or integer inputs\");\n\t\treturn detail::compute_clamp_vector<L, T, Q, detail::is_aligned<Q>::value>::call(x, minVal, maxVal);\n\t}\n\n\ttemplate<typename genTypeT, typename genTypeU>\n\tGLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a)\n\t{\n\t\treturn detail::compute_mix<genTypeT, genTypeU>::call(x, y, a);\n\t}\n\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mix(vec<L, T, Q> const& x, vec<L, T, Q> const& y, U a)\n\t{\n\t\treturn detail::compute_mix_scalar<L, T, U, Q, detail::is_aligned<Q>::value>::call(x, y, a);\n\t}\n\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mix(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, U, Q> const& a)\n\t{\n\t\treturn detail::compute_mix_vector<L, T, U, Q, detail::is_aligned<Q>::value>::call(x, y, a);\n\t}\n\n\t// step\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType step(genType edge, genType x)\n\t{\n\t\treturn mix(static_cast<genType>(1), static_cast<genType>(0), x < edge);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> step(T edge, vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_step_vector<L, T, Q, detail::is_aligned<Q>::value>::call(vec<L, T, Q>(edge), x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> step(vec<L, T, Q> const& edge, vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_step_vector<L, T, Q, detail::is_aligned<Q>::value>::call(edge, x);\n\t}\n\n\t// smoothstep\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'smoothstep' only accept floating-point inputs\");\n\n\t\tgenType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1)));\n\t\treturn tmp * tmp * (genType(3) - genType(2) * tmp);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> smoothstep(T edge0, T edge1, vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_smoothstep_vector<L, T, Q, detail::is_aligned<Q>::value>::call(vec<L, T, Q>(edge0), vec<L, T, Q>(edge1), x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> smoothstep(vec<L, T, Q> const& edge0, vec<L, T, Q> const& edge1, vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_smoothstep_vector<L, T, Q, detail::is_aligned<Q>::value>::call(edge0, edge1, x);\n\t}\n\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::isnan;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER bool isnan(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'isnan' only accept floating-point inputs\");\n\n#\t\t\tif GLM_HAS_CXX11_STL\n\t\t\t\treturn std::isnan(x);\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n\t\t\t\treturn _isnan(x) != 0;\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_INTEL\n#\t\t\t\tif GLM_PLATFORM & GLM_PLATFORM_WINDOWS\n\t\t\t\t\treturn _isnan(x) != 0;\n#\t\t\t\telse\n\t\t\t\t\treturn ::isnan(x) != 0;\n#\t\t\t\tendif\n#\t\t\telif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L\n\t\t\t\treturn _isnan(x) != 0;\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CUDA\n\t\t\t\treturn ::isnan(x) != 0;\n#\t\t\telse\n\t\t\t\treturn std::isnan(x);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> isnan(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isnan' only accept floating-point inputs\");\n\n\t\tvec<L, bool, Q> Result;\n\t\tfor (length_t l = 0; l < v.length(); ++l)\n\t\t\tResult[l] = glm::isnan(v[l]);\n\t\treturn Result;\n\t}\n\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::isinf;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER bool isinf(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'isinf' only accept floating-point inputs\");\n\n#\t\t\tif GLM_HAS_CXX11_STL\n\t\t\t\treturn std::isinf(x);\n#\t\t\telif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC)\n#\t\t\t\tif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS)\n\t\t\t\t\treturn _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF;\n#\t\t\t\telse\n\t\t\t\t\treturn ::isinf(x);\n#\t\t\t\tendif\n#\t\t\telif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)\n#\t\t\t\tif(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L)\n\t\t\t\t\treturn _isinf(x) != 0;\n#\t\t\t\telse\n\t\t\t\t\treturn std::isinf(x);\n#\t\t\t\tendif\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CUDA\n\t\t\t\t// http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab\n\t\t\t\treturn ::isinf(double(x)) != 0;\n#\t\t\telse\n\t\t\t\treturn std::isinf(x);\n#\t\t\tendif\n\t}\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> isinf(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isinf' only accept floating-point inputs\");\n\n\t\tvec<L, bool, Q> Result;\n\t\tfor (length_t l = 0; l < v.length(); ++l)\n\t\t\tResult[l] = glm::isinf(v[l]);\n\t\treturn Result;\n\t}\n\n\tGLM_FUNC_QUALIFIER int floatBitsToInt(float const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tfloat in;\n\t\t\tint out;\n\t\t} u;\n\n\t\tu.in = v;\n\n\t\treturn u.out;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> floatBitsToInt(vec<L, float, Q> const& v)\n\t{\n\t\treturn reinterpret_cast<vec<L, int, Q>&>(const_cast<vec<L, float, Q>&>(v));\n\t}\n\n\tGLM_FUNC_QUALIFIER uint floatBitsToUint(float const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tfloat in;\n\t\t\tuint out;\n\t\t} u;\n\n\t\tu.in = v;\n\n\t\treturn u.out;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, uint, Q> floatBitsToUint(vec<L, float, Q> const& v)\n\t{\n\t\treturn reinterpret_cast<vec<L, uint, Q>&>(const_cast<vec<L, float, Q>&>(v));\n\t}\n\n\tGLM_FUNC_QUALIFIER float intBitsToFloat(int const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tint in;\n\t\t\tfloat out;\n\t\t} u;\n\n\t\tu.in = v;\n\n\t\treturn u.out;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, float, Q> intBitsToFloat(vec<L, int, Q> const& v)\n\t{\n\t\treturn reinterpret_cast<vec<L, float, Q>&>(const_cast<vec<L, int, Q>&>(v));\n\t}\n\n\tGLM_FUNC_QUALIFIER float uintBitsToFloat(uint const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint in;\n\t\t\tfloat out;\n\t\t} u;\n\n\t\tu.in = v;\n\n\t\treturn u.out;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, float, Q> uintBitsToFloat(vec<L, uint, Q> const& v)\n\t{\n\t\treturn reinterpret_cast<vec<L, float, Q>&>(const_cast<vec<L, uint, Q>&>(v));\n\t}\n\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::fma;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER genType fma(genType const& a, genType const& b, genType const& c)\n\t\t{\n\t\t\treturn a * b + c;\n\t\t}\n#\tendif\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType frexp(genType x, int& exp)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'frexp' only accept floating-point inputs\");\n\n\t\treturn std::frexp(x, &exp);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> frexp(vec<L, T, Q> const& v, vec<L, int, Q>& exp)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'frexp' only accept floating-point inputs\");\n\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t l = 0; l < v.length(); ++l)\n\t\t\tResult[l] = std::frexp(v[l], &exp[l]);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType ldexp(genType const& x, int const& exp)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'ldexp' only accept floating-point inputs\");\n\n\t\treturn std::ldexp(x, exp);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> ldexp(vec<L, T, Q> const& v, vec<L, int, Q> const& exp)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'ldexp' only accept floating-point inputs\");\n\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t l = 0; l < v.length(); ++l)\n\t\t\tResult[l] = std::ldexp(v[l], exp[l]);\n\t\treturn Result;\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_common_simd.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/func_common_simd.inl",
    "content": "/// @ref core\n/// @file glm/detail/func_common_simd.inl\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n#include \"../simd/common.h\"\n\n#include <immintrin.h>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<qualifier Q>\n\tstruct compute_abs_vector<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = glm_vec4_abs(v.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_abs_vector<4, int, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v)\n\t\t{\n\t\t\tvec<4, int, Q> result;\n\t\t\tresult.data = glm_ivec4_abs(v.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_floor<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = glm_vec4_floor(v.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_ceil<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = glm_vec4_ceil(v.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_fract<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = glm_vec4_fract(v.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_round<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = glm_vec4_round(v.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_mod<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = glm_vec4_mod(x.data, y.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_min_vector<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = _mm_min_ps(v1.data, v2.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_min_vector<4, int, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)\n\t\t{\n\t\t\tvec<4, int, Q> result;\n\t\t\tresult.data = _mm_min_epi32(v1.data, v2.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_min_vector<4, uint, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2)\n\t\t{\n\t\t\tvec<4, uint, Q> result;\n\t\t\tresult.data = _mm_min_epu32(v1.data, v2.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_max_vector<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = _mm_max_ps(v1.data, v2.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_max_vector<4, int, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)\n\t\t{\n\t\t\tvec<4, int, Q> result;\n\t\t\tresult.data = _mm_max_epi32(v1.data, v2.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_max_vector<4, uint, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2)\n\t\t{\n\t\t\tvec<4, uint, Q> result;\n\t\t\tresult.data = _mm_max_epu32(v1.data, v2.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_clamp_vector<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& minVal, vec<4, float, Q> const& maxVal)\n\t\t{\n\t\t\tvec<4, float, Q> result;\n\t\t\tresult.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_clamp_vector<4, int, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& x, vec<4, int, Q> const& minVal, vec<4, int, Q> const& maxVal)\n\t\t{\n\t\t\tvec<4, int, Q> result;\n\t\t\tresult.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_clamp_vector<4, uint, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& x, vec<4, uint, Q> const& minVal, vec<4, uint, Q> const& maxVal)\n\t\t{\n\t\t\tvec<4, uint, Q> result;\n\t\t\tresult.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data);\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_mix_vector<4, float, bool, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& x, vec<4, float, Q> const& y, vec<4, bool, Q> const& a)\n\t\t{\n\t\t\t__m128i const Load = _mm_set_epi32(-static_cast<int>(a.w), -static_cast<int>(a.z), -static_cast<int>(a.y), -static_cast<int>(a.x));\n\t\t\t__m128 const Mask = _mm_castsi128_ps(Load);\n\n\t\t\tvec<4, float, Q> Result;\n#\t\t\tif 0 && GLM_ARCH & GLM_ARCH_AVX\n\t\t\t\tResult.data = _mm_blendv_ps(x.data, y.data, Mask);\n#\t\t\telse\n\t\t\t\tResult.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data));\n#\t\t\tendif\n\t\t\treturn Result;\n\t\t}\n\t};\n/* FIXME\n\ttemplate<qualifier Q>\n\tstruct compute_step_vector<float, Q, tvec4>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge, vec<4, float, Q> const& x)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tresult.data = glm_vec4_step(edge.data, x.data);\n\t\t\treturn result;\n\t\t}\n\t};\n*/\n\ttemplate<qualifier Q>\n\tstruct compute_smoothstep_vector<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& edge0, vec<4, float, Q> const& edge1, vec<4, float, Q> const& x)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/detail/func_exponential.inl",
    "content": "/// @ref core\n/// @file glm/detail/func_exponential.inl\n\n#include \"../vector_relational.hpp\"\n#include \"_vectorize.hpp\"\n#include <limits>\n#include <cmath>\n#include <cassert>\n\nnamespace glm{\nnamespace detail\n{\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::log2;\n#\telse\n\t\ttemplate<typename genType>\n\t\tgenType log2(genType Value)\n\t\t{\n\t\t\treturn std::log(Value) * static_cast<genType>(1.4426950408889634073599246810019);\n\t\t}\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q, bool isFloat, bool Aligned>\n\tstruct compute_log2\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'log2' only accept floating-point inputs. Include <glm/gtc/integer.hpp> for integer inputs.\");\n\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(log2, v);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_sqrt\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn detail::functor1<vec, L, T, T, Q>::call(std::sqrt, x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_inversesqrt\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\treturn static_cast<T>(1) / sqrt(x);\n\t\t}\n\t};\n\n\ttemplate<length_t L, bool Aligned>\n\tstruct compute_inversesqrt<L, float, lowp, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, float, lowp> call(vec<L, float, lowp> const& x)\n\t\t{\n\t\t\tvec<L, float, lowp> tmp(x);\n\t\t\tvec<L, float, lowp> xhalf(tmp * 0.5f);\n\t\t\tvec<L, uint, lowp>* p = reinterpret_cast<vec<L, uint, lowp>*>(const_cast<vec<L, float, lowp>*>(&x));\n\t\t\tvec<L, uint, lowp> i = vec<L, uint, lowp>(0x5f375a86) - (*p >> vec<L, uint, lowp>(1));\n\t\t\tvec<L, float, lowp>* ptmp = reinterpret_cast<vec<L, float, lowp>*>(&i);\n\t\t\ttmp = *ptmp;\n\t\t\ttmp = tmp * (1.5f - xhalf * tmp * tmp);\n\t\t\treturn tmp;\n\t\t}\n\t};\n}//namespace detail\n\n\t// pow\n\tusing std::pow;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> pow(vec<L, T, Q> const& base, vec<L, T, Q> const& exponent)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(pow, base, exponent);\n\t}\n\n\t// exp\n\tusing std::exp;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> exp(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(exp, x);\n\t}\n\n\t// log\n\tusing std::log;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> log(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(log, x);\n\t}\n\n#   if GLM_HAS_CXX11_STL\n    using std::exp2;\n#   else\n\t//exp2, ln2 = 0.69314718055994530941723212145818f\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType exp2(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'exp2' only accept floating-point inputs\");\n\n\t\treturn std::exp(static_cast<genType>(0.69314718055994530941723212145818) * x);\n\t}\n#   endif\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> exp2(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(exp2, x);\n\t}\n\n\t// log2, ln2 = 0.69314718055994530941723212145818f\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType log2(genType x)\n\t{\n\t\treturn log2(vec<1, genType>(x)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> log2(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_log2<L, T, Q, std::numeric_limits<T>::is_iec559, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// sqrt\n\tusing std::sqrt;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> sqrt(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'sqrt' only accept floating-point inputs\");\n\t\treturn detail::compute_sqrt<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// inversesqrt\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType inversesqrt(genType x)\n\t{\n\t\treturn static_cast<genType>(1) / sqrt(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> inversesqrt(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'inversesqrt' only accept floating-point inputs\");\n\t\treturn detail::compute_inversesqrt<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_exponential_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/func_exponential_simd.inl",
    "content": "/// @ref core\n/// @file glm/detail/func_exponential_simd.inl\n\n#include \"../simd/exponential.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<qualifier Q>\n\tstruct compute_sqrt<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_sqrt_ps(v.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n\ttemplate<>\n\tstruct compute_sqrt<4, float, aligned_lowp, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& v)\n\t\t{\n\t\t\tvec<4, float, aligned_lowp> Result;\n\t\t\tResult.data = glm_vec4_sqrt_lowp(v.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n}//namespace detail\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/detail/func_geometric.inl",
    "content": "#include \"../exponential.hpp\"\n#include \"../common.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_length\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\treturn sqrt(dot(v, v));\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_distance\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<L, T, Q> const& p0, vec<L, T, Q> const& p1)\n\t\t{\n\t\t\treturn length(p1 - p0);\n\t\t}\n\t};\n\n\ttemplate<typename V, typename T, bool Aligned>\n\tstruct compute_dot{};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_dot<vec<1, T, Q>, T, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<1, T, Q> const& a, vec<1, T, Q> const& b)\n\t\t{\n\t\t\treturn a.x * b.x;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_dot<vec<2, T, Q>, T, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& a, vec<2, T, Q> const& b)\n\t\t{\n\t\t\tvec<2, T, Q> tmp(a * b);\n\t\t\treturn tmp.x + tmp.y;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_dot<vec<3, T, Q>, T, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<3, T, Q> const& a, vec<3, T, Q> const& b)\n\t\t{\n\t\t\tvec<3, T, Q> tmp(a * b);\n\t\t\treturn tmp.x + tmp.y + tmp.z;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_dot<vec<4, T, Q>, T, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> tmp(a * b);\n\t\t\treturn (tmp.x + tmp.y) + (tmp.z + tmp.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_cross\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, T, Q> call(vec<3, T, Q> const& x, vec<3, T, Q> const& y)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'cross' accepts only floating-point inputs\");\n\n\t\t\treturn vec<3, T, Q>(\n\t\t\t\tx.y * y.z - y.y * x.z,\n\t\t\t\tx.z * y.x - y.z * x.x,\n\t\t\t\tx.x * y.y - y.x * x.y);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_normalize\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'normalize' accepts only floating-point inputs\");\n\n\t\t\treturn v * inversesqrt(dot(v, v));\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_faceforward\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& N, vec<L, T, Q> const& I, vec<L, T, Q> const& Nref)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'normalize' accepts only floating-point inputs\");\n\n\t\t\treturn dot(Nref, I) < static_cast<T>(0) ? N : -N;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_reflect\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& I, vec<L, T, Q> const& N)\n\t\t{\n\t\t\treturn I - N * dot(N, I) * static_cast<T>(2);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_refract\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& I, vec<L, T, Q> const& N, T eta)\n\t\t{\n\t\t\tT const dotValue(dot(N, I));\n\t\t\tT const k(static_cast<T>(1) - eta * eta * (static_cast<T>(1) - dotValue * dotValue));\n\t\t\tvec<L, T, Q> const Result =\n                (k >= static_cast<T>(0)) ? (eta * I - (eta * dotValue + std::sqrt(k)) * N) : vec<L, T, Q>(0);\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n\n\t// length\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType length(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'length' accepts only floating-point inputs\");\n\n\t\treturn abs(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T length(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'length' accepts only floating-point inputs\");\n\n\t\treturn detail::compute_length<L, T, Q, detail::is_aligned<Q>::value>::call(v);\n\t}\n\n\t// distance\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType distance(genType const& p0, genType const& p1)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'distance' accepts only floating-point inputs\");\n\n\t\treturn length(p1 - p0);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T distance(vec<L, T, Q> const& p0, vec<L, T, Q> const& p1)\n\t{\n\t\treturn detail::compute_distance<L, T, Q, detail::is_aligned<Q>::value>::call(p0, p1);\n\t}\n\n\t// dot\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T dot(T x, T y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'dot' accepts only floating-point inputs\");\n\t\treturn x * y;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T dot(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'dot' accepts only floating-point inputs\");\n\t\treturn detail::compute_dot<vec<L, T, Q>, T, detail::is_aligned<Q>::value>::call(x, y);\n\t}\n\n\t// cross\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y)\n\t{\n\t\treturn detail::compute_cross<T, Q, detail::is_aligned<Q>::value>::call(x, y);\n\t}\n/*\n\t// normalize\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType normalize(genType const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'normalize' accepts only floating-point inputs\");\n\n\t\treturn x < genType(0) ? genType(-1) : genType(1);\n\t}\n*/\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> normalize(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'normalize' accepts only floating-point inputs\");\n\n\t\treturn detail::compute_normalize<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// faceforward\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType faceforward(genType const& N, genType const& I, genType const& Nref)\n\t{\n\t\treturn dot(Nref, I) < static_cast<genType>(0) ? N : -N;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> faceforward(vec<L, T, Q> const& N, vec<L, T, Q> const& I, vec<L, T, Q> const& Nref)\n\t{\n\t\treturn detail::compute_faceforward<L, T, Q, detail::is_aligned<Q>::value>::call(N, I, Nref);\n\t}\n\n\t// reflect\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType reflect(genType const& I, genType const& N)\n\t{\n\t\treturn I - N * dot(N, I) * genType(2);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> reflect(vec<L, T, Q> const& I, vec<L, T, Q> const& N)\n\t{\n\t\treturn detail::compute_reflect<L, T, Q, detail::is_aligned<Q>::value>::call(I, N);\n\t}\n\n\t// refract\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType refract(genType const& I, genType const& N, genType eta)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'refract' accepts only floating-point inputs\");\n\t\tgenType const dotValue(dot(N, I));\n\t\tgenType const k(static_cast<genType>(1) - eta * eta * (static_cast<genType>(1) - dotValue * dotValue));\n\t\treturn (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast<genType>(k >= static_cast<genType>(0));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> refract(vec<L, T, Q> const& I, vec<L, T, Q> const& N, T eta)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'refract' accepts only floating-point inputs\");\n\t\treturn detail::compute_refract<L, T, Q, detail::is_aligned<Q>::value>::call(I, N, eta);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_geometric_simd.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/func_geometric_simd.inl",
    "content": "/// @ref core\n/// @file glm/detail/func_geometric_simd.inl\n\n#include \"../simd/geometric.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<qualifier Q>\n\tstruct compute_length<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\treturn _mm_cvtss_f32(glm_vec4_length(v.data));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_distance<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1)\n\t\t{\n\t\t\treturn _mm_cvtss_f32(glm_vec4_distance(p0.data, p1.data));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_dot<vec<4, float, Q>, float, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y)\n\t\t{\n\t\t\treturn _mm_cvtss_f32(glm_vec1_dot(x.data, y.data));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_cross<float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, float, Q> call(vec<3, float, Q> const& a, vec<3, float, Q> const& b)\n\t\t{\n\t\t\t__m128 const set0 = _mm_set_ps(0.0f, a.z, a.y, a.x);\n\t\t\t__m128 const set1 = _mm_set_ps(0.0f, b.z, b.y, b.x);\n\t\t\t__m128 const xpd0 = glm_vec4_cross(set0, set1);\n\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = xpd0;\n\t\t\treturn vec<3, float, Q>(Result);\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_normalize<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = glm_vec4_normalize(v.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_faceforward<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& N, vec<4, float, Q> const& I, vec<4, float, Q> const& Nref)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = glm_vec4_faceforward(N.data, I.data, Nref.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_reflect<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = glm_vec4_reflect(I.data, N.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_refract<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& I, vec<4, float, Q> const& N, float eta)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = glm_vec4_refract(I.data, N.data, _mm_set1_ps(eta));\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n\n#elif GLM_ARCH & GLM_ARCH_NEON_BIT\nnamespace glm{\nnamespace detail\n{\n\ttemplate<qualifier Q>\n\tstruct compute_length<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\treturn sqrt(compute_dot<vec<4, float, Q>, float, true>::call(v, v));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_distance<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& p0, vec<4, float, Q> const& p1)\n\t\t{\n\t\t\treturn compute_length<4, float, Q, true>::call(p1 - p0);\n\t\t}\n\t};\n\n\n\ttemplate<qualifier Q>\n\tstruct compute_dot<vec<4, float, Q>, float, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(vec<4, float, Q> const& x, vec<4, float, Q> const& y)\n\t\t{\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tfloat32x4_t v = vmulq_f32(x.data, y.data);\n\t\t\treturn vaddvq_f32(v);\n#else  // Armv7a with Neon\n\t\t\tfloat32x4_t p = vmulq_f32(x.data, y.data);\n\t\t\tfloat32x2_t v = vpadd_f32(vget_low_f32(p), vget_high_f32(p));\n\t\t\tv = vpadd_f32(v, v);\n\t\t\treturn vget_lane_f32(v, 0);\n#endif\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_normalize<4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> call(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tfloat32x4_t p = vmulq_f32(v.data, v.data);\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tp = vpaddq_f32(p, p);\n\t\t\tp = vpaddq_f32(p, p);\n#else\n\t\t\tfloat32x2_t t = vpadd_f32(vget_low_f32(p), vget_high_f32(p));\n\t\t\tt = vpadd_f32(t, t);\n\t\t\tp = vcombine_f32(t, t);\n#endif\n\n\t\t\tfloat32x4_t vd = vrsqrteq_f32(p);\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = vmulq_f32(v.data, vd);\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/detail/func_integer.inl",
    "content": "/// @ref core\n\n#include \"_vectorize.hpp\"\n#if(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC)\n#\tinclude <intrin.h>\n#\tpragma intrinsic(_BitScanReverse)\n#endif//(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC)\n#include <limits>\n\n#if !GLM_HAS_EXTENDED_INTEGER_TYPE\n#\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\tpragma GCC diagnostic ignored \"-Wlong-long\"\n#\tendif\n#\tif (GLM_COMPILER & GLM_COMPILER_CLANG)\n#\t\tpragma clang diagnostic ignored \"-Wc++11-long-long\"\n#\tendif\n#endif\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T mask(T Bits)\n\t{\n\t\treturn Bits >= static_cast<T>(sizeof(T) * 8) ? ~static_cast<T>(0) : (static_cast<T>(1) << Bits) - static_cast<T>(1);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned, bool EXEC>\n\tstruct compute_bitfieldReverseStep\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T, T)\n\t\t{\n\t\t\treturn v;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_bitfieldReverseStep<L, T, Q, Aligned, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T Mask, T Shift)\n\t\t{\n\t\t\treturn (v & Mask) << Shift | (v & (~Mask)) >> Shift;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned, bool EXEC>\n\tstruct compute_bitfieldBitCountStep\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T, T)\n\t\t{\n\t\t\treturn v;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_bitfieldBitCountStep<L, T, Q, Aligned, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T Mask, T Shift)\n\t\t{\n\t\t\treturn (v & Mask) + ((v >> Shift) & Mask);\n\t\t}\n\t};\n\n\ttemplate<typename genIUType, size_t Bits>\n\tstruct compute_findLSB\n\t{\n\t\tGLM_FUNC_QUALIFIER static int call(genIUType Value)\n\t\t{\n\t\t\tif(Value == 0)\n\t\t\t\treturn -1;\n\n\t\t\treturn glm::bitCount(~Value & (Value - static_cast<genIUType>(1)));\n\t\t}\n\t};\n\n#\tif GLM_HAS_BITSCAN_WINDOWS\n\t\ttemplate<typename genIUType>\n\t\tstruct compute_findLSB<genIUType, 32>\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER static int call(genIUType Value)\n\t\t\t{\n\t\t\t\tunsigned long Result(0);\n\t\t\t\tunsigned char IsNotNull = _BitScanForward(&Result, *reinterpret_cast<unsigned long*>(&Value));\n\t\t\t\treturn IsNotNull ? int(Result) : -1;\n\t\t\t}\n\t\t};\n\n#\t\tif !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32))\n\t\ttemplate<typename genIUType>\n\t\tstruct compute_findLSB<genIUType, 64>\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER static int call(genIUType Value)\n\t\t\t{\n\t\t\t\tunsigned long Result(0);\n\t\t\t\tunsigned char IsNotNull = _BitScanForward64(&Result, *reinterpret_cast<unsigned __int64*>(&Value));\n\t\t\t\treturn IsNotNull ? int(Result) : -1;\n\t\t\t}\n\t\t};\n#\t\tendif\n#\tendif//GLM_HAS_BITSCAN_WINDOWS\n\n\ttemplate<length_t L, typename T, qualifier Q, bool EXEC = true>\n\tstruct compute_findMSB_step_vec\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, T Shift)\n\t\t{\n\t\t\treturn x | (x >> Shift);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_findMSB_step_vec<L, T, Q, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x, T)\n\t\t{\n\t\t\treturn x;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, int>\n\tstruct compute_findMSB_vec\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, int, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\tvec<L, T, Q> x(v);\n\t\t\tx = compute_findMSB_step_vec<L, T, Q, sizeof(T) * 8 >=  8>::call(x, static_cast<T>( 1));\n\t\t\tx = compute_findMSB_step_vec<L, T, Q, sizeof(T) * 8 >=  8>::call(x, static_cast<T>( 2));\n\t\t\tx = compute_findMSB_step_vec<L, T, Q, sizeof(T) * 8 >=  8>::call(x, static_cast<T>( 4));\n\t\t\tx = compute_findMSB_step_vec<L, T, Q, sizeof(T) * 8 >= 16>::call(x, static_cast<T>( 8));\n\t\t\tx = compute_findMSB_step_vec<L, T, Q, sizeof(T) * 8 >= 32>::call(x, static_cast<T>(16));\n\t\t\tx = compute_findMSB_step_vec<L, T, Q, sizeof(T) * 8 >= 64>::call(x, static_cast<T>(32));\n\t\t\treturn vec<L, int, Q>(sizeof(T) * 8 - 1) - glm::bitCount(~x);\n\t\t}\n\t};\n\n#\tif GLM_HAS_BITSCAN_WINDOWS\n\t\ttemplate<typename genIUType>\n\t\tGLM_FUNC_QUALIFIER int compute_findMSB_32(genIUType Value)\n\t\t{\n\t\t\tunsigned long Result(0);\n\t\t\tunsigned char IsNotNull = _BitScanReverse(&Result, *reinterpret_cast<unsigned long*>(&Value));\n\t\t\treturn IsNotNull ? int(Result) : -1;\n\t\t}\n\n\t\ttemplate<length_t L, typename T, qualifier Q>\n\t\tstruct compute_findMSB_vec<L, T, Q, 32>\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER static vec<L, int, Q> call(vec<L, T, Q> const& x)\n\t\t\t{\n\t\t\t\treturn detail::functor1<vec, L, int, T, Q>::call(compute_findMSB_32, x);\n\t\t\t}\n\t\t};\n\n#\t\tif !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32))\n\t\ttemplate<typename genIUType>\n\t\tGLM_FUNC_QUALIFIER int compute_findMSB_64(genIUType Value)\n\t\t{\n\t\t\tunsigned long Result(0);\n\t\t\tunsigned char IsNotNull = _BitScanReverse64(&Result, *reinterpret_cast<unsigned __int64*>(&Value));\n\t\t\treturn IsNotNull ? int(Result) : -1;\n\t\t}\n\n\t\ttemplate<length_t L, typename T, qualifier Q>\n\t\tstruct compute_findMSB_vec<L, T, Q, 64>\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER static vec<L, int, Q> call(vec<L, T, Q> const& x)\n\t\t\t{\n\t\t\t\treturn detail::functor1<vec, L, int, T, Q>::call(compute_findMSB_64, x);\n\t\t\t}\n\t\t};\n#\t\tendif\n#\tendif//GLM_HAS_BITSCAN_WINDOWS\n}//namespace detail\n\n\t// uaddCarry\n\tGLM_FUNC_QUALIFIER uint uaddCarry(uint const& x, uint const& y, uint & Carry)\n\t{\n\t\tdetail::uint64 const Value64(static_cast<detail::uint64>(x) + static_cast<detail::uint64>(y));\n\t\tdetail::uint64 const Max32((static_cast<detail::uint64>(1) << static_cast<detail::uint64>(32)) - static_cast<detail::uint64>(1));\n\t\tCarry = Value64 > Max32 ? 1u : 0u;\n\t\treturn static_cast<uint>(Value64 % (Max32 + static_cast<detail::uint64>(1)));\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, uint, Q> uaddCarry(vec<L, uint, Q> const& x, vec<L, uint, Q> const& y, vec<L, uint, Q>& Carry)\n\t{\n\t\tvec<L, detail::uint64, Q> Value64(vec<L, detail::uint64, Q>(x) + vec<L, detail::uint64, Q>(y));\n\t\tvec<L, detail::uint64, Q> Max32((static_cast<detail::uint64>(1) << static_cast<detail::uint64>(32)) - static_cast<detail::uint64>(1));\n\t\tCarry = mix(vec<L, uint, Q>(0), vec<L, uint, Q>(1), greaterThan(Value64, Max32));\n\t\treturn vec<L, uint, Q>(Value64 % (Max32 + static_cast<detail::uint64>(1)));\n\t}\n\n\t// usubBorrow\n\tGLM_FUNC_QUALIFIER uint usubBorrow(uint const& x, uint const& y, uint & Borrow)\n\t{\n\t\tBorrow = x >= y ? static_cast<uint>(0) : static_cast<uint>(1);\n\t\tif(y >= x)\n\t\t\treturn y - x;\n\t\telse\n\t\t\treturn static_cast<uint>((static_cast<detail::int64>(1) << static_cast<detail::int64>(32)) + (static_cast<detail::int64>(y) - static_cast<detail::int64>(x)));\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, uint, Q> usubBorrow(vec<L, uint, Q> const& x, vec<L, uint, Q> const& y, vec<L, uint, Q>& Borrow)\n\t{\n\t\tBorrow = mix(vec<L, uint, Q>(1), vec<L, uint, Q>(0), greaterThanEqual(x, y));\n\t\tvec<L, uint, Q> const YgeX(y - x);\n\t\tvec<L, uint, Q> const XgeY(vec<L, uint, Q>((static_cast<detail::int64>(1) << static_cast<detail::int64>(32)) + (vec<L, detail::int64, Q>(y) - vec<L, detail::int64, Q>(x))));\n\t\treturn mix(XgeY, YgeX, greaterThanEqual(y, x));\n\t}\n\n\t// umulExtended\n\tGLM_FUNC_QUALIFIER void umulExtended(uint const& x, uint const& y, uint & msb, uint & lsb)\n\t{\n\t\tdetail::uint64 Value64 = static_cast<detail::uint64>(x) * static_cast<detail::uint64>(y);\n\t\tmsb = static_cast<uint>(Value64 >> static_cast<detail::uint64>(32));\n\t\tlsb = static_cast<uint>(Value64);\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER void umulExtended(vec<L, uint, Q> const& x, vec<L, uint, Q> const& y, vec<L, uint, Q>& msb, vec<L, uint, Q>& lsb)\n\t{\n\t\tvec<L, detail::uint64, Q> Value64(vec<L, detail::uint64, Q>(x) * vec<L, detail::uint64, Q>(y));\n\t\tmsb = vec<L, uint, Q>(Value64 >> static_cast<detail::uint64>(32));\n\t\tlsb = vec<L, uint, Q>(Value64);\n\t}\n\n\t// imulExtended\n\tGLM_FUNC_QUALIFIER void imulExtended(int x, int y, int& msb, int& lsb)\n\t{\n\t\tdetail::int64 Value64 = static_cast<detail::int64>(x) * static_cast<detail::int64>(y);\n\t\tmsb = static_cast<int>(Value64 >> static_cast<detail::int64>(32));\n\t\tlsb = static_cast<int>(Value64);\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER void imulExtended(vec<L, int, Q> const& x, vec<L, int, Q> const& y, vec<L, int, Q>& msb, vec<L, int, Q>& lsb)\n\t{\n\t\tvec<L, detail::int64, Q> Value64(vec<L, detail::int64, Q>(x) * vec<L, detail::int64, Q>(y));\n\t\tlsb = vec<L, int, Q>(Value64 & static_cast<detail::int64>(0xFFFFFFFF));\n\t\tmsb = vec<L, int, Q>((Value64 >> static_cast<detail::int64>(32)) & static_cast<detail::int64>(0xFFFFFFFF));\n\t}\n\n\t// bitfieldExtract\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits)\n\t{\n\t\treturn bitfieldExtract(vec<1, genIUType>(Value), Offset, Bits).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldExtract(vec<L, T, Q> const& Value, int Offset, int Bits)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'bitfieldExtract' only accept integer inputs\");\n\n\t\treturn (Value >> static_cast<T>(Offset)) & static_cast<T>(detail::mask(Bits));\n\t}\n\n\t// bitfieldInsert\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const& Base, genIUType const& Insert, int Offset, int Bits)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'bitfieldInsert' only accept integer values\");\n\n\t\treturn bitfieldInsert(vec<1, genIUType>(Base), vec<1, genIUType>(Insert), Offset, Bits).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldInsert(vec<L, T, Q> const& Base, vec<L, T, Q> const& Insert, int Offset, int Bits)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'bitfieldInsert' only accept integer values\");\n\n\t\tT const Mask = static_cast<T>(detail::mask(Bits) << Offset);\n\t\treturn (Base & ~Mask) | ((Insert << static_cast<T>(Offset)) & Mask);\n\t}\n\n\t// bitfieldReverse\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType bitfieldReverse(genIUType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'bitfieldReverse' only accept integer values\");\n\n\t\treturn bitfieldReverse(glm::vec<1, genIUType, glm::defaultp>(x)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldReverse(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'bitfieldReverse' only accept integer values\");\n\n\t\tvec<L, T, Q> x(v);\n\t\tx = detail::compute_bitfieldReverseStep<L, T, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>=  2>::call(x, static_cast<T>(0x5555555555555555ull), static_cast<T>( 1));\n\t\tx = detail::compute_bitfieldReverseStep<L, T, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>=  4>::call(x, static_cast<T>(0x3333333333333333ull), static_cast<T>( 2));\n\t\tx = detail::compute_bitfieldReverseStep<L, T, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>=  8>::call(x, static_cast<T>(0x0F0F0F0F0F0F0F0Full), static_cast<T>( 4));\n\t\tx = detail::compute_bitfieldReverseStep<L, T, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>= 16>::call(x, static_cast<T>(0x00FF00FF00FF00FFull), static_cast<T>( 8));\n\t\tx = detail::compute_bitfieldReverseStep<L, T, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>= 32>::call(x, static_cast<T>(0x0000FFFF0000FFFFull), static_cast<T>(16));\n\t\tx = detail::compute_bitfieldReverseStep<L, T, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>= 64>::call(x, static_cast<T>(0x00000000FFFFFFFFull), static_cast<T>(32));\n\t\treturn x;\n\t}\n\n\t// bitCount\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER int bitCount(genIUType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'bitCount' only accept integer values\");\n\n\t\treturn bitCount(glm::vec<1, genIUType, glm::defaultp>(x)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> bitCount(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'bitCount' only accept integer values\");\n\n#\t\tif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\tpragma warning(push)\n#\t\t\tpragma warning(disable : 4310) //cast truncates constant value\n#\t\tendif\n\n\t\tvec<L, typename detail::make_unsigned<T>::type, Q> x(*reinterpret_cast<vec<L, typename detail::make_unsigned<T>::type, Q> const *>(&v));\n\t\tx = detail::compute_bitfieldBitCountStep<L, typename detail::make_unsigned<T>::type, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>=  2>::call(x, typename detail::make_unsigned<T>::type(0x5555555555555555ull), typename detail::make_unsigned<T>::type( 1));\n\t\tx = detail::compute_bitfieldBitCountStep<L, typename detail::make_unsigned<T>::type, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>=  4>::call(x, typename detail::make_unsigned<T>::type(0x3333333333333333ull), typename detail::make_unsigned<T>::type( 2));\n\t\tx = detail::compute_bitfieldBitCountStep<L, typename detail::make_unsigned<T>::type, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>=  8>::call(x, typename detail::make_unsigned<T>::type(0x0F0F0F0F0F0F0F0Full), typename detail::make_unsigned<T>::type( 4));\n\t\tx = detail::compute_bitfieldBitCountStep<L, typename detail::make_unsigned<T>::type, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>= 16>::call(x, typename detail::make_unsigned<T>::type(0x00FF00FF00FF00FFull), typename detail::make_unsigned<T>::type( 8));\n\t\tx = detail::compute_bitfieldBitCountStep<L, typename detail::make_unsigned<T>::type, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>= 32>::call(x, typename detail::make_unsigned<T>::type(0x0000FFFF0000FFFFull), typename detail::make_unsigned<T>::type(16));\n\t\tx = detail::compute_bitfieldBitCountStep<L, typename detail::make_unsigned<T>::type, Q, detail::is_aligned<Q>::value, sizeof(T) * 8>= 64>::call(x, typename detail::make_unsigned<T>::type(0x00000000FFFFFFFFull), typename detail::make_unsigned<T>::type(32));\n\t\treturn vec<L, int, Q>(x);\n\n#\t\tif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\tpragma warning(pop)\n#\t\tendif\n\t}\n\n\t// findLSB\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER int findLSB(genIUType Value)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'findLSB' only accept integer values\");\n\n\t\treturn detail::compute_findLSB<genIUType, sizeof(genIUType) * 8>::call(Value);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> findLSB(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'findLSB' only accept integer values\");\n\n\t\treturn detail::functor1<vec, L, int, T, Q>::call(findLSB, x);\n\t}\n\n\t// findMSB\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER int findMSB(genIUType v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'findMSB' only accept integer values\");\n\n\t\treturn findMSB(vec<1, genIUType>(v)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> findMSB(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'findMSB' only accept integer values\");\n\n\t\treturn detail::compute_findMSB_vec<L, T, Q, sizeof(T) * 8>::call(v);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_integer_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/func_integer_simd.inl",
    "content": "#include \"../simd/integer.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<qualifier Q>\n\tstruct compute_bitfieldReverseStep<4, uint, Q, true, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift)\n\t\t{\n\t\t\t__m128i const set0 = v.data;\n\n\t\t\t__m128i const set1 = _mm_set1_epi32(static_cast<int>(Mask));\n\t\t\t__m128i const and1 = _mm_and_si128(set0, set1);\n\t\t\t__m128i const sft1 = _mm_slli_epi32(and1, Shift);\n\n\t\t\t__m128i const set2 = _mm_andnot_si128(set0, _mm_set1_epi32(-1));\n\t\t\t__m128i const and2 = _mm_and_si128(set0, set2);\n\t\t\t__m128i const sft2 = _mm_srai_epi32(and2, Shift);\n\n\t\t\t__m128i const or0 = _mm_or_si128(sft1, sft2);\n\n\t\t\treturn or0;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_bitfieldBitCountStep<4, uint, Q, true, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint, Q> call(vec<4, uint, Q> const& v, uint Mask, uint Shift)\n\t\t{\n\t\t\t__m128i const set0 = v.data;\n\n\t\t\t__m128i const set1 = _mm_set1_epi32(static_cast<int>(Mask));\n\t\t\t__m128i const and0 = _mm_and_si128(set0, set1);\n\t\t\t__m128i const sft0 = _mm_slli_epi32(set0, Shift);\n\t\t\t__m128i const and1 = _mm_and_si128(sft0, set1);\n\t\t\t__m128i const add0 = _mm_add_epi32(and0, and1);\n\n\t\t\treturn add0;\n\t\t}\n\t};\n}//namespace detail\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER int bitCount(uint x)\n\t{\n\t\treturn _mm_popcnt_u32(x);\n\t}\n\n#\tif(GLM_MODEL == GLM_MODEL_64)\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER int bitCount(detail::uint64 x)\n\t{\n\t\treturn static_cast<int>(_mm_popcnt_u64(x));\n\t}\n#\tendif//GLM_MODEL\n#\tendif//GLM_ARCH\n\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/detail/func_matrix.inl",
    "content": "#include \"../geometric.hpp\"\n#include <limits>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t C, length_t R, typename T, qualifier Q, bool Aligned>\n\tstruct compute_matrixCompMult\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<C, R, T, Q> call(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y)\n\t\t{\n\t\t\tmat<C, R, T, Q> Result;\n\t\t\tfor(length_t i = 0; i < Result.length(); ++i)\n\t\t\t\tResult[i] = x[i] * y[i];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose{};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<2, 2, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m)\n\t\t{\n\t\t\tmat<2, 2, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<2, 3, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<3, 2, T, Q> call(mat<2, 3, T, Q> const& m)\n\t\t{\n\t\t\tmat<3,2, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[2][0] = m[0][2];\n\t\t\tResult[2][1] = m[1][2];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<2, 4, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 2, T, Q> call(mat<2, 4, T, Q> const& m)\n\t\t{\n\t\t\tmat<4, 2, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[2][0] = m[0][2];\n\t\t\tResult[2][1] = m[1][2];\n\t\t\tResult[3][0] = m[0][3];\n\t\t\tResult[3][1] = m[1][3];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<3, 2, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<2, 3, T, Q> call(mat<3, 2, T, Q> const& m)\n\t\t{\n\t\t\tmat<2, 3, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[0][2] = m[2][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[1][2] = m[2][1];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<3, 3, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m)\n\t\t{\n\t\t\tmat<3, 3, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[0][2] = m[2][0];\n\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[1][2] = m[2][1];\n\n\t\t\tResult[2][0] = m[0][2];\n\t\t\tResult[2][1] = m[1][2];\n\t\t\tResult[2][2] = m[2][2];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<3, 4, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 3, T, Q> call(mat<3, 4, T, Q> const& m)\n\t\t{\n\t\t\tmat<4, 3, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[0][2] = m[2][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[1][2] = m[2][1];\n\t\t\tResult[2][0] = m[0][2];\n\t\t\tResult[2][1] = m[1][2];\n\t\t\tResult[2][2] = m[2][2];\n\t\t\tResult[3][0] = m[0][3];\n\t\t\tResult[3][1] = m[1][3];\n\t\t\tResult[3][2] = m[2][3];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<4, 2, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<2, 4, T, Q> call(mat<4, 2, T, Q> const& m)\n\t\t{\n\t\t\tmat<2, 4, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[0][2] = m[2][0];\n\t\t\tResult[0][3] = m[3][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[1][2] = m[2][1];\n\t\t\tResult[1][3] = m[3][1];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<4, 3, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<3, 4, T, Q> call(mat<4, 3, T, Q> const& m)\n\t\t{\n\t\t\tmat<3, 4, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[0][2] = m[2][0];\n\t\t\tResult[0][3] = m[3][0];\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[1][2] = m[2][1];\n\t\t\tResult[1][3] = m[3][1];\n\t\t\tResult[2][0] = m[0][2];\n\t\t\tResult[2][1] = m[1][2];\n\t\t\tResult[2][2] = m[2][2];\n\t\t\tResult[2][3] = m[3][2];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_transpose<4, 4, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m)\n\t\t{\n\t\t\tmat<4, 4, T, Q> Result;\n\t\t\tResult[0][0] = m[0][0];\n\t\t\tResult[0][1] = m[1][0];\n\t\t\tResult[0][2] = m[2][0];\n\t\t\tResult[0][3] = m[3][0];\n\n\t\t\tResult[1][0] = m[0][1];\n\t\t\tResult[1][1] = m[1][1];\n\t\t\tResult[1][2] = m[2][1];\n\t\t\tResult[1][3] = m[3][1];\n\n\t\t\tResult[2][0] = m[0][2];\n\t\t\tResult[2][1] = m[1][2];\n\t\t\tResult[2][2] = m[2][2];\n\t\t\tResult[2][3] = m[3][2];\n\n\t\t\tResult[3][0] = m[0][3];\n\t\t\tResult[3][1] = m[1][3];\n\t\t\tResult[3][2] = m[2][3];\n\t\t\tResult[3][3] = m[3][3];\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q, bool Aligned>\n\tstruct compute_determinant{};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_determinant<2, 2, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(mat<2, 2, T, Q> const& m)\n\t\t{\n\t\t\treturn m[0][0] * m[1][1] - m[1][0] * m[0][1];\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_determinant<3, 3, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(mat<3, 3, T, Q> const& m)\n\t\t{\n\t\t\treturn\n\t\t\t\t+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])\n\t\t\t\t- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])\n\t\t\t\t+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_determinant<4, 4, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(mat<4, 4, T, Q> const& m)\n\t\t{\n\t\t\tT SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t\tT SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t\tT SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t\tT SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t\tT SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t\tT SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\n\t\t\tvec<4, T, Q> DetCof(\n\t\t\t\t+ (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),\n\t\t\t\t- (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),\n\t\t\t\t+ (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),\n\t\t\t\t- (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));\n\n\t\t\treturn\n\t\t\t\tm[0][0] * DetCof[0] + m[0][1] * DetCof[1] +\n\t\t\t\tm[0][2] * DetCof[2] + m[0][3] * DetCof[3];\n\t\t}\n\t};\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q, bool Aligned>\n\tstruct compute_inverse{};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_inverse<2, 2, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<2, 2, T, Q> call(mat<2, 2, T, Q> const& m)\n\t\t{\n\t\t\tT OneOverDeterminant = static_cast<T>(1) / (\n\t\t\t\t+ m[0][0] * m[1][1]\n\t\t\t\t- m[1][0] * m[0][1]);\n\n\t\t\tmat<2, 2, T, Q> Inverse(\n\t\t\t\t+ m[1][1] * OneOverDeterminant,\n\t\t\t\t- m[0][1] * OneOverDeterminant,\n\t\t\t\t- m[1][0] * OneOverDeterminant,\n\t\t\t\t+ m[0][0] * OneOverDeterminant);\n\n\t\t\treturn Inverse;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_inverse<3, 3, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<3, 3, T, Q> call(mat<3, 3, T, Q> const& m)\n\t\t{\n\t\t\tT OneOverDeterminant = static_cast<T>(1) / (\n\t\t\t\t+ m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])\n\t\t\t\t- m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])\n\t\t\t\t+ m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));\n\n\t\t\tmat<3, 3, T, Q> Inverse;\n\t\t\tInverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;\n\t\t\tInverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;\n\t\t\tInverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;\n\t\t\tInverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;\n\t\t\tInverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;\n\t\t\tInverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;\n\t\t\tInverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;\n\t\t\tInverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;\n\t\t\tInverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;\n\n\t\t\treturn Inverse;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_inverse<4, 4, T, Q, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 4, T, Q> call(mat<4, 4, T, Q> const& m)\n\t\t{\n\t\t\tT Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t\tT Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];\n\t\t\tT Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];\n\n\t\t\tT Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t\tT Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];\n\t\t\tT Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];\n\n\t\t\tT Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t\tT Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];\n\t\t\tT Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n\n\t\t\tT Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t\tT Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];\n\t\t\tT Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];\n\n\t\t\tT Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t\tT Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];\n\t\t\tT Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];\n\n\t\t\tT Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t\tT Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];\n\t\t\tT Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n\n\t\t\tvec<4, T, Q> Fac0(Coef00, Coef00, Coef02, Coef03);\n\t\t\tvec<4, T, Q> Fac1(Coef04, Coef04, Coef06, Coef07);\n\t\t\tvec<4, T, Q> Fac2(Coef08, Coef08, Coef10, Coef11);\n\t\t\tvec<4, T, Q> Fac3(Coef12, Coef12, Coef14, Coef15);\n\t\t\tvec<4, T, Q> Fac4(Coef16, Coef16, Coef18, Coef19);\n\t\t\tvec<4, T, Q> Fac5(Coef20, Coef20, Coef22, Coef23);\n\n\t\t\tvec<4, T, Q> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]);\n\t\t\tvec<4, T, Q> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]);\n\t\t\tvec<4, T, Q> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]);\n\t\t\tvec<4, T, Q> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]);\n\n\t\t\tvec<4, T, Q> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2);\n\t\t\tvec<4, T, Q> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4);\n\t\t\tvec<4, T, Q> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5);\n\t\t\tvec<4, T, Q> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5);\n\n\t\t\tvec<4, T, Q> SignA(+1, -1, +1, -1);\n\t\t\tvec<4, T, Q> SignB(-1, +1, -1, +1);\n\t\t\tmat<4, 4, T, Q> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB);\n\n\t\t\tvec<4, T, Q> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]);\n\n\t\t\tvec<4, T, Q> Dot0(m[0] * Row0);\n\t\t\tT Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w);\n\n\t\t\tT OneOverDeterminant = static_cast<T>(1) / Dot1;\n\n\t\t\treturn Inverse * OneOverDeterminant;\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<C, R, T, Q> matrixCompMult(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'matrixCompMult' only accept floating-point inputs\");\n\t\treturn detail::compute_matrixCompMult<C, R, T, Q, detail::is_aligned<Q>::value>::call(x, y);\n\t}\n\n\ttemplate<length_t DA, length_t DB, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename detail::outerProduct_trait<DA, DB, T, Q>::type outerProduct(vec<DA, T, Q> const& c, vec<DB, T, Q> const& r)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'outerProduct' only accept floating-point inputs\");\n\n\t\ttypename detail::outerProduct_trait<DA, DB, T, Q>::type m;\n\t\tfor(length_t i = 0; i < m.length(); ++i)\n\t\t\tm[i] = c * r[i];\n\t\treturn m;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<C, R, T, Q>::transpose_type transpose(mat<C, R, T, Q> const& m)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'transpose' only accept floating-point inputs\");\n\t\treturn detail::compute_transpose<C, R, T, Q, detail::is_aligned<Q>::value>::call(m);\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T determinant(mat<C, R, T, Q> const& m)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'determinant' only accept floating-point inputs\");\n\t\treturn detail::compute_determinant<C, R, T, Q, detail::is_aligned<Q>::value>::call(m);\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<C, R, T, Q> inverse(mat<C, R, T, Q> const& m)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"'inverse' only accept floating-point inputs\");\n\t\treturn detail::compute_inverse<C, R, T, Q, detail::is_aligned<Q>::value>::call(m);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_matrix_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/func_matrix_simd.inl",
    "content": "#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n#include \"type_mat4x4.hpp\"\n#include \"../geometric.hpp\"\n#include \"../simd/matrix.h\"\n#include <cstring>\n\nnamespace glm{\nnamespace detail\n{\n#\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n\ttemplate<qualifier Q>\n\tstruct compute_matrixCompMult<4, 4, float, Q, true>\n\t{\n\t\tGLM_STATIC_ASSERT(detail::is_aligned<Q>::value, \"Specialization requires aligned\");\n\n\t\tGLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& x, mat<4, 4, float, Q> const& y)\n\t\t{\n\t\t\tmat<4, 4, float, Q> Result;\n\t\t\tglm_mat4_matrixCompMult(\n\t\t\t\t*static_cast<glm_vec4 const (*)[4]>(&x[0].data),\n\t\t\t\t*static_cast<glm_vec4 const (*)[4]>(&y[0].data),\n\t\t\t\t*static_cast<glm_vec4(*)[4]>(&Result[0].data));\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_transpose<4, 4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m)\n\t\t{\n\t\t\tmat<4, 4, float, Q> Result;\n\t\t\tglm_mat4_transpose(&m[0].data, &Result[0].data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_determinant<4, 4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static float call(mat<4, 4, float, Q> const& m)\n\t\t{\n\t\t\treturn _mm_cvtss_f32(glm_mat4_determinant(&m[0].data));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_inverse<4, 4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m)\n\t\t{\n\t\t\tmat<4, 4, float, Q> Result;\n\t\t\tglm_mat4_inverse(&m[0].data, &Result[0].data);\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n\n#\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER mat<4, 4, float, aligned_lowp> outerProduct<4, 4, float, aligned_lowp>(vec<4, float, aligned_lowp> const& c, vec<4, float, aligned_lowp> const& r)\n\t{\n\t\t__m128 NativeResult[4];\n\t\tglm_mat4_outerProduct(c.data, r.data, NativeResult);\n\t\tmat<4, 4, float, aligned_lowp> Result;\n\t\tstd::memcpy(&Result[0], &NativeResult[0], sizeof(Result));\n\t\treturn Result;\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER mat<4, 4, float, aligned_mediump> outerProduct<4, 4, float, aligned_mediump>(vec<4, float, aligned_mediump> const& c, vec<4, float, aligned_mediump> const& r)\n\t{\n\t\t__m128 NativeResult[4];\n\t\tglm_mat4_outerProduct(c.data, r.data, NativeResult);\n\t\tmat<4, 4, float, aligned_mediump> Result;\n\t\tstd::memcpy(&Result[0], &NativeResult[0], sizeof(Result));\n\t\treturn Result;\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER mat<4, 4, float, aligned_highp> outerProduct<4, 4, float, aligned_highp>(vec<4, float, aligned_highp> const& c, vec<4, float, aligned_highp> const& r)\n\t{\n\t\t__m128 NativeResult[4];\n\t\tglm_mat4_outerProduct(c.data, r.data, NativeResult);\n\t\tmat<4, 4, float, aligned_highp> Result;\n\t\tstd::memcpy(&Result[0], &NativeResult[0], sizeof(Result));\n\t\treturn Result;\n\t}\n#\tendif\n}//namespace glm\n\n#elif GLM_ARCH & GLM_ARCH_NEON_BIT\n\nnamespace glm {\n#if GLM_LANG & GLM_LANG_CXX11_FLAG\n\ttemplate <qualifier Q>\n\tGLM_FUNC_QUALIFIER\n\ttypename std::enable_if<detail::is_aligned<Q>::value, mat<4, 4, float, Q>>::type\n\toperator*(mat<4, 4, float, Q> const & m1, mat<4, 4, float, Q> const & m2)\n\t{\n\t\tauto MulRow = [&](int l) {\n\t\t\tfloat32x4_t const SrcA = m2[l].data;\n\n\t\t\tfloat32x4_t r = neon::mul_lane(m1[0].data, SrcA, 0);\n\t\t\tr = neon::madd_lane(r, m1[1].data, SrcA, 1);\n\t\t\tr = neon::madd_lane(r, m1[2].data, SrcA, 2);\n\t\t\tr = neon::madd_lane(r, m1[3].data, SrcA, 3);\n\n\t\t\treturn r;\n\t\t};\n\n\t\tmat<4, 4, float, aligned_highp> Result;\n\t\tResult[0].data = MulRow(0);\n\t\tResult[1].data = MulRow(1);\n\t\tResult[2].data = MulRow(2);\n\t\tResult[3].data = MulRow(3);\n\n\t\treturn Result;\n\t}\n#endif // CXX11\n\n\ttemplate<qualifier Q>\n\tstruct detail::compute_inverse<4, 4, float, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static mat<4, 4, float, Q> call(mat<4, 4, float, Q> const& m)\n\t\t{\n\t\t\tfloat32x4_t const& m0 = m[0].data;\n\t\t\tfloat32x4_t const& m1 = m[1].data;\n\t\t\tfloat32x4_t const& m2 = m[2].data;\n\t\t\tfloat32x4_t const& m3 = m[3].data;\n\n\t\t\t// m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t\t// m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t\t// m[1][2] * m[3][3] - m[3][2] * m[1][3];\n\t\t\t// m[1][2] * m[2][3] - m[2][2] * m[1][3];\n\n\t\t\tfloat32x4_t Fac0;\n\t\t\t{\n\t\t\t\tfloat32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2));\n\t\t\t\tfloat32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3);\n\t\t\t\tfloat32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2);\n\t\t\t\tfloat32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3));\n\t\t\t\tFac0 = w0 * w1 -  w2 * w3;\n\t\t\t}\n\n\t\t\t// m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t\t// m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t\t// m[1][1] * m[3][3] - m[3][1] * m[1][3];\n\t\t\t// m[1][1] * m[2][3] - m[2][1] * m[1][3];\n\n\t\t\tfloat32x4_t Fac1;\n\t\t\t{\n\t\t\t\tfloat32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1));\n\t\t\t\tfloat32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3);\n\t\t\t\tfloat32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1);\n\t\t\t\tfloat32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3));\n\t\t\t\tFac1 = w0 * w1 - w2 * w3;\n\t\t\t}\n\n\t\t\t// m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t\t// m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t\t// m[1][1] * m[3][2] - m[3][1] * m[1][2];\n\t\t\t// m[1][1] * m[2][2] - m[2][1] * m[1][2];\n\n\t\t\tfloat32x4_t Fac2;\n\t\t\t{\n\t\t\t\tfloat32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1));\n\t\t\t\tfloat32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2);\n\t\t\t\tfloat32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1);\n\t\t\t\tfloat32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2));\n\t\t\t\tFac2 = w0 * w1 - w2 * w3;\n\t\t\t}\n\n\t\t\t// m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t\t// m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t\t// m[1][0] * m[3][3] - m[3][0] * m[1][3];\n\t\t\t// m[1][0] * m[2][3] - m[2][0] * m[1][3];\n\n\t\t\tfloat32x4_t Fac3;\n\t\t\t{\n\t\t\t\tfloat32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0));\n\t\t\t\tfloat32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 3), 3, m2, 3);\n\t\t\t\tfloat32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0);\n\t\t\t\tfloat32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 3), neon::dup_lane(m1, 3));\n\t\t\t\tFac3 = w0 * w1 - w2 * w3;\n\t\t\t}\n\n\t\t\t// m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t\t// m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t\t// m[1][0] * m[3][2] - m[3][0] * m[1][2];\n\t\t\t// m[1][0] * m[2][2] - m[2][0] * m[1][2];\n\n\t\t\tfloat32x4_t Fac4;\n\t\t\t{\n\t\t\t\tfloat32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0));\n\t\t\t\tfloat32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 2), 3, m2, 2);\n\t\t\t\tfloat32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0);\n\t\t\t\tfloat32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 2), neon::dup_lane(m1, 2));\n\t\t\t\tFac4 = w0 * w1 - w2 * w3;\n\t\t\t}\n\n\t\t\t// m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t\t// m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t\t// m[1][0] * m[3][1] - m[3][0] * m[1][1];\n\t\t\t// m[1][0] * m[2][1] - m[2][0] * m[1][1];\n\n\t\t\tfloat32x4_t Fac5;\n\t\t\t{\n\t\t\t\tfloat32x4_t w0 = vcombine_f32(neon::dup_lane(m2, 0), neon::dup_lane(m1, 0));\n\t\t\t\tfloat32x4_t w1 = neon::copy_lane(neon::dupq_lane(m3, 1), 3, m2, 1);\n\t\t\t\tfloat32x4_t w2 = neon::copy_lane(neon::dupq_lane(m3, 0), 3, m2, 0);\n\t\t\t\tfloat32x4_t w3 = vcombine_f32(neon::dup_lane(m2, 1), neon::dup_lane(m1, 1));\n\t\t\t\tFac5 = w0 * w1 - w2 * w3;\n\t\t\t}\n\n\t\t\tfloat32x4_t Vec0 = neon::copy_lane(neon::dupq_lane(m0, 0), 0, m1, 0); // (m[1][0], m[0][0], m[0][0], m[0][0]);\n\t\t\tfloat32x4_t Vec1 = neon::copy_lane(neon::dupq_lane(m0, 1), 0, m1, 1); // (m[1][1], m[0][1], m[0][1], m[0][1]);\n\t\t\tfloat32x4_t Vec2 = neon::copy_lane(neon::dupq_lane(m0, 2), 0, m1, 2); // (m[1][2], m[0][2], m[0][2], m[0][2]);\n\t\t\tfloat32x4_t Vec3 = neon::copy_lane(neon::dupq_lane(m0, 3), 0, m1, 3); // (m[1][3], m[0][3], m[0][3], m[0][3]);\n\n\t\t\tfloat32x4_t Inv0 = Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2;\n\t\t\tfloat32x4_t Inv1 = Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4;\n\t\t\tfloat32x4_t Inv2 = Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5;\n\t\t\tfloat32x4_t Inv3 = Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5;\n\n\t\t\tfloat32x4_t r0 = float32x4_t{-1, +1, -1, +1} * Inv0;\n\t\t\tfloat32x4_t r1 = float32x4_t{+1, -1, +1, -1} * Inv1;\n\t\t\tfloat32x4_t r2 = float32x4_t{-1, +1, -1, +1} * Inv2;\n\t\t\tfloat32x4_t r3 = float32x4_t{+1, -1, +1, -1} * Inv3;\n\n\t\t\tfloat32x4_t det = neon::mul_lane(r0, m0, 0);\n\t\t\tdet = neon::madd_lane(det, r1, m0, 1);\n\t\t\tdet = neon::madd_lane(det, r2, m0, 2);\n\t\t\tdet = neon::madd_lane(det, r3, m0, 3);\n\n\t\t\tfloat32x4_t rdet = vdupq_n_f32(1 / vgetq_lane_f32(det, 0));\n\n\t\t\tmat<4, 4, float, Q> r;\n\t\t\tr[0].data = vmulq_f32(r0, rdet);\n\t\t\tr[1].data = vmulq_f32(r1, rdet);\n\t\t\tr[2].data = vmulq_f32(r2, rdet);\n\t\t\tr[3].data = vmulq_f32(r3, rdet);\n\t\t\treturn r;\n\t\t}\n\t};\n}//namespace glm\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/func_packing.inl",
    "content": "/// @ref core\n/// @file glm/detail/func_packing.inl\n\n#include \"../common.hpp\"\n#include \"type_half.hpp\"\n\nnamespace glm\n{\n\tGLM_FUNC_QUALIFIER uint packUnorm2x16(vec2 const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tunsigned short in[2];\n\t\t\tuint out;\n\t\t} u;\n\n\t\tvec<2, unsigned short, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 65535.0f));\n\n\t\tu.in[0] = result[0];\n\t\tu.in[1] = result[1];\n\n\t\treturn u.out;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec2 unpackUnorm2x16(uint p)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint in;\n\t\t\tunsigned short out[2];\n\t\t} u;\n\n\t\tu.in = p;\n\n\t\treturn vec2(u.out[0], u.out[1]) * 1.5259021896696421759365224689097e-5f;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint packSnorm2x16(vec2 const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tsigned short in[2];\n\t\t\tuint out;\n\t\t} u;\n \n\t\tvec<2, short, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 32767.0f));\n\n\t\tu.in[0] = result[0];\n\t\tu.in[1] = result[1];\n\n\t\treturn u.out;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec2 unpackSnorm2x16(uint p)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint in;\n\t\t\tsigned short out[2];\n\t\t} u;\n\n\t\tu.in = p;\n\n\t\treturn clamp(vec2(u.out[0], u.out[1]) * 3.0518509475997192297128208258309e-5f, -1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint packUnorm4x8(vec4 const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tunsigned char in[4];\n\t\t\tuint out;\n\t\t} u;\n\n\t\tvec<4, unsigned char, defaultp> result(round(clamp(v, 0.0f, 1.0f) * 255.0f));\n\n\t\tu.in[0] = result[0];\n\t\tu.in[1] = result[1];\n\t\tu.in[2] = result[2];\n\t\tu.in[3] = result[3];\n\n\t\treturn u.out;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackUnorm4x8(uint p)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint in;\n\t\t\tunsigned char out[4];\n\t\t} u;\n\n\t\tu.in = p;\n\n\t\treturn vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0039215686274509803921568627451f;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint packSnorm4x8(vec4 const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tsigned char in[4];\n\t\t\tuint out;\n\t\t} u;\n\n\t\tvec<4, signed char, defaultp> result(round(clamp(v, -1.0f, 1.0f) * 127.0f));\n\n\t\tu.in[0] = result[0];\n\t\tu.in[1] = result[1];\n\t\tu.in[2] = result[2];\n\t\tu.in[3] = result[3];\n\n\t\treturn u.out;\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::vec4 unpackSnorm4x8(uint p)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint in;\n\t\t\tsigned char out[4];\n\t\t} u;\n\n\t\tu.in = p;\n\n\t\treturn clamp(vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0078740157480315f, -1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER double packDouble2x32(uvec2 const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint   in[2];\n\t\t\tdouble out;\n\t\t} u;\n\n\t\tu.in[0] = v[0];\n\t\tu.in[1] = v[1];\n\n\t\treturn u.out;\n\t}\n\n\tGLM_FUNC_QUALIFIER uvec2 unpackDouble2x32(double v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tdouble in;\n\t\t\tuint   out[2];\n\t\t} u;\n\n\t\tu.in = v;\n\n\t\treturn uvec2(u.out[0], u.out[1]);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint packHalf2x16(vec2 const& v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tsigned short in[2];\n\t\t\tuint out;\n\t\t} u;\n\n\t\tu.in[0] = detail::toFloat16(v.x);\n\t\tu.in[1] = detail::toFloat16(v.y);\n\n\t\treturn u.out;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec2 unpackHalf2x16(uint v)\n\t{\n\t\tunion\n\t\t{\n\t\t\tuint in;\n\t\t\tsigned short out[2];\n\t\t} u;\n\n\t\tu.in = v;\n\n\t\treturn vec2(\n\t\t\tdetail::toFloat32(u.out[0]),\n\t\t\tdetail::toFloat32(u.out[1]));\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_packing_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/func_packing_simd.inl",
    "content": "namespace glm{\nnamespace detail\n{\n\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/func_trigonometric.inl",
    "content": "#include \"_vectorize.hpp\"\n#include <cmath>\n#include <limits>\n\nnamespace glm\n{\n\t// radians\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType radians(genType degrees)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'radians' only accept floating-point input\");\n\n\t\treturn degrees * static_cast<genType>(0.01745329251994329576923690768489);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> radians(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(radians, v);\n\t}\n\n\t// degrees\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType degrees(genType radians)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'degrees' only accept floating-point input\");\n\n\t\treturn radians * static_cast<genType>(57.295779513082320876798154814105);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> degrees(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(degrees, v);\n\t}\n\n\t// sin\n\tusing ::std::sin;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> sin(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(sin, v);\n\t}\n\n\t// cos\n\tusing std::cos;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> cos(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(cos, v);\n\t}\n\n\t// tan\n\tusing std::tan;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> tan(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(tan, v);\n\t}\n\n\t// asin\n\tusing std::asin;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> asin(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(asin, v);\n\t}\n\n\t// acos\n\tusing std::acos;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> acos(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(acos, v);\n\t}\n\n\t// atan\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType atan(genType y, genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'atan' only accept floating-point input\");\n\n\t\treturn ::std::atan2(y, x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> atan(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(::std::atan2, a, b);\n\t}\n\n\tusing std::atan;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> atan(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(atan, v);\n\t}\n\n\t// sinh\n\tusing std::sinh;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> sinh(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(sinh, v);\n\t}\n\n\t// cosh\n\tusing std::cosh;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> cosh(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(cosh, v);\n\t}\n\n\t// tanh\n\tusing std::tanh;\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> tanh(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(tanh, v);\n\t}\n\n\t// asinh\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::asinh;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER genType asinh(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'asinh' only accept floating-point input\");\n\n\t\t\treturn (x < static_cast<genType>(0) ? static_cast<genType>(-1) : (x > static_cast<genType>(0) ? static_cast<genType>(1) : static_cast<genType>(0))) * log(std::abs(x) + sqrt(static_cast<genType>(1) + x * x));\n\t\t}\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> asinh(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(asinh, v);\n\t}\n\n\t// acosh\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::acosh;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER genType acosh(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'acosh' only accept floating-point input\");\n\n\t\t\tif(x < static_cast<genType>(1))\n\t\t\t\treturn static_cast<genType>(0);\n\t\t\treturn log(x + sqrt(x * x - static_cast<genType>(1)));\n\t\t}\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> acosh(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(acosh, v);\n\t}\n\n\t// atanh\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::atanh;\n#\telse\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER genType atanh(genType x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'atanh' only accept floating-point input\");\n\n\t\t\tif(std::abs(x) >= static_cast<genType>(1))\n\t\t\t\treturn 0;\n\t\t\treturn static_cast<genType>(0.5) * log((static_cast<genType>(1) + x) / (static_cast<genType>(1) - x));\n\t\t}\n#\tendif\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> atanh(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(atanh, v);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_trigonometric_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/func_trigonometric_simd.inl",
    "content": ""
  },
  {
    "path": "lib/gli/glm/detail/func_vector_relational.inl",
    "content": "namespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> lessThan(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = x[i] < y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> lessThanEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = x[i] <= y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> greaterThan(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = x[i] > y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> greaterThanEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = x[i] >= y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = x[i] == y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = x[i] != y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool any(vec<L, bool, Q> const& v)\n\t{\n\t\tbool Result = false;\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult = Result || v[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool all(vec<L, bool, Q> const& v)\n\t{\n\t\tbool Result = true;\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult = Result && v[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> not_(vec<L, bool, Q> const& v)\n\t{\n\t\tvec<L, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t\tResult[i] = !v[i];\n\t\treturn Result;\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"func_vector_relational_simd.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/func_vector_relational_simd.inl",
    "content": "namespace glm{\nnamespace detail\n{\n\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/glm.cpp",
    "content": "/// @ref core\n/// @file glm/glm.cpp\n\n#ifndef GLM_ENABLE_EXPERIMENTAL\n#define GLM_ENABLE_EXPERIMENTAL\n#endif\n#include <glm/gtx/dual_quaternion.hpp>\n#include <glm/gtc/vec1.hpp>\n#include <glm/gtc/quaternion.hpp>\n#include <glm/ext/scalar_int_sized.hpp>\n#include <glm/ext/scalar_uint_sized.hpp>\n#include <glm/glm.hpp>\n\nnamespace glm\n{\n// tvec1 type explicit instantiation\ntemplate struct vec<1, uint8, lowp>;\ntemplate struct vec<1, uint16, lowp>;\ntemplate struct vec<1, uint32, lowp>;\ntemplate struct vec<1, uint64, lowp>;\ntemplate struct vec<1, int8, lowp>;\ntemplate struct vec<1, int16, lowp>;\ntemplate struct vec<1, int32, lowp>;\ntemplate struct vec<1, int64, lowp>;\ntemplate struct vec<1, float32, lowp>;\ntemplate struct vec<1, float64, lowp>;\n\ntemplate struct vec<1, uint8, mediump>;\ntemplate struct vec<1, uint16, mediump>;\ntemplate struct vec<1, uint32, mediump>;\ntemplate struct vec<1, uint64, mediump>;\ntemplate struct vec<1, int8, mediump>;\ntemplate struct vec<1, int16, mediump>;\ntemplate struct vec<1, int32, mediump>;\ntemplate struct vec<1, int64, mediump>;\ntemplate struct vec<1, float32, mediump>;\ntemplate struct vec<1, float64, mediump>;\n\ntemplate struct vec<1, uint8, highp>;\ntemplate struct vec<1, uint16, highp>;\ntemplate struct vec<1, uint32, highp>;\ntemplate struct vec<1, uint64, highp>;\ntemplate struct vec<1, int8, highp>;\ntemplate struct vec<1, int16, highp>;\ntemplate struct vec<1, int32, highp>;\ntemplate struct vec<1, int64, highp>;\ntemplate struct vec<1, float32, highp>;\ntemplate struct vec<1, float64, highp>;\n\n// tvec2 type explicit instantiation\ntemplate struct vec<2, uint8, lowp>;\ntemplate struct vec<2, uint16, lowp>;\ntemplate struct vec<2, uint32, lowp>;\ntemplate struct vec<2, uint64, lowp>;\ntemplate struct vec<2, int8, lowp>;\ntemplate struct vec<2, int16, lowp>;\ntemplate struct vec<2, int32, lowp>;\ntemplate struct vec<2, int64, lowp>;\ntemplate struct vec<2, float32, lowp>;\ntemplate struct vec<2, float64, lowp>;\n\ntemplate struct vec<2, uint8, mediump>;\ntemplate struct vec<2, uint16, mediump>;\ntemplate struct vec<2, uint32, mediump>;\ntemplate struct vec<2, uint64, mediump>;\ntemplate struct vec<2, int8, mediump>;\ntemplate struct vec<2, int16, mediump>;\ntemplate struct vec<2, int32, mediump>;\ntemplate struct vec<2, int64, mediump>;\ntemplate struct vec<2, float32, mediump>;\ntemplate struct vec<2, float64, mediump>;\n\ntemplate struct vec<2, uint8, highp>;\ntemplate struct vec<2, uint16, highp>;\ntemplate struct vec<2, uint32, highp>;\ntemplate struct vec<2, uint64, highp>;\ntemplate struct vec<2, int8, highp>;\ntemplate struct vec<2, int16, highp>;\ntemplate struct vec<2, int32, highp>;\ntemplate struct vec<2, int64, highp>;\ntemplate struct vec<2, float32, highp>;\ntemplate struct vec<2, float64, highp>;\n\n// tvec3 type explicit instantiation\ntemplate struct vec<3, uint8, lowp>;\ntemplate struct vec<3, uint16, lowp>;\ntemplate struct vec<3, uint32, lowp>;\ntemplate struct vec<3, uint64, lowp>;\ntemplate struct vec<3, int8, lowp>;\ntemplate struct vec<3, int16, lowp>;\ntemplate struct vec<3, int32, lowp>;\ntemplate struct vec<3, int64, lowp>;\ntemplate struct vec<3, float32, lowp>;\ntemplate struct vec<3, float64, lowp>;\n\ntemplate struct vec<3, uint8, mediump>;\ntemplate struct vec<3, uint16, mediump>;\ntemplate struct vec<3, uint32, mediump>;\ntemplate struct vec<3, uint64, mediump>;\ntemplate struct vec<3, int8, mediump>;\ntemplate struct vec<3, int16, mediump>;\ntemplate struct vec<3, int32, mediump>;\ntemplate struct vec<3, int64, mediump>;\ntemplate struct vec<3, float32, mediump>;\ntemplate struct vec<3, float64, mediump>;\n\ntemplate struct vec<3, uint8, highp>;\ntemplate struct vec<3, uint16, highp>;\ntemplate struct vec<3, uint32, highp>;\ntemplate struct vec<3, uint64, highp>;\ntemplate struct vec<3, int8, highp>;\ntemplate struct vec<3, int16, highp>;\ntemplate struct vec<3, int32, highp>;\ntemplate struct vec<3, int64, highp>;\ntemplate struct vec<3, float32, highp>;\ntemplate struct vec<3, float64, highp>;\n\n// tvec4 type explicit instantiation\ntemplate struct vec<4, uint8, lowp>;\ntemplate struct vec<4, uint16, lowp>;\ntemplate struct vec<4, uint32, lowp>;\ntemplate struct vec<4, uint64, lowp>;\ntemplate struct vec<4, int8, lowp>;\ntemplate struct vec<4, int16, lowp>;\ntemplate struct vec<4, int32, lowp>;\ntemplate struct vec<4, int64, lowp>;\ntemplate struct vec<4, float32, lowp>;\ntemplate struct vec<4, float64, lowp>;\n\ntemplate struct vec<4, uint8, mediump>;\ntemplate struct vec<4, uint16, mediump>;\ntemplate struct vec<4, uint32, mediump>;\ntemplate struct vec<4, uint64, mediump>;\ntemplate struct vec<4, int8, mediump>;\ntemplate struct vec<4, int16, mediump>;\ntemplate struct vec<4, int32, mediump>;\ntemplate struct vec<4, int64, mediump>;\ntemplate struct vec<4, float32, mediump>;\ntemplate struct vec<4, float64, mediump>;\n\ntemplate struct vec<4, uint8, highp>;\ntemplate struct vec<4, uint16, highp>;\ntemplate struct vec<4, uint32, highp>;\ntemplate struct vec<4, uint64, highp>;\ntemplate struct vec<4, int8, highp>;\ntemplate struct vec<4, int16, highp>;\ntemplate struct vec<4, int32, highp>;\ntemplate struct vec<4, int64, highp>;\ntemplate struct vec<4, float32, highp>;\ntemplate struct vec<4, float64, highp>;\n\n// tmat2x2 type explicit instantiation\ntemplate struct mat<2, 2, float32, lowp>;\ntemplate struct mat<2, 2, float64, lowp>;\n\ntemplate struct mat<2, 2, float32, mediump>;\ntemplate struct mat<2, 2, float64, mediump>;\n\ntemplate struct mat<2, 2, float32, highp>;\ntemplate struct mat<2, 2, float64, highp>;\n\n// tmat2x3 type explicit instantiation\ntemplate struct mat<2, 3, float32, lowp>;\ntemplate struct mat<2, 3, float64, lowp>;\n\ntemplate struct mat<2, 3, float32, mediump>;\ntemplate struct mat<2, 3, float64, mediump>;\n\ntemplate struct mat<2, 3, float32, highp>;\ntemplate struct mat<2, 3, float64, highp>;\n\n// tmat2x4 type explicit instantiation\ntemplate struct mat<2, 4, float32, lowp>;\ntemplate struct mat<2, 4, float64, lowp>;\n\ntemplate struct mat<2, 4, float32, mediump>;\ntemplate struct mat<2, 4, float64, mediump>;\n\ntemplate struct mat<2, 4, float32, highp>;\ntemplate struct mat<2, 4, float64, highp>;\n\n// tmat3x2 type explicit instantiation\ntemplate struct mat<3, 2, float32, lowp>;\ntemplate struct mat<3, 2, float64, lowp>;\n\ntemplate struct mat<3, 2, float32, mediump>;\ntemplate struct mat<3, 2, float64, mediump>;\n\ntemplate struct mat<3, 2, float32, highp>;\ntemplate struct mat<3, 2, float64, highp>;\n\n// tmat3x3 type explicit instantiation\ntemplate struct mat<3, 3, float32, lowp>;\ntemplate struct mat<3, 3, float64, lowp>;\n\ntemplate struct mat<3, 3, float32, mediump>;\ntemplate struct mat<3, 3, float64, mediump>;\n\ntemplate struct mat<3, 3, float32, highp>;\ntemplate struct mat<3, 3, float64, highp>;\n\n// tmat3x4 type explicit instantiation\ntemplate struct mat<3, 4, float32, lowp>;\ntemplate struct mat<3, 4, float64, lowp>;\n\ntemplate struct mat<3, 4, float32, mediump>;\ntemplate struct mat<3, 4, float64, mediump>;\n\ntemplate struct mat<3, 4, float32, highp>;\ntemplate struct mat<3, 4, float64, highp>;\n\n// tmat4x2 type explicit instantiation\ntemplate struct mat<4, 2, float32, lowp>;\ntemplate struct mat<4, 2, float64, lowp>;\n\ntemplate struct mat<4, 2, float32, mediump>;\ntemplate struct mat<4, 2, float64, mediump>;\n\ntemplate struct mat<4, 2, float32, highp>;\ntemplate struct mat<4, 2, float64, highp>;\n\n// tmat4x3 type explicit instantiation\ntemplate struct mat<4, 3, float32, lowp>;\ntemplate struct mat<4, 3, float64, lowp>;\n\ntemplate struct mat<4, 3, float32, mediump>;\ntemplate struct mat<4, 3, float64, mediump>;\n\ntemplate struct mat<4, 3, float32, highp>;\ntemplate struct mat<4, 3, float64, highp>;\n\n// tmat4x4 type explicit instantiation\ntemplate struct mat<4, 4, float32, lowp>;\ntemplate struct mat<4, 4, float64, lowp>;\n\ntemplate struct mat<4, 4, float32, mediump>;\ntemplate struct mat<4, 4, float64, mediump>;\n\ntemplate struct mat<4, 4, float32, highp>;\ntemplate struct mat<4, 4, float64, highp>;\n\n// tquat type explicit instantiation\ntemplate struct qua<float32, lowp>;\ntemplate struct qua<float64, lowp>;\n\ntemplate struct qua<float32, mediump>;\ntemplate struct qua<float64, mediump>;\n\ntemplate struct qua<float32, highp>;\ntemplate struct qua<float64, highp>;\n\n//tdualquat type explicit instantiation\ntemplate struct tdualquat<float32, lowp>;\ntemplate struct tdualquat<float64, lowp>;\n\ntemplate struct tdualquat<float32, mediump>;\ntemplate struct tdualquat<float64, mediump>;\n\ntemplate struct tdualquat<float32, highp>;\ntemplate struct tdualquat<float64, highp>;\n\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/detail/qualifier.hpp",
    "content": "#pragma once\n\n#include \"setup.hpp\"\n\nnamespace glm\n{\n\t/// Qualify GLM types in term of alignment (packed, aligned) and precision in term of ULPs (lowp, mediump, highp)\n\tenum qualifier\n\t{\n\t\tpacked_highp, ///< Typed data is tightly packed in memory and operations are executed with high precision in term of ULPs\n\t\tpacked_mediump, ///< Typed data is tightly packed in memory  and operations are executed with medium precision in term of ULPs for higher performance\n\t\tpacked_lowp, ///< Typed data is tightly packed in memory  and operations are executed with low precision in term of ULPs to maximize performance\n\n#\t\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n\t\t\taligned_highp, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs\n\t\t\taligned_mediump, ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs for higher performance\n\t\t\taligned_lowp, // ///< Typed data is aligned in memory allowing SIMD optimizations and operations are executed with high precision in term of ULPs to maximize performance\n\t\t\taligned = aligned_highp, ///< By default aligned qualifier is also high precision\n#\t\tendif\n\n\t\thighp = packed_highp, ///< By default highp qualifier is also packed\n\t\tmediump = packed_mediump, ///< By default mediump qualifier is also packed\n\t\tlowp = packed_lowp, ///< By default lowp qualifier is also packed\n\t\tpacked = packed_highp, ///< By default packed qualifier is also high precision\n\n#\t\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE && defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES)\n\t\t\tdefaultp = aligned_highp\n#\t\telse\n\t\t\tdefaultp = highp\n#\t\tendif\n\t};\n\n\ttypedef qualifier precision;\n\n\ttemplate<length_t L, typename T, qualifier Q = defaultp> struct vec;\n\ttemplate<length_t C, length_t R, typename T, qualifier Q = defaultp> struct mat;\n\ttemplate<typename T, qualifier Q = defaultp> struct qua;\n\n#\tif GLM_HAS_TEMPLATE_ALIASES\n\t\ttemplate <typename T, qualifier Q = defaultp> using tvec1 = vec<1, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tvec2 = vec<2, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tvec3 = vec<3, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tvec4 = vec<4, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat2x2 = mat<2, 2, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat2x3 = mat<2, 3, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat2x4 = mat<2, 4, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat3x2 = mat<3, 2, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat3x3 = mat<3, 3, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat3x4 = mat<3, 4, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat4x2 = mat<4, 2, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat4x3 = mat<4, 3, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tmat4x4 = mat<4, 4, T, Q>;\n\t\ttemplate <typename T, qualifier Q = defaultp> using tquat = qua<T, Q>;\n#\tendif\n\nnamespace detail\n{\n\ttemplate<glm::qualifier P>\n\tstruct is_aligned\n\t{\n\t\tstatic const bool value = false;\n\t};\n\n#\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n\t\ttemplate<>\n\t\tstruct is_aligned<glm::aligned_lowp>\n\t\t{\n\t\t\tstatic const bool value = true;\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct is_aligned<glm::aligned_mediump>\n\t\t{\n\t\t\tstatic const bool value = true;\n\t\t};\n\n\t\ttemplate<>\n\t\tstruct is_aligned<glm::aligned_highp>\n\t\t{\n\t\t\tstatic const bool value = true;\n\t\t};\n#\tendif\n\n\ttemplate<length_t L, typename T, bool is_aligned>\n\tstruct storage\n\t{\n\t\ttypedef struct type {\n\t\t\tT data[L];\n\t\t} type;\n\t};\n\n#\tif GLM_HAS_ALIGNOF\n\t\ttemplate<length_t L, typename T>\n\t\tstruct storage<L, T, true>\n\t\t{\n\t\t\ttypedef struct alignas(L * sizeof(T)) type {\n\t\t\t\tT data[L];\n\t\t\t} type;\n\t\t};\n\n\t\ttemplate<typename T>\n\t\tstruct storage<3, T, true>\n\t\t{\n\t\t\ttypedef struct alignas(4 * sizeof(T)) type {\n\t\t\t\tT data[4];\n\t\t\t} type;\n\t\t};\n#\tendif\n\n#\tif GLM_ARCH & GLM_ARCH_SSE2_BIT\n\ttemplate<>\n\tstruct storage<4, float, true>\n\t{\n\t\ttypedef glm_f32vec4 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<4, int, true>\n\t{\n\t\ttypedef glm_i32vec4 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<4, unsigned int, true>\n\t{\n\t\ttypedef glm_u32vec4 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<2, double, true>\n\t{\n\t\ttypedef glm_f64vec2 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<2, detail::int64, true>\n\t{\n\t\ttypedef glm_i64vec2 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<2, detail::uint64, true>\n\t{\n\t\ttypedef glm_u64vec2 type;\n\t};\n#\tendif\n\n#\tif (GLM_ARCH & GLM_ARCH_AVX_BIT)\n\ttemplate<>\n\tstruct storage<4, double, true>\n\t{\n\t\ttypedef glm_f64vec4 type;\n\t};\n#\tendif\n\n#\tif (GLM_ARCH & GLM_ARCH_AVX2_BIT)\n\ttemplate<>\n\tstruct storage<4, detail::int64, true>\n\t{\n\t\ttypedef glm_i64vec4 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<4, detail::uint64, true>\n\t{\n\t\ttypedef glm_u64vec4 type;\n\t};\n#\tendif\n\n#\tif GLM_ARCH & GLM_ARCH_NEON_BIT\n\ttemplate<>\n\tstruct storage<4, float, true>\n\t{\n\t\ttypedef glm_f32vec4 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<4, int, true>\n\t{\n\t\ttypedef glm_i32vec4 type;\n\t};\n\n\ttemplate<>\n\tstruct storage<4, unsigned int, true>\n\t{\n\t\ttypedef glm_u32vec4 type;\n\t};\n#\tendif\n\n\tenum genTypeEnum\n\t{\n\t\tGENTYPE_VEC,\n\t\tGENTYPE_MAT,\n\t\tGENTYPE_QUAT\n\t};\n\n\ttemplate <typename genType>\n\tstruct genTypeTrait\n\t{};\n\n\ttemplate <length_t C, length_t R, typename T>\n\tstruct genTypeTrait<mat<C, R, T> >\n\t{\n\t\tstatic const genTypeEnum GENTYPE = GENTYPE_MAT;\n\t};\n\n\ttemplate<typename genType, genTypeEnum type>\n\tstruct init_gentype\n\t{\n\t};\n\n\ttemplate<typename genType>\n\tstruct init_gentype<genType, GENTYPE_QUAT>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity()\n\t\t{\n\t\t\treturn genType(1, 0, 0, 0);\n\t\t}\n\t};\n\n\ttemplate<typename genType>\n\tstruct init_gentype<genType, GENTYPE_MAT>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static genType identity()\n\t\t{\n\t\t\treturn genType(1);\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/setup.hpp",
    "content": "#ifndef GLM_SETUP_INCLUDED\n\n#include <cassert>\n#include <cstddef>\n\n#define GLM_VERSION_MAJOR 0\n#define GLM_VERSION_MINOR 9\n#define GLM_VERSION_PATCH 9\n#define GLM_VERSION_REVISION 9\n#define GLM_VERSION 999\n#define GLM_VERSION_MESSAGE \"GLM: version 0.9.9.9\"\n\n#define GLM_SETUP_INCLUDED GLM_VERSION\n\n///////////////////////////////////////////////////////////////////////////////////\n// Active states\n\n#define GLM_DISABLE\t\t0\n#define GLM_ENABLE\t\t1\n\n///////////////////////////////////////////////////////////////////////////////////\n// Messages\n\n#if defined(GLM_FORCE_MESSAGES)\n#\tdefine GLM_MESSAGES GLM_ENABLE\n#else\n#\tdefine GLM_MESSAGES GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Detect the platform\n\n#include \"../simd/platform.h\"\n\n///////////////////////////////////////////////////////////////////////////////////\n// Build model\n\n#if defined(_M_ARM64) || defined(__LP64__) || defined(_M_X64) || defined(__ppc64__) || defined(__x86_64__)\n#\tdefine GLM_MODEL\tGLM_MODEL_64\n#elif defined(__i386__) || defined(__ppc__) || defined(__ILP32__) || defined(_M_ARM)\n#\tdefine GLM_MODEL\tGLM_MODEL_32\n#else\n#\tdefine GLM_MODEL\tGLM_MODEL_32\n#endif//\n\n#if !defined(GLM_MODEL) && GLM_COMPILER != 0\n#\terror \"GLM_MODEL undefined, your compiler may not be supported by GLM. Add #define GLM_MODEL 0 to ignore this message.\"\n#endif//GLM_MODEL\n\n///////////////////////////////////////////////////////////////////////////////////\n// C++ Version\n\n// User defines: GLM_FORCE_CXX98, GLM_FORCE_CXX03, GLM_FORCE_CXX11, GLM_FORCE_CXX14, GLM_FORCE_CXX17, GLM_FORCE_CXX2A\n\n#define GLM_LANG_CXX98_FLAG\t\t\t(1 << 1)\n#define GLM_LANG_CXX03_FLAG\t\t\t(1 << 2)\n#define GLM_LANG_CXX0X_FLAG\t\t\t(1 << 3)\n#define GLM_LANG_CXX11_FLAG\t\t\t(1 << 4)\n#define GLM_LANG_CXX14_FLAG\t\t\t(1 << 5)\n#define GLM_LANG_CXX17_FLAG\t\t\t(1 << 6)\n#define GLM_LANG_CXX2A_FLAG\t\t\t(1 << 7)\n#define GLM_LANG_CXXMS_FLAG\t\t\t(1 << 8)\n#define GLM_LANG_CXXGNU_FLAG\t\t(1 << 9)\n\n#define GLM_LANG_CXX98\t\t\tGLM_LANG_CXX98_FLAG\n#define GLM_LANG_CXX03\t\t\t(GLM_LANG_CXX98 | GLM_LANG_CXX03_FLAG)\n#define GLM_LANG_CXX0X\t\t\t(GLM_LANG_CXX03 | GLM_LANG_CXX0X_FLAG)\n#define GLM_LANG_CXX11\t\t\t(GLM_LANG_CXX0X | GLM_LANG_CXX11_FLAG)\n#define GLM_LANG_CXX14\t\t\t(GLM_LANG_CXX11 | GLM_LANG_CXX14_FLAG)\n#define GLM_LANG_CXX17\t\t\t(GLM_LANG_CXX14 | GLM_LANG_CXX17_FLAG)\n#define GLM_LANG_CXX2A\t\t\t(GLM_LANG_CXX17 | GLM_LANG_CXX2A_FLAG)\n#define GLM_LANG_CXXMS\t\t\tGLM_LANG_CXXMS_FLAG\n#define GLM_LANG_CXXGNU\t\t\tGLM_LANG_CXXGNU_FLAG\n\n#if (defined(_MSC_EXTENSIONS))\n#\tdefine GLM_LANG_EXT GLM_LANG_CXXMS_FLAG\n#elif ((GLM_COMPILER & (GLM_COMPILER_CLANG | GLM_COMPILER_GCC)) && (GLM_ARCH & GLM_ARCH_SIMD_BIT))\n#\tdefine GLM_LANG_EXT GLM_LANG_CXXMS_FLAG\n#else\n#\tdefine GLM_LANG_EXT 0\n#endif\n\n#if (defined(GLM_FORCE_CXX_UNKNOWN))\n#\tdefine GLM_LANG 0\n#elif defined(GLM_FORCE_CXX2A)\n#\tdefine GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT)\n#\tdefine GLM_LANG_STL11_FORCED\n#elif defined(GLM_FORCE_CXX17)\n#\tdefine GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT)\n#\tdefine GLM_LANG_STL11_FORCED\n#elif defined(GLM_FORCE_CXX14)\n#\tdefine GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT)\n#\tdefine GLM_LANG_STL11_FORCED\n#elif defined(GLM_FORCE_CXX11)\n#\tdefine GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT)\n#\tdefine GLM_LANG_STL11_FORCED\n#elif defined(GLM_FORCE_CXX03)\n#\tdefine GLM_LANG (GLM_LANG_CXX03 | GLM_LANG_EXT)\n#elif defined(GLM_FORCE_CXX98)\n#\tdefine GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT)\n#else\n#\tif GLM_COMPILER & GLM_COMPILER_VC && defined(_MSVC_LANG)\n#\t\tif GLM_COMPILER >= GLM_COMPILER_VC15_7\n#\t\t\tdefine GLM_LANG_PLATFORM _MSVC_LANG\n#\t\telif GLM_COMPILER >= GLM_COMPILER_VC15\n#\t\t\tif _MSVC_LANG > 201402L\n#\t\t\t\tdefine GLM_LANG_PLATFORM 201402L\n#\t\t\telse\n#\t\t\t\tdefine GLM_LANG_PLATFORM _MSVC_LANG\n#\t\t\tendif\n#\t\telse\n#\t\t\tdefine GLM_LANG_PLATFORM 0\n#\t\tendif\n#\telse\n#\t\tdefine GLM_LANG_PLATFORM 0\n#\tendif\n\n#\tif __cplusplus > 201703L || GLM_LANG_PLATFORM > 201703L\n#\t\tdefine GLM_LANG (GLM_LANG_CXX2A | GLM_LANG_EXT)\n#\telif __cplusplus == 201703L || GLM_LANG_PLATFORM == 201703L\n#\t\tdefine GLM_LANG (GLM_LANG_CXX17 | GLM_LANG_EXT)\n#\telif __cplusplus == 201402L || __cplusplus == 201406L || __cplusplus == 201500L || GLM_LANG_PLATFORM == 201402L\n#\t\tdefine GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_EXT)\n#\telif __cplusplus == 201103L || GLM_LANG_PLATFORM == 201103L\n#\t\tdefine GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_EXT)\n#\telif defined(__INTEL_CXX11_MODE__) || defined(_MSC_VER) || defined(__GXX_EXPERIMENTAL_CXX0X__)\n#\t\tdefine GLM_LANG (GLM_LANG_CXX0X | GLM_LANG_EXT)\n#\telif __cplusplus == 199711L\n#\t\tdefine GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_EXT)\n#\telse\n#\t\tdefine GLM_LANG (0 | GLM_LANG_EXT)\n#\tendif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Has of C++ features\n\n// http://clang.llvm.org/cxx_status.html\n// http://gcc.gnu.org/projects/cxx0x.html\n// http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx\n\n// Android has multiple STLs but C++11 STL detection doesn't always work #284 #564\n#if GLM_PLATFORM == GLM_PLATFORM_ANDROID && !defined(GLM_LANG_STL11_FORCED)\n#\tdefine GLM_HAS_CXX11_STL 0\n#elif GLM_COMPILER & GLM_COMPILER_CLANG\n#\tif (defined(_LIBCPP_VERSION) || (GLM_LANG & GLM_LANG_CXX11_FLAG) || defined(GLM_LANG_STL11_FORCED))\n#\t\tdefine GLM_HAS_CXX11_STL 1\n#\telse\n#\t\tdefine GLM_HAS_CXX11_STL 0\n#\tendif\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_CXX11_STL 1\n#else\n#\tdefine GLM_HAS_CXX11_STL ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \\\n\t\t((GLM_PLATFORM != GLM_PLATFORM_WINDOWS) && (GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15))))\n#endif\n\n// N1720\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_STATIC_ASSERT __has_feature(cxx_static_assert)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_STATIC_ASSERT 1\n#else\n#\tdefine GLM_HAS_STATIC_ASSERT ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC))))\n#endif\n\n// N1988\n#if GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_EXTENDED_INTEGER_TYPE 1\n#else\n#\tdefine GLM_HAS_EXTENDED_INTEGER_TYPE (\\\n\t\t((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_VC)) || \\\n\t\t((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CUDA)) || \\\n\t\t((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CLANG)))\n#endif\n\n// N2672 Initializer lists http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_INITIALIZER_LISTS __has_feature(cxx_generalized_initializers)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_INITIALIZER_LISTS 1\n#else\n#\tdefine GLM_HAS_INITIALIZER_LISTS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n// N2544 Unrestricted unions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_UNRESTRICTED_UNIONS __has_feature(cxx_unrestricted_unions)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_UNRESTRICTED_UNIONS 1\n#else\n#\tdefine GLM_HAS_UNRESTRICTED_UNIONS (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t(GLM_COMPILER & GLM_COMPILER_VC) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA)))\n#endif\n\n// N2346\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_DEFAULTED_FUNCTIONS __has_feature(cxx_defaulted_functions)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_DEFAULTED_FUNCTIONS 1\n#else\n#\tdefine GLM_HAS_DEFAULTED_FUNCTIONS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL)) || \\\n\t\t(GLM_COMPILER & GLM_COMPILER_CUDA)))\n#endif\n\n// N2118\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_RVALUE_REFERENCES 1\n#else\n#\tdefine GLM_HAS_RVALUE_REFERENCES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n// N2437 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_EXPLICIT_CONVERSION_OPERATORS __has_feature(cxx_explicit_conversions)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 1\n#else\n#\tdefine GLM_HAS_EXPLICIT_CONVERSION_OPERATORS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n// N2258 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_TEMPLATE_ALIASES __has_feature(cxx_alias_templates)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_TEMPLATE_ALIASES 1\n#else\n#\tdefine GLM_HAS_TEMPLATE_ALIASES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n// N2930 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_RANGE_FOR __has_feature(cxx_range_for)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_RANGE_FOR 1\n#else\n#\tdefine GLM_HAS_RANGE_FOR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n// N2341 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf\n#if GLM_COMPILER & GLM_COMPILER_CLANG\n#\tdefine GLM_HAS_ALIGNOF __has_feature(cxx_alignas)\n#elif GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_ALIGNOF 1\n#else\n#\tdefine GLM_HAS_ALIGNOF ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n// N2235 Generalized Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf\n// N3652 Extended Constant Expressions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3652.html\n#if (GLM_ARCH & GLM_ARCH_SIMD_BIT) // Compiler SIMD intrinsics don't support constexpr...\n#\tdefine GLM_HAS_CONSTEXPR 0\n#elif (GLM_COMPILER & GLM_COMPILER_CLANG)\n#\tdefine GLM_HAS_CONSTEXPR __has_feature(cxx_relaxed_constexpr)\n#elif (GLM_LANG & GLM_LANG_CXX14_FLAG)\n#\tdefine GLM_HAS_CONSTEXPR 1\n#else\n#\tdefine GLM_HAS_CONSTEXPR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && GLM_HAS_INITIALIZER_LISTS && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL17)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15))))\n#endif\n\n#if GLM_HAS_CONSTEXPR\n#\tdefine GLM_CONSTEXPR constexpr\n#else\n#\tdefine GLM_CONSTEXPR\n#endif\n\n//\n#if GLM_HAS_CONSTEXPR\n# if (GLM_COMPILER & GLM_COMPILER_CLANG)\n#\tif __has_feature(cxx_if_constexpr)\n#\t\tdefine GLM_HAS_IF_CONSTEXPR 1\n#\telse\n# \t\tdefine GLM_HAS_IF_CONSTEXPR 0\n#\tendif\n# elif (GLM_LANG & GLM_LANG_CXX17_FLAG)\n# \tdefine GLM_HAS_IF_CONSTEXPR 1\n# else\n# \tdefine GLM_HAS_IF_CONSTEXPR 0\n# endif\n#else\n#\tdefine GLM_HAS_IF_CONSTEXPR 0\n#endif\n\n#if GLM_HAS_IF_CONSTEXPR\n# \tdefine GLM_IF_CONSTEXPR if constexpr\n#else\n#\tdefine GLM_IF_CONSTEXPR if\n#endif\n\n//\n#if GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_ASSIGNABLE 1\n#else\n#\tdefine GLM_HAS_ASSIGNABLE ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC49))))\n#endif\n\n//\n#define GLM_HAS_TRIVIAL_QUERIES 0\n\n//\n#if GLM_LANG & GLM_LANG_CXX11_FLAG\n#\tdefine GLM_HAS_MAKE_SIGNED 1\n#else\n#\tdefine GLM_HAS_MAKE_SIGNED ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_CUDA))))\n#endif\n\n//\n#if defined(GLM_FORCE_INTRINSICS)\n#\tdefine GLM_HAS_BITSCAN_WINDOWS ((GLM_PLATFORM & GLM_PLATFORM_WINDOWS) && (\\\n\t\t((GLM_COMPILER & GLM_COMPILER_INTEL)) || \\\n\t\t((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14) && (GLM_ARCH & GLM_ARCH_X86_BIT))))\n#else\n#\tdefine GLM_HAS_BITSCAN_WINDOWS 0\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// OpenMP\n#ifdef _OPENMP\n#\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\tif GLM_COMPILER >= GLM_COMPILER_GCC61\n#\t\t\tdefine GLM_HAS_OPENMP 45\n#\t\telif GLM_COMPILER >= GLM_COMPILER_GCC49\n#\t\t\tdefine GLM_HAS_OPENMP 40\n#\t\telif GLM_COMPILER >= GLM_COMPILER_GCC47\n#\t\t\tdefine GLM_HAS_OPENMP 31\n#\t\telse\n#\t\t\tdefine GLM_HAS_OPENMP 0\n#\t\tendif\n#\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\tif GLM_COMPILER >= GLM_COMPILER_CLANG38\n#\t\t\tdefine GLM_HAS_OPENMP 31\n#\t\telse\n#\t\t\tdefine GLM_HAS_OPENMP 0\n#\t\tendif\n#\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\tdefine GLM_HAS_OPENMP 20\n#\telif GLM_COMPILER & GLM_COMPILER_INTEL\n#\t\tif GLM_COMPILER >= GLM_COMPILER_INTEL16\n#\t\t\tdefine GLM_HAS_OPENMP 40\n#\t\telse\n#\t\t\tdefine GLM_HAS_OPENMP 0\n#\t\tendif\n#\telse\n#\t\tdefine GLM_HAS_OPENMP 0\n#\tendif\n#else\n#\tdefine GLM_HAS_OPENMP 0\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// nullptr\n\n#if GLM_LANG & GLM_LANG_CXX0X_FLAG\n#\tdefine GLM_CONFIG_NULLPTR GLM_ENABLE\n#else\n#\tdefine GLM_CONFIG_NULLPTR GLM_DISABLE\n#endif\n\n#if GLM_CONFIG_NULLPTR == GLM_ENABLE\n#\tdefine GLM_NULLPTR nullptr\n#else\n#\tdefine GLM_NULLPTR 0\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Static assert\n\n#if GLM_HAS_STATIC_ASSERT\n#\tdefine GLM_STATIC_ASSERT(x, message) static_assert(x, message)\n#elif GLM_COMPILER & GLM_COMPILER_VC\n#\tdefine GLM_STATIC_ASSERT(x, message) typedef char __CASSERT__##__LINE__[(x) ? 1 : -1]\n#else\n#\tdefine GLM_STATIC_ASSERT(x, message) assert(x)\n#endif//GLM_LANG\n\n///////////////////////////////////////////////////////////////////////////////////\n// Qualifiers\n\n#if GLM_COMPILER & GLM_COMPILER_CUDA\n#\tdefine GLM_CUDA_FUNC_DEF __device__ __host__\n#\tdefine GLM_CUDA_FUNC_DECL __device__ __host__\n#else\n#\tdefine GLM_CUDA_FUNC_DEF\n#\tdefine GLM_CUDA_FUNC_DECL\n#endif\n\n#if defined(GLM_FORCE_INLINE)\n#\tif GLM_COMPILER & GLM_COMPILER_VC\n#\t\tdefine GLM_INLINE __forceinline\n#\t\tdefine GLM_NEVER_INLINE __declspec((noinline))\n#\telif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)\n#\t\tdefine GLM_INLINE inline __attribute__((__always_inline__))\n#\t\tdefine GLM_NEVER_INLINE __attribute__((__noinline__))\n#\telif GLM_COMPILER & GLM_COMPILER_CUDA\n#\t\tdefine GLM_INLINE __forceinline__\n#\t\tdefine GLM_NEVER_INLINE __noinline__\n#\telse\n#\t\tdefine GLM_INLINE inline\n#\t\tdefine GLM_NEVER_INLINE\n#\tendif//GLM_COMPILER\n#else\n#\tdefine GLM_INLINE inline\n#\tdefine GLM_NEVER_INLINE\n#endif//defined(GLM_FORCE_INLINE)\n\n#define GLM_FUNC_DECL GLM_CUDA_FUNC_DECL\n#define GLM_FUNC_QUALIFIER GLM_CUDA_FUNC_DEF GLM_INLINE\n\n///////////////////////////////////////////////////////////////////////////////////\n// Swizzle operators\n\n// User defines: GLM_FORCE_SWIZZLE\n\n#define GLM_SWIZZLE_DISABLED\t\t0\n#define GLM_SWIZZLE_OPERATOR\t\t1\n#define GLM_SWIZZLE_FUNCTION\t\t2\n\n#if defined(GLM_FORCE_XYZW_ONLY)\n#\tundef GLM_FORCE_SWIZZLE\n#endif\n\n#if defined(GLM_SWIZZLE)\n#\tpragma message(\"GLM: GLM_SWIZZLE is deprecated, use GLM_FORCE_SWIZZLE instead.\")\n#\tdefine GLM_FORCE_SWIZZLE\n#endif\n\n#if defined(GLM_FORCE_SWIZZLE) && (GLM_LANG & GLM_LANG_CXXMS_FLAG)\n#\tdefine GLM_CONFIG_SWIZZLE GLM_SWIZZLE_OPERATOR\n#elif defined(GLM_FORCE_SWIZZLE)\n#\tdefine GLM_CONFIG_SWIZZLE GLM_SWIZZLE_FUNCTION\n#else\n#\tdefine GLM_CONFIG_SWIZZLE GLM_SWIZZLE_DISABLED\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Allows using not basic types as genType\n\n// #define GLM_FORCE_UNRESTRICTED_GENTYPE\n\n#ifdef GLM_FORCE_UNRESTRICTED_GENTYPE\n#\tdefine GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_ENABLE\n#else\n#\tdefine GLM_CONFIG_UNRESTRICTED_GENTYPE GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Clip control, define GLM_FORCE_DEPTH_ZERO_TO_ONE before including GLM\n// to use a clip space between 0 to 1.\n// Coordinate system, define GLM_FORCE_LEFT_HANDED before including GLM\n// to use left handed coordinate system by default.\n\n#define GLM_CLIP_CONTROL_ZO_BIT\t\t(1 << 0) // ZERO_TO_ONE\n#define GLM_CLIP_CONTROL_NO_BIT\t\t(1 << 1) // NEGATIVE_ONE_TO_ONE\n#define GLM_CLIP_CONTROL_LH_BIT\t\t(1 << 2) // LEFT_HANDED, For DirectX, Metal, Vulkan\n#define GLM_CLIP_CONTROL_RH_BIT\t\t(1 << 3) // RIGHT_HANDED, For OpenGL, default in GLM\n\n#define GLM_CLIP_CONTROL_LH_ZO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_ZO_BIT)\n#define GLM_CLIP_CONTROL_LH_NO (GLM_CLIP_CONTROL_LH_BIT | GLM_CLIP_CONTROL_NO_BIT)\n#define GLM_CLIP_CONTROL_RH_ZO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_ZO_BIT)\n#define GLM_CLIP_CONTROL_RH_NO (GLM_CLIP_CONTROL_RH_BIT | GLM_CLIP_CONTROL_NO_BIT)\n\n#ifdef GLM_FORCE_DEPTH_ZERO_TO_ONE\n#\tifdef GLM_FORCE_LEFT_HANDED\n#\t\tdefine GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_ZO\n#\telse\n#\t\tdefine GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_ZO\n#\tendif\n#else\n#\tifdef GLM_FORCE_LEFT_HANDED\n#\t\tdefine GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_LH_NO\n#\telse\n#\t\tdefine GLM_CONFIG_CLIP_CONTROL GLM_CLIP_CONTROL_RH_NO\n#\tendif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Qualifiers\n\n#if (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))\n#\tdefine GLM_DEPRECATED __declspec(deprecated)\n#\tdefine GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef __declspec(align(alignment)) type name\n#elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG | GLM_COMPILER_INTEL)\n#\tdefine GLM_DEPRECATED __attribute__((__deprecated__))\n#\tdefine GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __attribute__((aligned(alignment)))\n#elif GLM_COMPILER & GLM_COMPILER_CUDA\n#\tdefine GLM_DEPRECATED\n#\tdefine GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __align__(x)\n#else\n#\tdefine GLM_DEPRECATED\n#\tdefine GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n\n#ifdef GLM_FORCE_EXPLICIT_CTOR\n#\tdefine GLM_EXPLICIT explicit\n#else\n#\tdefine GLM_EXPLICIT\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// SYCL\n\n#if GLM_COMPILER==GLM_COMPILER_SYCL\n\n#include <CL/sycl.hpp>\n#include <limits>\n\nnamespace glm {\nnamespace std {\n\t// Import SYCL's functions into the namespace glm::std to force their usages.\n\t// It's important to use the math built-in function (sin, exp, ...)\n\t// of SYCL instead the std ones.\n\tusing namespace cl::sycl;\n\n\t///////////////////////////////////////////////////////////////////////////////\n\t// Import some \"harmless\" std's stuffs used by glm into\n\t// the new glm::std namespace.\n\ttemplate<typename T>\n\tusing numeric_limits = ::std::numeric_limits<T>;\n\n\tusing ::std::size_t;\n\n\tusing ::std::uint8_t;\n\tusing ::std::uint16_t;\n\tusing ::std::uint32_t;\n\tusing ::std::uint64_t;\n\n\tusing ::std::int8_t;\n\tusing ::std::int16_t;\n\tusing ::std::int32_t;\n\tusing ::std::int64_t;\n\n\tusing ::std::make_unsigned;\n\t///////////////////////////////////////////////////////////////////////////////\n} //namespace std\n} //namespace glm\n\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n\n///////////////////////////////////////////////////////////////////////////////////\n// Length type: all length functions returns a length_t type.\n// When GLM_FORCE_SIZE_T_LENGTH is defined, length_t is a typedef of size_t otherwise\n// length_t is a typedef of int like GLSL defines it.\n\n#define GLM_LENGTH_INT\t\t1\n#define GLM_LENGTH_SIZE_T\t2\n\n#ifdef GLM_FORCE_SIZE_T_LENGTH\n#\tdefine GLM_CONFIG_LENGTH_TYPE\t\tGLM_LENGTH_SIZE_T\n#else\n#\tdefine GLM_CONFIG_LENGTH_TYPE\t\tGLM_LENGTH_INT\n#endif\n\nnamespace glm\n{\n\tusing std::size_t;\n#\tif GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T\n\t\ttypedef size_t length_t;\n#\telse\n\t\ttypedef int length_t;\n#\tendif\n}//namespace glm\n\n///////////////////////////////////////////////////////////////////////////////////\n// constexpr\n\n#if GLM_HAS_CONSTEXPR\n#\tdefine GLM_CONFIG_CONSTEXP GLM_ENABLE\n\n\tnamespace glm\n\t{\n\t\ttemplate<typename T, std::size_t N>\n\t\tconstexpr std::size_t countof(T const (&)[N])\n\t\t{\n\t\t\treturn N;\n\t\t}\n\t}//namespace glm\n#\tdefine GLM_COUNTOF(arr) glm::countof(arr)\n#elif defined(_MSC_VER)\n#\tdefine GLM_CONFIG_CONSTEXP GLM_DISABLE\n\n#\tdefine GLM_COUNTOF(arr) _countof(arr)\n#else\n#\tdefine GLM_CONFIG_CONSTEXP GLM_DISABLE\n\n#\tdefine GLM_COUNTOF(arr) sizeof(arr) / sizeof(arr[0])\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// uint\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename T>\n\tstruct is_int\n\t{\n\t\tenum test {value = 0};\n\t};\n\n\ttemplate<>\n\tstruct is_int<unsigned int>\n\t{\n\t\tenum test {value = ~0};\n\t};\n\n\ttemplate<>\n\tstruct is_int<signed int>\n\t{\n\t\tenum test {value = ~0};\n\t};\n}//namespace detail\n\n\ttypedef unsigned int\tuint;\n}//namespace glm\n\n///////////////////////////////////////////////////////////////////////////////////\n// 64-bit int\n\n#if GLM_HAS_EXTENDED_INTEGER_TYPE\n#\tinclude <cstdint>\n#endif\n\nnamespace glm{\nnamespace detail\n{\n#\tif GLM_HAS_EXTENDED_INTEGER_TYPE\n\t\ttypedef std::uint64_t\t\t\t\t\t\tuint64;\n\t\ttypedef std::int64_t\t\t\t\t\t\tint64;\n#\telif (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available\n\t\ttypedef uint64_t\t\t\t\t\t\t\tuint64;\n\t\ttypedef int64_t\t\t\t\t\t\t\t\tint64;\n#\telif GLM_COMPILER & GLM_COMPILER_VC\n\t\ttypedef unsigned __int64\t\t\t\t\tuint64;\n\t\ttypedef signed __int64\t\t\t\t\t\tint64;\n#\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\tpragma GCC diagnostic ignored \"-Wlong-long\"\n\t\t__extension__ typedef unsigned long long\tuint64;\n\t\t__extension__ typedef signed long long\t\tint64;\n#\telif (GLM_COMPILER & GLM_COMPILER_CLANG)\n#\t\tpragma clang diagnostic ignored \"-Wc++11-long-long\"\n\t\ttypedef unsigned long long\t\t\t\t\tuint64;\n\t\ttypedef signed long long\t\t\t\t\tint64;\n#\telse//unknown compiler\n\t\ttypedef unsigned long long\t\t\t\t\tuint64;\n\t\ttypedef signed long long\t\t\t\t\tint64;\n#\tendif\n}//namespace detail\n}//namespace glm\n\n///////////////////////////////////////////////////////////////////////////////////\n// make_unsigned\n\n#if GLM_HAS_MAKE_SIGNED\n#\tinclude <type_traits>\n\nnamespace glm{\nnamespace detail\n{\n\tusing std::make_unsigned;\n}//namespace detail\n}//namespace glm\n\n#else\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename genType>\n\tstruct make_unsigned\n\t{};\n\n\ttemplate<>\n\tstruct make_unsigned<char>\n\t{\n\t\ttypedef unsigned char type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<signed char>\n\t{\n\t\ttypedef unsigned char type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<short>\n\t{\n\t\ttypedef unsigned short type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<int>\n\t{\n\t\ttypedef unsigned int type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<long>\n\t{\n\t\ttypedef unsigned long type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<int64>\n\t{\n\t\ttypedef uint64 type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<unsigned char>\n\t{\n\t\ttypedef unsigned char type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<unsigned short>\n\t{\n\t\ttypedef unsigned short type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<unsigned int>\n\t{\n\t\ttypedef unsigned int type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<unsigned long>\n\t{\n\t\ttypedef unsigned long type;\n\t};\n\n\ttemplate<>\n\tstruct make_unsigned<uint64>\n\t{\n\t\ttypedef uint64 type;\n\t};\n}//namespace detail\n}//namespace glm\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Only use x, y, z, w as vector type components\n\n#ifdef GLM_FORCE_XYZW_ONLY\n#\tdefine GLM_CONFIG_XYZW_ONLY GLM_ENABLE\n#else\n#\tdefine GLM_CONFIG_XYZW_ONLY GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Configure the use of defaulted initialized types\n\n#define GLM_CTOR_INIT_DISABLE\t\t0\n#define GLM_CTOR_INITIALIZER_LIST\t1\n#define GLM_CTOR_INITIALISATION\t\t2\n\n#if defined(GLM_FORCE_CTOR_INIT) && GLM_HAS_INITIALIZER_LISTS\n#\tdefine GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALIZER_LIST\n#elif defined(GLM_FORCE_CTOR_INIT) && !GLM_HAS_INITIALIZER_LISTS\n#\tdefine GLM_CONFIG_CTOR_INIT GLM_CTOR_INITIALISATION\n#else\n#\tdefine GLM_CONFIG_CTOR_INIT GLM_CTOR_INIT_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Use SIMD instruction sets\n\n#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (GLM_ARCH & GLM_ARCH_SIMD_BIT)\n#\tdefine GLM_CONFIG_SIMD GLM_ENABLE\n#else\n#\tdefine GLM_CONFIG_SIMD GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Configure the use of defaulted function\n\n#if GLM_HAS_DEFAULTED_FUNCTIONS && GLM_CONFIG_CTOR_INIT == GLM_CTOR_INIT_DISABLE\n#\tdefine GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_ENABLE\n#\tdefine GLM_DEFAULT = default\n#else\n#\tdefine GLM_CONFIG_DEFAULTED_FUNCTIONS GLM_DISABLE\n#\tdefine GLM_DEFAULT\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Configure the use of aligned gentypes\n\n#ifdef GLM_FORCE_ALIGNED // Legacy define\n#\tdefine GLM_FORCE_DEFAULT_ALIGNED_GENTYPES\n#endif\n\n#ifdef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES\n#\tdefine GLM_FORCE_ALIGNED_GENTYPES\n#endif\n\n#if GLM_HAS_ALIGNOF && (GLM_LANG & GLM_LANG_CXXMS_FLAG) && (defined(GLM_FORCE_ALIGNED_GENTYPES) || (GLM_CONFIG_SIMD == GLM_ENABLE))\n#\tdefine GLM_CONFIG_ALIGNED_GENTYPES GLM_ENABLE\n#else\n#\tdefine GLM_CONFIG_ALIGNED_GENTYPES GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Configure the use of anonymous structure as implementation detail\n\n#if ((GLM_CONFIG_SIMD == GLM_ENABLE) || (GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR) || (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE))\n#\tdefine GLM_CONFIG_ANONYMOUS_STRUCT GLM_ENABLE\n#else\n#\tdefine GLM_CONFIG_ANONYMOUS_STRUCT GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Silent warnings\n\n#ifdef GLM_FORCE_SILENT_WARNINGS\n#\tdefine GLM_SILENT_WARNINGS GLM_ENABLE\n#else\n#\tdefine GLM_SILENT_WARNINGS GLM_DISABLE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Precision\n\n#define GLM_HIGHP\t\t1\n#define GLM_MEDIUMP\t\t2\n#define GLM_LOWP\t\t3\n\n#if defined(GLM_FORCE_PRECISION_HIGHP_BOOL) || defined(GLM_PRECISION_HIGHP_BOOL)\n#\tdefine GLM_CONFIG_PRECISION_BOOL\t\tGLM_HIGHP\n#elif defined(GLM_FORCE_PRECISION_MEDIUMP_BOOL) || defined(GLM_PRECISION_MEDIUMP_BOOL)\n#\tdefine GLM_CONFIG_PRECISION_BOOL\t\tGLM_MEDIUMP\n#elif defined(GLM_FORCE_PRECISION_LOWP_BOOL) || defined(GLM_PRECISION_LOWP_BOOL)\n#\tdefine GLM_CONFIG_PRECISION_BOOL\t\tGLM_LOWP\n#else\n#\tdefine GLM_CONFIG_PRECISION_BOOL\t\tGLM_HIGHP\n#endif\n\n#if defined(GLM_FORCE_PRECISION_HIGHP_INT) || defined(GLM_PRECISION_HIGHP_INT)\n#\tdefine GLM_CONFIG_PRECISION_INT\t\t\tGLM_HIGHP\n#elif defined(GLM_FORCE_PRECISION_MEDIUMP_INT) || defined(GLM_PRECISION_MEDIUMP_INT)\n#\tdefine GLM_CONFIG_PRECISION_INT\t\t\tGLM_MEDIUMP\n#elif defined(GLM_FORCE_PRECISION_LOWP_INT) || defined(GLM_PRECISION_LOWP_INT)\n#\tdefine GLM_CONFIG_PRECISION_INT\t\t\tGLM_LOWP\n#else\n#\tdefine GLM_CONFIG_PRECISION_INT\t\t\tGLM_HIGHP\n#endif\n\n#if defined(GLM_FORCE_PRECISION_HIGHP_UINT) || defined(GLM_PRECISION_HIGHP_UINT)\n#\tdefine GLM_CONFIG_PRECISION_UINT\t\tGLM_HIGHP\n#elif defined(GLM_FORCE_PRECISION_MEDIUMP_UINT) || defined(GLM_PRECISION_MEDIUMP_UINT)\n#\tdefine GLM_CONFIG_PRECISION_UINT\t\tGLM_MEDIUMP\n#elif defined(GLM_FORCE_PRECISION_LOWP_UINT) || defined(GLM_PRECISION_LOWP_UINT)\n#\tdefine GLM_CONFIG_PRECISION_UINT\t\tGLM_LOWP\n#else\n#\tdefine GLM_CONFIG_PRECISION_UINT\t\tGLM_HIGHP\n#endif\n\n#if defined(GLM_FORCE_PRECISION_HIGHP_FLOAT) || defined(GLM_PRECISION_HIGHP_FLOAT)\n#\tdefine GLM_CONFIG_PRECISION_FLOAT\t\tGLM_HIGHP\n#elif defined(GLM_FORCE_PRECISION_MEDIUMP_FLOAT) || defined(GLM_PRECISION_MEDIUMP_FLOAT)\n#\tdefine GLM_CONFIG_PRECISION_FLOAT\t\tGLM_MEDIUMP\n#elif defined(GLM_FORCE_PRECISION_LOWP_FLOAT) || defined(GLM_PRECISION_LOWP_FLOAT)\n#\tdefine GLM_CONFIG_PRECISION_FLOAT\t\tGLM_LOWP\n#else\n#\tdefine GLM_CONFIG_PRECISION_FLOAT\t\tGLM_HIGHP\n#endif\n\n#if defined(GLM_FORCE_PRECISION_HIGHP_DOUBLE) || defined(GLM_PRECISION_HIGHP_DOUBLE)\n#\tdefine GLM_CONFIG_PRECISION_DOUBLE\t\tGLM_HIGHP\n#elif defined(GLM_FORCE_PRECISION_MEDIUMP_DOUBLE) || defined(GLM_PRECISION_MEDIUMP_DOUBLE)\n#\tdefine GLM_CONFIG_PRECISION_DOUBLE\t\tGLM_MEDIUMP\n#elif defined(GLM_FORCE_PRECISION_LOWP_DOUBLE) || defined(GLM_PRECISION_LOWP_DOUBLE)\n#\tdefine GLM_CONFIG_PRECISION_DOUBLE\t\tGLM_LOWP\n#else\n#\tdefine GLM_CONFIG_PRECISION_DOUBLE\t\tGLM_HIGHP\n#endif\n\n///////////////////////////////////////////////////////////////////////////////////\n// Check inclusions of different versions of GLM\n\n#elif ((GLM_SETUP_INCLUDED != GLM_VERSION) && !defined(GLM_FORCE_IGNORE_VERSION))\n#\terror \"GLM error: A different version of GLM is already included. Define GLM_FORCE_IGNORE_VERSION before including GLM headers to ignore this error.\"\n#elif GLM_SETUP_INCLUDED == GLM_VERSION\n\n///////////////////////////////////////////////////////////////////////////////////\n// Messages\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_DISPLAYED)\n#\tdefine GLM_MESSAGE_DISPLAYED\n#\t\tdefine GLM_STR_HELPER(x) #x\n#\t\tdefine GLM_STR(x) GLM_STR_HELPER(x)\n\n\t// Report GLM version\n#\t\tpragma message (GLM_STR(GLM_VERSION_MESSAGE))\n\n\t// Report C++ language\n#\tif (GLM_LANG & GLM_LANG_CXX2A_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 2A with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX2A_FLAG)\n#\t\tpragma message(\"GLM: C++ 2A\")\n#\telif (GLM_LANG & GLM_LANG_CXX17_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 17 with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX17_FLAG)\n#\t\tpragma message(\"GLM: C++ 17\")\n#\telif (GLM_LANG & GLM_LANG_CXX14_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 14 with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX14_FLAG)\n#\t\tpragma message(\"GLM: C++ 14\")\n#\telif (GLM_LANG & GLM_LANG_CXX11_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 11 with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX11_FLAG)\n#\t\tpragma message(\"GLM: C++ 11\")\n#\telif (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 0x with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX0X_FLAG)\n#\t\tpragma message(\"GLM: C++ 0x\")\n#\telif (GLM_LANG & GLM_LANG_CXX03_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 03 with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX03_FLAG)\n#\t\tpragma message(\"GLM: C++ 03\")\n#\telif (GLM_LANG & GLM_LANG_CXX98_FLAG) && (GLM_LANG & GLM_LANG_EXT)\n#\t\tpragma message(\"GLM: C++ 98 with extensions\")\n#\telif (GLM_LANG & GLM_LANG_CXX98_FLAG)\n#\t\tpragma message(\"GLM: C++ 98\")\n#\telse\n#\t\tpragma message(\"GLM: C++ language undetected\")\n#\tendif//GLM_LANG\n\n\t// Report compiler detection\n#\tif GLM_COMPILER & GLM_COMPILER_CUDA\n#\t\tpragma message(\"GLM: CUDA compiler detected\")\n#\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\tpragma message(\"GLM: Visual C++ compiler detected\")\n#\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\tpragma message(\"GLM: Clang compiler detected\")\n#\telif GLM_COMPILER & GLM_COMPILER_INTEL\n#\t\tpragma message(\"GLM: Intel Compiler detected\")\n#\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\tpragma message(\"GLM: GCC compiler detected\")\n#\telse\n#\t\tpragma message(\"GLM: Compiler not detected\")\n#\tendif\n\n\t// Report build target\n#\tif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with AVX2 instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with AVX2 instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with AVX instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_AVX_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with AVX instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with SSE4.2 instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_SSE42_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with SSE4.2 instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with SSE4.1 instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_SSE41_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with SSE4.1 instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with SSSE3 instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_SSSE3_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with SSSE3 instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with SSE3 instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_SSE3_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with SSE3 instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits with SSE2 instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_SSE2_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits with SSE2 instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: x86 64 bits build target\")\n#\telif (GLM_ARCH & GLM_ARCH_X86_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: x86 32 bits build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: ARM 64 bits with Neon instruction set build target\")\n#\telif (GLM_ARCH & GLM_ARCH_NEON_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: ARM 32 bits with Neon instruction set build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: ARM 64 bits build target\")\n#\telif (GLM_ARCH & GLM_ARCH_ARM_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: ARM 32 bits build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: MIPS 64 bits build target\")\n#\telif (GLM_ARCH & GLM_ARCH_MIPS_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: MIPS 32 bits build target\")\n\n#\telif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_64)\n#\t\tpragma message(\"GLM: PowerPC 64 bits build target\")\n#\telif (GLM_ARCH & GLM_ARCH_PPC_BIT) && (GLM_MODEL == GLM_MODEL_32)\n#\t\tpragma message(\"GLM: PowerPC 32 bits build target\")\n#\telse\n#\t\tpragma message(\"GLM: Unknown build target\")\n#\tendif//GLM_ARCH\n\n\t// Report platform name\n#\tif(GLM_PLATFORM & GLM_PLATFORM_QNXNTO)\n#\t\tpragma message(\"GLM: QNX platform detected\")\n//#\telif(GLM_PLATFORM & GLM_PLATFORM_IOS)\n//#\t\tpragma message(\"GLM: iOS platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_APPLE)\n#\t\tpragma message(\"GLM: Apple platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_WINCE)\n#\t\tpragma message(\"GLM: WinCE platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS)\n#\t\tpragma message(\"GLM: Windows platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_CHROME_NACL)\n#\t\tpragma message(\"GLM: Native Client detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n#\t\tpragma message(\"GLM: Android platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_LINUX)\n#\t\tpragma message(\"GLM: Linux platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_UNIX)\n#\t\tpragma message(\"GLM: UNIX platform detected\")\n#\telif(GLM_PLATFORM & GLM_PLATFORM_UNKNOWN)\n#\t\tpragma message(\"GLM: platform unknown\")\n#\telse\n#\t\tpragma message(\"GLM: platform not detected\")\n#\tendif\n\n\t// Report whether only xyzw component are used\n#\tif defined GLM_FORCE_XYZW_ONLY\n#\t\tpragma message(\"GLM: GLM_FORCE_XYZW_ONLY is defined. Only x, y, z and w component are available in vector type. This define disables swizzle operators and SIMD instruction sets.\")\n#\tendif\n\n\t// Report swizzle operator support\n#\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n#\t\tpragma message(\"GLM: GLM_FORCE_SWIZZLE is defined, swizzling operators enabled.\")\n#\telif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n#\t\tpragma message(\"GLM: GLM_FORCE_SWIZZLE is defined, swizzling functions enabled. Enable compiler C++ language extensions to enable swizzle operators.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_FORCE_SWIZZLE is undefined. swizzling functions or operators are disabled.\")\n#\tendif\n\n\t// Report .length() type\n#\tif GLM_CONFIG_LENGTH_TYPE == GLM_LENGTH_SIZE_T\n#\t\tpragma message(\"GLM: GLM_FORCE_SIZE_T_LENGTH is defined. .length() returns a glm::length_t, a typedef of std::size_t.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_FORCE_SIZE_T_LENGTH is undefined. .length() returns a glm::length_t, a typedef of int following GLSL.\")\n#\tendif\n\n#\tif GLM_CONFIG_UNRESTRICTED_GENTYPE == GLM_ENABLE\n#\t\tpragma message(\"GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is defined. Removes GLSL restrictions on valid function genTypes.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_FORCE_UNRESTRICTED_GENTYPE is undefined. Follows strictly GLSL on valid function genTypes.\")\n#\tendif\n\n#\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\tpragma message(\"GLM: GLM_FORCE_SILENT_WARNINGS is defined. Ignores C++ warnings from using C++ language extensions.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_FORCE_SILENT_WARNINGS is undefined. Shows C++ warnings from using C++ language extensions.\")\n#\tendif\n\n#\tifdef GLM_FORCE_SINGLE_ONLY\n#\t\tpragma message(\"GLM: GLM_FORCE_SINGLE_ONLY is defined. Using only single precision floating-point types.\")\n#\tendif\n\n#\tif defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE)\n#\t\tundef GLM_FORCE_ALIGNED_GENTYPES\n#\t\tpragma message(\"GLM: GLM_FORCE_ALIGNED_GENTYPES is defined, allowing aligned types. This prevents the use of C++ constexpr.\")\n#\telif defined(GLM_FORCE_ALIGNED_GENTYPES) && (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE)\n#\t\tundef GLM_FORCE_ALIGNED_GENTYPES\n#\t\tpragma message(\"GLM: GLM_FORCE_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.\")\n#\tendif\n\n#\tif defined(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES)\n#\t\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE\n#\t\t\tundef GLM_FORCE_DEFAULT_ALIGNED_GENTYPES\n#\t\t\tpragma message(\"GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined but is disabled. It requires C++11 and language extensions.\")\n#\t\telif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n#\t\t\tpragma message(\"GLM: GLM_FORCE_DEFAULT_ALIGNED_GENTYPES is defined. All gentypes (e.g. vec3) will be aligned and padded by default.\")\n#\t\tendif\n#\tendif\n\n#\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n#\t\tpragma message(\"GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is defined. Using zero to one depth clip space.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_FORCE_DEPTH_ZERO_TO_ONE is undefined. Using negative one to one depth clip space.\")\n#\tendif\n\n#\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n#\t\tpragma message(\"GLM: GLM_FORCE_LEFT_HANDED is defined. Using left handed coordinate system.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_FORCE_LEFT_HANDED is undefined. Using right handed coordinate system.\")\n#\tendif\n#endif//GLM_MESSAGES\n\n#endif//GLM_SETUP_INCLUDED\n"
  },
  {
    "path": "lib/gli/glm/detail/type_float.hpp",
    "content": "#pragma once\n\n#include \"setup.hpp\"\n\n#if GLM_COMPILER == GLM_COMPILER_VC12\n#\tpragma warning(push)\n#\tpragma warning(disable: 4512) // assignment operator could not be generated\n#endif\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate <typename T>\n\tunion float_t\n\t{};\n\n\t// https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/\n\ttemplate <>\n\tunion float_t<float>\n\t{\n\t\ttypedef int int_type;\n\t\ttypedef float float_type;\n\n\t\tGLM_CONSTEXPR float_t(float_type Num = 0.0f) : f(Num) {}\n\n\t\tGLM_CONSTEXPR float_t& operator=(float_t const& x)\n\t\t{\n\t\t\tf = x.f;\n\t\t\treturn *this;\n\t\t}\n\n\t\t// Portable extraction of components.\n\t\tGLM_CONSTEXPR bool negative() const { return i < 0; }\n\t\tGLM_CONSTEXPR int_type mantissa() const { return i & ((1 << 23) - 1); }\n\t\tGLM_CONSTEXPR int_type exponent() const { return (i >> 23) & ((1 << 8) - 1); }\n\n\t\tint_type i;\n\t\tfloat_type f;\n\t};\n\n\ttemplate <>\n\tunion float_t<double>\n\t{\n\t\ttypedef detail::int64 int_type;\n\t\ttypedef double float_type;\n\n\t\tGLM_CONSTEXPR float_t(float_type Num = static_cast<float_type>(0)) : f(Num) {}\n\n\t\tGLM_CONSTEXPR float_t& operator=(float_t const& x)\n\t\t{\n\t\t\tf = x.f;\n\t\t\treturn *this;\n\t\t}\n\n\t\t// Portable extraction of components.\n\t\tGLM_CONSTEXPR bool negative() const { return i < 0; }\n\t\tGLM_CONSTEXPR int_type mantissa() const { return i & ((int_type(1) << 52) - 1); }\n\t\tGLM_CONSTEXPR int_type exponent() const { return (i >> 52) & ((int_type(1) << 11) - 1); }\n\n\t\tint_type i;\n\t\tfloat_type f;\n\t};\n}//namespace detail\n}//namespace glm\n\n#if GLM_COMPILER == GLM_COMPILER_VC12\n#\tpragma warning(pop)\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_half.hpp",
    "content": "#pragma once\n\n#include \"setup.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttypedef short hdata;\n\n\tGLM_FUNC_DECL float toFloat32(hdata value);\n\tGLM_FUNC_DECL hdata toFloat16(float const& value);\n\n}//namespace detail\n}//namespace glm\n\n#include \"type_half.inl\"\n"
  },
  {
    "path": "lib/gli/glm/detail/type_half.inl",
    "content": "namespace glm{\nnamespace detail\n{\n\tGLM_FUNC_QUALIFIER float overflow()\n\t{\n\t\tvolatile float f = 1e10;\n\n\t\tfor(int i = 0; i < 10; ++i)\n\t\t\tf *= f; // this will overflow before the for loop terminates\n\t\treturn f;\n\t}\n\n\tunion uif32\n\t{\n\t\tGLM_FUNC_QUALIFIER uif32() :\n\t\t\ti(0)\n\t\t{}\n\n\t\tGLM_FUNC_QUALIFIER uif32(float f_) :\n\t\t\tf(f_)\n\t\t{}\n\n\t\tGLM_FUNC_QUALIFIER uif32(unsigned int i_) :\n\t\t\ti(i_)\n\t\t{}\n\n\t\tfloat f;\n\t\tunsigned int i;\n\t};\n\n\tGLM_FUNC_QUALIFIER float toFloat32(hdata value)\n\t{\n\t\tint s = (value >> 15) & 0x00000001;\n\t\tint e = (value >> 10) & 0x0000001f;\n\t\tint m =  value        & 0x000003ff;\n\n\t\tif(e == 0)\n\t\t{\n\t\t\tif(m == 0)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Plus or minus zero\n\t\t\t\t//\n\n\t\t\t\tdetail::uif32 result;\n\t\t\t\tresult.i = static_cast<unsigned int>(s << 31);\n\t\t\t\treturn result.f;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Denormalized number -- renormalize it\n\t\t\t\t//\n\n\t\t\t\twhile(!(m & 0x00000400))\n\t\t\t\t{\n\t\t\t\t\tm <<= 1;\n\t\t\t\t\te -=  1;\n\t\t\t\t}\n\n\t\t\t\te += 1;\n\t\t\t\tm &= ~0x00000400;\n\t\t\t}\n\t\t}\n\t\telse if(e == 31)\n\t\t{\n\t\t\tif(m == 0)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Positive or negative infinity\n\t\t\t\t//\n\n\t\t\t\tuif32 result;\n\t\t\t\tresult.i = static_cast<unsigned int>((s << 31) | 0x7f800000);\n\t\t\t\treturn result.f;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// Nan -- preserve sign and significand bits\n\t\t\t\t//\n\n\t\t\t\tuif32 result;\n\t\t\t\tresult.i = static_cast<unsigned int>((s << 31) | 0x7f800000 | (m << 13));\n\t\t\t\treturn result.f;\n\t\t\t}\n\t\t}\n\n\t\t//\n\t\t// Normalized number\n\t\t//\n\n\t\te = e + (127 - 15);\n\t\tm = m << 13;\n\n\t\t//\n\t\t// Assemble s, e and m.\n\t\t//\n\n\t\tuif32 Result;\n\t\tResult.i = static_cast<unsigned int>((s << 31) | (e << 23) | m);\n\t\treturn Result.f;\n\t}\n\n\tGLM_FUNC_QUALIFIER hdata toFloat16(float const& f)\n\t{\n\t\tuif32 Entry;\n\t\tEntry.f = f;\n\t\tint i = static_cast<int>(Entry.i);\n\n\t\t//\n\t\t// Our floating point number, f, is represented by the bit\n\t\t// pattern in integer i.  Disassemble that bit pattern into\n\t\t// the sign, s, the exponent, e, and the significand, m.\n\t\t// Shift s into the position where it will go in the\n\t\t// resulting half number.\n\t\t// Adjust e, accounting for the different exponent bias\n\t\t// of float and half (127 versus 15).\n\t\t//\n\n\t\tint s =  (i >> 16) & 0x00008000;\n\t\tint e = ((i >> 23) & 0x000000ff) - (127 - 15);\n\t\tint m =   i        & 0x007fffff;\n\n\t\t//\n\t\t// Now reassemble s, e and m into a half:\n\t\t//\n\n\t\tif(e <= 0)\n\t\t{\n\t\t\tif(e < -10)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// E is less than -10.  The absolute value of f is\n\t\t\t\t// less than half_MIN (f may be a small normalized\n\t\t\t\t// float, a denormalized float or a zero).\n\t\t\t\t//\n\t\t\t\t// We convert f to a half zero.\n\t\t\t\t//\n\n\t\t\t\treturn hdata(s);\n\t\t\t}\n\n\t\t\t//\n\t\t\t// E is between -10 and 0.  F is a normalized float,\n\t\t\t// whose magnitude is less than __half_NRM_MIN.\n\t\t\t//\n\t\t\t// We convert f to a denormalized half.\n\t\t\t//\n\n\t\t\tm = (m | 0x00800000) >> (1 - e);\n\n\t\t\t//\n\t\t\t// Round to nearest, round \"0.5\" up.\n\t\t\t//\n\t\t\t// Rounding may cause the significand to overflow and make\n\t\t\t// our number normalized.  Because of the way a half's bits\n\t\t\t// are laid out, we don't have to treat this case separately;\n\t\t\t// the code below will handle it correctly.\n\t\t\t//\n\n\t\t\tif(m & 0x00001000)\n\t\t\t\tm += 0x00002000;\n\n\t\t\t//\n\t\t\t// Assemble the half from s, e (zero) and m.\n\t\t\t//\n\n\t\t\treturn hdata(s | (m >> 13));\n\t\t}\n\t\telse if(e == 0xff - (127 - 15))\n\t\t{\n\t\t\tif(m == 0)\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// F is an infinity; convert f to a half\n\t\t\t\t// infinity with the same sign as f.\n\t\t\t\t//\n\n\t\t\t\treturn hdata(s | 0x7c00);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t//\n\t\t\t\t// F is a NAN; we produce a half NAN that preserves\n\t\t\t\t// the sign bit and the 10 leftmost bits of the\n\t\t\t\t// significand of f, with one exception: If the 10\n\t\t\t\t// leftmost bits are all zero, the NAN would turn\n\t\t\t\t// into an infinity, so we have to set at least one\n\t\t\t\t// bit in the significand.\n\t\t\t\t//\n\n\t\t\t\tm >>= 13;\n\n\t\t\t\treturn hdata(s | 0x7c00 | m | (m == 0));\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//\n\t\t\t// E is greater than zero.  F is a normalized float.\n\t\t\t// We try to convert f to a normalized half.\n\t\t\t//\n\n\t\t\t//\n\t\t\t// Round to nearest, round \"0.5\" up\n\t\t\t//\n\n\t\t\tif(m &  0x00001000)\n\t\t\t{\n\t\t\t\tm += 0x00002000;\n\n\t\t\t\tif(m & 0x00800000)\n\t\t\t\t{\n\t\t\t\t\tm =  0;     // overflow in significand,\n\t\t\t\t\te += 1;     // adjust exponent\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t//\n\t\t\t// Handle exponent overflow\n\t\t\t//\n\n\t\t\tif (e > 30)\n\t\t\t{\n\t\t\t\toverflow();        // Cause a hardware floating point overflow;\n\n\t\t\t\treturn hdata(s | 0x7c00);\n\t\t\t\t// if this returns, the half becomes an\n\t\t\t}   // infinity with the same sign as f.\n\n\t\t\t//\n\t\t\t// Assemble the half from s, e and m.\n\t\t\t//\n\n\t\t\treturn hdata(s | (e << 10) | (m >> 13));\n\t\t}\n\t}\n\n}//namespace detail\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat2x2.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat2x2.hpp\n\n#pragma once\n\n#include \"type_vec2.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<2, 2, T, Q>\n\t{\n\t\ttypedef vec<2, T, Q> col_type;\n\t\ttypedef vec<2, T, Q> row_type;\n\t\ttypedef mat<2, 2, T, Q> type;\n\t\ttypedef mat<2, 2, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[2];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 2, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT const& x1, T const& y1,\n\t\t\tT const& x2, T const& y2);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<typename U, typename V, typename M, typename N>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tU const& x1, V const& y1,\n\t\t\tM const& x2, N const& y2);\n\n\t\ttemplate<typename U, typename V>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<2, U, Q> const& v1,\n\t\t\tvec<2, V, Q> const& v2);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator=(mat<2, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator+=(mat<2, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator-=(mat<2, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator*=(mat<2, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator/=(mat<2, 2, U, Q> const& m);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator++ ();\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> & operator-- ();\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<2, 2, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator*(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator*(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n} //namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat2x2.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat2x2.inl",
    "content": "#include \"../matrix.hpp\"\n\nnamespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0), col_type(0, 1)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{m[0], m[1]}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(T scalar)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(scalar, 0), col_type(0, scalar)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(scalar, 0);\n\t\t\tthis->value[1] = col_type(0, scalar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat\n\t(\n\t\tT const& x0, T const& y0,\n\t\tT const& x1, T const& y1\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0), col_type(x1, y1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0);\n\t\t\tthis->value[1] = col_type(x1, y1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(col_type const& v0, col_type const& v1)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{v0, v1}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X1, typename Y1, typename X2, typename Y2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat\n\t(\n\t\tX1 const& x1, Y1 const& y1,\n\t\tX2 const& x2, Y2 const& y2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(static_cast<T>(x1), value_type(y1)), col_type(static_cast<T>(x2), value_type(y2)) }\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(static_cast<T>(x1), value_type(y1));\n\t\t\tthis->value[1] = col_type(static_cast<T>(x2), value_type(y2));\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v1);\n\t\t\tthis->value[1] = col_type(v2);\n#\t\tendif\n\t}\n\n\t// -- mat2x2 matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 2, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 2, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 2, T, Q>::col_type const& mat<2, 2, T, Q>::operator[](typename mat<2, 2, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator=(mat<2, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(U scalar)\n\t{\n\t\tthis->value[0] += scalar;\n\t\tthis->value[1] += scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator+=(mat<2, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(U scalar)\n\t{\n\t\tthis->value[0] -= scalar;\n\t\tthis->value[1] -= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator-=(mat<2, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(U scalar)\n\t{\n\t\tthis->value[0] *= scalar;\n\t\tthis->value[1] *= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator*=(mat<2, 2, U, Q> const& m)\n\t{\n\t\treturn (*this = *this * m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(U scalar)\n\t{\n\t\tthis->value[0] /= scalar;\n\t\tthis->value[1] /= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator/=(mat<2, 2, U, Q> const& m)\n\t{\n\t\treturn *this *= inverse(m);\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q>& mat<2, 2, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator++(int)\n\t{\n\t\tmat<2, 2, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> mat<2, 2, T, Q>::operator--(int)\n\t{\n\t\tmat<2, 2, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(T scalar, mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator+(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(T scalar, mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tscalar - m[0],\n\t\t\tscalar - m[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator-(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(T scalar, mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator*\n\t(\n\t\tmat<2, 2, T, Q> const& m,\n\t\ttypename mat<2, 2, T, Q>::row_type const& v\n\t)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator*\n\t(\n\t\ttypename mat<2, 2, T, Q>::col_type const& v,\n\t\tmat<2, 2, T, Q> const& m\n\t)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x * m[0][0] + v.y * m[0][1],\n\t\t\tv.x * m[1][0] + v.y * m[1][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<2, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1],\n\t\t\tm1[0][0] * m2[3][0] + m1[1][0] * m2[3][1],\n\t\t\tm1[0][1] * m2[3][0] + m1[1][1] * m2[3][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(T scalar, mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::col_type operator/(mat<2, 2, T, Q> const& m, typename mat<2, 2, T, Q>::row_type const& v)\n\t{\n\t\treturn inverse(m) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 2, T, Q>::row_type operator/(typename mat<2, 2, T, Q>::col_type const& v, mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn v *  inverse(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator/(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\tmat<2, 2, T, Q> m1_copy(m1);\n\t\treturn m1_copy /= m2;\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<2, 2, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat2x3.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat2x3.hpp\n\n#pragma once\n\n#include \"type_vec2.hpp\"\n#include \"type_vec3.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<2, 3, T, Q>\n\t{\n\t\ttypedef vec<3, T, Q> col_type;\n\t\ttypedef vec<2, T, Q> row_type;\n\t\ttypedef mat<2, 3, T, Q> type;\n\t\ttypedef mat<3, 2, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[2];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 3, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT x0, T y0, T z0,\n\t\t\tT x1, T y1, T z1);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 x1, Y1 y1, Z1 z1,\n\t\t\tX2 x2, Y2 y2, Z2 z2);\n\n\t\ttemplate<typename U, typename V>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<3, U, Q> const& v1,\n\t\t\tvec<3, V, Q> const& v2);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator=(mat<2, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator+=(mat<2, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator-=(mat<2, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator/=(U s);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator++ ();\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> & operator-- ();\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<2, 3, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 3, T, Q>::col_type operator*(mat<2, 3, T, Q> const& m, typename mat<2, 3, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 3, T, Q>::row_type operator*(typename mat<2, 3, T, Q>::col_type const& v, mat<2, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat2x3.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat2x3.inl",
    "content": "namespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0, 0), col_type(0, 1, 0)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1, 0);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{m.value[0], m.value[1]}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m.value[0];\n\t\t\tthis->value[1] = m.value[1];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(T scalar)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(scalar, 0, 0), col_type(0, scalar, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(scalar, 0, 0);\n\t\t\tthis->value[1] = col_type(0, scalar, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat\n\t(\n\t\tT x0, T y0, T z0,\n\t\tT x1, T y1, T z1\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0, z0), col_type(x1, y1, z1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(col_type const& v0, col_type const& v1)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v0);\n\t\t\tthis->value[1] = col_type(v1);\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X1, typename Y1, typename Z1,\n\t\ttypename X2, typename Y2, typename Z2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat\n\t(\n\t\tX1 x1, Y1 y1, Z1 z1,\n\t\tX2 x2, Y2 y2, Z2 z2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x1, y1, z1), col_type(x2, y2, z2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x1, y1, z1);\n\t\t\tthis->value[1] = col_type(x2, y2, z2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v1);\n\t\t\tthis->value[1] = col_type(v2);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 3, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR  mat<2, 3, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 3, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type & mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 3, T, Q>::col_type const& mat<2, 3, T, Q>::operator[](typename mat<2, 3, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator=(mat<2, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator+=(mat<2, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator-=(mat<2, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q>& mat<2, 3, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> & mat<2, 3, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator++(int)\n\t{\n\t\tmat<2, 3, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> mat<2, 3, T, Q>::operator--(int)\n\t{\n\t\tmat<2, 3, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator+(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator-(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(T scalar, mat<2, 3, T, Q> const& m)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::col_type operator*\n\t(\n\t\tmat<2, 3, T, Q> const& m,\n\t\ttypename mat<2, 3, T, Q>::row_type const& v)\n\t{\n\t\treturn typename mat<2, 3, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y,\n\t\t\tm[0][2] * v.x + m[1][2] * v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 3, T, Q>::row_type operator*\n\t(\n\t\ttypename mat<2, 3, T, Q>::col_type const& v,\n\t\tmat<2, 3, T, Q> const& m)\n\t{\n\t\treturn typename mat<2, 3, T, Q>::row_type(\n\t\t\tv.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2],\n\t\t\tv.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\tT SrcA00 = m1[0][0];\n\t\tT SrcA01 = m1[0][1];\n\t\tT SrcA02 = m1[0][2];\n\t\tT SrcA10 = m1[1][0];\n\t\tT SrcA11 = m1[1][1];\n\t\tT SrcA12 = m1[1][2];\n\n\t\tT SrcB00 = m2[0][0];\n\t\tT SrcB01 = m2[0][1];\n\t\tT SrcB10 = m2[1][0];\n\t\tT SrcB11 = m2[1][1];\n\t\tT SrcB20 = m2[2][0];\n\t\tT SrcB21 = m2[2][1];\n\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01;\n\t\tResult[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11;\n\t\tResult[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11;\n\t\tResult[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21;\n\t\tResult[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21;\n\t\tResult[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<2, 3, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1],\n\t\t\tm1[0][2] * m2[2][0] + m1[1][2] * m2[2][1],\n\t\t\tm1[0][0] * m2[3][0] + m1[1][0] * m2[3][1],\n\t\t\tm1[0][1] * m2[3][0] + m1[1][1] * m2[3][1],\n\t\t\tm1[0][2] * m2[3][0] + m1[1][2] * m2[3][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(mat<2, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator/(T scalar, mat<2, 3, T, Q> const& m)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1]);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<2, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat2x4.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat2x4.hpp\n\n#pragma once\n\n#include \"type_vec2.hpp\"\n#include \"type_vec4.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<2, 4, T, Q>\n\t{\n\t\ttypedef vec<4, T, Q> col_type;\n\t\ttypedef vec<2, T, Q> row_type;\n\t\ttypedef mat<2, 4, T, Q> type;\n\t\ttypedef mat<4, 2, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[2];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 2; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<2, 4, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT x0, T y0, T z0, T w0,\n\t\t\tT x1, T y1, T z1, T w1);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X1, typename Y1, typename Z1, typename W1,\n\t\t\ttypename X2, typename Y2, typename Z2, typename W2>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 x1, Y1 y1, Z1 z1, W1 w1,\n\t\t\tX2 x2, Y2 y2, Z2 z2, W2 w2);\n\n\t\ttemplate<typename U, typename V>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<4, U, Q> const& v1,\n\t\t\tvec<4, V, Q> const& v2);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator=(mat<2, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator+=(mat<2, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator-=(mat<2, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator/=(U s);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator++ ();\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> & operator-- ();\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<2, 4, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat2x4.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat2x4.inl",
    "content": "namespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0, 0, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1, 0, 0);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{m[0], m[1]}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(T s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0, 0, 0);\n\t\t\tthis->value[1] = col_type(0, s, 0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat\n\t(\n\t\tT x0, T y0, T z0, T w0,\n\t\tT x1, T y1, T z1, T w1\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0, z0, w0), col_type(x1, y1, z1, w1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0, w0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1, w1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(col_type const& v0, col_type const& v1)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X1, typename Y1, typename Z1, typename W1,\n\t\ttypename X2, typename Y2, typename Z2, typename W2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat\n\t(\n\t\tX1 x1, Y1 y1, Z1 z1, W1 w1,\n\t\tX2 x2, Y2 y2, Z2 z2, W2 w2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{\n\t\t\t\tcol_type(x1, y1, z1, w1),\n\t\t\t\tcol_type(x2, y2, z2, w2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x1, y1, z1, w1);\n\t\t\tthis->value[1] = col_type(x2, y2, z2, w2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v1);\n\t\t\tthis->value[1] = col_type(v2);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 4, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<2, 4, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type & mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<2, 4, T, Q>::col_type const& mat<2, 4, T, Q>::operator[](typename mat<2, 4, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator=(mat<2, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator+=(mat<2, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator-=(mat<2, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> & mat<2, 4, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q>& mat<2, 4, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator++(int)\n\t{\n\t\tmat<2, 4, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat<2, 4, T, Q>::operator--(int)\n\t{\n\t\tmat<2, 4, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator+(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator-(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(T scalar, mat<2, 4, T, Q> const& m)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::col_type operator*(mat<2, 4, T, Q> const& m, typename mat<2, 4, T, Q>::row_type const& v)\n\t{\n\t\treturn typename mat<2, 4, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y,\n\t\t\tm[0][2] * v.x + m[1][2] * v.y,\n\t\t\tm[0][3] * v.x + m[1][3] * v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<2, 4, T, Q>::row_type operator*(typename mat<2, 4, T, Q>::col_type const& v, mat<2, 4, T, Q> const& m)\n\t{\n\t\treturn typename mat<2, 4, T, Q>::row_type(\n\t\t\tv.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],\n\t\t\tv.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\tT SrcA00 = m1[0][0];\n\t\tT SrcA01 = m1[0][1];\n\t\tT SrcA02 = m1[0][2];\n\t\tT SrcA03 = m1[0][3];\n\t\tT SrcA10 = m1[1][0];\n\t\tT SrcA11 = m1[1][1];\n\t\tT SrcA12 = m1[1][2];\n\t\tT SrcA13 = m1[1][3];\n\n\t\tT SrcB00 = m2[0][0];\n\t\tT SrcB01 = m2[0][1];\n\t\tT SrcB10 = m2[1][0];\n\t\tT SrcB11 = m2[1][1];\n\t\tT SrcB20 = m2[2][0];\n\t\tT SrcB21 = m2[2][1];\n\t\tT SrcB30 = m2[3][0];\n\t\tT SrcB31 = m2[3][1];\n\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01;\n\t\tResult[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01;\n\t\tResult[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11;\n\t\tResult[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11;\n\t\tResult[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11;\n\t\tResult[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21;\n\t\tResult[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21;\n\t\tResult[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21;\n\t\tResult[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21;\n\t\tResult[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31;\n\t\tResult[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31;\n\t\tResult[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31;\n\t\tResult[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<2, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],\n\t\t\tm1[0][3] * m2[0][0] + m1[1][3] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1],\n\t\t\tm1[0][3] * m2[1][0] + m1[1][3] * m2[1][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<2, 4, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],\n\t\t\tm1[0][3] * m2[0][0] + m1[1][3] * m2[0][1],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1],\n\t\t\tm1[0][3] * m2[1][0] + m1[1][3] * m2[1][1],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1],\n\t\t\tm1[0][2] * m2[2][0] + m1[1][2] * m2[2][1],\n\t\t\tm1[0][3] * m2[2][0] + m1[1][3] * m2[2][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(mat<2, 4, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator/(T scalar, mat<2, 4, T, Q> const& m)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1]);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<2, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat3x2.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat3x2.hpp\n\n#pragma once\n\n#include \"type_vec2.hpp\"\n#include \"type_vec3.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<3, 2, T, Q>\n\t{\n\t\ttypedef vec<2, T, Q> col_type;\n\t\ttypedef vec<3, T, Q> row_type;\n\t\ttypedef mat<3, 2, T, Q> type;\n\t\ttypedef mat<2, 3, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[3];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 2, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT x0, T y0,\n\t\t\tT x1, T y1,\n\t\t\tT x2, T y2);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X1, typename Y1,\n\t\t\ttypename X2, typename Y2,\n\t\t\ttypename X3, typename Y3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 x1, Y1 y1,\n\t\t\tX2 x2, Y2 y2,\n\t\t\tX3 x3, Y3 y3);\n\n\t\ttemplate<typename V1, typename V2, typename V3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<2, V1, Q> const& v1,\n\t\t\tvec<2, V2, Q> const& v2,\n\t\t\tvec<2, V3, Q> const& v3);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator=(mat<3, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator+=(mat<3, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator-=(mat<3, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator/=(U s);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator++ ();\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> & operator-- ();\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<3, 2, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2);\n\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat3x2.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat3x2.inl",
    "content": "namespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0), col_type(0, 1), col_type(0, 0)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1);\n\t\t\t\tthis->value[2] = col_type(0, 0);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(T s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0), col_type(0, s), col_type(0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0);\n\t\t\tthis->value[1] = col_type(0, s);\n\t\t\tthis->value[2] = col_type(0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat\n\t(\n\t\tT x0, T y0,\n\t\tT x1, T y1,\n\t\tT x2, T y2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0);\n\t\t\tthis->value[1] = col_type(x1, y1);\n\t\t\tthis->value[2] = col_type(x2, y2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n\t\t\tthis->value[2] = v2;\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X0, typename Y0,\n\t\ttypename X1, typename Y1,\n\t\ttypename X2, typename Y2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat\n\t(\n\t\tX0 x0, Y0 y0,\n\t\tX1 x1, Y1 y1,\n\t\tX2 x2, Y2 y2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0);\n\t\t\tthis->value[1] = col_type(x1, y1);\n\t\t\tthis->value[2] = col_type(x2, y2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V0, typename V1, typename V2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v0);\n\t\t\tthis->value[1] = col_type(v1);\n\t\t\tthis->value[2] = col_type(v2);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 2, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 2, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type & mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 2, T, Q>::col_type const& mat<3, 2, T, Q>::operator[](typename mat<3, 2, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator=(mat<3, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\tthis->value[2] = m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\tthis->value[2] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator+=(mat<3, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\tthis->value[2] += m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\tthis->value[2] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator-=(mat<3, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\tthis->value[2] -= m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\tthis->value[2] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> & mat<3, 2, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\tthis->value[2] /= s;\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\t++this->value[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q>& mat<3, 2, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\t--this->value[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator++(int)\n\t{\n\t\tmat<3, 2, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> mat<3, 2, T, Q>::operator--(int)\n\t{\n\t\tmat<3, 2, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1],\n\t\t\t-m[2]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar,\n\t\t\tm[2] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator+(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1],\n\t\t\tm1[2] + m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar,\n\t\t\tm[2] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator-(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1],\n\t\t\tm1[2] - m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(T scalar, mat<3, 2, T, Q> const& m)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::col_type operator*(mat<3, 2, T, Q> const& m, typename mat<3, 2, T, Q>::row_type const& v)\n\t{\n\t\treturn typename mat<3, 2, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 2, T, Q>::row_type operator*(typename mat<3, 2, T, Q>::col_type const& v, mat<3, 2, T, Q> const& m)\n\t{\n\t\treturn typename mat<3, 2, T, Q>::row_type(\n\t\t\tv.x * m[0][0] + v.y * m[0][1],\n\t\t\tv.x * m[1][0] + v.y * m[1][1],\n\t\t\tv.x * m[2][0] + v.y * m[2][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\tconst T SrcA00 = m1[0][0];\n\t\tconst T SrcA01 = m1[0][1];\n\t\tconst T SrcA10 = m1[1][0];\n\t\tconst T SrcA11 = m1[1][1];\n\t\tconst T SrcA20 = m1[2][0];\n\t\tconst T SrcA21 = m1[2][1];\n\n\t\tconst T SrcB00 = m2[0][0];\n\t\tconst T SrcB01 = m2[0][1];\n\t\tconst T SrcB02 = m2[0][2];\n\t\tconst T SrcB10 = m2[1][0];\n\t\tconst T SrcB11 = m2[1][1];\n\t\tconst T SrcB12 = m2[1][2];\n\n\t\tmat<2, 2, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<3, 2, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],\n\t\t\tm1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2],\n\t\t\tm1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(mat<3, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar,\n\t\t\tm[2] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator/(T scalar, mat<3, 2, T, Q> const& m)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1],\n\t\t\tscalar / m[2]);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<3, 2, T, Q> const& m1, mat<3, 2, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat3x3.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat3x3.hpp\n\n#pragma once\n\n#include \"type_vec3.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<3, 3, T, Q>\n\t{\n\t\ttypedef vec<3, T, Q> col_type;\n\t\ttypedef vec<3, T, Q> row_type;\n\t\ttypedef mat<3, 3, T, Q> type;\n\t\ttypedef mat<3, 3, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[3];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 3, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT x0, T y0, T z0,\n\t\t\tT x1, T y1, T z1,\n\t\t\tT x2, T y2, T z2);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X1, typename Y1, typename Z1,\n\t\t\ttypename X2, typename Y2, typename Z2,\n\t\t\ttypename X3, typename Y3, typename Z3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 x1, Y1 y1, Z1 z1,\n\t\t\tX2 x2, Y2 y2, Z2 z2,\n\t\t\tX3 x3, Y3 y3, Z3 z3);\n\n\t\ttemplate<typename V1, typename V2, typename V3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<3, V1, Q> const& v1,\n\t\t\tvec<3, V2, Q> const& v2,\n\t\t\tvec<3, V3, Q> const& v3);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator=(mat<3, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator+=(mat<3, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator-=(mat<3, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator*=(mat<3, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator/=(mat<3, 3, U, Q> const& m);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator++();\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> & operator--();\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<3, 3, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat3x3.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat3x3.inl",
    "content": "#include \"../matrix.hpp\"\n\nnamespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\tthis->value[0] = col_type(1, 0, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1, 0);\n\t\t\t\tthis->value[2] = col_type(0, 0, 1);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(T s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0, 0);\n\t\t\tthis->value[1] = col_type(0, s, 0);\n\t\t\tthis->value[2] = col_type(0, 0, s);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat\n\t(\n\t\tT x0, T y0, T z0,\n\t\tT x1, T y1, T z1,\n\t\tT x2, T y2, T z2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1);\n\t\t\tthis->value[2] = col_type(x2, y2, z2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v0);\n\t\t\tthis->value[1] = col_type(v1);\n\t\t\tthis->value[2] = col_type(v2);\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X1, typename Y1, typename Z1,\n\t\ttypename X2, typename Y2, typename Z2,\n\t\ttypename X3, typename Y3, typename Z3>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat\n\t(\n\t\tX1 x1, Y1 y1, Z1 z1,\n\t\tX2 x2, Y2 y2, Z2 z2,\n\t\tX3 x3, Y3 y3, Z3 z3\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x1, y1, z1);\n\t\t\tthis->value[1] = col_type(x2, y2, z2);\n\t\t\tthis->value[2] = col_type(x3, y3, z3);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2, typename V3>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v1), col_type(v2), col_type(v3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v1);\n\t\t\tthis->value[1] = col_type(v2);\n\t\t\tthis->value[2] = col_type(v3);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 3, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 3, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type & mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 3, T, Q>::col_type const& mat<3, 3, T, Q>::operator[](typename mat<3, 3, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator=(mat<3, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\tthis->value[2] = m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\tthis->value[2] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator+=(mat<3, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\tthis->value[2] += m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\tthis->value[2] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator-=(mat<3, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\tthis->value[2] -= m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\tthis->value[2] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator*=(mat<3, 3, U, Q> const& m)\n\t{\n\t\treturn (*this = *this * m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\tthis->value[2] /= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator/=(mat<3, 3, U, Q> const& m)\n\t{\n\t\treturn *this *= inverse(m);\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\t++this->value[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> & mat<3, 3, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\t--this->value[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator++(int)\n\t{\n\t\tmat<3, 3, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat<3, 3, T, Q>::operator--(int)\n\t{\n\t\tmat<3, 3, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1],\n\t\t\t-m[2]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar,\n\t\t\tm[2] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(T scalar, mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar,\n\t\t\tm[2] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator+(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1],\n\t\t\tm1[2] + m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar,\n\t\t\tm[2] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(T scalar, mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tscalar - m[0],\n\t\t\tscalar - m[1],\n\t\t\tscalar - m[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator-(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1],\n\t\t\tm1[2] - m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(T scalar, mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator*(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v)\n\t{\n\t\treturn typename mat<3, 3, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z,\n\t\t\tm[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator*(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn typename mat<3, 3, T, Q>::row_type(\n\t\t\tm[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,\n\t\t\tm[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,\n\t\t\tm[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\tT const SrcA00 = m1[0][0];\n\t\tT const SrcA01 = m1[0][1];\n\t\tT const SrcA02 = m1[0][2];\n\t\tT const SrcA10 = m1[1][0];\n\t\tT const SrcA11 = m1[1][1];\n\t\tT const SrcA12 = m1[1][2];\n\t\tT const SrcA20 = m1[2][0];\n\t\tT const SrcA21 = m1[2][1];\n\t\tT const SrcA22 = m1[2][2];\n\n\t\tT const SrcB00 = m2[0][0];\n\t\tT const SrcB01 = m2[0][1];\n\t\tT const SrcB02 = m2[0][2];\n\t\tT const SrcB10 = m2[1][0];\n\t\tT const SrcB11 = m2[1][1];\n\t\tT const SrcB12 = m2[1][2];\n\t\tT const SrcB20 = m2[2][0];\n\t\tT const SrcB21 = m2[2][1];\n\t\tT const SrcB22 = m2[2][2];\n\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;\n\t\tResult[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;\n\t\tResult[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12;\n\t\tResult[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22;\n\t\tResult[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22;\n\t\tResult[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<3, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],\n\t\t\tm1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2],\n\t\t\tm1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2],\n\t\t\tm1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2],\n\t\t\tm1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m,\tT scalar)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar,\n\t\t\tm[2] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(T scalar, mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1],\n\t\t\tscalar / m[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::col_type operator/(mat<3, 3, T, Q> const& m, typename mat<3, 3, T, Q>::row_type const& v)\n\t{\n\t\treturn  inverse(m) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 3, T, Q>::row_type operator/(typename mat<3, 3, T, Q>::col_type const& v, mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn v * inverse(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator/(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\tmat<3, 3, T, Q> m1_copy(m1);\n\t\treturn m1_copy /= m2;\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<3, 3, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat3x4.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat3x4.hpp\n\n#pragma once\n\n#include \"type_vec3.hpp\"\n#include \"type_vec4.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<3, 4, T, Q>\n\t{\n\t\ttypedef vec<4, T, Q> col_type;\n\t\ttypedef vec<3, T, Q> row_type;\n\t\ttypedef mat<3, 4, T, Q> type;\n\t\ttypedef mat<4, 3, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[3];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 3; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<3, 4, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT x0, T y0, T z0, T w0,\n\t\t\tT x1, T y1, T z1, T w1,\n\t\t\tT x2, T y2, T z2, T w2);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X1, typename Y1, typename Z1, typename W1,\n\t\t\ttypename X2, typename Y2, typename Z2, typename W2,\n\t\t\ttypename X3, typename Y3, typename Z3, typename W3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 x1, Y1 y1, Z1 z1, W1 w1,\n\t\t\tX2 x2, Y2 y2, Z2 z2, W2 w2,\n\t\t\tX3 x3, Y3 y3, Z3 z3, W3 w3);\n\n\t\ttemplate<typename V1, typename V2, typename V3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<4, V1, Q> const& v1,\n\t\t\tvec<4, V2, Q> const& v2,\n\t\t\tvec<4, V3, Q> const& v3);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator=(mat<3, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator+=(mat<3, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator-=(mat<3, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator/=(U s);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator++();\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> & operator--();\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<3, 4, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 4, T, Q>::col_type operator*(mat<3, 4, T, Q> const& m, typename mat<3, 4, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<3, 4, T, Q>::row_type operator*(typename mat<3, 4, T, Q>::col_type const& v, mat<3, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1,\tmat<4, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1,\tmat<3, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat3x4.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat3x4.inl",
    "content": "namespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0, 0, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1, 0, 0);\n\t\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(T s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0, 0, 0);\n\t\t\tthis->value[1] = col_type(0, s, 0, 0);\n\t\t\tthis->value[2] = col_type(0, 0, s, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat\n\t(\n\t\tT x0, T y0, T z0, T w0,\n\t\tT x1, T y1, T z1, T w1,\n\t\tT x2, T y2, T z2, T w2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{\n\t\t\t\tcol_type(x0, y0, z0, w0),\n\t\t\t\tcol_type(x1, y1, z1, w1),\n\t\t\t\tcol_type(x2, y2, z2, w2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0, w0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1, w1);\n\t\t\tthis->value[2] = col_type(x2, y2, z2, w2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n\t\t\tthis->value[2] = v2;\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X0, typename Y0, typename Z0, typename W0,\n\t\ttypename X1, typename Y1, typename Z1, typename W1,\n\t\ttypename X2, typename Y2, typename Z2, typename W2>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat\n\t(\n\t\tX0 x0, Y0 y0, Z0 z0, W0 w0,\n\t\tX1 x1, Y1 y1, Z1 z1, W1 w1,\n\t\tX2 x2, Y2 y2, Z2 z2, W2 w2\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{\n\t\t\t\tcol_type(x0, y0, z0, w0),\n\t\t\t\tcol_type(x1, y1, z1, w1),\n\t\t\t\tcol_type(x2, y2, z2, w2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0, w0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1, w1);\n\t\t\tthis->value[2] = col_type(x2, y2, z2, w2);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2, typename V3>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(vec<4, V1, Q> const& v0, vec<4, V2, Q> const& v1, vec<4, V3, Q> const& v2)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v0);\n\t\t\tthis->value[1] = col_type(v1);\n\t\t\tthis->value[2] = col_type(v2);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 4, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n\t\t\tthis->value[2] = col_type(m[2], 1, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n\t\t\tthis->value[2] = col_type(m[2], 1, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<3, 4, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 0);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type & mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<3, 4, T, Q>::col_type const& mat<3, 4, T, Q>::operator[](typename mat<3, 4, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator=(mat<3, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\tthis->value[2] = m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\tthis->value[2] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator+=(mat<3, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\tthis->value[2] += m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\tthis->value[2] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator-=(mat<3, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\tthis->value[2] -= m[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\tthis->value[2] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> & mat<3, 4, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\tthis->value[2] /= s;\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\t++this->value[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q>& mat<3, 4, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\t--this->value[2];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator++(int)\n\t{\n\t\tmat<3, 4, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat<3, 4, T, Q>::operator--(int)\n\t{\n\t\tmat<3, 4, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1],\n\t\t\t-m[2]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar,\n\t\t\tm[2] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator+(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1],\n\t\t\tm1[2] + m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m,\tT scalar)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar,\n\t\t\tm[2] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator-(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1],\n\t\t\tm1[2] - m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(T scalar, mat<3, 4, T, Q> const& m)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::col_type operator*\n\t(\n\t\tmat<3, 4, T, Q> const& m,\n\t\ttypename mat<3, 4, T, Q>::row_type const& v\n\t)\n\t{\n\t\treturn typename mat<3, 4, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z,\n\t\t\tm[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z,\n\t\t\tm[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<3, 4, T, Q>::row_type operator*\n\t(\n\t\ttypename mat<3, 4, T, Q>::col_type const& v,\n\t\tmat<3, 4, T, Q> const& m\n\t)\n\t{\n\t\treturn typename mat<3, 4, T, Q>::row_type(\n\t\t\tv.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],\n\t\t\tv.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3],\n\t\t\tv.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\tconst T SrcA00 = m1[0][0];\n\t\tconst T SrcA01 = m1[0][1];\n\t\tconst T SrcA02 = m1[0][2];\n\t\tconst T SrcA03 = m1[0][3];\n\t\tconst T SrcA10 = m1[1][0];\n\t\tconst T SrcA11 = m1[1][1];\n\t\tconst T SrcA12 = m1[1][2];\n\t\tconst T SrcA13 = m1[1][3];\n\t\tconst T SrcA20 = m1[2][0];\n\t\tconst T SrcA21 = m1[2][1];\n\t\tconst T SrcA22 = m1[2][2];\n\t\tconst T SrcA23 = m1[2][3];\n\n\t\tconst T SrcB00 = m2[0][0];\n\t\tconst T SrcB01 = m2[0][1];\n\t\tconst T SrcB02 = m2[0][2];\n\t\tconst T SrcB10 = m2[1][0];\n\t\tconst T SrcB11 = m2[1][1];\n\t\tconst T SrcB12 = m2[1][2];\n\t\tconst T SrcB20 = m2[2][0];\n\t\tconst T SrcB21 = m2[2][1];\n\t\tconst T SrcB22 = m2[2][2];\n\t\tconst T SrcB30 = m2[3][0];\n\t\tconst T SrcB31 = m2[3][1];\n\t\tconst T SrcB32 = m2[3][2];\n\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;\n\t\tResult[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02;\n\t\tResult[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01 + SrcA23 * SrcB02;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;\n\t\tResult[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12;\n\t\tResult[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11 + SrcA23 * SrcB12;\n\t\tResult[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22;\n\t\tResult[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22;\n\t\tResult[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22;\n\t\tResult[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21 + SrcA23 * SrcB22;\n\t\tResult[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31 + SrcA20 * SrcB32;\n\t\tResult[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31 + SrcA21 * SrcB32;\n\t\tResult[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31 + SrcA22 * SrcB32;\n\t\tResult[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31 + SrcA23 * SrcB32;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<2, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],\n\t\t\tm1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],\n\t\t\tm1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<3, 4, T, Q> const& m1, mat<3, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],\n\t\t\tm1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],\n\t\t\tm1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],\n\t\t\tm1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2],\n\t\t\tm1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(mat<3, 4, T, Q> const& m,\tT scalar)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar,\n\t\t\tm[2] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator/(T scalar, mat<3, 4, T, Q> const& m)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1],\n\t\t\tscalar / m[2]);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<3, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x2.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat4x2.hpp\n\n#pragma once\n\n#include \"type_vec2.hpp\"\n#include \"type_vec4.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<4, 2, T, Q>\n\t{\n\t\ttypedef vec<2, T, Q> col_type;\n\t\ttypedef vec<4, T, Q> row_type;\n\t\ttypedef mat<4, 2, T, Q> type;\n\t\ttypedef mat<2, 4, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[4];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 2, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT x0, T y0,\n\t\t\tT x1, T y1,\n\t\t\tT x2, T y2,\n\t\t\tT x3, T y3);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2,\n\t\t\tcol_type const& v3);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X0, typename Y0,\n\t\t\ttypename X1, typename Y1,\n\t\t\ttypename X2, typename Y2,\n\t\t\ttypename X3, typename Y3>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX0 x0, Y0 y0,\n\t\t\tX1 x1, Y1 y1,\n\t\t\tX2 x2, Y2 y2,\n\t\t\tX3 x3, Y3 y3);\n\n\t\ttemplate<typename V1, typename V2, typename V3, typename V4>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<2, V1, Q> const& v1,\n\t\t\tvec<2, V2, Q> const& v2,\n\t\t\tvec<2, V3, Q> const& v3,\n\t\t\tvec<2, V4, Q> const& v4);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator=(mat<4, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator+=(mat<4, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator-=(mat<4, 2, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator/=(U s);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator++ ();\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> & operator-- ();\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<4, 2, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1,\tmat<4, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat4x2.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x2.inl",
    "content": "namespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0), col_type(0, 1), col_type(0, 0), col_type(0, 0)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1);\n\t\t\t\tthis->value[2] = col_type(0, 0);\n\t\t\t\tthis->value[3] = col_type(0, 0);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n\t\t\tthis->value[3] = m[3];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(T s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0), col_type(0, s), col_type(0, 0), col_type(0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0);\n\t\t\tthis->value[1] = col_type(0, s);\n\t\t\tthis->value[2] = col_type(0, 0);\n\t\t\tthis->value[3] = col_type(0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat\n\t(\n\t\tT x0, T y0,\n\t\tT x1, T y1,\n\t\tT x2, T y2,\n\t\tT x3, T y3\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0);\n\t\t\tthis->value[1] = col_type(x1, y1);\n\t\t\tthis->value[2] = col_type(x2, y2);\n\t\t\tthis->value[3] = col_type(x3, y3);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n\t\t\tthis->value[2] = v2;\n\t\t\tthis->value[3] = v3;\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X0, typename Y0,\n\t\ttypename X1, typename Y1,\n\t\ttypename X2, typename Y2,\n\t\ttypename X3, typename Y3>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat\n\t(\n\t\tX0 x0, Y0 y0,\n\t\tX1 x1, Y1 y1,\n\t\tX2 x2, Y2 y2,\n\t\tX3 x3, Y3 y3\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0), col_type(x1, y1), col_type(x2, y2), col_type(x3, y3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0);\n\t\t\tthis->value[1] = col_type(x1, y1);\n\t\t\tthis->value[2] = col_type(x2, y2);\n\t\t\tthis->value[3] = col_type(x3, y3);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V0, typename V1, typename V2, typename V3>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(vec<2, V0, Q> const& v0, vec<2, V1, Q> const& v1, vec<2, V2, Q> const& v2, vec<2, V3, Q> const& v3)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v0);\n\t\t\tthis->value[1] = col_type(v1);\n\t\t\tthis->value[2] = col_type(v2);\n\t\t\tthis->value[3] = col_type(v3);\n#\t\tendif\n\t}\n\n\t// -- Conversion --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 2, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(m[3]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(m[3]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\t\tthis->value[3] = col_type(m[3]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 2, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type & mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 2, T, Q>::col_type const& mat<4, 2, T, Q>::operator[](typename mat<4, 2, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q>& mat<4, 2, T, Q>::operator=(mat<4, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\tthis->value[2] = m[2];\n\t\tthis->value[3] = m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\tthis->value[2] += s;\n\t\tthis->value[3] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator+=(mat<4, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\tthis->value[2] += m[2];\n\t\tthis->value[3] += m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\tthis->value[2] -= s;\n\t\tthis->value[3] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator-=(mat<4, 2, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\tthis->value[2] -= m[2];\n\t\tthis->value[3] -= m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\tthis->value[2] *= s;\n\t\tthis->value[3] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\tthis->value[2] /= s;\n\t\tthis->value[3] /= s;\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\t++this->value[2];\n\t\t++this->value[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> & mat<4, 2, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\t--this->value[2];\n\t\t--this->value[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator++(int)\n\t{\n\t\tmat<4, 2, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> mat<4, 2, T, Q>::operator--(int)\n\t{\n\t\tmat<4, 2, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1],\n\t\t\t-m[2],\n\t\t\t-m[3]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm[0] + scalar,\n\t\t\tm[1] + scalar,\n\t\t\tm[2] + scalar,\n\t\t\tm[3] + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator+(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1],\n\t\t\tm1[2] + m2[2],\n\t\t\tm1[3] + m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm[0] - scalar,\n\t\t\tm[1] - scalar,\n\t\t\tm[2] - scalar,\n\t\t\tm[3] - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator-(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1],\n\t\t\tm1[2] - m2[2],\n\t\t\tm1[3] - m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar,\n\t\t\tm[3] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(T scalar, mat<4, 2, T, Q> const& m)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm[0] * scalar,\n\t\t\tm[1] * scalar,\n\t\t\tm[2] * scalar,\n\t\t\tm[3] * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::col_type operator*(mat<4, 2, T, Q> const& m, typename mat<4, 2, T, Q>::row_type const& v)\n\t{\n\t\treturn typename mat<4, 2, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 2, T, Q>::row_type operator*(typename mat<4, 2, T, Q>::col_type const& v, mat<4, 2, T, Q> const& m)\n\t{\n\t\treturn typename mat<4, 2, T, Q>::row_type(\n\t\t\tv.x * m[0][0] + v.y * m[0][1],\n\t\t\tv.x * m[1][0] + v.y * m[1][1],\n\t\t\tv.x * m[2][0] + v.y * m[2][1],\n\t\t\tv.x * m[3][0] + v.y * m[3][1]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\tT const SrcA00 = m1[0][0];\n\t\tT const SrcA01 = m1[0][1];\n\t\tT const SrcA10 = m1[1][0];\n\t\tT const SrcA11 = m1[1][1];\n\t\tT const SrcA20 = m1[2][0];\n\t\tT const SrcA21 = m1[2][1];\n\t\tT const SrcA30 = m1[3][0];\n\t\tT const SrcA31 = m1[3][1];\n\n\t\tT const SrcB00 = m2[0][0];\n\t\tT const SrcB01 = m2[0][1];\n\t\tT const SrcB02 = m2[0][2];\n\t\tT const SrcB03 = m2[0][3];\n\t\tT const SrcB10 = m2[1][0];\n\t\tT const SrcB11 = m2[1][1];\n\t\tT const SrcB12 = m2[1][2];\n\t\tT const SrcB13 = m2[1][3];\n\n\t\tmat<2, 2, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator*(mat<4, 2, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3],\n\t\t\tm1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3],\n\t\t\tm1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(mat<4, 2, T, Q> const& m, T scalar)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tm[0] / scalar,\n\t\t\tm[1] / scalar,\n\t\t\tm[2] / scalar,\n\t\t\tm[3] / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> operator/(T scalar, mat<4, 2, T, Q> const& m)\n\t{\n\t\treturn mat<4, 2, T, Q>(\n\t\t\tscalar / m[0],\n\t\t\tscalar / m[1],\n\t\t\tscalar / m[2],\n\t\t\tscalar / m[3]);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<4, 2, T, Q> const& m1, mat<4, 2, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x3.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat4x3.hpp\n\n#pragma once\n\n#include \"type_vec3.hpp\"\n#include \"type_vec4.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<4, 3, T, Q>\n\t{\n\t\ttypedef vec<3, T, Q> col_type;\n\t\ttypedef vec<4, T, Q> row_type;\n\t\ttypedef mat<4, 3, T, Q> type;\n\t\ttypedef mat<3, 4, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[4];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length() { return 4; }\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 3, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT const& x0, T const& y0, T const& z0,\n\t\t\tT const& x1, T const& y1, T const& z1,\n\t\t\tT const& x2, T const& y2, T const& z2,\n\t\t\tT const& x3, T const& y3, T const& z3);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2,\n\t\t\tcol_type const& v3);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X1, typename Y1, typename Z1,\n\t\t\ttypename X2, typename Y2, typename Z2,\n\t\t\ttypename X3, typename Y3, typename Z3,\n\t\t\ttypename X4, typename Y4, typename Z4>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 const& x1, Y1 const& y1, Z1 const& z1,\n\t\t\tX2 const& x2, Y2 const& y2, Z2 const& z2,\n\t\t\tX3 const& x3, Y3 const& y3, Z3 const& z3,\n\t\t\tX4 const& x4, Y4 const& y4, Z4 const& z4);\n\n\t\ttemplate<typename V1, typename V2, typename V3, typename V4>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<3, V1, Q> const& v1,\n\t\t\tvec<3, V2, Q> const& v2,\n\t\t\tvec<3, V3, Q> const& v3,\n\t\t\tvec<3, V4, Q> const& v4);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator=(mat<4, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator+=(mat<4, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator-=(mat<4, 3, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> & operator/=(U s);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q>& operator++();\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q>& operator--();\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<4, 3, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 3, T, Q>::col_type operator*(mat<4, 3, T, Q> const& m, typename mat<4, 3, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 3, T, Q>::row_type operator*(typename mat<4, 3, T, Q>::col_type const& v, mat<4, 3, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1,\tmat<3, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat4x3.inl\"\n#endif //GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x3.inl",
    "content": "namespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0, 0), col_type(0, 1, 0), col_type(0, 0, 1), col_type(0, 0, 0)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1, 0);\n\t\t\t\tthis->value[2] = col_type(0, 0, 1);\n\t\t\t\tthis->value[3] = col_type(0, 0, 0);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n\t\t\tthis->value[3] = m[3];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(T const& s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0, 0), col_type(0, s, 0), col_type(0, 0, s), col_type(0, 0, 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0, 0);\n\t\t\tthis->value[1] = col_type(0, s, 0);\n\t\t\tthis->value[2] = col_type(0, 0, s);\n\t\t\tthis->value[3] = col_type(0, 0, 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat\n\t(\n\t\tT const& x0, T const& y0, T const& z0,\n\t\tT const& x1, T const& y1, T const& z1,\n\t\tT const& x2, T const& y2, T const& z2,\n\t\tT const& x3, T const& y3, T const& z3\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1);\n\t\t\tthis->value[2] = col_type(x2, y2, z2);\n\t\t\tthis->value[3] = col_type(x3, y3, z3);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n\t\t\tthis->value[2] = v2;\n\t\t\tthis->value[3] = v3;\n#\t\tendif\n\t}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X0, typename Y0, typename Z0,\n\t\ttypename X1, typename Y1, typename Z1,\n\t\ttypename X2, typename Y2, typename Z2,\n\t\ttypename X3, typename Y3, typename Z3>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat\n\t(\n\t\tX0 const& x0, Y0 const& y0, Z0 const& z0,\n\t\tX1 const& x1, Y1 const& y1, Z1 const& z1,\n\t\tX2 const& x2, Y2 const& y2, Z2 const& z2,\n\t\tX3 const& x3, Y3 const& y3, Z3 const& z3\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x0, y0, z0), col_type(x1, y1, z1), col_type(x2, y2, z2), col_type(x3, y3, z3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1);\n\t\t\tthis->value[2] = col_type(x2, y2, z2);\n\t\t\tthis->value[3] = col_type(x3, y3, z3);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2, typename V3, typename V4>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(vec<3, V1, Q> const& v1, vec<3, V2, Q> const& v2, vec<3, V3, Q> const& v3, vec<3, V4, Q> const& v4)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v1);\n\t\t\tthis->value[1] = col_type(v2);\n\t\t\tthis->value[2] = col_type(v3);\n\t\t\tthis->value[3] = col_type(v4);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 3, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(m[3]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(m[3]);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0, 0, 1);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 1);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(0, 0, 1);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 1), col_type(m[3], 0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 1);\n\t\t\tthis->value[3] = col_type(m[3], 0);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 3, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(0);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type & mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 3, T, Q>::col_type const& mat<4, 3, T, Q>::operator[](typename mat<4, 3, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary updatable operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q>& mat<4, 3, T, Q>::operator=(mat<4, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\tthis->value[2] = m[2];\n\t\tthis->value[3] = m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\tthis->value[2] += s;\n\t\tthis->value[3] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator+=(mat<4, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\tthis->value[2] += m[2];\n\t\tthis->value[3] += m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\tthis->value[2] -= s;\n\t\tthis->value[3] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator-=(mat<4, 3, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\tthis->value[2] -= m[2];\n\t\tthis->value[3] -= m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\tthis->value[2] *= s;\n\t\tthis->value[3] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\tthis->value[2] /= s;\n\t\tthis->value[3] /= s;\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\t++this->value[2];\n\t\t++this->value[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> & mat<4, 3, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\t--this->value[2];\n\t\t--this->value[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator++(int)\n\t{\n\t\tmat<4, 3, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> mat<4, 3, T, Q>::operator--(int)\n\t{\n\t\tmat<4, 3, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1],\n\t\t\t-m[2],\n\t\t\t-m[3]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm[0] + s,\n\t\t\tm[1] + s,\n\t\t\tm[2] + s,\n\t\t\tm[3] + s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator+(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1],\n\t\t\tm1[2] + m2[2],\n\t\t\tm1[3] + m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm[0] - s,\n\t\t\tm[1] - s,\n\t\t\tm[2] - s,\n\t\t\tm[3] - s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator-(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1],\n\t\t\tm1[2] - m2[2],\n\t\t\tm1[3] - m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm[0] * s,\n\t\t\tm[1] * s,\n\t\t\tm[2] * s,\n\t\t\tm[3] * s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(T const& s, mat<4, 3, T, Q> const& m)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm[0] * s,\n\t\t\tm[1] * s,\n\t\t\tm[2] * s,\n\t\t\tm[3] * s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::col_type operator*\n\t(\n\t\tmat<4, 3, T, Q> const& m,\n\t\ttypename mat<4, 3, T, Q>::row_type const& v)\n\t{\n\t\treturn typename mat<4, 3, T, Q>::col_type(\n\t\t\tm[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w,\n\t\t\tm[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w,\n\t\t\tm[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 3, T, Q>::row_type operator*\n\t(\n\t\ttypename mat<4, 3, T, Q>::col_type const& v,\n\t\tmat<4, 3, T, Q> const& m)\n\t{\n\t\treturn typename mat<4, 3, T, Q>::row_type(\n\t\t\tv.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2],\n\t\t\tv.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2],\n\t\t\tv.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2],\n\t\t\tv.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 3, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\tT const SrcA00 = m1[0][0];\n\t\tT const SrcA01 = m1[0][1];\n\t\tT const SrcA02 = m1[0][2];\n\t\tT const SrcA10 = m1[1][0];\n\t\tT const SrcA11 = m1[1][1];\n\t\tT const SrcA12 = m1[1][2];\n\t\tT const SrcA20 = m1[2][0];\n\t\tT const SrcA21 = m1[2][1];\n\t\tT const SrcA22 = m1[2][2];\n\t\tT const SrcA30 = m1[3][0];\n\t\tT const SrcA31 = m1[3][1];\n\t\tT const SrcA32 = m1[3][2];\n\n\t\tT const SrcB00 = m2[0][0];\n\t\tT const SrcB01 = m2[0][1];\n\t\tT const SrcB02 = m2[0][2];\n\t\tT const SrcB03 = m2[0][3];\n\t\tT const SrcB10 = m2[1][0];\n\t\tT const SrcB11 = m2[1][1];\n\t\tT const SrcB12 = m2[1][2];\n\t\tT const SrcB13 = m2[1][3];\n\t\tT const SrcB20 = m2[2][0];\n\t\tT const SrcB21 = m2[2][1];\n\t\tT const SrcB22 = m2[2][2];\n\t\tT const SrcB23 = m2[2][3];\n\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03;\n\t\tResult[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03;\n\t\tResult[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02 + SrcA32 * SrcB03;\n\t\tResult[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13;\n\t\tResult[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13;\n\t\tResult[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12 + SrcA32 * SrcB13;\n\t\tResult[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22 + SrcA30 * SrcB23;\n\t\tResult[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22 + SrcA31 * SrcB23;\n\t\tResult[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22 + SrcA32 * SrcB23;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator*(mat<4, 3, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3],\n\t\t\tm1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3],\n\t\t\tm1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3],\n\t\t\tm1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3],\n\t\t\tm1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(mat<4, 3, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\tm[0] / s,\n\t\t\tm[1] / s,\n\t\t\tm[2] / s,\n\t\t\tm[3] / s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> operator/(T const& s, mat<4, 3, T, Q> const& m)\n\t{\n\t\treturn mat<4, 3, T, Q>(\n\t\t\ts / m[0],\n\t\t\ts / m[1],\n\t\t\ts / m[2],\n\t\t\ts / m[3]);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<4, 3, T, Q> const& m1, mat<4, 3, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x4.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_mat4x4.hpp\n\n#pragma once\n\n#include \"type_vec4.hpp\"\n#include <limits>\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct mat<4, 4, T, Q>\n\t{\n\t\ttypedef vec<4, T, Q> col_type;\n\t\ttypedef vec<4, T, Q> row_type;\n\t\ttypedef mat<4, 4, T, Q> type;\n\t\ttypedef mat<4, 4, T, Q> transpose_type;\n\t\ttypedef T value_type;\n\n\tprivate:\n\t\tcol_type value[4];\n\n\tpublic:\n\t\t// -- Accesses --\n\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;}\n\n\t\tGLM_FUNC_DECL col_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR col_type const& operator[](length_type i) const;\n\n\t\t// -- Constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat() GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(mat<4, 4, T, P> const& m);\n\n\t\tGLM_FUNC_DECL explicit GLM_CONSTEXPR mat(T const& x);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tT const& x0, T const& y0, T const& z0, T const& w0,\n\t\t\tT const& x1, T const& y1, T const& z1, T const& w1,\n\t\t\tT const& x2, T const& y2, T const& z2, T const& w2,\n\t\t\tT const& x3, T const& y3, T const& z3, T const& w3);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tcol_type const& v0,\n\t\t\tcol_type const& v1,\n\t\t\tcol_type const& v2,\n\t\t\tcol_type const& v3);\n\n\t\t// -- Conversions --\n\n\t\ttemplate<\n\t\t\ttypename X1, typename Y1, typename Z1, typename W1,\n\t\t\ttypename X2, typename Y2, typename Z2, typename W2,\n\t\t\ttypename X3, typename Y3, typename Z3, typename W3,\n\t\t\ttypename X4, typename Y4, typename Z4, typename W4>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tX1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1,\n\t\t\tX2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2,\n\t\t\tX3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3,\n\t\t\tX4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4);\n\n\t\ttemplate<typename V1, typename V2, typename V3, typename V4>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR mat(\n\t\t\tvec<4, V1, Q> const& v1,\n\t\t\tvec<4, V2, Q> const& v2,\n\t\t\tvec<4, V3, Q> const& v3,\n\t\t\tvec<4, V4, Q> const& v4);\n\n\t\t// -- Matrix conversions --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 4, U, P> const& m);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 3, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<2, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 2, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<3, 4, T, Q> const& x);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR mat(mat<4, 3, T, Q> const& x);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator=(mat<4, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator+=(mat<4, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator-=(mat<4, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator*=(mat<4, 4, U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator/=(mat<4, 4, U, Q> const& m);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator++();\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> & operator--();\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL mat<4, 4, T, Q> operator--(int);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1,\tmat<4, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator*(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator*(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator/(T const& s, mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1,\tmat<4, 4, T, Q> const& m2);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_mat4x4.inl\"\n#endif//GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x4.inl",
    "content": "#include \"../matrix.hpp\"\n\nnamespace glm\n{\n\t// -- Constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat()\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALIZER_LIST\n\t\t\t\t: value{col_type(1, 0, 0, 0), col_type(0, 1, 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)}\n#\t\t\tendif\n\t\t{\n#\t\t\tif GLM_CONFIG_CTOR_INIT == GLM_CTOR_INITIALISATION\n\t\t\t\tthis->value[0] = col_type(1, 0, 0, 0);\n\t\t\t\tthis->value[1] = col_type(0, 1, 0, 0);\n\t\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n\t\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\t\tendif\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, T, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n\t\t\tthis->value[3] = m[3];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(T const& s)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(s, 0, 0, 0), col_type(0, s, 0, 0), col_type(0, 0, s, 0), col_type(0, 0, 0, s)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(s, 0, 0, 0);\n\t\t\tthis->value[1] = col_type(0, s, 0, 0);\n\t\t\tthis->value[2] = col_type(0, 0, s, 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, s);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat\n\t(\n\t\tT const& x0, T const& y0, T const& z0, T const& w0,\n\t\tT const& x1, T const& y1, T const& z1, T const& w1,\n\t\tT const& x2, T const& y2, T const& z2, T const& w2,\n\t\tT const& x3, T const& y3, T const& z3, T const& w3\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{\n\t\t\t\tcol_type(x0, y0, z0, w0),\n\t\t\t\tcol_type(x1, y1, z1, w1),\n\t\t\t\tcol_type(x2, y2, z2, w2),\n\t\t\t\tcol_type(x3, y3, z3, w3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x0, y0, z0, w0);\n\t\t\tthis->value[1] = col_type(x1, y1, z1, w1);\n\t\t\tthis->value[2] = col_type(x2, y2, z2, w2);\n\t\t\tthis->value[3] = col_type(x3, y3, z3, w3);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(col_type const& v0, col_type const& v1, col_type const& v2, col_type const& v3)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v0), col_type(v1), col_type(v2), col_type(v3)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = v0;\n\t\t\tthis->value[1] = v1;\n\t\t\tthis->value[2] = v2;\n\t\t\tthis->value[3] = v3;\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 4, U, P> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(m[3])}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0]);\n\t\t\tthis->value[1] = col_type(m[1]);\n\t\t\tthis->value[2] = col_type(m[2]);\n\t\t\tthis->value[3] = col_type(m[3]);\n#\t\tendif\n\t}\n\n\t// -- Conversions --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<\n\t\ttypename X1, typename Y1, typename Z1, typename W1,\n\t\ttypename X2, typename Y2, typename Z2, typename W2,\n\t\ttypename X3, typename Y3, typename Z3, typename W3,\n\t\ttypename X4, typename Y4, typename Z4, typename W4>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat\n\t(\n\t\tX1 const& x1, Y1 const& y1, Z1 const& z1, W1 const& w1,\n\t\tX2 const& x2, Y2 const& y2, Z2 const& z2, W2 const& w2,\n\t\tX3 const& x3, Y3 const& y3, Z3 const& z3, W3 const& w3,\n\t\tX4 const& x4, Y4 const& y4, Z4 const& z4, W4 const& w4\n\t)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(x1, y1, z1, w1), col_type(x2, y2, z2, w2), col_type(x3, y3, z3, w3), col_type(x4, y4, z4, w4)}\n#\t\tendif\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<X1>::is_iec559 || std::numeric_limits<X1>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 1st parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Y1>::is_iec559 || std::numeric_limits<Y1>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Z1>::is_iec559 || std::numeric_limits<Z1>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<W1>::is_iec559 || std::numeric_limits<W1>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 4th parameter type invalid.\");\n\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<X2>::is_iec559 || std::numeric_limits<X2>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 5th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Y2>::is_iec559 || std::numeric_limits<Y2>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 6th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Z2>::is_iec559 || std::numeric_limits<Z2>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 7th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<W2>::is_iec559 || std::numeric_limits<W2>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 8th parameter type invalid.\");\n\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<X3>::is_iec559 || std::numeric_limits<X3>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 9th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Y3>::is_iec559 || std::numeric_limits<Y3>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 10th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Z3>::is_iec559 || std::numeric_limits<Z3>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 11th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<W3>::is_iec559 || std::numeric_limits<W3>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 12th parameter type invalid.\");\n\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<X4>::is_iec559 || std::numeric_limits<X4>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 13th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Y4>::is_iec559 || std::numeric_limits<Y4>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 14th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<Z4>::is_iec559 || std::numeric_limits<Z4>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 15th parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<W4>::is_iec559 || std::numeric_limits<W4>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 16th parameter type invalid.\");\n\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(x1, y1, z1, w1);\n\t\t\tthis->value[1] = col_type(x2, y2, z2, w2);\n\t\t\tthis->value[2] = col_type(x3, y3, z3, w3);\n\t\t\tthis->value[3] = col_type(x4, y4, z4, w4);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename V1, typename V2, typename V3, typename V4>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(vec<4, V1, Q> const& v1, vec<4, V2, Q> const& v2, vec<4, V3, Q> const& v3, vec<4, V4, Q> const& v4)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(v1), col_type(v2), col_type(v3), col_type(v4)}\n#\t\tendif\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<V1>::is_iec559 || std::numeric_limits<V1>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 1st parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<V2>::is_iec559 || std::numeric_limits<V2>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<V3>::is_iec559 || std::numeric_limits<V3>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid.\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<V4>::is_iec559 || std::numeric_limits<V4>::is_integer || GLM_CONFIG_UNRESTRICTED_GENTYPE, \"*mat4x4 constructor only takes float and integer types, 4th parameter type invalid.\");\n\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(v1);\n\t\t\tthis->value[1] = col_type(v2);\n\t\t\tthis->value[2] = col_type(v3);\n\t\t\tthis->value[3] = col_type(v4);\n#\t\tendif\n\t}\n\n\t// -- Matrix conversions --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(m[2], 1, 0), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n\t\t\tthis->value[2] = col_type(m[2], 1, 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<2, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 2, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0, 0), col_type(m[1], 0, 0), col_type(0, 0, 1, 0), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0, 0);\n\t\t\tthis->value[1] = col_type(m[1], 0, 0);\n\t\t\tthis->value[2] = col_type(0, 0, 1, 0);\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<3, 4, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0]), col_type(m[1]), col_type(m[2]), col_type(0, 0, 0, 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = m[0];\n\t\t\tthis->value[1] = m[1];\n\t\t\tthis->value[2] = m[2];\n\t\t\tthis->value[3] = col_type(0, 0, 0, 1);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR mat<4, 4, T, Q>::mat(mat<4, 3, T, Q> const& m)\n#\t\tif GLM_HAS_INITIALIZER_LISTS\n\t\t\t: value{col_type(m[0], 0), col_type(m[1], 0), col_type(m[2], 0), col_type(m[3], 1)}\n#\t\tendif\n\t{\n#\t\tif !GLM_HAS_INITIALIZER_LISTS\n\t\t\tthis->value[0] = col_type(m[0], 0);\n\t\t\tthis->value[1] = col_type(m[1], 0);\n\t\t\tthis->value[2] = col_type(m[2], 0);\n\t\t\tthis->value[3] = col_type(m[3], 1);\n#\t\tendif\n\t}\n\n\t// -- Accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type & mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i)\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR typename mat<4, 4, T, Q>::col_type const& mat<4, 4, T, Q>::operator[](typename mat<4, 4, T, Q>::length_type i) const\n\t{\n\t\tassert(i < this->length());\n\t\treturn this->value[i];\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator=(mat<4, 4, U, Q> const& m)\n\t{\n\t\t//memcpy could be faster\n\t\t//memcpy(&this->value, &m.value, 16 * sizeof(valType));\n\t\tthis->value[0] = m[0];\n\t\tthis->value[1] = m[1];\n\t\tthis->value[2] = m[2];\n\t\tthis->value[3] = m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(U s)\n\t{\n\t\tthis->value[0] += s;\n\t\tthis->value[1] += s;\n\t\tthis->value[2] += s;\n\t\tthis->value[3] += s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q>& mat<4, 4, T, Q>::operator+=(mat<4, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] += m[0];\n\t\tthis->value[1] += m[1];\n\t\tthis->value[2] += m[2];\n\t\tthis->value[3] += m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(U s)\n\t{\n\t\tthis->value[0] -= s;\n\t\tthis->value[1] -= s;\n\t\tthis->value[2] -= s;\n\t\tthis->value[3] -= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator-=(mat<4, 4, U, Q> const& m)\n\t{\n\t\tthis->value[0] -= m[0];\n\t\tthis->value[1] -= m[1];\n\t\tthis->value[2] -= m[2];\n\t\tthis->value[3] -= m[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(U s)\n\t{\n\t\tthis->value[0] *= s;\n\t\tthis->value[1] *= s;\n\t\tthis->value[2] *= s;\n\t\tthis->value[3] *= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator*=(mat<4, 4, U, Q> const& m)\n\t{\n\t\treturn (*this = *this * m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(U s)\n\t{\n\t\tthis->value[0] /= s;\n\t\tthis->value[1] /= s;\n\t\tthis->value[2] /= s;\n\t\tthis->value[3] /= s;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator/=(mat<4, 4, U, Q> const& m)\n\t{\n\t\treturn *this *= inverse(m);\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator++()\n\t{\n\t\t++this->value[0];\n\t\t++this->value[1];\n\t\t++this->value[2];\n\t\t++this->value[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> & mat<4, 4, T, Q>::operator--()\n\t{\n\t\t--this->value[0];\n\t\t--this->value[1];\n\t\t--this->value[2];\n\t\t--this->value[3];\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator++(int)\n\t{\n\t\tmat<4, 4, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat<4, 4, T, Q>::operator--(int)\n\t{\n\t\tmat<4, 4, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary constant operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn m;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\t-m[0],\n\t\t\t-m[1],\n\t\t\t-m[2],\n\t\t\t-m[3]);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0] + s,\n\t\t\tm[1] + s,\n\t\t\tm[2] + s,\n\t\t\tm[3] + s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(T const& s, mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0] + s,\n\t\t\tm[1] + s,\n\t\t\tm[2] + s,\n\t\t\tm[3] + s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator+(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm1[0] + m2[0],\n\t\t\tm1[1] + m2[1],\n\t\t\tm1[2] + m2[2],\n\t\t\tm1[3] + m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0] - s,\n\t\t\tm[1] - s,\n\t\t\tm[2] - s,\n\t\t\tm[3] - s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(T const& s, mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\ts - m[0],\n\t\t\ts - m[1],\n\t\t\ts - m[2],\n\t\t\ts - m[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator-(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm1[0] - m2[0],\n\t\t\tm1[1] - m2[1],\n\t\t\tm1[2] - m2[2],\n\t\t\tm1[3] - m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m, T const  & s)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0] * s,\n\t\t\tm[1] * s,\n\t\t\tm[2] * s,\n\t\t\tm[3] * s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(T const& s, mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0] * s,\n\t\t\tm[1] * s,\n\t\t\tm[2] * s,\n\t\t\tm[3] * s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator*\n\t(\n\t\tmat<4, 4, T, Q> const& m,\n\t\ttypename mat<4, 4, T, Q>::row_type const& v\n\t)\n\t{\n/*\n\t\t__m128 v0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 v1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 v2 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 v3 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 m0 = _mm_mul_ps(m[0].data, v0);\n\t\t__m128 m1 = _mm_mul_ps(m[1].data, v1);\n\t\t__m128 a0 = _mm_add_ps(m0, m1);\n\n\t\t__m128 m2 = _mm_mul_ps(m[2].data, v2);\n\t\t__m128 m3 = _mm_mul_ps(m[3].data, v3);\n\t\t__m128 a1 = _mm_add_ps(m2, m3);\n\n\t\t__m128 a2 = _mm_add_ps(a0, a1);\n\n\t\treturn typename mat<4, 4, T, Q>::col_type(a2);\n*/\n\n\t\ttypename mat<4, 4, T, Q>::col_type const Mov0(v[0]);\n\t\ttypename mat<4, 4, T, Q>::col_type const Mov1(v[1]);\n\t\ttypename mat<4, 4, T, Q>::col_type const Mul0 = m[0] * Mov0;\n\t\ttypename mat<4, 4, T, Q>::col_type const Mul1 = m[1] * Mov1;\n\t\ttypename mat<4, 4, T, Q>::col_type const Add0 = Mul0 + Mul1;\n\t\ttypename mat<4, 4, T, Q>::col_type const Mov2(v[2]);\n\t\ttypename mat<4, 4, T, Q>::col_type const Mov3(v[3]);\n\t\ttypename mat<4, 4, T, Q>::col_type const Mul2 = m[2] * Mov2;\n\t\ttypename mat<4, 4, T, Q>::col_type const Mul3 = m[3] * Mov3;\n\t\ttypename mat<4, 4, T, Q>::col_type const Add1 = Mul2 + Mul3;\n\t\ttypename mat<4, 4, T, Q>::col_type const Add2 = Add0 + Add1;\n\t\treturn Add2;\n\n/*\n\t\treturn typename mat<4, 4, T, Q>::col_type(\n\t\t\tm[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3],\n\t\t\tm[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3],\n\t\t\tm[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3],\n\t\t\tm[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]);\n*/\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator*\n\t(\n\t\ttypename mat<4, 4, T, Q>::col_type const& v,\n\t\tmat<4, 4, T, Q> const& m\n\t)\n\t{\n\t\treturn typename mat<4, 4, T, Q>::row_type(\n\t\t\tm[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3],\n\t\t\tm[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3],\n\t\t\tm[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3],\n\t\t\tm[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<2, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<2, 4, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],\n\t\t\tm1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3],\n\t\t\tm1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<3, 4, T, Q> const& m2)\n\t{\n\t\treturn mat<3, 4, T, Q>(\n\t\t\tm1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],\n\t\t\tm1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],\n\t\t\tm1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],\n\t\t\tm1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3],\n\t\t\tm1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],\n\t\t\tm1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],\n\t\t\tm1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3],\n\t\t\tm1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3],\n\t\t\tm1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],\n\t\t\tm1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3],\n\t\t\tm1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3],\n\t\t\tm1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator*(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcA0 = m1[0];\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcA1 = m1[1];\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcA2 = m1[2];\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcA3 = m1[3];\n\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcB0 = m2[0];\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcB1 = m2[1];\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcB2 = m2[2];\n\t\ttypename mat<4, 4, T, Q>::col_type const SrcB3 = m2[3];\n\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3];\n\t\tResult[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3];\n\t\tResult[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3];\n\t\tResult[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m, T const& s)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0] / s,\n\t\t\tm[1] / s,\n\t\t\tm[2] / s,\n\t\t\tm[3] / s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(T const& s,\tmat<4, 4, T, Q> const& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\ts / m[0],\n\t\t\ts / m[1],\n\t\t\ts / m[2],\n\t\t\ts / m[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator/(mat<4, 4, T, Q> const& m, typename mat<4, 4, T, Q>::row_type const& v)\n\t{\n\t\treturn inverse(m) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::row_type operator/(typename mat<4, 4, T, Q>::col_type const& v, mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn v * inverse(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> operator/(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\tmat<4, 4, T, Q> m1_copy(m1);\n\t\treturn m1_copy /= m2;\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2)\n\t{\n\t\treturn (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"type_mat4x4_simd.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_mat4x4_simd.inl",
    "content": "/// @ref core\n\nnamespace glm\n{\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_quat.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_quat.hpp\n\n#pragma once\n\n// Dependency:\n#include \"../detail/type_mat3x3.hpp\"\n#include \"../detail/type_mat4x4.hpp\"\n#include \"../detail/type_vec3.hpp\"\n#include \"../detail/type_vec4.hpp\"\n#include \"../ext/vector_relational.hpp\"\n#include \"../ext/quaternion_relational.hpp\"\n#include \"../gtc/constants.hpp\"\n#include \"../gtc/matrix_transform.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct qua\n\t{\n\t\t// -- Implementation detail --\n\n\t\ttypedef qua<T, Q> type;\n\t\ttypedef T value_type;\n\n\t\t// -- Data --\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic push\n#\t\t\t\tpragma GCC diagnostic ignored \"-Wpedantic\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic push\n#\t\t\t\tpragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#\t\t\t\tpragma clang diagnostic ignored \"-Wnested-anon-types\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(push)\n#\t\t\t\tpragma warning(disable: 4201)  // nonstandard extension used : nameless struct/union\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_LANG & GLM_LANG_CXXMS_FLAG\n\t\t\tunion\n\t\t\t{\n#\t\t\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t\t\tstruct { T w, x, y, z; };\n#\t\t\t\telse\n\t\t\t\t\tstruct { T x, y, z, w; };\n#\t\t\t\tendif\n\n\t\t\t\ttypename detail::storage<4, T, detail::is_aligned<Q>::value>::type data;\n\t\t\t};\n#\t\telse\n#\t\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t\tT w, x, y, z;\n#\t\t\telse\n\t\t\t\tT x, y, z, w;\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(pop)\n#\t\t\tendif\n#\t\tendif\n\n\t\t// -- Component accesses --\n\n\t\ttypedef length_t length_type;\n\n\t\t/// Return the count of components of a quaternion\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;}\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const;\n\n\t\t// -- Implicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua() GLM_DEFAULT;\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua(qua<T, Q> const& q) GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua(qua<T, P> const& q);\n\n\t\t// -- Explicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua(T s, vec<3, T, Q> const& v);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua(T w, T x, T y, T z);\n\n\t\t// -- Conversion constructors --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(qua<U, P> const& q);\n\n\t\t/// Explicit conversion operators\n#\t\tif GLM_HAS_EXPLICIT_CONVERSION_OPERATORS\n\t\t\tGLM_FUNC_DECL explicit operator mat<3, 3, T, Q>() const;\n\t\t\tGLM_FUNC_DECL explicit operator mat<4, 4, T, Q>() const;\n#\t\tendif\n\n\t\t/// Create a quaternion from two normalized axis\n\t\t///\n\t\t/// @param u A first normalized axis\n\t\t/// @param v A second normalized axis\n\t\t/// @see gtc_quaternion\n\t\t/// @see http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors\n\t\tGLM_FUNC_DECL qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v);\n\n\t\t/// Build a quaternion from euler angles (pitch, yaw, roll), in radians.\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT qua(vec<3, T, Q> const& eulerAngles);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT qua(mat<3, 3, T, Q> const& q);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT qua(mat<4, 4, T, Q> const& q);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator=(qua<T, Q> const& q) GLM_DEFAULT;\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator=(qua<U, Q> const& q);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator+=(qua<U, Q> const& q);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator-=(qua<U, Q> const& q);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator*=(qua<U, Q> const& q);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q>& operator/=(U s);\n\t};\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator+(qua<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator-(qua<T, Q> const& q);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator+(qua<T, Q> const& q, qua<T, Q> const& p);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator-(qua<T, Q> const& q, qua<T, Q> const& p);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator*(qua<T, Q> const& q, qua<T, Q> const& p);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(qua<T, Q> const& q, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator*(qua<T, Q> const& q, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator*(T const& s, qua<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> operator/(qua<T, Q> const& q, T const& s);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator==(qua<T, Q> const& q1, qua<T, Q> const& q2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(qua<T, Q> const& q1, qua<T, Q> const& q2);\n} //namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_quat.inl\"\n#endif//GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_quat.inl",
    "content": "#include \"../trigonometric.hpp\"\n#include \"../exponential.hpp\"\n#include \"../ext/quaternion_geometric.hpp\"\n#include <limits>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate <typename T>\n\tstruct genTypeTrait<qua<T> >\n\t{\n\t\tstatic const genTypeEnum GENTYPE = GENTYPE_QUAT;\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_dot<qua<T, Q>, T, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static T call(qua<T, Q> const& a, qua<T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> tmp(a.w * b.w, a.x * b.x, a.y * b.y, a.z * b.z);\n\t\t\treturn (tmp.x + tmp.y) + (tmp.z + tmp.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_quat_add\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua<T, Q> call(qua<T, Q> const& q, qua<T, Q> const& p)\n\t\t{\n\t\t\treturn qua<T, Q>(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_quat_sub\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua<T, Q> call(qua<T, Q> const& q, qua<T, Q> const& p)\n\t\t{\n\t\t\treturn qua<T, Q>(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_quat_mul_scalar\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua<T, Q> call(qua<T, Q> const& q, T s)\n\t\t{\n\t\t\treturn qua<T, Q>(q.w * s, q.x * s, q.y * s, q.z * s);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_quat_div_scalar\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static qua<T, Q> call(qua<T, Q> const& q, T s)\n\t\t{\n\t\t\treturn qua<T, Q>(q.w / s, q.x / s, q.y / s, q.z / s);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_quat_mul_vec4\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(qua<T, Q> const& q, vec<4, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<4, T, Q>(q * vec<3, T, Q>(v), v.w);\n\t\t}\n\t};\n}//namespace detail\n\n\t// -- Component accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T & qua<T, Q>::operator[](typename qua<T, Q>::length_type i)\n\t{\n\t\tassert(i >= 0 && i < this->length());\n#\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\treturn (&w)[i];\n#\t\telse\n\t\t\treturn (&x)[i];\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& qua<T, Q>::operator[](typename qua<T, Q>::length_type i) const\n\t{\n\t\tassert(i >= 0 && i < this->length());\n#\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\treturn (&w)[i];\n#\t\telse\n\t\t\treturn (&x)[i];\n#\t\tendif\n\t}\n\n\t// -- Implicit basic constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua()\n#\t\t\tif GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE\n#\t\t\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t\t\t: w(1), x(0), y(0), z(0)\n#\t\t\t\telse\n\t\t\t\t\t: x(0), y(0), z(0), w(1)\n#\t\t\t\tendif\n#\t\t\tendif\n\t\t{}\n\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua(qua<T, Q> const& q)\n#\t\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t\t: w(q.w), x(q.x), y(q.y), z(q.z)\n#\t\t\telse\n\t\t\t\t: x(q.x), y(q.y), z(q.z), w(q.w)\n#\t\t\tendif\n\t\t{}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua(qua<T, P> const& q)\n#\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t: w(q.w), x(q.x), y(q.y), z(q.z)\n#\t\telse\n\t\t\t: x(q.x), y(q.y), z(q.z), w(q.w)\n#\t\tendif\n\t{}\n\n\t// -- Explicit basic constructors --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua(T s, vec<3, T, Q> const& v)\n#\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t: w(s), x(v.x), y(v.y), z(v.z)\n#\t\telse\n\t\t\t: x(v.x), y(v.y), z(v.z), w(s)\n#\t\tendif\n\t{}\n\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua(T _w, T _x, T _y, T _z)\n#\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t: w(_w), x(_x), y(_y), z(_z)\n#\t\telse\n\t\t\t: x(_x), y(_y), z(_z), w(_w)\n#\t\tendif\n\t{}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua(qua<U, P> const& q)\n#\t\tifdef GLM_FORCE_QUAT_DATA_WXYZ\n\t\t\t: w(static_cast<T>(q.w)), x(static_cast<T>(q.x)), y(static_cast<T>(q.y)), z(static_cast<T>(q.z))\n#\t\telse\n\t\t\t: x(static_cast<T>(q.x)), y(static_cast<T>(q.y)), z(static_cast<T>(q.z)), w(static_cast<T>(q.w))\n#\t\tendif\n\t{}\n\n\t//template<typename valType>\n\t//GLM_FUNC_QUALIFIER qua<valType>::qua\n\t//(\n\t//\tvalType const& pitch,\n\t//\tvalType const& yaw,\n\t//\tvalType const& roll\n\t//)\n\t//{\n\t//\tvec<3, valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5));\n\t//\tvec<3, valType> c = glm::cos(eulerAngle * valType(0.5));\n\t//\tvec<3, valType> s = glm::sin(eulerAngle * valType(0.5));\n\t//\n\t//\tthis->w = c.x * c.y * c.z + s.x * s.y * s.z;\n\t//\tthis->x = s.x * c.y * c.z - c.x * s.y * s.z;\n\t//\tthis->y = c.x * s.y * c.z + s.x * c.y * s.z;\n\t//\tthis->z = c.x * c.y * s.z - s.x * s.y * c.z;\n\t//}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q>::qua(vec<3, T, Q> const& u, vec<3, T, Q> const& v)\n\t{\n\t\tT norm_u_norm_v = sqrt(dot(u, u) * dot(v, v));\n\t\tT real_part = norm_u_norm_v + dot(u, v);\n\t\tvec<3, T, Q> t;\n\n\t\tif(real_part < static_cast<T>(1.e-6f) * norm_u_norm_v)\n\t\t{\n\t\t\t// If u and v are exactly opposite, rotate 180 degrees\n\t\t\t// around an arbitrary orthogonal axis. Axis normalisation\n\t\t\t// can happen later, when we normalise the quaternion.\n\t\t\treal_part = static_cast<T>(0);\n\t\t\tt = abs(u.x) > abs(u.z) ? vec<3, T, Q>(-u.y, u.x, static_cast<T>(0)) : vec<3, T, Q>(static_cast<T>(0), -u.z, u.y);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Otherwise, build quaternion the standard way.\n\t\t\tt = cross(u, v);\n\t\t}\n\n\t\t*this = normalize(qua<T, Q>(real_part, t.x, t.y, t.z));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q>::qua(vec<3, T, Q> const& eulerAngle)\n\t{\n\t\tvec<3, T, Q> c = glm::cos(eulerAngle * T(0.5));\n\t\tvec<3, T, Q> s = glm::sin(eulerAngle * T(0.5));\n\n\t\tthis->w = c.x * c.y * c.z + s.x * s.y * s.z;\n\t\tthis->x = s.x * c.y * c.z - c.x * s.y * s.z;\n\t\tthis->y = c.x * s.y * c.z + s.x * c.y * s.z;\n\t\tthis->z = c.x * c.y * s.z - s.x * s.y * c.z;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q>::qua(mat<3, 3, T, Q> const& m)\n\t{\n\t\t*this = quat_cast(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q>::qua(mat<4, 4, T, Q> const& m)\n\t{\n\t\t*this = quat_cast(m);\n\t}\n\n#\tif GLM_HAS_EXPLICIT_CONVERSION_OPERATORS\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q>::operator mat<3, 3, T, Q>() const\n\t{\n\t\treturn mat3_cast(*this);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q>::operator mat<4, 4, T, Q>() const\n\t{\n\t\treturn mat4_cast(*this);\n\t}\n#\tendif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS\n\n\t// -- Unary arithmetic operators --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator=(qua<T, Q> const& q)\n\t\t{\n\t\t\tthis->w = q.w;\n\t\t\tthis->x = q.x;\n\t\t\tthis->y = q.y;\n\t\t\tthis->z = q.z;\n\t\t\treturn *this;\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator=(qua<U, Q> const& q)\n\t{\n\t\tthis->w = static_cast<T>(q.w);\n\t\tthis->x = static_cast<T>(q.x);\n\t\tthis->y = static_cast<T>(q.y);\n\t\tthis->z = static_cast<T>(q.z);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator+=(qua<U, Q> const& q)\n\t{\n\t\treturn (*this = detail::compute_quat_add<T, Q, detail::is_aligned<Q>::value>::call(*this, qua<T, Q>(q)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator-=(qua<U, Q> const& q)\n\t{\n\t\treturn (*this = detail::compute_quat_sub<T, Q, detail::is_aligned<Q>::value>::call(*this, qua<T, Q>(q)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator*=(qua<U, Q> const& r)\n\t{\n\t\tqua<T, Q> const p(*this);\n\t\tqua<T, Q> const q(r);\n\n\t\tthis->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z;\n\t\tthis->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y;\n\t\tthis->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z;\n\t\tthis->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator*=(U s)\n\t{\n\t\treturn (*this = detail::compute_quat_mul_scalar<T, Q, detail::is_aligned<Q>::value>::call(*this, static_cast<U>(s)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> & qua<T, Q>::operator/=(U s)\n\t{\n\t\treturn (*this = detail::compute_quat_div_scalar<T, Q, detail::is_aligned<Q>::value>::call(*this, static_cast<U>(s)));\n\t}\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator+(qua<T, Q> const& q)\n\t{\n\t\treturn q;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator-(qua<T, Q> const& q)\n\t{\n\t\treturn qua<T, Q>(-q.w, -q.x, -q.y, -q.z);\n\t}\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator+(qua<T, Q> const& q, qua<T, Q> const& p)\n\t{\n\t\treturn qua<T, Q>(q) += p;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator-(qua<T, Q> const& q, qua<T, Q> const& p)\n\t{\n\t\treturn qua<T, Q>(q) -= p;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator*(qua<T, Q> const& q, qua<T, Q> const& p)\n\t{\n\t\treturn qua<T, Q>(q) *= p;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(qua<T, Q> const& q, vec<3, T, Q> const& v)\n\t{\n\t\tvec<3, T, Q> const QuatVector(q.x, q.y, q.z);\n\t\tvec<3, T, Q> const uv(glm::cross(QuatVector, v));\n\t\tvec<3, T, Q> const uuv(glm::cross(QuatVector, uv));\n\n\t\treturn v + ((uv * q.w) + uuv) * static_cast<T>(2);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, qua<T, Q> const& q)\n\t{\n\t\treturn glm::inverse(q) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(qua<T, Q> const& q, vec<4, T, Q> const& v)\n\t{\n\t\treturn detail::compute_quat_mul_vec4<T, Q, detail::is_aligned<Q>::value>::call(q, v);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, qua<T, Q> const& q)\n\t{\n\t\treturn glm::inverse(q) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator*(qua<T, Q> const& q, T const& s)\n\t{\n\t\treturn qua<T, Q>(\n\t\t\tq.w * s, q.x * s, q.y * s, q.z * s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator*(T const& s, qua<T, Q> const& q)\n\t{\n\t\treturn q * s;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> operator/(qua<T, Q> const& q, T const& s)\n\t{\n\t\treturn qua<T, Q>(\n\t\t\tq.w / s, q.x / s, q.y / s, q.z / s);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(qua<T, Q> const& q1, qua<T, Q> const& q2)\n\t{\n\t\treturn q1.x == q2.x && q1.y == q2.y && q1.z == q2.z && q1.w == q2.w;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(qua<T, Q> const& q1, qua<T, Q> const& q2)\n\t{\n\t\treturn q1.x != q2.x || q1.y != q2.y || q1.z != q2.z || q1.w != q2.w;\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"type_quat_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/detail/type_quat_simd.inl",
    "content": "/// @ref core\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nnamespace glm{\nnamespace detail\n{\n/*\n\ttemplate<qualifier Q>\n\tstruct compute_quat_mul<float, Q, true>\n\t{\n\t\tstatic qua<float, Q> call(qua<float, Q> const& q1, qua<float, Q> const& q2)\n\t\t{\n\t\t\t// SSE2 STATS: 11 shuffle, 8 mul, 8 add\n\t\t\t// SSE4 STATS: 3 shuffle, 4 mul, 4 dpps\n\n\t\t\t__m128 const mul0 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(0, 1, 2, 3)));\n\t\t\t__m128 const mul1 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(1, 0, 3, 2)));\n\t\t\t__m128 const mul2 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(2, 3, 0, 1)));\n\t\t\t__m128 const mul3 = _mm_mul_ps(q1.Data, q2.Data);\n\n#\t\t\tif GLM_ARCH & GLM_ARCH_SSE41_BIT\n\t\t\t\t__m128 const add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f,  1.0f,  1.0f), 0xff);\n\t\t\t\t__m128 const add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f,  1.0f,  1.0f, -1.0f), 0xff);\n\t\t\t\t__m128 const add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f,  1.0f, -1.0f,  1.0f), 0xff);\n\t\t\t\t__m128 const add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff);\n#\t\t\telse\n\t\t\t\t__m128 const mul4 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f,  1.0f,  1.0f));\n\t\t\t\t__m128 const add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul4, mul4));\n\t\t\t\t__m128 const add4 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1));\n\n\t\t\t\t__m128 const mul5 = _mm_mul_ps(mul1, _mm_set_ps(1.0f,  1.0f,  1.0f, -1.0f));\n\t\t\t\t__m128 const add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul5, mul5));\n\t\t\t\t__m128 const add5 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1));\n\n\t\t\t\t__m128 const mul6 = _mm_mul_ps(mul2, _mm_set_ps(1.0f,  1.0f, -1.0f,  1.0f));\n\t\t\t\t__m128 const add2 = _mm_add_ps(mul6, _mm_movehl_ps(mul6, mul6));\n\t\t\t\t__m128 const add6 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1));\n\n\t\t\t\t__m128 const mul7 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f));\n\t\t\t\t__m128 const add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul7, mul7));\n\t\t\t\t__m128 const add7 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1));\n\t\t#endif\n\n\t\t\t// This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than\n\t\t\t// the final code below. I'll keep this here for reference - maybe somebody else can do something better...\n\t\t\t//\n\t\t\t//__m128 xxyy = _mm_shuffle_ps(add4, add5, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t\t//__m128 zzww = _mm_shuffle_ps(add6, add7, _MM_SHUFFLE(0, 0, 0, 0));\n\t\t\t//\n\t\t\t//return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0));\n\n\t\t\tqua<float, Q> Result;\n\t\t\t_mm_store_ss(&Result.x, add4);\n\t\t\t_mm_store_ss(&Result.y, add5);\n\t\t\t_mm_store_ss(&Result.z, add6);\n\t\t\t_mm_store_ss(&Result.w, add7);\n\t\t\treturn Result;\n\t\t}\n\t};\n*/\n\n\ttemplate<qualifier Q>\n\tstruct compute_quat_add<float, Q, true>\n\t{\n\t\tstatic qua<float, Q> call(qua<float, Q> const& q, qua<float, Q> const& p)\n\t\t{\n\t\t\tqua<float, Q> Result;\n\t\t\tResult.data = _mm_add_ps(q.data, p.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_quat_add<double, Q, true>\n\t{\n\t\tstatic qua<double, Q> call(qua<double, Q> const& a, qua<double, Q> const& b)\n\t\t{\n\t\t\tqua<double, Q> Result;\n\t\t\tResult.data = _mm256_add_pd(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_quat_sub<float, Q, true>\n\t{\n\t\tstatic qua<float, Q> call(qua<float, Q> const& q, qua<float, Q> const& p)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_sub_ps(q.data, p.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_quat_sub<double, Q, true>\n\t{\n\t\tstatic qua<double, Q> call(qua<double, Q> const& a, qua<double, Q> const& b)\n\t\t{\n\t\t\tqua<double, Q> Result;\n\t\t\tResult.data = _mm256_sub_pd(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_quat_mul_scalar<float, Q, true>\n\t{\n\t\tstatic qua<float, Q> call(qua<float, Q> const& q, float s)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_mul_ps(q.data, _mm_set_ps1(s));\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_quat_mul_scalar<double, Q, true>\n\t{\n\t\tstatic qua<double, Q> call(qua<double, Q> const& q, double s)\n\t\t{\n\t\t\tqua<double, Q> Result;\n\t\t\tResult.data = _mm256_mul_pd(q.data, _mm_set_ps1(s));\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_quat_div_scalar<float, Q, true>\n\t{\n\t\tstatic qua<float, Q> call(qua<float, Q> const& q, float s)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_div_ps(q.data, _mm_set_ps1(s));\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_quat_div_scalar<double, Q, true>\n\t{\n\t\tstatic qua<double, Q> call(qua<double, Q> const& q, double s)\n\t\t{\n\t\t\tqua<double, Q> Result;\n\t\t\tResult.data = _mm256_div_pd(q.data, _mm_set_ps1(s));\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_quat_mul_vec4<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(qua<float, Q> const& q, vec<4, float, Q> const& v)\n\t\t{\n\t\t\t__m128 const q_wwww = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 3, 3, 3));\n\t\t\t__m128 const q_swp0 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 0, 2, 1));\n\t\t\t__m128 const q_swp1 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 1, 0, 2));\n\t\t\t__m128 const v_swp0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 0, 2, 1));\n\t\t\t__m128 const v_swp1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 1, 0, 2));\n\n\t\t\t__m128 uv      = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0));\n\t\t\t__m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1));\n\t\t\t__m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2));\n\t\t\t__m128 uuv     = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0));\n\n\t\t\t__m128 const two = _mm_set1_ps(2.0f);\n\t\t\tuv  = _mm_mul_ps(uv, _mm_mul_ps(q_wwww, two));\n\t\t\tuuv = _mm_mul_ps(uuv, two);\n\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_add_ps(v.Data, _mm_add_ps(uv, uuv));\n\t\t\treturn Result;\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec1.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_vec1.hpp\n\n#pragma once\n\n#include \"qualifier.hpp\"\n#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n#\tinclude \"_swizzle.hpp\"\n#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n#\tinclude \"_swizzle_func.hpp\"\n#endif\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct vec<1, T, Q>\n\t{\n\t\t// -- Implementation detail --\n\n\t\ttypedef T value_type;\n\t\ttypedef vec<1, T, Q> type;\n\t\ttypedef vec<1, bool, Q> bool_type;\n\n\t\t// -- Data --\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic push\n#\t\t\t\tpragma GCC diagnostic ignored \"-Wpedantic\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic push\n#\t\t\t\tpragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#\t\t\t\tpragma clang diagnostic ignored \"-Wnested-anon-types\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(push)\n#\t\t\t\tpragma warning(disable: 4201)  // nonstandard extension used : nameless struct/union\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_CONFIG_XYZW_ONLY\n\t\t\tT x;\n#\t\telif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE\n\t\t\tunion\n\t\t\t{\n\t\t\t\tT x;\n\t\t\t\tT r;\n\t\t\t\tT s;\n\n\t\t\t\ttypename detail::storage<1, T, detail::is_aligned<Q>::value>::type data;\n/*\n#\t\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\t\t\t_GLM_SWIZZLE1_2_MEMBERS(T, Q, x)\n\t\t\t\t\t_GLM_SWIZZLE1_2_MEMBERS(T, Q, r)\n\t\t\t\t\t_GLM_SWIZZLE1_2_MEMBERS(T, Q, s)\n\t\t\t\t\t_GLM_SWIZZLE1_3_MEMBERS(T, Q, x)\n\t\t\t\t\t_GLM_SWIZZLE1_3_MEMBERS(T, Q, r)\n\t\t\t\t\t_GLM_SWIZZLE1_3_MEMBERS(T, Q, s)\n\t\t\t\t\t_GLM_SWIZZLE1_4_MEMBERS(T, Q, x)\n\t\t\t\t\t_GLM_SWIZZLE1_4_MEMBERS(T, Q, r)\n\t\t\t\t\t_GLM_SWIZZLE1_4_MEMBERS(T, Q, s)\n#\t\t\t\tendif\n*/\n\t\t\t};\n#\t\telse\n\t\t\tunion {T x, r, s;};\n/*\n#\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n\t\t\t\tGLM_SWIZZLE_GEN_VEC_FROM_VEC1(T, Q)\n#\t\t\tendif\n*/\n#\t\tendif\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(pop)\n#\t\t\tendif\n#\t\tendif\n\n\t\t// -- Component accesses --\n\n\t\t/// Return the count of components of the vector\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 1;}\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const;\n\n\t\t// -- Implicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT;\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, T, P> const& v);\n\n\t\t// -- Explicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar);\n\n\t\t// -- Conversion vector constructors --\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<1, U, P> const& v);\n\n\t\t// -- Swizzle constructors --\n/*\n#\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\ttemplate<int E0>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<1, T, Q, E0, -1,-2,-3> const& that)\n\t\t\t{\n\t\t\t\t*this = that();\n\t\t\t}\n#\t\tendif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n*/\n\t\t// -- Unary arithmetic operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec const& v) GLM_DEFAULT;\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator+=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator-=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator*=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator/=(vec<1, U, Q> const& v);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator++();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator--();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator--(int);\n\n\t\t// -- Unary bit operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator%=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator&=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator|=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator^=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator<<=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> & operator>>=(vec<1, U, Q> const& v);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_vec1.inl\"\n#endif//GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec1.inl",
    "content": "/// @ref core\n\n#include \"./compute_vector_relational.hpp\"\n\nnamespace glm\n{\n\t// -- Implicit basic constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec()\n#\t\t\tif GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE\n\t\t\t\t: x(0)\n#\t\t\tendif\n\t\t{}\n\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, Q> const& v)\n\t\t\t: x(v.x)\n\t\t{}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, T, P> const& v)\n\t\t: x(v.x)\n\t{}\n\n\t// -- Explicit basic constructors --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(T scalar)\n\t\t: x(scalar)\n\t{}\n\n\t// -- Conversion vector constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<1, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<2, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<3, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q>::vec(vec<4, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t{}\n\n\t// -- Component accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type)\n\t{\n\t\treturn x;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<1, T, Q>::operator[](typename vec<1, T, Q>::length_type) const\n\t{\n\t\treturn x;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, T, Q> const& v)\n\t\t{\n\t\t\tthis->x = v.x;\n\t\t\treturn *this;\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x = static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(U scalar)\n\t{\n\t\tthis->x += static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator+=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x += static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(U scalar)\n\t{\n\t\tthis->x -= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator-=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x -= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(U scalar)\n\t{\n\t\tthis->x *= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator*=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x *= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(U scalar)\n\t{\n\t\tthis->x /= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator/=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x /= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator++()\n\t{\n\t\t++this->x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator--()\n\t{\n\t\t--this->x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator++(int)\n\t{\n\t\tvec<1, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> vec<1, T, Q>::operator--(int)\n\t{\n\t\tvec<1, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(U scalar)\n\t{\n\t\tthis->x %= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator%=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x %= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(U scalar)\n\t{\n\t\tthis->x &= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator&=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x &= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(U scalar)\n\t{\n\t\tthis->x |= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator|=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x |= U(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(U scalar)\n\t{\n\t\tthis->x ^= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator^=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x ^= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(U scalar)\n\t{\n\t\tthis->x <<= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator<<=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x <<= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(U scalar)\n\t{\n\t\tthis->x >>= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> & vec<1, T, Q>::operator>>=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x >>= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\t// -- Unary constant operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\t-v.x);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar + v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator+(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x + v2.x);\n\t}\n\n\t//operator-\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar - v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator-(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x - v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar * v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator*(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x * v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar / v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator/(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x / v2.x);\n\t}\n\n\t// -- Binary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x % scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar % v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator%(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x % v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x & scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar & v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator&(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x & v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x | scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar | v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator|(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x | v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv.x ^ scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tscalar ^ v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator^(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tv1.x ^ v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tstatic_cast<T>(v.x << scalar));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tstatic_cast<T>(scalar << v.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator<<(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tstatic_cast<T>(v1.x << v2.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tstatic_cast<T>(v.x >> scalar));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(T scalar, vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tstatic_cast<T>(scalar >> v.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator>>(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\tstatic_cast<T>(v1.x >> v2.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, T, Q> operator~(vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(\n\t\t\t~v.x);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn detail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.x, v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<1, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn !(v1 == v2);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator&&(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2)\n\t{\n\t\treturn vec<1, bool, Q>(v1.x && v2.x);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<1, bool, Q> operator||(vec<1, bool, Q> const& v1, vec<1, bool, Q> const& v2)\n\t{\n\t\treturn vec<1, bool, Q>(v1.x || v2.x);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec2.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_vec2.hpp\n\n#pragma once\n\n#include \"qualifier.hpp\"\n#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n#\tinclude \"_swizzle.hpp\"\n#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n#\tinclude \"_swizzle_func.hpp\"\n#endif\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct vec<2, T, Q>\n\t{\n\t\t// -- Implementation detail --\n\n\t\ttypedef T value_type;\n\t\ttypedef vec<2, T, Q> type;\n\t\ttypedef vec<2, bool, Q> bool_type;\n\n\t\t// -- Data --\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic push\n#\t\t\t\tpragma GCC diagnostic ignored \"-Wpedantic\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic push\n#\t\t\t\tpragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#\t\t\t\tpragma clang diagnostic ignored \"-Wnested-anon-types\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(push)\n#\t\t\t\tpragma warning(disable: 4201)  // nonstandard extension used : nameless struct/union\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_CONFIG_XYZW_ONLY\n\t\t\tT x, y;\n#\t\telif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE\n\t\t\tunion\n\t\t\t{\n\t\t\t\tstruct{ T x, y; };\n\t\t\t\tstruct{ T r, g; };\n\t\t\t\tstruct{ T s, t; };\n\n\t\t\t\ttypename detail::storage<2, T, detail::is_aligned<Q>::value>::type data;\n\n#\t\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\t\t\tGLM_SWIZZLE2_2_MEMBERS(T, Q, x, y)\n\t\t\t\t\tGLM_SWIZZLE2_2_MEMBERS(T, Q, r, g)\n\t\t\t\t\tGLM_SWIZZLE2_2_MEMBERS(T, Q, s, t)\n\t\t\t\t\tGLM_SWIZZLE2_3_MEMBERS(T, Q, x, y)\n\t\t\t\t\tGLM_SWIZZLE2_3_MEMBERS(T, Q, r, g)\n\t\t\t\t\tGLM_SWIZZLE2_3_MEMBERS(T, Q, s, t)\n\t\t\t\t\tGLM_SWIZZLE2_4_MEMBERS(T, Q, x, y)\n\t\t\t\t\tGLM_SWIZZLE2_4_MEMBERS(T, Q, r, g)\n\t\t\t\t\tGLM_SWIZZLE2_4_MEMBERS(T, Q, s, t)\n#\t\t\t\tendif\n\t\t\t};\n#\t\telse\n\t\t\tunion {T x, r, s;};\n\t\t\tunion {T y, g, t;};\n\n#\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n\t\t\t\tGLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, Q)\n#\t\t\tendif//GLM_CONFIG_SWIZZLE\n#\t\tendif\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(pop)\n#\t\t\tendif\n#\t\tendif\n\n\t\t// -- Component accesses --\n\n\t\t/// Return the count of components of the vector\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;}\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T& operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const;\n\n\t\t// -- Implicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT;\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, T, P> const& v);\n\n\t\t// -- Explicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y);\n\n\t\t// -- Conversion constructors --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A x, B y);\n\t\ttemplate<typename A, typename B>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, B y);\n\t\ttemplate<typename A, typename B>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A x, vec<1, B, Q> const& y);\n\t\ttemplate<typename A, typename B>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, Q> const& x, vec<1, B, Q> const& y);\n\n\t\t// -- Conversion vector constructors --\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<2, U, P> const& v);\n\n\t\t// -- Swizzle constructors --\n#\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\ttemplate<int E0, int E1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1,-1,-2> const& that)\n\t\t\t{\n\t\t\t\t*this = that();\n\t\t\t}\n#\t\tendif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\n\t\t// -- Unary arithmetic operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec const& v) GLM_DEFAULT;\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator+=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator-=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator*=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator/=(vec<2, U, Q> const& v);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator++();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator--();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator--(int);\n\n\t\t// -- Unary bit operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator%=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator&=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator|=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator^=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator<<=(vec<2, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> & operator>>=(vec<2, U, Q> const& v);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_vec2.inl\"\n#endif//GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec2.inl",
    "content": "/// @ref core\n\n#include \"./compute_vector_relational.hpp\"\n\nnamespace glm\n{\n\t// -- Implicit basic constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec()\n#\t\t\tif GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE\n\t\t\t\t: x(0), y(0)\n#\t\t\tendif\n\t\t{}\n\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, Q> const& v)\n\t\t\t: x(v.x), y(v.y)\n\t\t{}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, T, P> const& v)\n\t\t: x(v.x), y(v.y)\n\t{}\n\n\t// -- Explicit basic constructors --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T scalar)\n\t\t: x(scalar), y(scalar)\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(T _x, T _y)\n\t\t: x(_x), y(_y)\n\t{}\n\n\t// -- Conversion scalar constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, B _y)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, B _y)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(A _x, vec<1, B, Q> const& _y)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<1, A, Q> const& _x, vec<1, B, Q> const& _y)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t{}\n\n\t// -- Conversion vector constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<2, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<3, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q>::vec(vec<4, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.y))\n\t{}\n\n\t// -- Component accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i)\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\tswitch(i)\n\t\t{\n\t\tdefault:\n\t\tcase 0:\n\t\t\treturn x;\n\t\tcase 1:\n\t\t\treturn y;\n\t\t}\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<2, T, Q>::operator[](typename vec<2, T, Q>::length_type i) const\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\tswitch(i)\n\t\t{\n\t\tdefault:\n\t\tcase 0:\n\t\t\treturn x;\n\t\tcase 1:\n\t\t\treturn y;\n\t\t}\n\t}\n\n\t// -- Unary arithmetic operators --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, T, Q> const& v)\n\t\t{\n\t\t\tthis->x = v.x;\n\t\t\tthis->y = v.y;\n\t\t\treturn *this;\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x = static_cast<T>(v.x);\n\t\tthis->y = static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(U scalar)\n\t{\n\t\tthis->x += static_cast<T>(scalar);\n\t\tthis->y += static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x += static_cast<T>(v.x);\n\t\tthis->y += static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator+=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x += static_cast<T>(v.x);\n\t\tthis->y += static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(U scalar)\n\t{\n\t\tthis->x -= static_cast<T>(scalar);\n\t\tthis->y -= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x -= static_cast<T>(v.x);\n\t\tthis->y -= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator-=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x -= static_cast<T>(v.x);\n\t\tthis->y -= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(U scalar)\n\t{\n\t\tthis->x *= static_cast<T>(scalar);\n\t\tthis->y *= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x *= static_cast<T>(v.x);\n\t\tthis->y *= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator*=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x *= static_cast<T>(v.x);\n\t\tthis->y *= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(U scalar)\n\t{\n\t\tthis->x /= static_cast<T>(scalar);\n\t\tthis->y /= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x /= static_cast<T>(v.x);\n\t\tthis->y /= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator/=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x /= static_cast<T>(v.x);\n\t\tthis->y /= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator++()\n\t{\n\t\t++this->x;\n\t\t++this->y;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator--()\n\t{\n\t\t--this->x;\n\t\t--this->y;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator++(int)\n\t{\n\t\tvec<2, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> vec<2, T, Q>::operator--(int)\n\t{\n\t\tvec<2, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(U scalar)\n\t{\n\t\tthis->x %= static_cast<T>(scalar);\n\t\tthis->y %= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x %= static_cast<T>(v.x);\n\t\tthis->y %= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator%=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x %= static_cast<T>(v.x);\n\t\tthis->y %= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(U scalar)\n\t{\n\t\tthis->x &= static_cast<T>(scalar);\n\t\tthis->y &= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x &= static_cast<T>(v.x);\n\t\tthis->y &= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator&=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x &= static_cast<T>(v.x);\n\t\tthis->y &= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(U scalar)\n\t{\n\t\tthis->x |= static_cast<T>(scalar);\n\t\tthis->y |= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x |= static_cast<T>(v.x);\n\t\tthis->y |= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator|=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x |= static_cast<T>(v.x);\n\t\tthis->y |= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(U scalar)\n\t{\n\t\tthis->x ^= static_cast<T>(scalar);\n\t\tthis->y ^= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x ^= static_cast<T>(v.x);\n\t\tthis->y ^= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator^=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x ^= static_cast<T>(v.x);\n\t\tthis->y ^= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(U scalar)\n\t{\n\t\tthis->x <<= static_cast<T>(scalar);\n\t\tthis->y <<= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x <<= static_cast<T>(v.x);\n\t\tthis->y <<= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator<<=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x <<= static_cast<T>(v.x);\n\t\tthis->y <<= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(U scalar)\n\t{\n\t\tthis->x >>= static_cast<T>(scalar);\n\t\tthis->y >>= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x >>= static_cast<T>(v.x);\n\t\tthis->y >>= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> & vec<2, T, Q>::operator>>=(vec<2, U, Q> const& v)\n\t{\n\t\tthis->x >>= static_cast<T>(v.x);\n\t\tthis->y >>= static_cast<T>(v.y);\n\t\treturn *this;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\t-v.x,\n\t\t\t-v.y);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x + scalar,\n\t\t\tv.y + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x + v2.x,\n\t\t\tv1.y + v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar + v.x,\n\t\t\tscalar + v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x + v2.x,\n\t\t\tv1.x + v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator+(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x + v2.x,\n\t\t\tv1.y + v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x - scalar,\n\t\t\tv.y - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x - v2.x,\n\t\t\tv1.y - v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar - v.x,\n\t\t\tscalar - v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x - v2.x,\n\t\t\tv1.x - v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator-(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x - v2.x,\n\t\t\tv1.y - v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x * scalar,\n\t\t\tv.y * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x * v2.x,\n\t\t\tv1.y * v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar * v.x,\n\t\t\tscalar * v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x * v2.x,\n\t\t\tv1.x * v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator*(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x * v2.x,\n\t\t\tv1.y * v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x / scalar,\n\t\t\tv.y / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x / v2.x,\n\t\t\tv1.y / v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar / v.x,\n\t\t\tscalar / v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x / v2.x,\n\t\t\tv1.x / v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator/(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x / v2.x,\n\t\t\tv1.y / v2.y);\n\t}\n\n\t// -- Binary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x % scalar,\n\t\t\tv.y % scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x % v2.x,\n\t\t\tv1.y % v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar % v.x,\n\t\t\tscalar % v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x % v2.x,\n\t\t\tv1.x % v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator%(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x % v2.x,\n\t\t\tv1.y % v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x & scalar,\n\t\t\tv.y & scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x & v2.x,\n\t\t\tv1.y & v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar & v.x,\n\t\t\tscalar & v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x & v2.x,\n\t\t\tv1.x & v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator&(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x & v2.x,\n\t\t\tv1.y & v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x | scalar,\n\t\t\tv.y | scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x | v2.x,\n\t\t\tv1.y | v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar | v.x,\n\t\t\tscalar | v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x | v2.x,\n\t\t\tv1.x | v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator|(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x | v2.x,\n\t\t\tv1.y | v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x ^ scalar,\n\t\t\tv.y ^ scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x ^ v2.x,\n\t\t\tv1.y ^ v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar ^ v.x,\n\t\t\tscalar ^ v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x ^ v2.x,\n\t\t\tv1.x ^ v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator^(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x ^ v2.x,\n\t\t\tv1.y ^ v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x << scalar,\n\t\t\tv.y << scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x << v2.x,\n\t\t\tv1.y << v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar << v.x,\n\t\t\tscalar << v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x << v2.x,\n\t\t\tv1.x << v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator<<(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x << v2.x,\n\t\t\tv1.y << v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv.x >> scalar,\n\t\t\tv.y >> scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x >> v2.x,\n\t\t\tv1.y >> v2.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(T scalar, vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tscalar >> v.x,\n\t\t\tscalar >> v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<1, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x >> v2.x,\n\t\t\tv1.x >> v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator>>(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tv1.x >> v2.x,\n\t\t\tv1.y >> v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, T, Q> operator~(vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\t~v.x,\n\t\t\t~v.y);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn\n\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.x, v2.x) &&\n\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.y, v2.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<2, T, Q> const& v1, vec<2, T, Q> const& v2)\n\t{\n\t\treturn !(v1 == v2);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator&&(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2)\n\t{\n\t\treturn vec<2, bool, Q>(v1.x && v2.x, v1.y && v2.y);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<2, bool, Q> operator||(vec<2, bool, Q> const& v1, vec<2, bool, Q> const& v2)\n\t{\n\t\treturn vec<2, bool, Q>(v1.x || v2.x, v1.y || v2.y);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec3.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_vec3.hpp\n\n#pragma once\n\n#include \"qualifier.hpp\"\n#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n#\tinclude \"_swizzle.hpp\"\n#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n#\tinclude \"_swizzle_func.hpp\"\n#endif\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct vec<3, T, Q>\n\t{\n\t\t// -- Implementation detail --\n\n\t\ttypedef T value_type;\n\t\ttypedef vec<3, T, Q> type;\n\t\ttypedef vec<3, bool, Q> bool_type;\n\n\t\t// -- Data --\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic push\n#\t\t\t\tpragma GCC diagnostic ignored \"-Wpedantic\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic push\n#\t\t\t\tpragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#\t\t\t\tpragma clang diagnostic ignored \"-Wnested-anon-types\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(push)\n#\t\t\t\tpragma warning(disable: 4201)  // nonstandard extension used : nameless struct/union\n#\t\t\t\tif GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n#\t\t\t\t\tpragma warning(disable: 4324)  // structure was padded due to alignment specifier\n#\t\t\t\tendif\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_CONFIG_XYZW_ONLY\n\t\t\tT x, y, z;\n#\t\telif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE\n\t\t\tunion\n\t\t\t{\n\t\t\t\tstruct{ T x, y, z; };\n\t\t\t\tstruct{ T r, g, b; };\n\t\t\t\tstruct{ T s, t, p; };\n\n\t\t\t\ttypename detail::storage<3, T, detail::is_aligned<Q>::value>::type data;\n\n#\t\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\t\t\tGLM_SWIZZLE3_2_MEMBERS(T, Q, x, y, z)\n\t\t\t\t\tGLM_SWIZZLE3_2_MEMBERS(T, Q, r, g, b)\n\t\t\t\t\tGLM_SWIZZLE3_2_MEMBERS(T, Q, s, t, p)\n\t\t\t\t\tGLM_SWIZZLE3_3_MEMBERS(T, Q, x, y, z)\n\t\t\t\t\tGLM_SWIZZLE3_3_MEMBERS(T, Q, r, g, b)\n\t\t\t\t\tGLM_SWIZZLE3_3_MEMBERS(T, Q, s, t, p)\n\t\t\t\t\tGLM_SWIZZLE3_4_MEMBERS(T, Q, x, y, z)\n\t\t\t\t\tGLM_SWIZZLE3_4_MEMBERS(T, Q, r, g, b)\n\t\t\t\t\tGLM_SWIZZLE3_4_MEMBERS(T, Q, s, t, p)\n#\t\t\t\tendif\n\t\t\t};\n#\t\telse\n\t\t\tunion { T x, r, s; };\n\t\t\tunion { T y, g, t; };\n\t\t\tunion { T z, b, p; };\n\n#\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n\t\t\t\tGLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, Q)\n#\t\t\tendif//GLM_CONFIG_SWIZZLE\n#\t\tendif//GLM_LANG\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(pop)\n#\t\t\tendif\n#\t\tendif\n\n\t\t// -- Component accesses --\n\n\t\t/// Return the count of components of the vector\n\t\ttypedef length_t length_type;\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 3;}\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const;\n\n\t\t// -- Implicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT;\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec const& v) GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, T, P> const& v);\n\n\t\t// -- Explicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T a, T b, T c);\n\n\t\t// -- Conversion scalar constructors --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X x, Y y, Z z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z);\n\t\ttemplate<typename X, typename Y, typename Z>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z);\n\n\t\t// -- Conversion vector constructors --\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<3, U, P> const& v);\n\n\t\t// -- Swizzle constructors --\n#\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\ttemplate<int E0, int E1, int E2>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& that)\n\t\t\t{\n\t\t\t\t*this = that();\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& scalar)\n\t\t\t{\n\t\t\t\t*this = vec(v(), scalar);\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T const& scalar, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v)\n\t\t\t{\n\t\t\t\t*this = vec(scalar, v());\n\t\t\t}\n#\t\tendif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\n\t\t// -- Unary arithmetic operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q>& operator=(vec<3, T, Q> const& v) GLM_DEFAULT;\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator+=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator-=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator*=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator/=(vec<3, U, Q> const& v);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator++();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator--();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator--(int);\n\n\t\t// -- Unary bit operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator%=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator&=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator|=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator^=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator<<=(vec<3, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> & operator>>=(vec<3, U, Q> const& v);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_vec3.inl\"\n#endif//GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec3.inl",
    "content": "/// @ref core\n\n#include \"compute_vector_relational.hpp\"\n\nnamespace glm\n{\n\t// -- Implicit basic constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec()\n#\t\t\tif GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE\n\t\t\t\t: x(0), y(0), z(0)\n#\t\t\tendif\n\t\t{}\n\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, Q> const& v)\n\t\t\t: x(v.x), y(v.y), z(v.z)\n\t\t{}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, T, P> const& v)\n\t\t: x(v.x), y(v.y), z(v.z)\n\t{}\n\n\t// -- Explicit basic constructors --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T scalar)\n\t\t: x(scalar), y(scalar), z(scalar)\n\t{}\n\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(T _x, T _y, T _z)\n\t\t: x(_x), y(_y), z(_z)\n\t{}\n\n\t// -- Conversion scalar constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.x))\n\t\t, z(static_cast<T>(v.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, Z _z)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z.x))\n\t{}\n\n\t// -- Conversion vector constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, B _z)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_z.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(A _x, vec<2, B, P> const& _yz)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_yz.x))\n\t\t, z(static_cast<T>(_yz.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_yz.x))\n\t\t, z(static_cast<T>(_yz.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<3, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.y))\n\t\t, z(static_cast<T>(v.z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>::vec(vec<4, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.y))\n\t\t, z(static_cast<T>(v.z))\n\t{}\n\n\t// -- Component accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T & vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i)\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\tswitch(i)\n\t\t{\n\t\tdefault:\n\t\t\tcase 0:\n\t\treturn x;\n\t\t\tcase 1:\n\t\treturn y;\n\t\t\tcase 2:\n\t\treturn z;\n\t\t}\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<3, T, Q>::operator[](typename vec<3, T, Q>::length_type i) const\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\tswitch(i)\n\t\t{\n\t\tdefault:\n\t\tcase 0:\n\t\t\treturn x;\n\t\tcase 1:\n\t\t\treturn y;\n\t\tcase 2:\n\t\t\treturn z;\n\t\t}\n\t}\n\n\t// -- Unary arithmetic operators --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, T, Q> const& v)\n\t\t{\n\t\t\tthis->x = v.x;\n\t\t\tthis->y = v.y;\n\t\t\tthis->z = v.z;\n\t\t\treturn *this;\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q>& vec<3, T, Q>::operator=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x = static_cast<T>(v.x);\n\t\tthis->y = static_cast<T>(v.y);\n\t\tthis->z = static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(U scalar)\n\t{\n\t\tthis->x += static_cast<T>(scalar);\n\t\tthis->y += static_cast<T>(scalar);\n\t\tthis->z += static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x += static_cast<T>(v.x);\n\t\tthis->y += static_cast<T>(v.x);\n\t\tthis->z += static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator+=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x += static_cast<T>(v.x);\n\t\tthis->y += static_cast<T>(v.y);\n\t\tthis->z += static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(U scalar)\n\t{\n\t\tthis->x -= static_cast<T>(scalar);\n\t\tthis->y -= static_cast<T>(scalar);\n\t\tthis->z -= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x -= static_cast<T>(v.x);\n\t\tthis->y -= static_cast<T>(v.x);\n\t\tthis->z -= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator-=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x -= static_cast<T>(v.x);\n\t\tthis->y -= static_cast<T>(v.y);\n\t\tthis->z -= static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(U scalar)\n\t{\n\t\tthis->x *= static_cast<T>(scalar);\n\t\tthis->y *= static_cast<T>(scalar);\n\t\tthis->z *= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x *= static_cast<T>(v.x);\n\t\tthis->y *= static_cast<T>(v.x);\n\t\tthis->z *= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator*=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x *= static_cast<T>(v.x);\n\t\tthis->y *= static_cast<T>(v.y);\n\t\tthis->z *= static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(U v)\n\t{\n\t\tthis->x /= static_cast<T>(v);\n\t\tthis->y /= static_cast<T>(v);\n\t\tthis->z /= static_cast<T>(v);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x /= static_cast<T>(v.x);\n\t\tthis->y /= static_cast<T>(v.x);\n\t\tthis->z /= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator/=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x /= static_cast<T>(v.x);\n\t\tthis->y /= static_cast<T>(v.y);\n\t\tthis->z /= static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator++()\n\t{\n\t\t++this->x;\n\t\t++this->y;\n\t\t++this->z;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator--()\n\t{\n\t\t--this->x;\n\t\t--this->y;\n\t\t--this->z;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator++(int)\n\t{\n\t\tvec<3, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> vec<3, T, Q>::operator--(int)\n\t{\n\t\tvec<3, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(U scalar)\n\t{\n\t\tthis->x %= scalar;\n\t\tthis->y %= scalar;\n\t\tthis->z %= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x %= v.x;\n\t\tthis->y %= v.x;\n\t\tthis->z %= v.x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator%=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x %= v.x;\n\t\tthis->y %= v.y;\n\t\tthis->z %= v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(U scalar)\n\t{\n\t\tthis->x &= scalar;\n\t\tthis->y &= scalar;\n\t\tthis->z &= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x &= v.x;\n\t\tthis->y &= v.x;\n\t\tthis->z &= v.x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator&=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x &= v.x;\n\t\tthis->y &= v.y;\n\t\tthis->z &= v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(U scalar)\n\t{\n\t\tthis->x |= scalar;\n\t\tthis->y |= scalar;\n\t\tthis->z |= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x |= v.x;\n\t\tthis->y |= v.x;\n\t\tthis->z |= v.x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator|=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x |= v.x;\n\t\tthis->y |= v.y;\n\t\tthis->z |= v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(U scalar)\n\t{\n\t\tthis->x ^= scalar;\n\t\tthis->y ^= scalar;\n\t\tthis->z ^= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x ^= v.x;\n\t\tthis->y ^= v.x;\n\t\tthis->z ^= v.x;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator^=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x ^= v.x;\n\t\tthis->y ^= v.y;\n\t\tthis->z ^= v.z;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(U scalar)\n\t{\n\t\tthis->x <<= scalar;\n\t\tthis->y <<= scalar;\n\t\tthis->z <<= scalar;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x <<= static_cast<T>(v.x);\n\t\tthis->y <<= static_cast<T>(v.x);\n\t\tthis->z <<= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator<<=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x <<= static_cast<T>(v.x);\n\t\tthis->y <<= static_cast<T>(v.y);\n\t\tthis->z <<= static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(U scalar)\n\t{\n\t\tthis->x >>= static_cast<T>(scalar);\n\t\tthis->y >>= static_cast<T>(scalar);\n\t\tthis->z >>= static_cast<T>(scalar);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<1, U, Q> const& v)\n\t{\n\t\tthis->x >>= static_cast<T>(v.x);\n\t\tthis->y >>= static_cast<T>(v.x);\n\t\tthis->z >>= static_cast<T>(v.x);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> & vec<3, T, Q>::operator>>=(vec<3, U, Q> const& v)\n\t{\n\t\tthis->x >>= static_cast<T>(v.x);\n\t\tthis->y >>= static_cast<T>(v.y);\n\t\tthis->z >>= static_cast<T>(v.z);\n\t\treturn *this;\n\t}\n\n\t// -- Unary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\t-v.x,\n\t\t\t-v.y,\n\t\t\t-v.z);\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x + scalar,\n\t\t\tv.y + scalar,\n\t\t\tv.z + scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x + scalar.x,\n\t\t\tv.y + scalar.x,\n\t\t\tv.z + scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar + v.x,\n\t\t\tscalar + v.y,\n\t\t\tscalar + v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x + v.x,\n\t\t\tscalar.x + v.y,\n\t\t\tscalar.x + v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator+(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x + v2.x,\n\t\t\tv1.y + v2.y,\n\t\t\tv1.z + v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x - scalar,\n\t\t\tv.y - scalar,\n\t\t\tv.z - scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x - scalar.x,\n\t\t\tv.y - scalar.x,\n\t\t\tv.z - scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar - v.x,\n\t\t\tscalar - v.y,\n\t\t\tscalar - v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x - v.x,\n\t\t\tscalar.x - v.y,\n\t\t\tscalar.x - v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator-(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x - v2.x,\n\t\t\tv1.y - v2.y,\n\t\t\tv1.z - v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x * scalar,\n\t\t\tv.y * scalar,\n\t\t\tv.z * scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x * scalar.x,\n\t\t\tv.y * scalar.x,\n\t\t\tv.z * scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar * v.x,\n\t\t\tscalar * v.y,\n\t\t\tscalar * v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x * v.x,\n\t\t\tscalar.x * v.y,\n\t\t\tscalar.x * v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator*(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x * v2.x,\n\t\t\tv1.y * v2.y,\n\t\t\tv1.z * v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x / scalar,\n\t\t\tv.y / scalar,\n\t\t\tv.z / scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x / scalar.x,\n\t\t\tv.y / scalar.x,\n\t\t\tv.z / scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar / v.x,\n\t\t\tscalar / v.y,\n\t\t\tscalar / v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x / v.x,\n\t\t\tscalar.x / v.y,\n\t\t\tscalar.x / v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator/(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x / v2.x,\n\t\t\tv1.y / v2.y,\n\t\t\tv1.z / v2.z);\n\t}\n\n\t// -- Binary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x % scalar,\n\t\t\tv.y % scalar,\n\t\t\tv.z % scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x % scalar.x,\n\t\t\tv.y % scalar.x,\n\t\t\tv.z % scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar % v.x,\n\t\t\tscalar % v.y,\n\t\t\tscalar % v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x % v.x,\n\t\t\tscalar.x % v.y,\n\t\t\tscalar.x % v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator%(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x % v2.x,\n\t\t\tv1.y % v2.y,\n\t\t\tv1.z % v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x & scalar,\n\t\t\tv.y & scalar,\n\t\t\tv.z & scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x & scalar.x,\n\t\t\tv.y & scalar.x,\n\t\t\tv.z & scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar & v.x,\n\t\t\tscalar & v.y,\n\t\t\tscalar & v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x & v.x,\n\t\t\tscalar.x & v.y,\n\t\t\tscalar.x & v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator&(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x & v2.x,\n\t\t\tv1.y & v2.y,\n\t\t\tv1.z & v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x | scalar,\n\t\t\tv.y | scalar,\n\t\t\tv.z | scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x | scalar.x,\n\t\t\tv.y | scalar.x,\n\t\t\tv.z | scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar | v.x,\n\t\t\tscalar | v.y,\n\t\t\tscalar | v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x | v.x,\n\t\t\tscalar.x | v.y,\n\t\t\tscalar.x | v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator|(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x | v2.x,\n\t\t\tv1.y | v2.y,\n\t\t\tv1.z | v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x ^ scalar,\n\t\t\tv.y ^ scalar,\n\t\t\tv.z ^ scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x ^ scalar.x,\n\t\t\tv.y ^ scalar.x,\n\t\t\tv.z ^ scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar ^ v.x,\n\t\t\tscalar ^ v.y,\n\t\t\tscalar ^ v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x ^ v.x,\n\t\t\tscalar.x ^ v.y,\n\t\t\tscalar.x ^ v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator^(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x ^ v2.x,\n\t\t\tv1.y ^ v2.y,\n\t\t\tv1.z ^ v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x << scalar,\n\t\t\tv.y << scalar,\n\t\t\tv.z << scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x << scalar.x,\n\t\t\tv.y << scalar.x,\n\t\t\tv.z << scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar << v.x,\n\t\t\tscalar << v.y,\n\t\t\tscalar << v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x << v.x,\n\t\t\tscalar.x << v.y,\n\t\t\tscalar.x << v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator<<(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x << v2.x,\n\t\t\tv1.y << v2.y,\n\t\t\tv1.z << v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x >> scalar,\n\t\t\tv.y >> scalar,\n\t\t\tv.z >> scalar);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv.x >> scalar.x,\n\t\t\tv.y >> scalar.x,\n\t\t\tv.z >> scalar.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(T scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar >> v.x,\n\t\t\tscalar >> v.y,\n\t\t\tscalar >> v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tscalar.x >> v.x,\n\t\t\tscalar.x >> v.y,\n\t\t\tscalar.x >> v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator>>(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tv1.x >> v2.x,\n\t\t\tv1.y >> v2.y,\n\t\t\tv1.z >> v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, T, Q> operator~(vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\t~v.x,\n\t\t\t~v.y,\n\t\t\t~v.z);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn\n\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.x, v2.x) &&\n\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.y, v2.y) &&\n\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.z, v2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<3, T, Q> const& v1, vec<3, T, Q> const& v2)\n\t{\n\t\treturn !(v1 == v2);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator&&(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2)\n\t{\n\t\treturn vec<3, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<3, bool, Q> operator||(vec<3, bool, Q> const& v1, vec<3, bool, Q> const& v2)\n\t{\n\t\treturn vec<3, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec4.hpp",
    "content": "/// @ref core\n/// @file glm/detail/type_vec4.hpp\n\n#pragma once\n\n#include \"qualifier.hpp\"\n#if GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n#\tinclude \"_swizzle.hpp\"\n#elif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n#\tinclude \"_swizzle_func.hpp\"\n#endif\n#include <cstddef>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tstruct vec<4, T, Q>\n\t{\n\t\t// -- Implementation detail --\n\n\t\ttypedef T value_type;\n\t\ttypedef vec<4, T, Q> type;\n\t\ttypedef vec<4, bool, Q> bool_type;\n\n\t\t// -- Data --\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic push\n#\t\t\t\tpragma GCC diagnostic ignored \"-Wpedantic\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic push\n#\t\t\t\tpragma clang diagnostic ignored \"-Wgnu-anonymous-struct\"\n#\t\t\t\tpragma clang diagnostic ignored \"-Wnested-anon-types\"\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(push)\n#\t\t\t\tpragma warning(disable: 4201)  // nonstandard extension used : nameless struct/union\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_CONFIG_XYZW_ONLY\n\t\t\tT x, y, z, w;\n#\t\telif GLM_CONFIG_ANONYMOUS_STRUCT == GLM_ENABLE\n\t\t\tunion\n\t\t\t{\n\t\t\t\tstruct { T x, y, z, w; };\n\t\t\t\tstruct { T r, g, b, a; };\n\t\t\t\tstruct { T s, t, p, q; };\n\n\t\t\t\ttypename detail::storage<4, T, detail::is_aligned<Q>::value>::type data;\n\n#\t\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\t\t\tGLM_SWIZZLE4_2_MEMBERS(T, Q, x, y, z, w)\n\t\t\t\t\tGLM_SWIZZLE4_2_MEMBERS(T, Q, r, g, b, a)\n\t\t\t\t\tGLM_SWIZZLE4_2_MEMBERS(T, Q, s, t, p, q)\n\t\t\t\t\tGLM_SWIZZLE4_3_MEMBERS(T, Q, x, y, z, w)\n\t\t\t\t\tGLM_SWIZZLE4_3_MEMBERS(T, Q, r, g, b, a)\n\t\t\t\t\tGLM_SWIZZLE4_3_MEMBERS(T, Q, s, t, p, q)\n\t\t\t\t\tGLM_SWIZZLE4_4_MEMBERS(T, Q, x, y, z, w)\n\t\t\t\t\tGLM_SWIZZLE4_4_MEMBERS(T, Q, r, g, b, a)\n\t\t\t\t\tGLM_SWIZZLE4_4_MEMBERS(T, Q, s, t, p, q)\n#\t\t\t\tendif\n\t\t\t};\n#\t\telse\n\t\t\tunion { T x, r, s; };\n\t\t\tunion { T y, g, t; };\n\t\t\tunion { T z, b, p; };\n\t\t\tunion { T w, a, q; };\n\n#\t\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_FUNCTION\n\t\t\t\tGLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, Q)\n#\t\t\tendif\n#\t\tendif\n\n#\t\tif GLM_SILENT_WARNINGS == GLM_ENABLE\n#\t\t\tif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\t\t\tpragma clang diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_GCC\n#\t\t\t\tpragma GCC diagnostic pop\n#\t\t\telif GLM_COMPILER & GLM_COMPILER_VC\n#\t\t\t\tpragma warning(pop)\n#\t\t\tendif\n#\t\tendif\n\n\t\t// -- Component accesses --\n\n\t\ttypedef length_t length_type;\n\n\t\t/// Return the count of components of the vector\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 4;}\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T & operator[](length_type i);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR T const& operator[](length_type i) const;\n\n\t\t// -- Implicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec() GLM_DEFAULT;\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, Q> const& v) GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<4, T, P> const& v);\n\n\t\t// -- Explicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(T scalar);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T x, T y, T z, T w);\n\n\t\t// -- Conversion scalar constructors --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR explicit vec(vec<1, U, P> const& v);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, Z _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w);\n\t\ttemplate<typename X, typename Y, typename Z, typename W>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _Y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w);\n\n\t\t// -- Conversion vector constructors --\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, C _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, C _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, B _y, vec<2, C, P> const& _zw);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, typename C, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, B _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(A _x, vec<3, B, P> const& _yzw);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw);\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename A, typename B, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw);\n\n\t\t/// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT vec(vec<4, U, P> const& v);\n\n\t\t// -- Swizzle constructors --\n#\t\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\t\t\ttemplate<int E0, int E1, int E2, int E3>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<4, T, Q, E0, E1, E2, E3> const& that)\n\t\t\t{\n\t\t\t\t*this = that();\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1, int F0, int F1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, detail::_swizzle<2, T, Q, F0, F1, -1, -2> const& u)\n\t\t\t{\n\t\t\t\t*this = vec<4, T, Q>(v(), u());\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, T const& y, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v)\n\t\t\t{\n\t\t\t\t*this = vec<4, T, Q>(x, y, v());\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& w)\n\t\t\t{\n\t\t\t\t*this = vec<4, T, Q>(x, v(), w);\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<2, T, Q, E0, E1, -1, -2> const& v, T const& z, T const& w)\n\t\t\t{\n\t\t\t\t*this = vec<4, T, Q>(v(), z, w);\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1, int E2>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v, T const& w)\n\t\t\t{\n\t\t\t\t*this = vec<4, T, Q>(v(), w);\n\t\t\t}\n\n\t\t\ttemplate<int E0, int E1, int E2>\n\t\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec(T const& x, detail::_swizzle<3, T, Q, E0, E1, E2, -1> const& v)\n\t\t\t{\n\t\t\t\t*this = vec<4, T, Q>(x, v());\n\t\t\t}\n#\t\tendif//GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\n\t\t// -- Unary arithmetic operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, T, Q> const& v) GLM_DEFAULT;\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator+=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator-=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator*=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q>& operator/=(vec<4, U, Q> const& v);\n\n\t\t// -- Increment and decrement operators --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator++();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator--();\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator++(int);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator--(int);\n\n\t\t// -- Unary bit operators --\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator%=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator&=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator|=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator^=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator<<=(vec<4, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(U scalar);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<1, U, Q> const& v);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> & operator>>=(vec<4, U, Q> const& v);\n\t};\n\n\t// -- Unary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2);\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2);\n}//namespace glm\n\n#ifndef GLM_EXTERNAL_TEMPLATE\n#include \"type_vec4.inl\"\n#endif//GLM_EXTERNAL_TEMPLATE\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec4.inl",
    "content": "/// @ref core\n\n#include \"compute_vector_relational.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_vec4_add\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_vec4_sub\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_vec4_mul\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_vec4_div\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_vec4_mod\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x % b.x, a.y % b.y, a.z % b.z, a.w % b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_and\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_or\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_xor\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_shift_left\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x << b.x, a.y << b.y, a.z << b.z, a.w << b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_shift_right\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\treturn vec<4, T, Q>(a.x >> b.x, a.y >> b.y, a.z >> b.z, a.w >> b.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_equal\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t\t{\n\t\t\treturn\n\t\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.x, v2.x) &&\n\t\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.y, v2.y) &&\n\t\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.z, v2.z) &&\n\t\t\t\tdetail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(v1.w, v2.w);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_nequal\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static bool call(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t\t{\n\t\t\treturn !compute_vec4_equal<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(v1, v2);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q, int IsInt, std::size_t Size, bool Aligned>\n\tstruct compute_vec4_bitwise_not\n\t{\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR static vec<4, T, Q> call(vec<4, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<4, T, Q>(~v.x, ~v.y, ~v.z, ~v.w);\n\t\t}\n\t};\n}//namespace detail\n\n\t// -- Implicit basic constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec()\n#\t\t\tif GLM_CONFIG_CTOR_INIT != GLM_CTOR_INIT_DISABLE\n\t\t\t\t: x(0), y(0), z(0), w(0)\n#\t\t\tendif\n\t\t{}\n\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, Q> const& v)\n\t\t\t: x(v.x), y(v.y), z(v.z), w(v.w)\n\t\t{}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, T, P> const& v)\n\t\t: x(v.x), y(v.y), z(v.z), w(v.w)\n\t{}\n\n\t// -- Explicit basic constructors --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T scalar)\n\t\t: x(scalar), y(scalar), z(scalar), w(scalar)\n\t{}\n\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(T _x, T _y, T _z, T _w)\n\t\t: x(_x), y(_y), z(_z), w(_w)\n\t{}\n\n\t// -- Conversion scalar constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.x))\n\t\t, z(static_cast<T>(v.x))\n\t\t, w(static_cast<T>(v.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, Z _z, W _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, W _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, W _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, W _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, W _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, W _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, W _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, Z _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, Z _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, Y _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(X _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename X, typename Y, typename Z, typename W>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, X, Q> const& _x, vec<1, Y, Q> const& _y, vec<1, Z, Q> const& _z, vec<1, W, Q> const& _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\t// -- Conversion vector constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, C _w)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, C _w)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, B _z, vec<1, C, P> const& _w)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_z))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<1, B, P> const& _z, vec<1, C, P> const& _w)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_z.x))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, C _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_yz.x))\n\t\t, z(static_cast<T>(_yz.y))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, C _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_yz.x))\n\t\t, z(static_cast<T>(_yz.y))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_yz.x))\n\t\t, z(static_cast<T>(_yz.y))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<2, B, P> const& _yz, vec<1, C, P> const& _w)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_yz.x))\n\t\t, z(static_cast<T>(_yz.y))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, B _y, vec<2, C, P> const& _zw)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_zw.x))\n\t\t, w(static_cast<T>(_zw.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, B _y, vec<2, C, P> const& _zw)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y))\n\t\t, z(static_cast<T>(_zw.x))\n\t\t, w(static_cast<T>(_zw.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_zw.x))\n\t\t, w(static_cast<T>(_zw.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, typename C, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<1, B, P> const& _y, vec<2, C, P> const& _zw)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_y.x))\n\t\t, z(static_cast<T>(_zw.x))\n\t\t, w(static_cast<T>(_zw.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, B _w)\n\t\t: x(static_cast<T>(_xyz.x))\n\t\t, y(static_cast<T>(_xyz.y))\n\t\t, z(static_cast<T>(_xyz.z))\n\t\t, w(static_cast<T>(_w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<3, A, P> const& _xyz, vec<1, B, P> const& _w)\n\t\t: x(static_cast<T>(_xyz.x))\n\t\t, y(static_cast<T>(_xyz.y))\n\t\t, z(static_cast<T>(_xyz.z))\n\t\t, w(static_cast<T>(_w.x))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(A _x, vec<3, B, P> const& _yzw)\n\t\t: x(static_cast<T>(_x))\n\t\t, y(static_cast<T>(_yzw.x))\n\t\t, z(static_cast<T>(_yzw.y))\n\t\t, w(static_cast<T>(_yzw.z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<1, A, P> const& _x, vec<3, B, P> const& _yzw)\n\t\t: x(static_cast<T>(_x.x))\n\t\t, y(static_cast<T>(_yzw.x))\n\t\t, z(static_cast<T>(_yzw.y))\n\t\t, w(static_cast<T>(_yzw.z))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename A, typename B, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<2, A, P> const& _xy, vec<2, B, P> const& _zw)\n\t\t: x(static_cast<T>(_xy.x))\n\t\t, y(static_cast<T>(_xy.y))\n\t\t, z(static_cast<T>(_zw.x))\n\t\t, w(static_cast<T>(_zw.y))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>::vec(vec<4, U, P> const& v)\n\t\t: x(static_cast<T>(v.x))\n\t\t, y(static_cast<T>(v.y))\n\t\t, z(static_cast<T>(v.z))\n\t\t, w(static_cast<T>(v.w))\n\t{}\n\n\t// -- Component accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i)\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\tswitch(i)\n\t\t{\n\t\tdefault:\n\t\tcase 0:\n\t\t\treturn x;\n\t\tcase 1:\n\t\t\treturn y;\n\t\tcase 2:\n\t\t\treturn z;\n\t\tcase 3:\n\t\t\treturn w;\n\t\t}\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T const& vec<4, T, Q>::operator[](typename vec<4, T, Q>::length_type i) const\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\tswitch(i)\n\t\t{\n\t\tdefault:\n\t\tcase 0:\n\t\t\treturn x;\n\t\tcase 1:\n\t\t\treturn y;\n\t\tcase 2:\n\t\t\treturn z;\n\t\tcase 3:\n\t\t\treturn w;\n\t\t}\n\t}\n\n\t// -- Unary arithmetic operators --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, T, Q> const& v)\n\t\t{\n\t\t\tthis->x = v.x;\n\t\t\tthis->y = v.y;\n\t\t\tthis->z = v.z;\n\t\t\tthis->w = v.w;\n\t\t\treturn *this;\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q>& vec<4, T, Q>::operator=(vec<4, U, Q> const& v)\n\t{\n\t\tthis->x = static_cast<T>(v.x);\n\t\tthis->y = static_cast<T>(v.y);\n\t\tthis->z = static_cast<T>(v.z);\n\t\tthis->w = static_cast<T>(v.w);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_add<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_add<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v.x)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator+=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_add<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_sub<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_sub<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v.x)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator-=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_sub<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_mul<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_mul<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v.x)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator*=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_mul<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_div<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_div<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v.x)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator/=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_div<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\t// -- Increment and decrement operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator++()\n\t{\n\t\t++this->x;\n\t\t++this->y;\n\t\t++this->z;\n\t\t++this->w;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator--()\n\t{\n\t\t--this->x;\n\t\t--this->y;\n\t\t--this->z;\n\t\t--this->w;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator++(int)\n\t{\n\t\tvec<4, T, Q> Result(*this);\n\t\t++*this;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> vec<4, T, Q>::operator--(int)\n\t{\n\t\tvec<4, T, Q> Result(*this);\n\t\t--*this;\n\t\treturn Result;\n\t}\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_mod<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_mod<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator%=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_mod<T, Q, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_and<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_and<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator&=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_and<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_or<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_or<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator|=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_or<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_xor<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_xor<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator^=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_xor<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_shift_left<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_shift_left<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator<<=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_shift_left<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(U scalar)\n\t{\n\t\treturn (*this = detail::compute_vec4_shift_right<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(scalar)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<1, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_shift_right<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> & vec<4, T, Q>::operator>>=(vec<4, U, Q> const& v)\n\t{\n\t\treturn (*this = detail::compute_vec4_shift_right<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(*this, vec<4, T, Q>(v)));\n\t}\n\n\t// -- Unary constant operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(0) -= v;\n\t}\n\n\t// -- Binary arithmetic operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v, T const & scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) += scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) += v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(v) += scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v2) += v1;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator+(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) += v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v, T const & scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) -= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) -= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) -= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) -= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator-(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) -= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v, T const & scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) *= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) *= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(v) *= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v2) *= v1;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator*(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) *= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v, T const & scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) /= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) /= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) /= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) /= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator/(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) /= v2;\n\t}\n\n\t// -- Binary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) %= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) %= v2.x;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) %= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<1, T, Q> const& scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar.x) %= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator%(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) %= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) &= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v, vec<1, T, Q> const& scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) &= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) &= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) &= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator&(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) &= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) |= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) |= v2.x;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) |= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) |= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator|(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) |= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) ^= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) ^= v2.x;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) ^= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) ^= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator^(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) ^= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) <<= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) <<= v2.x;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) <<= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) <<= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator<<(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) <<= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v, T scalar)\n\t{\n\t\treturn vec<4, T, Q>(v) >>= scalar;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<1, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) >>= v2.x;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(T scalar, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(scalar) >>= v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<1, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1.x) >>= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator>>(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn vec<4, T, Q>(v1) >>= v2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, T, Q> operator~(vec<4, T, Q> const& v)\n\t{\n\t\treturn detail::compute_vec4_bitwise_not<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(v);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator==(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn detail::compute_vec4_equal<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(v1, v2);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool operator!=(vec<4, T, Q> const& v1, vec<4, T, Q> const& v2)\n\t{\n\t\treturn detail::compute_vec4_nequal<T, Q, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<Q>::value>::call(v1, v2);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator&&(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2)\n\t{\n\t\treturn vec<4, bool, Q>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z, v1.w && v2.w);\n\t}\n\n\ttemplate<qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, bool, Q> operator||(vec<4, bool, Q> const& v1, vec<4, bool, Q> const& v2)\n\t{\n\t\treturn vec<4, bool, Q>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"type_vec4_simd.inl\"\n#endif\n"
  },
  {
    "path": "lib/gli/glm/detail/type_vec4_simd.inl",
    "content": "#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nnamespace glm{\nnamespace detail\n{\n#\tif GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\ttemplate<qualifier Q, int E0, int E1, int E2, int E3>\n\tstruct _swizzle_base1<4, float, Q, E0,E1,E2,E3, true> : public _swizzle_base0<float, 4>\n\t{\n\t\tGLM_FUNC_QUALIFIER vec<4, float, Q> operator ()()  const\n\t\t{\n\t\t\t__m128 data = *reinterpret_cast<__m128 const*>(&this->_buffer);\n\n\t\t\tvec<4, float, Q> Result;\n#\t\t\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\t\t\t\tResult.data = _mm_permute_ps(data, _MM_SHUFFLE(E3, E2, E1, E0));\n#\t\t\telse\n\t\t\t\tResult.data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(E3, E2, E1, E0));\n#\t\t\tendif\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q, int E0, int E1, int E2, int E3>\n\tstruct _swizzle_base1<4, int, Q, E0,E1,E2,E3, true> : public _swizzle_base0<int, 4>\n\t{\n\t\tGLM_FUNC_QUALIFIER vec<4, int, Q> operator ()()  const\n\t\t{\n\t\t\t__m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer);\n\n\t\t\tvec<4, int, Q> Result;\n\t\t\tResult.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0));\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q, int E0, int E1, int E2, int E3>\n\tstruct _swizzle_base1<4, uint, Q, E0,E1,E2,E3, true> : public _swizzle_base0<uint, 4>\n\t{\n\t\tGLM_FUNC_QUALIFIER vec<4, uint, Q> operator ()()  const\n\t\t{\n\t\t\t__m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer);\n\n\t\t\tvec<4, uint, Q> Result;\n\t\t\tResult.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0));\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif// GLM_CONFIG_SWIZZLE == GLM_SWIZZLE_OPERATOR\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_add<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_add_ps(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_add<double, Q, true>\n\t{\n\t\tstatic vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b)\n\t\t{\n\t\t\tvec<4, double, Q> Result;\n\t\t\tResult.data = _mm256_add_pd(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_sub<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_sub_ps(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_sub<double, Q, true>\n\t{\n\t\tstatic vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b)\n\t\t{\n\t\t\tvec<4, double, Q> Result;\n\t\t\tResult.data = _mm256_sub_pd(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_mul<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_mul_ps(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_mul<double, Q, true>\n\t{\n\t\tstatic vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b)\n\t\t{\n\t\t\tvec<4, double, Q> Result;\n\t\t\tResult.data = _mm256_mul_pd(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_div<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = _mm_div_ps(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\t#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_div<double, Q, true>\n\t{\n\t\tstatic vec<4, double, Q> call(vec<4, double, Q> const& a, vec<4, double, Q> const& b)\n\t\t{\n\t\t\tvec<4, double, Q> Result;\n\t\t\tResult.data = _mm256_div_pd(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<>\n\tstruct compute_vec4_div<float, aligned_lowp, true>\n\t{\n\t\tstatic vec<4, float, aligned_lowp> call(vec<4, float, aligned_lowp> const& a, vec<4, float, aligned_lowp> const& b)\n\t\t{\n\t\t\tvec<4, float, aligned_lowp> Result;\n\t\t\tResult.data = _mm_mul_ps(a.data, _mm_rcp_ps(b.data));\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_and<T, Q, true, 32, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm_and_si128(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_and<T, Q, true, 64, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm256_and_si256(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_or<T, Q, true, 32, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm_or_si128(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_or<T, Q, true, 64, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm256_or_si256(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_xor<T, Q, true, 32, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm_xor_si128(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_xor<T, Q, true, 64, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm256_xor_si256(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_shift_left<T, Q, true, 32, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm_sll_epi32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_shift_left<T, Q, true, 64, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm256_sll_epi64(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_shift_right<T, Q, true, 32, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm_srl_epi32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_shift_right<T, Q, true, 64, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& a, vec<4, T, Q> const& b)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm256_srl_epi64(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_bitwise_not<T, Q, true, 32, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& v)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm_xor_si128(v.data, _mm_set1_epi32(-1));\n\t\t\treturn Result;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_vec4_bitwise_not<T, Q, true, 64, true>\n\t{\n\t\tstatic vec<4, T, Q> call(vec<4, T, Q> const& v)\n\t\t{\n\t\t\tvec<4, T, Q> Result;\n\t\t\tResult.data = _mm256_xor_si256(v.data, _mm_set1_epi32(-1));\n\t\t\treturn Result;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_equal<float, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)\n\t\t{\n\t\t\treturn _mm_movemask_ps(_mm_cmpeq_ps(v1.data, v2.data)) != 0;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_SSE41_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_equal<int, Q, true, 32, true>\n\t{\n\t\tstatic bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)\n\t\t{\n\t\t\t//return _mm_movemask_epi8(_mm_cmpeq_epi32(v1.data, v2.data)) != 0;\n\t\t\t__m128i neq = _mm_xor_si128(v1.data, v2.data);\n\t\t\treturn _mm_test_all_zeros(neq, neq) == 0;\n\t\t}\n\t};\n#\tendif\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_nequal<float, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)\n\t\t{\n\t\t\treturn _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) != 0;\n\t\t}\n\t};\n\n#\tif GLM_ARCH & GLM_ARCH_SSE41_BIT\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_nequal<int, Q, true, 32, true>\n\t{\n\t\tstatic bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)\n\t\t{\n\t\t\t//return _mm_movemask_epi8(_mm_cmpneq_epi32(v1.data, v2.data)) != 0;\n\t\t\t__m128i neq = _mm_xor_si128(v1.data, v2.data);\n\t\t\treturn _mm_test_all_zeros(neq, neq) != 0;\n\t\t}\n\t};\n#\tendif\n}//namespace detail\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) :\n\t\tdata(_mm_set1_ps(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) :\n\t\tdata(_mm_set1_ps(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) :\n\t\tdata(_mm_set1_ps(_s))\n\t{}\n\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_lowp>::vec(double _s) :\n\t\tdata(_mm256_set1_pd(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_mediump>::vec(double _s) :\n\t\tdata(_mm256_set1_pd(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, double, aligned_highp>::vec(double _s) :\n\t\tdata(_mm256_set1_pd(_s))\n\t{}\n#\tendif\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) :\n\t\tdata(_mm_set1_epi32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) :\n\t\tdata(_mm_set1_epi32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) :\n\t\tdata(_mm_set1_epi32(_s))\n\t{}\n\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_lowp>::vec(detail::int64 _s) :\n\t\tdata(_mm256_set1_epi64x(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_mediump>::vec(detail::int64 _s) :\n\t\tdata(_mm256_set1_epi64x(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, detail::int64, aligned_highp>::vec(detail::int64 _s) :\n\t\tdata(_mm256_set1_epi64x(_s))\n\t{}\n#\tendif\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _x, float _y, float _z, float _w) :\n\t\tdata(_mm_set_ps(_w, _z, _y, _x))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _x, float _y, float _z, float _w) :\n\t\tdata(_mm_set_ps(_w, _z, _y, _x))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _x, float _y, float _z, float _w) :\n\t\tdata(_mm_set_ps(_w, _z, _y, _x))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(_mm_set_epi32(_w, _z, _y, _x))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(_mm_set_epi32(_w, _z, _y, _x))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(_mm_set_epi32(_w, _z, _y, _x))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x)))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x)))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(_mm_cvtepi32_ps(_mm_set_epi32(_w, _z, _y, _x)))\n\t{}\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n#if GLM_ARCH & GLM_ARCH_NEON_BIT\nnamespace glm {\nnamespace detail {\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_add<float, Q, true>\n\t{\n\t\tstatic\n\t\tvec<4, float, Q>\n\t\tcall(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = vaddq_f32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_add<uint, Q, true>\n\t{\n\t\tstatic\n\t\tvec<4, uint, Q>\n\t\tcall(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b)\n\t\t{\n\t\t\tvec<4, uint, Q> Result;\n\t\t\tResult.data = vaddq_u32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_add<int, Q, true>\n\t{\n\t\tstatic\n\t\tvec<4, int, Q>\n\t\tcall(vec<4, int, Q> const& a, vec<4, int, Q> const& b)\n\t\t{\n\t\t\tvec<4, uint, Q> Result;\n\t\t\tResult.data = vaddq_s32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_sub<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = vsubq_f32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_sub<uint, Q, true>\n\t{\n\t\tstatic vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b)\n\t\t{\n\t\t\tvec<4, uint, Q> Result;\n\t\t\tResult.data = vsubq_u32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_sub<int, Q, true>\n\t{\n\t\tstatic vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b)\n\t\t{\n\t\t\tvec<4, int, Q> Result;\n\t\t\tResult.data = vsubq_s32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_mul<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = vmulq_f32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_mul<uint, Q, true>\n\t{\n\t\tstatic vec<4, uint, Q> call(vec<4, uint, Q> const& a, vec<4, uint, Q> const& b)\n\t\t{\n\t\t\tvec<4, uint, Q> Result;\n\t\t\tResult.data = vmulq_u32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_mul<int, Q, true>\n\t{\n\t\tstatic vec<4, int, Q> call(vec<4, int, Q> const& a, vec<4, int, Q> const& b)\n\t\t{\n\t\t\tvec<4, int, Q> Result;\n\t\t\tResult.data = vmulq_s32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_div<float, Q, true>\n\t{\n\t\tstatic vec<4, float, Q> call(vec<4, float, Q> const& a, vec<4, float, Q> const& b)\n\t\t{\n\t\t\tvec<4, float, Q> Result;\n\t\t\tResult.data = vdivq_f32(a.data, b.data);\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_equal<float, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)\n\t\t{\n\t\t\tuint32x4_t cmp = vceqq_f32(v1.data, v2.data);\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tcmp = vpminq_u32(cmp, cmp);\n\t\t\tcmp = vpminq_u32(cmp, cmp);\n\t\t\tuint32_t r = cmp[0];\n#else\n\t\t\tuint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp));\n\t\t\tcmpx2 = vpmin_u32(cmpx2, cmpx2);\n\t\t\tuint32_t r = cmpx2[0];\n#endif\n\t\t\treturn r == ~0u;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_equal<uint, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2)\n\t\t{\n\t\t\tuint32x4_t cmp = vceqq_u32(v1.data, v2.data);\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tcmp = vpminq_u32(cmp, cmp);\n\t\t\tcmp = vpminq_u32(cmp, cmp);\n\t\t\tuint32_t r = cmp[0];\n#else\n\t\t\tuint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp));\n\t\t\tcmpx2 = vpmin_u32(cmpx2, cmpx2);\n\t\t\tuint32_t r = cmpx2[0];\n#endif\n\t\t\treturn r == ~0u;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_equal<int, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)\n\t\t{\n\t\t\tuint32x4_t cmp = vceqq_s32(v1.data, v2.data);\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tcmp = vpminq_u32(cmp, cmp);\n\t\t\tcmp = vpminq_u32(cmp, cmp);\n\t\t\tuint32_t r = cmp[0];\n#else\n\t\t\tuint32x2_t cmpx2 = vpmin_u32(vget_low_f32(cmp), vget_high_f32(cmp));\n\t\t\tcmpx2 = vpmin_u32(cmpx2, cmpx2);\n\t\t\tuint32_t r = cmpx2[0];\n#endif\n\t\t\treturn r == ~0u;\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_nequal<float, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, float, Q> const& v1, vec<4, float, Q> const& v2)\n\t\t{\n\t\t\treturn !compute_vec4_equal<float, Q, false, 32, true>::call(v1, v2);\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_nequal<uint, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, uint, Q> const& v1, vec<4, uint, Q> const& v2)\n\t\t{\n\t\t\treturn !compute_vec4_equal<uint, Q, false, 32, true>::call(v1, v2);\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_vec4_nequal<int, Q, false, 32, true>\n\t{\n\t\tstatic bool call(vec<4, int, Q> const& v1, vec<4, int, Q> const& v2)\n\t\t{\n\t\t\treturn !compute_vec4_equal<int, Q, false, 32, true>::call(v1, v2);\n\t\t}\n\t};\n\n}//namespace detail\n\n#if !GLM_CONFIG_XYZW_ONLY\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(float _s) :\n\t\tdata(vdupq_n_f32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(float _s) :\n\t\tdata(vdupq_n_f32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(float _s) :\n\t\tdata(vdupq_n_f32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_lowp>::vec(int _s) :\n\t\tdata(vdupq_n_s32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_mediump>::vec(int _s) :\n\t\tdata(vdupq_n_s32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, int, aligned_highp>::vec(int _s) :\n\t\tdata(vdupq_n_s32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_lowp>::vec(uint _s) :\n\t\tdata(vdupq_n_u32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_mediump>::vec(uint _s) :\n\t\tdata(vdupq_n_u32(_s))\n\t{}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, uint, aligned_highp>::vec(uint _s) :\n\t\tdata(vdupq_n_u32(_s))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, float, aligned_highp>& rhs) :\n\t\tdata(rhs.data)\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, int, aligned_highp>& rhs) :\n\t\tdata(vcvtq_f32_s32(rhs.data))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(const vec<4, uint, aligned_highp>& rhs) :\n\t\tdata(vcvtq_f32_u32(rhs.data))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(vcvtq_f32_s32(vec<4, int, aligned_lowp>(_x, _y, _z, _w).data))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(vcvtq_f32_s32(vec<4, int, aligned_mediump>(_x, _y, _z, _w).data))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(int _x, int _y, int _z, int _w) :\n\t\tdata(vcvtq_f32_s32(vec<4, int, aligned_highp>(_x, _y, _z, _w).data))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_lowp>::vec(uint _x, uint _y, uint _z, uint _w) :\n\t\tdata(vcvtq_f32_u32(vec<4, uint, aligned_lowp>(_x, _y, _z, _w).data))\n\t{}\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_mediump>::vec(uint _x, uint _y, uint _z, uint _w) :\n\t\tdata(vcvtq_f32_u32(vec<4, uint, aligned_mediump>(_x, _y, _z, _w).data))\n\t{}\n\n\n\ttemplate<>\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<4, float, aligned_highp>::vec(uint _x, uint _y, uint _z, uint _w) :\n\t\tdata(vcvtq_f32_u32(vec<4, uint, aligned_highp>(_x, _y, _z, _w).data))\n\t{}\n\n#endif\n}//namespace glm\n\n#endif\n"
  },
  {
    "path": "lib/gli/glm/exponential.hpp",
    "content": "/// @ref core\n/// @file glm/exponential.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n///\n/// @defgroup core_func_exponential Exponential functions\n/// @ingroup core\n///\n/// Provides GLSL exponential functions\n///\n/// These all operate component-wise. The description is per component.\n///\n/// Include <glm/exponential.hpp> to use these core features.\n\n#pragma once\n\n#include \"detail/type_vec1.hpp\"\n#include \"detail/type_vec2.hpp\"\n#include \"detail/type_vec3.hpp\"\n#include \"detail/type_vec4.hpp\"\n#include <cmath>\n\nnamespace glm\n{\n\t/// @addtogroup core_func_exponential\n\t/// @{\n\n\t/// Returns 'base' raised to the power 'exponent'.\n\t///\n\t/// @param base Floating point value. pow function is defined for input values of 'base' defined in the range (inf-, inf+) in the limit of the type qualifier.\n\t/// @param exponent Floating point value representing the 'exponent'.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/pow.xml\">GLSL pow man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> pow(vec<L, T, Q> const& base, vec<L, T, Q> const& exponent);\n\n\t/// Returns the natural exponentiation of x, i.e., e^x.\n\t///\n\t/// @param v exp function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier.\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/exp.xml\">GLSL exp man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> exp(vec<L, T, Q> const& v);\n\n\t/// Returns the natural logarithm of v, i.e.,\n\t/// returns the value y which satisfies the equation x = e^y.\n\t/// Results are undefined if v <= 0.\n\t///\n\t/// @param v log function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier.\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/log.xml\">GLSL log man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> log(vec<L, T, Q> const& v);\n\n\t/// Returns 2 raised to the v power.\n\t///\n\t/// @param v exp2 function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type qualifier.\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/exp2.xml\">GLSL exp2 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> exp2(vec<L, T, Q> const& v);\n\n\t/// Returns the base 2 log of x, i.e., returns the value y,\n\t/// which satisfies the equation x = 2 ^ y.\n\t///\n\t/// @param v log2 function is defined for input values of v defined in the range (0, inf+) in the limit of the type qualifier.\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/log2.xml\">GLSL log2 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> log2(vec<L, T, Q> const& v);\n\n\t/// Returns the positive square root of v.\n\t///\n\t/// @param v sqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier.\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/sqrt.xml\">GLSL sqrt man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> sqrt(vec<L, T, Q> const& v);\n\n\t/// Returns the reciprocal of the positive square root of v.\n\t///\n\t/// @param v inversesqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type qualifier.\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/inversesqrt.xml\">GLSL inversesqrt man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> inversesqrt(vec<L, T, Q> const& v);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_exponential.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_clip_space.hpp",
    "content": "/// @ref ext_matrix_clip_space\n/// @file glm/ext/matrix_clip_space.hpp\n///\n/// @defgroup ext_matrix_clip_space GLM_EXT_matrix_clip_space\n/// @ingroup ext\n///\n/// Defines functions that generate clip space transformation matrices.\n///\n/// The matrices generated by this extension use standard OpenGL fixed-function\n/// conventions. For example, the lookAt function generates a transform from world\n/// space into the specific eye space that the projective matrix functions\n/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility\n/// specifications defines the particular layout of this eye space.\n///\n/// Include <glm/ext/matrix_clip_space.hpp> to use the features of this extension.\n///\n/// @see ext_matrix_transform\n/// @see ext_matrix_projection\n\n#pragma once\n\n// Dependencies\n#include \"../ext/scalar_constants.hpp\"\n#include \"../geometric.hpp\"\n#include \"../trigonometric.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_clip_space extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_clip_space\n\t/// @{\n\n\t/// Creates a matrix for projecting two-dimensional coordinates onto the screen.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top, T const& zNear, T const& zFar)\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluOrtho2D.xml\">gluOrtho2D man page</a>\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> ortho(\n\t\tT left, T right, T bottom, T top);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_ZO(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume using right-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH_NO(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_ZO(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH_NO(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoZO(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoNO(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using left-handed coordinates.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoLH(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using right-handed coordinates.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> orthoRH(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a matrix for an orthographic parallel viewing volume, using the default handedness and default near and far clip planes definition.\n\t/// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t///\n\t/// @see - glm::ortho(T const& left, T const& right, T const& bottom, T const& top)\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glOrtho.xml\">glOrtho man page</a>\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> ortho(\n\t\tT left, T right, T bottom, T top, T zNear, T zFar);\n\n\t/// Creates a left handed frustum matrix.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_ZO(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a left handed frustum matrix.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH_NO(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a right handed frustum matrix.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_ZO(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a right handed frustum matrix.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH_NO(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumZO(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a frustum matrix using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumNO(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a left handed frustum matrix.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumLH(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a right handed frustum matrix.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustumRH(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\t/// Creates a frustum matrix with default handedness, using the default handedness and default near and far clip planes definition.\n\t/// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glFrustum.xml\">glFrustum man page</a>\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> frustum(\n\t\tT left, T right, T bottom, T top, T near, T far);\n\n\n\t/// Creates a matrix for a right handed, symetric perspective-view frustum.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_ZO(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a right handed, symetric perspective-view frustum.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH_NO(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a left handed, symetric perspective-view frustum.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_ZO(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a left handed, symetric perspective-view frustum.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH_NO(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveZO(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a symetric perspective-view frustum using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveNO(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a right handed, symetric perspective-view frustum.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveRH(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a left handed, symetric perspective-view frustum.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveLH(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Creates a matrix for a symetric perspective-view frustum based on the default handedness and default near and far clip planes definition.\n\t/// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE.\n\t///\n\t/// @param fovy Specifies the field of view angle in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml\">gluPerspective man page</a>\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspective(\n\t\tT fovy, T aspect, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view using right-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_ZO(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view using right-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH_NO(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view using left-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_ZO(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view using left-handed coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH_NO(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovZO(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view using left-handed coordinates if GLM_FORCE_LEFT_HANDED if defined or right-handed coordinates otherwise.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovNO(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a right handed perspective projection matrix based on a field of view.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovRH(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a left handed perspective projection matrix based on a field of view.\n\t/// If GLM_FORCE_DEPTH_ZERO_TO_ONE is defined, the near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t/// Otherwise, the near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFovLH(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Builds a perspective projection matrix based on a field of view and the default handedness and default near and far clip planes definition.\n\t/// To change default handedness use GLM_FORCE_LEFT_HANDED. To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE.\n\t///\n\t/// @param fov Expressed in radians.\n\t/// @param width Width of the viewport\n\t/// @param height Height of the viewport\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param far Specifies the distance from the viewer to the far clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> perspectiveFov(\n\t\tT fov, T width, T height, T near, T far);\n\n\t/// Creates a matrix for a left handed, symmetric perspective-view frustum with far plane at infinite.\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveLH(\n\t\tT fovy, T aspect, T near);\n\n\t/// Creates a matrix for a right handed, symmetric perspective-view frustum with far plane at infinite.\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspectiveRH(\n\t\tT fovy, T aspect, T near);\n\n\t/// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite with default handedness.\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> infinitePerspective(\n\t\tT fovy, T aspect, T near);\n\n\t/// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping.\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective(\n\t\tT fovy, T aspect, T near);\n\n\t/// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping.\n\t///\n\t/// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.\n\t/// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).\n\t/// @param near Specifies the distance from the viewer to the near clipping plane (always positive).\n\t/// @param ep Epsilon\n\t///\n\t/// @tparam T A floating-point scalar type\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> tweakedInfinitePerspective(\n\t\tT fovy, T aspect, T near, T ep);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_clip_space.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_clip_space.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(1));\n\t\tResult[0][0] = static_cast<T>(2) / (right - left);\n\t\tResult[1][1] = static_cast<T>(2) / (top - bottom);\n\t\tResult[2][2] = - static_cast<T>(1);\n\t\tResult[3][0] = - (right + left) / (right - left);\n\t\tResult[3][1] = - (top + bottom) / (top - bottom);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_ZO(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(1);\n\t\tResult[0][0] = static_cast<T>(2) / (right - left);\n\t\tResult[1][1] = static_cast<T>(2) / (top - bottom);\n\t\tResult[2][2] = static_cast<T>(1) / (zFar - zNear);\n\t\tResult[3][0] = - (right + left) / (right - left);\n\t\tResult[3][1] = - (top + bottom) / (top - bottom);\n\t\tResult[3][2] = - zNear / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH_NO(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(1);\n\t\tResult[0][0] = static_cast<T>(2) / (right - left);\n\t\tResult[1][1] = static_cast<T>(2) / (top - bottom);\n\t\tResult[2][2] = static_cast<T>(2) / (zFar - zNear);\n\t\tResult[3][0] = - (right + left) / (right - left);\n\t\tResult[3][1] = - (top + bottom) / (top - bottom);\n\t\tResult[3][2] = - (zFar + zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_ZO(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(1);\n\t\tResult[0][0] = static_cast<T>(2) / (right - left);\n\t\tResult[1][1] = static_cast<T>(2) / (top - bottom);\n\t\tResult[2][2] = - static_cast<T>(1) / (zFar - zNear);\n\t\tResult[3][0] = - (right + left) / (right - left);\n\t\tResult[3][1] = - (top + bottom) / (top - bottom);\n\t\tResult[3][2] = - zNear / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH_NO(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(1);\n\t\tResult[0][0] = static_cast<T>(2) / (right - left);\n\t\tResult[1][1] = static_cast<T>(2) / (top - bottom);\n\t\tResult[2][2] = - static_cast<T>(2) / (zFar - zNear);\n\t\tResult[3][0] = - (right + left) / (right - left);\n\t\tResult[3][1] = - (top + bottom) / (top - bottom);\n\t\tResult[3][2] = - (zFar + zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoZO(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn orthoLH_ZO(left, right, bottom, top, zNear, zFar);\n#\t\telse\n\t\t\treturn orthoRH_ZO(left, right, bottom, top, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoNO(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn orthoLH_NO(left, right, bottom, top, zNear, zFar);\n#\t\telse\n\t\t\treturn orthoRH_NO(left, right, bottom, top, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoLH(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn orthoLH_ZO(left, right, bottom, top, zNear, zFar);\n#\t\telse\n\t\t\treturn orthoLH_NO(left, right, bottom, top, zNear, zFar);\n#\t\tendif\n\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> orthoRH(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn orthoRH_ZO(left, right, bottom, top, zNear, zFar);\n#\t\telse\n\t\t\treturn orthoRH_NO(left, right, bottom, top, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> ortho(T left, T right, T bottom, T top, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO\n\t\t\treturn orthoLH_ZO(left, right, bottom, top, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO\n\t\t\treturn orthoLH_NO(left, right, bottom, top, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO\n\t\t\treturn orthoRH_ZO(left, right, bottom, top, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO\n\t\t\treturn orthoRH_NO(left, right, bottom, top, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(0);\n\t\tResult[0][0] = (static_cast<T>(2) * nearVal) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);\n\t\tResult[2][0] = (right + left) / (right - left);\n\t\tResult[2][1] = (top + bottom) / (top - bottom);\n\t\tResult[2][2] = farVal / (farVal - nearVal);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = -(farVal * nearVal) / (farVal - nearVal);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH_NO(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(0);\n\t\tResult[0][0] = (static_cast<T>(2) * nearVal) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);\n\t\tResult[2][0] = (right + left) / (right - left);\n\t\tResult[2][1] = (top + bottom) / (top - bottom);\n\t\tResult[2][2] = (farVal + nearVal) / (farVal - nearVal);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_ZO(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(0);\n\t\tResult[0][0] = (static_cast<T>(2) * nearVal) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);\n\t\tResult[2][0] = (right + left) / (right - left);\n\t\tResult[2][1] = (top + bottom) / (top - bottom);\n\t\tResult[2][2] = farVal / (nearVal - farVal);\n\t\tResult[2][3] = static_cast<T>(-1);\n\t\tResult[3][2] = -(farVal * nearVal) / (farVal - nearVal);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH_NO(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n\t\tmat<4, 4, T, defaultp> Result(0);\n\t\tResult[0][0] = (static_cast<T>(2) * nearVal) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);\n\t\tResult[2][0] = (right + left) / (right - left);\n\t\tResult[2][1] = (top + bottom) / (top - bottom);\n\t\tResult[2][2] = - (farVal + nearVal) / (farVal - nearVal);\n\t\tResult[2][3] = static_cast<T>(-1);\n\t\tResult[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumZO(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn frustumLH_ZO(left, right, bottom, top, nearVal, farVal);\n#\t\telse\n\t\t\treturn frustumRH_ZO(left, right, bottom, top, nearVal, farVal);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumNO(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn frustumLH_NO(left, right, bottom, top, nearVal, farVal);\n#\t\telse\n\t\t\treturn frustumRH_NO(left, right, bottom, top, nearVal, farVal);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumLH(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn frustumLH_ZO(left, right, bottom, top, nearVal, farVal);\n#\t\telse\n\t\t\treturn frustumLH_NO(left, right, bottom, top, nearVal, farVal);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustumRH(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn frustumRH_ZO(left, right, bottom, top, nearVal, farVal);\n#\t\telse\n\t\t\treturn frustumRH_NO(left, right, bottom, top, nearVal, farVal);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> frustum(T left, T right, T bottom, T top, T nearVal, T farVal)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO\n\t\t\treturn frustumLH_ZO(left, right, bottom, top, nearVal, farVal);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO\n\t\t\treturn frustumLH_NO(left, right, bottom, top, nearVal, farVal);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO\n\t\t\treturn frustumRH_ZO(left, right, bottom, top, nearVal, farVal);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO\n\t\t\treturn frustumRH_NO(left, right, bottom, top, nearVal, farVal);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_ZO(T fovy, T aspect, T zNear, T zFar)\n\t{\n\t\tassert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));\n\n\t\tT const tanHalfFovy = tan(fovy / static_cast<T>(2));\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);\n\t\tResult[1][1] = static_cast<T>(1) / (tanHalfFovy);\n\t\tResult[2][2] = zFar / (zNear - zFar);\n\t\tResult[2][3] = - static_cast<T>(1);\n\t\tResult[3][2] = -(zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH_NO(T fovy, T aspect, T zNear, T zFar)\n\t{\n\t\tassert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));\n\n\t\tT const tanHalfFovy = tan(fovy / static_cast<T>(2));\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);\n\t\tResult[1][1] = static_cast<T>(1) / (tanHalfFovy);\n\t\tResult[2][2] = - (zFar + zNear) / (zFar - zNear);\n\t\tResult[2][3] = - static_cast<T>(1);\n\t\tResult[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_ZO(T fovy, T aspect, T zNear, T zFar)\n\t{\n\t\tassert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));\n\n\t\tT const tanHalfFovy = tan(fovy / static_cast<T>(2));\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);\n\t\tResult[1][1] = static_cast<T>(1) / (tanHalfFovy);\n\t\tResult[2][2] = zFar / (zFar - zNear);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = -(zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH_NO(T fovy, T aspect, T zNear, T zFar)\n\t{\n\t\tassert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));\n\n\t\tT const tanHalfFovy = tan(fovy / static_cast<T>(2));\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);\n\t\tResult[1][1] = static_cast<T>(1) / (tanHalfFovy);\n\t\tResult[2][2] = (zFar + zNear) / (zFar - zNear);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveZO(T fovy, T aspect, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn perspectiveLH_ZO(fovy, aspect, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveRH_ZO(fovy, aspect, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveNO(T fovy, T aspect, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn perspectiveLH_NO(fovy, aspect, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveRH_NO(fovy, aspect, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn perspectiveLH_ZO(fovy, aspect, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveLH_NO(fovy, aspect, zNear, zFar);\n#\t\tendif\n\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn perspectiveRH_ZO(fovy, aspect, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveRH_NO(fovy, aspect, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO\n\t\t\treturn perspectiveLH_ZO(fovy, aspect, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO\n\t\t\treturn perspectiveLH_NO(fovy, aspect, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO\n\t\t\treturn perspectiveRH_ZO(fovy, aspect, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO\n\t\t\treturn perspectiveRH_NO(fovy, aspect, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_ZO(T fov, T width, T height, T zNear, T zFar)\n\t{\n\t\tassert(width > static_cast<T>(0));\n\t\tassert(height > static_cast<T>(0));\n\t\tassert(fov > static_cast<T>(0));\n\n\t\tT const rad = fov;\n\t\tT const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);\n\t\tT const w = h * height / width; ///todo max(width , Height) / min(width , Height)?\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = w;\n\t\tResult[1][1] = h;\n\t\tResult[2][2] = zFar / (zNear - zFar);\n\t\tResult[2][3] = - static_cast<T>(1);\n\t\tResult[3][2] = -(zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH_NO(T fov, T width, T height, T zNear, T zFar)\n\t{\n\t\tassert(width > static_cast<T>(0));\n\t\tassert(height > static_cast<T>(0));\n\t\tassert(fov > static_cast<T>(0));\n\n\t\tT const rad = fov;\n\t\tT const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);\n\t\tT const w = h * height / width; ///todo max(width , Height) / min(width , Height)?\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = w;\n\t\tResult[1][1] = h;\n\t\tResult[2][2] = - (zFar + zNear) / (zFar - zNear);\n\t\tResult[2][3] = - static_cast<T>(1);\n\t\tResult[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_ZO(T fov, T width, T height, T zNear, T zFar)\n\t{\n\t\tassert(width > static_cast<T>(0));\n\t\tassert(height > static_cast<T>(0));\n\t\tassert(fov > static_cast<T>(0));\n\n\t\tT const rad = fov;\n\t\tT const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);\n\t\tT const w = h * height / width; ///todo max(width , Height) / min(width , Height)?\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = w;\n\t\tResult[1][1] = h;\n\t\tResult[2][2] = zFar / (zFar - zNear);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = -(zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH_NO(T fov, T width, T height, T zNear, T zFar)\n\t{\n\t\tassert(width > static_cast<T>(0));\n\t\tassert(height > static_cast<T>(0));\n\t\tassert(fov > static_cast<T>(0));\n\n\t\tT const rad = fov;\n\t\tT const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);\n\t\tT const w = h * height / width; ///todo max(width , Height) / min(width , Height)?\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = w;\n\t\tResult[1][1] = h;\n\t\tResult[2][2] = (zFar + zNear) / (zFar - zNear);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovZO(T fov, T width, T height, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn perspectiveFovLH_ZO(fov, width, height, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveFovRH_ZO(fov, width, height, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovNO(T fov, T width, T height, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn perspectiveFovLH_NO(fov, width, height, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveFovRH_NO(fov, width, height, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn perspectiveFovLH_ZO(fov, width, height, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveFovLH_NO(fov, width, height, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn perspectiveFovRH_ZO(fov, width, height, zNear, zFar);\n#\t\telse\n\t\t\treturn perspectiveFovRH_NO(fov, width, height, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_ZO\n\t\t\treturn perspectiveFovLH_ZO(fov, width, height, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_LH_NO\n\t\t\treturn perspectiveFovLH_NO(fov, width, height, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_ZO\n\t\t\treturn perspectiveFovRH_ZO(fov, width, height, zNear, zFar);\n#\t\telif GLM_CONFIG_CLIP_CONTROL == GLM_CLIP_CONTROL_RH_NO\n\t\t\treturn perspectiveFovRH_NO(fov, width, height, zNear, zFar);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear)\n\t{\n\t\tT const range = tan(fovy / static_cast<T>(2)) * zNear;\n\t\tT const left = -range * aspect;\n\t\tT const right = range * aspect;\n\t\tT const bottom = -range;\n\t\tT const top = range;\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = (static_cast<T>(2) * zNear) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);\n\t\tResult[2][2] = - static_cast<T>(1);\n\t\tResult[2][3] = - static_cast<T>(1);\n\t\tResult[3][2] = - static_cast<T>(2) * zNear;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear)\n\t{\n\t\tT const range = tan(fovy / static_cast<T>(2)) * zNear;\n\t\tT const left = -range * aspect;\n\t\tT const right = range * aspect;\n\t\tT const bottom = -range;\n\t\tT const top = range;\n\n\t\tmat<4, 4, T, defaultp> Result(T(0));\n\t\tResult[0][0] = (static_cast<T>(2) * zNear) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);\n\t\tResult[2][2] = static_cast<T>(1);\n\t\tResult[2][3] = static_cast<T>(1);\n\t\tResult[3][2] = - static_cast<T>(2) * zNear;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> infinitePerspective(T fovy, T aspect, T zNear)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn infinitePerspectiveLH(fovy, aspect, zNear);\n#\t\telse\n\t\t\treturn infinitePerspectiveRH(fovy, aspect, zNear);\n#\t\tendif\n\t}\n\n\t// Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep)\n\t{\n\t\tT const range = tan(fovy / static_cast<T>(2)) * zNear;\n\t\tT const left = -range * aspect;\n\t\tT const right = range * aspect;\n\t\tT const bottom = -range;\n\t\tT const top = range;\n\n\t\tmat<4, 4, T, defaultp> Result(static_cast<T>(0));\n\t\tResult[0][0] = (static_cast<T>(2) * zNear) / (right - left);\n\t\tResult[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);\n\t\tResult[2][2] = ep - static_cast<T>(1);\n\t\tResult[2][3] = static_cast<T>(-1);\n\t\tResult[3][2] = (ep - static_cast<T>(2)) * zNear;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear)\n\t{\n\t\treturn tweakedInfinitePerspective(fovy, aspect, zNear, epsilon<T>());\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_common.hpp",
    "content": "/// @ref ext_matrix_common\n/// @file glm/ext/matrix_common.hpp\n///\n/// @defgroup ext_matrix_common GLM_EXT_matrix_common\n/// @ingroup ext\n///\n/// Defines functions for common matrix operations.\n///\n/// Include <glm/ext/matrix_common.hpp> to use the features of this extension.\n///\n/// @see ext_matrix_common\n\n#pragma once\n\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_fixes.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_transform extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_common\n\t/// @{\n\n\ttemplate<length_t C, length_t R, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL mat<C, R, T, Q> mix(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, mat<C, R, U, Q> const& a);\n\n\ttemplate<length_t C, length_t R, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL mat<C, R, T, Q> mix(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, U a);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_common.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_common.inl",
    "content": "#include \"../matrix.hpp\"\n\nnamespace glm\n{\n\ttemplate<length_t C, length_t R, typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<C, R, T, Q> mix(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, U a)\n\t{\n\t\treturn mat<C, R, U, Q>(x) * (static_cast<U>(1) - a) + mat<C, R, U, Q>(y) * a;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<C, R, T, Q> mix(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, mat<C, R, U, Q> const& a)\n\t{\n\t\treturn matrixCompMult(mat<C, R, U, Q>(x), static_cast<U>(1) - a) + matrixCompMult(mat<C, R, U, Q>(y), a);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double2x2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double2x2.hpp\n\n#pragma once\n#include \"../detail/type_mat2x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 2, double, defaultp>\t\tdmat2x2;\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 2, double, defaultp>\t\tdmat2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double2x2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double2x2_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, double, lowp>\t\tlowp_dmat2;\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, double, mediump>\tmediump_dmat2;\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, double, highp>\thighp_dmat2;\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, double, lowp>\t\tlowp_dmat2x2;\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, double, mediump>\tmediump_dmat2x2;\n\n\t/// 2 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, double, highp>\thighp_dmat2x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double2x3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double2x3.hpp\n\n#pragma once\n#include \"../detail/type_mat2x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 2 columns of 3 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 3, double, defaultp>\t\tdmat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double2x3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double2x3_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 2 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 3, double, lowp>\t\tlowp_dmat2x3;\n\n\t/// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 3, double, mediump>\tmediump_dmat2x3;\n\n\t/// 2 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 3, double, highp>\thighp_dmat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double2x4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double2x4.hpp\n\n#pragma once\n#include \"../detail/type_mat2x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 2 columns of 4 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 4, double, defaultp>\t\tdmat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double2x4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double2x4_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 2 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 4, double, lowp>\t\tlowp_dmat2x4;\n\n\t/// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 4, double, mediump>\tmediump_dmat2x4;\n\n\t/// 2 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 4, double, highp>\thighp_dmat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double3x2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double3x2.hpp\n\n#pragma once\n#include \"../detail/type_mat3x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 3 columns of 2 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 2, double, defaultp>\t\tdmat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double3x2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double3x2_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat3x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 3 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 2, double, lowp>\t\tlowp_dmat3x2;\n\n\t/// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 2, double, mediump>\tmediump_dmat3x2;\n\n\t/// 3 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 2, double, highp>\thighp_dmat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double3x3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double3x3.hpp\n\n#pragma once\n#include \"../detail/type_mat3x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 3, double, defaultp>\t\tdmat3x3;\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 3, double, defaultp>\t\tdmat3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double3x3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double3x3_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat3x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, double, lowp>\t\tlowp_dmat3;\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, double, mediump>\tmediump_dmat3;\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, double, highp>\thighp_dmat3;\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, double, lowp>\t\tlowp_dmat3x3;\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, double, mediump>\tmediump_dmat3x3;\n\n\t/// 3 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, double, highp>\thighp_dmat3x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double3x4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double3x4.hpp\n\n#pragma once\n#include \"../detail/type_mat3x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 3 columns of 4 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 4, double, defaultp>\t\tdmat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double3x4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double3x4_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat3x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 3 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 4, double, lowp>\t\tlowp_dmat3x4;\n\n\t/// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 4, double, mediump>\tmediump_dmat3x4;\n\n\t/// 3 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 4, double, highp>\thighp_dmat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double4x2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double4x2.hpp\n\n#pragma once\n#include \"../detail/type_mat4x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 4 columns of 2 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 2, double, defaultp>\t\tdmat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double4x2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double4x2_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat4x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 4 columns of 2 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 2, double, lowp>\t\tlowp_dmat4x2;\n\n\t/// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 2, double, mediump>\tmediump_dmat4x2;\n\n\t/// 4 columns of 2 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 2, double, highp>\thighp_dmat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double4x3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double4x3.hpp\n\n#pragma once\n#include \"../detail/type_mat4x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 4 columns of 3 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 3, double, defaultp>\t\tdmat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double4x3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double4x3_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat4x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 4 columns of 3 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 3, double, lowp>\t\tlowp_dmat4x3;\n\n\t/// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 3, double, mediump>\tmediump_dmat4x3;\n\n\t/// 4 columns of 3 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 3, double, highp>\thighp_dmat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double4x4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double4x4.hpp\n\n#pragma once\n#include \"../detail/type_mat4x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 4, double, defaultp>\t\tdmat4x4;\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 4, double, defaultp>\t\tdmat4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_double4x4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_double4x4_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat4x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, double, lowp>\t\tlowp_dmat4;\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, double, mediump>\tmediump_dmat4;\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, double, highp>\thighp_dmat4;\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, double, lowp>\t\tlowp_dmat4x4;\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, double, mediump>\tmediump_dmat4x4;\n\n\t/// 4 columns of 4 components matrix of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, double, highp>\thighp_dmat4x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float2x2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x2.hpp\n\n#pragma once\n#include \"../detail/type_mat2x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 2, float, defaultp>\t\tmat2x2;\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 2, float, defaultp>\t\tmat2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float2x2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x2_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, float, lowp>\t\tlowp_mat2;\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, float, mediump>\tmediump_mat2;\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, float, highp>\t\thighp_mat2;\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, float, lowp>\t\tlowp_mat2x2;\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, float, mediump>\tmediump_mat2x2;\n\n\t/// 2 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 2, float, highp>\t\thighp_mat2x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float2x3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x3.hpp\n\n#pragma once\n#include \"../detail/type_mat2x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 2 columns of 3 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 3, float, defaultp>\t\tmat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float2x3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x3_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 2 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 3, float, lowp>\t\tlowp_mat2x3;\n\n\t/// 2 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 3, float, mediump>\tmediump_mat2x3;\n\n\t/// 2 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 3, float, highp>\t\thighp_mat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float2x4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x4.hpp\n\n#pragma once\n#include \"../detail/type_mat2x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 2 columns of 4 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<2, 4, float, defaultp>\t\tmat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float2x4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x4_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 2 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 4, float, lowp>\t\tlowp_mat2x4;\n\n\t/// 2 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 4, float, mediump>\tmediump_mat2x4;\n\n\t/// 2 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<2, 4, float, highp>\t\thighp_mat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float3x2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float3x2.hpp\n\n#pragma once\n#include \"../detail/type_mat3x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core\n\t/// @{\n\n\t/// 3 columns of 2 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 2, float, defaultp>\t\t\tmat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float3x2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float3x2_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat3x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 3 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 2, float, lowp>\t\tlowp_mat3x2;\n\n\t/// 3 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 2, float, mediump>\tmediump_mat3x2;\n\n\t/// 3 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 2, float, highp>\t\thighp_mat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float3x3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float3x3.hpp\n\n#pragma once\n#include \"../detail/type_mat3x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 3, float, defaultp>\t\t\tmat3x3;\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 3, float, defaultp>\t\t\tmat3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float3x3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float3x3_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat3x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, float, lowp>\t\tlowp_mat3;\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, float, mediump>\tmediump_mat3;\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, float, highp>\t\thighp_mat3;\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, float, lowp>\t\tlowp_mat3x3;\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, float, mediump>\tmediump_mat3x3;\n\n\t/// 3 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 3, float, highp>\t\thighp_mat3x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float3x4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float3x4.hpp\n\n#pragma once\n#include \"../detail/type_mat3x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 3 columns of 4 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<3, 4, float, defaultp>\t\t\tmat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float3x4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float3x4_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat3x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 3 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 4, float, lowp>\t\tlowp_mat3x4;\n\n\t/// 3 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 4, float, mediump>\tmediump_mat3x4;\n\n\t/// 3 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<3, 4, float, highp>\t\thighp_mat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float4x2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float4x2.hpp\n\n#pragma once\n#include \"../detail/type_mat4x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 4 columns of 2 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 2, float, defaultp>\t\t\tmat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float4x2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float2x2_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat2x2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 4 columns of 2 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 2, float, lowp>\t\tlowp_mat4x2;\n\n\t/// 4 columns of 2 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 2, float, mediump>\tmediump_mat4x2;\n\n\t/// 4 columns of 2 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 2, float, highp>\t\thighp_mat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float4x3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float4x3.hpp\n\n#pragma once\n#include \"../detail/type_mat4x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix\n\t/// @{\n\n\t/// 4 columns of 3 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 3, float, defaultp>\t\t\tmat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float4x3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float4x3_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat4x3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 4 columns of 3 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 3, float, lowp>\t\tlowp_mat4x3;\n\n\t/// 4 columns of 3 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 3, float, mediump>\tmediump_mat4x3;\n\n\t/// 4 columns of 3 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 3, float, highp>\t\thighp_mat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float4x4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float4x4.hpp\n\n#pragma once\n#include \"../detail/type_mat4x4.hpp\"\n\nnamespace glm\n{\n\t/// @ingroup core_matrix\n\t/// @{\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 4, float, defaultp>\t\t\tmat4x4;\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\ttypedef mat<4, 4, float, defaultp>\t\t\tmat4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_float4x4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/matrix_float4x4_precision.hpp\n\n#pragma once\n#include \"../detail/type_mat4x4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_matrix_precision\n\t/// @{\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, float, lowp>\t\tlowp_mat4;\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, float, mediump>\tmediump_mat4;\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, float, highp>\t\thighp_mat4;\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, float, lowp>\t\tlowp_mat4x4;\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, float, mediump>\tmediump_mat4x4;\n\n\t/// 4 columns of 4 components matrix of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef mat<4, 4, float, highp>\t\thighp_mat4x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int2x2.hpp",
    "content": "/// @ref ext_matrix_int2x2\n/// @file glm/ext/matrix_int2x2.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x2 GLM_EXT_matrix_int2x2\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int2x2.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int2x2 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int2x2\n\t/// @{\n\n\t/// Signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2\n\ttypedef mat<2, 2, int, defaultp>\timat2x2;\n\n\t/// Signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2\n\ttypedef mat<2, 2, int, defaultp>\timat2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int2x2_sized.hpp",
    "content": "/// @ref ext_matrix_int2x2_sized\n/// @file glm/ext/matrix_int2x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x2_sized GLM_EXT_matrix_int2x2_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int2x2_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x2.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int2x2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int2x2_sized\n\t/// @{\n\n\t/// 8 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int8, defaultp>\t\t\t\ti8mat2x2;\n\n\t/// 16 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int16, defaultp>\t\t\t\ti16mat2x2;\n\n\t/// 32 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int32, defaultp>\t\t\t\ti32mat2x2;\n\n\t/// 64 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int64, defaultp>\t\t\t\ti64mat2x2;\n\n\n\t/// 8 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int8, defaultp>\t\t\t\ti8mat2;\n\n\t/// 16 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int16, defaultp>\t\t\t\ti16mat2;\n\n\t/// 32 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int32, defaultp>\t\t\t\ti32mat2;\n\n\t/// 64 bit signed integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_int2x2_sized\n\ttypedef mat<2, 2, int64, defaultp>\t\t\t\ti64mat2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int2x3.hpp",
    "content": "/// @ref ext_matrix_int2x3\n/// @file glm/ext/matrix_int2x3.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x3 GLM_EXT_matrix_int2x3\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int2x3.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x3.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int2x3 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int2x3\n\t/// @{\n\n\t/// Signed integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_int2x3\n\ttypedef mat<2, 3, int, defaultp>\timat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int2x3_sized.hpp",
    "content": "/// @ref ext_matrix_int2x3_sized\n/// @file glm/ext/matrix_int2x3_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x3_sized GLM_EXT_matrix_int2x3_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int2x3_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x3.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int2x3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int2x3_sized\n\t/// @{\n\n\t/// 8 bit signed integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_int2x3_sized\n\ttypedef mat<2, 3, int8, defaultp>\t\t\t\ti8mat2x3;\n\n\t/// 16 bit signed integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_int2x3_sized\n\ttypedef mat<2, 3, int16, defaultp>\t\t\t\ti16mat2x3;\n\n\t/// 32 bit signed integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_int2x3_sized\n\ttypedef mat<2, 3, int32, defaultp>\t\t\t\ti32mat2x3;\n\n\t/// 64 bit signed integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_int2x3_sized\n\ttypedef mat<2, 3, int64, defaultp>\t\t\t\ti64mat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int2x4.hpp",
    "content": "/// @ref ext_matrix_int2x4\n/// @file glm/ext/matrix_int2x4.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x4 GLM_EXT_matrix_int2x4\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int2x4.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int2x4 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int2x4\n\t/// @{\n\n\t/// Signed integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_int2x4\n\ttypedef mat<2, 4, int, defaultp>\timat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int2x4_sized.hpp",
    "content": "/// @ref ext_matrix_int2x4_sized\n/// @file glm/ext/matrix_int2x4_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x4_sized GLM_EXT_matrix_int2x4_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int2x4_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x4.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int2x4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int2x4_sized\n\t/// @{\n\n\t/// 8 bit signed integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_int2x4_sized\n\ttypedef mat<2, 4, int8, defaultp>\t\t\t\ti8mat2x4;\n\n\t/// 16 bit signed integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_int2x4_sized\n\ttypedef mat<2, 4, int16, defaultp>\t\t\t\ti16mat2x4;\n\n\t/// 32 bit signed integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_int2x4_sized\n\ttypedef mat<2, 4, int32, defaultp>\t\t\t\ti32mat2x4;\n\n\t/// 64 bit signed integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_int2x4_sized\n\ttypedef mat<2, 4, int64, defaultp>\t\t\t\ti64mat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int3x2.hpp",
    "content": "/// @ref ext_matrix_int3x2\n/// @file glm/ext/matrix_int3x2.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x2 GLM_EXT_matrix_int3x2\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int3x2.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int3x2 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int3x2\n\t/// @{\n\n\t/// Signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_int3x2\n\ttypedef mat<3, 2, int, defaultp>\timat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int3x2_sized.hpp",
    "content": "/// @ref ext_matrix_int3x2_sized\n/// @file glm/ext/matrix_int3x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x2_sized GLM_EXT_matrix_int3x2_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int3x2_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x2.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int3x2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int3x2_sized\n\t/// @{\n\n\t/// 8 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_int3x2_sized\n\ttypedef mat<3, 2, int8, defaultp>\t\t\t\ti8mat3x2;\n\n\t/// 16 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_int3x2_sized\n\ttypedef mat<3, 2, int16, defaultp>\t\t\t\ti16mat3x2;\n\n\t/// 32 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_int3x2_sized\n\ttypedef mat<3, 2, int32, defaultp>\t\t\t\ti32mat3x2;\n\n\t/// 64 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_int3x2_sized\n\ttypedef mat<3, 2, int64, defaultp>\t\t\t\ti64mat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int3x3.hpp",
    "content": "/// @ref ext_matrix_int3x3\n/// @file glm/ext/matrix_int3x3.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x3 GLM_EXT_matrix_int3x3\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int3x3.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x3.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int3x3 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int3x3\n\t/// @{\n\n\t/// Signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3\n\ttypedef mat<3, 3, int, defaultp>\timat3x3;\n\n\t/// Signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3\n\ttypedef mat<3, 3, int, defaultp>\timat3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int3x3_sized.hpp",
    "content": "/// @ref ext_matrix_int3x3_sized\n/// @file glm/ext/matrix_int3x3_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x3_sized GLM_EXT_matrix_int3x3_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int3x3_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x3.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int3x3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int3x3_sized\n\t/// @{\n\n\t/// 8 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int8, defaultp>\t\t\t\ti8mat3x3;\n\n\t/// 16 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int16, defaultp>\t\t\t\ti16mat3x3;\n\n\t/// 32 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int32, defaultp>\t\t\t\ti32mat3x3;\n\n\t/// 64 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int64, defaultp>\t\t\t\ti64mat3x3;\n\n\n\t/// 8 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int8, defaultp>\t\t\t\ti8mat3;\n\n\t/// 16 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int16, defaultp>\t\t\t\ti16mat3;\n\n\t/// 32 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int32, defaultp>\t\t\t\ti32mat3;\n\n\t/// 64 bit signed integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_int3x3_sized\n\ttypedef mat<3, 3, int64, defaultp>\t\t\t\ti64mat3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int3x4.hpp",
    "content": "/// @ref ext_matrix_int3x4\n/// @file glm/ext/matrix_int3x4.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x4 GLM_EXT_matrix_int3x4\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int3x4.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int3x4 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int3x4\n\t/// @{\n\n\t/// Signed integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_int3x4\n\ttypedef mat<3, 4, int, defaultp>\timat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int3x4_sized.hpp",
    "content": "/// @ref ext_matrix_int3x4_sized\n/// @file glm/ext/matrix_int3x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x4_sized GLM_EXT_matrix_int3x4_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int3x4_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x4.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int3x4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int3x4_sized\n\t/// @{\n\n\t/// 8 bit signed integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_int3x4_sized\n\ttypedef mat<3, 4, int8, defaultp>\t\t\t\ti8mat3x4;\n\n\t/// 16 bit signed integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_int3x4_sized\n\ttypedef mat<3, 4, int16, defaultp>\t\t\t\ti16mat3x4;\n\n\t/// 32 bit signed integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_int3x4_sized\n\ttypedef mat<3, 4, int32, defaultp>\t\t\t\ti32mat3x4;\n\n\t/// 64 bit signed integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_int3x4_sized\n\ttypedef mat<3, 4, int64, defaultp>\t\t\t\ti64mat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int4x2.hpp",
    "content": "/// @ref ext_matrix_int4x2\n/// @file glm/ext/matrix_int4x2.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int4x2 GLM_EXT_matrix_int4x2\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int4x2.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int4x2 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int4x2\n\t/// @{\n\n\t/// Signed integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_int4x2\n\ttypedef mat<4, 2, int, defaultp>\timat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int4x2_sized.hpp",
    "content": "/// @ref ext_matrix_int4x2_sized\n/// @file glm/ext/matrix_int4x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int4x2_sized GLM_EXT_matrix_int4x2_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int4x2_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x2.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int4x2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int4x2_sized\n\t/// @{\n\n\t/// 8 bit signed integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_int4x2_sized\n\ttypedef mat<4, 2, int8, defaultp>\t\t\t\ti8mat4x2;\n\n\t/// 16 bit signed integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_int4x2_sized\n\ttypedef mat<4, 2, int16, defaultp>\t\t\t\ti16mat4x2;\n\n\t/// 32 bit signed integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_int4x2_sized\n\ttypedef mat<4, 2, int32, defaultp>\t\t\t\ti32mat4x2;\n\n\t/// 64 bit signed integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_int4x2_sized\n\ttypedef mat<4, 2, int64, defaultp>\t\t\t\ti64mat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int4x3.hpp",
    "content": "/// @ref ext_matrix_int4x3\n/// @file glm/ext/matrix_int4x3.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int4x3 GLM_EXT_matrix_int4x3\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int4x3.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x3.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int4x3 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int4x3\n\t/// @{\n\n\t/// Signed integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_int4x3\n\ttypedef mat<4, 3, int, defaultp>\timat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int4x3_sized.hpp",
    "content": "/// @ref ext_matrix_int4x3_sized\n/// @file glm/ext/matrix_int4x3_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int4x3_sized GLM_EXT_matrix_int4x3_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int4x3_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x3.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int4x3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int4x3_sized\n\t/// @{\n\n\t/// 8 bit signed integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_int4x3_sized\n\ttypedef mat<4, 3, int8, defaultp>\t\t\t\ti8mat4x3;\n\n\t/// 16 bit signed integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_int4x3_sized\n\ttypedef mat<4, 3, int16, defaultp>\t\t\t\ti16mat4x3;\n\n\t/// 32 bit signed integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_int4x3_sized\n\ttypedef mat<4, 3, int32, defaultp>\t\t\t\ti32mat4x3;\n\n\t/// 64 bit signed integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_int4x3_sized\n\ttypedef mat<4, 3, int64, defaultp>\t\t\t\ti64mat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int4x4.hpp",
    "content": "/// @ref ext_matrix_int4x4\n/// @file glm/ext/matrix_int4x4.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int4x4 GLM_EXT_matrix_int4x4\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int4x4.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int4x4 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int4x4\n\t/// @{\n\n\t/// Signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4\n\ttypedef mat<4, 4, int, defaultp>\timat4x4;\n\n\t/// Signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4\n\ttypedef mat<4, 4, int, defaultp>\timat4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_int4x4_sized.hpp",
    "content": "/// @ref ext_matrix_int4x4_sized\n/// @file glm/ext/matrix_int4x4_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int4x4_sized GLM_EXT_matrix_int4x4_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_int4x4_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x4.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_int4x4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_int4x4_sized\n\t/// @{\n\n\t/// 8 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int8, defaultp>\t\t\t\ti8mat4x4;\n\n\t/// 16 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int16, defaultp>\t\t\t\ti16mat4x4;\n\n\t/// 32 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int32, defaultp>\t\t\t\ti32mat4x4;\n\n\t/// 64 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int64, defaultp>\t\t\t\ti64mat4x4;\n\n\n\t/// 8 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int8, defaultp>\t\t\t\ti8mat4;\n\n\t/// 16 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int16, defaultp>\t\t\t\ti16mat4;\n\n\t/// 32 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int32, defaultp>\t\t\t\ti32mat4;\n\n\t/// 64 bit signed integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_int4x4_sized\n\ttypedef mat<4, 4, int64, defaultp>\t\t\t\ti64mat4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_projection.hpp",
    "content": "/// @ref ext_matrix_projection\n/// @file glm/ext/matrix_projection.hpp\n///\n/// @defgroup ext_matrix_projection GLM_EXT_matrix_projection\n/// @ingroup ext\n///\n/// Functions that generate common projection transformation matrices.\n///\n/// The matrices generated by this extension use standard OpenGL fixed-function\n/// conventions. For example, the lookAt function generates a transform from world\n/// space into the specific eye space that the projective matrix functions\n/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility\n/// specifications defines the particular layout of this eye space.\n///\n/// Include <glm/ext/matrix_projection.hpp> to use the features of this extension.\n///\n/// @see ext_matrix_transform\n/// @see ext_matrix_clip_space\n\n#pragma once\n\n// Dependencies\n#include \"../gtc/constants.hpp\"\n#include \"../geometric.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../matrix.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_projection extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_projection\n\t/// @{\n\n\t/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param obj Specify the object coordinates.\n\t/// @param model Specifies the current modelview matrix\n\t/// @param proj Specifies the current projection matrix\n\t/// @param viewport Specifies the current viewport\n\t/// @return Return the computed window coordinates.\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluProject.xml\">gluProject man page</a>\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> projectZO(\n\t\tvec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport);\n\n\t/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param obj Specify the object coordinates.\n\t/// @param model Specifies the current modelview matrix\n\t/// @param proj Specifies the current projection matrix\n\t/// @param viewport Specifies the current viewport\n\t/// @return Return the computed window coordinates.\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluProject.xml\">gluProject man page</a>\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> projectNO(\n\t\tvec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport);\n\n\t/// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates using default near and far clip planes definition.\n\t/// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE.\n\t///\n\t/// @param obj Specify the object coordinates.\n\t/// @param model Specifies the current modelview matrix\n\t/// @param proj Specifies the current projection matrix\n\t/// @param viewport Specifies the current viewport\n\t/// @return Return the computed window coordinates.\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluProject.xml\">gluProject man page</a>\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> project(\n\t\tvec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport);\n\n\t/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of 0 and +1 respectively. (Direct3D clip volume definition)\n\t///\n\t/// @param win Specify the window coordinates to be mapped.\n\t/// @param model Specifies the modelview matrix\n\t/// @param proj Specifies the projection matrix\n\t/// @param viewport Specifies the viewport\n\t/// @return Returns the computed object coordinates.\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluUnProject.xml\">gluUnProject man page</a>\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> unProjectZO(\n\t\tvec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport);\n\n\t/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.\n\t/// The near and far clip planes correspond to z normalized device coordinates of -1 and +1 respectively. (OpenGL clip volume definition)\n\t///\n\t/// @param win Specify the window coordinates to be mapped.\n\t/// @param model Specifies the modelview matrix\n\t/// @param proj Specifies the projection matrix\n\t/// @param viewport Specifies the viewport\n\t/// @return Returns the computed object coordinates.\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluUnProject.xml\">gluUnProject man page</a>\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> unProjectNO(\n\t\tvec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport);\n\n\t/// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates using default near and far clip planes definition.\n\t/// To change default near and far clip planes definition use GLM_FORCE_DEPTH_ZERO_TO_ONE.\n\t///\n\t/// @param win Specify the window coordinates to be mapped.\n\t/// @param model Specifies the modelview matrix\n\t/// @param proj Specifies the projection matrix\n\t/// @param viewport Specifies the viewport\n\t/// @return Returns the computed object coordinates.\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluUnProject.xml\">gluUnProject man page</a>\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> unProject(\n\t\tvec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport);\n\n\t/// Define a picking region\n\t///\n\t/// @param center Specify the center of a picking region in window coordinates.\n\t/// @param delta Specify the width and height, respectively, of the picking region in window coordinates.\n\t/// @param viewport Rendering viewport\n\t/// @tparam T Native type used for the computation. Currently supported: half (not recommended), float or double.\n\t/// @tparam U Currently supported: Floating-point types and integer types.\n\t///\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPickMatrix.xml\">gluPickMatrix man page</a>\n\ttemplate<typename T, qualifier Q, typename U>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> pickMatrix(\n\t\tvec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_projection.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_projection.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> projectZO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)\n\t{\n\t\tvec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast<T>(1));\n\t\ttmp = model * tmp;\n\t\ttmp = proj * tmp;\n\n\t\ttmp /= tmp.w;\n\t\ttmp.x = tmp.x * static_cast<T>(0.5) + static_cast<T>(0.5);\n\t\ttmp.y = tmp.y * static_cast<T>(0.5) + static_cast<T>(0.5);\n\n\t\ttmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]);\n\t\ttmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]);\n\n\t\treturn vec<3, T, Q>(tmp);\n\t}\n\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> projectNO(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)\n\t{\n\t\tvec<4, T, Q> tmp = vec<4, T, Q>(obj, static_cast<T>(1));\n\t\ttmp = model * tmp;\n\t\ttmp = proj * tmp;\n\n\t\ttmp /= tmp.w;\n\t\ttmp = tmp * static_cast<T>(0.5) + static_cast<T>(0.5);\n\t\ttmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]);\n\t\ttmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]);\n\n\t\treturn vec<3, T, Q>(tmp);\n\t}\n\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> project(vec<3, T, Q> const& obj, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn projectZO(obj, model, proj, viewport);\n#\t\telse\n\t\t\treturn projectNO(obj, model, proj, viewport);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> unProjectZO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)\n\t{\n\t\tmat<4, 4, T, Q> Inverse = inverse(proj * model);\n\n\t\tvec<4, T, Q> tmp = vec<4, T, Q>(win, T(1));\n\t\ttmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]);\n\t\ttmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]);\n\t\ttmp.x = tmp.x * static_cast<T>(2) - static_cast<T>(1);\n\t\ttmp.y = tmp.y * static_cast<T>(2) - static_cast<T>(1);\n\n\t\tvec<4, T, Q> obj = Inverse * tmp;\n\t\tobj /= obj.w;\n\n\t\treturn vec<3, T, Q>(obj);\n\t}\n\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> unProjectNO(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)\n\t{\n\t\tmat<4, 4, T, Q> Inverse = inverse(proj * model);\n\n\t\tvec<4, T, Q> tmp = vec<4, T, Q>(win, T(1));\n\t\ttmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]);\n\t\ttmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]);\n\t\ttmp = tmp * static_cast<T>(2) - static_cast<T>(1);\n\n\t\tvec<4, T, Q> obj = Inverse * tmp;\n\t\tobj /= obj.w;\n\n\t\treturn vec<3, T, Q>(obj);\n\t}\n\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> unProject(vec<3, T, Q> const& win, mat<4, 4, T, Q> const& model, mat<4, 4, T, Q> const& proj, vec<4, U, Q> const& viewport)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_ZO_BIT\n\t\t\treturn unProjectZO(win, model, proj, viewport);\n#\t\telse\n\t\t\treturn unProjectNO(win, model, proj, viewport);\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q, typename U>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> pickMatrix(vec<2, T, Q> const& center, vec<2, T, Q> const& delta, vec<4, U, Q> const& viewport)\n\t{\n\t\tassert(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0));\n\t\tmat<4, 4, T, Q> Result(static_cast<T>(1));\n\n\t\tif(!(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0)))\n\t\t\treturn Result; // Error\n\n\t\tvec<3, T, Q> Temp(\n\t\t\t(static_cast<T>(viewport[2]) - static_cast<T>(2) * (center.x - static_cast<T>(viewport[0]))) / delta.x,\n\t\t\t(static_cast<T>(viewport[3]) - static_cast<T>(2) * (center.y - static_cast<T>(viewport[1]))) / delta.y,\n\t\t\tstatic_cast<T>(0));\n\n\t\t// Translate and scale the picked region to the entire window\n\t\tResult = translate(Result, Temp);\n\t\treturn scale(Result, vec<3, T, Q>(static_cast<T>(viewport[2]) / delta.x, static_cast<T>(viewport[3]) / delta.y, static_cast<T>(1)));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_relational.hpp",
    "content": "/// @ref ext_matrix_relational\n/// @file glm/ext/matrix_relational.hpp\n///\n/// @defgroup ext_matrix_relational GLM_EXT_matrix_relational\n/// @ingroup ext\n///\n/// Exposes comparison functions for matrix types that take a user defined epsilon values.\n///\n/// Include <glm/ext/matrix_relational.hpp> to use the features of this extension.\n///\n/// @see ext_vector_relational\n/// @see ext_scalar_relational\n/// @see ext_quaternion_relational\n\n#pragma once\n\n// Dependencies\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_relational extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_relational\n\t/// @{\n\n\t/// Perform a component-wise equal-to comparison of two matrices.\n\t/// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y);\n\n\t/// Perform a component-wise not-equal-to comparison of two matrices.\n\t/// Return a boolean vector which components value is True if this expression is satisfied per column of the matrices.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, T epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, vec<C, T, Q> const& epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, T epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| >= epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, vec<C, T, Q> const& epsilon);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, int ULPs);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, vec<C, int, Q> const& ULPs);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, int ULPs);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number of columns of the matrix\n\t/// @tparam R Integer between 1 and 4 included that qualify the number of rows of the matrix\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, vec<C, int, Q> const& ULPs);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_relational.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_relational.inl",
    "content": "/// @ref ext_vector_relational\n/// @file glm/ext/vector_relational.inl\n\n// Dependency:\n#include \"../ext/vector_relational.hpp\"\n#include \"../common.hpp\"\n\nnamespace glm\n{\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b)\n\t{\n\t\treturn equal(a, b, static_cast<T>(0));\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b, T Epsilon)\n\t{\n\t\treturn equal(a, b, vec<C, T, Q>(Epsilon));\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b, vec<C, T, Q> const& Epsilon)\n\t{\n\t\tvec<C, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < C; ++i)\n\t\t\tResult[i] = all(equal(a[i], b[i], Epsilon[i]));\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y)\n\t{\n\t\treturn notEqual(x, y, static_cast<T>(0));\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, T Epsilon)\n\t{\n\t\treturn notEqual(x, y, vec<C, T, Q>(Epsilon));\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b, vec<C, T, Q> const& Epsilon)\n\t{\n\t\tvec<C, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < C; ++i)\n\t\t\tResult[i] = any(notEqual(a[i], b[i], Epsilon[i]));\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b, int MaxULPs)\n\t{\n\t\treturn equal(a, b, vec<C, int, Q>(MaxULPs));\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> equal(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b, vec<C, int, Q> const& MaxULPs)\n\t{\n\t\tvec<C, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < C; ++i)\n\t\t\tResult[i] = all(equal(a[i], b[i], MaxULPs[i]));\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y, int MaxULPs)\n\t{\n\t\treturn notEqual(x, y, vec<C, int, Q>(MaxULPs));\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<C, bool, Q> notEqual(mat<C, R, T, Q> const& a, mat<C, R, T, Q> const& b, vec<C, int, Q> const& MaxULPs)\n\t{\n\t\tvec<C, bool, Q> Result(true);\n\t\tfor(length_t i = 0; i < C; ++i)\n\t\t\tResult[i] = any(notEqual(a[i], b[i], MaxULPs[i]));\n\t\treturn Result;\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_transform.hpp",
    "content": "/// @ref ext_matrix_transform\n/// @file glm/ext/matrix_transform.hpp\n///\n/// @defgroup ext_matrix_transform GLM_EXT_matrix_transform\n/// @ingroup ext\n///\n/// Defines functions that generate common transformation matrices.\n///\n/// The matrices generated by this extension use standard OpenGL fixed-function\n/// conventions. For example, the lookAt function generates a transform from world\n/// space into the specific eye space that the projective matrix functions\n/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility\n/// specifications defines the particular layout of this eye space.\n///\n/// Include <glm/ext/matrix_transform.hpp> to use the features of this extension.\n///\n/// @see ext_matrix_projection\n/// @see ext_matrix_clip_space\n\n#pragma once\n\n// Dependencies\n#include \"../gtc/constants.hpp\"\n#include \"../geometric.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../matrix.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_transform extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_transform\n\t/// @{\n\n\t/// Builds an identity matrix.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType identity();\n\n\t/// Builds a translation 4 * 4 matrix created from a vector of 3 components.\n\t///\n\t/// @param m Input matrix multiplied by this translation matrix.\n\t/// @param v Coordinates of a translation vector.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @code\n\t/// #include <glm/glm.hpp>\n\t/// #include <glm/gtc/matrix_transform.hpp>\n\t/// ...\n\t/// glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f));\n\t/// // m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f\n\t/// // m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f\n\t/// // m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f\n\t/// // m[3][0] == 1.0f, m[3][1] == 1.0f, m[3][2] == 1.0f, m[3][3] == 1.0f\n\t/// @endcode\n\t///\n\t/// @see - translate(mat<4, 4, T, Q> const& m, T x, T y, T z)\n\t/// @see - translate(vec<3, T, Q> const& v)\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml\">glTranslate man page</a>\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> translate(\n\t\tmat<4, 4, T, Q> const& m, vec<3, T, Q> const& v);\n\n\t/// Builds a rotation 4 * 4 matrix created from an axis vector and an angle.\n\t///\n\t/// @param m Input matrix multiplied by this rotation matrix.\n\t/// @param angle Rotation angle expressed in radians.\n\t/// @param axis Rotation axis, recommended to be normalized.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z)\n\t/// @see - rotate(T angle, vec<3, T, Q> const& v)\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml\">glRotate man page</a>\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> rotate(\n\t\tmat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& axis);\n\n\t/// Builds a scale 4 * 4 matrix created from 3 scalars.\n\t///\n\t/// @param m Input matrix multiplied by this scale matrix.\n\t/// @param v Ratio of scaling for each axis.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @see - scale(mat<4, 4, T, Q> const& m, T x, T y, T z)\n\t/// @see - scale(vec<3, T, Q> const& v)\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glScale.xml\">glScale man page</a>\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> scale(\n\t\tmat<4, 4, T, Q> const& m, vec<3, T, Q> const& v);\n\n\t/// Build a right handed look at view matrix.\n\t///\n\t/// @param eye Position of the camera\n\t/// @param center Position where the camera is looking at\n\t/// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal)\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> lookAtRH(\n\t\tvec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up);\n\n\t/// Build a left handed look at view matrix.\n\t///\n\t/// @param eye Position of the camera\n\t/// @param center Position where the camera is looking at\n\t/// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal)\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> lookAtLH(\n\t\tvec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up);\n\n\t/// Build a look at view matrix based on the default handedness.\n\t///\n\t/// @param eye Position of the camera\n\t/// @param center Position where the camera is looking at\n\t/// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1)\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @see - frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal) frustum(T const& left, T const& right, T const& bottom, T const& top, T const& nearVal, T const& farVal)\n\t/// @see <a href=\"https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluLookAt.xml\">gluLookAt man page</a>\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> lookAt(\n\t\tvec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_transform.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_transform.inl",
    "content": "namespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType identity()\n\t{\n\t\treturn detail::init_gentype<genType, detail::genTypeTrait<genType>::GENTYPE>::identity();\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)\n\t{\n\t\tmat<4, 4, T, Q> Result(m);\n\t\tResult[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v)\n\t{\n\t\tT const a = angle;\n\t\tT const c = cos(a);\n\t\tT const s = sin(a);\n\n\t\tvec<3, T, Q> axis(normalize(v));\n\t\tvec<3, T, Q> temp((T(1) - c) * axis);\n\n\t\tmat<4, 4, T, Q> Rotate;\n\t\tRotate[0][0] = c + temp[0] * axis[0];\n\t\tRotate[0][1] = temp[0] * axis[1] + s * axis[2];\n\t\tRotate[0][2] = temp[0] * axis[2] - s * axis[1];\n\n\t\tRotate[1][0] = temp[1] * axis[0] - s * axis[2];\n\t\tRotate[1][1] = c + temp[1] * axis[1];\n\t\tRotate[1][2] = temp[1] * axis[2] + s * axis[0];\n\n\t\tRotate[2][0] = temp[2] * axis[0] + s * axis[1];\n\t\tRotate[2][1] = temp[2] * axis[1] - s * axis[0];\n\t\tRotate[2][2] = c + temp[2] * axis[2];\n\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];\n\t\tResult[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];\n\t\tResult[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];\n\t\tResult[3] = m[3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate_slow(mat<4, 4, T, Q> const& m, T angle, vec<3, T, Q> const& v)\n\t{\n\t\tT const a = angle;\n\t\tT const c = cos(a);\n\t\tT const s = sin(a);\n\t\tmat<4, 4, T, Q> Result;\n\n\t\tvec<3, T, Q> axis = normalize(v);\n\n\t\tResult[0][0] = c + (static_cast<T>(1) - c)      * axis.x     * axis.x;\n\t\tResult[0][1] = (static_cast<T>(1) - c) * axis.x * axis.y + s * axis.z;\n\t\tResult[0][2] = (static_cast<T>(1) - c) * axis.x * axis.z - s * axis.y;\n\t\tResult[0][3] = static_cast<T>(0);\n\n\t\tResult[1][0] = (static_cast<T>(1) - c) * axis.y * axis.x - s * axis.z;\n\t\tResult[1][1] = c + (static_cast<T>(1) - c) * axis.y * axis.y;\n\t\tResult[1][2] = (static_cast<T>(1) - c) * axis.y * axis.z + s * axis.x;\n\t\tResult[1][3] = static_cast<T>(0);\n\n\t\tResult[2][0] = (static_cast<T>(1) - c) * axis.z * axis.x + s * axis.y;\n\t\tResult[2][1] = (static_cast<T>(1) - c) * axis.z * axis.y - s * axis.x;\n\t\tResult[2][2] = c + (static_cast<T>(1) - c) * axis.z * axis.z;\n\t\tResult[2][3] = static_cast<T>(0);\n\n\t\tResult[3] = vec<4, T, Q>(0, 0, 0, 1);\n\t\treturn m * Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)\n\t{\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0] = m[0] * v[0];\n\t\tResult[1] = m[1] * v[1];\n\t\tResult[2] = m[2] * v[2];\n\t\tResult[3] = m[3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale_slow(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& v)\n\t{\n\t\tmat<4, 4, T, Q> Result(T(1));\n\t\tResult[0][0] = v.x;\n\t\tResult[1][1] = v.y;\n\t\tResult[2][2] = v.z;\n\t\treturn m * Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtRH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)\n\t{\n\t\tvec<3, T, Q> const f(normalize(center - eye));\n\t\tvec<3, T, Q> const s(normalize(cross(f, up)));\n\t\tvec<3, T, Q> const u(cross(s, f));\n\n\t\tmat<4, 4, T, Q> Result(1);\n\t\tResult[0][0] = s.x;\n\t\tResult[1][0] = s.y;\n\t\tResult[2][0] = s.z;\n\t\tResult[0][1] = u.x;\n\t\tResult[1][1] = u.y;\n\t\tResult[2][1] = u.z;\n\t\tResult[0][2] =-f.x;\n\t\tResult[1][2] =-f.y;\n\t\tResult[2][2] =-f.z;\n\t\tResult[3][0] =-dot(s, eye);\n\t\tResult[3][1] =-dot(u, eye);\n\t\tResult[3][2] = dot(f, eye);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAtLH(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)\n\t{\n\t\tvec<3, T, Q> const f(normalize(center - eye));\n\t\tvec<3, T, Q> const s(normalize(cross(up, f)));\n\t\tvec<3, T, Q> const u(cross(f, s));\n\n\t\tmat<4, 4, T, Q> Result(1);\n\t\tResult[0][0] = s.x;\n\t\tResult[1][0] = s.y;\n\t\tResult[2][0] = s.z;\n\t\tResult[0][1] = u.x;\n\t\tResult[1][1] = u.y;\n\t\tResult[2][1] = u.z;\n\t\tResult[0][2] = f.x;\n\t\tResult[1][2] = f.y;\n\t\tResult[2][2] = f.z;\n\t\tResult[3][0] = -dot(s, eye);\n\t\tResult[3][1] = -dot(u, eye);\n\t\tResult[3][2] = -dot(f, eye);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> lookAt(vec<3, T, Q> const& eye, vec<3, T, Q> const& center, vec<3, T, Q> const& up)\n\t{\n#       if (GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT)\n            return lookAtLH(eye, center, up);\n#       else\n            return lookAtRH(eye, center, up);\n#       endif\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint2x2.hpp",
    "content": "/// @ref ext_matrix_uint2x2\n/// @file glm/ext/matrix_uint2x2.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint2x2 GLM_EXT_matrix_uint2x2\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint2x2.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint2x2 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint2x2\n\t/// @{\n\n\t/// Unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2\n\ttypedef mat<2, 2, uint, defaultp>\tumat2x2;\n\n\t/// Unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2\n\ttypedef mat<2, 2, uint, defaultp>\tumat2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint2x2_sized.hpp",
    "content": "/// @ref ext_matrix_uint2x2_sized\n/// @file glm/ext/matrix_uint2x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint2x2_sized GLM_EXT_matrix_uint2x2_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint2x2_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x2.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint2x2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint2x2_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint8, defaultp>\t\t\t\tu8mat2x2;\n\n\t/// 16 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint16, defaultp>\t\t\t\tu16mat2x2;\n\n\t/// 32 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint32, defaultp>\t\t\t\tu32mat2x2;\n\n\t/// 64 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint64, defaultp>\t\t\t\tu64mat2x2;\n\n\n\t/// 8 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint8, defaultp>\t\t\t\tu8mat2;\n\n\t/// 16 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint16, defaultp>\t\t\t\tu16mat2;\n\n\t/// 32 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint32, defaultp>\t\t\t\tu32mat2;\n\n\t/// 64 bit unsigned integer 2x2 matrix.\n\t///\n\t/// @see ext_matrix_uint2x2_sized\n\ttypedef mat<2, 2, uint64, defaultp>\t\t\t\tu64mat2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint2x3.hpp",
    "content": "/// @ref ext_matrix_uint2x3\n/// @file glm/ext/matrix_uint2x3.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int2x3 GLM_EXT_matrix_uint2x3\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint2x3.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x3.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint2x3 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint2x3\n\t/// @{\n\n\t/// Unsigned integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_uint2x3\n\ttypedef mat<2, 3, uint, defaultp>\tumat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint2x3_sized.hpp",
    "content": "/// @ref ext_matrix_uint2x3_sized\n/// @file glm/ext/matrix_uint2x3_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint2x3_sized GLM_EXT_matrix_uint2x3_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint2x3_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x3.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint2x3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint2x3_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_uint2x3_sized\n\ttypedef mat<2, 3, uint8, defaultp>\t\t\t\tu8mat2x3;\n\n\t/// 16 bit unsigned integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_uint2x3_sized\n\ttypedef mat<2, 3, uint16, defaultp>\t\t\t\tu16mat2x3;\n\n\t/// 32 bit unsigned integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_uint2x3_sized\n\ttypedef mat<2, 3, uint32, defaultp>\t\t\t\tu32mat2x3;\n\n\t/// 64 bit unsigned integer 2x3 matrix.\n\t///\n\t/// @see ext_matrix_uint2x3_sized\n\ttypedef mat<2, 3, uint64, defaultp>\t\t\t\tu64mat2x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint2x4.hpp",
    "content": "/// @ref ext_matrix_uint2x4\n/// @file glm/ext/matrix_uint2x4.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint2x4 GLM_EXT_matrix_int2x4\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint2x4.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint2x4 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint2x4\n\t/// @{\n\n\t/// Unsigned integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_uint2x4\n\ttypedef mat<2, 4, uint, defaultp>\tumat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint2x4_sized.hpp",
    "content": "/// @ref ext_matrix_uint2x4_sized\n/// @file glm/ext/matrixu_uint2x4_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint2x4_sized GLM_EXT_matrix_uint2x4_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint2x4_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x4.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint2x4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint2x4_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_uint2x4_sized\n\ttypedef mat<2, 4, uint8, defaultp>\t\t\t\tu8mat2x4;\n\n\t/// 16 bit unsigned integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_uint2x4_sized\n\ttypedef mat<2, 4, uint16, defaultp>\t\t\t\tu16mat2x4;\n\n\t/// 32 bit unsigned integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_uint2x4_sized\n\ttypedef mat<2, 4, uint32, defaultp>\t\t\t\tu32mat2x4;\n\n\t/// 64 bit unsigned integer 2x4 matrix.\n\t///\n\t/// @see ext_matrix_uint2x4_sized\n\ttypedef mat<2, 4, uint64, defaultp>\t\t\t\tu64mat2x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint3x2.hpp",
    "content": "/// @ref ext_matrix_uint3x2\n/// @file glm/ext/matrix_uint3x2.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_int3x2 GLM_EXT_matrix_uint3x2\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint3x2.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint3x2 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint3x2\n\t/// @{\n\n\t/// Unsigned integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_uint3x2\n\ttypedef mat<3, 2, uint, defaultp>\tumat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint3x2_sized.hpp",
    "content": "/// @ref ext_matrix_uint3x2_sized\n/// @file glm/ext/matrix_uint3x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint3x2_sized GLM_EXT_matrix_uint3x2_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint3x2_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x2.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint3x2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint3x2_sized\n\t/// @{\n\n\t/// 8 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_uint3x2_sized\n\ttypedef mat<3, 2, uint8, defaultp>\t\t\t\tu8mat3x2;\n\n\t/// 16 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_uint3x2_sized\n\ttypedef mat<3, 2, uint16, defaultp>\t\t\t\tu16mat3x2;\n\n\t/// 32 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_uint3x2_sized\n\ttypedef mat<3, 2, uint32, defaultp>\t\t\t\tu32mat3x2;\n\n\t/// 64 bit signed integer 3x2 matrix.\n\t///\n\t/// @see ext_matrix_uint3x2_sized\n\ttypedef mat<3, 2, uint64, defaultp>\t\t\t\tu64mat3x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint3x3.hpp",
    "content": "/// @ref ext_matrix_uint3x3\n/// @file glm/ext/matrix_uint3x3.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint3x3 GLM_EXT_matrix_uint3x3\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint3x3.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x3.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint3x3 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint3x3\n\t/// @{\n\n\t/// Unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3\n\ttypedef mat<3, 3, uint, defaultp>\tumat3x3;\n\n\t/// Unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3\n\ttypedef mat<3, 3, uint, defaultp>\tumat3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint3x3_sized.hpp",
    "content": "/// @ref ext_matrix_uint3x3_sized\n/// @file glm/ext/matrix_uint3x3_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint3x3_sized GLM_EXT_matrix_uint3x3_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint3x3_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x3.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint3x3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint3x3_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint8, defaultp>\t\t\t\tu8mat3x3;\n\n\t/// 16 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint16, defaultp>\t\t\t\tu16mat3x3;\n\n\t/// 32 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint32, defaultp>\t\t\t\tu32mat3x3;\n\n\t/// 64 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint64, defaultp>\t\t\t\tu64mat3x3;\n\n\n\t/// 8 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint8, defaultp>\t\t\t\tu8mat3;\n\n\t/// 16 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint16, defaultp>\t\t\t\tu16mat3;\n\n\t/// 32 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint32, defaultp>\t\t\t\tu32mat3;\n\n\t/// 64 bit unsigned integer 3x3 matrix.\n\t///\n\t/// @see ext_matrix_uint3x3_sized\n\ttypedef mat<3, 3, uint64, defaultp>\t\t\t\tu64mat3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint3x4.hpp",
    "content": "/// @ref ext_matrix_uint3x4\n/// @file glm/ext/matrix_uint3x4.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint3x4 GLM_EXT_matrix_uint3x4\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint3x4.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint3x4 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint3x4\n\t/// @{\n\n\t/// Signed integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_uint3x4\n\ttypedef mat<3, 4, uint, defaultp>\tumat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint3x4_sized.hpp",
    "content": "/// @ref ext_matrix_uint3x4_sized\n/// @file glm/ext/matrix_uint3x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint3x4_sized GLM_EXT_matrix_uint3x4_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint3x4_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x4.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint3x4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint3x4_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_uint3x4_sized\n\ttypedef mat<3, 4, uint8, defaultp>\t\t\t\tu8mat3x4;\n\n\t/// 16 bit unsigned integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_uint3x4_sized\n\ttypedef mat<3, 4, uint16, defaultp>\t\t\t\tu16mat3x4;\n\n\t/// 32 bit unsigned integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_uint3x4_sized\n\ttypedef mat<3, 4, uint32, defaultp>\t\t\t\tu32mat3x4;\n\n\t/// 64 bit unsigned integer 3x4 matrix.\n\t///\n\t/// @see ext_matrix_uint3x4_sized\n\ttypedef mat<3, 4, uint64, defaultp>\t\t\t\tu64mat3x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint4x2.hpp",
    "content": "/// @ref ext_matrix_uint4x2\n/// @file glm/ext/matrix_uint4x2.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint4x2 GLM_EXT_matrix_uint4x2\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint4x2.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint4x2 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint4x2\n\t/// @{\n\n\t/// Unsigned integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_uint4x2\n\ttypedef mat<4, 2, uint, defaultp>\tumat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint4x2_sized.hpp",
    "content": "/// @ref ext_matrix_uint4x2_sized\n/// @file glm/ext/matrix_uint4x2_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint4x2_sized GLM_EXT_matrix_uint4x2_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint4x2_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x2.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint4x2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint4x2_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_uint4x2_sized\n\ttypedef mat<4, 2, uint8, defaultp>\t\t\t\tu8mat4x2;\n\n\t/// 16 bit unsigned integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_uint4x2_sized\n\ttypedef mat<4, 2, uint16, defaultp>\t\t\t\tu16mat4x2;\n\n\t/// 32 bit unsigned integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_uint4x2_sized\n\ttypedef mat<4, 2, uint32, defaultp>\t\t\t\tu32mat4x2;\n\n\t/// 64 bit unsigned integer 4x2 matrix.\n\t///\n\t/// @see ext_matrix_uint4x2_sized\n\ttypedef mat<4, 2, uint64, defaultp>\t\t\t\tu64mat4x2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint4x3.hpp",
    "content": "/// @ref ext_matrix_uint4x3\n/// @file glm/ext/matrix_uint4x3.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint4x3 GLM_EXT_matrix_uint4x3\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint4x3.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x3.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint4x3 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint4x3\n\t/// @{\n\n\t/// Unsigned integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_uint4x3\n\ttypedef mat<4, 3, uint, defaultp>\tumat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint4x3_sized.hpp",
    "content": "/// @ref ext_matrix_uint4x3_sized\n/// @file glm/ext/matrix_uint4x3_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint4x3_sized GLM_EXT_matrix_uint4x3_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint4x3_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x3.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint4x3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint4x3_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_uint4x3_sized\n\ttypedef mat<4, 3, uint8, defaultp>\t\t\t\tu8mat4x3;\n\n\t/// 16 bit unsigned integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_uint4x3_sized\n\ttypedef mat<4, 3, uint16, defaultp>\t\t\t\tu16mat4x3;\n\n\t/// 32 bit unsigned integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_uint4x3_sized\n\ttypedef mat<4, 3, uint32, defaultp>\t\t\t\tu32mat4x3;\n\n\t/// 64 bit unsigned integer 4x3 matrix.\n\t///\n\t/// @see ext_matrix_uint4x3_sized\n\ttypedef mat<4, 3, uint64, defaultp>\t\t\t\tu64mat4x3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint4x4.hpp",
    "content": "/// @ref ext_matrix_uint4x4\n/// @file glm/ext/matrix_uint4x4.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint4x4 GLM_EXT_matrix_uint4x4\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint4x4.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint4x4 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint4x4\n\t/// @{\n\n\t/// Unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4\n\ttypedef mat<4, 4, uint, defaultp>\tumat4x4;\n\n\t/// Unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4\n\ttypedef mat<4, 4, uint, defaultp>\tumat4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/matrix_uint4x4_sized.hpp",
    "content": "/// @ref ext_matrix_uint4x4_sized\n/// @file glm/ext/matrix_uint4x4_sized.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_matrix_uint4x4_sized GLM_EXT_matrix_uint4x4_sized\n/// @ingroup ext\n///\n/// Include <glm/ext/matrix_uint4x4_sized.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat4x4.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_matrix_uint4x4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_matrix_uint4x4_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint8, defaultp>\t\t\t\tu8mat4x4;\n\n\t/// 16 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint16, defaultp>\t\t\t\tu16mat4x4;\n\n\t/// 32 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint32, defaultp>\t\t\t\tu32mat4x4;\n\n\t/// 64 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint64, defaultp>\t\t\t\tu64mat4x4;\n\n\n\t/// 8 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint8, defaultp>\t\t\t\tu8mat4;\n\n\t/// 16 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint16, defaultp>\t\t\t\tu16mat4;\n\n\t/// 32 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint32, defaultp>\t\t\t\tu32mat4;\n\n\t/// 64 bit unsigned integer 4x4 matrix.\n\t///\n\t/// @see ext_matrix_uint4x4_sized\n\ttypedef mat<4, 4, uint64, defaultp>\t\t\t\tu64mat4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_common.hpp",
    "content": "/// @ref ext_quaternion_common\n/// @file glm/ext/quaternion_common.hpp\n///\n/// @defgroup ext_quaternion_common GLM_EXT_quaternion_common\n/// @ingroup ext\n///\n/// Provides common functions for quaternion types\n///\n/// Include <glm/ext/quaternion_common.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_common\n/// @see ext_vector_common\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double\n/// @see ext_quaternion_exponential\n/// @see ext_quaternion_geometric\n/// @see ext_quaternion_relational\n/// @see ext_quaternion_trigonometric\n/// @see ext_quaternion_transform\n\n#pragma once\n\n// Dependency:\n#include \"../ext/scalar_constants.hpp\"\n#include \"../ext/quaternion_geometric.hpp\"\n#include \"../common.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../exponential.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_common extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_common\n\t/// @{\n\n\t/// Spherical linear interpolation of two quaternions.\n\t/// The interpolation is oriented and the rotation is performed at constant speed.\n\t/// For short path spherical linear interpolation, use the slerp function.\n\t///\n\t/// @param x A quaternion\n\t/// @param y A quaternion\n\t/// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\t///\n\t/// @see - slerp(qua<T, Q> const& x, qua<T, Q> const& y, T const& a)\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> mix(qua<T, Q> const& x, qua<T, Q> const& y, T a);\n\n\t/// Linear interpolation of two quaternions.\n\t/// The interpolation is oriented.\n\t///\n\t/// @param x A quaternion\n\t/// @param y A quaternion\n\t/// @param a Interpolation factor. The interpolation is defined in the range [0, 1].\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> lerp(qua<T, Q> const& x, qua<T, Q> const& y, T a);\n\n\t/// Spherical linear interpolation of two quaternions.\n\t/// The interpolation always take the short path and the rotation is performed at constant speed.\n\t///\n\t/// @param x A quaternion\n\t/// @param y A quaternion\n\t/// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> slerp(qua<T, Q> const& x, qua<T, Q> const& y, T a);\n\n    /// Spherical linear interpolation of two quaternions with multiple spins over rotation axis.\n    /// The interpolation always take the short path when the spin count is positive and long path\n    /// when count is negative. Rotation is performed at constant speed.\n    ///\n    /// @param x A quaternion\n    /// @param y A quaternion\n    /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].\n    /// @param k Additional spin count. If Value is negative interpolation will be on \"long\" path.\n    ///\n    /// @tparam T A floating-point scalar type\n    /// @tparam S An integer scalar type\n    /// @tparam Q A value from qualifier enum\n    template<typename T, typename S, qualifier Q>\n    GLM_FUNC_DECL qua<T, Q> slerp(qua<T, Q> const& x, qua<T, Q> const& y, T a, S k);\n\n\t/// Returns the q conjugate.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> conjugate(qua<T, Q> const& q);\n\n\t/// Returns the q inverse.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> inverse(qua<T, Q> const& q);\n\n\t/// Returns true if x holds a NaN (not a number)\n\t/// representation in the underlying implementation's set of\n\t/// floating point representations. Returns false otherwise,\n\t/// including for implementations with no NaN\n\t/// representations.\n\t///\n\t/// /!\\ When using compiler fast math, this function may fail.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> isnan(qua<T, Q> const& x);\n\n\t/// Returns true if x holds a positive infinity or negative\n\t/// infinity representation in the underlying implementation's\n\t/// set of floating point representations. Returns false\n\t/// otherwise, including for implementations with no infinity\n\t/// representations.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> isinf(qua<T, Q> const& x);\n\n\t/// @}\n} //namespace glm\n\n#include \"quaternion_common.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_common.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> mix(qua<T, Q> const& x, qua<T, Q> const& y, T a)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'mix' only accept floating-point inputs\");\n\n\t\tT const cosTheta = dot(x, y);\n\n\t\t// Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator\n\t\tif(cosTheta > static_cast<T>(1) - epsilon<T>())\n\t\t{\n\t\t\t// Linear interpolation\n\t\t\treturn qua<T, Q>(\n\t\t\t\tmix(x.w, y.w, a),\n\t\t\t\tmix(x.x, y.x, a),\n\t\t\t\tmix(x.y, y.y, a),\n\t\t\t\tmix(x.z, y.z, a));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Essential Mathematics, page 467\n\t\t\tT angle = acos(cosTheta);\n\t\t\treturn (sin((static_cast<T>(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle);\n\t\t}\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> lerp(qua<T, Q> const& x, qua<T, Q> const& y, T a)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'lerp' only accept floating-point inputs\");\n\n\t\t// Lerp is only defined in [0, 1]\n\t\tassert(a >= static_cast<T>(0));\n\t\tassert(a <= static_cast<T>(1));\n\n\t\treturn x * (static_cast<T>(1) - a) + (y * a);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> slerp(qua<T, Q> const& x, qua<T, Q> const& y, T a)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'slerp' only accept floating-point inputs\");\n\n\t\tqua<T, Q> z = y;\n\n\t\tT cosTheta = dot(x, y);\n\n\t\t// If cosTheta < 0, the interpolation will take the long way around the sphere.\n\t\t// To fix this, one quat must be negated.\n\t\tif(cosTheta < static_cast<T>(0))\n\t\t{\n\t\t\tz = -y;\n\t\t\tcosTheta = -cosTheta;\n\t\t}\n\n\t\t// Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator\n\t\tif(cosTheta > static_cast<T>(1) - epsilon<T>())\n\t\t{\n\t\t\t// Linear interpolation\n\t\t\treturn qua<T, Q>(\n\t\t\t\tmix(x.w, z.w, a),\n\t\t\t\tmix(x.x, z.x, a),\n\t\t\t\tmix(x.y, z.y, a),\n\t\t\t\tmix(x.z, z.z, a));\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// Essential Mathematics, page 467\n\t\t\tT angle = acos(cosTheta);\n\t\t\treturn (sin((static_cast<T>(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle);\n\t\t}\n\t}\n\n    template<typename T, typename S, qualifier Q>\n    GLM_FUNC_QUALIFIER qua<T, Q> slerp(qua<T, Q> const& x, qua<T, Q> const& y, T a, S k)\n    {\n        GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'slerp' only accept floating-point inputs\");\n        GLM_STATIC_ASSERT(std::numeric_limits<S>::is_integer, \"'slerp' only accept integer for spin count\");\n\n        qua<T, Q> z = y;\n\n        T cosTheta = dot(x, y);\n\n        // If cosTheta < 0, the interpolation will take the long way around the sphere.\n        // To fix this, one quat must be negated.\n        if (cosTheta < static_cast<T>(0))\n        {\n            z = -y;\n            cosTheta = -cosTheta;\n        }\n\n        // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator\n        if (cosTheta > static_cast<T>(1) - epsilon<T>())\n        {\n            // Linear interpolation\n            return qua<T, Q>(\n                mix(x.w, z.w, a),\n                mix(x.x, z.x, a),\n                mix(x.y, z.y, a),\n                mix(x.z, z.z, a));\n        }\n        else\n        {\n            // Graphics Gems III, page 96\n            T angle = acos(cosTheta);\n            T phi = angle + k * glm::pi<T>();\n            return (sin(angle - a * phi)* x + sin(a * phi) * z) / sin(angle);\n        }\n    }\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> conjugate(qua<T, Q> const& q)\n\t{\n\t\treturn qua<T, Q>(q.w, -q.x, -q.y, -q.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> inverse(qua<T, Q> const& q)\n\t{\n\t\treturn conjugate(q) / dot(q, q);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> isnan(qua<T, Q> const& q)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isnan' only accept floating-point inputs\");\n\n\t\treturn vec<4, bool, Q>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> isinf(qua<T, Q> const& q)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isinf' only accept floating-point inputs\");\n\n\t\treturn vec<4, bool, Q>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w));\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"quaternion_common_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_common_simd.inl",
    "content": "#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<qualifier Q>\n\tstruct compute_dot<qua<float, Q>, float, true>\n\t{\n\t\tstatic GLM_FUNC_QUALIFIER float call(qua<float, Q> const& x, qua<float, Q> const& y)\n\t\t{\n\t\t\treturn _mm_cvtss_f32(glm_vec1_dot(x.data, y.data));\n\t\t}\n\t};\n}//namespace detail\n}//namespace glm\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_double.hpp",
    "content": "/// @ref ext_quaternion_double\n/// @file glm/ext/quaternion_double.hpp\n///\n/// @defgroup ext_quaternion_double GLM_EXT_quaternion_double\n/// @ingroup ext\n///\n/// Exposes double-precision floating point quaternion type.\n///\n/// Include <glm/ext/quaternion_double.hpp> to use the features of this extension.\n///\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double_precision\n/// @see ext_quaternion_common\n/// @see ext_quaternion_exponential\n/// @see ext_quaternion_geometric\n/// @see ext_quaternion_relational\n/// @see ext_quaternion_transform\n/// @see ext_quaternion_trigonometric\n\n#pragma once\n\n// Dependency:\n#include \"../detail/type_quat.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_double extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_double\n\t/// @{\n\n\t/// Quaternion of double-precision floating-point numbers.\n\ttypedef qua<double, defaultp>\t\tdquat;\n\n\t/// @}\n} //namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_double_precision.hpp",
    "content": "/// @ref ext_quaternion_double_precision\n/// @file glm/ext/quaternion_double_precision.hpp\n///\n/// @defgroup ext_quaternion_double_precision GLM_EXT_quaternion_double_precision\n/// @ingroup ext\n///\n/// Exposes double-precision floating point quaternion type with various precision in term of ULPs.\n///\n/// Include <glm/ext/quaternion_double_precision.hpp> to use the features of this extension.\n\n#pragma once\n\n// Dependency:\n#include \"../detail/type_quat.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_double_precision extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_double_precision\n\t/// @{\n\n\t/// Quaternion of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see ext_quaternion_double_precision\n\ttypedef qua<double, lowp>\t\tlowp_dquat;\n\n\t/// Quaternion of medium double-qualifier floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see ext_quaternion_double_precision\n\ttypedef qua<double, mediump>\tmediump_dquat;\n\n\t/// Quaternion of high double-qualifier floating-point numbers using high precision arithmetic in term of ULPs.\n\t///\n\t/// @see ext_quaternion_double_precision\n\ttypedef qua<double, highp>\t\thighp_dquat;\n\n\t/// @}\n} //namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_exponential.hpp",
    "content": "/// @ref ext_quaternion_exponential\n/// @file glm/ext/quaternion_exponential.hpp\n///\n/// @defgroup ext_quaternion_exponential GLM_EXT_quaternion_exponential\n/// @ingroup ext\n///\n/// Provides exponential functions for quaternion types\n///\n/// Include <glm/ext/quaternion_exponential.hpp> to use the features of this extension.\n///\n/// @see core_exponential\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double\n\n#pragma once\n\n// Dependency:\n#include \"../common.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../geometric.hpp\"\n#include \"../ext/scalar_constants.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_exponential extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_transform\n\t/// @{\n\n\t/// Returns a exponential of a quaternion.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> exp(qua<T, Q> const& q);\n\n\t/// Returns a logarithm of a quaternion\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> log(qua<T, Q> const& q);\n\n\t/// Returns a quaternion raised to a power.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> pow(qua<T, Q> const& q, T y);\n\n\t/// Returns the square root of a quaternion\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> sqrt(qua<T, Q> const& q);\n\n\t/// @}\n} //namespace glm\n\n#include \"quaternion_exponential.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_exponential.inl",
    "content": "#include \"scalar_constants.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> exp(qua<T, Q> const& q)\n\t{\n\t\tvec<3, T, Q> u(q.x, q.y, q.z);\n\t\tT const Angle = glm::length(u);\n\t\tif (Angle < epsilon<T>())\n\t\t\treturn qua<T, Q>();\n\n\t\tvec<3, T, Q> const v(u / Angle);\n\t\treturn qua<T, Q>(cos(Angle), sin(Angle) * v);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> log(qua<T, Q> const& q)\n\t{\n\t\tvec<3, T, Q> u(q.x, q.y, q.z);\n\t\tT Vec3Len = length(u);\n\n\t\tif (Vec3Len < epsilon<T>())\n\t\t{\n\t\t\tif(q.w > static_cast<T>(0))\n\t\t\t\treturn qua<T, Q>(log(q.w), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));\n\t\t\telse if(q.w < static_cast<T>(0))\n\t\t\t\treturn qua<T, Q>(log(-q.w), pi<T>(), static_cast<T>(0), static_cast<T>(0));\n\t\t\telse\n\t\t\t\treturn qua<T, Q>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());\n\t\t}\n\t\telse\n\t\t{\n\t\t\tT t = atan(Vec3Len, T(q.w)) / Vec3Len;\n\t\t\tT QuatLen2 = Vec3Len * Vec3Len + q.w * q.w;\n\t\t\treturn qua<T, Q>(static_cast<T>(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z);\n\t\t}\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> pow(qua<T, Q> const& x, T y)\n\t{\n\t\t//Raising to the power of 0 should yield 1\n\t\t//Needed to prevent a division by 0 error later on\n\t\tif(y > -epsilon<T>() && y < epsilon<T>())\n\t\t\treturn qua<T, Q>(1,0,0,0);\n\n\t\t//To deal with non-unit quaternions\n\t\tT magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w);\n\n\t\tT Angle;\n\t\tif(abs(x.w / magnitude) > cos_one_over_two<T>())\n\t\t{\n\t\t\t//Scalar component is close to 1; using it to recover angle would lose precision\n\t\t\t//Instead, we use the non-scalar components since sin() is accurate around 0\n\n\t\t\t//Prevent a division by 0 error later on\n\t\t\tT VectorMagnitude = x.x * x.x + x.y * x.y + x.z * x.z;\n\t\t\tif (glm::abs(VectorMagnitude - static_cast<T>(0)) < glm::epsilon<T>()) {\n\t\t\t\t//Equivalent to raising a real number to a power\n\t\t\t\treturn qua<T, Q>(pow(x.w, y), 0, 0, 0);\n\t\t\t}\n\n\t\t\tAngle = asin(sqrt(VectorMagnitude) / magnitude);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t//Scalar component is small, shouldn't cause loss of precision\n\t\t\tAngle = acos(x.w / magnitude);\n\t\t}\n\n\t\tT NewAngle = Angle * y;\n\t\tT Div = sin(NewAngle) / sin(Angle);\n\t\tT Mag = pow(magnitude, y - static_cast<T>(1));\n\t\treturn qua<T, Q>(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> sqrt(qua<T, Q> const& x)\n\t{\n\t\treturn pow(x, static_cast<T>(0.5));\n\t}\n}//namespace glm\n\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_float.hpp",
    "content": "/// @ref ext_quaternion_float\n/// @file glm/ext/quaternion_float.hpp\n///\n/// @defgroup ext_quaternion_float GLM_EXT_quaternion_float\n/// @ingroup ext\n///\n/// Exposes single-precision floating point quaternion type.\n///\n/// Include <glm/ext/quaternion_float.hpp> to use the features of this extension.\n///\n/// @see ext_quaternion_double\n/// @see ext_quaternion_float_precision\n/// @see ext_quaternion_common\n/// @see ext_quaternion_exponential\n/// @see ext_quaternion_geometric\n/// @see ext_quaternion_relational\n/// @see ext_quaternion_transform\n/// @see ext_quaternion_trigonometric\n\n#pragma once\n\n// Dependency:\n#include \"../detail/type_quat.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_float extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_float\n\t/// @{\n\n\t/// Quaternion of single-precision floating-point numbers.\n\ttypedef qua<float, defaultp>\t\tquat;\n\n\t/// @}\n} //namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_float_precision.hpp",
    "content": "/// @ref ext_quaternion_float_precision\n/// @file glm/ext/quaternion_float_precision.hpp\n///\n/// @defgroup ext_quaternion_float_precision GLM_EXT_quaternion_float_precision\n/// @ingroup ext\n///\n/// Exposes single-precision floating point quaternion type with various precision in term of ULPs.\n///\n/// Include <glm/ext/quaternion_float_precision.hpp> to use the features of this extension.\n\n#pragma once\n\n// Dependency:\n#include \"../detail/type_quat.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_float_precision extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_float_precision\n\t/// @{\n\n\t/// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef qua<float, lowp>\t\tlowp_quat;\n\n\t/// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef qua<float, mediump>\t\tmediump_quat;\n\n\t/// Quaternion of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef qua<float, highp>\t\thighp_quat;\n\n\t/// @}\n} //namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_geometric.hpp",
    "content": "/// @ref ext_quaternion_geometric\n/// @file glm/ext/quaternion_geometric.hpp\n///\n/// @defgroup ext_quaternion_geometric GLM_EXT_quaternion_geometric\n/// @ingroup ext\n///\n/// Provides geometric functions for quaternion types\n///\n/// Include <glm/ext/quaternion_geometric.hpp> to use the features of this extension.\n///\n/// @see core_geometric\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double\n\n#pragma once\n\n// Dependency:\n#include \"../geometric.hpp\"\n#include \"../exponential.hpp\"\n#include \"../ext/vector_relational.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_geometric extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_geometric\n\t/// @{\n\n\t/// Returns the norm of a quaternions\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_geometric\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T length(qua<T, Q> const& q);\n\n\t/// Returns the normalized quaternion.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_geometric\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> normalize(qua<T, Q> const& q);\n\n\t/// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ...\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_geometric\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T dot(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Compute a cross product.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_geometric\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> cross(qua<T, Q> const& q1, qua<T, Q> const& q2);\n\n\t/// @}\n} //namespace glm\n\n#include \"quaternion_geometric.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_geometric.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T dot(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'dot' accepts only floating-point inputs\");\n\t\treturn detail::compute_dot<qua<T, Q>, T, detail::is_aligned<Q>::value>::call(x, y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T length(qua<T, Q> const& q)\n\t{\n\t\treturn glm::sqrt(dot(q, q));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> normalize(qua<T, Q> const& q)\n\t{\n\t\tT len = length(q);\n\t\tif(len <= static_cast<T>(0)) // Problem\n\t\t\treturn qua<T, Q>(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));\n\t\tT oneOverLen = static_cast<T>(1) / len;\n\t\treturn qua<T, Q>(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> cross(qua<T, Q> const& q1, qua<T, Q> const& q2)\n\t{\n\t\treturn qua<T, Q>(\n\t\t\tq1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,\n\t\t\tq1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,\n\t\t\tq1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,\n\t\t\tq1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x);\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_relational.hpp",
    "content": "/// @ref ext_quaternion_relational\n/// @file glm/ext/quaternion_relational.hpp\n///\n/// @defgroup ext_quaternion_relational GLM_EXT_quaternion_relational\n/// @ingroup ext\n///\n/// Exposes comparison functions for quaternion types that take a user defined epsilon values.\n///\n/// Include <glm/ext/quaternion_relational.hpp> to use the features of this extension.\n///\n/// @see core_vector_relational\n/// @see ext_vector_relational\n/// @see ext_matrix_relational\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double\n\n#pragma once\n\n// Dependency:\n#include \"../vector_relational.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_relational extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_relational\n\t/// @{\n\n\t/// Returns the component-wise comparison of result x == y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> equal(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> equal(qua<T, Q> const& x, qua<T, Q> const& y, T epsilon);\n\n\t/// Returns the component-wise comparison of result x != y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> notEqual(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Returns the component-wise comparison of |x - y| >= epsilon.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> notEqual(qua<T, Q> const& x, qua<T, Q> const& y, T epsilon);\n\n\t/// @}\n} //namespace glm\n\n#include \"quaternion_relational.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_relational.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tvec<4, bool, Q> Result;\n\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\tResult[i] = x[i] == y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> equal(qua<T, Q> const& x, qua<T, Q> const& y, T epsilon)\n\t{\n\t\tvec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w);\n\t\treturn lessThan(abs(v), vec<4, T, Q>(epsilon));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tvec<4, bool, Q> Result;\n\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\tResult[i] = x[i] != y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> notEqual(qua<T, Q> const& x, qua<T, Q> const& y, T epsilon)\n\t{\n\t\tvec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w);\n\t\treturn greaterThanEqual(abs(v), vec<4, T, Q>(epsilon));\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_transform.hpp",
    "content": "/// @ref ext_quaternion_transform\n/// @file glm/ext/quaternion_transform.hpp\n///\n/// @defgroup ext_quaternion_transform GLM_EXT_quaternion_transform\n/// @ingroup ext\n///\n/// Provides transformation functions for quaternion types\n///\n/// Include <glm/ext/quaternion_transform.hpp> to use the features of this extension.\n///\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double\n/// @see ext_quaternion_exponential\n/// @see ext_quaternion_geometric\n/// @see ext_quaternion_relational\n/// @see ext_quaternion_trigonometric\n\n#pragma once\n\n// Dependency:\n#include \"../common.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../geometric.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_transform extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_transform\n\t/// @{\n\n\t/// Rotates a quaternion from a vector of 3 components axis and an angle.\n\t///\n\t/// @param q Source orientation\n\t/// @param angle Angle expressed in radians.\n\t/// @param axis Axis of the rotation\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> rotate(qua<T, Q> const& q, T const& angle, vec<3, T, Q> const& axis);\n\t/// @}\n} //namespace glm\n\n#include \"quaternion_transform.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_transform.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> rotate(qua<T, Q> const& q, T const& angle, vec<3, T, Q> const& v)\n\t{\n\t\tvec<3, T, Q> Tmp = v;\n\n\t\t// Axis of rotation must be normalised\n\t\tT len = glm::length(Tmp);\n\t\tif(abs(len - static_cast<T>(1)) > static_cast<T>(0.001))\n\t\t{\n\t\t\tT oneOverLen = static_cast<T>(1) / len;\n\t\t\tTmp.x *= oneOverLen;\n\t\t\tTmp.y *= oneOverLen;\n\t\t\tTmp.z *= oneOverLen;\n\t\t}\n\n\t\tT const AngleRad(angle);\n\t\tT const Sin = sin(AngleRad * static_cast<T>(0.5));\n\n\t\treturn q * qua<T, Q>(cos(AngleRad * static_cast<T>(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin);\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_trigonometric.hpp",
    "content": "/// @ref ext_quaternion_trigonometric\n/// @file glm/ext/quaternion_trigonometric.hpp\n///\n/// @defgroup ext_quaternion_trigonometric GLM_EXT_quaternion_trigonometric\n/// @ingroup ext\n///\n/// Provides trigonometric functions for quaternion types\n///\n/// Include <glm/ext/quaternion_trigonometric.hpp> to use the features of this extension.\n///\n/// @see ext_quaternion_float\n/// @see ext_quaternion_double\n/// @see ext_quaternion_exponential\n/// @see ext_quaternion_geometric\n/// @see ext_quaternion_relational\n/// @see ext_quaternion_transform\n\n#pragma once\n\n// Dependency:\n#include \"../trigonometric.hpp\"\n#include \"../exponential.hpp\"\n#include \"scalar_constants.hpp\"\n#include \"vector_relational.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_quaternion_trigonometric extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_quaternion_trigonometric\n\t/// @{\n\n\t/// Returns the quaternion rotation angle.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T angle(qua<T, Q> const& x);\n\n\t/// Returns the q rotation axis.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> axis(qua<T, Q> const& x);\n\n\t/// Build a quaternion from an angle and a normalized axis.\n\t///\n\t/// @param angle Angle expressed in radians.\n\t/// @param axis Axis of the quaternion, must be normalized.\n\t///\n\t/// @tparam T A floating-point scalar type\n\t/// @tparam Q A value from qualifier enum\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> angleAxis(T const& angle, vec<3, T, Q> const& axis);\n\n\t/// @}\n} //namespace glm\n\n#include \"quaternion_trigonometric.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/quaternion_trigonometric.inl",
    "content": "#include \"scalar_constants.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T angle(qua<T, Q> const& x)\n\t{\n\t\tif (abs(x.w) > cos_one_over_two<T>())\n\t\t{\n\t\t\treturn asin(sqrt(x.x * x.x + x.y * x.y + x.z * x.z)) * static_cast<T>(2);\n\t\t}\n\n\t\treturn acos(x.w) * static_cast<T>(2);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> axis(qua<T, Q> const& x)\n\t{\n\t\tT const tmp1 = static_cast<T>(1) - x.w * x.w;\n\t\tif(tmp1 <= static_cast<T>(0))\n\t\t\treturn vec<3, T, Q>(0, 0, 1);\n\t\tT const tmp2 = static_cast<T>(1) / sqrt(tmp1);\n\t\treturn vec<3, T, Q>(x.x * tmp2, x.y * tmp2, x.z * tmp2);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> angleAxis(T const& angle, vec<3, T, Q> const& v)\n\t{\n\t\tT const a(angle);\n\t\tT const s = glm::sin(a * static_cast<T>(0.5));\n\n\t\treturn qua<T, Q>(glm::cos(a * static_cast<T>(0.5)), v * s);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_common.hpp",
    "content": "/// @ref ext_scalar_common\n/// @file glm/ext/scalar_common.hpp\n///\n/// @defgroup ext_scalar_common GLM_EXT_scalar_common\n/// @ingroup ext\n///\n/// Exposes min and max functions for 3 to 4 scalar parameters.\n///\n/// Include <glm/ext/scalar_common.hpp> to use the features of this extension.\n///\n/// @see core_func_common\n/// @see ext_vector_common\n\n#pragma once\n\n// Dependency:\n#include \"../common.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_common extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_scalar_common\n\t/// @{\n\n\t/// Returns the minimum component-wise values of 3 inputs\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T min(T a, T b, T c);\n\n\t/// Returns the minimum component-wise values of 4 inputs\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T min(T a, T b, T c, T d);\n\n\t/// Returns the maximum component-wise values of 3 inputs\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T max(T a, T b, T c);\n\n\t/// Returns the maximum component-wise values of 4 inputs\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T max(T a, T b, T c, T d);\n\n\t/// Returns the minimum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fmin(T a, T b);\n\n\t/// Returns the minimum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fmin(T a, T b, T c);\n\n\t/// Returns the minimum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fmin(T a, T b, T c, T d);\n\n\t/// Returns the maximum component-wise values of 2 inputs. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fmax(T a, T b);\n\n\t/// Returns the maximum component-wise values of 3 inputs. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fmax(T a, T b, T C);\n\n\t/// Returns the maximum component-wise values of 4 inputs. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam T A floating-point scalar type.\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\t/// @see ext_scalar_common\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fmax(T a, T b, T C, T D);\n\n\t/// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam genType Floating-point scalar types.\n\t///\n\t/// @see ext_scalar_common\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fclamp(genType x, genType minVal, genType maxVal);\n\n\t/// Simulate GL_CLAMP OpenGL wrap mode\n\t///\n\t/// @tparam genType Floating-point scalar types.\n\t///\n\t/// @see ext_scalar_common extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType clamp(genType const& Texcoord);\n\n\t/// Simulate GL_REPEAT OpenGL wrap mode\n\t///\n\t/// @tparam genType Floating-point scalar types.\n\t///\n\t/// @see ext_scalar_common extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType repeat(genType const& Texcoord);\n\n\t/// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode\n\t///\n\t/// @tparam genType Floating-point scalar types.\n\t///\n\t/// @see ext_scalar_common extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType mirrorClamp(genType const& Texcoord);\n\n\t/// Simulate GL_MIRROR_REPEAT OpenGL wrap mode\n\t///\n\t/// @tparam genType Floating-point scalar types.\n\t///\n\t/// @see ext_scalar_common extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType mirrorRepeat(genType const& Texcoord);\n\n\t/// @}\n}//namespace glm\n\n#include \"scalar_common.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_common.inl",
    "content": "namespace glm\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T min(T a, T b, T c)\n\t{\n\t\treturn glm::min(glm::min(a, b), c);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T min(T a, T b, T c, T d)\n\t{\n\t\treturn glm::min(glm::min(a, b), glm::min(c, d));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T max(T a, T b, T c)\n\t{\n\t\treturn glm::max(glm::max(a, b), c);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T max(T a, T b, T c, T d)\n\t{\n\t\treturn glm::max(glm::max(a, b), glm::max(c, d));\n\t}\n\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::fmin;\n#\telse\n\t\ttemplate<typename T>\n\t\tGLM_FUNC_QUALIFIER T fmin(T a, T b)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point input\");\n\n\t\t\tif (isnan(a))\n\t\t\t\treturn b;\n\t\t\treturn min(a, b);\n\t\t}\n#\tendif\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fmin(T a, T b, T c)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point input\");\n\n\t\tif (isnan(a))\n\t\t\treturn fmin(b, c);\n\t\tif (isnan(b))\n\t\t\treturn fmin(a, c);\n\t\tif (isnan(c))\n\t\t\treturn min(a, b);\n\t\treturn min(a, b, c);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fmin(T a, T b, T c, T d)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point input\");\n\n\t\tif (isnan(a))\n\t\t\treturn fmin(b, c, d);\n\t\tif (isnan(b))\n\t\t\treturn min(a, fmin(c, d));\n\t\tif (isnan(c))\n\t\t\treturn fmin(min(a, b), d);\n\t\tif (isnan(d))\n\t\t\treturn min(a, b, c);\n\t\treturn min(a, b, c, d);\n\t}\n\n\n#\tif GLM_HAS_CXX11_STL\n\t\tusing std::fmax;\n#\telse\n\t\ttemplate<typename T>\n\t\tGLM_FUNC_QUALIFIER T fmax(T a, T b)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point input\");\n\n\t\t\tif (isnan(a))\n\t\t\t\treturn b;\n\t\t\treturn max(a, b);\n\t\t}\n#\tendif\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fmax(T a, T b, T c)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point input\");\n\n\t\tif (isnan(a))\n\t\t\treturn fmax(b, c);\n\t\tif (isnan(b))\n\t\t\treturn fmax(a, c);\n\t\tif (isnan(c))\n\t\t\treturn max(a, b);\n\t\treturn max(a, b, c);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fmax(T a, T b, T c, T d)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point input\");\n\n\t\tif (isnan(a))\n\t\t\treturn fmax(b, c, d);\n\t\tif (isnan(b))\n\t\t\treturn max(a, fmax(c, d));\n\t\tif (isnan(c))\n\t\t\treturn fmax(max(a, b), d);\n\t\tif (isnan(d))\n\t\t\treturn max(a, b, c);\n\t\treturn max(a, b, c, d);\n\t}\n\n\t// fclamp\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fclamp(genType x, genType minVal, genType maxVal)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'fclamp' only accept floating-point or integer inputs\");\n\t\treturn fmin(fmax(x, minVal), maxVal);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType clamp(genType const& Texcoord)\n\t{\n\t\treturn glm::clamp(Texcoord, static_cast<genType>(0), static_cast<genType>(1));\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType repeat(genType const& Texcoord)\n\t{\n\t\treturn glm::fract(Texcoord);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType mirrorClamp(genType const& Texcoord)\n\t{\n\t\treturn glm::fract(glm::abs(Texcoord));\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType mirrorRepeat(genType const& Texcoord)\n\t{\n\t\tgenType const Abs = glm::abs(Texcoord);\n\t\tgenType const Clamp = glm::mod(glm::floor(Abs), static_cast<genType>(2));\n\t\tgenType const Floor = glm::floor(Abs);\n\t\tgenType const Rest = Abs - Floor;\n\t\tgenType const Mirror = Clamp + Rest;\n\t\treturn mix(Rest, static_cast<genType>(1) - Rest, Mirror >= static_cast<genType>(1));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_constants.hpp",
    "content": "/// @ref ext_scalar_constants\n/// @file glm/ext/scalar_constants.hpp\n///\n/// @defgroup ext_scalar_constants GLM_EXT_scalar_constants\n/// @ingroup ext\n///\n/// Provides a list of constants and precomputed useful values.\n///\n/// Include <glm/ext/scalar_constants.hpp> to use the features of this extension.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_constants extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_scalar_constants\n\t/// @{\n\n\t/// Return the epsilon constant for floating point types.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType epsilon();\n\n\t/// Return the pi constant for floating point types.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType pi();\n\n\t/// Return the value of cos(1 / 2) for floating point types.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType cos_one_over_two();\n\n\t/// @}\n} //namespace glm\n\n#include \"scalar_constants.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_constants.inl",
    "content": "#include <limits>\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType epsilon()\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'epsilon' only accepts floating-point inputs\");\n\t\treturn std::numeric_limits<genType>::epsilon();\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType pi()\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'pi' only accepts floating-point inputs\");\n\t\treturn static_cast<genType>(3.14159265358979323846264338327950288);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType cos_one_over_two()\n\t{\n\t\treturn genType(0.877582561890372716130286068203503191);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_int_sized.hpp",
    "content": "/// @ref ext_scalar_int_sized\n/// @file glm/ext/scalar_int_sized.hpp\n///\n/// @defgroup ext_scalar_int_sized GLM_EXT_scalar_int_sized\n/// @ingroup ext\n///\n/// Exposes sized signed integer scalar types.\n///\n/// Include <glm/ext/scalar_int_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_uint_sized\n\n#pragma once\n\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_int_sized extension included\")\n#endif\n\nnamespace glm{\nnamespace detail\n{\n#\tif GLM_HAS_EXTENDED_INTEGER_TYPE\n\t\ttypedef std::int8_t\t\t\tint8;\n\t\ttypedef std::int16_t\t\tint16;\n\t\ttypedef std::int32_t\t\tint32;\n#\telse\n\t\ttypedef signed char\t\t\tint8;\n\t\ttypedef signed short\t\tint16;\n\t\ttypedef signed int\t\t\tint32;\n#endif//\n\n\ttemplate<>\n\tstruct is_int<int8>\n\t{\n\t\tenum test {value = ~0};\n\t};\n\n\ttemplate<>\n\tstruct is_int<int16>\n\t{\n\t\tenum test {value = ~0};\n\t};\n\n\ttemplate<>\n\tstruct is_int<int64>\n\t{\n\t\tenum test {value = ~0};\n\t};\n}//namespace detail\n\n\n\t/// @addtogroup ext_scalar_int_sized\n\t/// @{\n\n\t/// 8 bit signed integer type.\n\ttypedef detail::int8\t\tint8;\n\n\t/// 16 bit signed integer type.\n\ttypedef detail::int16\t\tint16;\n\n\t/// 32 bit signed integer type.\n\ttypedef detail::int32\t\tint32;\n\n\t/// 64 bit signed integer type.\n\ttypedef detail::int64\t\tint64;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_integer.hpp",
    "content": "/// @ref ext_scalar_integer\n/// @file glm/ext/scalar_integer.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_scalar_integer GLM_EXT_scalar_integer\n/// @ingroup ext\n///\n/// Include <glm/ext/scalar_integer.hpp> to use the features of this extension.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_vectorize.hpp\"\n#include \"../detail/type_float.hpp\"\n#include \"../vector_relational.hpp\"\n#include \"../common.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_integer extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_scalar_integer\n\t/// @{\n\n\t/// Return true if the value is a power of two number.\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL bool isPowerOfTwo(genIUType v);\n\n\t/// Return the power of two number which value is just higher the input value,\n\t/// round up to a power of two.\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType nextPowerOfTwo(genIUType v);\n\n\t/// Return the power of two number which value is just lower the input value,\n\t/// round down to a power of two.\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType prevPowerOfTwo(genIUType v);\n\n\t/// Return true if the 'Value' is a multiple of 'Multiple'.\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL bool isMultiple(genIUType v, genIUType Multiple);\n\n\t/// Higher multiple number of Source.\n\t///\n\t/// @tparam genIUType Integer scalar or vector types.\n\t///\n\t/// @param v Source value to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType nextMultiple(genIUType v, genIUType Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam genIUType Integer scalar or vector types.\n\t///\n\t/// @param v Source value to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType prevMultiple(genIUType v, genIUType Multiple);\n\n\t/// Returns the bit number of the Nth significant bit set to\n\t/// 1 in the binary representation of value.\n\t/// If value bitcount is less than the Nth significant bit, -1 will be returned.\n\t///\n\t/// @tparam genIUType Signed or unsigned integer scalar types.\n\t///\n\t/// @see ext_scalar_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL int findNSB(genIUType x, int significantBitCount);\n\n\t/// @}\n} //namespace glm\n\n#include \"scalar_integer.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_integer.inl",
    "content": "#include \"../integer.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q, bool compute = false>\n\tstruct compute_ceilShift\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T)\n\t\t{\n\t\t\treturn v;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_ceilShift<L, T, Q, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v, T Shift)\n\t\t{\n\t\t\treturn v | (v >> Shift);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q, bool isSigned = true>\n\tstruct compute_ceilPowerOfTwo\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, \"'ceilPowerOfTwo' only accept integer scalar or vector inputs\");\n\n\t\t\tvec<L, T, Q> const Sign(sign(x));\n\n\t\t\tvec<L, T, Q> v(abs(x));\n\n\t\t\tv = v - static_cast<T>(1);\n\t\t\tv = v | (v >> static_cast<T>(1));\n\t\t\tv = v | (v >> static_cast<T>(2));\n\t\t\tv = v | (v >> static_cast<T>(4));\n\t\t\tv = compute_ceilShift<L, T, Q, sizeof(T) >= 2>::call(v, 8);\n\t\t\tv = compute_ceilShift<L, T, Q, sizeof(T) >= 4>::call(v, 16);\n\t\t\tv = compute_ceilShift<L, T, Q, sizeof(T) >= 8>::call(v, 32);\n\t\t\treturn (v + static_cast<T>(1)) * Sign;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_ceilPowerOfTwo<L, T, Q, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& x)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, \"'ceilPowerOfTwo' only accept integer scalar or vector inputs\");\n\n\t\t\tvec<L, T, Q> v(x);\n\n\t\t\tv = v - static_cast<T>(1);\n\t\t\tv = v | (v >> static_cast<T>(1));\n\t\t\tv = v | (v >> static_cast<T>(2));\n\t\t\tv = v | (v >> static_cast<T>(4));\n\t\t\tv = compute_ceilShift<L, T, Q, sizeof(T) >= 2>::call(v, 8);\n\t\t\tv = compute_ceilShift<L, T, Q, sizeof(T) >= 4>::call(v, 16);\n\t\t\tv = compute_ceilShift<L, T, Q, sizeof(T) >= 8>::call(v, 32);\n\t\t\treturn v + static_cast<T>(1);\n\t\t}\n\t};\n\n\ttemplate<bool is_float, bool is_signed>\n\tstruct compute_ceilMultiple{};\n\n\ttemplate<>\n\tstruct compute_ceilMultiple<true, true>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif(Source > genType(0))\n\t\t\t\treturn Source + (Multiple - std::fmod(Source, Multiple));\n\t\t\telse\n\t\t\t\treturn Source + std::fmod(-Source, Multiple);\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct compute_ceilMultiple<false, false>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tgenType Tmp = Source - genType(1);\n\t\t\treturn Tmp + (Multiple - (Tmp % Multiple));\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct compute_ceilMultiple<false, true>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tassert(Multiple > genType(0));\n\t\t\tif(Source > genType(0))\n\t\t\t{\n\t\t\t\tgenType Tmp = Source - genType(1);\n\t\t\t\treturn Tmp + (Multiple - (Tmp % Multiple));\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn Source + (-Source % Multiple);\n\t\t}\n\t};\n\n\ttemplate<bool is_float, bool is_signed>\n\tstruct compute_floorMultiple{};\n\n\ttemplate<>\n\tstruct compute_floorMultiple<true, true>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif(Source >= genType(0))\n\t\t\t\treturn Source - std::fmod(Source, Multiple);\n\t\t\telse\n\t\t\t\treturn Source - std::fmod(Source, Multiple) - Multiple;\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct compute_floorMultiple<false, false>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif(Source >= genType(0))\n\t\t\t\treturn Source - Source % Multiple;\n\t\t\telse\n\t\t\t{\n\t\t\t\tgenType Tmp = Source + genType(1);\n\t\t\t\treturn Tmp - Tmp % Multiple - Multiple;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct compute_floorMultiple<false, true>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif(Source >= genType(0))\n\t\t\t\treturn Source - Source % Multiple;\n\t\t\telse\n\t\t\t{\n\t\t\t\tgenType Tmp = Source + genType(1);\n\t\t\t\treturn Tmp - Tmp % Multiple - Multiple;\n\t\t\t}\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER bool isPowerOfTwo(genIUType Value)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'isPowerOfTwo' only accept integer inputs\");\n\n\t\tgenIUType const Result = glm::abs(Value);\n\t\treturn !(Result & (Result - 1));\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType nextPowerOfTwo(genIUType value)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'nextPowerOfTwo' only accept integer inputs\");\n\n\t\treturn detail::compute_ceilPowerOfTwo<1, genIUType, defaultp, std::numeric_limits<genIUType>::is_signed>::call(vec<1, genIUType, defaultp>(value)).x;\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType prevPowerOfTwo(genIUType value)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'prevPowerOfTwo' only accept integer inputs\");\n\n\t\treturn isPowerOfTwo(value) ? value : static_cast<genIUType>(static_cast<genIUType>(1) << static_cast<genIUType>(findMSB(value)));\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER bool isMultiple(genIUType Value, genIUType Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'isMultiple' only accept integer inputs\");\n\n\t\treturn isMultiple(vec<1, genIUType>(Value), vec<1, genIUType>(Multiple)).x;\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType nextMultiple(genIUType Source, genIUType Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'nextMultiple' only accept integer inputs\");\n\n\t\treturn detail::compute_ceilMultiple<std::numeric_limits<genIUType>::is_iec559, std::numeric_limits<genIUType>::is_signed>::call(Source, Multiple);\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType prevMultiple(genIUType Source, genIUType Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'prevMultiple' only accept integer inputs\");\n\n\t\treturn detail::compute_floorMultiple<std::numeric_limits<genIUType>::is_iec559, std::numeric_limits<genIUType>::is_signed>::call(Source, Multiple);\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER int findNSB(genIUType x, int significantBitCount)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'findNSB' only accept integer inputs\");\n\n\t\tif(bitCount(x) < significantBitCount)\n\t\t\treturn -1;\n\n\t\tgenIUType const One = static_cast<genIUType>(1);\n\t\tint bitPos = 0;\n\n\t\tgenIUType key = x;\n\t\tint nBitCount = significantBitCount;\n\t\tint Step = sizeof(x) * 8 / 2;\n\t\twhile (key > One)\n\t\t{\n\t\t\tgenIUType Mask = static_cast<genIUType>((One << Step) - One);\n\t\t\tgenIUType currentKey = key & Mask;\n\t\t\tint currentBitCount = bitCount(currentKey);\n\t\t\tif (nBitCount > currentBitCount)\n\t\t\t{\n\t\t\t\tnBitCount -= currentBitCount;\n\t\t\t\tbitPos += Step;\n\t\t\t\tkey >>= static_cast<genIUType>(Step);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tkey = key & Mask;\n\t\t\t}\n\n\t\t\tStep >>= 1;\n\t\t}\n\n\t\treturn static_cast<int>(bitPos);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_packing.hpp",
    "content": "/// @ref ext_scalar_packing\n/// @file glm/ext/scalar_packing.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_scalar_packing GLM_EXT_scalar_packing\n/// @ingroup ext\n///\n/// Include <glm/ext/scalar_packing.hpp> to use the features of this extension.\n///\n/// This extension provides a set of function to convert scalar values to packed\n/// formats.\n\n#pragma once\n\n// Dependency:\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_packing extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_scalar_packing\n\t/// @{\n\n\n\t/// @}\n}// namespace glm\n\n#include \"scalar_packing.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_packing.inl",
    "content": ""
  },
  {
    "path": "lib/gli/glm/ext/scalar_relational.hpp",
    "content": "/// @ref ext_scalar_relational\n/// @file glm/ext/scalar_relational.hpp\n///\n/// @defgroup ext_scalar_relational GLM_EXT_scalar_relational\n/// @ingroup ext\n///\n/// Exposes comparison functions for scalar types that take a user defined epsilon values.\n///\n/// Include <glm/ext/scalar_relational.hpp> to use the features of this extension.\n///\n/// @see core_vector_relational\n/// @see ext_vector_relational\n/// @see ext_matrix_relational\n\n#pragma once\n\n// Dependencies\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_relational extension included\")\n#endif\n\nnamespace glm\n{\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam genType Floating-point or integer scalar types\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| >= epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam genType Floating-point or integer scalar types\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon);\n\n\t/// Returns the component-wise comparison between two scalars in term of ULPs.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @param x First operand.\n\t/// @param y Second operand.\n\t/// @param ULPs Maximum difference in ULPs between the two operators to consider them equal.\n\t///\n\t/// @tparam genType Floating-point or integer scalar types\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int ULPs);\n\n\t/// Returns the component-wise comparison between two scalars in term of ULPs.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @param x First operand.\n\t/// @param y Second operand.\n\t/// @param ULPs Maximum difference in ULPs between the two operators to consider them not equal.\n\t///\n\t/// @tparam genType Floating-point or integer scalar types\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs);\n\n\t/// @}\n}//namespace glm\n\n#include \"scalar_relational.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_relational.inl",
    "content": "#include \"../common.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n#include \"../detail/type_float.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, genType const& epsilon)\n\t{\n\t\treturn abs(x - y) <= epsilon;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, genType const& epsilon)\n\t{\n\t\treturn abs(x - y) > epsilon;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool equal(genType const& x, genType const& y, int MaxULPs)\n\t{\n\t\tdetail::float_t<genType> const a(x);\n\t\tdetail::float_t<genType> const b(y);\n\n\t\t// Different signs means they do not match.\n\t\tif(a.negative() != b.negative())\n\t\t\treturn false;\n\n\t\t// Find the difference in ULPs.\n\t\ttypename detail::float_t<genType>::int_type const DiffULPs = abs(a.i - b.i);\n\t\treturn DiffULPs <= MaxULPs;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR bool notEqual(genType const& x, genType const& y, int ULPs)\n\t{\n\t\treturn !equal(x, y, ULPs);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_uint_sized.hpp",
    "content": "/// @ref ext_scalar_uint_sized\n/// @file glm/ext/scalar_uint_sized.hpp\n///\n/// @defgroup ext_scalar_uint_sized GLM_EXT_scalar_uint_sized\n/// @ingroup ext\n///\n/// Exposes sized unsigned integer scalar types.\n///\n/// Include <glm/ext/scalar_uint_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_int_sized\n\n#pragma once\n\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_uint_sized extension included\")\n#endif\n\nnamespace glm{\nnamespace detail\n{\n#\tif GLM_HAS_EXTENDED_INTEGER_TYPE\n\t\ttypedef std::uint8_t\t\tuint8;\n\t\ttypedef std::uint16_t\t\tuint16;\n\t\ttypedef std::uint32_t\t\tuint32;\n#\telse\n\t\ttypedef unsigned char\t\tuint8;\n\t\ttypedef unsigned short\t\tuint16;\n\t\ttypedef unsigned int\t\tuint32;\n#endif\n\n\ttemplate<>\n\tstruct is_int<uint8>\n\t{\n\t\tenum test {value = ~0};\n\t};\n\n\ttemplate<>\n\tstruct is_int<uint16>\n\t{\n\t\tenum test {value = ~0};\n\t};\n\n\ttemplate<>\n\tstruct is_int<uint64>\n\t{\n\t\tenum test {value = ~0};\n\t};\n}//namespace detail\n\n\n\t/// @addtogroup ext_scalar_uint_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer type.\n\ttypedef detail::uint8\t\tuint8;\n\n\t/// 16 bit unsigned integer type.\n\ttypedef detail::uint16\t\tuint16;\n\n\t/// 32 bit unsigned integer type.\n\ttypedef detail::uint32\t\tuint32;\n\n\t/// 64 bit unsigned integer type.\n\ttypedef detail::uint64\t\tuint64;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_ulp.hpp",
    "content": "/// @ref ext_scalar_ulp\n/// @file glm/ext/scalar_ulp.hpp\n///\n/// @defgroup ext_scalar_ulp GLM_EXT_scalar_ulp\n/// @ingroup ext\n///\n/// Allow the measurement of the accuracy of a function against a reference\n/// implementation. This extension works on floating-point data and provide results\n/// in ULP.\n///\n/// Include <glm/ext/scalar_ulp.hpp> to use the features of this extension.\n///\n/// @see ext_vector_ulp\n/// @see ext_scalar_relational\n\n#pragma once\n\n// Dependencies\n#include \"../ext/scalar_int_sized.hpp\"\n#include \"../common.hpp\"\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_scalar_ulp extension included\")\n#endif\n\nnamespace glm\n{\n\t/// Return the next ULP value(s) after the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType nextFloat(genType x);\n\n\t/// Return the previous ULP value(s) before the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType prevFloat(genType x);\n\n\t/// Return the value(s) ULP distance after the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType nextFloat(genType x, int ULPs);\n\n\t/// Return the value(s) ULP distance before the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType prevFloat(genType x, int ULPs);\n\n\t/// Return the distance in the number of ULP between 2 single-precision floating-point scalars.\n\t///\n\t/// @see ext_scalar_ulp\n\tGLM_FUNC_DECL int floatDistance(float x, float y);\n\n\t/// Return the distance in the number of ULP between 2 double-precision floating-point scalars.\n\t///\n\t/// @see ext_scalar_ulp\n\tGLM_FUNC_DECL int64 floatDistance(double x, double y);\n\n\t/// @}\n}//namespace glm\n\n#include \"scalar_ulp.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/scalar_ulp.inl",
    "content": "/// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.\n///\n/// Developed at SunPro, a Sun Microsystems, Inc. business.\n/// Permission to use, copy, modify, and distribute this\n/// software is freely granted, provided that this notice\n/// is preserved.\n\n#include \"../detail/type_float.hpp\"\n#include \"../ext/scalar_constants.hpp\"\n#include <cmath>\n#include <cfloat>\n\n#if(GLM_COMPILER & GLM_COMPILER_VC)\n#\tpragma warning(push)\n#\tpragma warning(disable : 4127)\n#endif\n\ntypedef union\n{\n\tfloat value;\n\t/* FIXME: Assumes 32 bit int.  */\n\tunsigned int word;\n} ieee_float_shape_type;\n\ntypedef union\n{\n\tdouble value;\n\tstruct\n\t{\n\t\tint lsw;\n\t\tint msw;\n\t} parts;\n} ieee_double_shape_type;\n\n#define GLM_EXTRACT_WORDS(ix0,ix1,d)\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\t\\\n\t\tieee_double_shape_type ew_u;\t\t\\\n\t\tew_u.value = (d);\t\t\t\t\t\\\n\t\t(ix0) = ew_u.parts.msw;\t\t\t\t\\\n\t\t(ix1) = ew_u.parts.lsw;\t\t\t\t\\\n\t} while (0)\n\n#define GLM_GET_FLOAT_WORD(i,d)\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\t\\\n\t\tieee_float_shape_type gf_u;\t\t\t\\\n\t\tgf_u.value = (d);\t\t\t\t\t\\\n\t\t(i) = gf_u.word;\t\t\t\t\t\\\n\t} while (0)\n\n#define GLM_SET_FLOAT_WORD(d,i)\t\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\t\\\n\t\tieee_float_shape_type sf_u;\t\t\t\\\n\t\tsf_u.word = (i);\t\t\t\t\t\\\n\t\t(d) = sf_u.value;\t\t\t\t\t\\\n\t} while (0)\n\n#define GLM_INSERT_WORDS(d,ix0,ix1)\t\t\t\\\n\tdo {\t\t\t\t\t\t\t\t\t\\\n\t\tieee_double_shape_type iw_u;\t\t\\\n\t\tiw_u.parts.msw = (ix0);\t\t\t\t\\\n\t\tiw_u.parts.lsw = (ix1);\t\t\t\t\\\n\t\t(d) = iw_u.value;\t\t\t\t\t\\\n\t} while (0)\n\nnamespace glm{\nnamespace detail\n{\n\tGLM_FUNC_QUALIFIER float nextafterf(float x, float y)\n\t{\n\t\tvolatile float t;\n\t\tint hx, hy, ix, iy;\n\n\t\tGLM_GET_FLOAT_WORD(hx, x);\n\t\tGLM_GET_FLOAT_WORD(hy, y);\n\t\tix = hx & 0x7fffffff;\t\t// |x|\n\t\tiy = hy & 0x7fffffff;\t\t// |y|\n\n\t\tif((ix > 0x7f800000) ||\t// x is nan\n\t\t\t(iy > 0x7f800000))\t// y is nan\n\t\t\treturn x + y;\n\t\tif(abs(y - x) <= epsilon<float>())\n\t\t\treturn y;\t\t// x=y, return y\n\t\tif(ix == 0)\n\t\t{\t\t\t\t// x == 0\n\t\t\tGLM_SET_FLOAT_WORD(x, (hy & 0x80000000) | 1);// return +-minsubnormal\n\t\t\tt = x * x;\n\t\t\tif(abs(t - x) <= epsilon<float>())\n\t\t\t\treturn t;\n\t\t\telse\n\t\t\t\treturn x;\t// raise underflow flag\n\t\t}\n\t\tif(hx >= 0)\n\t\t{\t\t\t\t\t\t// x > 0\n\t\t\tif(hx > hy)\t\t\t// x > y, x -= ulp\n\t\t\t\thx -= 1;\n\t\t\telse\t\t\t\t// x < y, x += ulp\n\t\t\t\thx += 1;\n\t\t}\n\t\telse\n\t\t{\t\t\t\t\t\t// x < 0\n\t\t\tif(hy >= 0 || hx > hy)\t// x < y, x -= ulp\n\t\t\t\thx -= 1;\n\t\t\telse\t\t\t\t// x > y, x += ulp\n\t\t\t\thx += 1;\n\t\t}\n\t\thy = hx & 0x7f800000;\n\t\tif(hy >= 0x7f800000)\n\t\t\treturn x + x;  \t\t// overflow\n\t\tif(hy < 0x00800000)\t\t// underflow\n\t\t{\n\t\t\tt = x * x;\n\t\t\tif(abs(t - x) > epsilon<float>())\n\t\t\t{\t\t\t\t\t// raise underflow flag\n\t\t\t\tGLM_SET_FLOAT_WORD(y, hx);\n\t\t\t\treturn y;\n\t\t\t}\n\t\t}\n\t\tGLM_SET_FLOAT_WORD(x, hx);\n\t\treturn x;\n\t}\n\n\tGLM_FUNC_QUALIFIER double nextafter(double x, double y)\n\t{\n\t\tvolatile double t;\n\t\tint hx, hy, ix, iy;\n\t\tunsigned int lx, ly;\n\n\t\tGLM_EXTRACT_WORDS(hx, lx, x);\n\t\tGLM_EXTRACT_WORDS(hy, ly, y);\n\t\tix = hx & 0x7fffffff;\t\t\t\t\t\t\t\t// |x|\n\t\tiy = hy & 0x7fffffff;\t\t\t\t\t\t\t\t// |y|\n\n\t\tif(((ix >= 0x7ff00000) && ((ix - 0x7ff00000) | lx) != 0) ||\t// x is nan\n\t\t\t((iy >= 0x7ff00000) && ((iy - 0x7ff00000) | ly) != 0))\t// y is nan\n\t\t\treturn x + y;\n\t\tif(abs(y - x) <= epsilon<double>())\n\t\t\treturn y;\t\t\t\t\t\t\t\t\t// x=y, return y\n\t\tif((ix | lx) == 0)\n\t\t{\t\t\t\t\t\t\t\t\t\t\t\t\t// x == 0\n\t\t\tGLM_INSERT_WORDS(x, hy & 0x80000000, 1);\t\t// return +-minsubnormal\n\t\t\tt = x * x;\n\t\t\tif(abs(t - x) <= epsilon<double>())\n\t\t\t\treturn t;\n\t\t\telse\n\t\t\t\treturn x;   // raise underflow flag\n\t\t}\n\t\tif(hx >= 0) {                             // x > 0\n\t\t\tif(hx > hy || ((hx == hy) && (lx > ly))) {    // x > y, x -= ulp\n\t\t\t\tif(lx == 0) hx -= 1;\n\t\t\t\tlx -= 1;\n\t\t\t}\n\t\t\telse {                            // x < y, x += ulp\n\t\t\t\tlx += 1;\n\t\t\t\tif(lx == 0) hx += 1;\n\t\t\t}\n\t\t}\n\t\telse {                                // x < 0\n\t\t\tif(hy >= 0 || hx > hy || ((hx == hy) && (lx > ly))){// x < y, x -= ulp\n\t\t\t\tif(lx == 0) hx -= 1;\n\t\t\t\tlx -= 1;\n\t\t\t}\n\t\t\telse {                            // x > y, x += ulp\n\t\t\t\tlx += 1;\n\t\t\t\tif(lx == 0) hx += 1;\n\t\t\t}\n\t\t}\n\t\thy = hx & 0x7ff00000;\n\t\tif(hy >= 0x7ff00000)\n\t\t\treturn x + x;\t\t\t// overflow\n\t\tif(hy < 0x00100000)\n\t\t{\t\t\t\t\t\t// underflow\n\t\t\tt = x * x;\n\t\t\tif(abs(t - x) > epsilon<double>())\n\t\t\t{\t\t\t\t\t// raise underflow flag\n\t\t\t\tGLM_INSERT_WORDS(y, hx, lx);\n\t\t\t\treturn y;\n\t\t\t}\n\t\t}\n\t\tGLM_INSERT_WORDS(x, hx, lx);\n\t\treturn x;\n\t}\n}//namespace detail\n}//namespace glm\n\n#if(GLM_COMPILER & GLM_COMPILER_VC)\n#\tpragma warning(pop)\n#endif\n\nnamespace glm\n{\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER float nextFloat(float x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\t\treturn std::nextafter(x, std::numeric_limits<float>::max());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\t\treturn detail::nextafterf(x, FLT_MAX);\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\t\treturn __builtin_nextafterf(x, FLT_MAX);\n#\t\telse\n\t\t\treturn nextafterf(x, FLT_MAX);\n#\t\tendif\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER double nextFloat(double x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\t\treturn std::nextafter(x, std::numeric_limits<double>::max());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\t\treturn detail::nextafter(x, std::numeric_limits<double>::max());\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\t\treturn __builtin_nextafter(x, DBL_MAX);\n#\t\telse\n\t\t\treturn nextafter(x, DBL_MAX);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T nextFloat(T x, int ULPs)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'next_float' only accept floating-point input\");\n\t\tassert(ULPs >= 0);\n\n\t\tT temp = x;\n\t\tfor(int i = 0; i < ULPs; ++i)\n\t\t\ttemp = nextFloat(temp);\n\t\treturn temp;\n\t}\n\n\tGLM_FUNC_QUALIFIER float prevFloat(float x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\t\treturn std::nextafter(x, std::numeric_limits<float>::min());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\t\treturn detail::nextafterf(x, FLT_MIN);\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\t\treturn __builtin_nextafterf(x, FLT_MIN);\n#\t\telse\n\t\t\treturn nextafterf(x, FLT_MIN);\n#\t\tendif\n\t}\n\n\tGLM_FUNC_QUALIFIER double prevFloat(double x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\t\treturn std::nextafter(x, std::numeric_limits<double>::min());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\t\treturn _nextafter(x, DBL_MIN);\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\t\treturn __builtin_nextafter(x, DBL_MIN);\n#\t\telse\n\t\t\treturn nextafter(x, DBL_MIN);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T prevFloat(T x, int ULPs)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'prev_float' only accept floating-point input\");\n\t\tassert(ULPs >= 0);\n\n\t\tT temp = x;\n\t\tfor(int i = 0; i < ULPs; ++i)\n\t\t\ttemp = prevFloat(temp);\n\t\treturn temp;\n\t}\n\n\tGLM_FUNC_QUALIFIER int floatDistance(float x, float y)\n\t{\n\t\tdetail::float_t<float> const a(x);\n\t\tdetail::float_t<float> const b(y);\n\n\t\treturn abs(a.i - b.i);\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 floatDistance(double x, double y)\n\t{\n\t\tdetail::float_t<double> const a(x);\n\t\tdetail::float_t<double> const b(y);\n\n\t\treturn abs(a.i - b.i);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool1.hpp",
    "content": "/// @ref ext_vector_bool1\n/// @file glm/ext/vector_bool1.hpp\n///\n/// @defgroup ext_vector_bool1 GLM_EXT_vector_bool1\n/// @ingroup ext\n///\n/// Exposes bvec1 vector type.\n///\n/// Include <glm/ext/vector_bool1.hpp> to use the features of this extension.\n///\n/// @see ext_vector_bool1_precision extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_bool1 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_bool1\n\t/// @{\n\n\t/// 1 components vector of boolean.\n\ttypedef vec<1, bool, defaultp>\t\tbvec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool1_precision.hpp",
    "content": "/// @ref ext_vector_bool1_precision\n/// @file glm/ext/vector_bool1_precision.hpp\n///\n/// @defgroup ext_vector_bool1_precision GLM_EXT_vector_bool1_precision\n/// @ingroup ext\n///\n/// Exposes highp_bvec1, mediump_bvec1 and lowp_bvec1 types.\n///\n/// Include <glm/ext/vector_bool1_precision.hpp> to use the features of this extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_bool1_precision extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_bool1_precision\n\t/// @{\n\n\t/// 1 component vector of bool values.\n\ttypedef vec<1, bool, highp>\t\t\thighp_bvec1;\n\n\t/// 1 component vector of bool values.\n\ttypedef vec<1, bool, mediump>\t\tmediump_bvec1;\n\n\t/// 1 component vector of bool values.\n\ttypedef vec<1, bool, lowp>\t\t\tlowp_bvec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_bool2.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 2 components vector of boolean.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<2, bool, defaultp>\t\tbvec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_bool2_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 2 components vector of high qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, bool, highp>\t\thighp_bvec2;\n\n\t/// 2 components vector of medium qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, bool, mediump>\tmediump_bvec2;\n\n\t/// 2 components vector of low qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, bool, lowp>\t\tlowp_bvec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_bool3.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 3 components vector of boolean.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<3, bool, defaultp>\t\tbvec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_bool3_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 3 components vector of high qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, bool, highp>\t\thighp_bvec3;\n\n\t/// 3 components vector of medium qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, bool, mediump>\tmediump_bvec3;\n\n\t/// 3 components vector of low qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, bool, lowp>\t\tlowp_bvec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_bool4.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 4 components vector of boolean.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<4, bool, defaultp>\t\tbvec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_bool4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_bool4_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 4 components vector of high qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, bool, highp>\t\thighp_bvec4;\n\n\t/// 4 components vector of medium qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, bool, mediump>\tmediump_bvec4;\n\n\t/// 4 components vector of low qualifier bool numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, bool, lowp>\t\tlowp_bvec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_common.hpp",
    "content": "/// @ref ext_vector_common\n/// @file glm/ext/vector_common.hpp\n///\n/// @defgroup ext_vector_common GLM_EXT_vector_common\n/// @ingroup ext\n///\n/// Exposes min and max functions for 3 to 4 vector parameters.\n///\n/// Include <glm/ext/vector_common.hpp> to use the features of this extension.\n///\n/// @see core_common\n/// @see ext_scalar_common\n\n#pragma once\n\n// Dependency:\n#include \"../ext/scalar_common.hpp\"\n#include \"../common.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_common extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_common\n\t/// @{\n\n\t/// Return the minimum component-wise values of 3 inputs\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c);\n\n\t/// Return the minimum component-wise values of 4 inputs\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c, vec<L, T, Q> const& d);\n\n\t/// Return the maximum component-wise values of 3 inputs\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z);\n\n\t/// Return the maximum component-wise values of 4 inputs\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> max( vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z, vec<L, T, Q> const& w);\n\n\t/// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmin(vec<L, T, Q> const& x, T y);\n\n\t/// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmin(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmin(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c);\n\n\t/// Returns y if y < x; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmin\">std::fmin documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmin(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c, vec<L, T, Q> const& d);\n\n\t/// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmax(vec<L, T, Q> const& a, T b);\n\n\t/// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b);\n\n\t/// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c);\n\n\t/// Returns y if x < y; otherwise, it returns x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://en.cppreference.com/w/cpp/numeric/math/fmax\">std::fmax documentation</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c, vec<L, T, Q> const& d);\n\n\t/// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_common\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fclamp(vec<L, T, Q> const& x, T minVal, T maxVal);\n\n\t/// Returns min(max(x, minVal), maxVal) for each component in x. If one of the two arguments is NaN, the value of the other argument is returned.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_common\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fclamp(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal);\n\n\t/// Simulate GL_CLAMP OpenGL wrap mode\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_common extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> clamp(vec<L, T, Q> const& Texcoord);\n\n\t/// Simulate GL_REPEAT OpenGL wrap mode\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_common extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> repeat(vec<L, T, Q> const& Texcoord);\n\n\t/// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_common extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mirrorClamp(vec<L, T, Q> const& Texcoord);\n\n\t/// Simulate GL_MIRROR_REPEAT OpenGL wrap mode\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_common extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mirrorRepeat(vec<L, T, Q> const& Texcoord);\n\n\t/// @}\n}//namespace glm\n\n#include \"vector_common.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_common.inl",
    "content": "#include \"../detail/_vectorize.hpp\"\n\nnamespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'min' only accept floating-point or integer inputs\");\n\t\treturn glm::min(glm::min(x, y), z);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> min(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z, vec<L, T, Q> const& w)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'min' only accept floating-point or integer inputs\");\n\t\treturn glm::min(glm::min(x, y), glm::min(z, w));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'max' only accept floating-point or integer inputs\");\n\t\treturn glm::max(glm::max(x, y), z);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, T, Q> max(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& z, vec<L, T, Q> const& w)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer, \"'max' only accept floating-point or integer inputs\");\n\t\treturn glm::max(glm::max(x, y), glm::max(z, w));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmin(vec<L, T, Q> const& a, T b)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point inputs\");\n\t\treturn detail::functor2<vec, L, T, Q>::call(fmin, a, vec<L, T, Q>(b));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmin(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point inputs\");\n\t\treturn detail::functor2<vec, L, T, Q>::call(fmin, a, b);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmin(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point inputs\");\n\t\treturn fmin(fmin(a, b), c);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmin(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c, vec<L, T, Q> const& d)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmin' only accept floating-point inputs\");\n\t\treturn fmin(fmin(a, b), fmin(c, d));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmax(vec<L, T, Q> const& a, T b)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point inputs\");\n\t\treturn detail::functor2<vec, L, T, Q>::call(fmax, a, vec<L, T, Q>(b));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point inputs\");\n\t\treturn detail::functor2<vec, L, T, Q>::call(fmax, a, b);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point inputs\");\n\t\treturn fmax(fmax(a, b), c);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmax(vec<L, T, Q> const& a, vec<L, T, Q> const& b, vec<L, T, Q> const& c, vec<L, T, Q> const& d)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fmax' only accept floating-point inputs\");\n\t\treturn fmax(fmax(a, b), fmax(c, d));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fclamp(vec<L, T, Q> const& x, T minVal, T maxVal)\n\t{\n\t\treturn fmin(fmax(x, vec<L, T, Q>(minVal)), vec<L, T, Q>(maxVal));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fclamp(vec<L, T, Q> const& x, vec<L, T, Q> const& minVal, vec<L, T, Q> const& maxVal)\n\t{\n\t\treturn fmin(fmax(x, minVal), maxVal);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> clamp(vec<L, T, Q> const& Texcoord)\n\t{\n\t\treturn glm::clamp(Texcoord, vec<L, T, Q>(0), vec<L, T, Q>(1));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> repeat(vec<L, T, Q> const& Texcoord)\n\t{\n\t\treturn glm::fract(Texcoord);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mirrorClamp(vec<L, T, Q> const& Texcoord)\n\t{\n\t\treturn glm::fract(glm::abs(Texcoord));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mirrorRepeat(vec<L, T, Q> const& Texcoord)\n\t{\n\t\tvec<L, T, Q> const Abs = glm::abs(Texcoord);\n\t\tvec<L, T, Q> const Clamp = glm::mod(glm::floor(Abs), vec<L, T, Q>(2));\n\t\tvec<L, T, Q> const Floor = glm::floor(Abs);\n\t\tvec<L, T, Q> const Rest = Abs - Floor;\n\t\tvec<L, T, Q> const Mirror = Clamp + Rest;\n\t\treturn mix(Rest, vec<L, T, Q>(1) - Rest, glm::greaterThanEqual(Mirror, vec<L, T, Q>(1)));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double1.hpp",
    "content": "/// @ref ext_vector_double1\n/// @file glm/ext/vector_double1.hpp\n///\n/// @defgroup ext_vector_double1 GLM_EXT_vector_double1\n/// @ingroup ext\n///\n/// Exposes double-precision floating point vector type with one component.\n///\n/// Include <glm/ext/vector_double1.hpp> to use the features of this extension.\n///\n/// @see ext_vector_double1_precision extension.\n/// @see ext_vector_float1 extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_double1 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_double1\n\t/// @{\n\n\t/// 1 components vector of double-precision floating-point numbers.\n\ttypedef vec<1, double, defaultp>\t\tdvec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double1_precision.hpp",
    "content": "/// @ref ext_vector_double1_precision\n/// @file glm/ext/vector_double1_precision.hpp\n///\n/// @defgroup ext_vector_double1_precision GLM_EXT_vector_double1_precision\n/// @ingroup ext\n///\n/// Exposes highp_dvec1, mediump_dvec1 and lowp_dvec1 types.\n///\n/// Include <glm/ext/vector_double1_precision.hpp> to use the features of this extension.\n///\n/// @see ext_vector_double1\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_double1_precision extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_double1_precision\n\t/// @{\n\n\t/// 1 component vector of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, highp>\t\thighp_dvec1;\n\n\t/// 1 component vector of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, mediump>\t\tmediump_dvec1;\n\n\t/// 1 component vector of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, lowp>\t\tlowp_dvec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_double2.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 2 components vector of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<2, double, defaultp>\t\tdvec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_double2_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 2 components vector of high double-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, double, highp>\t\thighp_dvec2;\n\n\t/// 2 components vector of medium double-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, double, mediump>\t\tmediump_dvec2;\n\n\t/// 2 components vector of low double-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, double, lowp>\t\tlowp_dvec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_double3.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 3 components vector of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<3, double, defaultp>\t\tdvec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_double3_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 3 components vector of high double-qualifier floating-point numbers.\n\t/// There is no guarantee on the actual qualifier.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, double, highp>\t\thighp_dvec3;\n\n\t/// 3 components vector of medium double-qualifier floating-point numbers.\n\t/// There is no guarantee on the actual qualifier.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, double, mediump>\t\tmediump_dvec3;\n\n\t/// 3 components vector of low double-qualifier floating-point numbers.\n\t/// There is no guarantee on the actual qualifier.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, double, lowp>\t\tlowp_dvec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_double4.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 4 components vector of double-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<4, double, defaultp>\t\tdvec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_double4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_double4_precision.hpp\n\n#pragma once\n#include \"../detail/setup.hpp\"\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 4 components vector of high double-qualifier floating-point numbers.\n\t/// There is no guarantee on the actual qualifier.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, double, highp>\t\thighp_dvec4;\n\n\t/// 4 components vector of medium double-qualifier floating-point numbers.\n\t/// There is no guarantee on the actual qualifier.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, double, mediump>\t\tmediump_dvec4;\n\n\t/// 4 components vector of low double-qualifier floating-point numbers.\n\t/// There is no guarantee on the actual qualifier.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, double, lowp>\t\tlowp_dvec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float1.hpp",
    "content": "/// @ref ext_vector_float1\n/// @file glm/ext/vector_float1.hpp\n///\n/// @defgroup ext_vector_float1 GLM_EXT_vector_float1\n/// @ingroup ext\n///\n/// Exposes single-precision floating point vector type with one component.\n///\n/// Include <glm/ext/vector_float1.hpp> to use the features of this extension.\n///\n/// @see ext_vector_float1_precision extension.\n/// @see ext_vector_double1 extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_float1 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_float1\n\t/// @{\n\n\t/// 1 components vector of single-precision floating-point numbers.\n\ttypedef vec<1, float, defaultp>\t\tvec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float1_precision.hpp",
    "content": "/// @ref ext_vector_float1_precision\n/// @file glm/ext/vector_float1_precision.hpp\n///\n/// @defgroup ext_vector_float1_precision GLM_EXT_vector_float1_precision\n/// @ingroup ext\n///\n/// Exposes highp_vec1, mediump_vec1 and lowp_vec1 types.\n///\n/// Include <glm/ext/vector_float1_precision.hpp> to use the features of this extension.\n///\n/// @see ext_vector_float1 extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_float1_precision extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_float1_precision\n\t/// @{\n\n\t/// 1 component vector of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, highp>\t\thighp_vec1;\n\n\t/// 1 component vector of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, mediump>\t\tmediump_vec1;\n\n\t/// 1 component vector of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, lowp>\t\t\tlowp_vec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_float2.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 2 components vector of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<2, float, defaultp>\tvec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float2_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_float2_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 2 components vector of high single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, float, highp>\t\thighp_vec2;\n\n\t/// 2 components vector of medium single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, float, mediump>\t\tmediump_vec2;\n\n\t/// 2 components vector of low single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<2, float, lowp>\t\t\tlowp_vec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_float3.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 3 components vector of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<3, float, defaultp>\t\tvec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float3_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_float3_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 3 components vector of high single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, float, highp>\t\thighp_vec3;\n\n\t/// 3 components vector of medium single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, float, mediump>\t\tmediump_vec3;\n\n\t/// 3 components vector of low single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<3, float, lowp>\t\t\tlowp_vec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_float4.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 4 components vector of single-precision floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<4, float, defaultp>\t\tvec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_float4_precision.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_float4_precision.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector_precision\n\t/// @{\n\n\t/// 4 components vector of high single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, float, highp>\t\thighp_vec4;\n\n\t/// 4 components vector of medium single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, float, mediump>\t\tmediump_vec4;\n\n\t/// 4 components vector of low single-qualifier floating-point numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>\n\ttypedef vec<4, float, lowp>\t\t\tlowp_vec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int1.hpp",
    "content": "/// @ref ext_vector_int1\n/// @file glm/ext/vector_int1.hpp\n///\n/// @defgroup ext_vector_int1 GLM_EXT_vector_int1\n/// @ingroup ext\n///\n/// Exposes ivec1 vector type.\n///\n/// Include <glm/ext/vector_int1.hpp> to use the features of this extension.\n///\n/// @see ext_vector_uint1 extension.\n/// @see ext_vector_int1_precision extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_int1 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_int1\n\t/// @{\n\n\t/// 1 component vector of signed integer numbers.\n\ttypedef vec<1, int, defaultp>\t\t\tivec1;\n\n\t/// @}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int1_sized.hpp",
    "content": "/// @ref ext_vector_int1_sized\n/// @file glm/ext/vector_int1_sized.hpp\n///\n/// @defgroup ext_vector_int1_sized GLM_EXT_vector_int1_sized\n/// @ingroup ext\n///\n/// Exposes sized signed integer vector types.\n///\n/// Include <glm/ext/vector_int1_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_int_sized\n/// @see ext_vector_uint1_sized\n\n#pragma once\n\n#include \"../ext/vector_int1.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_int1_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_int1_sized\n\t/// @{\n\n\t/// 8 bit signed integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_int1_sized\n\ttypedef vec<1, int8, defaultp>\ti8vec1;\n\n\t/// 16 bit signed integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_int1_sized\n\ttypedef vec<1, int16, defaultp>\ti16vec1;\n\n\t/// 32 bit signed integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_int1_sized\n\ttypedef vec<1, int32, defaultp>\ti32vec1;\n\n\t/// 64 bit signed integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_int1_sized\n\ttypedef vec<1, int64, defaultp>\ti64vec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_int2.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 2 components vector of signed integer numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<2, int, defaultp>\t\tivec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int2_sized.hpp",
    "content": "/// @ref ext_vector_int2_sized\n/// @file glm/ext/vector_int2_sized.hpp\n///\n/// @defgroup ext_vector_int2_sized GLM_EXT_vector_int2_sized\n/// @ingroup ext\n///\n/// Exposes sized signed integer vector of 2 components type.\n///\n/// Include <glm/ext/vector_int2_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_int_sized\n/// @see ext_vector_uint2_sized\n\n#pragma once\n\n#include \"../ext/vector_int2.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_int2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_int2_sized\n\t/// @{\n\n\t/// 8 bit signed integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_int2_sized\n\ttypedef vec<2, int8, defaultp>\t\ti8vec2;\n\n\t/// 16 bit signed integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_int2_sized\n\ttypedef vec<2, int16, defaultp>\t\ti16vec2;\n\n\t/// 32 bit signed integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_int2_sized\n\ttypedef vec<2, int32, defaultp>\t\ti32vec2;\n\n\t/// 64 bit signed integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_int2_sized\n\ttypedef vec<2, int64, defaultp>\t\ti64vec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_int3.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 3 components vector of signed integer numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<3, int, defaultp>\t\tivec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int3_sized.hpp",
    "content": "/// @ref ext_vector_int3_sized\n/// @file glm/ext/vector_int3_sized.hpp\n///\n/// @defgroup ext_vector_int3_sized GLM_EXT_vector_int3_sized\n/// @ingroup ext\n///\n/// Exposes sized signed integer vector of 3 components type.\n///\n/// Include <glm/ext/vector_int3_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_int_sized\n/// @see ext_vector_uint3_sized\n\n#pragma once\n\n#include \"../ext/vector_int3.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_int3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_int3_sized\n\t/// @{\n\n\t/// 8 bit signed integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_int3_sized\n\ttypedef vec<3, int8, defaultp>\t\ti8vec3;\n\n\t/// 16 bit signed integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_int3_sized\n\ttypedef vec<3, int16, defaultp>\t\ti16vec3;\n\n\t/// 32 bit signed integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_int3_sized\n\ttypedef vec<3, int32, defaultp>\t\ti32vec3;\n\n\t/// 64 bit signed integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_int3_sized\n\ttypedef vec<3, int64, defaultp>\t\ti64vec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_int4.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 4 components vector of signed integer numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<4, int, defaultp>\t\tivec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_int4_sized.hpp",
    "content": "/// @ref ext_vector_int4_sized\n/// @file glm/ext/vector_int4_sized.hpp\n///\n/// @defgroup ext_vector_int4_sized GLM_EXT_vector_int4_sized\n/// @ingroup ext\n///\n/// Exposes sized signed integer vector of 4 components type.\n///\n/// Include <glm/ext/vector_int4_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_int_sized\n/// @see ext_vector_uint4_sized\n\n#pragma once\n\n#include \"../ext/vector_int4.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_int4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_int4_sized\n\t/// @{\n\n\t/// 8 bit signed integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_int4_sized\n\ttypedef vec<4, int8, defaultp>\t\ti8vec4;\n\n\t/// 16 bit signed integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_int4_sized\n\ttypedef vec<4, int16, defaultp>\t\ti16vec4;\n\n\t/// 32 bit signed integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_int4_sized\n\ttypedef vec<4, int32, defaultp>\t\ti32vec4;\n\n\t/// 64 bit signed integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_int4_sized\n\ttypedef vec<4, int64, defaultp>\t\ti64vec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_integer.hpp",
    "content": "/// @ref ext_vector_integer\n/// @file glm/ext/vector_integer.hpp\n///\n/// @see core (dependence)\n/// @see ext_vector_integer (dependence)\n///\n/// @defgroup ext_vector_integer GLM_EXT_vector_integer\n/// @ingroup ext\n///\n/// Include <glm/ext/vector_integer.hpp> to use the features of this extension.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_vectorize.hpp\"\n#include \"../vector_relational.hpp\"\n#include \"../common.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_integer extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_integer\n\t/// @{\n\n\t/// Return true if the value is a power of two number.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> isPowerOfTwo(vec<L, T, Q> const& v);\n\n\t/// Return the power of two number which value is just higher the input value,\n\t/// round up to a power of two.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> nextPowerOfTwo(vec<L, T, Q> const& v);\n\n\t/// Return the power of two number which value is just lower the input value,\n\t/// round down to a power of two.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prevPowerOfTwo(vec<L, T, Q> const& v);\n\n\t/// Return true if the 'Value' is a multiple of 'Multiple'.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> isMultiple(vec<L, T, Q> const& v, T Multiple);\n\n\t/// Return true if the 'Value' is a multiple of 'Multiple'.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> isMultiple(vec<L, T, Q> const& v, vec<L, T, Q> const& Multiple);\n\n\t/// Higher multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> nextMultiple(vec<L, T, Q> const& v, T Multiple);\n\n\t/// Higher multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> nextMultiple(vec<L, T, Q> const& v, vec<L, T, Q> const& Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prevMultiple(vec<L, T, Q> const& v, T Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prevMultiple(vec<L, T, Q> const& v, vec<L, T, Q> const& Multiple);\n\n\t/// Returns the bit number of the Nth significant bit set to\n\t/// 1 in the binary representation of value.\n\t/// If value bitcount is less than the Nth significant bit, -1 will be returned.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t///\n\t/// @see ext_vector_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> findNSB(vec<L, T, Q> const& Source, vec<L, int, Q> SignificantBitCount);\n\n\t/// @}\n} //namespace glm\n\n#include \"vector_integer.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_integer.inl",
    "content": "#include \"scalar_integer.hpp\"\n\nnamespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> isPowerOfTwo(vec<L, T, Q> const& Value)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'isPowerOfTwo' only accept integer inputs\");\n\n\t\tvec<L, T, Q> const Result(abs(Value));\n\t\treturn equal(Result & (Result - vec<L, T, Q>(1)), vec<L, T, Q>(0));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> nextPowerOfTwo(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'nextPowerOfTwo' only accept integer inputs\");\n\n\t\treturn detail::compute_ceilPowerOfTwo<L, T, Q, std::numeric_limits<T>::is_signed>::call(v);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prevPowerOfTwo(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'prevPowerOfTwo' only accept integer inputs\");\n\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(prevPowerOfTwo, v);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> isMultiple(vec<L, T, Q> const& Value, T Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'isMultiple' only accept integer inputs\");\n\n\t\treturn (Value % Multiple) == vec<L, T, Q>(0);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> isMultiple(vec<L, T, Q> const& Value, vec<L, T, Q> const& Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'isMultiple' only accept integer inputs\");\n\n\t\treturn (Value % Multiple) == vec<L, T, Q>(0);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> nextMultiple(vec<L, T, Q> const& Source, T Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'nextMultiple' only accept integer inputs\");\n\n\t\treturn detail::functor2<vec, L, T, Q>::call(nextMultiple, Source, vec<L, T, Q>(Multiple));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> nextMultiple(vec<L, T, Q> const& Source, vec<L, T, Q> const& Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'nextMultiple' only accept integer inputs\");\n\n\t\treturn detail::functor2<vec, L, T, Q>::call(nextMultiple, Source, Multiple);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prevMultiple(vec<L, T, Q> const& Source, T Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'prevMultiple' only accept integer inputs\");\n\n\t\treturn detail::functor2<vec, L, T, Q>::call(prevMultiple, Source, vec<L, T, Q>(Multiple));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prevMultiple(vec<L, T, Q> const& Source, vec<L, T, Q> const& Multiple)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'prevMultiple' only accept integer inputs\");\n\n\t\treturn detail::functor2<vec, L, T, Q>::call(prevMultiple, Source, Multiple);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> findNSB(vec<L, T, Q> const& Source, vec<L, int, Q> SignificantBitCount)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'findNSB' only accept integer inputs\");\n\n\t\treturn detail::functor2_vec_int<L, T, Q>::call(findNSB, Source, SignificantBitCount);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_packing.hpp",
    "content": "/// @ref ext_vector_packing\n/// @file glm/ext/vector_packing.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup ext_vector_packing GLM_EXT_vector_packing\n/// @ingroup ext\n///\n/// Include <glm/ext/vector_packing.hpp> to use the features of this extension.\n///\n/// This extension provides a set of function to convert vectors to packed\n/// formats.\n\n#pragma once\n\n// Dependency:\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_packing extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_packing\n\t/// @{\n\n\n\t/// @}\n}// namespace glm\n\n#include \"vector_packing.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_packing.inl",
    "content": ""
  },
  {
    "path": "lib/gli/glm/ext/vector_relational.hpp",
    "content": "/// @ref ext_vector_relational\n/// @file glm/ext/vector_relational.hpp\n///\n/// @see core (dependence)\n/// @see ext_scalar_integer (dependence)\n///\n/// @defgroup ext_vector_relational GLM_EXT_vector_relational\n/// @ingroup ext\n///\n/// Exposes comparison functions for vector types that take a user defined epsilon values.\n///\n/// Include <glm/ext/vector_relational.hpp> to use the features of this extension.\n///\n/// @see core_vector_relational\n/// @see ext_scalar_relational\n/// @see ext_matrix_relational\n\n#pragma once\n\n// Dependencies\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_relational extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_relational\n\t/// @{\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| >= epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| >= epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& epsilon);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, int ULPs);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, int, Q> const& ULPs);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, int ULPs);\n\n\t/// Returns the component-wise comparison between two vectors in term of ULPs.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, int, Q> const& ULPs);\n\n\t/// @}\n}//namespace glm\n\n#include \"vector_relational.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_relational.inl",
    "content": "#include \"../vector_relational.hpp\"\n#include \"../common.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/type_float.hpp\"\n\nnamespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T Epsilon)\n\t{\n\t\treturn equal(x, y, vec<L, T, Q>(Epsilon));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& Epsilon)\n\t{\n\t\treturn lessThanEqual(abs(x - y), Epsilon);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T Epsilon)\n\t{\n\t\treturn notEqual(x, y, vec<L, T, Q>(Epsilon));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& Epsilon)\n\t{\n\t\treturn greaterThan(abs(x - y), Epsilon);\n\t}\n\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, int MaxULPs)\n\t{\n\t\treturn equal(x, y, vec<L, int, Q>(MaxULPs));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, int, Q> const& MaxULPs)\n\t{\n\t\tvec<L, bool, Q> Result(false);\n\t\tfor(length_t i = 0; i < L; ++i)\n\t\t{\n\t\t\tdetail::float_t<T> const a(x[i]);\n\t\t\tdetail::float_t<T> const b(y[i]);\n\n\t\t\t// Different signs means they do not match.\n\t\t\tif(a.negative() != b.negative())\n\t\t\t{\n\t\t\t\t// Check for equality to make sure +0==-0\n\t\t\t\tResult[i] = a.mantissa() == b.mantissa() && a.exponent() == b.exponent();\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Find the difference in ULPs.\n\t\t\t\ttypename detail::float_t<T>::int_type const DiffULPs = abs(a.i - b.i);\n\t\t\t\tResult[i] = DiffULPs <= MaxULPs[i];\n\t\t\t}\n\t\t}\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, int MaxULPs)\n\t{\n\t\treturn notEqual(x, y, vec<L, int, Q>(MaxULPs));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, int, Q> const& MaxULPs)\n\t{\n\t\treturn not_(equal(x, y, MaxULPs));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint1.hpp",
    "content": "/// @ref ext_vector_uint1\n/// @file glm/ext/vector_uint1.hpp\n///\n/// @defgroup ext_vector_uint1 GLM_EXT_vector_uint1\n/// @ingroup ext\n///\n/// Exposes uvec1 vector type.\n///\n/// Include <glm/ext/vector_uvec1.hpp> to use the features of this extension.\n///\n/// @see ext_vector_int1 extension.\n/// @see ext_vector_uint1_precision extension.\n\n#pragma once\n\n#include \"../detail/type_vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_uint1 extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_uint1\n\t/// @{\n\n\t/// 1 component vector of unsigned integer numbers.\n\ttypedef vec<1, unsigned int, defaultp>\t\t\tuvec1;\n\n\t/// @}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint1_sized.hpp",
    "content": "/// @ref ext_vector_uint1_sized\n/// @file glm/ext/vector_uint1_sized.hpp\n///\n/// @defgroup ext_vector_uint1_sized GLM_EXT_vector_uint1_sized\n/// @ingroup ext\n///\n/// Exposes sized unsigned integer vector types.\n///\n/// Include <glm/ext/vector_uint1_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_uint_sized\n/// @see ext_vector_int1_sized\n\n#pragma once\n\n#include \"../ext/vector_uint1.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_uint1_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_uint1_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_uint1_sized\n\ttypedef vec<1, uint8, defaultp>\t\tu8vec1;\n\n\t/// 16 bit unsigned integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_uint1_sized\n\ttypedef vec<1, uint16, defaultp>\tu16vec1;\n\n\t/// 32 bit unsigned integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_uint1_sized\n\ttypedef vec<1, uint32, defaultp>\tu32vec1;\n\n\t/// 64 bit unsigned integer vector of 1 component type.\n\t///\n\t/// @see ext_vector_uint1_sized\n\ttypedef vec<1, uint64, defaultp>\tu64vec1;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint2.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_uint2.hpp\n\n#pragma once\n#include \"../detail/type_vec2.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 2 components vector of unsigned integer numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<2, unsigned int, defaultp>\t\tuvec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint2_sized.hpp",
    "content": "/// @ref ext_vector_uint2_sized\n/// @file glm/ext/vector_uint2_sized.hpp\n///\n/// @defgroup ext_vector_uint2_sized GLM_EXT_vector_uint2_sized\n/// @ingroup ext\n///\n/// Exposes sized unsigned integer vector of 2 components type.\n///\n/// Include <glm/ext/vector_uint2_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_uint_sized\n/// @see ext_vector_int2_sized\n\n#pragma once\n\n#include \"../ext/vector_uint2.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_uint2_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_uint2_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_uint2_sized\n\ttypedef vec<2, uint8, defaultp>\t\tu8vec2;\n\n\t/// 16 bit unsigned integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_uint2_sized\n\ttypedef vec<2, uint16, defaultp>\tu16vec2;\n\n\t/// 32 bit unsigned integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_uint2_sized\n\ttypedef vec<2, uint32, defaultp>\tu32vec2;\n\n\t/// 64 bit unsigned integer vector of 2 components type.\n\t///\n\t/// @see ext_vector_uint2_sized\n\ttypedef vec<2, uint64, defaultp>\tu64vec2;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint3.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_uint3.hpp\n\n#pragma once\n#include \"../detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 3 components vector of unsigned integer numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<3, unsigned int, defaultp>\t\tuvec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint3_sized.hpp",
    "content": "/// @ref ext_vector_uint3_sized\n/// @file glm/ext/vector_uint3_sized.hpp\n///\n/// @defgroup ext_vector_uint3_sized GLM_EXT_vector_uint3_sized\n/// @ingroup ext\n///\n/// Exposes sized unsigned integer vector of 3 components type.\n///\n/// Include <glm/ext/vector_uint3_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_uint_sized\n/// @see ext_vector_int3_sized\n\n#pragma once\n\n#include \"../ext/vector_uint3.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_uint3_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_uint3_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_uint3_sized\n\ttypedef vec<3, uint8, defaultp>\t\tu8vec3;\n\n\t/// 16 bit unsigned integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_uint3_sized\n\ttypedef vec<3, uint16, defaultp>\tu16vec3;\n\n\t/// 32 bit unsigned integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_uint3_sized\n\ttypedef vec<3, uint32, defaultp>\tu32vec3;\n\n\t/// 64 bit unsigned integer vector of 3 components type.\n\t///\n\t/// @see ext_vector_uint3_sized\n\ttypedef vec<3, uint64, defaultp>\tu64vec3;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint4.hpp",
    "content": "/// @ref core\n/// @file glm/ext/vector_uint4.hpp\n\n#pragma once\n#include \"../detail/type_vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_vector\n\t/// @{\n\n\t/// 4 components vector of unsigned integer numbers.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>\n\ttypedef vec<4, unsigned int, defaultp>\t\tuvec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_uint4_sized.hpp",
    "content": "/// @ref ext_vector_uint4_sized\n/// @file glm/ext/vector_uint4_sized.hpp\n///\n/// @defgroup ext_vector_uint4_sized GLM_EXT_vector_uint4_sized\n/// @ingroup ext\n///\n/// Exposes sized unsigned integer vector of 4 components type.\n///\n/// Include <glm/ext/vector_uint4_sized.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_uint_sized\n/// @see ext_vector_int4_sized\n\n#pragma once\n\n#include \"../ext/vector_uint4.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_uint4_sized extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup ext_vector_uint4_sized\n\t/// @{\n\n\t/// 8 bit unsigned integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_uint4_sized\n\ttypedef vec<4, uint8, defaultp>\t\tu8vec4;\n\n\t/// 16 bit unsigned integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_uint4_sized\n\ttypedef vec<4, uint16, defaultp>\tu16vec4;\n\n\t/// 32 bit unsigned integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_uint4_sized\n\ttypedef vec<4, uint32, defaultp>\tu32vec4;\n\n\t/// 64 bit unsigned integer vector of 4 components type.\n\t///\n\t/// @see ext_vector_uint4_sized\n\ttypedef vec<4, uint64, defaultp>\tu64vec4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_ulp.hpp",
    "content": "/// @ref ext_vector_ulp\n/// @file glm/ext/vector_ulp.hpp\n///\n/// @defgroup ext_vector_ulp GLM_EXT_vector_ulp\n/// @ingroup ext\n///\n/// Allow the measurement of the accuracy of a function against a reference\n/// implementation. This extension works on floating-point data and provide results\n/// in ULP.\n///\n/// Include <glm/ext/vector_ulp.hpp> to use the features of this extension.\n///\n/// @see ext_scalar_ulp\n/// @see ext_scalar_relational\n/// @see ext_vector_relational\n\n#pragma once\n\n// Dependencies\n#include \"../ext/scalar_ulp.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_EXT_vector_ulp extension included\")\n#endif\n\nnamespace glm\n{\n\t/// Return the next ULP value(s) after the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> nextFloat(vec<L, T, Q> const& x);\n\n\t/// Return the value(s) ULP distance after the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> nextFloat(vec<L, T, Q> const& x, int ULPs);\n\n\t/// Return the value(s) ULP distance after the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> nextFloat(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs);\n\n\t/// Return the previous ULP value(s) before the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prevFloat(vec<L, T, Q> const& x);\n\n\t/// Return the value(s) ULP distance before the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prevFloat(vec<L, T, Q> const& x, int ULPs);\n\n\t/// Return the value(s) ULP distance before the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prevFloat(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs);\n\n\t/// Return the distance in the number of ULP between 2 single-precision floating-point scalars.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> floatDistance(vec<L, float, Q> const& x, vec<L, float, Q> const& y);\n\n\t/// Return the distance in the number of ULP between 2 double-precision floating-point scalars.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_scalar_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int64, Q> floatDistance(vec<L, double, Q> const& x, vec<L, double, Q> const& y);\n\n\t/// @}\n}//namespace glm\n\n#include \"vector_ulp.inl\"\n"
  },
  {
    "path": "lib/gli/glm/ext/vector_ulp.inl",
    "content": "namespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> nextFloat(vec<L, T, Q> const& x)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = nextFloat(x[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> nextFloat(vec<L, T, Q> const& x, int ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = nextFloat(x[i], ULPs);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> nextFloat(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = nextFloat(x[i], ULPs[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prevFloat(vec<L, T, Q> const& x)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = prevFloat(x[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prevFloat(vec<L, T, Q> const& x, int ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = prevFloat(x[i], ULPs);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prevFloat(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = prevFloat(x[i], ULPs[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> floatDistance(vec<L, float, Q> const& x, vec<L, float, Q> const& y)\n\t{\n\t\tvec<L, int, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = floatDistance(x[i], y[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int64, Q> floatDistance(vec<L, double, Q> const& x, vec<L, double, Q> const& y)\n\t{\n\t\tvec<L, int64, Q> Result;\n\t\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = floatDistance(x[i], y[i]);\n\t\treturn Result;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/ext.hpp",
    "content": "/// @file glm/ext.hpp\n///\n/// @ref core (Dependence)\n\n#include \"detail/setup.hpp\"\n\n#pragma once\n\n#include \"glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_MESSAGE_EXT_INCLUDED_DISPLAYED)\n#\tdefine GLM_MESSAGE_EXT_INCLUDED_DISPLAYED\n#\tpragma message(\"GLM: All extensions included (not recommended)\")\n#endif//GLM_MESSAGES\n\n#include \"./ext/matrix_clip_space.hpp\"\n#include \"./ext/matrix_common.hpp\"\n\n#include \"./ext/matrix_double2x2.hpp\"\n#include \"./ext/matrix_double2x2_precision.hpp\"\n#include \"./ext/matrix_double2x3.hpp\"\n#include \"./ext/matrix_double2x3_precision.hpp\"\n#include \"./ext/matrix_double2x4.hpp\"\n#include \"./ext/matrix_double2x4_precision.hpp\"\n#include \"./ext/matrix_double3x2.hpp\"\n#include \"./ext/matrix_double3x2_precision.hpp\"\n#include \"./ext/matrix_double3x3.hpp\"\n#include \"./ext/matrix_double3x3_precision.hpp\"\n#include \"./ext/matrix_double3x4.hpp\"\n#include \"./ext/matrix_double3x4_precision.hpp\"\n#include \"./ext/matrix_double4x2.hpp\"\n#include \"./ext/matrix_double4x2_precision.hpp\"\n#include \"./ext/matrix_double4x3.hpp\"\n#include \"./ext/matrix_double4x3_precision.hpp\"\n#include \"./ext/matrix_double4x4.hpp\"\n#include \"./ext/matrix_double4x4_precision.hpp\"\n\n#include \"./ext/matrix_float2x2.hpp\"\n#include \"./ext/matrix_float2x2_precision.hpp\"\n#include \"./ext/matrix_float2x3.hpp\"\n#include \"./ext/matrix_float2x3_precision.hpp\"\n#include \"./ext/matrix_float2x4.hpp\"\n#include \"./ext/matrix_float2x4_precision.hpp\"\n#include \"./ext/matrix_float3x2.hpp\"\n#include \"./ext/matrix_float3x2_precision.hpp\"\n#include \"./ext/matrix_float3x3.hpp\"\n#include \"./ext/matrix_float3x3_precision.hpp\"\n#include \"./ext/matrix_float3x4.hpp\"\n#include \"./ext/matrix_float3x4_precision.hpp\"\n#include \"./ext/matrix_float4x2.hpp\"\n#include \"./ext/matrix_float4x2_precision.hpp\"\n#include \"./ext/matrix_float4x3.hpp\"\n#include \"./ext/matrix_float4x3_precision.hpp\"\n#include \"./ext/matrix_float4x4.hpp\"\n#include \"./ext/matrix_float4x4_precision.hpp\"\n\n#include \"./ext/matrix_int2x2.hpp\"\n#include \"./ext/matrix_int2x2_sized.hpp\"\n#include \"./ext/matrix_int2x3.hpp\"\n#include \"./ext/matrix_int2x3_sized.hpp\"\n#include \"./ext/matrix_int2x4.hpp\"\n#include \"./ext/matrix_int2x4_sized.hpp\"\n#include \"./ext/matrix_int3x2.hpp\"\n#include \"./ext/matrix_int3x2_sized.hpp\"\n#include \"./ext/matrix_int3x3.hpp\"\n#include \"./ext/matrix_int3x3_sized.hpp\"\n#include \"./ext/matrix_int3x4.hpp\"\n#include \"./ext/matrix_int3x4_sized.hpp\"\n#include \"./ext/matrix_int4x2.hpp\"\n#include \"./ext/matrix_int4x2_sized.hpp\"\n#include \"./ext/matrix_int4x3.hpp\"\n#include \"./ext/matrix_int4x3_sized.hpp\"\n#include \"./ext/matrix_int4x4.hpp\"\n#include \"./ext/matrix_int4x4_sized.hpp\"\n\n#include \"./ext/matrix_uint2x2.hpp\"\n#include \"./ext/matrix_uint2x2_sized.hpp\"\n#include \"./ext/matrix_uint2x3.hpp\"\n#include \"./ext/matrix_uint2x3_sized.hpp\"\n#include \"./ext/matrix_uint2x4.hpp\"\n#include \"./ext/matrix_uint2x4_sized.hpp\"\n#include \"./ext/matrix_uint3x2.hpp\"\n#include \"./ext/matrix_uint3x2_sized.hpp\"\n#include \"./ext/matrix_uint3x3.hpp\"\n#include \"./ext/matrix_uint3x3_sized.hpp\"\n#include \"./ext/matrix_uint3x4.hpp\"\n#include \"./ext/matrix_uint3x4_sized.hpp\"\n#include \"./ext/matrix_uint4x2.hpp\"\n#include \"./ext/matrix_uint4x2_sized.hpp\"\n#include \"./ext/matrix_uint4x3.hpp\"\n#include \"./ext/matrix_uint4x3_sized.hpp\"\n#include \"./ext/matrix_uint4x4.hpp\"\n#include \"./ext/matrix_uint4x4_sized.hpp\"\n\n#include \"./ext/matrix_projection.hpp\"\n#include \"./ext/matrix_relational.hpp\"\n#include \"./ext/matrix_transform.hpp\"\n\n#include \"./ext/quaternion_common.hpp\"\n#include \"./ext/quaternion_double.hpp\"\n#include \"./ext/quaternion_double_precision.hpp\"\n#include \"./ext/quaternion_float.hpp\"\n#include \"./ext/quaternion_float_precision.hpp\"\n#include \"./ext/quaternion_exponential.hpp\"\n#include \"./ext/quaternion_geometric.hpp\"\n#include \"./ext/quaternion_relational.hpp\"\n#include \"./ext/quaternion_transform.hpp\"\n#include \"./ext/quaternion_trigonometric.hpp\"\n\n#include \"./ext/scalar_common.hpp\"\n#include \"./ext/scalar_constants.hpp\"\n#include \"./ext/scalar_integer.hpp\"\n#include \"./ext/scalar_packing.hpp\"\n#include \"./ext/scalar_relational.hpp\"\n#include \"./ext/scalar_ulp.hpp\"\n\n#include \"./ext/scalar_int_sized.hpp\"\n#include \"./ext/scalar_uint_sized.hpp\"\n\n#include \"./ext/vector_common.hpp\"\n#include \"./ext/vector_integer.hpp\"\n#include \"./ext/vector_packing.hpp\"\n#include \"./ext/vector_relational.hpp\"\n#include \"./ext/vector_ulp.hpp\"\n\n#include \"./ext/vector_bool1.hpp\"\n#include \"./ext/vector_bool1_precision.hpp\"\n#include \"./ext/vector_bool2.hpp\"\n#include \"./ext/vector_bool2_precision.hpp\"\n#include \"./ext/vector_bool3.hpp\"\n#include \"./ext/vector_bool3_precision.hpp\"\n#include \"./ext/vector_bool4.hpp\"\n#include \"./ext/vector_bool4_precision.hpp\"\n\n#include \"./ext/vector_double1.hpp\"\n#include \"./ext/vector_double1_precision.hpp\"\n#include \"./ext/vector_double2.hpp\"\n#include \"./ext/vector_double2_precision.hpp\"\n#include \"./ext/vector_double3.hpp\"\n#include \"./ext/vector_double3_precision.hpp\"\n#include \"./ext/vector_double4.hpp\"\n#include \"./ext/vector_double4_precision.hpp\"\n\n#include \"./ext/vector_float1.hpp\"\n#include \"./ext/vector_float1_precision.hpp\"\n#include \"./ext/vector_float2.hpp\"\n#include \"./ext/vector_float2_precision.hpp\"\n#include \"./ext/vector_float3.hpp\"\n#include \"./ext/vector_float3_precision.hpp\"\n#include \"./ext/vector_float4.hpp\"\n#include \"./ext/vector_float4_precision.hpp\"\n\n#include \"./ext/vector_int1.hpp\"\n#include \"./ext/vector_int1_sized.hpp\"\n#include \"./ext/vector_int2.hpp\"\n#include \"./ext/vector_int2_sized.hpp\"\n#include \"./ext/vector_int3.hpp\"\n#include \"./ext/vector_int3_sized.hpp\"\n#include \"./ext/vector_int4.hpp\"\n#include \"./ext/vector_int4_sized.hpp\"\n\n#include \"./ext/vector_uint1.hpp\"\n#include \"./ext/vector_uint1_sized.hpp\"\n#include \"./ext/vector_uint2.hpp\"\n#include \"./ext/vector_uint2_sized.hpp\"\n#include \"./ext/vector_uint3.hpp\"\n#include \"./ext/vector_uint3_sized.hpp\"\n#include \"./ext/vector_uint4.hpp\"\n#include \"./ext/vector_uint4_sized.hpp\"\n\n#include \"./gtc/bitfield.hpp\"\n#include \"./gtc/color_space.hpp\"\n#include \"./gtc/constants.hpp\"\n#include \"./gtc/epsilon.hpp\"\n#include \"./gtc/integer.hpp\"\n#include \"./gtc/matrix_access.hpp\"\n#include \"./gtc/matrix_integer.hpp\"\n#include \"./gtc/matrix_inverse.hpp\"\n#include \"./gtc/matrix_transform.hpp\"\n#include \"./gtc/noise.hpp\"\n#include \"./gtc/packing.hpp\"\n#include \"./gtc/quaternion.hpp\"\n#include \"./gtc/random.hpp\"\n#include \"./gtc/reciprocal.hpp\"\n#include \"./gtc/round.hpp\"\n#include \"./gtc/type_precision.hpp\"\n#include \"./gtc/type_ptr.hpp\"\n#include \"./gtc/ulp.hpp\"\n#include \"./gtc/vec1.hpp\"\n#if GLM_CONFIG_ALIGNED_GENTYPES == GLM_ENABLE\n#\tinclude \"./gtc/type_aligned.hpp\"\n#endif\n\n#ifdef GLM_ENABLE_EXPERIMENTAL\n#include \"./gtx/associated_min_max.hpp\"\n#include \"./gtx/bit.hpp\"\n#include \"./gtx/closest_point.hpp\"\n#include \"./gtx/color_encoding.hpp\"\n#include \"./gtx/color_space.hpp\"\n#include \"./gtx/color_space_YCoCg.hpp\"\n#include \"./gtx/compatibility.hpp\"\n#include \"./gtx/component_wise.hpp\"\n#include \"./gtx/dual_quaternion.hpp\"\n#include \"./gtx/euler_angles.hpp\"\n#include \"./gtx/extend.hpp\"\n#include \"./gtx/extended_min_max.hpp\"\n#include \"./gtx/fast_exponential.hpp\"\n#include \"./gtx/fast_square_root.hpp\"\n#include \"./gtx/fast_trigonometry.hpp\"\n#include \"./gtx/functions.hpp\"\n#include \"./gtx/gradient_paint.hpp\"\n#include \"./gtx/handed_coordinate_space.hpp\"\n#include \"./gtx/integer.hpp\"\n#include \"./gtx/intersect.hpp\"\n#include \"./gtx/log_base.hpp\"\n#include \"./gtx/matrix_cross_product.hpp\"\n#include \"./gtx/matrix_interpolation.hpp\"\n#include \"./gtx/matrix_major_storage.hpp\"\n#include \"./gtx/matrix_operation.hpp\"\n#include \"./gtx/matrix_query.hpp\"\n#include \"./gtx/mixed_product.hpp\"\n#include \"./gtx/norm.hpp\"\n#include \"./gtx/normal.hpp\"\n#include \"./gtx/normalize_dot.hpp\"\n#include \"./gtx/number_precision.hpp\"\n#include \"./gtx/optimum_pow.hpp\"\n#include \"./gtx/orthonormalize.hpp\"\n#include \"./gtx/perpendicular.hpp\"\n#include \"./gtx/polar_coordinates.hpp\"\n#include \"./gtx/projection.hpp\"\n#include \"./gtx/quaternion.hpp\"\n#include \"./gtx/raw_data.hpp\"\n#include \"./gtx/rotate_vector.hpp\"\n#include \"./gtx/spline.hpp\"\n#include \"./gtx/std_based_type.hpp\"\n#if !(GLM_COMPILER & GLM_COMPILER_CUDA)\n#\tinclude \"./gtx/string_cast.hpp\"\n#endif\n#include \"./gtx/transform.hpp\"\n#include \"./gtx/transform2.hpp\"\n#include \"./gtx/vec_swizzle.hpp\"\n#include \"./gtx/vector_angle.hpp\"\n#include \"./gtx/vector_query.hpp\"\n#include \"./gtx/wrap.hpp\"\n\n#if GLM_HAS_TEMPLATE_ALIASES\n#\tinclude \"./gtx/scalar_multiplication.hpp\"\n#endif\n\n#if GLM_HAS_RANGE_FOR\n#\tinclude \"./gtx/range.hpp\"\n#endif\n#endif//GLM_ENABLE_EXPERIMENTAL\n"
  },
  {
    "path": "lib/gli/glm/fwd.hpp",
    "content": "#pragma once\n\n#include \"detail/qualifier.hpp\"\n\nnamespace glm\n{\n#if GLM_HAS_EXTENDED_INTEGER_TYPE\n\ttypedef std::int8_t\t\t\t\tint8;\n\ttypedef std::int16_t\t\t\tint16;\n\ttypedef std::int32_t\t\t\tint32;\n\ttypedef std::int64_t\t\t\tint64;\n\n\ttypedef std::uint8_t\t\t\tuint8;\n\ttypedef std::uint16_t\t\t\tuint16;\n\ttypedef std::uint32_t\t\t\tuint32;\n\ttypedef std::uint64_t\t\t\tuint64;\n#else\n\ttypedef signed char\t\t\t\tint8;\n\ttypedef signed short\t\t\tint16;\n\ttypedef signed int\t\t\t\tint32;\n\ttypedef detail::int64\t\t\tint64;\n\n\ttypedef unsigned char\t\t\tuint8;\n\ttypedef unsigned short\t\t\tuint16;\n\ttypedef unsigned int\t\t\tuint32;\n\ttypedef detail::uint64\t\t\tuint64;\n#endif\n\n\t// Scalar int\n\n\ttypedef int8\t\t\t\t\tlowp_i8;\n\ttypedef int8\t\t\t\t\tmediump_i8;\n\ttypedef int8\t\t\t\t\thighp_i8;\n\ttypedef int8\t\t\t\t\ti8;\n\n\ttypedef int8\t\t\t\t\tlowp_int8;\n\ttypedef int8\t\t\t\t\tmediump_int8;\n\ttypedef int8\t\t\t\t\thighp_int8;\n\n\ttypedef int8\t\t\t\t\tlowp_int8_t;\n\ttypedef int8\t\t\t\t\tmediump_int8_t;\n\ttypedef int8\t\t\t\t\thighp_int8_t;\n\ttypedef int8\t\t\t\t\tint8_t;\n\n\ttypedef int16\t\t\t\t\tlowp_i16;\n\ttypedef int16\t\t\t\t\tmediump_i16;\n\ttypedef int16\t\t\t\t\thighp_i16;\n\ttypedef int16\t\t\t\t\ti16;\n\n\ttypedef int16\t\t\t\t\tlowp_int16;\n\ttypedef int16\t\t\t\t\tmediump_int16;\n\ttypedef int16\t\t\t\t\thighp_int16;\n\n\ttypedef int16\t\t\t\t\tlowp_int16_t;\n\ttypedef int16\t\t\t\t\tmediump_int16_t;\n\ttypedef int16\t\t\t\t\thighp_int16_t;\n\ttypedef int16\t\t\t\t\tint16_t;\n\n\ttypedef int32\t\t\t\t\tlowp_i32;\n\ttypedef int32\t\t\t\t\tmediump_i32;\n\ttypedef int32\t\t\t\t\thighp_i32;\n\ttypedef int32\t\t\t\t\ti32;\n\n\ttypedef int32\t\t\t\t\tlowp_int32;\n\ttypedef int32\t\t\t\t\tmediump_int32;\n\ttypedef int32\t\t\t\t\thighp_int32;\n\n\ttypedef int32\t\t\t\t\tlowp_int32_t;\n\ttypedef int32\t\t\t\t\tmediump_int32_t;\n\ttypedef int32\t\t\t\t\thighp_int32_t;\n\ttypedef int32\t\t\t\t\tint32_t;\n\n\ttypedef int64\t\t\t\t\tlowp_i64;\n\ttypedef int64\t\t\t\t\tmediump_i64;\n\ttypedef int64\t\t\t\t\thighp_i64;\n\ttypedef int64\t\t\t\t\ti64;\n\n\ttypedef int64\t\t\t\t\tlowp_int64;\n\ttypedef int64\t\t\t\t\tmediump_int64;\n\ttypedef int64\t\t\t\t\thighp_int64;\n\n\ttypedef int64\t\t\t\t\tlowp_int64_t;\n\ttypedef int64\t\t\t\t\tmediump_int64_t;\n\ttypedef int64\t\t\t\t\thighp_int64_t;\n\ttypedef int64\t\t\t\t\tint64_t;\n\n\t// Scalar uint\n\n\ttypedef unsigned int\t\t\tuint;\n\n\ttypedef uint8\t\t\t\t\tlowp_u8;\n\ttypedef uint8\t\t\t\t\tmediump_u8;\n\ttypedef uint8\t\t\t\t\thighp_u8;\n\ttypedef uint8\t\t\t\t\tu8;\n\n\ttypedef uint8\t\t\t\t\tlowp_uint8;\n\ttypedef uint8\t\t\t\t\tmediump_uint8;\n\ttypedef uint8\t\t\t\t\thighp_uint8;\n\n\ttypedef uint8\t\t\t\t\tlowp_uint8_t;\n\ttypedef uint8\t\t\t\t\tmediump_uint8_t;\n\ttypedef uint8\t\t\t\t\thighp_uint8_t;\n\ttypedef uint8\t\t\t\t\tuint8_t;\n\n\ttypedef uint16\t\t\t\t\tlowp_u16;\n\ttypedef uint16\t\t\t\t\tmediump_u16;\n\ttypedef uint16\t\t\t\t\thighp_u16;\n\ttypedef uint16\t\t\t\t\tu16;\n\n\ttypedef uint16\t\t\t\t\tlowp_uint16;\n\ttypedef uint16\t\t\t\t\tmediump_uint16;\n\ttypedef uint16\t\t\t\t\thighp_uint16;\n\n\ttypedef uint16\t\t\t\t\tlowp_uint16_t;\n\ttypedef uint16\t\t\t\t\tmediump_uint16_t;\n\ttypedef uint16\t\t\t\t\thighp_uint16_t;\n\ttypedef uint16\t\t\t\t\tuint16_t;\n\n\ttypedef uint32\t\t\t\t\tlowp_u32;\n\ttypedef uint32\t\t\t\t\tmediump_u32;\n\ttypedef uint32\t\t\t\t\thighp_u32;\n\ttypedef uint32\t\t\t\t\tu32;\n\n\ttypedef uint32\t\t\t\t\tlowp_uint32;\n\ttypedef uint32\t\t\t\t\tmediump_uint32;\n\ttypedef uint32\t\t\t\t\thighp_uint32;\n\n\ttypedef uint32\t\t\t\t\tlowp_uint32_t;\n\ttypedef uint32\t\t\t\t\tmediump_uint32_t;\n\ttypedef uint32\t\t\t\t\thighp_uint32_t;\n\ttypedef uint32\t\t\t\t\tuint32_t;\n\n\ttypedef uint64\t\t\t\t\tlowp_u64;\n\ttypedef uint64\t\t\t\t\tmediump_u64;\n\ttypedef uint64\t\t\t\t\thighp_u64;\n\ttypedef uint64\t\t\t\t\tu64;\n\n\ttypedef uint64\t\t\t\t\tlowp_uint64;\n\ttypedef uint64\t\t\t\t\tmediump_uint64;\n\ttypedef uint64\t\t\t\t\thighp_uint64;\n\n\ttypedef uint64\t\t\t\t\tlowp_uint64_t;\n\ttypedef uint64\t\t\t\t\tmediump_uint64_t;\n\ttypedef uint64\t\t\t\t\thighp_uint64_t;\n\ttypedef uint64\t\t\t\t\tuint64_t;\n\n\t// Scalar float\n\n\ttypedef float\t\t\t\t\tlowp_f32;\n\ttypedef float\t\t\t\t\tmediump_f32;\n\ttypedef float\t\t\t\t\thighp_f32;\n\ttypedef float\t\t\t\t\tf32;\n\n\ttypedef float\t\t\t\t\tlowp_float32;\n\ttypedef float\t\t\t\t\tmediump_float32;\n\ttypedef float\t\t\t\t\thighp_float32;\n\ttypedef float\t\t\t\t\tfloat32;\n\n\ttypedef float\t\t\t\t\tlowp_float32_t;\n\ttypedef float\t\t\t\t\tmediump_float32_t;\n\ttypedef float\t\t\t\t\thighp_float32_t;\n\ttypedef float\t\t\t\t\tfloat32_t;\n\n\n\ttypedef double\t\t\t\t\tlowp_f64;\n\ttypedef double\t\t\t\t\tmediump_f64;\n\ttypedef double\t\t\t\t\thighp_f64;\n\ttypedef double\t\t\t\t\tf64;\n\n\ttypedef double\t\t\t\t\tlowp_float64;\n\ttypedef double\t\t\t\t\tmediump_float64;\n\ttypedef double\t\t\t\t\thighp_float64;\n\ttypedef double\t\t\t\t\tfloat64;\n\n\ttypedef double\t\t\t\t\tlowp_float64_t;\n\ttypedef double\t\t\t\t\tmediump_float64_t;\n\ttypedef double\t\t\t\t\thighp_float64_t;\n\ttypedef double\t\t\t\t\tfloat64_t;\n\n\t// Vector bool\n\n\ttypedef vec<1, bool, lowp>\t\tlowp_bvec1;\n\ttypedef vec<2, bool, lowp>\t\tlowp_bvec2;\n\ttypedef vec<3, bool, lowp>\t\tlowp_bvec3;\n\ttypedef vec<4, bool, lowp>\t\tlowp_bvec4;\n\n\ttypedef vec<1, bool, mediump>\tmediump_bvec1;\n\ttypedef vec<2, bool, mediump>\tmediump_bvec2;\n\ttypedef vec<3, bool, mediump>\tmediump_bvec3;\n\ttypedef vec<4, bool, mediump>\tmediump_bvec4;\n\n\ttypedef vec<1, bool, highp>\t\thighp_bvec1;\n\ttypedef vec<2, bool, highp>\t\thighp_bvec2;\n\ttypedef vec<3, bool, highp>\t\thighp_bvec3;\n\ttypedef vec<4, bool, highp>\t\thighp_bvec4;\n\n\ttypedef vec<1, bool, defaultp>\tbvec1;\n\ttypedef vec<2, bool, defaultp>\tbvec2;\n\ttypedef vec<3, bool, defaultp>\tbvec3;\n\ttypedef vec<4, bool, defaultp>\tbvec4;\n\n\t// Vector int\n\n\ttypedef vec<1, int, lowp>\t\tlowp_ivec1;\n\ttypedef vec<2, int, lowp>\t\tlowp_ivec2;\n\ttypedef vec<3, int, lowp>\t\tlowp_ivec3;\n\ttypedef vec<4, int, lowp>\t\tlowp_ivec4;\n\n\ttypedef vec<1, int, mediump>\tmediump_ivec1;\n\ttypedef vec<2, int, mediump>\tmediump_ivec2;\n\ttypedef vec<3, int, mediump>\tmediump_ivec3;\n\ttypedef vec<4, int, mediump>\tmediump_ivec4;\n\n\ttypedef vec<1, int, highp>\t\thighp_ivec1;\n\ttypedef vec<2, int, highp>\t\thighp_ivec2;\n\ttypedef vec<3, int, highp>\t\thighp_ivec3;\n\ttypedef vec<4, int, highp>\t\thighp_ivec4;\n\n\ttypedef vec<1, int, defaultp>\tivec1;\n\ttypedef vec<2, int, defaultp>\tivec2;\n\ttypedef vec<3, int, defaultp>\tivec3;\n\ttypedef vec<4, int, defaultp>\tivec4;\n\n\ttypedef vec<1, i8, lowp>\t\tlowp_i8vec1;\n\ttypedef vec<2, i8, lowp>\t\tlowp_i8vec2;\n\ttypedef vec<3, i8, lowp>\t\tlowp_i8vec3;\n\ttypedef vec<4, i8, lowp>\t\tlowp_i8vec4;\n\n\ttypedef vec<1, i8, mediump>\t\tmediump_i8vec1;\n\ttypedef vec<2, i8, mediump>\t\tmediump_i8vec2;\n\ttypedef vec<3, i8, mediump>\t\tmediump_i8vec3;\n\ttypedef vec<4, i8, mediump>\t\tmediump_i8vec4;\n\n\ttypedef vec<1, i8, highp>\t\thighp_i8vec1;\n\ttypedef vec<2, i8, highp>\t\thighp_i8vec2;\n\ttypedef vec<3, i8, highp>\t\thighp_i8vec3;\n\ttypedef vec<4, i8, highp>\t\thighp_i8vec4;\n\n\ttypedef vec<1, i8, defaultp>\ti8vec1;\n\ttypedef vec<2, i8, defaultp>\ti8vec2;\n\ttypedef vec<3, i8, defaultp>\ti8vec3;\n\ttypedef vec<4, i8, defaultp>\ti8vec4;\n\n\ttypedef vec<1, i16, lowp>\t\tlowp_i16vec1;\n\ttypedef vec<2, i16, lowp>\t\tlowp_i16vec2;\n\ttypedef vec<3, i16, lowp>\t\tlowp_i16vec3;\n\ttypedef vec<4, i16, lowp>\t\tlowp_i16vec4;\n\n\ttypedef vec<1, i16, mediump>\tmediump_i16vec1;\n\ttypedef vec<2, i16, mediump>\tmediump_i16vec2;\n\ttypedef vec<3, i16, mediump>\tmediump_i16vec3;\n\ttypedef vec<4, i16, mediump>\tmediump_i16vec4;\n\n\ttypedef vec<1, i16, highp>\t\thighp_i16vec1;\n\ttypedef vec<2, i16, highp>\t\thighp_i16vec2;\n\ttypedef vec<3, i16, highp>\t\thighp_i16vec3;\n\ttypedef vec<4, i16, highp>\t\thighp_i16vec4;\n\n\ttypedef vec<1, i16, defaultp>\ti16vec1;\n\ttypedef vec<2, i16, defaultp>\ti16vec2;\n\ttypedef vec<3, i16, defaultp>\ti16vec3;\n\ttypedef vec<4, i16, defaultp>\ti16vec4;\n\n\ttypedef vec<1, i32, lowp>\t\tlowp_i32vec1;\n\ttypedef vec<2, i32, lowp>\t\tlowp_i32vec2;\n\ttypedef vec<3, i32, lowp>\t\tlowp_i32vec3;\n\ttypedef vec<4, i32, lowp>\t\tlowp_i32vec4;\n\n\ttypedef vec<1, i32, mediump>\tmediump_i32vec1;\n\ttypedef vec<2, i32, mediump>\tmediump_i32vec2;\n\ttypedef vec<3, i32, mediump>\tmediump_i32vec3;\n\ttypedef vec<4, i32, mediump>\tmediump_i32vec4;\n\n\ttypedef vec<1, i32, highp>\t\thighp_i32vec1;\n\ttypedef vec<2, i32, highp>\t\thighp_i32vec2;\n\ttypedef vec<3, i32, highp>\t\thighp_i32vec3;\n\ttypedef vec<4, i32, highp>\t\thighp_i32vec4;\n\n\ttypedef vec<1, i32, defaultp>\ti32vec1;\n\ttypedef vec<2, i32, defaultp>\ti32vec2;\n\ttypedef vec<3, i32, defaultp>\ti32vec3;\n\ttypedef vec<4, i32, defaultp>\ti32vec4;\n\n\ttypedef vec<1, i64, lowp>\t\tlowp_i64vec1;\n\ttypedef vec<2, i64, lowp>\t\tlowp_i64vec2;\n\ttypedef vec<3, i64, lowp>\t\tlowp_i64vec3;\n\ttypedef vec<4, i64, lowp>\t\tlowp_i64vec4;\n\n\ttypedef vec<1, i64, mediump>\tmediump_i64vec1;\n\ttypedef vec<2, i64, mediump>\tmediump_i64vec2;\n\ttypedef vec<3, i64, mediump>\tmediump_i64vec3;\n\ttypedef vec<4, i64, mediump>\tmediump_i64vec4;\n\n\ttypedef vec<1, i64, highp>\t\thighp_i64vec1;\n\ttypedef vec<2, i64, highp>\t\thighp_i64vec2;\n\ttypedef vec<3, i64, highp>\t\thighp_i64vec3;\n\ttypedef vec<4, i64, highp>\t\thighp_i64vec4;\n\n\ttypedef vec<1, i64, defaultp>\ti64vec1;\n\ttypedef vec<2, i64, defaultp>\ti64vec2;\n\ttypedef vec<3, i64, defaultp>\ti64vec3;\n\ttypedef vec<4, i64, defaultp>\ti64vec4;\n\n\t// Vector uint\n\n\ttypedef vec<1, uint, lowp>\t\tlowp_uvec1;\n\ttypedef vec<2, uint, lowp>\t\tlowp_uvec2;\n\ttypedef vec<3, uint, lowp>\t\tlowp_uvec3;\n\ttypedef vec<4, uint, lowp>\t\tlowp_uvec4;\n\n\ttypedef vec<1, uint, mediump>\tmediump_uvec1;\n\ttypedef vec<2, uint, mediump>\tmediump_uvec2;\n\ttypedef vec<3, uint, mediump>\tmediump_uvec3;\n\ttypedef vec<4, uint, mediump>\tmediump_uvec4;\n\n\ttypedef vec<1, uint, highp>\t\thighp_uvec1;\n\ttypedef vec<2, uint, highp>\t\thighp_uvec2;\n\ttypedef vec<3, uint, highp>\t\thighp_uvec3;\n\ttypedef vec<4, uint, highp>\t\thighp_uvec4;\n\n\ttypedef vec<1, uint, defaultp>\tuvec1;\n\ttypedef vec<2, uint, defaultp>\tuvec2;\n\ttypedef vec<3, uint, defaultp>\tuvec3;\n\ttypedef vec<4, uint, defaultp>\tuvec4;\n\n\ttypedef vec<1, u8, lowp>\t\tlowp_u8vec1;\n\ttypedef vec<2, u8, lowp>\t\tlowp_u8vec2;\n\ttypedef vec<3, u8, lowp>\t\tlowp_u8vec3;\n\ttypedef vec<4, u8, lowp>\t\tlowp_u8vec4;\n\n\ttypedef vec<1, u8, mediump>\t\tmediump_u8vec1;\n\ttypedef vec<2, u8, mediump>\t\tmediump_u8vec2;\n\ttypedef vec<3, u8, mediump>\t\tmediump_u8vec3;\n\ttypedef vec<4, u8, mediump>\t\tmediump_u8vec4;\n\n\ttypedef vec<1, u8, highp>\t\thighp_u8vec1;\n\ttypedef vec<2, u8, highp>\t\thighp_u8vec2;\n\ttypedef vec<3, u8, highp>\t\thighp_u8vec3;\n\ttypedef vec<4, u8, highp>\t\thighp_u8vec4;\n\n\ttypedef vec<1, u8, defaultp>\tu8vec1;\n\ttypedef vec<2, u8, defaultp>\tu8vec2;\n\ttypedef vec<3, u8, defaultp>\tu8vec3;\n\ttypedef vec<4, u8, defaultp>\tu8vec4;\n\n\ttypedef vec<1, u16, lowp>\t\tlowp_u16vec1;\n\ttypedef vec<2, u16, lowp>\t\tlowp_u16vec2;\n\ttypedef vec<3, u16, lowp>\t\tlowp_u16vec3;\n\ttypedef vec<4, u16, lowp>\t\tlowp_u16vec4;\n\n\ttypedef vec<1, u16, mediump>\tmediump_u16vec1;\n\ttypedef vec<2, u16, mediump>\tmediump_u16vec2;\n\ttypedef vec<3, u16, mediump>\tmediump_u16vec3;\n\ttypedef vec<4, u16, mediump>\tmediump_u16vec4;\n\n\ttypedef vec<1, u16, highp>\t\thighp_u16vec1;\n\ttypedef vec<2, u16, highp>\t\thighp_u16vec2;\n\ttypedef vec<3, u16, highp>\t\thighp_u16vec3;\n\ttypedef vec<4, u16, highp>\t\thighp_u16vec4;\n\n\ttypedef vec<1, u16, defaultp>\tu16vec1;\n\ttypedef vec<2, u16, defaultp>\tu16vec2;\n\ttypedef vec<3, u16, defaultp>\tu16vec3;\n\ttypedef vec<4, u16, defaultp>\tu16vec4;\n\n\ttypedef vec<1, u32, lowp>\t\tlowp_u32vec1;\n\ttypedef vec<2, u32, lowp>\t\tlowp_u32vec2;\n\ttypedef vec<3, u32, lowp>\t\tlowp_u32vec3;\n\ttypedef vec<4, u32, lowp>\t\tlowp_u32vec4;\n\n\ttypedef vec<1, u32, mediump>\tmediump_u32vec1;\n\ttypedef vec<2, u32, mediump>\tmediump_u32vec2;\n\ttypedef vec<3, u32, mediump>\tmediump_u32vec3;\n\ttypedef vec<4, u32, mediump>\tmediump_u32vec4;\n\n\ttypedef vec<1, u32, highp>\t\thighp_u32vec1;\n\ttypedef vec<2, u32, highp>\t\thighp_u32vec2;\n\ttypedef vec<3, u32, highp>\t\thighp_u32vec3;\n\ttypedef vec<4, u32, highp>\t\thighp_u32vec4;\n\n\ttypedef vec<1, u32, defaultp>\tu32vec1;\n\ttypedef vec<2, u32, defaultp>\tu32vec2;\n\ttypedef vec<3, u32, defaultp>\tu32vec3;\n\ttypedef vec<4, u32, defaultp>\tu32vec4;\n\n\ttypedef vec<1, u64, lowp>\t\tlowp_u64vec1;\n\ttypedef vec<2, u64, lowp>\t\tlowp_u64vec2;\n\ttypedef vec<3, u64, lowp>\t\tlowp_u64vec3;\n\ttypedef vec<4, u64, lowp>\t\tlowp_u64vec4;\n\n\ttypedef vec<1, u64, mediump>\tmediump_u64vec1;\n\ttypedef vec<2, u64, mediump>\tmediump_u64vec2;\n\ttypedef vec<3, u64, mediump>\tmediump_u64vec3;\n\ttypedef vec<4, u64, mediump>\tmediump_u64vec4;\n\n\ttypedef vec<1, u64, highp>\t\thighp_u64vec1;\n\ttypedef vec<2, u64, highp>\t\thighp_u64vec2;\n\ttypedef vec<3, u64, highp>\t\thighp_u64vec3;\n\ttypedef vec<4, u64, highp>\t\thighp_u64vec4;\n\n\ttypedef vec<1, u64, defaultp>\tu64vec1;\n\ttypedef vec<2, u64, defaultp>\tu64vec2;\n\ttypedef vec<3, u64, defaultp>\tu64vec3;\n\ttypedef vec<4, u64, defaultp>\tu64vec4;\n\n\t// Vector float\n\n\ttypedef vec<1, float, lowp>\t\t\tlowp_vec1;\n\ttypedef vec<2, float, lowp>\t\t\tlowp_vec2;\n\ttypedef vec<3, float, lowp>\t\t\tlowp_vec3;\n\ttypedef vec<4, float, lowp>\t\t\tlowp_vec4;\n\n\ttypedef vec<1, float, mediump>\t\tmediump_vec1;\n\ttypedef vec<2, float, mediump>\t\tmediump_vec2;\n\ttypedef vec<3, float, mediump>\t\tmediump_vec3;\n\ttypedef vec<4, float, mediump>\t\tmediump_vec4;\n\n\ttypedef vec<1, float, highp>\t\thighp_vec1;\n\ttypedef vec<2, float, highp>\t\thighp_vec2;\n\ttypedef vec<3, float, highp>\t\thighp_vec3;\n\ttypedef vec<4, float, highp>\t\thighp_vec4;\n\n\ttypedef vec<1, float, defaultp>\t\tvec1;\n\ttypedef vec<2, float, defaultp>\t\tvec2;\n\ttypedef vec<3, float, defaultp>\t\tvec3;\n\ttypedef vec<4, float, defaultp>\t\tvec4;\n\n\ttypedef vec<1, float, lowp>\t\t\tlowp_fvec1;\n\ttypedef vec<2, float, lowp>\t\t\tlowp_fvec2;\n\ttypedef vec<3, float, lowp>\t\t\tlowp_fvec3;\n\ttypedef vec<4, float, lowp>\t\t\tlowp_fvec4;\n\n\ttypedef vec<1, float, mediump>\t\tmediump_fvec1;\n\ttypedef vec<2, float, mediump>\t\tmediump_fvec2;\n\ttypedef vec<3, float, mediump>\t\tmediump_fvec3;\n\ttypedef vec<4, float, mediump>\t\tmediump_fvec4;\n\n\ttypedef vec<1, float, highp>\t\thighp_fvec1;\n\ttypedef vec<2, float, highp>\t\thighp_fvec2;\n\ttypedef vec<3, float, highp>\t\thighp_fvec3;\n\ttypedef vec<4, float, highp>\t\thighp_fvec4;\n\n\ttypedef vec<1, f32, defaultp>\t\tfvec1;\n\ttypedef vec<2, f32, defaultp>\t\tfvec2;\n\ttypedef vec<3, f32, defaultp>\t\tfvec3;\n\ttypedef vec<4, f32, defaultp>\t\tfvec4;\n\n\ttypedef vec<1, f32, lowp>\t\t\tlowp_f32vec1;\n\ttypedef vec<2, f32, lowp>\t\t\tlowp_f32vec2;\n\ttypedef vec<3, f32, lowp>\t\t\tlowp_f32vec3;\n\ttypedef vec<4, f32, lowp>\t\t\tlowp_f32vec4;\n\n\ttypedef vec<1, f32, mediump>\t\tmediump_f32vec1;\n\ttypedef vec<2, f32, mediump>\t\tmediump_f32vec2;\n\ttypedef vec<3, f32, mediump>\t\tmediump_f32vec3;\n\ttypedef vec<4, f32, mediump>\t\tmediump_f32vec4;\n\n\ttypedef vec<1, f32, highp>\t\t\thighp_f32vec1;\n\ttypedef vec<2, f32, highp>\t\t\thighp_f32vec2;\n\ttypedef vec<3, f32, highp>\t\t\thighp_f32vec3;\n\ttypedef vec<4, f32, highp>\t\t\thighp_f32vec4;\n\n\ttypedef vec<1, f32, defaultp>\t\tf32vec1;\n\ttypedef vec<2, f32, defaultp>\t\tf32vec2;\n\ttypedef vec<3, f32, defaultp>\t\tf32vec3;\n\ttypedef vec<4, f32, defaultp>\t\tf32vec4;\n\n\ttypedef vec<1, f64, lowp>\t\t\tlowp_dvec1;\n\ttypedef vec<2, f64, lowp>\t\t\tlowp_dvec2;\n\ttypedef vec<3, f64, lowp>\t\t\tlowp_dvec3;\n\ttypedef vec<4, f64, lowp>\t\t\tlowp_dvec4;\n\n\ttypedef vec<1, f64, mediump>\t\tmediump_dvec1;\n\ttypedef vec<2, f64, mediump>\t\tmediump_dvec2;\n\ttypedef vec<3, f64, mediump>\t\tmediump_dvec3;\n\ttypedef vec<4, f64, mediump>\t\tmediump_dvec4;\n\n\ttypedef vec<1, f64, highp>\t\t\thighp_dvec1;\n\ttypedef vec<2, f64, highp>\t\t\thighp_dvec2;\n\ttypedef vec<3, f64, highp>\t\t\thighp_dvec3;\n\ttypedef vec<4, f64, highp>\t\t\thighp_dvec4;\n\n\ttypedef vec<1, f64, defaultp>\t\tdvec1;\n\ttypedef vec<2, f64, defaultp>\t\tdvec2;\n\ttypedef vec<3, f64, defaultp>\t\tdvec3;\n\ttypedef vec<4, f64, defaultp>\t\tdvec4;\n\n\ttypedef vec<1, f64, lowp>\t\t\tlowp_f64vec1;\n\ttypedef vec<2, f64, lowp>\t\t\tlowp_f64vec2;\n\ttypedef vec<3, f64, lowp>\t\t\tlowp_f64vec3;\n\ttypedef vec<4, f64, lowp>\t\t\tlowp_f64vec4;\n\n\ttypedef vec<1, f64, mediump>\t\tmediump_f64vec1;\n\ttypedef vec<2, f64, mediump>\t\tmediump_f64vec2;\n\ttypedef vec<3, f64, mediump>\t\tmediump_f64vec3;\n\ttypedef vec<4, f64, mediump>\t\tmediump_f64vec4;\n\n\ttypedef vec<1, f64, highp>\t\t\thighp_f64vec1;\n\ttypedef vec<2, f64, highp>\t\t\thighp_f64vec2;\n\ttypedef vec<3, f64, highp>\t\t\thighp_f64vec3;\n\ttypedef vec<4, f64, highp>\t\t\thighp_f64vec4;\n\n\ttypedef vec<1, f64, defaultp>\t\tf64vec1;\n\ttypedef vec<2, f64, defaultp>\t\tf64vec2;\n\ttypedef vec<3, f64, defaultp>\t\tf64vec3;\n\ttypedef vec<4, f64, defaultp>\t\tf64vec4;\n\n\t// Matrix NxN\n\n\ttypedef mat<2, 2, f32, lowp>\t\tlowp_mat2;\n\ttypedef mat<3, 3, f32, lowp>\t\tlowp_mat3;\n\ttypedef mat<4, 4, f32, lowp>\t\tlowp_mat4;\n\n\ttypedef mat<2, 2, f32, mediump>\t\tmediump_mat2;\n\ttypedef mat<3, 3, f32, mediump>\t\tmediump_mat3;\n\ttypedef mat<4, 4, f32, mediump>\t\tmediump_mat4;\n\n\ttypedef mat<2, 2, f32, highp>\t\thighp_mat2;\n\ttypedef mat<3, 3, f32, highp>\t\thighp_mat3;\n\ttypedef mat<4, 4, f32, highp>\t\thighp_mat4;\n\n\ttypedef mat<2, 2, f32, defaultp>\tmat2;\n\ttypedef mat<3, 3, f32, defaultp>\tmat3;\n\ttypedef mat<4, 4, f32, defaultp>\tmat4;\n\n\ttypedef mat<2, 2, f32, lowp>\t\tlowp_fmat2;\n\ttypedef mat<3, 3, f32, lowp>\t\tlowp_fmat3;\n\ttypedef mat<4, 4, f32, lowp>\t\tlowp_fmat4;\n\n\ttypedef mat<2, 2, f32, mediump>\t\tmediump_fmat2;\n\ttypedef mat<3, 3, f32, mediump>\t\tmediump_fmat3;\n\ttypedef mat<4, 4, f32, mediump>\t\tmediump_fmat4;\n\n\ttypedef mat<2, 2, f32, highp>\t\thighp_fmat2;\n\ttypedef mat<3, 3, f32, highp>\t\thighp_fmat3;\n\ttypedef mat<4, 4, f32, highp>\t\thighp_fmat4;\n\n\ttypedef mat<2, 2, f32, defaultp>\tfmat2;\n\ttypedef mat<3, 3, f32, defaultp>\tfmat3;\n\ttypedef mat<4, 4, f32, defaultp>\tfmat4;\n\n\ttypedef mat<2, 2, f32, lowp>\t\tlowp_f32mat2;\n\ttypedef mat<3, 3, f32, lowp>\t\tlowp_f32mat3;\n\ttypedef mat<4, 4, f32, lowp>\t\tlowp_f32mat4;\n\n\ttypedef mat<2, 2, f32, mediump>\t\tmediump_f32mat2;\n\ttypedef mat<3, 3, f32, mediump>\t\tmediump_f32mat3;\n\ttypedef mat<4, 4, f32, mediump>\t\tmediump_f32mat4;\n\n\ttypedef mat<2, 2, f32, highp>\t\thighp_f32mat2;\n\ttypedef mat<3, 3, f32, highp>\t\thighp_f32mat3;\n\ttypedef mat<4, 4, f32, highp>\t\thighp_f32mat4;\n\n\ttypedef mat<2, 2, f32, defaultp>\tf32mat2;\n\ttypedef mat<3, 3, f32, defaultp>\tf32mat3;\n\ttypedef mat<4, 4, f32, defaultp>\tf32mat4;\n\n\ttypedef mat<2, 2, f64, lowp>\t\tlowp_dmat2;\n\ttypedef mat<3, 3, f64, lowp>\t\tlowp_dmat3;\n\ttypedef mat<4, 4, f64, lowp>\t\tlowp_dmat4;\n\n\ttypedef mat<2, 2, f64, mediump>\t\tmediump_dmat2;\n\ttypedef mat<3, 3, f64, mediump>\t\tmediump_dmat3;\n\ttypedef mat<4, 4, f64, mediump>\t\tmediump_dmat4;\n\n\ttypedef mat<2, 2, f64, highp>\t\thighp_dmat2;\n\ttypedef mat<3, 3, f64, highp>\t\thighp_dmat3;\n\ttypedef mat<4, 4, f64, highp>\t\thighp_dmat4;\n\n\ttypedef mat<2, 2, f64, defaultp>\tdmat2;\n\ttypedef mat<3, 3, f64, defaultp>\tdmat3;\n\ttypedef mat<4, 4, f64, defaultp>\tdmat4;\n\n\ttypedef mat<2, 2, f64, lowp>\t\tlowp_f64mat2;\n\ttypedef mat<3, 3, f64, lowp>\t\tlowp_f64mat3;\n\ttypedef mat<4, 4, f64, lowp>\t\tlowp_f64mat4;\n\n\ttypedef mat<2, 2, f64, mediump>\t\tmediump_f64mat2;\n\ttypedef mat<3, 3, f64, mediump>\t\tmediump_f64mat3;\n\ttypedef mat<4, 4, f64, mediump>\t\tmediump_f64mat4;\n\n\ttypedef mat<2, 2, f64, highp>\t\thighp_f64mat2;\n\ttypedef mat<3, 3, f64, highp>\t\thighp_f64mat3;\n\ttypedef mat<4, 4, f64, highp>\t\thighp_f64mat4;\n\n\ttypedef mat<2, 2, f64, defaultp>\tf64mat2;\n\ttypedef mat<3, 3, f64, defaultp>\tf64mat3;\n\ttypedef mat<4, 4, f64, defaultp>\tf64mat4;\n\n\t// Matrix MxN\n\n\ttypedef mat<2, 2, f32, lowp>\t\tlowp_mat2x2;\n\ttypedef mat<2, 3, f32, lowp>\t\tlowp_mat2x3;\n\ttypedef mat<2, 4, f32, lowp>\t\tlowp_mat2x4;\n\ttypedef mat<3, 2, f32, lowp>\t\tlowp_mat3x2;\n\ttypedef mat<3, 3, f32, lowp>\t\tlowp_mat3x3;\n\ttypedef mat<3, 4, f32, lowp>\t\tlowp_mat3x4;\n\ttypedef mat<4, 2, f32, lowp>\t\tlowp_mat4x2;\n\ttypedef mat<4, 3, f32, lowp>\t\tlowp_mat4x3;\n\ttypedef mat<4, 4, f32, lowp>\t\tlowp_mat4x4;\n\n\ttypedef mat<2, 2, f32, mediump>\t\tmediump_mat2x2;\n\ttypedef mat<2, 3, f32, mediump>\t\tmediump_mat2x3;\n\ttypedef mat<2, 4, f32, mediump>\t\tmediump_mat2x4;\n\ttypedef mat<3, 2, f32, mediump>\t\tmediump_mat3x2;\n\ttypedef mat<3, 3, f32, mediump>\t\tmediump_mat3x3;\n\ttypedef mat<3, 4, f32, mediump>\t\tmediump_mat3x4;\n\ttypedef mat<4, 2, f32, mediump>\t\tmediump_mat4x2;\n\ttypedef mat<4, 3, f32, mediump>\t\tmediump_mat4x3;\n\ttypedef mat<4, 4, f32, mediump>\t\tmediump_mat4x4;\n\n\ttypedef mat<2, 2, f32, highp>\t\thighp_mat2x2;\n\ttypedef mat<2, 3, f32, highp>\t\thighp_mat2x3;\n\ttypedef mat<2, 4, f32, highp>\t\thighp_mat2x4;\n\ttypedef mat<3, 2, f32, highp>\t\thighp_mat3x2;\n\ttypedef mat<3, 3, f32, highp>\t\thighp_mat3x3;\n\ttypedef mat<3, 4, f32, highp>\t\thighp_mat3x4;\n\ttypedef mat<4, 2, f32, highp>\t\thighp_mat4x2;\n\ttypedef mat<4, 3, f32, highp>\t\thighp_mat4x3;\n\ttypedef mat<4, 4, f32, highp>\t\thighp_mat4x4;\n\n\ttypedef mat<2, 2, f32, defaultp>\tmat2x2;\n\ttypedef mat<3, 2, f32, defaultp>\tmat3x2;\n\ttypedef mat<4, 2, f32, defaultp>\tmat4x2;\n\ttypedef mat<2, 3, f32, defaultp>\tmat2x3;\n\ttypedef mat<3, 3, f32, defaultp>\tmat3x3;\n\ttypedef mat<4, 3, f32, defaultp>\tmat4x3;\n\ttypedef mat<2, 4, f32, defaultp>\tmat2x4;\n\ttypedef mat<3, 4, f32, defaultp>\tmat3x4;\n\ttypedef mat<4, 4, f32, defaultp>\tmat4x4;\n\n\ttypedef mat<2, 2, f32, lowp>\t\tlowp_fmat2x2;\n\ttypedef mat<2, 3, f32, lowp>\t\tlowp_fmat2x3;\n\ttypedef mat<2, 4, f32, lowp>\t\tlowp_fmat2x4;\n\ttypedef mat<3, 2, f32, lowp>\t\tlowp_fmat3x2;\n\ttypedef mat<3, 3, f32, lowp>\t\tlowp_fmat3x3;\n\ttypedef mat<3, 4, f32, lowp>\t\tlowp_fmat3x4;\n\ttypedef mat<4, 2, f32, lowp>\t\tlowp_fmat4x2;\n\ttypedef mat<4, 3, f32, lowp>\t\tlowp_fmat4x3;\n\ttypedef mat<4, 4, f32, lowp>\t\tlowp_fmat4x4;\n\n\ttypedef mat<2, 2, f32, mediump>\t\tmediump_fmat2x2;\n\ttypedef mat<2, 3, f32, mediump>\t\tmediump_fmat2x3;\n\ttypedef mat<2, 4, f32, mediump>\t\tmediump_fmat2x4;\n\ttypedef mat<3, 2, f32, mediump>\t\tmediump_fmat3x2;\n\ttypedef mat<3, 3, f32, mediump>\t\tmediump_fmat3x3;\n\ttypedef mat<3, 4, f32, mediump>\t\tmediump_fmat3x4;\n\ttypedef mat<4, 2, f32, mediump>\t\tmediump_fmat4x2;\n\ttypedef mat<4, 3, f32, mediump>\t\tmediump_fmat4x3;\n\ttypedef mat<4, 4, f32, mediump>\t\tmediump_fmat4x4;\n\n\ttypedef mat<2, 2, f32, highp>\t\thighp_fmat2x2;\n\ttypedef mat<2, 3, f32, highp>\t\thighp_fmat2x3;\n\ttypedef mat<2, 4, f32, highp>\t\thighp_fmat2x4;\n\ttypedef mat<3, 2, f32, highp>\t\thighp_fmat3x2;\n\ttypedef mat<3, 3, f32, highp>\t\thighp_fmat3x3;\n\ttypedef mat<3, 4, f32, highp>\t\thighp_fmat3x4;\n\ttypedef mat<4, 2, f32, highp>\t\thighp_fmat4x2;\n\ttypedef mat<4, 3, f32, highp>\t\thighp_fmat4x3;\n\ttypedef mat<4, 4, f32, highp>\t\thighp_fmat4x4;\n\n\ttypedef mat<2, 2, f32, defaultp>\tfmat2x2;\n\ttypedef mat<3, 2, f32, defaultp>\tfmat3x2;\n\ttypedef mat<4, 2, f32, defaultp>\tfmat4x2;\n\ttypedef mat<2, 3, f32, defaultp>\tfmat2x3;\n\ttypedef mat<3, 3, f32, defaultp>\tfmat3x3;\n\ttypedef mat<4, 3, f32, defaultp>\tfmat4x3;\n\ttypedef mat<2, 4, f32, defaultp>\tfmat2x4;\n\ttypedef mat<3, 4, f32, defaultp>\tfmat3x4;\n\ttypedef mat<4, 4, f32, defaultp>\tfmat4x4;\n\n\ttypedef mat<2, 2, f32, lowp>\t\tlowp_f32mat2x2;\n\ttypedef mat<2, 3, f32, lowp>\t\tlowp_f32mat2x3;\n\ttypedef mat<2, 4, f32, lowp>\t\tlowp_f32mat2x4;\n\ttypedef mat<3, 2, f32, lowp>\t\tlowp_f32mat3x2;\n\ttypedef mat<3, 3, f32, lowp>\t\tlowp_f32mat3x3;\n\ttypedef mat<3, 4, f32, lowp>\t\tlowp_f32mat3x4;\n\ttypedef mat<4, 2, f32, lowp>\t\tlowp_f32mat4x2;\n\ttypedef mat<4, 3, f32, lowp>\t\tlowp_f32mat4x3;\n\ttypedef mat<4, 4, f32, lowp>\t\tlowp_f32mat4x4;\n\t\n\ttypedef mat<2, 2, f32, mediump>\t\tmediump_f32mat2x2;\n\ttypedef mat<2, 3, f32, mediump>\t\tmediump_f32mat2x3;\n\ttypedef mat<2, 4, f32, mediump>\t\tmediump_f32mat2x4;\n\ttypedef mat<3, 2, f32, mediump>\t\tmediump_f32mat3x2;\n\ttypedef mat<3, 3, f32, mediump>\t\tmediump_f32mat3x3;\n\ttypedef mat<3, 4, f32, mediump>\t\tmediump_f32mat3x4;\n\ttypedef mat<4, 2, f32, mediump>\t\tmediump_f32mat4x2;\n\ttypedef mat<4, 3, f32, mediump>\t\tmediump_f32mat4x3;\n\ttypedef mat<4, 4, f32, mediump>\t\tmediump_f32mat4x4;\n\n\ttypedef mat<2, 2, f32, highp>\t\thighp_f32mat2x2;\n\ttypedef mat<2, 3, f32, highp>\t\thighp_f32mat2x3;\n\ttypedef mat<2, 4, f32, highp>\t\thighp_f32mat2x4;\n\ttypedef mat<3, 2, f32, highp>\t\thighp_f32mat3x2;\n\ttypedef mat<3, 3, f32, highp>\t\thighp_f32mat3x3;\n\ttypedef mat<3, 4, f32, highp>\t\thighp_f32mat3x4;\n\ttypedef mat<4, 2, f32, highp>\t\thighp_f32mat4x2;\n\ttypedef mat<4, 3, f32, highp>\t\thighp_f32mat4x3;\n\ttypedef mat<4, 4, f32, highp>\t\thighp_f32mat4x4;\n\n\ttypedef mat<2, 2, f32, defaultp>\tf32mat2x2;\n\ttypedef mat<3, 2, f32, defaultp>\tf32mat3x2;\n\ttypedef mat<4, 2, f32, defaultp>\tf32mat4x2;\n\ttypedef mat<2, 3, f32, defaultp>\tf32mat2x3;\n\ttypedef mat<3, 3, f32, defaultp>\tf32mat3x3;\n\ttypedef mat<4, 3, f32, defaultp>\tf32mat4x3;\n\ttypedef mat<2, 4, f32, defaultp>\tf32mat2x4;\n\ttypedef mat<3, 4, f32, defaultp>\tf32mat3x4;\n\ttypedef mat<4, 4, f32, defaultp>\tf32mat4x4;\n\n\ttypedef mat<2, 2, double, lowp>\t\tlowp_dmat2x2;\n\ttypedef mat<2, 3, double, lowp>\t\tlowp_dmat2x3;\n\ttypedef mat<2, 4, double, lowp>\t\tlowp_dmat2x4;\n\ttypedef mat<3, 2, double, lowp>\t\tlowp_dmat3x2;\n\ttypedef mat<3, 3, double, lowp>\t\tlowp_dmat3x3;\n\ttypedef mat<3, 4, double, lowp>\t\tlowp_dmat3x4;\n\ttypedef mat<4, 2, double, lowp>\t\tlowp_dmat4x2;\n\ttypedef mat<4, 3, double, lowp>\t\tlowp_dmat4x3;\n\ttypedef mat<4, 4, double, lowp>\t\tlowp_dmat4x4;\n\n\ttypedef mat<2, 2, double, mediump>\tmediump_dmat2x2;\n\ttypedef mat<2, 3, double, mediump>\tmediump_dmat2x3;\n\ttypedef mat<2, 4, double, mediump>\tmediump_dmat2x4;\n\ttypedef mat<3, 2, double, mediump>\tmediump_dmat3x2;\n\ttypedef mat<3, 3, double, mediump>\tmediump_dmat3x3;\n\ttypedef mat<3, 4, double, mediump>\tmediump_dmat3x4;\n\ttypedef mat<4, 2, double, mediump>\tmediump_dmat4x2;\n\ttypedef mat<4, 3, double, mediump>\tmediump_dmat4x3;\n\ttypedef mat<4, 4, double, mediump>\tmediump_dmat4x4;\n\n\ttypedef mat<2, 2, double, highp>\thighp_dmat2x2;\n\ttypedef mat<2, 3, double, highp>\thighp_dmat2x3;\n\ttypedef mat<2, 4, double, highp>\thighp_dmat2x4;\n\ttypedef mat<3, 2, double, highp>\thighp_dmat3x2;\n\ttypedef mat<3, 3, double, highp>\thighp_dmat3x3;\n\ttypedef mat<3, 4, double, highp>\thighp_dmat3x4;\n\ttypedef mat<4, 2, double, highp>\thighp_dmat4x2;\n\ttypedef mat<4, 3, double, highp>\thighp_dmat4x3;\n\ttypedef mat<4, 4, double, highp>\thighp_dmat4x4;\n\n\ttypedef mat<2, 2, double, defaultp>\tdmat2x2;\n\ttypedef mat<3, 2, double, defaultp>\tdmat3x2;\n\ttypedef mat<4, 2, double, defaultp>\tdmat4x2;\n\ttypedef mat<2, 3, double, defaultp>\tdmat2x3;\n\ttypedef mat<3, 3, double, defaultp>\tdmat3x3;\n\ttypedef mat<4, 3, double, defaultp>\tdmat4x3;\n\ttypedef mat<2, 4, double, defaultp>\tdmat2x4;\n\ttypedef mat<3, 4, double, defaultp>\tdmat3x4;\n\ttypedef mat<4, 4, double, defaultp>\tdmat4x4;\n\n\ttypedef mat<2, 2, f64, lowp>\t\tlowp_f64mat2x2;\n\ttypedef mat<2, 3, f64, lowp>\t\tlowp_f64mat2x3;\n\ttypedef mat<2, 4, f64, lowp>\t\tlowp_f64mat2x4;\n\ttypedef mat<3, 2, f64, lowp>\t\tlowp_f64mat3x2;\n\ttypedef mat<3, 3, f64, lowp>\t\tlowp_f64mat3x3;\n\ttypedef mat<3, 4, f64, lowp>\t\tlowp_f64mat3x4;\n\ttypedef mat<4, 2, f64, lowp>\t\tlowp_f64mat4x2;\n\ttypedef mat<4, 3, f64, lowp>\t\tlowp_f64mat4x3;\n\ttypedef mat<4, 4, f64, lowp>\t\tlowp_f64mat4x4;\n\n\ttypedef mat<2, 2, f64, mediump>\t\tmediump_f64mat2x2;\n\ttypedef mat<2, 3, f64, mediump>\t\tmediump_f64mat2x3;\n\ttypedef mat<2, 4, f64, mediump>\t\tmediump_f64mat2x4;\n\ttypedef mat<3, 2, f64, mediump>\t\tmediump_f64mat3x2;\n\ttypedef mat<3, 3, f64, mediump>\t\tmediump_f64mat3x3;\n\ttypedef mat<3, 4, f64, mediump>\t\tmediump_f64mat3x4;\n\ttypedef mat<4, 2, f64, mediump>\t\tmediump_f64mat4x2;\n\ttypedef mat<4, 3, f64, mediump>\t\tmediump_f64mat4x3;\n\ttypedef mat<4, 4, f64, mediump>\t\tmediump_f64mat4x4;\n\n\ttypedef mat<2, 2, f64, highp>\t\thighp_f64mat2x2;\n\ttypedef mat<2, 3, f64, highp>\t\thighp_f64mat2x3;\n\ttypedef mat<2, 4, f64, highp>\t\thighp_f64mat2x4;\n\ttypedef mat<3, 2, f64, highp>\t\thighp_f64mat3x2;\n\ttypedef mat<3, 3, f64, highp>\t\thighp_f64mat3x3;\n\ttypedef mat<3, 4, f64, highp>\t\thighp_f64mat3x4;\n\ttypedef mat<4, 2, f64, highp>\t\thighp_f64mat4x2;\n\ttypedef mat<4, 3, f64, highp>\t\thighp_f64mat4x3;\n\ttypedef mat<4, 4, f64, highp>\t\thighp_f64mat4x4;\n\n\ttypedef mat<2, 2, f64, defaultp>\tf64mat2x2;\n\ttypedef mat<3, 2, f64, defaultp>\tf64mat3x2;\n\ttypedef mat<4, 2, f64, defaultp>\tf64mat4x2;\n\ttypedef mat<2, 3, f64, defaultp>\tf64mat2x3;\n\ttypedef mat<3, 3, f64, defaultp>\tf64mat3x3;\n\ttypedef mat<4, 3, f64, defaultp>\tf64mat4x3;\n\ttypedef mat<2, 4, f64, defaultp>\tf64mat2x4;\n\ttypedef mat<3, 4, f64, defaultp>\tf64mat3x4;\n\ttypedef mat<4, 4, f64, defaultp>\tf64mat4x4;\n\n\t// Signed integer matrix MxN\n\n\ttypedef mat<2, 2, int, lowp>\t\tlowp_imat2x2;\n\ttypedef mat<2, 3, int, lowp>\t\tlowp_imat2x3;\n\ttypedef mat<2, 4, int, lowp>\t\tlowp_imat2x4;\n\ttypedef mat<3, 2, int, lowp>\t\tlowp_imat3x2;\n\ttypedef mat<3, 3, int, lowp>\t\tlowp_imat3x3;\n\ttypedef mat<3, 4, int, lowp>\t\tlowp_imat3x4;\n\ttypedef mat<4, 2, int, lowp>\t\tlowp_imat4x2;\n\ttypedef mat<4, 3, int, lowp>\t\tlowp_imat4x3;\n\ttypedef mat<4, 4, int, lowp>\t\tlowp_imat4x4;\n\n\ttypedef mat<2, 2, int, mediump>\t\tmediump_imat2x2;\n\ttypedef mat<2, 3, int, mediump>\t\tmediump_imat2x3;\n\ttypedef mat<2, 4, int, mediump>\t\tmediump_imat2x4;\n\ttypedef mat<3, 2, int, mediump>\t\tmediump_imat3x2;\n\ttypedef mat<3, 3, int, mediump>\t\tmediump_imat3x3;\n\ttypedef mat<3, 4, int, mediump>\t\tmediump_imat3x4;\n\ttypedef mat<4, 2, int, mediump>\t\tmediump_imat4x2;\n\ttypedef mat<4, 3, int, mediump>\t\tmediump_imat4x3;\n\ttypedef mat<4, 4, int, mediump>\t\tmediump_imat4x4;\n\n\ttypedef mat<2, 2, int, highp>\t\thighp_imat2x2;\n\ttypedef mat<2, 3, int, highp>\t\thighp_imat2x3;\n\ttypedef mat<2, 4, int, highp>\t\thighp_imat2x4;\n\ttypedef mat<3, 2, int, highp>\t\thighp_imat3x2;\n\ttypedef mat<3, 3, int, highp>\t\thighp_imat3x3;\n\ttypedef mat<3, 4, int, highp>\t\thighp_imat3x4;\n\ttypedef mat<4, 2, int, highp>\t\thighp_imat4x2;\n\ttypedef mat<4, 3, int, highp>\t\thighp_imat4x3;\n\ttypedef mat<4, 4, int, highp>\t\thighp_imat4x4;\n\n\ttypedef mat<2, 2, int, defaultp>\timat2x2;\n\ttypedef mat<3, 2, int, defaultp>\timat3x2;\n\ttypedef mat<4, 2, int, defaultp>\timat4x2;\n\ttypedef mat<2, 3, int, defaultp>\timat2x3;\n\ttypedef mat<3, 3, int, defaultp>\timat3x3;\n\ttypedef mat<4, 3, int, defaultp>\timat4x3;\n\ttypedef mat<2, 4, int, defaultp>\timat2x4;\n\ttypedef mat<3, 4, int, defaultp>\timat3x4;\n\ttypedef mat<4, 4, int, defaultp>\timat4x4;\n\n\n\ttypedef mat<2, 2, int8, lowp>\t\tlowp_i8mat2x2;\n\ttypedef mat<2, 3, int8, lowp>\t\tlowp_i8mat2x3;\n\ttypedef mat<2, 4, int8, lowp>\t\tlowp_i8mat2x4;\n\ttypedef mat<3, 2, int8, lowp>\t\tlowp_i8mat3x2;\n\ttypedef mat<3, 3, int8, lowp>\t\tlowp_i8mat3x3;\n\ttypedef mat<3, 4, int8, lowp>\t\tlowp_i8mat3x4;\n\ttypedef mat<4, 2, int8, lowp>\t\tlowp_i8mat4x2;\n\ttypedef mat<4, 3, int8, lowp>\t\tlowp_i8mat4x3;\n\ttypedef mat<4, 4, int8, lowp>\t\tlowp_i8mat4x4;\n\n\ttypedef mat<2, 2, int8, mediump>\tmediump_i8mat2x2;\n\ttypedef mat<2, 3, int8, mediump>\tmediump_i8mat2x3;\n\ttypedef mat<2, 4, int8, mediump>\tmediump_i8mat2x4;\n\ttypedef mat<3, 2, int8, mediump>\tmediump_i8mat3x2;\n\ttypedef mat<3, 3, int8, mediump>\tmediump_i8mat3x3;\n\ttypedef mat<3, 4, int8, mediump>\tmediump_i8mat3x4;\n\ttypedef mat<4, 2, int8, mediump>\tmediump_i8mat4x2;\n\ttypedef mat<4, 3, int8, mediump>\tmediump_i8mat4x3;\n\ttypedef mat<4, 4, int8, mediump>\tmediump_i8mat4x4;\n\n\ttypedef mat<2, 2, int8, highp>\t\thighp_i8mat2x2;\n\ttypedef mat<2, 3, int8, highp>\t\thighp_i8mat2x3;\n\ttypedef mat<2, 4, int8, highp>\t\thighp_i8mat2x4;\n\ttypedef mat<3, 2, int8, highp>\t\thighp_i8mat3x2;\n\ttypedef mat<3, 3, int8, highp>\t\thighp_i8mat3x3;\n\ttypedef mat<3, 4, int8, highp>\t\thighp_i8mat3x4;\n\ttypedef mat<4, 2, int8, highp>\t\thighp_i8mat4x2;\n\ttypedef mat<4, 3, int8, highp>\t\thighp_i8mat4x3;\n\ttypedef mat<4, 4, int8, highp>\t\thighp_i8mat4x4;\n\n\ttypedef mat<2, 2, int8, defaultp>\ti8mat2x2;\n\ttypedef mat<3, 2, int8, defaultp>\ti8mat3x2;\n\ttypedef mat<4, 2, int8, defaultp>\ti8mat4x2;\n\ttypedef mat<2, 3, int8, defaultp>\ti8mat2x3;\n\ttypedef mat<3, 3, int8, defaultp>\ti8mat3x3;\n\ttypedef mat<4, 3, int8, defaultp>\ti8mat4x3;\n\ttypedef mat<2, 4, int8, defaultp>\ti8mat2x4;\n\ttypedef mat<3, 4, int8, defaultp>\ti8mat3x4;\n\ttypedef mat<4, 4, int8, defaultp>\ti8mat4x4;\n\n\n\ttypedef mat<2, 2, int16, lowp>\t\tlowp_i16mat2x2;\n\ttypedef mat<2, 3, int16, lowp>\t\tlowp_i16mat2x3;\n\ttypedef mat<2, 4, int16, lowp>\t\tlowp_i16mat2x4;\n\ttypedef mat<3, 2, int16, lowp>\t\tlowp_i16mat3x2;\n\ttypedef mat<3, 3, int16, lowp>\t\tlowp_i16mat3x3;\n\ttypedef mat<3, 4, int16, lowp>\t\tlowp_i16mat3x4;\n\ttypedef mat<4, 2, int16, lowp>\t\tlowp_i16mat4x2;\n\ttypedef mat<4, 3, int16, lowp>\t\tlowp_i16mat4x3;\n\ttypedef mat<4, 4, int16, lowp>\t\tlowp_i16mat4x4;\n\n\ttypedef mat<2, 2, int16, mediump>\tmediump_i16mat2x2;\n\ttypedef mat<2, 3, int16, mediump>\tmediump_i16mat2x3;\n\ttypedef mat<2, 4, int16, mediump>\tmediump_i16mat2x4;\n\ttypedef mat<3, 2, int16, mediump>\tmediump_i16mat3x2;\n\ttypedef mat<3, 3, int16, mediump>\tmediump_i16mat3x3;\n\ttypedef mat<3, 4, int16, mediump>\tmediump_i16mat3x4;\n\ttypedef mat<4, 2, int16, mediump>\tmediump_i16mat4x2;\n\ttypedef mat<4, 3, int16, mediump>\tmediump_i16mat4x3;\n\ttypedef mat<4, 4, int16, mediump>\tmediump_i16mat4x4;\n\n\ttypedef mat<2, 2, int16, highp>\t\thighp_i16mat2x2;\n\ttypedef mat<2, 3, int16, highp>\t\thighp_i16mat2x3;\n\ttypedef mat<2, 4, int16, highp>\t\thighp_i16mat2x4;\n\ttypedef mat<3, 2, int16, highp>\t\thighp_i16mat3x2;\n\ttypedef mat<3, 3, int16, highp>\t\thighp_i16mat3x3;\n\ttypedef mat<3, 4, int16, highp>\t\thighp_i16mat3x4;\n\ttypedef mat<4, 2, int16, highp>\t\thighp_i16mat4x2;\n\ttypedef mat<4, 3, int16, highp>\t\thighp_i16mat4x3;\n\ttypedef mat<4, 4, int16, highp>\t\thighp_i16mat4x4;\n\n\ttypedef mat<2, 2, int16, defaultp>\ti16mat2x2;\n\ttypedef mat<3, 2, int16, defaultp>\ti16mat3x2;\n\ttypedef mat<4, 2, int16, defaultp>\ti16mat4x2;\n\ttypedef mat<2, 3, int16, defaultp>\ti16mat2x3;\n\ttypedef mat<3, 3, int16, defaultp>\ti16mat3x3;\n\ttypedef mat<4, 3, int16, defaultp>\ti16mat4x3;\n\ttypedef mat<2, 4, int16, defaultp>\ti16mat2x4;\n\ttypedef mat<3, 4, int16, defaultp>\ti16mat3x4;\n\ttypedef mat<4, 4, int16, defaultp>\ti16mat4x4;\n\n\n\ttypedef mat<2, 2, int32, lowp>\t\tlowp_i32mat2x2;\n\ttypedef mat<2, 3, int32, lowp>\t\tlowp_i32mat2x3;\n\ttypedef mat<2, 4, int32, lowp>\t\tlowp_i32mat2x4;\n\ttypedef mat<3, 2, int32, lowp>\t\tlowp_i32mat3x2;\n\ttypedef mat<3, 3, int32, lowp>\t\tlowp_i32mat3x3;\n\ttypedef mat<3, 4, int32, lowp>\t\tlowp_i32mat3x4;\n\ttypedef mat<4, 2, int32, lowp>\t\tlowp_i32mat4x2;\n\ttypedef mat<4, 3, int32, lowp>\t\tlowp_i32mat4x3;\n\ttypedef mat<4, 4, int32, lowp>\t\tlowp_i32mat4x4;\n\n\ttypedef mat<2, 2, int32, mediump>\tmediump_i32mat2x2;\n\ttypedef mat<2, 3, int32, mediump>\tmediump_i32mat2x3;\n\ttypedef mat<2, 4, int32, mediump>\tmediump_i32mat2x4;\n\ttypedef mat<3, 2, int32, mediump>\tmediump_i32mat3x2;\n\ttypedef mat<3, 3, int32, mediump>\tmediump_i32mat3x3;\n\ttypedef mat<3, 4, int32, mediump>\tmediump_i32mat3x4;\n\ttypedef mat<4, 2, int32, mediump>\tmediump_i32mat4x2;\n\ttypedef mat<4, 3, int32, mediump>\tmediump_i32mat4x3;\n\ttypedef mat<4, 4, int32, mediump>\tmediump_i32mat4x4;\n\n\ttypedef mat<2, 2, int32, highp>\t\thighp_i32mat2x2;\n\ttypedef mat<2, 3, int32, highp>\t\thighp_i32mat2x3;\n\ttypedef mat<2, 4, int32, highp>\t\thighp_i32mat2x4;\n\ttypedef mat<3, 2, int32, highp>\t\thighp_i32mat3x2;\n\ttypedef mat<3, 3, int32, highp>\t\thighp_i32mat3x3;\n\ttypedef mat<3, 4, int32, highp>\t\thighp_i32mat3x4;\n\ttypedef mat<4, 2, int32, highp>\t\thighp_i32mat4x2;\n\ttypedef mat<4, 3, int32, highp>\t\thighp_i32mat4x3;\n\ttypedef mat<4, 4, int32, highp>\t\thighp_i32mat4x4;\n\n\ttypedef mat<2, 2, int32, defaultp>\ti32mat2x2;\n\ttypedef mat<3, 2, int32, defaultp>\ti32mat3x2;\n\ttypedef mat<4, 2, int32, defaultp>\ti32mat4x2;\n\ttypedef mat<2, 3, int32, defaultp>\ti32mat2x3;\n\ttypedef mat<3, 3, int32, defaultp>\ti32mat3x3;\n\ttypedef mat<4, 3, int32, defaultp>\ti32mat4x3;\n\ttypedef mat<2, 4, int32, defaultp>\ti32mat2x4;\n\ttypedef mat<3, 4, int32, defaultp>\ti32mat3x4;\n\ttypedef mat<4, 4, int32, defaultp>\ti32mat4x4;\n\n\n\ttypedef mat<2, 2, int64, lowp>\t\tlowp_i64mat2x2;\n\ttypedef mat<2, 3, int64, lowp>\t\tlowp_i64mat2x3;\n\ttypedef mat<2, 4, int64, lowp>\t\tlowp_i64mat2x4;\n\ttypedef mat<3, 2, int64, lowp>\t\tlowp_i64mat3x2;\n\ttypedef mat<3, 3, int64, lowp>\t\tlowp_i64mat3x3;\n\ttypedef mat<3, 4, int64, lowp>\t\tlowp_i64mat3x4;\n\ttypedef mat<4, 2, int64, lowp>\t\tlowp_i64mat4x2;\n\ttypedef mat<4, 3, int64, lowp>\t\tlowp_i64mat4x3;\n\ttypedef mat<4, 4, int64, lowp>\t\tlowp_i64mat4x4;\n\n\ttypedef mat<2, 2, int64, mediump>\tmediump_i64mat2x2;\n\ttypedef mat<2, 3, int64, mediump>\tmediump_i64mat2x3;\n\ttypedef mat<2, 4, int64, mediump>\tmediump_i64mat2x4;\n\ttypedef mat<3, 2, int64, mediump>\tmediump_i64mat3x2;\n\ttypedef mat<3, 3, int64, mediump>\tmediump_i64mat3x3;\n\ttypedef mat<3, 4, int64, mediump>\tmediump_i64mat3x4;\n\ttypedef mat<4, 2, int64, mediump>\tmediump_i64mat4x2;\n\ttypedef mat<4, 3, int64, mediump>\tmediump_i64mat4x3;\n\ttypedef mat<4, 4, int64, mediump>\tmediump_i64mat4x4;\n\n\ttypedef mat<2, 2, int64, highp>\t\thighp_i64mat2x2;\n\ttypedef mat<2, 3, int64, highp>\t\thighp_i64mat2x3;\n\ttypedef mat<2, 4, int64, highp>\t\thighp_i64mat2x4;\n\ttypedef mat<3, 2, int64, highp>\t\thighp_i64mat3x2;\n\ttypedef mat<3, 3, int64, highp>\t\thighp_i64mat3x3;\n\ttypedef mat<3, 4, int64, highp>\t\thighp_i64mat3x4;\n\ttypedef mat<4, 2, int64, highp>\t\thighp_i64mat4x2;\n\ttypedef mat<4, 3, int64, highp>\t\thighp_i64mat4x3;\n\ttypedef mat<4, 4, int64, highp>\t\thighp_i64mat4x4;\n\n\ttypedef mat<2, 2, int64, defaultp>\ti64mat2x2;\n\ttypedef mat<3, 2, int64, defaultp>\ti64mat3x2;\n\ttypedef mat<4, 2, int64, defaultp>\ti64mat4x2;\n\ttypedef mat<2, 3, int64, defaultp>\ti64mat2x3;\n\ttypedef mat<3, 3, int64, defaultp>\ti64mat3x3;\n\ttypedef mat<4, 3, int64, defaultp>\ti64mat4x3;\n\ttypedef mat<2, 4, int64, defaultp>\ti64mat2x4;\n\ttypedef mat<3, 4, int64, defaultp>\ti64mat3x4;\n\ttypedef mat<4, 4, int64, defaultp>\ti64mat4x4;\n\n\n\t// Unsigned integer matrix MxN\n\n\ttypedef mat<2, 2, uint, lowp>\t\tlowp_umat2x2;\n\ttypedef mat<2, 3, uint, lowp>\t\tlowp_umat2x3;\n\ttypedef mat<2, 4, uint, lowp>\t\tlowp_umat2x4;\n\ttypedef mat<3, 2, uint, lowp>\t\tlowp_umat3x2;\n\ttypedef mat<3, 3, uint, lowp>\t\tlowp_umat3x3;\n\ttypedef mat<3, 4, uint, lowp>\t\tlowp_umat3x4;\n\ttypedef mat<4, 2, uint, lowp>\t\tlowp_umat4x2;\n\ttypedef mat<4, 3, uint, lowp>\t\tlowp_umat4x3;\n\ttypedef mat<4, 4, uint, lowp>\t\tlowp_umat4x4;\n\n\ttypedef mat<2, 2, uint, mediump>\tmediump_umat2x2;\n\ttypedef mat<2, 3, uint, mediump>\tmediump_umat2x3;\n\ttypedef mat<2, 4, uint, mediump>\tmediump_umat2x4;\n\ttypedef mat<3, 2, uint, mediump>\tmediump_umat3x2;\n\ttypedef mat<3, 3, uint, mediump>\tmediump_umat3x3;\n\ttypedef mat<3, 4, uint, mediump>\tmediump_umat3x4;\n\ttypedef mat<4, 2, uint, mediump>\tmediump_umat4x2;\n\ttypedef mat<4, 3, uint, mediump>\tmediump_umat4x3;\n\ttypedef mat<4, 4, uint, mediump>\tmediump_umat4x4;\n\n\ttypedef mat<2, 2, uint, highp>\t\thighp_umat2x2;\n\ttypedef mat<2, 3, uint, highp>\t\thighp_umat2x3;\n\ttypedef mat<2, 4, uint, highp>\t\thighp_umat2x4;\n\ttypedef mat<3, 2, uint, highp>\t\thighp_umat3x2;\n\ttypedef mat<3, 3, uint, highp>\t\thighp_umat3x3;\n\ttypedef mat<3, 4, uint, highp>\t\thighp_umat3x4;\n\ttypedef mat<4, 2, uint, highp>\t\thighp_umat4x2;\n\ttypedef mat<4, 3, uint, highp>\t\thighp_umat4x3;\n\ttypedef mat<4, 4, uint, highp>\t\thighp_umat4x4;\n\n\ttypedef mat<2, 2, uint, defaultp>\tumat2x2;\n\ttypedef mat<3, 2, uint, defaultp>\tumat3x2;\n\ttypedef mat<4, 2, uint, defaultp>\tumat4x2;\n\ttypedef mat<2, 3, uint, defaultp>\tumat2x3;\n\ttypedef mat<3, 3, uint, defaultp>\tumat3x3;\n\ttypedef mat<4, 3, uint, defaultp>\tumat4x3;\n\ttypedef mat<2, 4, uint, defaultp>\tumat2x4;\n\ttypedef mat<3, 4, uint, defaultp>\tumat3x4;\n\ttypedef mat<4, 4, uint, defaultp>\tumat4x4;\n\n\n\ttypedef mat<2, 2, uint8, lowp>\t\tlowp_u8mat2x2;\n\ttypedef mat<2, 3, uint8, lowp>\t\tlowp_u8mat2x3;\n\ttypedef mat<2, 4, uint8, lowp>\t\tlowp_u8mat2x4;\n\ttypedef mat<3, 2, uint8, lowp>\t\tlowp_u8mat3x2;\n\ttypedef mat<3, 3, uint8, lowp>\t\tlowp_u8mat3x3;\n\ttypedef mat<3, 4, uint8, lowp>\t\tlowp_u8mat3x4;\n\ttypedef mat<4, 2, uint8, lowp>\t\tlowp_u8mat4x2;\n\ttypedef mat<4, 3, uint8, lowp>\t\tlowp_u8mat4x3;\n\ttypedef mat<4, 4, uint8, lowp>\t\tlowp_u8mat4x4;\n\n\ttypedef mat<2, 2, uint8, mediump>\tmediump_u8mat2x2;\n\ttypedef mat<2, 3, uint8, mediump>\tmediump_u8mat2x3;\n\ttypedef mat<2, 4, uint8, mediump>\tmediump_u8mat2x4;\n\ttypedef mat<3, 2, uint8, mediump>\tmediump_u8mat3x2;\n\ttypedef mat<3, 3, uint8, mediump>\tmediump_u8mat3x3;\n\ttypedef mat<3, 4, uint8, mediump>\tmediump_u8mat3x4;\n\ttypedef mat<4, 2, uint8, mediump>\tmediump_u8mat4x2;\n\ttypedef mat<4, 3, uint8, mediump>\tmediump_u8mat4x3;\n\ttypedef mat<4, 4, uint8, mediump>\tmediump_u8mat4x4;\n\n\ttypedef mat<2, 2, uint8, highp>\t\thighp_u8mat2x2;\n\ttypedef mat<2, 3, uint8, highp>\t\thighp_u8mat2x3;\n\ttypedef mat<2, 4, uint8, highp>\t\thighp_u8mat2x4;\n\ttypedef mat<3, 2, uint8, highp>\t\thighp_u8mat3x2;\n\ttypedef mat<3, 3, uint8, highp>\t\thighp_u8mat3x3;\n\ttypedef mat<3, 4, uint8, highp>\t\thighp_u8mat3x4;\n\ttypedef mat<4, 2, uint8, highp>\t\thighp_u8mat4x2;\n\ttypedef mat<4, 3, uint8, highp>\t\thighp_u8mat4x3;\n\ttypedef mat<4, 4, uint8, highp>\t\thighp_u8mat4x4;\n\n\ttypedef mat<2, 2, uint8, defaultp>\tu8mat2x2;\n\ttypedef mat<3, 2, uint8, defaultp>\tu8mat3x2;\n\ttypedef mat<4, 2, uint8, defaultp>\tu8mat4x2;\n\ttypedef mat<2, 3, uint8, defaultp>\tu8mat2x3;\n\ttypedef mat<3, 3, uint8, defaultp>\tu8mat3x3;\n\ttypedef mat<4, 3, uint8, defaultp>\tu8mat4x3;\n\ttypedef mat<2, 4, uint8, defaultp>\tu8mat2x4;\n\ttypedef mat<3, 4, uint8, defaultp>\tu8mat3x4;\n\ttypedef mat<4, 4, uint8, defaultp>\tu8mat4x4;\n\n\n\ttypedef mat<2, 2, uint16, lowp>\t\tlowp_u16mat2x2;\n\ttypedef mat<2, 3, uint16, lowp>\t\tlowp_u16mat2x3;\n\ttypedef mat<2, 4, uint16, lowp>\t\tlowp_u16mat2x4;\n\ttypedef mat<3, 2, uint16, lowp>\t\tlowp_u16mat3x2;\n\ttypedef mat<3, 3, uint16, lowp>\t\tlowp_u16mat3x3;\n\ttypedef mat<3, 4, uint16, lowp>\t\tlowp_u16mat3x4;\n\ttypedef mat<4, 2, uint16, lowp>\t\tlowp_u16mat4x2;\n\ttypedef mat<4, 3, uint16, lowp>\t\tlowp_u16mat4x3;\n\ttypedef mat<4, 4, uint16, lowp>\t\tlowp_u16mat4x4;\n\n\ttypedef mat<2, 2, uint16, mediump>\tmediump_u16mat2x2;\n\ttypedef mat<2, 3, uint16, mediump>\tmediump_u16mat2x3;\n\ttypedef mat<2, 4, uint16, mediump>\tmediump_u16mat2x4;\n\ttypedef mat<3, 2, uint16, mediump>\tmediump_u16mat3x2;\n\ttypedef mat<3, 3, uint16, mediump>\tmediump_u16mat3x3;\n\ttypedef mat<3, 4, uint16, mediump>\tmediump_u16mat3x4;\n\ttypedef mat<4, 2, uint16, mediump>\tmediump_u16mat4x2;\n\ttypedef mat<4, 3, uint16, mediump>\tmediump_u16mat4x3;\n\ttypedef mat<4, 4, uint16, mediump>\tmediump_u16mat4x4;\n\n\ttypedef mat<2, 2, uint16, highp>\thighp_u16mat2x2;\n\ttypedef mat<2, 3, uint16, highp>\thighp_u16mat2x3;\n\ttypedef mat<2, 4, uint16, highp>\thighp_u16mat2x4;\n\ttypedef mat<3, 2, uint16, highp>\thighp_u16mat3x2;\n\ttypedef mat<3, 3, uint16, highp>\thighp_u16mat3x3;\n\ttypedef mat<3, 4, uint16, highp>\thighp_u16mat3x4;\n\ttypedef mat<4, 2, uint16, highp>\thighp_u16mat4x2;\n\ttypedef mat<4, 3, uint16, highp>\thighp_u16mat4x3;\n\ttypedef mat<4, 4, uint16, highp>\thighp_u16mat4x4;\n\n\ttypedef mat<2, 2, uint16, defaultp>\tu16mat2x2;\n\ttypedef mat<3, 2, uint16, defaultp>\tu16mat3x2;\n\ttypedef mat<4, 2, uint16, defaultp>\tu16mat4x2;\n\ttypedef mat<2, 3, uint16, defaultp>\tu16mat2x3;\n\ttypedef mat<3, 3, uint16, defaultp>\tu16mat3x3;\n\ttypedef mat<4, 3, uint16, defaultp>\tu16mat4x3;\n\ttypedef mat<2, 4, uint16, defaultp>\tu16mat2x4;\n\ttypedef mat<3, 4, uint16, defaultp>\tu16mat3x4;\n\ttypedef mat<4, 4, uint16, defaultp>\tu16mat4x4;\n\n\n\ttypedef mat<2, 2, uint32, lowp>\t\tlowp_u32mat2x2;\n\ttypedef mat<2, 3, uint32, lowp>\t\tlowp_u32mat2x3;\n\ttypedef mat<2, 4, uint32, lowp>\t\tlowp_u32mat2x4;\n\ttypedef mat<3, 2, uint32, lowp>\t\tlowp_u32mat3x2;\n\ttypedef mat<3, 3, uint32, lowp>\t\tlowp_u32mat3x3;\n\ttypedef mat<3, 4, uint32, lowp>\t\tlowp_u32mat3x4;\n\ttypedef mat<4, 2, uint32, lowp>\t\tlowp_u32mat4x2;\n\ttypedef mat<4, 3, uint32, lowp>\t\tlowp_u32mat4x3;\n\ttypedef mat<4, 4, uint32, lowp>\t\tlowp_u32mat4x4;\n\n\ttypedef mat<2, 2, uint32, mediump>\tmediump_u32mat2x2;\n\ttypedef mat<2, 3, uint32, mediump>\tmediump_u32mat2x3;\n\ttypedef mat<2, 4, uint32, mediump>\tmediump_u32mat2x4;\n\ttypedef mat<3, 2, uint32, mediump>\tmediump_u32mat3x2;\n\ttypedef mat<3, 3, uint32, mediump>\tmediump_u32mat3x3;\n\ttypedef mat<3, 4, uint32, mediump>\tmediump_u32mat3x4;\n\ttypedef mat<4, 2, uint32, mediump>\tmediump_u32mat4x2;\n\ttypedef mat<4, 3, uint32, mediump>\tmediump_u32mat4x3;\n\ttypedef mat<4, 4, uint32, mediump>\tmediump_u32mat4x4;\n\n\ttypedef mat<2, 2, uint32, highp>\thighp_u32mat2x2;\n\ttypedef mat<2, 3, uint32, highp>\thighp_u32mat2x3;\n\ttypedef mat<2, 4, uint32, highp>\thighp_u32mat2x4;\n\ttypedef mat<3, 2, uint32, highp>\thighp_u32mat3x2;\n\ttypedef mat<3, 3, uint32, highp>\thighp_u32mat3x3;\n\ttypedef mat<3, 4, uint32, highp>\thighp_u32mat3x4;\n\ttypedef mat<4, 2, uint32, highp>\thighp_u32mat4x2;\n\ttypedef mat<4, 3, uint32, highp>\thighp_u32mat4x3;\n\ttypedef mat<4, 4, uint32, highp>\thighp_u32mat4x4;\n\n\ttypedef mat<2, 2, uint32, defaultp>\tu32mat2x2;\n\ttypedef mat<3, 2, uint32, defaultp>\tu32mat3x2;\n\ttypedef mat<4, 2, uint32, defaultp>\tu32mat4x2;\n\ttypedef mat<2, 3, uint32, defaultp>\tu32mat2x3;\n\ttypedef mat<3, 3, uint32, defaultp>\tu32mat3x3;\n\ttypedef mat<4, 3, uint32, defaultp>\tu32mat4x3;\n\ttypedef mat<2, 4, uint32, defaultp>\tu32mat2x4;\n\ttypedef mat<3, 4, uint32, defaultp>\tu32mat3x4;\n\ttypedef mat<4, 4, uint32, defaultp>\tu32mat4x4;\n\n\n\ttypedef mat<2, 2, uint64, lowp>\t\tlowp_u64mat2x2;\n\ttypedef mat<2, 3, uint64, lowp>\t\tlowp_u64mat2x3;\n\ttypedef mat<2, 4, uint64, lowp>\t\tlowp_u64mat2x4;\n\ttypedef mat<3, 2, uint64, lowp>\t\tlowp_u64mat3x2;\n\ttypedef mat<3, 3, uint64, lowp>\t\tlowp_u64mat3x3;\n\ttypedef mat<3, 4, uint64, lowp>\t\tlowp_u64mat3x4;\n\ttypedef mat<4, 2, uint64, lowp>\t\tlowp_u64mat4x2;\n\ttypedef mat<4, 3, uint64, lowp>\t\tlowp_u64mat4x3;\n\ttypedef mat<4, 4, uint64, lowp>\t\tlowp_u64mat4x4;\n\n\ttypedef mat<2, 2, uint64, mediump>\tmediump_u64mat2x2;\n\ttypedef mat<2, 3, uint64, mediump>\tmediump_u64mat2x3;\n\ttypedef mat<2, 4, uint64, mediump>\tmediump_u64mat2x4;\n\ttypedef mat<3, 2, uint64, mediump>\tmediump_u64mat3x2;\n\ttypedef mat<3, 3, uint64, mediump>\tmediump_u64mat3x3;\n\ttypedef mat<3, 4, uint64, mediump>\tmediump_u64mat3x4;\n\ttypedef mat<4, 2, uint64, mediump>\tmediump_u64mat4x2;\n\ttypedef mat<4, 3, uint64, mediump>\tmediump_u64mat4x3;\n\ttypedef mat<4, 4, uint64, mediump>\tmediump_u64mat4x4;\n\n\ttypedef mat<2, 2, uint64, highp>\thighp_u64mat2x2;\n\ttypedef mat<2, 3, uint64, highp>\thighp_u64mat2x3;\n\ttypedef mat<2, 4, uint64, highp>\thighp_u64mat2x4;\n\ttypedef mat<3, 2, uint64, highp>\thighp_u64mat3x2;\n\ttypedef mat<3, 3, uint64, highp>\thighp_u64mat3x3;\n\ttypedef mat<3, 4, uint64, highp>\thighp_u64mat3x4;\n\ttypedef mat<4, 2, uint64, highp>\thighp_u64mat4x2;\n\ttypedef mat<4, 3, uint64, highp>\thighp_u64mat4x3;\n\ttypedef mat<4, 4, uint64, highp>\thighp_u64mat4x4;\n\n\ttypedef mat<2, 2, uint64, defaultp>\tu64mat2x2;\n\ttypedef mat<3, 2, uint64, defaultp>\tu64mat3x2;\n\ttypedef mat<4, 2, uint64, defaultp>\tu64mat4x2;\n\ttypedef mat<2, 3, uint64, defaultp>\tu64mat2x3;\n\ttypedef mat<3, 3, uint64, defaultp>\tu64mat3x3;\n\ttypedef mat<4, 3, uint64, defaultp>\tu64mat4x3;\n\ttypedef mat<2, 4, uint64, defaultp>\tu64mat2x4;\n\ttypedef mat<3, 4, uint64, defaultp>\tu64mat3x4;\n\ttypedef mat<4, 4, uint64, defaultp>\tu64mat4x4;\n\n\t// Quaternion\n\n\ttypedef qua<float, lowp>\t\t\tlowp_quat;\n\ttypedef qua<float, mediump>\t\t\tmediump_quat;\n\ttypedef qua<float, highp>\t\t\thighp_quat;\n\ttypedef qua<float, defaultp>\t\tquat;\n\n\ttypedef qua<float, lowp>\t\t\tlowp_fquat;\n\ttypedef qua<float, mediump>\t\t\tmediump_fquat;\n\ttypedef qua<float, highp>\t\t\thighp_fquat;\n\ttypedef qua<float, defaultp>\t\tfquat;\n\n\ttypedef qua<f32, lowp>\t\t\t\tlowp_f32quat;\n\ttypedef qua<f32, mediump>\t\t\tmediump_f32quat;\n\ttypedef qua<f32, highp>\t\t\t\thighp_f32quat;\n\ttypedef qua<f32, defaultp>\t\t\tf32quat;\n\n\ttypedef qua<double, lowp>\t\t\tlowp_dquat;\n\ttypedef qua<double, mediump>\t\tmediump_dquat;\n\ttypedef qua<double, highp>\t\t\thighp_dquat;\n\ttypedef qua<double, defaultp>\t\tdquat;\n\n\ttypedef qua<f64, lowp>\t\t\t\tlowp_f64quat;\n\ttypedef qua<f64, mediump>\t\t\tmediump_f64quat;\n\ttypedef qua<f64, highp>\t\t\t\thighp_f64quat;\n\ttypedef qua<f64, defaultp>\t\t\tf64quat;\n}//namespace glm\n\n\n"
  },
  {
    "path": "lib/gli/glm/geometric.hpp",
    "content": "/// @ref core\n/// @file glm/geometric.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n///\n/// @defgroup core_func_geometric Geometric functions\n/// @ingroup core\n///\n/// These operate on vectors as vectors, not component-wise.\n///\n/// Include <glm/geometric.hpp> to use these core features.\n\n#pragma once\n\n#include \"detail/type_vec3.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_func_geometric\n\t/// @{\n\n\t/// Returns the length of x, i.e., sqrt(x * x).\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/length.xml\">GLSL length man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T length(vec<L, T, Q> const& x);\n\n\t/// Returns the distance betwwen p0 and p1, i.e., length(p0 - p1).\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/distance.xml\">GLSL distance man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T distance(vec<L, T, Q> const& p0, vec<L, T, Q> const& p1);\n\n\t/// Returns the dot product of x and y, i.e., result = x * y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/dot.xml\">GLSL dot man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T dot(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the cross product of x and y.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/cross.xml\">GLSL cross man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> cross(vec<3, T, Q> const& x, vec<3, T, Q> const& y);\n\n\t/// Returns a vector in the same direction as x but with length of 1.\n\t/// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefined and generate an error.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/normalize.xml\">GLSL normalize man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> normalize(vec<L, T, Q> const& x);\n\n\t/// If dot(Nref, I) < 0.0, return N, otherwise, return -N.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/faceforward.xml\">GLSL faceforward man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> faceforward(\n\t\tvec<L, T, Q> const& N,\n\t\tvec<L, T, Q> const& I,\n\t\tvec<L, T, Q> const& Nref);\n\n\t/// For the incident vector I and surface orientation N,\n\t/// returns the reflection direction : result = I - 2.0 * dot(N, I) * N.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/reflect.xml\">GLSL reflect man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> reflect(\n\t\tvec<L, T, Q> const& I,\n\t\tvec<L, T, Q> const& N);\n\n\t/// For the incident vector I and surface normal N,\n\t/// and the ratio of indices of refraction eta,\n\t/// return the refraction vector.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/refract.xml\">GLSL refract man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> refract(\n\t\tvec<L, T, Q> const& I,\n\t\tvec<L, T, Q> const& N,\n\t\tT eta);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_geometric.inl\"\n"
  },
  {
    "path": "lib/gli/glm/glm.hpp",
    "content": "/// @ref core\n/// @file glm/glm.hpp\n///\n/// @defgroup core Core features\n///\n/// @brief Features that implement in C++ the GLSL specification as closely as possible.\n///\n/// The GLM core consists of C++ types that mirror GLSL types and\n/// C++ functions that mirror the GLSL functions.\n///\n/// The best documentation for GLM Core is the current GLSL specification,\n/// <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.clean.pdf\">version 4.2\n/// (pdf file)</a>.\n///\n/// GLM core functionalities require <glm/glm.hpp> to be included to be used.\n///\n///\n/// @defgroup core_vector Vector types\n///\n/// Vector types of two to four components with an exhaustive set of operators.\n///\n/// @ingroup core\n///\n///\n/// @defgroup core_vector_precision Vector types with precision qualifiers\n///\n/// @brief Vector types with precision qualifiers which may result in various precision in term of ULPs\n///\n/// GLSL allows defining qualifiers for particular variables.\n/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility,\n/// with OpenGL ES's GLSL, these qualifiers do have an effect.\n///\n/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing:\n/// a number of typedefs that use a particular qualifier.\n///\n/// None of these types make any guarantees about the actual qualifier used.\n///\n/// @ingroup core\n///\n///\n/// @defgroup core_matrix Matrix types\n///\n/// Matrix types of with C columns and R rows where C and R are values between 2 to 4 included.\n/// These types have exhaustive sets of operators.\n///\n/// @ingroup core\n///\n///\n/// @defgroup core_matrix_precision Matrix types with precision qualifiers\n///\n/// @brief Matrix types with precision qualifiers which may result in various precision in term of ULPs\n///\n/// GLSL allows defining qualifiers for particular variables.\n/// With OpenGL's GLSL, these qualifiers have no effect; they are there for compatibility,\n/// with OpenGL ES's GLSL, these qualifiers do have an effect.\n///\n/// C++ has no language equivalent to qualifier qualifiers. So GLM provides the next-best thing:\n/// a number of typedefs that use a particular qualifier.\n///\n/// None of these types make any guarantees about the actual qualifier used.\n///\n/// @ingroup core\n///\n///\n/// @defgroup ext Stable extensions\n///\n/// @brief Additional features not specified by GLSL specification.\n///\n/// EXT extensions are fully tested and documented.\n///\n/// Even if it's highly unrecommended, it's possible to include all the extensions at once by\n/// including <glm/ext.hpp>. Otherwise, each extension needs to be included  a specific file.\n///\n///\n/// @defgroup gtc Recommended extensions\n///\n/// @brief Additional features not specified by GLSL specification.\n///\n/// GTC extensions aim to be stable with tests and documentation.\n///\n/// Even if it's highly unrecommended, it's possible to include all the extensions at once by\n/// including <glm/ext.hpp>. Otherwise, each extension needs to be included  a specific file.\n///\n///\n/// @defgroup gtx Experimental extensions\n///\n/// @brief Experimental features not specified by GLSL specification.\n///\n/// Experimental extensions are useful functions and types, but the development of\n/// their API and functionality is not necessarily stable. They can change\n/// substantially between versions. Backwards compatibility is not much of an issue\n/// for them.\n///\n/// Even if it's highly unrecommended, it's possible to include all the extensions\n/// at once by including <glm/ext.hpp>. Otherwise, each extension needs to be\n/// included  a specific file.\n///\n/// @mainpage OpenGL Mathematics (GLM)\n/// - Website: <a href=\"https://glm.g-truc.net\">glm.g-truc.net</a>\n/// - <a href=\"modules.html\">GLM API documentation</a>\n/// - <a href=\"https://github.com/g-truc/glm/blob/master/manual.md\">GLM Manual</a>\n\n#include \"detail/_fixes.hpp\"\n\n#include \"detail/setup.hpp\"\n\n#pragma once\n\n#include <cmath>\n#include <climits>\n#include <cfloat>\n#include <limits>\n#include <cassert>\n#include \"fwd.hpp\"\n\n#include \"vec2.hpp\"\n#include \"vec3.hpp\"\n#include \"vec4.hpp\"\n#include \"mat2x2.hpp\"\n#include \"mat2x3.hpp\"\n#include \"mat2x4.hpp\"\n#include \"mat3x2.hpp\"\n#include \"mat3x3.hpp\"\n#include \"mat3x4.hpp\"\n#include \"mat4x2.hpp\"\n#include \"mat4x3.hpp\"\n#include \"mat4x4.hpp\"\n\n#include \"trigonometric.hpp\"\n#include \"exponential.hpp\"\n#include \"common.hpp\"\n#include \"packing.hpp\"\n#include \"geometric.hpp\"\n#include \"matrix.hpp\"\n#include \"vector_relational.hpp\"\n#include \"integer.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/bitfield.hpp",
    "content": "/// @ref gtc_bitfield\n/// @file glm/gtc/bitfield.hpp\n///\n/// @see core (dependence)\n/// @see gtc_bitfield (dependence)\n///\n/// @defgroup gtc_bitfield GLM_GTC_bitfield\n/// @ingroup gtc\n///\n/// Include <glm/gtc/bitfield.hpp> to use the features of this extension.\n///\n/// Allow to perform bit operations on integer values\n\n#include \"../detail/setup.hpp\"\n\n#pragma once\n\n// Dependencies\n#include \"../ext/scalar_int_sized.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_vectorize.hpp\"\n#include \"type_precision.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_bitfield extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_bitfield\n\t/// @{\n\n\t/// Build a mask of 'count' bits\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType mask(genIUType Bits);\n\n\t/// Build a mask of 'count' bits\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed and unsigned integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> mask(vec<L, T, Q> const& v);\n\n\t/// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side.\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType bitfieldRotateRight(genIUType In, int Shift);\n\n\t/// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed and unsigned integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldRotateRight(vec<L, T, Q> const& In, int Shift);\n\n\t/// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side.\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType bitfieldRotateLeft(genIUType In, int Shift);\n\n\t/// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed and unsigned integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldRotateLeft(vec<L, T, Q> const& In, int Shift);\n\n\t/// Set to 1 a range of bits.\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount);\n\n\t/// Set to 1 a range of bits.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed and unsigned integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldFillOne(vec<L, T, Q> const& Value, int FirstBit, int BitCount);\n\n\t/// Set to 0 a range of bits.\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount);\n\n\t/// Set to 0 a range of bits.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Signed and unsigned integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_bitfield\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldFillZero(vec<L, T, Q> const& Value, int FirstBit, int BitCount);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of x followed by the first bit of y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int16 bitfieldInterleave(int8 x, int8 y);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of x followed by the first bit of y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint16 bitfieldInterleave(uint8 x, uint8 y);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of v.x followed by the first bit of v.y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint16 bitfieldInterleave(u8vec2 const& v);\n\n\t/// Deinterleaves the bits of x.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL glm::u8vec2 bitfieldDeinterleave(glm::uint16 x);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of x followed by the first bit of y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int32 bitfieldInterleave(int16 x, int16 y);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of x followed by the first bit of y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint32 bitfieldInterleave(uint16 x, uint16 y);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of v.x followed by the first bit of v.y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint32 bitfieldInterleave(u16vec2 const& v);\n\n\t/// Deinterleaves the bits of x.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL glm::u16vec2 bitfieldDeinterleave(glm::uint32 x);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of x followed by the first bit of y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of x followed by the first bit of y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y);\n\n\t/// Interleaves the bits of x and y.\n\t/// The first bit is the first bit of v.x followed by the first bit of v.y.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint64 bitfieldInterleave(u32vec2 const& v);\n\n\t/// Deinterleaves the bits of x.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL glm::u32vec2 bitfieldDeinterleave(glm::uint64 x);\n\n\t/// Interleaves the bits of x, y and z.\n\t/// The first bit is the first bit of x followed by the first bit of y and the first bit of z.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z);\n\n\t/// Interleaves the bits of x, y and z.\n\t/// The first bit is the first bit of x followed by the first bit of y and the first bit of z.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z);\n\n\t/// Interleaves the bits of x, y and z.\n\t/// The first bit is the first bit of x followed by the first bit of y and the first bit of z.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z);\n\n\t/// Interleaves the bits of x, y and z.\n\t/// The first bit is the first bit of x followed by the first bit of y and the first bit of z.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z);\n\n\t/// Interleaves the bits of x, y and z.\n\t/// The first bit is the first bit of x followed by the first bit of y and the first bit of z.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y, int32 z);\n\n\t/// Interleaves the bits of x, y and z.\n\t/// The first bit is the first bit of x followed by the first bit of y and the first bit of z.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z);\n\n\t/// Interleaves the bits of x, y, z and w.\n\t/// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w);\n\n\t/// Interleaves the bits of x, y, z and w.\n\t/// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w);\n\n\t/// Interleaves the bits of x, y, z and w.\n\t/// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w);\n\n\t/// Interleaves the bits of x, y, z and w.\n\t/// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.\n\t/// The other bits are interleaved following the previous sequence.\n\t///\n\t/// @see gtc_bitfield\n\tGLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w);\n\n\t/// @}\n} //namespace glm\n\n#include \"bitfield.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/bitfield.inl",
    "content": "/// @ref gtc_bitfield\n\n#include \"../simd/integer.h\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<typename PARAM, typename RET>\n\tGLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y);\n\n\ttemplate<typename PARAM, typename RET>\n\tGLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z);\n\n\ttemplate<typename PARAM, typename RET>\n\tGLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w);\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave(glm::uint8 x, glm::uint8 y)\n\t{\n\t\tglm::uint16 REG1(x);\n\t\tglm::uint16 REG2(y);\n\n\t\tREG1 = ((REG1 <<  4) | REG1) & static_cast<glm::uint16>(0x0F0F);\n\t\tREG2 = ((REG2 <<  4) | REG2) & static_cast<glm::uint16>(0x0F0F);\n\n\t\tREG1 = ((REG1 <<  2) | REG1) & static_cast<glm::uint16>(0x3333);\n\t\tREG2 = ((REG2 <<  2) | REG2) & static_cast<glm::uint16>(0x3333);\n\n\t\tREG1 = ((REG1 <<  1) | REG1) & static_cast<glm::uint16>(0x5555);\n\t\tREG2 = ((REG2 <<  1) | REG2) & static_cast<glm::uint16>(0x5555);\n\n\t\treturn REG1 | static_cast<glm::uint16>(REG2 << 1);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint16 x, glm::uint16 y)\n\t{\n\t\tglm::uint32 REG1(x);\n\t\tglm::uint32 REG2(y);\n\n\t\tREG1 = ((REG1 <<  8) | REG1) & static_cast<glm::uint32>(0x00FF00FF);\n\t\tREG2 = ((REG2 <<  8) | REG2) & static_cast<glm::uint32>(0x00FF00FF);\n\n\t\tREG1 = ((REG1 <<  4) | REG1) & static_cast<glm::uint32>(0x0F0F0F0F);\n\t\tREG2 = ((REG2 <<  4) | REG2) & static_cast<glm::uint32>(0x0F0F0F0F);\n\n\t\tREG1 = ((REG1 <<  2) | REG1) & static_cast<glm::uint32>(0x33333333);\n\t\tREG2 = ((REG2 <<  2) | REG2) & static_cast<glm::uint32>(0x33333333);\n\n\t\tREG1 = ((REG1 <<  1) | REG1) & static_cast<glm::uint32>(0x55555555);\n\t\tREG2 = ((REG2 <<  1) | REG2) & static_cast<glm::uint32>(0x55555555);\n\n\t\treturn REG1 | (REG2 << 1);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y)\n\t{\n\t\tglm::uint64 REG1(x);\n\t\tglm::uint64 REG2(y);\n\n\t\tREG1 = ((REG1 << 16) | REG1) & static_cast<glm::uint64>(0x0000FFFF0000FFFFull);\n\t\tREG2 = ((REG2 << 16) | REG2) & static_cast<glm::uint64>(0x0000FFFF0000FFFFull);\n\n\t\tREG1 = ((REG1 <<  8) | REG1) & static_cast<glm::uint64>(0x00FF00FF00FF00FFull);\n\t\tREG2 = ((REG2 <<  8) | REG2) & static_cast<glm::uint64>(0x00FF00FF00FF00FFull);\n\n\t\tREG1 = ((REG1 <<  4) | REG1) & static_cast<glm::uint64>(0x0F0F0F0F0F0F0F0Full);\n\t\tREG2 = ((REG2 <<  4) | REG2) & static_cast<glm::uint64>(0x0F0F0F0F0F0F0F0Full);\n\n\t\tREG1 = ((REG1 <<  2) | REG1) & static_cast<glm::uint64>(0x3333333333333333ull);\n\t\tREG2 = ((REG2 <<  2) | REG2) & static_cast<glm::uint64>(0x3333333333333333ull);\n\n\t\tREG1 = ((REG1 <<  1) | REG1) & static_cast<glm::uint64>(0x5555555555555555ull);\n\t\tREG2 = ((REG2 <<  1) | REG2) & static_cast<glm::uint64>(0x5555555555555555ull);\n\n\t\treturn REG1 | (REG2 << 1);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z)\n\t{\n\t\tglm::uint32 REG1(x);\n\t\tglm::uint32 REG2(y);\n\t\tglm::uint32 REG3(z);\n\n\t\tREG1 = ((REG1 << 16) | REG1) & static_cast<glm::uint32>(0xFF0000FFu);\n\t\tREG2 = ((REG2 << 16) | REG2) & static_cast<glm::uint32>(0xFF0000FFu);\n\t\tREG3 = ((REG3 << 16) | REG3) & static_cast<glm::uint32>(0xFF0000FFu);\n\n\t\tREG1 = ((REG1 <<  8) | REG1) & static_cast<glm::uint32>(0x0F00F00Fu);\n\t\tREG2 = ((REG2 <<  8) | REG2) & static_cast<glm::uint32>(0x0F00F00Fu);\n\t\tREG3 = ((REG3 <<  8) | REG3) & static_cast<glm::uint32>(0x0F00F00Fu);\n\n\t\tREG1 = ((REG1 <<  4) | REG1) & static_cast<glm::uint32>(0xC30C30C3u);\n\t\tREG2 = ((REG2 <<  4) | REG2) & static_cast<glm::uint32>(0xC30C30C3u);\n\t\tREG3 = ((REG3 <<  4) | REG3) & static_cast<glm::uint32>(0xC30C30C3u);\n\n\t\tREG1 = ((REG1 <<  2) | REG1) & static_cast<glm::uint32>(0x49249249u);\n\t\tREG2 = ((REG2 <<  2) | REG2) & static_cast<glm::uint32>(0x49249249u);\n\t\tREG3 = ((REG3 <<  2) | REG3) & static_cast<glm::uint32>(0x49249249u);\n\n\t\treturn REG1 | (REG2 << 1) | (REG3 << 2);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z)\n\t{\n\t\tglm::uint64 REG1(x);\n\t\tglm::uint64 REG2(y);\n\t\tglm::uint64 REG3(z);\n\n\t\tREG1 = ((REG1 << 32) | REG1) & static_cast<glm::uint64>(0xFFFF00000000FFFFull);\n\t\tREG2 = ((REG2 << 32) | REG2) & static_cast<glm::uint64>(0xFFFF00000000FFFFull);\n\t\tREG3 = ((REG3 << 32) | REG3) & static_cast<glm::uint64>(0xFFFF00000000FFFFull);\n\n\t\tREG1 = ((REG1 << 16) | REG1) & static_cast<glm::uint64>(0x00FF0000FF0000FFull);\n\t\tREG2 = ((REG2 << 16) | REG2) & static_cast<glm::uint64>(0x00FF0000FF0000FFull);\n\t\tREG3 = ((REG3 << 16) | REG3) & static_cast<glm::uint64>(0x00FF0000FF0000FFull);\n\n\t\tREG1 = ((REG1 <<  8) | REG1) & static_cast<glm::uint64>(0xF00F00F00F00F00Full);\n\t\tREG2 = ((REG2 <<  8) | REG2) & static_cast<glm::uint64>(0xF00F00F00F00F00Full);\n\t\tREG3 = ((REG3 <<  8) | REG3) & static_cast<glm::uint64>(0xF00F00F00F00F00Full);\n\n\t\tREG1 = ((REG1 <<  4) | REG1) & static_cast<glm::uint64>(0x30C30C30C30C30C3ull);\n\t\tREG2 = ((REG2 <<  4) | REG2) & static_cast<glm::uint64>(0x30C30C30C30C30C3ull);\n\t\tREG3 = ((REG3 <<  4) | REG3) & static_cast<glm::uint64>(0x30C30C30C30C30C3ull);\n\n\t\tREG1 = ((REG1 <<  2) | REG1) & static_cast<glm::uint64>(0x9249249249249249ull);\n\t\tREG2 = ((REG2 <<  2) | REG2) & static_cast<glm::uint64>(0x9249249249249249ull);\n\t\tREG3 = ((REG3 <<  2) | REG3) & static_cast<glm::uint64>(0x9249249249249249ull);\n\n\t\treturn REG1 | (REG2 << 1) | (REG3 << 2);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y, glm::uint32 z)\n\t{\n\t\tglm::uint64 REG1(x);\n\t\tglm::uint64 REG2(y);\n\t\tglm::uint64 REG3(z);\n\n\t\tREG1 = ((REG1 << 32) | REG1) & static_cast<glm::uint64>(0xFFFF00000000FFFFull);\n\t\tREG2 = ((REG2 << 32) | REG2) & static_cast<glm::uint64>(0xFFFF00000000FFFFull);\n\t\tREG3 = ((REG3 << 32) | REG3) & static_cast<glm::uint64>(0xFFFF00000000FFFFull);\n\n\t\tREG1 = ((REG1 << 16) | REG1) & static_cast<glm::uint64>(0x00FF0000FF0000FFull);\n\t\tREG2 = ((REG2 << 16) | REG2) & static_cast<glm::uint64>(0x00FF0000FF0000FFull);\n\t\tREG3 = ((REG3 << 16) | REG3) & static_cast<glm::uint64>(0x00FF0000FF0000FFull);\n\n\t\tREG1 = ((REG1 <<  8) | REG1) & static_cast<glm::uint64>(0xF00F00F00F00F00Full);\n\t\tREG2 = ((REG2 <<  8) | REG2) & static_cast<glm::uint64>(0xF00F00F00F00F00Full);\n\t\tREG3 = ((REG3 <<  8) | REG3) & static_cast<glm::uint64>(0xF00F00F00F00F00Full);\n\n\t\tREG1 = ((REG1 <<  4) | REG1) & static_cast<glm::uint64>(0x30C30C30C30C30C3ull);\n\t\tREG2 = ((REG2 <<  4) | REG2) & static_cast<glm::uint64>(0x30C30C30C30C30C3ull);\n\t\tREG3 = ((REG3 <<  4) | REG3) & static_cast<glm::uint64>(0x30C30C30C30C30C3ull);\n\n\t\tREG1 = ((REG1 <<  2) | REG1) & static_cast<glm::uint64>(0x9249249249249249ull);\n\t\tREG2 = ((REG2 <<  2) | REG2) & static_cast<glm::uint64>(0x9249249249249249ull);\n\t\tREG3 = ((REG3 <<  2) | REG3) & static_cast<glm::uint64>(0x9249249249249249ull);\n\n\t\treturn REG1 | (REG2 << 1) | (REG3 << 2);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w)\n\t{\n\t\tglm::uint32 REG1(x);\n\t\tglm::uint32 REG2(y);\n\t\tglm::uint32 REG3(z);\n\t\tglm::uint32 REG4(w);\n\n\t\tREG1 = ((REG1 << 12) | REG1) & static_cast<glm::uint32>(0x000F000Fu);\n\t\tREG2 = ((REG2 << 12) | REG2) & static_cast<glm::uint32>(0x000F000Fu);\n\t\tREG3 = ((REG3 << 12) | REG3) & static_cast<glm::uint32>(0x000F000Fu);\n\t\tREG4 = ((REG4 << 12) | REG4) & static_cast<glm::uint32>(0x000F000Fu);\n\n\t\tREG1 = ((REG1 <<  6) | REG1) & static_cast<glm::uint32>(0x03030303u);\n\t\tREG2 = ((REG2 <<  6) | REG2) & static_cast<glm::uint32>(0x03030303u);\n\t\tREG3 = ((REG3 <<  6) | REG3) & static_cast<glm::uint32>(0x03030303u);\n\t\tREG4 = ((REG4 <<  6) | REG4) & static_cast<glm::uint32>(0x03030303u);\n\n\t\tREG1 = ((REG1 <<  3) | REG1) & static_cast<glm::uint32>(0x11111111u);\n\t\tREG2 = ((REG2 <<  3) | REG2) & static_cast<glm::uint32>(0x11111111u);\n\t\tREG3 = ((REG3 <<  3) | REG3) & static_cast<glm::uint32>(0x11111111u);\n\t\tREG4 = ((REG4 <<  3) | REG4) & static_cast<glm::uint32>(0x11111111u);\n\n\t\treturn REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3);\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z, glm::uint16 w)\n\t{\n\t\tglm::uint64 REG1(x);\n\t\tglm::uint64 REG2(y);\n\t\tglm::uint64 REG3(z);\n\t\tglm::uint64 REG4(w);\n\n\t\tREG1 = ((REG1 << 24) | REG1) & static_cast<glm::uint64>(0x000000FF000000FFull);\n\t\tREG2 = ((REG2 << 24) | REG2) & static_cast<glm::uint64>(0x000000FF000000FFull);\n\t\tREG3 = ((REG3 << 24) | REG3) & static_cast<glm::uint64>(0x000000FF000000FFull);\n\t\tREG4 = ((REG4 << 24) | REG4) & static_cast<glm::uint64>(0x000000FF000000FFull);\n\n\t\tREG1 = ((REG1 << 12) | REG1) & static_cast<glm::uint64>(0x000F000F000F000Full);\n\t\tREG2 = ((REG2 << 12) | REG2) & static_cast<glm::uint64>(0x000F000F000F000Full);\n\t\tREG3 = ((REG3 << 12) | REG3) & static_cast<glm::uint64>(0x000F000F000F000Full);\n\t\tREG4 = ((REG4 << 12) | REG4) & static_cast<glm::uint64>(0x000F000F000F000Full);\n\n\t\tREG1 = ((REG1 <<  6) | REG1) & static_cast<glm::uint64>(0x0303030303030303ull);\n\t\tREG2 = ((REG2 <<  6) | REG2) & static_cast<glm::uint64>(0x0303030303030303ull);\n\t\tREG3 = ((REG3 <<  6) | REG3) & static_cast<glm::uint64>(0x0303030303030303ull);\n\t\tREG4 = ((REG4 <<  6) | REG4) & static_cast<glm::uint64>(0x0303030303030303ull);\n\n\t\tREG1 = ((REG1 <<  3) | REG1) & static_cast<glm::uint64>(0x1111111111111111ull);\n\t\tREG2 = ((REG2 <<  3) | REG2) & static_cast<glm::uint64>(0x1111111111111111ull);\n\t\tREG3 = ((REG3 <<  3) | REG3) & static_cast<glm::uint64>(0x1111111111111111ull);\n\t\tREG4 = ((REG4 <<  3) | REG4) & static_cast<glm::uint64>(0x1111111111111111ull);\n\n\t\treturn REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3);\n\t}\n}//namespace detail\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType mask(genIUType Bits)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, \"'mask' accepts only integer values\");\n\n\t\treturn Bits >= sizeof(genIUType) * 8 ? ~static_cast<genIUType>(0) : (static_cast<genIUType>(1) << Bits) - static_cast<genIUType>(1);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> mask(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'mask' accepts only integer values\");\n\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(mask, v);\n\t}\n\n\ttemplate<typename genIType>\n\tGLM_FUNC_QUALIFIER genIType bitfieldRotateRight(genIType In, int Shift)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIType>::is_integer, \"'bitfieldRotateRight' accepts only integer values\");\n\n\t\tint const BitSize = static_cast<genIType>(sizeof(genIType) * 8);\n\t\treturn (In << static_cast<genIType>(Shift)) | (In >> static_cast<genIType>(BitSize - Shift));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldRotateRight(vec<L, T, Q> const& In, int Shift)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'bitfieldRotateRight' accepts only integer values\");\n\n\t\tint const BitSize = static_cast<int>(sizeof(T) * 8);\n\t\treturn (In << static_cast<T>(Shift)) | (In >> static_cast<T>(BitSize - Shift));\n\t}\n\n\ttemplate<typename genIType>\n\tGLM_FUNC_QUALIFIER genIType bitfieldRotateLeft(genIType In, int Shift)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genIType>::is_integer, \"'bitfieldRotateLeft' accepts only integer values\");\n\n\t\tint const BitSize = static_cast<genIType>(sizeof(genIType) * 8);\n\t\treturn (In >> static_cast<genIType>(Shift)) | (In << static_cast<genIType>(BitSize - Shift));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldRotateLeft(vec<L, T, Q> const& In, int Shift)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, \"'bitfieldRotateLeft' accepts only integer values\");\n\n\t\tint const BitSize = static_cast<int>(sizeof(T) * 8);\n\t\treturn (In >> static_cast<T>(Shift)) | (In << static_cast<T>(BitSize - Shift));\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount)\n\t{\n\t\treturn Value | static_cast<genIUType>(mask(BitCount) << FirstBit);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldFillOne(vec<L, T, Q> const& Value, int FirstBit, int BitCount)\n\t{\n\t\treturn Value | static_cast<T>(mask(BitCount) << FirstBit);\n\t}\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount)\n\t{\n\t\treturn Value & static_cast<genIUType>(~(mask(BitCount) << FirstBit));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> bitfieldFillZero(vec<L, T, Q> const& Value, int FirstBit, int BitCount)\n\t{\n\t\treturn Value & static_cast<T>(~(mask(BitCount) << FirstBit));\n\t}\n\n\tGLM_FUNC_QUALIFIER int16 bitfieldInterleave(int8 x, int8 y)\n\t{\n\t\tunion sign8\n\t\t{\n\t\t\tint8 i;\n\t\t\tuint8 u;\n\t\t} sign_x, sign_y;\n\n\t\tunion sign16\n\t\t{\n\t\t\tint16 i;\n\t\t\tuint16 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 bitfieldInterleave(uint8 x, uint8 y)\n\t{\n\t\treturn detail::bitfieldInterleave<uint8, uint16>(x, y);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 bitfieldInterleave(u8vec2 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint8, uint16>(v.x, v.y);\n\t}\n\n\tGLM_FUNC_QUALIFIER u8vec2 bitfieldDeinterleave(glm::uint16 x)\n\t{\n\t\tuint16 REG1(x);\n\t\tuint16 REG2(x >>= 1);\n\n\t\tREG1 = REG1 & static_cast<uint16>(0x5555);\n\t\tREG2 = REG2 & static_cast<uint16>(0x5555);\n\n\t\tREG1 = ((REG1 >> 1) | REG1) & static_cast<uint16>(0x3333);\n\t\tREG2 = ((REG2 >> 1) | REG2) & static_cast<uint16>(0x3333);\n\n\t\tREG1 = ((REG1 >> 2) | REG1) & static_cast<uint16>(0x0F0F);\n\t\tREG2 = ((REG2 >> 2) | REG2) & static_cast<uint16>(0x0F0F);\n\n\t\tREG1 = ((REG1 >> 4) | REG1) & static_cast<uint16>(0x00FF);\n\t\tREG2 = ((REG2 >> 4) | REG2) & static_cast<uint16>(0x00FF);\n\n\t\tREG1 = ((REG1 >> 8) | REG1) & static_cast<uint16>(0xFFFF);\n\t\tREG2 = ((REG2 >> 8) | REG2) & static_cast<uint16>(0xFFFF);\n\n\t\treturn glm::u8vec2(REG1, REG2);\n\t}\n\n\tGLM_FUNC_QUALIFIER int32 bitfieldInterleave(int16 x, int16 y)\n\t{\n\t\tunion sign16\n\t\t{\n\t\t\tint16 i;\n\t\t\tuint16 u;\n\t\t} sign_x, sign_y;\n\n\t\tunion sign32\n\t\t{\n\t\t\tint32 i;\n\t\t\tuint32 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint16 x, uint16 y)\n\t{\n\t\treturn detail::bitfieldInterleave<uint16, uint32>(x, y);\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(u16vec2 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint16, uint32>(v.x, v.y);\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::u16vec2 bitfieldDeinterleave(glm::uint32 x)\n\t{\n\t\tglm::uint32 REG1(x);\n\t\tglm::uint32 REG2(x >>= 1);\n\n\t\tREG1 = REG1 & static_cast<glm::uint32>(0x55555555);\n\t\tREG2 = REG2 & static_cast<glm::uint32>(0x55555555);\n\n\t\tREG1 = ((REG1 >> 1) | REG1) & static_cast<glm::uint32>(0x33333333);\n\t\tREG2 = ((REG2 >> 1) | REG2) & static_cast<glm::uint32>(0x33333333);\n\n\t\tREG1 = ((REG1 >> 2) | REG1) & static_cast<glm::uint32>(0x0F0F0F0F);\n\t\tREG2 = ((REG2 >> 2) | REG2) & static_cast<glm::uint32>(0x0F0F0F0F);\n\n\t\tREG1 = ((REG1 >> 4) | REG1) & static_cast<glm::uint32>(0x00FF00FF);\n\t\tREG2 = ((REG2 >> 4) | REG2) & static_cast<glm::uint32>(0x00FF00FF);\n\n\t\tREG1 = ((REG1 >> 8) | REG1) & static_cast<glm::uint32>(0x0000FFFF);\n\t\tREG2 = ((REG2 >> 8) | REG2) & static_cast<glm::uint32>(0x0000FFFF);\n\n\t\treturn glm::u16vec2(REG1, REG2);\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y)\n\t{\n\t\tunion sign32\n\t\t{\n\t\t\tint32 i;\n\t\t\tuint32 u;\n\t\t} sign_x, sign_y;\n\n\t\tunion sign64\n\t\t{\n\t\t\tint64 i;\n\t\t\tuint64 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y)\n\t{\n\t\treturn detail::bitfieldInterleave<uint32, uint64>(x, y);\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(u32vec2 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint32, uint64>(v.x, v.y);\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::u32vec2 bitfieldDeinterleave(glm::uint64 x)\n\t{\n\t\tglm::uint64 REG1(x);\n\t\tglm::uint64 REG2(x >>= 1);\n\n\t\tREG1 = REG1 & static_cast<glm::uint64>(0x5555555555555555ull);\n\t\tREG2 = REG2 & static_cast<glm::uint64>(0x5555555555555555ull);\n\n\t\tREG1 = ((REG1 >> 1) | REG1) & static_cast<glm::uint64>(0x3333333333333333ull);\n\t\tREG2 = ((REG2 >> 1) | REG2) & static_cast<glm::uint64>(0x3333333333333333ull);\n\n\t\tREG1 = ((REG1 >> 2) | REG1) & static_cast<glm::uint64>(0x0F0F0F0F0F0F0F0Full);\n\t\tREG2 = ((REG2 >> 2) | REG2) & static_cast<glm::uint64>(0x0F0F0F0F0F0F0F0Full);\n\n\t\tREG1 = ((REG1 >> 4) | REG1) & static_cast<glm::uint64>(0x00FF00FF00FF00FFull);\n\t\tREG2 = ((REG2 >> 4) | REG2) & static_cast<glm::uint64>(0x00FF00FF00FF00FFull);\n\n\t\tREG1 = ((REG1 >> 8) | REG1) & static_cast<glm::uint64>(0x0000FFFF0000FFFFull);\n\t\tREG2 = ((REG2 >> 8) | REG2) & static_cast<glm::uint64>(0x0000FFFF0000FFFFull);\n\n\t\tREG1 = ((REG1 >> 16) | REG1) & static_cast<glm::uint64>(0x00000000FFFFFFFFull);\n\t\tREG2 = ((REG2 >> 16) | REG2) & static_cast<glm::uint64>(0x00000000FFFFFFFFull);\n\n\t\treturn glm::u32vec2(REG1, REG2);\n\t}\n\n\tGLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z)\n\t{\n\t\tunion sign8\n\t\t{\n\t\t\tint8 i;\n\t\t\tuint8 u;\n\t\t} sign_x, sign_y, sign_z;\n\n\t\tunion sign32\n\t\t{\n\t\t\tint32 i;\n\t\t\tuint32 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tsign_z.i = z;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z)\n\t{\n\t\treturn detail::bitfieldInterleave<uint8, uint32>(x, y, z);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec3 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint8, uint32>(v.x, v.y, v.z);\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z)\n\t{\n\t\tunion sign16\n\t\t{\n\t\t\tint16 i;\n\t\t\tuint16 u;\n\t\t} sign_x, sign_y, sign_z;\n\n\t\tunion sign64\n\t\t{\n\t\t\tint64 i;\n\t\t\tuint64 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tsign_z.i = z;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z)\n\t{\n\t\treturn detail::bitfieldInterleave<uint32, uint64>(x, y, z);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec3 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint32, uint64>(v.x, v.y, v.z);\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y, int32 z)\n\t{\n\t\tunion sign16\n\t\t{\n\t\t\tint32 i;\n\t\t\tuint32 u;\n\t\t} sign_x, sign_y, sign_z;\n\n\t\tunion sign64\n\t\t{\n\t\t\tint64 i;\n\t\t\tuint64 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tsign_z.i = z;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z)\n\t{\n\t\treturn detail::bitfieldInterleave<uint32, uint64>(x, y, z);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u32vec3 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint32, uint64>(v.x, v.y, v.z);\n\t}\n\n\tGLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w)\n\t{\n\t\tunion sign8\n\t\t{\n\t\t\tint8 i;\n\t\t\tuint8 u;\n\t\t} sign_x, sign_y, sign_z, sign_w;\n\n\t\tunion sign32\n\t\t{\n\t\t\tint32 i;\n\t\t\tuint32 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tsign_z.i = z;\n\t\tsign_w.i = w;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w)\n\t{\n\t\treturn detail::bitfieldInterleave<uint8, uint32>(x, y, z, w);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 bitfieldInterleave(u8vec4 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint8, uint32>(v.x, v.y, v.z, v.w);\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w)\n\t{\n\t\tunion sign16\n\t\t{\n\t\t\tint16 i;\n\t\t\tuint16 u;\n\t\t} sign_x, sign_y, sign_z, sign_w;\n\n\t\tunion sign64\n\t\t{\n\t\t\tint64 i;\n\t\t\tuint64 u;\n\t\t} result;\n\n\t\tsign_x.i = x;\n\t\tsign_y.i = y;\n\t\tsign_z.i = z;\n\t\tsign_w.i = w;\n\t\tresult.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u);\n\n\t\treturn result.i;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w)\n\t{\n\t\treturn detail::bitfieldInterleave<uint16, uint64>(x, y, z, w);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 bitfieldInterleave(u16vec4 const& v)\n\t{\n\t\treturn detail::bitfieldInterleave<uint16, uint64>(v.x, v.y, v.z, v.w);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/color_space.hpp",
    "content": "/// @ref gtc_color_space\n/// @file glm/gtc/color_space.hpp\n///\n/// @see core (dependence)\n/// @see gtc_color_space (dependence)\n///\n/// @defgroup gtc_color_space GLM_GTC_color_space\n/// @ingroup gtc\n///\n/// Include <glm/gtc/color_space.hpp> to use the features of this extension.\n///\n/// Allow to perform bit operations on integer values\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../exponential.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_color_space extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_color_space\n\t/// @{\n\n\t/// Convert a linear color to sRGB color using a standard gamma correction.\n\t/// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> convertLinearToSRGB(vec<L, T, Q> const& ColorLinear);\n\n\t/// Convert a linear color to sRGB color using a custom gamma correction.\n\t/// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> convertLinearToSRGB(vec<L, T, Q> const& ColorLinear, T Gamma);\n\n\t/// Convert a sRGB color to linear color using a standard gamma correction.\n\t/// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> convertSRGBToLinear(vec<L, T, Q> const& ColorSRGB);\n\n\t/// Convert a sRGB color to linear color using a custom gamma correction.\n\t// IEC 61966-2-1:1999 / Rec. 709 specification https://www.w3.org/Graphics/Color/srgb\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> convertSRGBToLinear(vec<L, T, Q> const& ColorSRGB, T Gamma);\n\n\t/// @}\n} //namespace glm\n\n#include \"color_space.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/color_space.inl",
    "content": "/// @ref gtc_color_space\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_rgbToSrgb\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& ColorRGB, T GammaCorrection)\n\t\t{\n\t\t\tvec<L, T, Q> const ClampedColor(clamp(ColorRGB, static_cast<T>(0), static_cast<T>(1)));\n\n\t\t\treturn mix(\n\t\t\t\tpow(ClampedColor, vec<L, T, Q>(GammaCorrection)) * static_cast<T>(1.055) - static_cast<T>(0.055),\n\t\t\t\tClampedColor * static_cast<T>(12.92),\n\t\t\t\tlessThan(ClampedColor, vec<L, T, Q>(static_cast<T>(0.0031308))));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_rgbToSrgb<4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorRGB, T GammaCorrection)\n\t\t{\n\t\t\treturn vec<4, T, Q>(compute_rgbToSrgb<3, T, Q>::call(vec<3, T, Q>(ColorRGB), GammaCorrection), ColorRGB.w);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_srgbToRgb\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& ColorSRGB, T Gamma)\n\t\t{\n\t\t\treturn mix(\n\t\t\t\tpow((ColorSRGB + static_cast<T>(0.055)) * static_cast<T>(0.94786729857819905213270142180095), vec<L, T, Q>(Gamma)),\n\t\t\t\tColorSRGB * static_cast<T>(0.07739938080495356037151702786378),\n\t\t\t\tlessThanEqual(ColorSRGB, vec<L, T, Q>(static_cast<T>(0.04045))));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_srgbToRgb<4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, T, Q> call(vec<4, T, Q> const& ColorSRGB, T Gamma)\n\t\t{\n\t\t\treturn vec<4, T, Q>(compute_srgbToRgb<3, T, Q>::call(vec<3, T, Q>(ColorSRGB), Gamma), ColorSRGB.w);\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> convertLinearToSRGB(vec<L, T, Q> const& ColorLinear)\n\t{\n\t\treturn detail::compute_rgbToSrgb<L, T, Q>::call(ColorLinear, static_cast<T>(0.41666));\n\t}\n\n\t// Based on Ian Taylor http://chilliant.blogspot.fr/2012/08/srgb-approximations-for-hlsl.html\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER vec<3, float, lowp> convertLinearToSRGB(vec<3, float, lowp> const& ColorLinear)\n\t{\n\t\tvec<3, float, lowp> S1 = sqrt(ColorLinear);\n\t\tvec<3, float, lowp> S2 = sqrt(S1);\n\t\tvec<3, float, lowp> S3 = sqrt(S2);\n\t\treturn 0.662002687f * S1 + 0.684122060f * S2 - 0.323583601f * S3 - 0.0225411470f * ColorLinear;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> convertLinearToSRGB(vec<L, T, Q> const& ColorLinear, T Gamma)\n\t{\n\t\treturn detail::compute_rgbToSrgb<L, T, Q>::call(ColorLinear, static_cast<T>(1) / Gamma);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> convertSRGBToLinear(vec<L, T, Q> const& ColorSRGB)\n\t{\n\t\treturn detail::compute_srgbToRgb<L, T, Q>::call(ColorSRGB, static_cast<T>(2.4));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> convertSRGBToLinear(vec<L, T, Q> const& ColorSRGB, T Gamma)\n\t{\n\t\treturn detail::compute_srgbToRgb<L, T, Q>::call(ColorSRGB, Gamma);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/constants.hpp",
    "content": "/// @ref gtc_constants\n/// @file glm/gtc/constants.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_constants GLM_GTC_constants\n/// @ingroup gtc\n///\n/// Include <glm/gtc/constants.hpp> to use the features of this extension.\n///\n/// Provide a list of constants and precomputed useful values.\n\n#pragma once\n\n// Dependencies\n#include \"../ext/scalar_constants.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_constants extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_constants\n\t/// @{\n\n\t/// Return 0.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType zero();\n\n\t/// Return 1.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType one();\n\n\t/// Return pi * 2.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType two_pi();\n\n\t/// Return square root of pi.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_pi();\n\n\t/// Return pi / 2.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType half_pi();\n\n\t/// Return pi / 2 * 3.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType three_over_two_pi();\n\n\t/// Return pi / 4.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType quarter_pi();\n\n\t/// Return 1 / pi.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType one_over_pi();\n\n\t/// Return 1 / (pi * 2).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType one_over_two_pi();\n\n\t/// Return 2 / pi.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType two_over_pi();\n\n\t/// Return 4 / pi.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType four_over_pi();\n\n\t/// Return 2 / sqrt(pi).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType two_over_root_pi();\n\n\t/// Return 1 / sqrt(2).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType one_over_root_two();\n\n\t/// Return sqrt(pi / 2).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_half_pi();\n\n\t/// Return sqrt(2 * pi).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_two_pi();\n\n\t/// Return sqrt(ln(4)).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_ln_four();\n\n\t/// Return e constant.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType e();\n\n\t/// Return Euler's constant.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType euler();\n\n\t/// Return sqrt(2).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_two();\n\n\t/// Return sqrt(3).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_three();\n\n\t/// Return sqrt(5).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType root_five();\n\n\t/// Return ln(2).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType ln_two();\n\n\t/// Return ln(10).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType ln_ten();\n\n\t/// Return ln(ln(2)).\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType ln_ln_two();\n\n\t/// Return 1 / 3.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType third();\n\n\t/// Return 2 / 3.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType two_thirds();\n\n\t/// Return the golden ratio constant.\n\t/// @see gtc_constants\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL GLM_CONSTEXPR genType golden_ratio();\n\n\t/// @}\n} //namespace glm\n\n#include \"constants.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/constants.inl",
    "content": "/// @ref gtc_constants\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType zero()\n\t{\n\t\treturn genType(0);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one()\n\t{\n\t\treturn genType(1);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_pi()\n\t{\n\t\treturn genType(6.28318530717958647692528676655900576);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_pi()\n\t{\n\t\treturn genType(1.772453850905516027);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType half_pi()\n\t{\n\t\treturn genType(1.57079632679489661923132169163975144);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType three_over_two_pi()\n\t{\n\t\treturn genType(4.71238898038468985769396507491925432);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType quarter_pi()\n\t{\n\t\treturn genType(0.785398163397448309615660845819875721);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_pi()\n\t{\n\t\treturn genType(0.318309886183790671537767526745028724);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_two_pi()\n\t{\n\t\treturn genType(0.159154943091895335768883763372514362);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_pi()\n\t{\n\t\treturn genType(0.636619772367581343075535053490057448);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType four_over_pi()\n\t{\n\t\treturn genType(1.273239544735162686151070106980114898);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_root_pi()\n\t{\n\t\treturn genType(1.12837916709551257389615890312154517);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_root_two()\n\t{\n\t\treturn genType(0.707106781186547524400844362104849039);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_half_pi()\n\t{\n\t\treturn genType(1.253314137315500251);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two_pi()\n\t{\n\t\treturn genType(2.506628274631000502);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_ln_four()\n\t{\n\t\treturn genType(1.17741002251547469);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType e()\n\t{\n\t\treturn genType(2.71828182845904523536);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType euler()\n\t{\n\t\treturn genType(0.577215664901532860606);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two()\n\t{\n\t\treturn genType(1.41421356237309504880168872420969808);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_three()\n\t{\n\t\treturn genType(1.73205080756887729352744634150587236);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_five()\n\t{\n\t\treturn genType(2.23606797749978969640917366873127623);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_two()\n\t{\n\t\treturn genType(0.693147180559945309417232121458176568);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ten()\n\t{\n\t\treturn genType(2.30258509299404568401799145468436421);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ln_two()\n\t{\n\t\treturn genType(-0.3665129205816643);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType third()\n\t{\n\t\treturn genType(0.3333333333333333333333333333333333333333);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_thirds()\n\t{\n\t\treturn genType(0.666666666666666666666666666666666666667);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR genType golden_ratio()\n\t{\n\t\treturn genType(1.61803398874989484820458683436563811);\n\t}\n\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/epsilon.hpp",
    "content": "/// @ref gtc_epsilon\n/// @file glm/gtc/epsilon.hpp\n///\n/// @see core (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtc_epsilon GLM_GTC_epsilon\n/// @ingroup gtc\n///\n/// Include <glm/gtc/epsilon.hpp> to use the features of this extension.\n///\n/// Comparison functions for a user defined epsilon values.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_epsilon extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_epsilon\n\t/// @{\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @see gtc_epsilon\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> epsilonEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T const& epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is satisfied.\n\t///\n\t/// @see gtc_epsilon\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool epsilonEqual(genType const& x, genType const& y, genType const& epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| < epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @see gtc_epsilon\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> epsilonNotEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T const& epsilon);\n\n\t/// Returns the component-wise comparison of |x - y| >= epsilon.\n\t/// True if this expression is not satisfied.\n\t///\n\t/// @see gtc_epsilon\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool epsilonNotEqual(genType const& x, genType const& y, genType const& epsilon);\n\n\t/// @}\n}//namespace glm\n\n#include \"epsilon.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/epsilon.inl",
    "content": "/// @ref gtc_epsilon\n\n// Dependency:\n#include \"../vector_relational.hpp\"\n#include \"../common.hpp\"\n\nnamespace glm\n{\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER bool epsilonEqual\n\t(\n\t\tfloat const& x,\n\t\tfloat const& y,\n\t\tfloat const& epsilon\n\t)\n\t{\n\t\treturn abs(x - y) < epsilon;\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER bool epsilonEqual\n\t(\n\t\tdouble const& x,\n\t\tdouble const& y,\n\t\tdouble const& epsilon\n\t)\n\t{\n\t\treturn abs(x - y) < epsilon;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> epsilonEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T const& epsilon)\n\t{\n\t\treturn lessThan(abs(x - y), vec<L, T, Q>(epsilon));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> epsilonEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& epsilon)\n\t{\n\t\treturn lessThan(abs(x - y), vec<L, T, Q>(epsilon));\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER bool epsilonNotEqual(float const& x, float const& y, float const& epsilon)\n\t{\n\t\treturn abs(x - y) >= epsilon;\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER bool epsilonNotEqual(double const& x, double const& y, double const& epsilon)\n\t{\n\t\treturn abs(x - y) >= epsilon;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> epsilonNotEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, T const& epsilon)\n\t{\n\t\treturn greaterThanEqual(abs(x - y), vec<L, T, Q>(epsilon));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> epsilonNotEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y, vec<L, T, Q> const& epsilon)\n\t{\n\t\treturn greaterThanEqual(abs(x - y), vec<L, T, Q>(epsilon));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonEqual(qua<T, Q> const& x, qua<T, Q> const& y, T const& epsilon)\n\t{\n\t\tvec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w);\n\t\treturn lessThan(abs(v), vec<4, T, Q>(epsilon));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> epsilonNotEqual(qua<T, Q> const& x, qua<T, Q> const& y, T const& epsilon)\n\t{\n\t\tvec<4, T, Q> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w);\n\t\treturn greaterThanEqual(abs(v), vec<4, T, Q>(epsilon));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/integer.hpp",
    "content": "/// @ref gtc_integer\n/// @file glm/gtc/integer.hpp\n///\n/// @see core (dependence)\n/// @see gtc_integer (dependence)\n///\n/// @defgroup gtc_integer GLM_GTC_integer\n/// @ingroup gtc\n///\n/// Include <glm/gtc/integer.hpp> to use the features of this extension.\n///\n/// @brief Allow to perform bit operations on integer values\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../common.hpp\"\n#include \"../integer.hpp\"\n#include \"../exponential.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_integer extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_integer\n\t/// @{\n\n\t/// Returns the log2 of x for integer values. Usefull to compute mipmap count from the texture size.\n\t/// @see gtc_integer\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType log2(genIUType x);\n\n\t/// Returns a value equal to the nearest integer to x.\n\t/// The fraction 0.5 will round in a direction chosen by the\n\t/// implementation, presumably the direction that is fastest.\n\t///\n\t/// @param x The values of the argument must be greater or equal to zero.\n\t/// @tparam T floating point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/round.xml\">GLSL round man page</a>\n\t/// @see gtc_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> iround(vec<L, T, Q> const& x);\n\n\t/// Returns a value equal to the nearest integer to x.\n\t/// The fraction 0.5 will round in a direction chosen by the\n\t/// implementation, presumably the direction that is fastest.\n\t///\n\t/// @param x The values of the argument must be greater or equal to zero.\n\t/// @tparam T floating point scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/round.xml\">GLSL round man page</a>\n\t/// @see gtc_integer\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, uint, Q> uround(vec<L, T, Q> const& x);\n\n\t/// @}\n} //namespace glm\n\n#include \"integer.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/integer.inl",
    "content": "/// @ref gtc_integer\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_log2<L, T, Q, false, Aligned>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\t//Equivalent to return findMSB(vec); but save one function call in ASM with VC\n\t\t\t//return findMSB(vec);\n\t\t\treturn vec<L, T, Q>(detail::compute_findMSB_vec<L, T, Q, sizeof(T) * 8>::call(v));\n\t\t}\n\t};\n\n#\tif GLM_HAS_BITSCAN_WINDOWS\n\t\ttemplate<qualifier Q, bool Aligned>\n\t\tstruct compute_log2<4, int, Q, false, Aligned>\n\t\t{\n\t\t\tGLM_FUNC_QUALIFIER static vec<4, int, Q> call(vec<4, int, Q> const& v)\n\t\t\t{\n\t\t\t\tvec<4, int, Q> Result;\n\t\t\t\t_BitScanReverse(reinterpret_cast<unsigned long*>(&Result.x), v.x);\n\t\t\t\t_BitScanReverse(reinterpret_cast<unsigned long*>(&Result.y), v.y);\n\t\t\t\t_BitScanReverse(reinterpret_cast<unsigned long*>(&Result.z), v.z);\n\t\t\t\t_BitScanReverse(reinterpret_cast<unsigned long*>(&Result.w), v.w);\n\t\t\t\treturn Result;\n\t\t\t}\n\t\t};\n#\tendif//GLM_HAS_BITSCAN_WINDOWS\n}//namespace detail\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER int iround(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'iround' only accept floating-point inputs\");\n\t\tassert(static_cast<genType>(0.0) <= x);\n\n\t\treturn static_cast<int>(x + static_cast<genType>(0.5));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> iround(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'iround' only accept floating-point inputs\");\n\t\tassert(all(lessThanEqual(vec<L, T, Q>(0), x)));\n\n\t\treturn vec<L, int, Q>(x + static_cast<T>(0.5));\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER uint uround(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'uround' only accept floating-point inputs\");\n\t\tassert(static_cast<genType>(0.0) <= x);\n\n\t\treturn static_cast<uint>(x + static_cast<genType>(0.5));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, uint, Q> uround(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'uround' only accept floating-point inputs\");\n\t\tassert(all(lessThanEqual(vec<L, T, Q>(0), x)));\n\n\t\treturn vec<L, uint, Q>(x + static_cast<T>(0.5));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_access.hpp",
    "content": "/// @ref gtc_matrix_access\n/// @file glm/gtc/matrix_access.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_matrix_access GLM_GTC_matrix_access\n/// @ingroup gtc\n///\n/// Include <glm/gtc/matrix_access.hpp> to use the features of this extension.\n///\n/// Defines functions to access rows or columns of a matrix easily.\n\n#pragma once\n\n// Dependency:\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_matrix_access extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_matrix_access\n\t/// @{\n\n\t/// Get a specific row of a matrix.\n\t/// @see gtc_matrix_access\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::row_type row(\n\t\tgenType const& m,\n\t\tlength_t index);\n\n\t/// Set a specific row to a matrix.\n\t/// @see gtc_matrix_access\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType row(\n\t\tgenType const& m,\n\t\tlength_t index,\n\t\ttypename genType::row_type const& x);\n\n\t/// Get a specific column of a matrix.\n\t/// @see gtc_matrix_access\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::col_type column(\n\t\tgenType const& m,\n\t\tlength_t index);\n\n\t/// Set a specific column to a matrix.\n\t/// @see gtc_matrix_access\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType column(\n\t\tgenType const& m,\n\t\tlength_t index,\n\t\ttypename genType::col_type const& x);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_access.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_access.inl",
    "content": "/// @ref gtc_matrix_access\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType row\n\t(\n\t\tgenType const& m,\n\t\tlength_t index,\n\t\ttypename genType::row_type const& x\n\t)\n\t{\n\t\tassert(index >= 0 && index < m[0].length());\n\n\t\tgenType Result = m;\n\t\tfor(length_t i = 0; i < m.length(); ++i)\n\t\t\tResult[i][index] = x[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER typename genType::row_type row\n\t(\n\t\tgenType const& m,\n\t\tlength_t index\n\t)\n\t{\n\t\tassert(index >= 0 && index < m[0].length());\n\n\t\ttypename genType::row_type Result(0);\n\t\tfor(length_t i = 0; i < m.length(); ++i)\n\t\t\tResult[i] = m[i][index];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType column\n\t(\n\t\tgenType const& m,\n\t\tlength_t index,\n\t\ttypename genType::col_type const& x\n\t)\n\t{\n\t\tassert(index >= 0 && index < m.length());\n\n\t\tgenType Result = m;\n\t\tResult[index] = x;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER typename genType::col_type column\n\t(\n\t\tgenType const& m,\n\t\tlength_t index\n\t)\n\t{\n\t\tassert(index >= 0 && index < m.length());\n\n\t\treturn m[index];\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_integer.hpp",
    "content": "/// @ref gtc_matrix_integer\n/// @file glm/gtc/matrix_integer.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_matrix_integer GLM_GTC_matrix_integer\n/// @ingroup gtc\n///\n/// Include <glm/gtc/matrix_integer.hpp> to use the features of this extension.\n///\n/// Defines a number of matrices with integer types.\n\n#pragma once\n\n// Dependency:\n#include \"../mat2x2.hpp\"\n#include \"../mat2x3.hpp\"\n#include \"../mat2x4.hpp\"\n#include \"../mat3x2.hpp\"\n#include \"../mat3x3.hpp\"\n#include \"../mat3x4.hpp\"\n#include \"../mat4x2.hpp\"\n#include \"../mat4x3.hpp\"\n#include \"../mat4x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_matrix_integer extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_matrix_integer\n\t/// @{\n\n\t/// High-qualifier signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, highp>\t\t\t\thighp_imat2;\n\n\t/// High-qualifier signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, highp>\t\t\t\thighp_imat3;\n\n\t/// High-qualifier signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, highp>\t\t\t\thighp_imat4;\n\n\t/// High-qualifier signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, highp>\t\t\t\thighp_imat2x2;\n\n\t/// High-qualifier signed integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, int, highp>\t\t\t\thighp_imat2x3;\n\n\t/// High-qualifier signed integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, int, highp>\t\t\t\thighp_imat2x4;\n\n\t/// High-qualifier signed integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, int, highp>\t\t\t\thighp_imat3x2;\n\n\t/// High-qualifier signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, highp>\t\t\t\thighp_imat3x3;\n\n\t/// High-qualifier signed integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, int, highp>\t\t\t\thighp_imat3x4;\n\n\t/// High-qualifier signed integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, int, highp>\t\t\t\thighp_imat4x2;\n\n\t/// High-qualifier signed integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, int, highp>\t\t\t\thighp_imat4x3;\n\n\t/// High-qualifier signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, highp>\t\t\t\thighp_imat4x4;\n\n\n\t/// Medium-qualifier signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, mediump>\t\t\tmediump_imat2;\n\n\t/// Medium-qualifier signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, mediump>\t\t\tmediump_imat3;\n\n\t/// Medium-qualifier signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, mediump>\t\t\tmediump_imat4;\n\n\n\t/// Medium-qualifier signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, mediump>\t\t\tmediump_imat2x2;\n\n\t/// Medium-qualifier signed integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, int, mediump>\t\t\tmediump_imat2x3;\n\n\t/// Medium-qualifier signed integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, int, mediump>\t\t\tmediump_imat2x4;\n\n\t/// Medium-qualifier signed integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, int, mediump>\t\t\tmediump_imat3x2;\n\n\t/// Medium-qualifier signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, mediump>\t\t\tmediump_imat3x3;\n\n\t/// Medium-qualifier signed integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, int, mediump>\t\t\tmediump_imat3x4;\n\n\t/// Medium-qualifier signed integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, int, mediump>\t\t\tmediump_imat4x2;\n\n\t/// Medium-qualifier signed integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, int, mediump>\t\t\tmediump_imat4x3;\n\n\t/// Medium-qualifier signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, mediump>\t\t\tmediump_imat4x4;\n\n\n\t/// Low-qualifier signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, lowp>\t\t\t\tlowp_imat2;\n\n\t/// Low-qualifier signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, lowp>\t\t\t\tlowp_imat3;\n\n\t/// Low-qualifier signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, lowp>\t\t\t\tlowp_imat4;\n\n\n\t/// Low-qualifier signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, lowp>\t\t\t\tlowp_imat2x2;\n\n\t/// Low-qualifier signed integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, int, lowp>\t\t\t\tlowp_imat2x3;\n\n\t/// Low-qualifier signed integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, int, lowp>\t\t\t\tlowp_imat2x4;\n\n\t/// Low-qualifier signed integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, int, lowp>\t\t\t\tlowp_imat3x2;\n\n\t/// Low-qualifier signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, lowp>\t\t\t\tlowp_imat3x3;\n\n\t/// Low-qualifier signed integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, int, lowp>\t\t\t\tlowp_imat3x4;\n\n\t/// Low-qualifier signed integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, int, lowp>\t\t\t\tlowp_imat4x2;\n\n\t/// Low-qualifier signed integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, int, lowp>\t\t\t\tlowp_imat4x3;\n\n\t/// Low-qualifier signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, lowp>\t\t\t\tlowp_imat4x4;\n\n\n\t/// High-qualifier unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, highp>\t\t\t\thighp_umat2;\n\n\t/// High-qualifier unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, highp>\t\t\t\thighp_umat3;\n\n\t/// High-qualifier unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, highp>\t\t\t\thighp_umat4;\n\n\t/// High-qualifier unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, highp>\t\t\t\thighp_umat2x2;\n\n\t/// High-qualifier unsigned integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, uint, highp>\t\t\t\thighp_umat2x3;\n\n\t/// High-qualifier unsigned integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, uint, highp>\t\t\t\thighp_umat2x4;\n\n\t/// High-qualifier unsigned integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, uint, highp>\t\t\t\thighp_umat3x2;\n\n\t/// High-qualifier unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, highp>\t\t\t\thighp_umat3x3;\n\n\t/// High-qualifier unsigned integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, uint, highp>\t\t\t\thighp_umat3x4;\n\n\t/// High-qualifier unsigned integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, uint, highp>\t\t\t\thighp_umat4x2;\n\n\t/// High-qualifier unsigned integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, uint, highp>\t\t\t\thighp_umat4x3;\n\n\t/// High-qualifier unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, highp>\t\t\t\thighp_umat4x4;\n\n\n\t/// Medium-qualifier unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, mediump>\t\t\tmediump_umat2;\n\n\t/// Medium-qualifier unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, mediump>\t\t\tmediump_umat3;\n\n\t/// Medium-qualifier unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, mediump>\t\t\tmediump_umat4;\n\n\n\t/// Medium-qualifier unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, mediump>\t\t\tmediump_umat2x2;\n\n\t/// Medium-qualifier unsigned integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, uint, mediump>\t\t\tmediump_umat2x3;\n\n\t/// Medium-qualifier unsigned integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, uint, mediump>\t\t\tmediump_umat2x4;\n\n\t/// Medium-qualifier unsigned integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, uint, mediump>\t\t\tmediump_umat3x2;\n\n\t/// Medium-qualifier unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, mediump>\t\t\tmediump_umat3x3;\n\n\t/// Medium-qualifier unsigned integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, uint, mediump>\t\t\tmediump_umat3x4;\n\n\t/// Medium-qualifier unsigned integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, uint, mediump>\t\t\tmediump_umat4x2;\n\n\t/// Medium-qualifier unsigned integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, uint, mediump>\t\t\tmediump_umat4x3;\n\n\t/// Medium-qualifier unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, mediump>\t\t\tmediump_umat4x4;\n\n\n\t/// Low-qualifier unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, lowp>\t\t\t\tlowp_umat2;\n\n\t/// Low-qualifier unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, lowp>\t\t\t\tlowp_umat3;\n\n\t/// Low-qualifier unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, lowp>\t\t\t\tlowp_umat4;\n\n\n\t/// Low-qualifier unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, lowp>\t\t\t\tlowp_umat2x2;\n\n\t/// Low-qualifier unsigned integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, uint, lowp>\t\t\t\tlowp_umat2x3;\n\n\t/// Low-qualifier unsigned integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, uint, lowp>\t\t\t\tlowp_umat2x4;\n\n\t/// Low-qualifier unsigned integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, uint, lowp>\t\t\t\tlowp_umat3x2;\n\n\t/// Low-qualifier unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, lowp>\t\t\t\tlowp_umat3x3;\n\n\t/// Low-qualifier unsigned integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, uint, lowp>\t\t\t\tlowp_umat3x4;\n\n\t/// Low-qualifier unsigned integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, uint, lowp>\t\t\t\tlowp_umat4x2;\n\n\t/// Low-qualifier unsigned integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, uint, lowp>\t\t\t\tlowp_umat4x3;\n\n\t/// Low-qualifier unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, lowp>\t\t\t\tlowp_umat4x4;\n\n\n\n\t/// Signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, defaultp>\t\t\t\timat2;\n\n\t/// Signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, defaultp>\t\t\t\timat3;\n\n\t/// Signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, defaultp>\t\t\t\timat4;\n\n\t/// Signed integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, int, defaultp>\t\t\t\timat2x2;\n\n\t/// Signed integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, int, defaultp>\t\t\t\timat2x3;\n\n\t/// Signed integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, int, defaultp>\t\t\t\timat2x4;\n\n\t/// Signed integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, int, defaultp>\t\t\t\timat3x2;\n\n\t/// Signed integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, int, defaultp>\t\t\t\timat3x3;\n\n\t/// Signed integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, int, defaultp>\t\t\t\timat3x4;\n\n\t/// Signed integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, int, defaultp>\t\t\t\timat4x2;\n\n\t/// Signed integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, int, defaultp>\t\t\t\timat4x3;\n\n\t/// Signed integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, int, defaultp>\t\t\t\timat4x4;\n\n\n\n\t/// Unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, defaultp>\t\t\t\tumat2;\n\n\t/// Unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, defaultp>\t\t\t\tumat3;\n\n\t/// Unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, defaultp>\t\t\t\tumat4;\n\n\t/// Unsigned integer 2x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 2, uint, defaultp>\t\t\t\tumat2x2;\n\n\t/// Unsigned integer 2x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 3, uint, defaultp>\t\t\t\tumat2x3;\n\n\t/// Unsigned integer 2x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<2, 4, uint, defaultp>\t\t\t\tumat2x4;\n\n\t/// Unsigned integer 3x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 2, uint, defaultp>\t\t\t\tumat3x2;\n\n\t/// Unsigned integer 3x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 3, uint, defaultp>\t\t\t\tumat3x3;\n\n\t/// Unsigned integer 3x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<3, 4, uint, defaultp>\t\t\t\tumat3x4;\n\n\t/// Unsigned integer 4x2 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 2, uint, defaultp>\t\t\t\tumat4x2;\n\n\t/// Unsigned integer 4x3 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 3, uint, defaultp>\t\t\t\tumat4x3;\n\n\t/// Unsigned integer 4x4 matrix.\n\t/// @see gtc_matrix_integer\n\ttypedef mat<4, 4, uint, defaultp>\t\t\t\tumat4x4;\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_inverse.hpp",
    "content": "/// @ref gtc_matrix_inverse\n/// @file glm/gtc/matrix_inverse.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_matrix_inverse GLM_GTC_matrix_inverse\n/// @ingroup gtc\n///\n/// Include <glm/gtc/matrix_integer.hpp> to use the features of this extension.\n///\n/// Defines additional matrix inverting functions.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../matrix.hpp\"\n#include \"../mat2x2.hpp\"\n#include \"../mat3x3.hpp\"\n#include \"../mat4x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_matrix_inverse extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_matrix_inverse\n\t/// @{\n\n\t/// Fast matrix inverse for affine matrix.\n\t///\n\t/// @param m Input matrix to invert.\n\t/// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate.\n\t/// @see gtc_matrix_inverse\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType affineInverse(genType const& m);\n\n\t/// Compute the inverse transpose of a matrix.\n\t///\n\t/// @param m Input matrix to invert transpose.\n\t/// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-qualifier floating point value is highly innacurate.\n\t/// @see gtc_matrix_inverse\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType inverseTranspose(genType const& m);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_inverse.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_inverse.inl",
    "content": "/// @ref gtc_matrix_inverse\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> affineInverse(mat<3, 3, T, Q> const& m)\n\t{\n\t\tmat<2, 2, T, Q> const Inv(inverse(mat<2, 2, T, Q>(m)));\n\n\t\treturn mat<3, 3, T, Q>(\n\t\t\tvec<3, T, Q>(Inv[0], static_cast<T>(0)),\n\t\t\tvec<3, T, Q>(Inv[1], static_cast<T>(0)),\n\t\t\tvec<3, T, Q>(-Inv * vec<2, T, Q>(m[2]), static_cast<T>(1)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> affineInverse(mat<4, 4, T, Q> const& m)\n\t{\n\t\tmat<3, 3, T, Q> const Inv(inverse(mat<3, 3, T, Q>(m)));\n\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tvec<4, T, Q>(Inv[0], static_cast<T>(0)),\n\t\t\tvec<4, T, Q>(Inv[1], static_cast<T>(0)),\n\t\t\tvec<4, T, Q>(Inv[2], static_cast<T>(0)),\n\t\t\tvec<4, T, Q>(-Inv * vec<3, T, Q>(m[3]), static_cast<T>(1)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> inverseTranspose(mat<2, 2, T, Q> const& m)\n\t{\n\t\tT Determinant = m[0][0] * m[1][1] - m[1][0] * m[0][1];\n\n\t\tmat<2, 2, T, Q> Inverse(\n\t\t\t+ m[1][1] / Determinant,\n\t\t\t- m[0][1] / Determinant,\n\t\t\t- m[1][0] / Determinant,\n\t\t\t+ m[0][0] / Determinant);\n\n\t\treturn Inverse;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> inverseTranspose(mat<3, 3, T, Q> const& m)\n\t{\n\t\tT Determinant =\n\t\t\t+ m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])\n\t\t\t- m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])\n\t\t\t+ m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);\n\n\t\tmat<3, 3, T, Q> Inverse;\n\t\tInverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]);\n\t\tInverse[0][1] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]);\n\t\tInverse[0][2] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]);\n\t\tInverse[1][0] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]);\n\t\tInverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]);\n\t\tInverse[1][2] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]);\n\t\tInverse[2][0] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]);\n\t\tInverse[2][1] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]);\n\t\tInverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]);\n\t\tInverse /= Determinant;\n\n\t\treturn Inverse;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> inverseTranspose(mat<4, 4, T, Q> const& m)\n\t{\n\t\tT SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\tT SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\tT SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\tT SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\tT SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\tT SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\tT SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];\n\t\tT SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];\n\t\tT SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];\n\t\tT SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];\n\t\tT SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];\n\t\tT SubFactor11 = m[1][0] * m[3][1] - m[3][0] * m[1][1];\n\t\tT SubFactor12 = m[1][2] * m[2][3] - m[2][2] * m[1][3];\n\t\tT SubFactor13 = m[1][1] * m[2][3] - m[2][1] * m[1][3];\n\t\tT SubFactor14 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n\t\tT SubFactor15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];\n\t\tT SubFactor16 = m[1][0] * m[2][2] - m[2][0] * m[1][2];\n\t\tT SubFactor17 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n\n\t\tmat<4, 4, T, Q> Inverse;\n\t\tInverse[0][0] = + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02);\n\t\tInverse[0][1] = - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04);\n\t\tInverse[0][2] = + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05);\n\t\tInverse[0][3] = - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05);\n\n\t\tInverse[1][0] = - (m[0][1] * SubFactor00 - m[0][2] * SubFactor01 + m[0][3] * SubFactor02);\n\t\tInverse[1][1] = + (m[0][0] * SubFactor00 - m[0][2] * SubFactor03 + m[0][3] * SubFactor04);\n\t\tInverse[1][2] = - (m[0][0] * SubFactor01 - m[0][1] * SubFactor03 + m[0][3] * SubFactor05);\n\t\tInverse[1][3] = + (m[0][0] * SubFactor02 - m[0][1] * SubFactor04 + m[0][2] * SubFactor05);\n\n\t\tInverse[2][0] = + (m[0][1] * SubFactor06 - m[0][2] * SubFactor07 + m[0][3] * SubFactor08);\n\t\tInverse[2][1] = - (m[0][0] * SubFactor06 - m[0][2] * SubFactor09 + m[0][3] * SubFactor10);\n\t\tInverse[2][2] = + (m[0][0] * SubFactor07 - m[0][1] * SubFactor09 + m[0][3] * SubFactor11);\n\t\tInverse[2][3] = - (m[0][0] * SubFactor08 - m[0][1] * SubFactor10 + m[0][2] * SubFactor11);\n\n\t\tInverse[3][0] = - (m[0][1] * SubFactor12 - m[0][2] * SubFactor13 + m[0][3] * SubFactor14);\n\t\tInverse[3][1] = + (m[0][0] * SubFactor12 - m[0][2] * SubFactor15 + m[0][3] * SubFactor16);\n\t\tInverse[3][2] = - (m[0][0] * SubFactor13 - m[0][1] * SubFactor15 + m[0][3] * SubFactor17);\n\t\tInverse[3][3] = + (m[0][0] * SubFactor14 - m[0][1] * SubFactor16 + m[0][2] * SubFactor17);\n\n\t\tT Determinant =\n\t\t\t+ m[0][0] * Inverse[0][0]\n\t\t\t+ m[0][1] * Inverse[0][1]\n\t\t\t+ m[0][2] * Inverse[0][2]\n\t\t\t+ m[0][3] * Inverse[0][3];\n\n\t\tInverse /= Determinant;\n\n\t\treturn Inverse;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_transform.hpp",
    "content": "/// @ref gtc_matrix_transform\n/// @file glm/gtc/matrix_transform.hpp\n///\n/// @see core (dependence)\n/// @see gtx_transform\n/// @see gtx_transform2\n///\n/// @defgroup gtc_matrix_transform GLM_GTC_matrix_transform\n/// @ingroup gtc\n///\n/// Include <glm/gtc/matrix_transform.hpp> to use the features of this extension.\n///\n/// Defines functions that generate common transformation matrices.\n///\n/// The matrices generated by this extension use standard OpenGL fixed-function\n/// conventions. For example, the lookAt function generates a transform from world\n/// space into the specific eye space that the projective matrix functions\n/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility\n/// specifications defines the particular layout of this eye space.\n\n#pragma once\n\n// Dependencies\n#include \"../mat4x4.hpp\"\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../ext/matrix_projection.hpp\"\n#include \"../ext/matrix_clip_space.hpp\"\n#include \"../ext/matrix_transform.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_matrix_transform extension included\")\n#endif\n\n#include \"matrix_transform.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/matrix_transform.inl",
    "content": "#include \"../geometric.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../matrix.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/noise.hpp",
    "content": "/// @ref gtc_noise\n/// @file glm/gtc/noise.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_noise GLM_GTC_noise\n/// @ingroup gtc\n///\n/// Include <glm/gtc/noise.hpp> to use the features of this extension.\n///\n/// Defines 2D, 3D and 4D procedural noise functions\n/// Based on the work of Stefan Gustavson and Ashima Arts on \"webgl-noise\":\n/// https://github.com/ashima/webgl-noise\n/// Following Stefan Gustavson's paper \"Simplex noise demystified\":\n/// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_noise.hpp\"\n#include \"../geometric.hpp\"\n#include \"../common.hpp\"\n#include \"../vector_relational.hpp\"\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_noise extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_noise\n\t/// @{\n\n\t/// Classic perlin noise.\n\t/// @see gtc_noise\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T perlin(\n\t\tvec<L, T, Q> const& p);\n\n\t/// Periodic perlin noise.\n\t/// @see gtc_noise\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T perlin(\n\t\tvec<L, T, Q> const& p,\n\t\tvec<L, T, Q> const& rep);\n\n\t/// Simplex noise.\n\t/// @see gtc_noise\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T simplex(\n\t\tvec<L, T, Q> const& p);\n\n\t/// @}\n}//namespace glm\n\n#include \"noise.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/noise.inl",
    "content": "/// @ref gtc_noise\n///\n// Based on the work of Stefan Gustavson and Ashima Arts on \"webgl-noise\":\n// https://github.com/ashima/webgl-noise\n// Following Stefan Gustavson's paper \"Simplex noise demystified\":\n// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf\n\nnamespace glm{\nnamespace gtc\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> grad4(T const& j, vec<4, T, Q> const& ip)\n\t{\n\t\tvec<3, T, Q> pXYZ = floor(fract(vec<3, T, Q>(j) * vec<3, T, Q>(ip)) * T(7)) * ip[2] - T(1);\n\t\tT pW = static_cast<T>(1.5) - dot(abs(pXYZ), vec<3, T, Q>(1));\n\t\tvec<4, T, Q> s = vec<4, T, Q>(lessThan(vec<4, T, Q>(pXYZ, pW), vec<4, T, Q>(0.0)));\n\t\tpXYZ = pXYZ + (vec<3, T, Q>(s) * T(2) - T(1)) * s.w;\n\t\treturn vec<4, T, Q>(pXYZ, pW);\n\t}\n}//namespace gtc\n\n\t// Classic Perlin noise\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position)\n\t{\n\t\tvec<4, T, Q> Pi = glm::floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0);\n\t\tvec<4, T, Q> Pf = glm::fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0);\n\t\tPi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation\n\t\tvec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z);\n\t\tvec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w);\n\t\tvec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z);\n\t\tvec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w);\n\n\t\tvec<4, T, Q> i = detail::permute(detail::permute(ix) + iy);\n\n\t\tvec<4, T, Q> gx = static_cast<T>(2) * glm::fract(i / T(41)) - T(1);\n\t\tvec<4, T, Q> gy = glm::abs(gx) - T(0.5);\n\t\tvec<4, T, Q> tx = glm::floor(gx + T(0.5));\n\t\tgx = gx - tx;\n\n\t\tvec<2, T, Q> g00(gx.x, gy.x);\n\t\tvec<2, T, Q> g10(gx.y, gy.y);\n\t\tvec<2, T, Q> g01(gx.z, gy.z);\n\t\tvec<2, T, Q> g11(gx.w, gy.w);\n\n\t\tvec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));\n\t\tg00 *= norm.x;\n\t\tg01 *= norm.y;\n\t\tg10 *= norm.z;\n\t\tg11 *= norm.w;\n\n\t\tT n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x));\n\t\tT n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y));\n\t\tT n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z));\n\t\tT n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w));\n\n\t\tvec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y));\n\t\tvec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x);\n\t\tT n_xy = mix(n_x.x, n_x.y, fade_xy.y);\n\t\treturn T(2.3) * n_xy;\n\t}\n\n\t// Classic Perlin noise\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position)\n\t{\n\t\tvec<3, T, Q> Pi0 = floor(Position); // Integer part for indexing\n\t\tvec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1\n\t\tPi0 = detail::mod289(Pi0);\n\t\tPi1 = detail::mod289(Pi1);\n\t\tvec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation\n\t\tvec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0\n\t\tvec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x);\n\t\tvec<4, T, Q> iy = vec<4, T, Q>(vec<2, T, Q>(Pi0.y), vec<2, T, Q>(Pi1.y));\n\t\tvec<4, T, Q> iz0(Pi0.z);\n\t\tvec<4, T, Q> iz1(Pi1.z);\n\n\t\tvec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy);\n\t\tvec<4, T, Q> ixy0 = detail::permute(ixy + iz0);\n\t\tvec<4, T, Q> ixy1 = detail::permute(ixy + iz1);\n\n\t\tvec<4, T, Q> gx0 = ixy0 * T(1.0 / 7.0);\n\t\tvec<4, T, Q> gy0 = fract(floor(gx0) * T(1.0 / 7.0)) - T(0.5);\n\t\tgx0 = fract(gx0);\n\t\tvec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0);\n\t\tvec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0));\n\t\tgx0 -= sz0 * (step(T(0), gx0) - T(0.5));\n\t\tgy0 -= sz0 * (step(T(0), gy0) - T(0.5));\n\n\t\tvec<4, T, Q> gx1 = ixy1 * T(1.0 / 7.0);\n\t\tvec<4, T, Q> gy1 = fract(floor(gx1) * T(1.0 / 7.0)) - T(0.5);\n\t\tgx1 = fract(gx1);\n\t\tvec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1);\n\t\tvec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0));\n\t\tgx1 -= sz1 * (step(T(0), gx1) - T(0.5));\n\t\tgy1 -= sz1 * (step(T(0), gy1) - T(0.5));\n\n\t\tvec<3, T, Q> g000(gx0.x, gy0.x, gz0.x);\n\t\tvec<3, T, Q> g100(gx0.y, gy0.y, gz0.y);\n\t\tvec<3, T, Q> g010(gx0.z, gy0.z, gz0.z);\n\t\tvec<3, T, Q> g110(gx0.w, gy0.w, gz0.w);\n\t\tvec<3, T, Q> g001(gx1.x, gy1.x, gz1.x);\n\t\tvec<3, T, Q> g101(gx1.y, gy1.y, gz1.y);\n\t\tvec<3, T, Q> g011(gx1.z, gy1.z, gz1.z);\n\t\tvec<3, T, Q> g111(gx1.w, gy1.w, gz1.w);\n\n\t\tvec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));\n\t\tg000 *= norm0.x;\n\t\tg010 *= norm0.y;\n\t\tg100 *= norm0.z;\n\t\tg110 *= norm0.w;\n\t\tvec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));\n\t\tg001 *= norm1.x;\n\t\tg011 *= norm1.y;\n\t\tg101 *= norm1.z;\n\t\tg111 *= norm1.w;\n\n\t\tT n000 = dot(g000, Pf0);\n\t\tT n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z));\n\t\tT n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z));\n\t\tT n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z));\n\t\tT n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z));\n\t\tT n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z));\n\t\tT n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z));\n\t\tT n111 = dot(g111, Pf1);\n\n\t\tvec<3, T, Q> fade_xyz = detail::fade(Pf0);\n\t\tvec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z);\n\t\tvec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y);\n\t\tT n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);\n\t\treturn T(2.2) * n_xyz;\n\t}\n\t/*\n\t// Classic Perlin noise\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& P)\n\t{\n\t\tvec<3, T, Q> Pi0 = floor(P); // Integer part for indexing\n\t\tvec<3, T, Q> Pi1 = Pi0 + T(1); // Integer part + 1\n\t\tPi0 = mod(Pi0, T(289));\n\t\tPi1 = mod(Pi1, T(289));\n\t\tvec<3, T, Q> Pf0 = fract(P); // Fractional part for interpolation\n\t\tvec<3, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0\n\t\tvec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x);\n\t\tvec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y);\n\t\tvec<4, T, Q> iz0(Pi0.z);\n\t\tvec<4, T, Q> iz1(Pi1.z);\n\n\t\tvec<4, T, Q> ixy = permute(permute(ix) + iy);\n\t\tvec<4, T, Q> ixy0 = permute(ixy + iz0);\n\t\tvec<4, T, Q> ixy1 = permute(ixy + iz1);\n\n\t\tvec<4, T, Q> gx0 = ixy0 / T(7);\n\t\tvec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5);\n\t\tgx0 = fract(gx0);\n\t\tvec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0);\n\t\tvec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0.0));\n\t\tgx0 -= sz0 * (step(0.0, gx0) - T(0.5));\n\t\tgy0 -= sz0 * (step(0.0, gy0) - T(0.5));\n\n\t\tvec<4, T, Q> gx1 = ixy1 / T(7);\n\t\tvec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5);\n\t\tgx1 = fract(gx1);\n\t\tvec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1);\n\t\tvec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(0.0));\n\t\tgx1 -= sz1 * (step(T(0), gx1) - T(0.5));\n\t\tgy1 -= sz1 * (step(T(0), gy1) - T(0.5));\n\n\t\tvec<3, T, Q> g000(gx0.x, gy0.x, gz0.x);\n\t\tvec<3, T, Q> g100(gx0.y, gy0.y, gz0.y);\n\t\tvec<3, T, Q> g010(gx0.z, gy0.z, gz0.z);\n\t\tvec<3, T, Q> g110(gx0.w, gy0.w, gz0.w);\n\t\tvec<3, T, Q> g001(gx1.x, gy1.x, gz1.x);\n\t\tvec<3, T, Q> g101(gx1.y, gy1.y, gz1.y);\n\t\tvec<3, T, Q> g011(gx1.z, gy1.z, gz1.z);\n\t\tvec<3, T, Q> g111(gx1.w, gy1.w, gz1.w);\n\n\t\tvec<4, T, Q> norm0 = taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));\n\t\tg000 *= norm0.x;\n\t\tg010 *= norm0.y;\n\t\tg100 *= norm0.z;\n\t\tg110 *= norm0.w;\n\t\tvec<4, T, Q> norm1 = taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));\n\t\tg001 *= norm1.x;\n\t\tg011 *= norm1.y;\n\t\tg101 *= norm1.z;\n\t\tg111 *= norm1.w;\n\n\t\tT n000 = dot(g000, Pf0);\n\t\tT n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z));\n\t\tT n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z));\n\t\tT n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z));\n\t\tT n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z));\n\t\tT n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z));\n\t\tT n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z));\n\t\tT n111 = dot(g111, Pf1);\n\n\t\tvec<3, T, Q> fade_xyz = fade(Pf0);\n\t\tvec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z);\n\t\tvec<2, T, Q> n_yz = mix(\n\t\t\tvec<2, T, Q>(n_z.x, n_z.y),\n\t\t\tvec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y);\n\t\tT n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);\n\t\treturn T(2.2) * n_xyz;\n\t}\n\t*/\n\t// Classic Perlin noise\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position)\n\t{\n\t\tvec<4, T, Q> Pi0 = floor(Position);\t// Integer part for indexing\n\t\tvec<4, T, Q> Pi1 = Pi0 + T(1);\t\t// Integer part + 1\n\t\tPi0 = mod(Pi0, vec<4, T, Q>(289));\n\t\tPi1 = mod(Pi1, vec<4, T, Q>(289));\n\t\tvec<4, T, Q> Pf0 = fract(Position);\t// Fractional part for interpolation\n\t\tvec<4, T, Q> Pf1 = Pf0 - T(1);\t\t// Fractional part - 1.0\n\t\tvec<4, T, Q> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x);\n\t\tvec<4, T, Q> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y);\n\t\tvec<4, T, Q> iz0(Pi0.z);\n\t\tvec<4, T, Q> iz1(Pi1.z);\n\t\tvec<4, T, Q> iw0(Pi0.w);\n\t\tvec<4, T, Q> iw1(Pi1.w);\n\n\t\tvec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy);\n\t\tvec<4, T, Q> ixy0 = detail::permute(ixy + iz0);\n\t\tvec<4, T, Q> ixy1 = detail::permute(ixy + iz1);\n\t\tvec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0);\n\t\tvec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1);\n\t\tvec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0);\n\t\tvec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1);\n\n\t\tvec<4, T, Q> gx00 = ixy00 / T(7);\n\t\tvec<4, T, Q> gy00 = floor(gx00) / T(7);\n\t\tvec<4, T, Q> gz00 = floor(gy00) / T(6);\n\t\tgx00 = fract(gx00) - T(0.5);\n\t\tgy00 = fract(gy00) - T(0.5);\n\t\tgz00 = fract(gz00) - T(0.5);\n\t\tvec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00);\n\t\tvec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0.0));\n\t\tgx00 -= sw00 * (step(T(0), gx00) - T(0.5));\n\t\tgy00 -= sw00 * (step(T(0), gy00) - T(0.5));\n\n\t\tvec<4, T, Q> gx01 = ixy01 / T(7);\n\t\tvec<4, T, Q> gy01 = floor(gx01) / T(7);\n\t\tvec<4, T, Q> gz01 = floor(gy01) / T(6);\n\t\tgx01 = fract(gx01) - T(0.5);\n\t\tgy01 = fract(gy01) - T(0.5);\n\t\tgz01 = fract(gz01) - T(0.5);\n\t\tvec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01);\n\t\tvec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0));\n\t\tgx01 -= sw01 * (step(T(0), gx01) - T(0.5));\n\t\tgy01 -= sw01 * (step(T(0), gy01) - T(0.5));\n\n\t\tvec<4, T, Q> gx10 = ixy10 / T(7);\n\t\tvec<4, T, Q> gy10 = floor(gx10) / T(7);\n\t\tvec<4, T, Q> gz10 = floor(gy10) / T(6);\n\t\tgx10 = fract(gx10) - T(0.5);\n\t\tgy10 = fract(gy10) - T(0.5);\n\t\tgz10 = fract(gz10) - T(0.5);\n\t\tvec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10);\n\t\tvec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0));\n\t\tgx10 -= sw10 * (step(T(0), gx10) - T(0.5));\n\t\tgy10 -= sw10 * (step(T(0), gy10) - T(0.5));\n\n\t\tvec<4, T, Q> gx11 = ixy11 / T(7);\n\t\tvec<4, T, Q> gy11 = floor(gx11) / T(7);\n\t\tvec<4, T, Q> gz11 = floor(gy11) / T(6);\n\t\tgx11 = fract(gx11) - T(0.5);\n\t\tgy11 = fract(gy11) - T(0.5);\n\t\tgz11 = fract(gz11) - T(0.5);\n\t\tvec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11);\n\t\tvec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(0.0));\n\t\tgx11 -= sw11 * (step(T(0), gx11) - T(0.5));\n\t\tgy11 -= sw11 * (step(T(0), gy11) - T(0.5));\n\n\t\tvec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x);\n\t\tvec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y);\n\t\tvec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z);\n\t\tvec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w);\n\t\tvec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x);\n\t\tvec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y);\n\t\tvec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z);\n\t\tvec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w);\n\t\tvec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x);\n\t\tvec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y);\n\t\tvec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z);\n\t\tvec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w);\n\t\tvec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x);\n\t\tvec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y);\n\t\tvec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z);\n\t\tvec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w);\n\n\t\tvec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));\n\t\tg0000 *= norm00.x;\n\t\tg0100 *= norm00.y;\n\t\tg1000 *= norm00.z;\n\t\tg1100 *= norm00.w;\n\n\t\tvec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));\n\t\tg0001 *= norm01.x;\n\t\tg0101 *= norm01.y;\n\t\tg1001 *= norm01.z;\n\t\tg1101 *= norm01.w;\n\n\t\tvec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));\n\t\tg0010 *= norm10.x;\n\t\tg0110 *= norm10.y;\n\t\tg1010 *= norm10.z;\n\t\tg1110 *= norm10.w;\n\n\t\tvec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));\n\t\tg0011 *= norm11.x;\n\t\tg0111 *= norm11.y;\n\t\tg1011 *= norm11.z;\n\t\tg1111 *= norm11.w;\n\n\t\tT n0000 = dot(g0000, Pf0);\n\t\tT n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w));\n\t\tT n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w));\n\t\tT n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w));\n\t\tT n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w));\n\t\tT n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w));\n\t\tT n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w));\n\t\tT n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w));\n\t\tT n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w));\n\t\tT n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w));\n\t\tT n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w));\n\t\tT n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w));\n\t\tT n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w));\n\t\tT n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w));\n\t\tT n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w));\n\t\tT n1111 = dot(g1111, Pf1);\n\n\t\tvec<4, T, Q> fade_xyzw = detail::fade(Pf0);\n\t\tvec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w);\n\t\tvec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w);\n\t\tvec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z);\n\t\tvec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y);\n\t\tT n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);\n\t\treturn T(2.2) * n_xyzw;\n\t}\n\n\t// Classic Perlin noise, periodic variant\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<2, T, Q> const& Position, vec<2, T, Q> const& rep)\n\t{\n\t\tvec<4, T, Q> Pi = floor(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) + vec<4, T, Q>(0.0, 0.0, 1.0, 1.0);\n\t\tvec<4, T, Q> Pf = fract(vec<4, T, Q>(Position.x, Position.y, Position.x, Position.y)) - vec<4, T, Q>(0.0, 0.0, 1.0, 1.0);\n\t\tPi = mod(Pi, vec<4, T, Q>(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period\n\t\tPi = mod(Pi, vec<4, T, Q>(289)); // To avoid truncation effects in permutation\n\t\tvec<4, T, Q> ix(Pi.x, Pi.z, Pi.x, Pi.z);\n\t\tvec<4, T, Q> iy(Pi.y, Pi.y, Pi.w, Pi.w);\n\t\tvec<4, T, Q> fx(Pf.x, Pf.z, Pf.x, Pf.z);\n\t\tvec<4, T, Q> fy(Pf.y, Pf.y, Pf.w, Pf.w);\n\n\t\tvec<4, T, Q> i = detail::permute(detail::permute(ix) + iy);\n\n\t\tvec<4, T, Q> gx = static_cast<T>(2) * fract(i / T(41)) - T(1);\n\t\tvec<4, T, Q> gy = abs(gx) - T(0.5);\n\t\tvec<4, T, Q> tx = floor(gx + T(0.5));\n\t\tgx = gx - tx;\n\n\t\tvec<2, T, Q> g00(gx.x, gy.x);\n\t\tvec<2, T, Q> g10(gx.y, gy.y);\n\t\tvec<2, T, Q> g01(gx.z, gy.z);\n\t\tvec<2, T, Q> g11(gx.w, gy.w);\n\n\t\tvec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));\n\t\tg00 *= norm.x;\n\t\tg01 *= norm.y;\n\t\tg10 *= norm.z;\n\t\tg11 *= norm.w;\n\n\t\tT n00 = dot(g00, vec<2, T, Q>(fx.x, fy.x));\n\t\tT n10 = dot(g10, vec<2, T, Q>(fx.y, fy.y));\n\t\tT n01 = dot(g01, vec<2, T, Q>(fx.z, fy.z));\n\t\tT n11 = dot(g11, vec<2, T, Q>(fx.w, fy.w));\n\n\t\tvec<2, T, Q> fade_xy = detail::fade(vec<2, T, Q>(Pf.x, Pf.y));\n\t\tvec<2, T, Q> n_x = mix(vec<2, T, Q>(n00, n01), vec<2, T, Q>(n10, n11), fade_xy.x);\n\t\tT n_xy = mix(n_x.x, n_x.y, fade_xy.y);\n\t\treturn T(2.3) * n_xy;\n\t}\n\n\t// Classic Perlin noise, periodic variant\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<3, T, Q> const& Position, vec<3, T, Q> const& rep)\n\t{\n\t\tvec<3, T, Q> Pi0 = mod(floor(Position), rep); // Integer part, modulo period\n\t\tvec<3, T, Q> Pi1 = mod(Pi0 + vec<3, T, Q>(T(1)), rep); // Integer part + 1, mod period\n\t\tPi0 = mod(Pi0, vec<3, T, Q>(289));\n\t\tPi1 = mod(Pi1, vec<3, T, Q>(289));\n\t\tvec<3, T, Q> Pf0 = fract(Position); // Fractional part for interpolation\n\t\tvec<3, T, Q> Pf1 = Pf0 - vec<3, T, Q>(T(1)); // Fractional part - 1.0\n\t\tvec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x);\n\t\tvec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y);\n\t\tvec<4, T, Q> iz0(Pi0.z);\n\t\tvec<4, T, Q> iz1(Pi1.z);\n\n\t\tvec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy);\n\t\tvec<4, T, Q> ixy0 = detail::permute(ixy + iz0);\n\t\tvec<4, T, Q> ixy1 = detail::permute(ixy + iz1);\n\n\t\tvec<4, T, Q> gx0 = ixy0 / T(7);\n\t\tvec<4, T, Q> gy0 = fract(floor(gx0) / T(7)) - T(0.5);\n\t\tgx0 = fract(gx0);\n\t\tvec<4, T, Q> gz0 = vec<4, T, Q>(0.5) - abs(gx0) - abs(gy0);\n\t\tvec<4, T, Q> sz0 = step(gz0, vec<4, T, Q>(0));\n\t\tgx0 -= sz0 * (step(T(0), gx0) - T(0.5));\n\t\tgy0 -= sz0 * (step(T(0), gy0) - T(0.5));\n\n\t\tvec<4, T, Q> gx1 = ixy1 / T(7);\n\t\tvec<4, T, Q> gy1 = fract(floor(gx1) / T(7)) - T(0.5);\n\t\tgx1 = fract(gx1);\n\t\tvec<4, T, Q> gz1 = vec<4, T, Q>(0.5) - abs(gx1) - abs(gy1);\n\t\tvec<4, T, Q> sz1 = step(gz1, vec<4, T, Q>(T(0)));\n\t\tgx1 -= sz1 * (step(T(0), gx1) - T(0.5));\n\t\tgy1 -= sz1 * (step(T(0), gy1) - T(0.5));\n\n\t\tvec<3, T, Q> g000 = vec<3, T, Q>(gx0.x, gy0.x, gz0.x);\n\t\tvec<3, T, Q> g100 = vec<3, T, Q>(gx0.y, gy0.y, gz0.y);\n\t\tvec<3, T, Q> g010 = vec<3, T, Q>(gx0.z, gy0.z, gz0.z);\n\t\tvec<3, T, Q> g110 = vec<3, T, Q>(gx0.w, gy0.w, gz0.w);\n\t\tvec<3, T, Q> g001 = vec<3, T, Q>(gx1.x, gy1.x, gz1.x);\n\t\tvec<3, T, Q> g101 = vec<3, T, Q>(gx1.y, gy1.y, gz1.y);\n\t\tvec<3, T, Q> g011 = vec<3, T, Q>(gx1.z, gy1.z, gz1.z);\n\t\tvec<3, T, Q> g111 = vec<3, T, Q>(gx1.w, gy1.w, gz1.w);\n\n\t\tvec<4, T, Q> norm0 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));\n\t\tg000 *= norm0.x;\n\t\tg010 *= norm0.y;\n\t\tg100 *= norm0.z;\n\t\tg110 *= norm0.w;\n\t\tvec<4, T, Q> norm1 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));\n\t\tg001 *= norm1.x;\n\t\tg011 *= norm1.y;\n\t\tg101 *= norm1.z;\n\t\tg111 *= norm1.w;\n\n\t\tT n000 = dot(g000, Pf0);\n\t\tT n100 = dot(g100, vec<3, T, Q>(Pf1.x, Pf0.y, Pf0.z));\n\t\tT n010 = dot(g010, vec<3, T, Q>(Pf0.x, Pf1.y, Pf0.z));\n\t\tT n110 = dot(g110, vec<3, T, Q>(Pf1.x, Pf1.y, Pf0.z));\n\t\tT n001 = dot(g001, vec<3, T, Q>(Pf0.x, Pf0.y, Pf1.z));\n\t\tT n101 = dot(g101, vec<3, T, Q>(Pf1.x, Pf0.y, Pf1.z));\n\t\tT n011 = dot(g011, vec<3, T, Q>(Pf0.x, Pf1.y, Pf1.z));\n\t\tT n111 = dot(g111, Pf1);\n\n\t\tvec<3, T, Q> fade_xyz = detail::fade(Pf0);\n\t\tvec<4, T, Q> n_z = mix(vec<4, T, Q>(n000, n100, n010, n110), vec<4, T, Q>(n001, n101, n011, n111), fade_xyz.z);\n\t\tvec<2, T, Q> n_yz = mix(vec<2, T, Q>(n_z.x, n_z.y), vec<2, T, Q>(n_z.z, n_z.w), fade_xyz.y);\n\t\tT n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);\n\t\treturn T(2.2) * n_xyz;\n\t}\n\n\t// Classic Perlin noise, periodic version\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T perlin(vec<4, T, Q> const& Position, vec<4, T, Q> const& rep)\n\t{\n\t\tvec<4, T, Q> Pi0 = mod(floor(Position), rep); // Integer part modulo rep\n\t\tvec<4, T, Q> Pi1 = mod(Pi0 + T(1), rep); // Integer part + 1 mod rep\n\t\tvec<4, T, Q> Pf0 = fract(Position); // Fractional part for interpolation\n\t\tvec<4, T, Q> Pf1 = Pf0 - T(1); // Fractional part - 1.0\n\t\tvec<4, T, Q> ix = vec<4, T, Q>(Pi0.x, Pi1.x, Pi0.x, Pi1.x);\n\t\tvec<4, T, Q> iy = vec<4, T, Q>(Pi0.y, Pi0.y, Pi1.y, Pi1.y);\n\t\tvec<4, T, Q> iz0(Pi0.z);\n\t\tvec<4, T, Q> iz1(Pi1.z);\n\t\tvec<4, T, Q> iw0(Pi0.w);\n\t\tvec<4, T, Q> iw1(Pi1.w);\n\n\t\tvec<4, T, Q> ixy = detail::permute(detail::permute(ix) + iy);\n\t\tvec<4, T, Q> ixy0 = detail::permute(ixy + iz0);\n\t\tvec<4, T, Q> ixy1 = detail::permute(ixy + iz1);\n\t\tvec<4, T, Q> ixy00 = detail::permute(ixy0 + iw0);\n\t\tvec<4, T, Q> ixy01 = detail::permute(ixy0 + iw1);\n\t\tvec<4, T, Q> ixy10 = detail::permute(ixy1 + iw0);\n\t\tvec<4, T, Q> ixy11 = detail::permute(ixy1 + iw1);\n\n\t\tvec<4, T, Q> gx00 = ixy00 / T(7);\n\t\tvec<4, T, Q> gy00 = floor(gx00) / T(7);\n\t\tvec<4, T, Q> gz00 = floor(gy00) / T(6);\n\t\tgx00 = fract(gx00) - T(0.5);\n\t\tgy00 = fract(gy00) - T(0.5);\n\t\tgz00 = fract(gz00) - T(0.5);\n\t\tvec<4, T, Q> gw00 = vec<4, T, Q>(0.75) - abs(gx00) - abs(gy00) - abs(gz00);\n\t\tvec<4, T, Q> sw00 = step(gw00, vec<4, T, Q>(0));\n\t\tgx00 -= sw00 * (step(T(0), gx00) - T(0.5));\n\t\tgy00 -= sw00 * (step(T(0), gy00) - T(0.5));\n\n\t\tvec<4, T, Q> gx01 = ixy01 / T(7);\n\t\tvec<4, T, Q> gy01 = floor(gx01) / T(7);\n\t\tvec<4, T, Q> gz01 = floor(gy01) / T(6);\n\t\tgx01 = fract(gx01) - T(0.5);\n\t\tgy01 = fract(gy01) - T(0.5);\n\t\tgz01 = fract(gz01) - T(0.5);\n\t\tvec<4, T, Q> gw01 = vec<4, T, Q>(0.75) - abs(gx01) - abs(gy01) - abs(gz01);\n\t\tvec<4, T, Q> sw01 = step(gw01, vec<4, T, Q>(0.0));\n\t\tgx01 -= sw01 * (step(T(0), gx01) - T(0.5));\n\t\tgy01 -= sw01 * (step(T(0), gy01) - T(0.5));\n\n\t\tvec<4, T, Q> gx10 = ixy10 / T(7);\n\t\tvec<4, T, Q> gy10 = floor(gx10) / T(7);\n\t\tvec<4, T, Q> gz10 = floor(gy10) / T(6);\n\t\tgx10 = fract(gx10) - T(0.5);\n\t\tgy10 = fract(gy10) - T(0.5);\n\t\tgz10 = fract(gz10) - T(0.5);\n\t\tvec<4, T, Q> gw10 = vec<4, T, Q>(0.75) - abs(gx10) - abs(gy10) - abs(gz10);\n\t\tvec<4, T, Q> sw10 = step(gw10, vec<4, T, Q>(0.0));\n\t\tgx10 -= sw10 * (step(T(0), gx10) - T(0.5));\n\t\tgy10 -= sw10 * (step(T(0), gy10) - T(0.5));\n\n\t\tvec<4, T, Q> gx11 = ixy11 / T(7);\n\t\tvec<4, T, Q> gy11 = floor(gx11) / T(7);\n\t\tvec<4, T, Q> gz11 = floor(gy11) / T(6);\n\t\tgx11 = fract(gx11) - T(0.5);\n\t\tgy11 = fract(gy11) - T(0.5);\n\t\tgz11 = fract(gz11) - T(0.5);\n\t\tvec<4, T, Q> gw11 = vec<4, T, Q>(0.75) - abs(gx11) - abs(gy11) - abs(gz11);\n\t\tvec<4, T, Q> sw11 = step(gw11, vec<4, T, Q>(T(0)));\n\t\tgx11 -= sw11 * (step(T(0), gx11) - T(0.5));\n\t\tgy11 -= sw11 * (step(T(0), gy11) - T(0.5));\n\n\t\tvec<4, T, Q> g0000(gx00.x, gy00.x, gz00.x, gw00.x);\n\t\tvec<4, T, Q> g1000(gx00.y, gy00.y, gz00.y, gw00.y);\n\t\tvec<4, T, Q> g0100(gx00.z, gy00.z, gz00.z, gw00.z);\n\t\tvec<4, T, Q> g1100(gx00.w, gy00.w, gz00.w, gw00.w);\n\t\tvec<4, T, Q> g0010(gx10.x, gy10.x, gz10.x, gw10.x);\n\t\tvec<4, T, Q> g1010(gx10.y, gy10.y, gz10.y, gw10.y);\n\t\tvec<4, T, Q> g0110(gx10.z, gy10.z, gz10.z, gw10.z);\n\t\tvec<4, T, Q> g1110(gx10.w, gy10.w, gz10.w, gw10.w);\n\t\tvec<4, T, Q> g0001(gx01.x, gy01.x, gz01.x, gw01.x);\n\t\tvec<4, T, Q> g1001(gx01.y, gy01.y, gz01.y, gw01.y);\n\t\tvec<4, T, Q> g0101(gx01.z, gy01.z, gz01.z, gw01.z);\n\t\tvec<4, T, Q> g1101(gx01.w, gy01.w, gz01.w, gw01.w);\n\t\tvec<4, T, Q> g0011(gx11.x, gy11.x, gz11.x, gw11.x);\n\t\tvec<4, T, Q> g1011(gx11.y, gy11.y, gz11.y, gw11.y);\n\t\tvec<4, T, Q> g0111(gx11.z, gy11.z, gz11.z, gw11.z);\n\t\tvec<4, T, Q> g1111(gx11.w, gy11.w, gz11.w, gw11.w);\n\n\t\tvec<4, T, Q> norm00 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));\n\t\tg0000 *= norm00.x;\n\t\tg0100 *= norm00.y;\n\t\tg1000 *= norm00.z;\n\t\tg1100 *= norm00.w;\n\n\t\tvec<4, T, Q> norm01 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));\n\t\tg0001 *= norm01.x;\n\t\tg0101 *= norm01.y;\n\t\tg1001 *= norm01.z;\n\t\tg1101 *= norm01.w;\n\n\t\tvec<4, T, Q> norm10 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));\n\t\tg0010 *= norm10.x;\n\t\tg0110 *= norm10.y;\n\t\tg1010 *= norm10.z;\n\t\tg1110 *= norm10.w;\n\n\t\tvec<4, T, Q> norm11 = detail::taylorInvSqrt(vec<4, T, Q>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));\n\t\tg0011 *= norm11.x;\n\t\tg0111 *= norm11.y;\n\t\tg1011 *= norm11.z;\n\t\tg1111 *= norm11.w;\n\n\t\tT n0000 = dot(g0000, Pf0);\n\t\tT n1000 = dot(g1000, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf0.w));\n\t\tT n0100 = dot(g0100, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf0.w));\n\t\tT n1100 = dot(g1100, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf0.w));\n\t\tT n0010 = dot(g0010, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf0.w));\n\t\tT n1010 = dot(g1010, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf0.w));\n\t\tT n0110 = dot(g0110, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf0.w));\n\t\tT n1110 = dot(g1110, vec<4, T, Q>(Pf1.x, Pf1.y, Pf1.z, Pf0.w));\n\t\tT n0001 = dot(g0001, vec<4, T, Q>(Pf0.x, Pf0.y, Pf0.z, Pf1.w));\n\t\tT n1001 = dot(g1001, vec<4, T, Q>(Pf1.x, Pf0.y, Pf0.z, Pf1.w));\n\t\tT n0101 = dot(g0101, vec<4, T, Q>(Pf0.x, Pf1.y, Pf0.z, Pf1.w));\n\t\tT n1101 = dot(g1101, vec<4, T, Q>(Pf1.x, Pf1.y, Pf0.z, Pf1.w));\n\t\tT n0011 = dot(g0011, vec<4, T, Q>(Pf0.x, Pf0.y, Pf1.z, Pf1.w));\n\t\tT n1011 = dot(g1011, vec<4, T, Q>(Pf1.x, Pf0.y, Pf1.z, Pf1.w));\n\t\tT n0111 = dot(g0111, vec<4, T, Q>(Pf0.x, Pf1.y, Pf1.z, Pf1.w));\n\t\tT n1111 = dot(g1111, Pf1);\n\n\t\tvec<4, T, Q> fade_xyzw = detail::fade(Pf0);\n\t\tvec<4, T, Q> n_0w = mix(vec<4, T, Q>(n0000, n1000, n0100, n1100), vec<4, T, Q>(n0001, n1001, n0101, n1101), fade_xyzw.w);\n\t\tvec<4, T, Q> n_1w = mix(vec<4, T, Q>(n0010, n1010, n0110, n1110), vec<4, T, Q>(n0011, n1011, n0111, n1111), fade_xyzw.w);\n\t\tvec<4, T, Q> n_zw = mix(n_0w, n_1w, fade_xyzw.z);\n\t\tvec<2, T, Q> n_yzw = mix(vec<2, T, Q>(n_zw.x, n_zw.y), vec<2, T, Q>(n_zw.z, n_zw.w), fade_xyzw.y);\n\t\tT n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);\n\t\treturn T(2.2) * n_xyzw;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T simplex(glm::vec<2, T, Q> const& v)\n\t{\n\t\tvec<4, T, Q> const C = vec<4, T, Q>(\n\t\t\tT( 0.211324865405187),  // (3.0 -  sqrt(3.0)) / 6.0\n\t\t\tT( 0.366025403784439),  //  0.5 * (sqrt(3.0)  - 1.0)\n\t\t\tT(-0.577350269189626),\t// -1.0 + 2.0 * C.x\n\t\t\tT( 0.024390243902439)); //  1.0 / 41.0\n\n\t\t// First corner\n\t\tvec<2, T, Q> i  = floor(v + dot(v, vec<2, T, Q>(C[1])));\n\t\tvec<2, T, Q> x0 = v -   i + dot(i, vec<2, T, Q>(C[0]));\n\n\t\t// Other corners\n\t\t//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0\n\t\t//i1.y = 1.0 - i1.x;\n\t\tvec<2, T, Q> i1 = (x0.x > x0.y) ? vec<2, T, Q>(1, 0) : vec<2, T, Q>(0, 1);\n\t\t// x0 = x0 - 0.0 + 0.0 * C.xx ;\n\t\t// x1 = x0 - i1 + 1.0 * C.xx ;\n\t\t// x2 = x0 - 1.0 + 2.0 * C.xx ;\n\t\tvec<4, T, Q> x12 = vec<4, T, Q>(x0.x, x0.y, x0.x, x0.y) + vec<4, T, Q>(C.x, C.x, C.z, C.z);\n\t\tx12 = vec<4, T, Q>(vec<2, T, Q>(x12) - i1, x12.z, x12.w);\n\n\t\t// Permutations\n\t\ti = mod(i, vec<2, T, Q>(289)); // Avoid truncation effects in permutation\n\t\tvec<3, T, Q> p = detail::permute(\n\t\t\tdetail::permute(i.y + vec<3, T, Q>(T(0), i1.y, T(1)))\n\t\t\t+ i.x + vec<3, T, Q>(T(0), i1.x, T(1)));\n\n\t\tvec<3, T, Q> m = max(vec<3, T, Q>(0.5) - vec<3, T, Q>(\n\t\t\tdot(x0, x0),\n\t\t\tdot(vec<2, T, Q>(x12.x, x12.y), vec<2, T, Q>(x12.x, x12.y)),\n\t\t\tdot(vec<2, T, Q>(x12.z, x12.w), vec<2, T, Q>(x12.z, x12.w))), vec<3, T, Q>(0));\n\t\tm = m * m ;\n\t\tm = m * m ;\n\n\t\t// Gradients: 41 points uniformly over a line, mapped onto a diamond.\n\t\t// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)\n\n\t\tvec<3, T, Q> x = static_cast<T>(2) * fract(p * C.w) - T(1);\n\t\tvec<3, T, Q> h = abs(x) - T(0.5);\n\t\tvec<3, T, Q> ox = floor(x + T(0.5));\n\t\tvec<3, T, Q> a0 = x - ox;\n\n\t\t// Normalise gradients implicitly by scaling m\n\t\t// Inlined for speed: m *= taylorInvSqrt( a0*a0 + h*h );\n\t\tm *= static_cast<T>(1.79284291400159) - T(0.85373472095314) * (a0 * a0 + h * h);\n\n\t\t// Compute final noise value at P\n\t\tvec<3, T, Q> g;\n\t\tg.x  = a0.x  * x0.x  + h.x  * x0.y;\n\t\t//g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n\t\tg.y = a0.y * x12.x + h.y * x12.y;\n\t\tg.z = a0.z * x12.z + h.z * x12.w;\n\t\treturn T(130) * dot(m, g);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T simplex(vec<3, T, Q> const& v)\n\t{\n\t\tvec<2, T, Q> const C(1.0 / 6.0, 1.0 / 3.0);\n\t\tvec<4, T, Q> const D(0.0, 0.5, 1.0, 2.0);\n\n\t\t// First corner\n\t\tvec<3, T, Q> i(floor(v + dot(v, vec<3, T, Q>(C.y))));\n\t\tvec<3, T, Q> x0(v - i + dot(i, vec<3, T, Q>(C.x)));\n\n\t\t// Other corners\n\t\tvec<3, T, Q> g(step(vec<3, T, Q>(x0.y, x0.z, x0.x), x0));\n\t\tvec<3, T, Q> l(T(1) - g);\n\t\tvec<3, T, Q> i1(min(g, vec<3, T, Q>(l.z, l.x, l.y)));\n\t\tvec<3, T, Q> i2(max(g, vec<3, T, Q>(l.z, l.x, l.y)));\n\n\t\t//   x0 = x0 - 0.0 + 0.0 * C.xxx;\n\t\t//   x1 = x0 - i1  + 1.0 * C.xxx;\n\t\t//   x2 = x0 - i2  + 2.0 * C.xxx;\n\t\t//   x3 = x0 - 1.0 + 3.0 * C.xxx;\n\t\tvec<3, T, Q> x1(x0 - i1 + C.x);\n\t\tvec<3, T, Q> x2(x0 - i2 + C.y); // 2.0*C.x = 1/3 = C.y\n\t\tvec<3, T, Q> x3(x0 - D.y);      // -1.0+3.0*C.x = -0.5 = -D.y\n\n\t\t// Permutations\n\t\ti = detail::mod289(i);\n\t\tvec<4, T, Q> p(detail::permute(detail::permute(detail::permute(\n\t\t\ti.z + vec<4, T, Q>(T(0), i1.z, i2.z, T(1))) +\n\t\t\ti.y + vec<4, T, Q>(T(0), i1.y, i2.y, T(1))) +\n\t\t\ti.x + vec<4, T, Q>(T(0), i1.x, i2.x, T(1))));\n\n\t\t// Gradients: 7x7 points over a square, mapped onto an octahedron.\n\t\t// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)\n\t\tT n_ = static_cast<T>(0.142857142857); // 1.0/7.0\n\t\tvec<3, T, Q> ns(n_ * vec<3, T, Q>(D.w, D.y, D.z) - vec<3, T, Q>(D.x, D.z, D.x));\n\n\t\tvec<4, T, Q> j(p - T(49) * floor(p * ns.z * ns.z));  //  mod(p,7*7)\n\n\t\tvec<4, T, Q> x_(floor(j * ns.z));\n\t\tvec<4, T, Q> y_(floor(j - T(7) * x_));    // mod(j,N)\n\n\t\tvec<4, T, Q> x(x_ * ns.x + ns.y);\n\t\tvec<4, T, Q> y(y_ * ns.x + ns.y);\n\t\tvec<4, T, Q> h(T(1) - abs(x) - abs(y));\n\n\t\tvec<4, T, Q> b0(x.x, x.y, y.x, y.y);\n\t\tvec<4, T, Q> b1(x.z, x.w, y.z, y.w);\n\n\t\t// vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;\n\t\t// vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;\n\t\tvec<4, T, Q> s0(floor(b0) * T(2) + T(1));\n\t\tvec<4, T, Q> s1(floor(b1) * T(2) + T(1));\n\t\tvec<4, T, Q> sh(-step(h, vec<4, T, Q>(0.0)));\n\n\t\tvec<4, T, Q> a0 = vec<4, T, Q>(b0.x, b0.z, b0.y, b0.w) + vec<4, T, Q>(s0.x, s0.z, s0.y, s0.w) * vec<4, T, Q>(sh.x, sh.x, sh.y, sh.y);\n\t\tvec<4, T, Q> a1 = vec<4, T, Q>(b1.x, b1.z, b1.y, b1.w) + vec<4, T, Q>(s1.x, s1.z, s1.y, s1.w) * vec<4, T, Q>(sh.z, sh.z, sh.w, sh.w);\n\n\t\tvec<3, T, Q> p0(a0.x, a0.y, h.x);\n\t\tvec<3, T, Q> p1(a0.z, a0.w, h.y);\n\t\tvec<3, T, Q> p2(a1.x, a1.y, h.z);\n\t\tvec<3, T, Q> p3(a1.z, a1.w, h.w);\n\n\t\t// Normalise gradients\n\t\tvec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));\n\t\tp0 *= norm.x;\n\t\tp1 *= norm.y;\n\t\tp2 *= norm.z;\n\t\tp3 *= norm.w;\n\n\t\t// Mix final noise value\n\t\tvec<4, T, Q> m = max(T(0.6) - vec<4, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec<4, T, Q>(0));\n\t\tm = m * m;\n\t\treturn T(42) * dot(m * m, vec<4, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T simplex(vec<4, T, Q> const& v)\n\t{\n\t\tvec<4, T, Q> const C(\n\t\t\t0.138196601125011,  // (5 - sqrt(5))/20  G4\n\t\t\t0.276393202250021,  // 2 * G4\n\t\t\t0.414589803375032,  // 3 * G4\n\t\t\t-0.447213595499958); // -1 + 4 * G4\n\n\t\t// (sqrt(5) - 1)/4 = F4, used once below\n\t\tT const F4 = static_cast<T>(0.309016994374947451);\n\n\t\t// First corner\n\t\tvec<4, T, Q> i  = floor(v + dot(v, vec<4, T, Q>(F4)));\n\t\tvec<4, T, Q> x0 = v -   i + dot(i, vec<4, T, Q>(C.x));\n\n\t\t// Other corners\n\n\t\t// Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)\n\t\tvec<4, T, Q> i0;\n\t\tvec<3, T, Q> isX = step(vec<3, T, Q>(x0.y, x0.z, x0.w), vec<3, T, Q>(x0.x));\n\t\tvec<3, T, Q> isYZ = step(vec<3, T, Q>(x0.z, x0.w, x0.w), vec<3, T, Q>(x0.y, x0.y, x0.z));\n\t\t//  i0.x = dot(isX, vec3(1.0));\n\t\t//i0.x = isX.x + isX.y + isX.z;\n\t\t//i0.yzw = static_cast<T>(1) - isX;\n\t\ti0 = vec<4, T, Q>(isX.x + isX.y + isX.z, T(1) - isX);\n\t\t//  i0.y += dot(isYZ.xy, vec2(1.0));\n\t\ti0.y += isYZ.x + isYZ.y;\n\t\t//i0.zw += 1.0 - vec<2, T, Q>(isYZ.x, isYZ.y);\n\t\ti0.z += static_cast<T>(1) - isYZ.x;\n\t\ti0.w += static_cast<T>(1) - isYZ.y;\n\t\ti0.z += isYZ.z;\n\t\ti0.w += static_cast<T>(1) - isYZ.z;\n\n\t\t// i0 now contains the unique values 0,1,2,3 in each channel\n\t\tvec<4, T, Q> i3 = clamp(i0, T(0), T(1));\n\t\tvec<4, T, Q> i2 = clamp(i0 - T(1), T(0), T(1));\n\t\tvec<4, T, Q> i1 = clamp(i0 - T(2), T(0), T(1));\n\n\t\t//  x0 = x0 - 0.0 + 0.0 * C.xxxx\n\t\t//  x1 = x0 - i1  + 0.0 * C.xxxx\n\t\t//  x2 = x0 - i2  + 0.0 * C.xxxx\n\t\t//  x3 = x0 - i3  + 0.0 * C.xxxx\n\t\t//  x4 = x0 - 1.0 + 4.0 * C.xxxx\n\t\tvec<4, T, Q> x1 = x0 - i1 + C.x;\n\t\tvec<4, T, Q> x2 = x0 - i2 + C.y;\n\t\tvec<4, T, Q> x3 = x0 - i3 + C.z;\n\t\tvec<4, T, Q> x4 = x0 + C.w;\n\n\t\t// Permutations\n\t\ti = mod(i, vec<4, T, Q>(289));\n\t\tT j0 = detail::permute(detail::permute(detail::permute(detail::permute(i.w) + i.z) + i.y) + i.x);\n\t\tvec<4, T, Q> j1 = detail::permute(detail::permute(detail::permute(detail::permute(\n\t\t\ti.w + vec<4, T, Q>(i1.w, i2.w, i3.w, T(1))) +\n\t\t\ti.z + vec<4, T, Q>(i1.z, i2.z, i3.z, T(1))) +\n\t\t\ti.y + vec<4, T, Q>(i1.y, i2.y, i3.y, T(1))) +\n\t\t\ti.x + vec<4, T, Q>(i1.x, i2.x, i3.x, T(1)));\n\n\t\t// Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope\n\t\t// 7*7*6 = 294, which is close to the ring size 17*17 = 289.\n\t\tvec<4, T, Q> ip = vec<4, T, Q>(T(1) / T(294), T(1) / T(49), T(1) / T(7), T(0));\n\n\t\tvec<4, T, Q> p0 = gtc::grad4(j0,   ip);\n\t\tvec<4, T, Q> p1 = gtc::grad4(j1.x, ip);\n\t\tvec<4, T, Q> p2 = gtc::grad4(j1.y, ip);\n\t\tvec<4, T, Q> p3 = gtc::grad4(j1.z, ip);\n\t\tvec<4, T, Q> p4 = gtc::grad4(j1.w, ip);\n\n\t\t// Normalise gradients\n\t\tvec<4, T, Q> norm = detail::taylorInvSqrt(vec<4, T, Q>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));\n\t\tp0 *= norm.x;\n\t\tp1 *= norm.y;\n\t\tp2 *= norm.z;\n\t\tp3 *= norm.w;\n\t\tp4 *= detail::taylorInvSqrt(dot(p4, p4));\n\n\t\t// Mix contributions from the five corners\n\t\tvec<3, T, Q> m0 = max(T(0.6) - vec<3, T, Q>(dot(x0, x0), dot(x1, x1), dot(x2, x2)), vec<3, T, Q>(0));\n\t\tvec<2, T, Q> m1 = max(T(0.6) - vec<2, T, Q>(dot(x3, x3), dot(x4, x4)             ), vec<2, T, Q>(0));\n\t\tm0 = m0 * m0;\n\t\tm1 = m1 * m1;\n\t\treturn T(49) *\n\t\t\t(dot(m0 * m0, vec<3, T, Q>(dot(p0, x0), dot(p1, x1), dot(p2, x2))) +\n\t\t\tdot(m1 * m1, vec<2, T, Q>(dot(p3, x3), dot(p4, x4))));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/packing.hpp",
    "content": "/// @ref gtc_packing\n/// @file glm/gtc/packing.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_packing GLM_GTC_packing\n/// @ingroup gtc\n///\n/// Include <glm/gtc/packing.hpp> to use the features of this extension.\n///\n/// This extension provides a set of function to convert vertors to packed\n/// formats.\n\n#pragma once\n\n// Dependency:\n#include \"type_precision.hpp\"\n#include \"../ext/vector_packing.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_packing extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_packing\n\t/// @{\n\n\t/// First, converts the normalized floating-point value v into a 8-bit integer value.\n\t/// Then, the results are packed into the returned 8-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm1x8:\tround(clamp(c, 0, +1) * 255.0)\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packUnorm2x8(vec2 const& v)\n\t/// @see uint32 packUnorm4x8(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml\">GLSL packUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint8 packUnorm1x8(float v);\n\n\t/// Convert a single 8-bit integer to a normalized floating-point value.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackUnorm4x8: f / 255.0\n\t///\n\t/// @see gtc_packing\n\t/// @see vec2 unpackUnorm2x8(uint16 p)\n\t/// @see vec4 unpackUnorm4x8(uint32 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm4x8.xml\">GLSL unpackUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL float unpackUnorm1x8(uint8 p);\n\n\t/// First, converts each component of the normalized floating-point value v into 8-bit integer values.\n\t/// Then, the results are packed into the returned 16-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm2x8:\tround(clamp(c, 0, +1) * 255.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint8 packUnorm1x8(float const& v)\n\t/// @see uint32 packUnorm4x8(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml\">GLSL packUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint16 packUnorm2x8(vec2 const& v);\n\n\t/// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit unsigned integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackUnorm4x8: f / 255.0\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see float unpackUnorm1x8(uint8 v)\n\t/// @see vec4 unpackUnorm4x8(uint32 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm4x8.xml\">GLSL unpackUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec2 unpackUnorm2x8(uint16 p);\n\n\t/// First, converts the normalized floating-point value v into 8-bit integer value.\n\t/// Then, the results are packed into the returned 8-bit unsigned integer.\n\t///\n\t/// The conversion to fixed point is done as follows:\n\t/// packSnorm1x8:\tround(clamp(s, -1, +1) * 127.0)\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packSnorm2x8(vec2 const& v)\n\t/// @see uint32 packSnorm4x8(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml\">GLSL packSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint8 packSnorm1x8(float s);\n\n\t/// First, unpacks a single 8-bit unsigned integer p into a single 8-bit signed integers.\n\t/// Then, the value is converted to a normalized floating-point value to generate the returned scalar.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm1x8: clamp(f / 127.0, -1, +1)\n\t///\n\t/// @see gtc_packing\n\t/// @see vec2 unpackSnorm2x8(uint16 p)\n\t/// @see vec4 unpackSnorm4x8(uint32 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm4x8.xml\">GLSL unpackSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL float unpackSnorm1x8(uint8 p);\n\n\t/// First, converts each component of the normalized floating-point value v into 8-bit integer values.\n\t/// Then, the results are packed into the returned 16-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packSnorm2x8:\tround(clamp(c, -1, +1) * 127.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint8 packSnorm1x8(float const& v)\n\t/// @see uint32 packSnorm4x8(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml\">GLSL packSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint16 packSnorm2x8(vec2 const& v);\n\n\t/// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm2x8: clamp(f / 127.0, -1, +1)\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see float unpackSnorm1x8(uint8 p)\n\t/// @see vec4 unpackSnorm4x8(uint32 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm4x8.xml\">GLSL unpackSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec2 unpackSnorm2x8(uint16 p);\n\n\t/// First, converts the normalized floating-point value v into a 16-bit integer value.\n\t/// Then, the results are packed into the returned 16-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm1x16:\tround(clamp(c, 0, +1) * 65535.0)\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packSnorm1x16(float const& v)\n\t/// @see uint64 packSnorm4x16(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml\">GLSL packUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint16 packUnorm1x16(float v);\n\n\t/// First, unpacks a single 16-bit unsigned integer p into a of 16-bit unsigned integers.\n\t/// Then, the value is converted to a normalized floating-point value to generate the returned scalar.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackUnorm1x16: f / 65535.0\n\t///\n\t/// @see gtc_packing\n\t/// @see vec2 unpackUnorm2x16(uint32 p)\n\t/// @see vec4 unpackUnorm4x16(uint64 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm2x16.xml\">GLSL unpackUnorm2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL float unpackUnorm1x16(uint16 p);\n\n\t/// First, converts each component of the normalized floating-point value v into 16-bit integer values.\n\t/// Then, the results are packed into the returned 64-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm4x16:\tround(clamp(c, 0, +1) * 65535.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packUnorm1x16(float const& v)\n\t/// @see uint32 packUnorm2x16(vec2 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml\">GLSL packUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint64 packUnorm4x16(vec4 const& v);\n\n\t/// First, unpacks a single 64-bit unsigned integer p into four 16-bit unsigned integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackUnormx4x16: f / 65535.0\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see float unpackUnorm1x16(uint16 p)\n\t/// @see vec2 unpackUnorm2x16(uint32 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm2x16.xml\">GLSL unpackUnorm2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec4 unpackUnorm4x16(uint64 p);\n\n\t/// First, converts the normalized floating-point value v into 16-bit integer value.\n\t/// Then, the results are packed into the returned 16-bit unsigned integer.\n\t///\n\t/// The conversion to fixed point is done as follows:\n\t/// packSnorm1x8:\tround(clamp(s, -1, +1) * 32767.0)\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packSnorm2x16(vec2 const& v)\n\t/// @see uint64 packSnorm4x16(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml\">GLSL packSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint16 packSnorm1x16(float v);\n\n\t/// First, unpacks a single 16-bit unsigned integer p into a single 16-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned scalar.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm1x16: clamp(f / 32767.0, -1, +1)\n\t///\n\t/// @see gtc_packing\n\t/// @see vec2 unpackSnorm2x16(uint32 p)\n\t/// @see vec4 unpackSnorm4x16(uint64 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm1x16.xml\">GLSL unpackSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL float unpackSnorm1x16(uint16 p);\n\n\t/// First, converts each component of the normalized floating-point value v into 16-bit integer values.\n\t/// Then, the results are packed into the returned 64-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packSnorm2x8:\tround(clamp(c, -1, +1) * 32767.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packSnorm1x16(float const& v)\n\t/// @see uint32 packSnorm2x16(vec2 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml\">GLSL packSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint64 packSnorm4x16(vec4 const& v);\n\n\t/// First, unpacks a single 64-bit unsigned integer p into four 16-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm4x16: clamp(f / 32767.0, -1, +1)\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see float unpackSnorm1x16(uint16 p)\n\t/// @see vec2 unpackSnorm2x16(uint32 p)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm2x16.xml\">GLSL unpackSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec4 unpackSnorm4x16(uint64 p);\n\n\t/// Returns an unsigned integer obtained by converting the components of a floating-point scalar\n\t/// to the 16-bit floating-point representation found in the OpenGL Specification,\n\t/// and then packing this 16-bit value into a 16-bit unsigned integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packHalf2x16(vec2 const& v)\n\t/// @see uint64 packHalf4x16(vec4 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packHalf2x16.xml\">GLSL packHalf2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint16 packHalf1x16(float v);\n\n\t/// Returns a floating-point scalar with components obtained by unpacking a 16-bit unsigned integer into a 16-bit value,\n\t/// interpreted as a 16-bit floating-point number according to the OpenGL Specification,\n\t/// and converting it to 32-bit floating-point values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec2 unpackHalf2x16(uint32 const& v)\n\t/// @see vec4 unpackHalf4x16(uint64 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackHalf2x16.xml\">GLSL unpackHalf2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL float unpackHalf1x16(uint16 v);\n\n\t/// Returns an unsigned integer obtained by converting the components of a four-component floating-point vector\n\t/// to the 16-bit floating-point representation found in the OpenGL Specification,\n\t/// and then packing these four 16-bit values into a 64-bit unsigned integer.\n\t/// The first vector component specifies the 16 least-significant bits of the result;\n\t/// the forth component specifies the 16 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packHalf1x16(float const& v)\n\t/// @see uint32 packHalf2x16(vec2 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packHalf2x16.xml\">GLSL packHalf2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint64 packHalf4x16(vec4 const& v);\n\n\t/// Returns a four-component floating-point vector with components obtained by unpacking a 64-bit unsigned integer into four 16-bit values,\n\t/// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification,\n\t/// and converting them to 32-bit floating-point values.\n\t/// The first component of the vector is obtained from the 16 least-significant bits of v;\n\t/// the forth component is obtained from the 16 most-significant bits of v.\n\t///\n\t/// @see gtc_packing\n\t/// @see float unpackHalf1x16(uint16 const& v)\n\t/// @see vec2 unpackHalf2x16(uint32 const& v)\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackHalf2x16.xml\">GLSL unpackHalf2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec4 unpackHalf4x16(uint64 p);\n\n\t/// Returns an unsigned integer obtained by converting the components of a four-component signed integer vector\n\t/// to the 10-10-10-2-bit signed integer representation found in the OpenGL Specification,\n\t/// and then packing these four values into a 32-bit unsigned integer.\n\t/// The first vector component specifies the 10 least-significant bits of the result;\n\t/// the forth component specifies the 2 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packI3x10_1x2(uvec4 const& v)\n\t/// @see uint32 packSnorm3x10_1x2(vec4 const& v)\n\t/// @see uint32 packUnorm3x10_1x2(vec4 const& v)\n\t/// @see ivec4 unpackI3x10_1x2(uint32 const& p)\n\tGLM_FUNC_DECL uint32 packI3x10_1x2(ivec4 const& v);\n\n\t/// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit signed integers.\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packU3x10_1x2(uvec4 const& v)\n\t/// @see vec4 unpackSnorm3x10_1x2(uint32 const& p);\n\t/// @see uvec4 unpackI3x10_1x2(uint32 const& p);\n\tGLM_FUNC_DECL ivec4 unpackI3x10_1x2(uint32 p);\n\n\t/// Returns an unsigned integer obtained by converting the components of a four-component unsigned integer vector\n\t/// to the 10-10-10-2-bit unsigned integer representation found in the OpenGL Specification,\n\t/// and then packing these four values into a 32-bit unsigned integer.\n\t/// The first vector component specifies the 10 least-significant bits of the result;\n\t/// the forth component specifies the 2 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packI3x10_1x2(ivec4 const& v)\n\t/// @see uint32 packSnorm3x10_1x2(vec4 const& v)\n\t/// @see uint32 packUnorm3x10_1x2(vec4 const& v)\n\t/// @see ivec4 unpackU3x10_1x2(uint32 const& p)\n\tGLM_FUNC_DECL uint32 packU3x10_1x2(uvec4 const& v);\n\n\t/// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit unsigned integers.\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packU3x10_1x2(uvec4 const& v)\n\t/// @see vec4 unpackSnorm3x10_1x2(uint32 const& p);\n\t/// @see uvec4 unpackI3x10_1x2(uint32 const& p);\n\tGLM_FUNC_DECL uvec4 unpackU3x10_1x2(uint32 p);\n\n\t/// First, converts the first three components of the normalized floating-point value v into 10-bit signed integer values.\n\t/// Then, converts the forth component of the normalized floating-point value v into 2-bit signed integer values.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packSnorm3x10_1x2(xyz):\tround(clamp(c, -1, +1) * 511.0)\n\t/// packSnorm3x10_1x2(w):\tround(clamp(c, -1, +1) * 1.0)\n\t///\n\t/// The first vector component specifies the 10 least-significant bits of the result;\n\t/// the forth component specifies the 2 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec4 unpackSnorm3x10_1x2(uint32 const& p)\n\t/// @see uint32 packUnorm3x10_1x2(vec4 const& v)\n\t/// @see uint32 packU3x10_1x2(uvec4 const& v)\n\t/// @see uint32 packI3x10_1x2(ivec4 const& v)\n\tGLM_FUNC_DECL uint32 packSnorm3x10_1x2(vec4 const& v);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm3x10_1x2(xyz): clamp(f / 511.0, -1, +1)\n\t/// unpackSnorm3x10_1x2(w): clamp(f / 511.0, -1, +1)\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packSnorm3x10_1x2(vec4 const& v)\n\t/// @see vec4 unpackUnorm3x10_1x2(uint32 const& p))\n\t/// @see uvec4 unpackI3x10_1x2(uint32 const& p)\n\t/// @see uvec4 unpackU3x10_1x2(uint32 const& p)\n\tGLM_FUNC_DECL vec4 unpackSnorm3x10_1x2(uint32 p);\n\n\t/// First, converts the first three components of the normalized floating-point value v into 10-bit unsigned integer values.\n\t/// Then, converts the forth component of the normalized floating-point value v into 2-bit signed uninteger values.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm3x10_1x2(xyz):\tround(clamp(c, 0, +1) * 1023.0)\n\t/// packUnorm3x10_1x2(w):\tround(clamp(c, 0, +1) * 3.0)\n\t///\n\t/// The first vector component specifies the 10 least-significant bits of the result;\n\t/// the forth component specifies the 2 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec4 unpackUnorm3x10_1x2(uint32 const& p)\n\t/// @see uint32 packUnorm3x10_1x2(vec4 const& v)\n\t/// @see uint32 packU3x10_1x2(uvec4 const& v)\n\t/// @see uint32 packI3x10_1x2(ivec4 const& v)\n\tGLM_FUNC_DECL uint32 packUnorm3x10_1x2(vec4 const& v);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm3x10_1x2(xyz): clamp(f / 1023.0, 0, +1)\n\t/// unpackSnorm3x10_1x2(w): clamp(f / 3.0, 0, +1)\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packSnorm3x10_1x2(vec4 const& v)\n\t/// @see vec4 unpackInorm3x10_1x2(uint32 const& p))\n\t/// @see uvec4 unpackI3x10_1x2(uint32 const& p)\n\t/// @see uvec4 unpackU3x10_1x2(uint32 const& p)\n\tGLM_FUNC_DECL vec4 unpackUnorm3x10_1x2(uint32 p);\n\n\t/// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values.\n\t/// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The first vector component specifies the 11 least-significant bits of the result;\n\t/// the last component specifies the 10 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec3 unpackF2x11_1x10(uint32 const& p)\n\tGLM_FUNC_DECL uint32 packF2x11_1x10(vec3 const& v);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value .\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector.\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packF2x11_1x10(vec3 const& v)\n\tGLM_FUNC_DECL vec3 unpackF2x11_1x10(uint32 p);\n\n\n\t/// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values.\n\t/// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The first vector component specifies the 11 least-significant bits of the result;\n\t/// the last component specifies the 10 most-significant bits.\n\t///\n\t/// packF3x9_E1x5 allows encoding into RGBE / RGB9E5 format\n\t///\n\t/// @see gtc_packing\n\t/// @see vec3 unpackF3x9_E1x5(uint32 const& p)\n\tGLM_FUNC_DECL uint32 packF3x9_E1x5(vec3 const& v);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value .\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector.\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// unpackF3x9_E1x5 allows decoding RGBE / RGB9E5 data\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packF3x9_E1x5(vec3 const& v)\n\tGLM_FUNC_DECL vec3 unpackF3x9_E1x5(uint32 p);\n\n\t/// Returns an unsigned integer vector obtained by converting the components of a floating-point vector\n\t/// to the 16-bit floating-point representation found in the OpenGL Specification.\n\t/// The first vector component specifies the 16 least-significant bits of the result;\n\t/// the forth component specifies the 16 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& p)\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb);\n\n\t/// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values.\n\t/// The first component of the vector is obtained from the 16 least-significant bits of v;\n\t/// the forth component is obtained from the 16 most-significant bits of v.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<4, T, Q> packRGBM(vec<3, float, Q> const& v)\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm);\n\n\t/// Returns an unsigned integer vector obtained by converting the components of a floating-point vector\n\t/// to the 16-bit floating-point representation found in the OpenGL Specification.\n\t/// The first vector component specifies the 16 least-significant bits of the result;\n\t/// the forth component specifies the 16 most-significant bits.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<L, float, Q> unpackHalf(vec<L, uint16, Q> const& p)\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, uint16, Q> packHalf(vec<L, float, Q> const& v);\n\n\t/// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values.\n\t/// The first component of the vector is obtained from the 16 least-significant bits of v;\n\t/// the forth component is obtained from the 16 most-significant bits of v.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<L, uint16, Q> packHalf(vec<L, float, Q> const& v)\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, float, Q> unpackHalf(vec<L, uint16, Q> const& p);\n\n\t/// Convert each component of the normalized floating-point vector into unsigned integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<L, floatType, Q> unpackUnorm(vec<L, intType, Q> const& p);\n\ttemplate<typename uintType, length_t L, typename floatType, qualifier Q>\n\tGLM_FUNC_DECL vec<L, uintType, Q> packUnorm(vec<L, floatType, Q> const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<L, intType, Q> packUnorm(vec<L, floatType, Q> const& v)\n\ttemplate<typename floatType, length_t L, typename uintType, qualifier Q>\n\tGLM_FUNC_DECL vec<L, floatType, Q> unpackUnorm(vec<L, uintType, Q> const& v);\n\n\t/// Convert each component of the normalized floating-point vector into signed integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<L, floatType, Q> unpackSnorm(vec<L, intType, Q> const& p);\n\ttemplate<typename intType, length_t L, typename floatType, qualifier Q>\n\tGLM_FUNC_DECL vec<L, intType, Q> packSnorm(vec<L, floatType, Q> const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec<L, intType, Q> packSnorm(vec<L, floatType, Q> const& v)\n\ttemplate<typename floatType, length_t L, typename intType, qualifier Q>\n\tGLM_FUNC_DECL vec<L, floatType, Q> unpackSnorm(vec<L, intType, Q> const& v);\n\n\t/// Convert each component of the normalized floating-point vector into unsigned integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec2 unpackUnorm2x4(uint8 p)\n\tGLM_FUNC_DECL uint8 packUnorm2x4(vec2 const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint8 packUnorm2x4(vec2 const& v)\n\tGLM_FUNC_DECL vec2 unpackUnorm2x4(uint8 p);\n\n\t/// Convert each component of the normalized floating-point vector into unsigned integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec4 unpackUnorm4x4(uint16 p)\n\tGLM_FUNC_DECL uint16 packUnorm4x4(vec4 const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packUnorm4x4(vec4 const& v)\n\tGLM_FUNC_DECL vec4 unpackUnorm4x4(uint16 p);\n\n\t/// Convert each component of the normalized floating-point vector into unsigned integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec3 unpackUnorm1x5_1x6_1x5(uint16 p)\n\tGLM_FUNC_DECL uint16 packUnorm1x5_1x6_1x5(vec3 const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packUnorm1x5_1x6_1x5(vec3 const& v)\n\tGLM_FUNC_DECL vec3 unpackUnorm1x5_1x6_1x5(uint16 p);\n\n\t/// Convert each component of the normalized floating-point vector into unsigned integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec4 unpackUnorm3x5_1x1(uint16 p)\n\tGLM_FUNC_DECL uint16 packUnorm3x5_1x1(vec4 const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packUnorm3x5_1x1(vec4 const& v)\n\tGLM_FUNC_DECL vec4 unpackUnorm3x5_1x1(uint16 p);\n\n\t/// Convert each component of the normalized floating-point vector into unsigned integer values.\n\t///\n\t/// @see gtc_packing\n\t/// @see vec3 unpackUnorm2x3_1x2(uint8 p)\n\tGLM_FUNC_DECL uint8 packUnorm2x3_1x2(vec3 const& v);\n\n\t/// Convert a packed integer to a normalized floating-point vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint8 packUnorm2x3_1x2(vec3 const& v)\n\tGLM_FUNC_DECL vec3 unpackUnorm2x3_1x2(uint8 p);\n\n\n\n\t/// Convert each component from an integer vector into a packed integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see i8vec2 unpackInt2x8(int16 p)\n\tGLM_FUNC_DECL int16 packInt2x8(i8vec2 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see int16 packInt2x8(i8vec2 const& v)\n\tGLM_FUNC_DECL i8vec2 unpackInt2x8(int16 p);\n\n\t/// Convert each component from an integer vector into a packed unsigned integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see u8vec2 unpackInt2x8(uint16 p)\n\tGLM_FUNC_DECL uint16 packUint2x8(u8vec2 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint16 packInt2x8(u8vec2 const& v)\n\tGLM_FUNC_DECL u8vec2 unpackUint2x8(uint16 p);\n\n\t/// Convert each component from an integer vector into a packed integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see i8vec4 unpackInt4x8(int32 p)\n\tGLM_FUNC_DECL int32 packInt4x8(i8vec4 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see int32 packInt2x8(i8vec4 const& v)\n\tGLM_FUNC_DECL i8vec4 unpackInt4x8(int32 p);\n\n\t/// Convert each component from an integer vector into a packed unsigned integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see u8vec4 unpackUint4x8(uint32 p)\n\tGLM_FUNC_DECL uint32 packUint4x8(u8vec4 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint32 packUint4x8(u8vec2 const& v)\n\tGLM_FUNC_DECL u8vec4 unpackUint4x8(uint32 p);\n\n\t/// Convert each component from an integer vector into a packed integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see i16vec2 unpackInt2x16(int p)\n\tGLM_FUNC_DECL int packInt2x16(i16vec2 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see int packInt2x16(i16vec2 const& v)\n\tGLM_FUNC_DECL i16vec2 unpackInt2x16(int p);\n\n\t/// Convert each component from an integer vector into a packed integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see i16vec4 unpackInt4x16(int64 p)\n\tGLM_FUNC_DECL int64 packInt4x16(i16vec4 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see int64 packInt4x16(i16vec4 const& v)\n\tGLM_FUNC_DECL i16vec4 unpackInt4x16(int64 p);\n\n\t/// Convert each component from an integer vector into a packed unsigned integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see u16vec2 unpackUint2x16(uint p)\n\tGLM_FUNC_DECL uint packUint2x16(u16vec2 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint packUint2x16(u16vec2 const& v)\n\tGLM_FUNC_DECL u16vec2 unpackUint2x16(uint p);\n\n\t/// Convert each component from an integer vector into a packed unsigned integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see u16vec4 unpackUint4x16(uint64 p)\n\tGLM_FUNC_DECL uint64 packUint4x16(u16vec4 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see uint64 packUint4x16(u16vec4 const& v)\n\tGLM_FUNC_DECL u16vec4 unpackUint4x16(uint64 p);\n\n\t/// Convert each component from an integer vector into a packed integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see i32vec2 unpackInt2x32(int p)\n\tGLM_FUNC_DECL int64 packInt2x32(i32vec2 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see int packInt2x16(i32vec2 const& v)\n\tGLM_FUNC_DECL i32vec2 unpackInt2x32(int64 p);\n\n\t/// Convert each component from an integer vector into a packed unsigned integer.\n\t///\n\t/// @see gtc_packing\n\t/// @see u32vec2 unpackUint2x32(int p)\n\tGLM_FUNC_DECL uint64 packUint2x32(u32vec2 const& v);\n\n\t/// Convert a packed integer into an integer vector.\n\t///\n\t/// @see gtc_packing\n\t/// @see int packUint2x16(u32vec2 const& v)\n\tGLM_FUNC_DECL u32vec2 unpackUint2x32(uint64 p);\n\n\t/// @}\n}// namespace glm\n\n#include \"packing.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/packing.inl",
    "content": "/// @ref gtc_packing\n\n#include \"../ext/scalar_relational.hpp\"\n#include \"../ext/vector_relational.hpp\"\n#include \"../common.hpp\"\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../detail/type_half.hpp\"\n#include <cstring>\n#include <limits>\n\nnamespace glm{\nnamespace detail\n{\n\tGLM_FUNC_QUALIFIER glm::uint16 float2half(glm::uint32 f)\n\t{\n\t\t// 10 bits    =>                         EE EEEFFFFF\n\t\t// 11 bits    =>                        EEE EEFFFFFF\n\t\t// Half bits  =>                   SEEEEEFF FFFFFFFF\n\t\t// Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF\n\n\t\t// 0x00007c00 => 00000000 00000000 01111100 00000000\n\t\t// 0x000003ff => 00000000 00000000 00000011 11111111\n\t\t// 0x38000000 => 00111000 00000000 00000000 00000000\n\t\t// 0x7f800000 => 01111111 10000000 00000000 00000000\n\t\t// 0x00008000 => 00000000 00000000 10000000 00000000\n\t\treturn\n\t\t\t((f >> 16) & 0x8000) | // sign\n\t\t\t((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | // exponential\n\t\t\t((f >> 13) & 0x03ff); // Mantissa\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint32 float2packed11(glm::uint32 f)\n\t{\n\t\t// 10 bits    =>                         EE EEEFFFFF\n\t\t// 11 bits    =>                        EEE EEFFFFFF\n\t\t// Half bits  =>                   SEEEEEFF FFFFFFFF\n\t\t// Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF\n\n\t\t// 0x000007c0 => 00000000 00000000 00000111 11000000\n\t\t// 0x00007c00 => 00000000 00000000 01111100 00000000\n\t\t// 0x000003ff => 00000000 00000000 00000011 11111111\n\t\t// 0x38000000 => 00111000 00000000 00000000 00000000\n\t\t// 0x7f800000 => 01111111 10000000 00000000 00000000\n\t\t// 0x00008000 => 00000000 00000000 10000000 00000000\n\t\treturn\n\t\t\t((((f & 0x7f800000) - 0x38000000) >> 17) & 0x07c0) | // exponential\n\t\t\t((f >> 17) & 0x003f); // Mantissa\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint32 packed11ToFloat(glm::uint32 p)\n\t{\n\t\t// 10 bits    =>                         EE EEEFFFFF\n\t\t// 11 bits    =>                        EEE EEFFFFFF\n\t\t// Half bits  =>                   SEEEEEFF FFFFFFFF\n\t\t// Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF\n\n\t\t// 0x000007c0 => 00000000 00000000 00000111 11000000\n\t\t// 0x00007c00 => 00000000 00000000 01111100 00000000\n\t\t// 0x000003ff => 00000000 00000000 00000011 11111111\n\t\t// 0x38000000 => 00111000 00000000 00000000 00000000\n\t\t// 0x7f800000 => 01111111 10000000 00000000 00000000\n\t\t// 0x00008000 => 00000000 00000000 10000000 00000000\n\t\treturn\n\t\t\t((((p & 0x07c0) << 17) + 0x38000000) & 0x7f800000) | // exponential\n\t\t\t((p & 0x003f) << 17); // Mantissa\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint32 float2packed10(glm::uint32 f)\n\t{\n\t\t// 10 bits    =>                         EE EEEFFFFF\n\t\t// 11 bits    =>                        EEE EEFFFFFF\n\t\t// Half bits  =>                   SEEEEEFF FFFFFFFF\n\t\t// Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF\n\n\t\t// 0x0000001F => 00000000 00000000 00000000 00011111\n\t\t// 0x0000003F => 00000000 00000000 00000000 00111111\n\t\t// 0x000003E0 => 00000000 00000000 00000011 11100000\n\t\t// 0x000007C0 => 00000000 00000000 00000111 11000000\n\t\t// 0x00007C00 => 00000000 00000000 01111100 00000000\n\t\t// 0x000003FF => 00000000 00000000 00000011 11111111\n\t\t// 0x38000000 => 00111000 00000000 00000000 00000000\n\t\t// 0x7f800000 => 01111111 10000000 00000000 00000000\n\t\t// 0x00008000 => 00000000 00000000 10000000 00000000\n\t\treturn\n\t\t\t((((f & 0x7f800000) - 0x38000000) >> 18) & 0x03E0) | // exponential\n\t\t\t((f >> 18) & 0x001f); // Mantissa\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint32 packed10ToFloat(glm::uint32 p)\n\t{\n\t\t// 10 bits    =>                         EE EEEFFFFF\n\t\t// 11 bits    =>                        EEE EEFFFFFF\n\t\t// Half bits  =>                   SEEEEEFF FFFFFFFF\n\t\t// Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF\n\n\t\t// 0x0000001F => 00000000 00000000 00000000 00011111\n\t\t// 0x0000003F => 00000000 00000000 00000000 00111111\n\t\t// 0x000003E0 => 00000000 00000000 00000011 11100000\n\t\t// 0x000007C0 => 00000000 00000000 00000111 11000000\n\t\t// 0x00007C00 => 00000000 00000000 01111100 00000000\n\t\t// 0x000003FF => 00000000 00000000 00000011 11111111\n\t\t// 0x38000000 => 00111000 00000000 00000000 00000000\n\t\t// 0x7f800000 => 01111111 10000000 00000000 00000000\n\t\t// 0x00008000 => 00000000 00000000 10000000 00000000\n\t\treturn\n\t\t\t((((p & 0x03E0) << 18) + 0x38000000) & 0x7f800000) | // exponential\n\t\t\t((p & 0x001f) << 18); // Mantissa\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint half2float(glm::uint h)\n\t{\n\t\treturn ((h & 0x8000) << 16) | ((( h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13);\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint floatTo11bit(float x)\n\t{\n\t\tif(x == 0.0f)\n\t\t\treturn 0u;\n\t\telse if(glm::isnan(x))\n\t\t\treturn ~0u;\n\t\telse if(glm::isinf(x))\n\t\t\treturn 0x1Fu << 6u;\n\n\t\tuint Pack = 0u;\n\t\tmemcpy(&Pack, &x, sizeof(Pack));\n\t\treturn float2packed11(Pack);\n\t}\n\n\tGLM_FUNC_QUALIFIER float packed11bitToFloat(glm::uint x)\n\t{\n\t\tif(x == 0)\n\t\t\treturn 0.0f;\n\t\telse if(x == ((1 << 11) - 1))\n\t\t\treturn ~0;//NaN\n\t\telse if(x == (0x1f << 6))\n\t\t\treturn ~0;//Inf\n\n\t\tuint Result = packed11ToFloat(x);\n\n\t\tfloat Temp = 0;\n\t\tmemcpy(&Temp, &Result, sizeof(Temp));\n\t\treturn Temp;\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::uint floatTo10bit(float x)\n\t{\n\t\tif(x == 0.0f)\n\t\t\treturn 0u;\n\t\telse if(glm::isnan(x))\n\t\t\treturn ~0u;\n\t\telse if(glm::isinf(x))\n\t\t\treturn 0x1Fu << 5u;\n\n\t\tuint Pack = 0;\n\t\tmemcpy(&Pack, &x, sizeof(Pack));\n\t\treturn float2packed10(Pack);\n\t}\n\n\tGLM_FUNC_QUALIFIER float packed10bitToFloat(glm::uint x)\n\t{\n\t\tif(x == 0)\n\t\t\treturn 0.0f;\n\t\telse if(x == ((1 << 10) - 1))\n\t\t\treturn ~0;//NaN\n\t\telse if(x == (0x1f << 5))\n\t\t\treturn ~0;//Inf\n\n\t\tuint Result = packed10ToFloat(x);\n\n\t\tfloat Temp = 0;\n\t\tmemcpy(&Temp, &Result, sizeof(Temp));\n\t\treturn Temp;\n\t}\n\n//\tGLM_FUNC_QUALIFIER glm::uint f11_f11_f10(float x, float y, float z)\n//\t{\n//\t\treturn ((floatTo11bit(x) & ((1 << 11) - 1)) << 0) |  ((floatTo11bit(y) & ((1 << 11) - 1)) << 11) | ((floatTo10bit(z) & ((1 << 10) - 1)) << 22);\n//\t}\n\n\tunion u3u3u2\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 3;\n\t\t\tuint y : 3;\n\t\t\tuint z : 2;\n\t\t} data;\n\t\tuint8 pack;\n\t};\n\n\tunion u4u4\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 4;\n\t\t\tuint y : 4;\n\t\t} data;\n\t\tuint8 pack;\n\t};\n\n\tunion u4u4u4u4\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 4;\n\t\t\tuint y : 4;\n\t\t\tuint z : 4;\n\t\t\tuint w : 4;\n\t\t} data;\n\t\tuint16 pack;\n\t};\n\n\tunion u5u6u5\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 5;\n\t\t\tuint y : 6;\n\t\t\tuint z : 5;\n\t\t} data;\n\t\tuint16 pack;\n\t};\n\n\tunion u5u5u5u1\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 5;\n\t\t\tuint y : 5;\n\t\t\tuint z : 5;\n\t\t\tuint w : 1;\n\t\t} data;\n\t\tuint16 pack;\n\t};\n\n\tunion u10u10u10u2\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 10;\n\t\t\tuint y : 10;\n\t\t\tuint z : 10;\n\t\t\tuint w : 2;\n\t\t} data;\n\t\tuint32 pack;\n\t};\n\n\tunion i10i10i10i2\n\t{\n\t\tstruct\n\t\t{\n\t\t\tint x : 10;\n\t\t\tint y : 10;\n\t\t\tint z : 10;\n\t\t\tint w : 2;\n\t\t} data;\n\t\tuint32 pack;\n\t};\n\n\tunion u9u9u9e5\n\t{\n\t\tstruct\n\t\t{\n\t\t\tuint x : 9;\n\t\t\tuint y : 9;\n\t\t\tuint z : 9;\n\t\t\tuint w : 5;\n\t\t} data;\n\t\tuint32 pack;\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_half\n\t{};\n\n\ttemplate<qualifier Q>\n\tstruct compute_half<1, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<1, uint16, Q> pack(vec<1, float, Q> const& v)\n\t\t{\n\t\t\tint16 const Unpack(detail::toFloat16(v.x));\n\t\t\tu16vec1 Packed;\n\t\t\tmemcpy(&Packed, &Unpack, sizeof(Packed));\n\t\t\treturn Packed;\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER static vec<1, float, Q> unpack(vec<1, uint16, Q> const& v)\n\t\t{\n\t\t\ti16vec1 Unpack;\n\t\t\tmemcpy(&Unpack, &v, sizeof(Unpack));\n\t\t\treturn vec<1, float, Q>(detail::toFloat32(v.x));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_half<2, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<2, uint16, Q> pack(vec<2, float, Q> const& v)\n\t\t{\n\t\t\tvec<2, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y));\n\t\t\tu16vec2 Packed;\n\t\t\tmemcpy(&Packed, &Unpack, sizeof(Packed));\n\t\t\treturn Packed;\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER static vec<2, float, Q> unpack(vec<2, uint16, Q> const& v)\n\t\t{\n\t\t\ti16vec2 Unpack;\n\t\t\tmemcpy(&Unpack, &v, sizeof(Unpack));\n\t\t\treturn vec<2, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_half<3, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, uint16, Q> pack(vec<3, float, Q> const& v)\n\t\t{\n\t\t\tvec<3, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z));\n\t\t\tu16vec3 Packed;\n\t\t\tmemcpy(&Packed, &Unpack, sizeof(Packed));\n\t\t\treturn Packed;\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER static vec<3, float, Q> unpack(vec<3, uint16, Q> const& v)\n\t\t{\n\t\t\ti16vec3 Unpack;\n\t\t\tmemcpy(&Unpack, &v, sizeof(Unpack));\n\t\t\treturn vec<3, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z));\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_half<4, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint16, Q> pack(vec<4, float, Q> const& v)\n\t\t{\n\t\t\tvec<4, int16, Q> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w));\n\t\t\tu16vec4 Packed;\n\t\t\tmemcpy(&Packed, &Unpack, sizeof(Packed));\n\t\t\treturn Packed;\n\t\t}\n\n\t\tGLM_FUNC_QUALIFIER static vec<4, float, Q> unpack(vec<4, uint16, Q> const& v)\n\t\t{\n\t\t\ti16vec4 Unpack;\n\t\t\tmemcpy(&Unpack, &v, sizeof(Unpack));\n\t\t\treturn vec<4, float, Q>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z), detail::toFloat32(v.w));\n\t\t}\n\t};\n}//namespace detail\n\n\tGLM_FUNC_QUALIFIER uint8 packUnorm1x8(float v)\n\t{\n\t\treturn static_cast<uint8>(round(clamp(v, 0.0f, 1.0f) * 255.0f));\n\t}\n\n\tGLM_FUNC_QUALIFIER float unpackUnorm1x8(uint8 p)\n\t{\n\t\tfloat const Unpack(p);\n\t\treturn Unpack * static_cast<float>(0.0039215686274509803921568627451); // 1 / 255\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packUnorm2x8(vec2 const& v)\n\t{\n\t\tu8vec2 const Topack(round(clamp(v, 0.0f, 1.0f) * 255.0f));\n\n\t\tuint16 Unpack = 0;\n\t\tmemcpy(&Unpack, &Topack, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec2 unpackUnorm2x8(uint16 p)\n\t{\n\t\tu8vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn vec2(Unpack) * float(0.0039215686274509803921568627451); // 1 / 255\n\t}\n\n\tGLM_FUNC_QUALIFIER uint8 packSnorm1x8(float v)\n\t{\n\t\tint8 const Topack(static_cast<int8>(round(clamp(v ,-1.0f, 1.0f) * 127.0f)));\n\t\tuint8 Packed = 0;\n\t\tmemcpy(&Packed, &Topack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER float unpackSnorm1x8(uint8 p)\n\t{\n\t\tint8 Unpack = 0;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn clamp(\n\t\t\tstatic_cast<float>(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f\n\t\t\t-1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packSnorm2x8(vec2 const& v)\n\t{\n\t\ti8vec2 const Topack(round(clamp(v, -1.0f, 1.0f) * 127.0f));\n\t\tuint16 Packed = 0;\n\t\tmemcpy(&Packed, &Topack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec2 unpackSnorm2x8(uint16 p)\n\t{\n\t\ti8vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn clamp(\n\t\t\tvec2(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f\n\t\t\t-1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packUnorm1x16(float s)\n\t{\n\t\treturn static_cast<uint16>(round(clamp(s, 0.0f, 1.0f) * 65535.0f));\n\t}\n\n\tGLM_FUNC_QUALIFIER float unpackUnorm1x16(uint16 p)\n\t{\n\t\tfloat const Unpack(p);\n\t\treturn Unpack * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 packUnorm4x16(vec4 const& v)\n\t{\n\t\tu16vec4 const Topack(round(clamp(v , 0.0f, 1.0f) * 65535.0f));\n\t\tuint64 Packed = 0;\n\t\tmemcpy(&Packed, &Topack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackUnorm4x16(uint64 p)\n\t{\n\t\tu16vec4 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn vec4(Unpack) * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packSnorm1x16(float v)\n\t{\n\t\tint16 const Topack = static_cast<int16>(round(clamp(v ,-1.0f, 1.0f) * 32767.0f));\n\t\tuint16 Packed = 0;\n\t\tmemcpy(&Packed, &Topack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER float unpackSnorm1x16(uint16 p)\n\t{\n\t\tint16 Unpack = 0;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn clamp(\n\t\t\tstatic_cast<float>(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f,\n\t\t\t-1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 packSnorm4x16(vec4 const& v)\n\t{\n\t\ti16vec4 const Topack(round(clamp(v ,-1.0f, 1.0f) * 32767.0f));\n\t\tuint64 Packed = 0;\n\t\tmemcpy(&Packed, &Topack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackSnorm4x16(uint64 p)\n\t{\n\t\ti16vec4 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn clamp(\n\t\t\tvec4(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f,\n\t\t\t-1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packHalf1x16(float v)\n\t{\n\t\tint16 const Topack(detail::toFloat16(v));\n\t\tuint16 Packed = 0;\n\t\tmemcpy(&Packed, &Topack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER float unpackHalf1x16(uint16 v)\n\t{\n\t\tint16 Unpack = 0;\n\t\tmemcpy(&Unpack, &v, sizeof(Unpack));\n\t\treturn detail::toFloat32(Unpack);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 packHalf4x16(glm::vec4 const& v)\n\t{\n\t\ti16vec4 const Unpack(\n\t\t\tdetail::toFloat16(v.x),\n\t\t\tdetail::toFloat16(v.y),\n\t\t\tdetail::toFloat16(v.z),\n\t\t\tdetail::toFloat16(v.w));\n\t\tuint64 Packed = 0;\n\t\tmemcpy(&Packed, &Unpack, sizeof(Packed));\n\t\treturn Packed;\n\t}\n\n\tGLM_FUNC_QUALIFIER glm::vec4 unpackHalf4x16(uint64 v)\n\t{\n\t\ti16vec4 Unpack;\n\t\tmemcpy(&Unpack, &v, sizeof(Unpack));\n\t\treturn vec4(\n\t\t\tdetail::toFloat32(Unpack.x),\n\t\t\tdetail::toFloat32(Unpack.y),\n\t\t\tdetail::toFloat32(Unpack.z),\n\t\t\tdetail::toFloat32(Unpack.w));\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packI3x10_1x2(ivec4 const& v)\n\t{\n\t\tdetail::i10i10i10i2 Result;\n\t\tResult.data.x = v.x;\n\t\tResult.data.y = v.y;\n\t\tResult.data.z = v.z;\n\t\tResult.data.w = v.w;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER ivec4 unpackI3x10_1x2(uint32 v)\n\t{\n\t\tdetail::i10i10i10i2 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn ivec4(\n\t\t\tUnpack.data.x,\n\t\t\tUnpack.data.y,\n\t\t\tUnpack.data.z,\n\t\t\tUnpack.data.w);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packU3x10_1x2(uvec4 const& v)\n\t{\n\t\tdetail::u10u10u10u2 Result;\n\t\tResult.data.x = v.x;\n\t\tResult.data.y = v.y;\n\t\tResult.data.z = v.z;\n\t\tResult.data.w = v.w;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER uvec4 unpackU3x10_1x2(uint32 v)\n\t{\n\t\tdetail::u10u10u10u2 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn uvec4(\n\t\t\tUnpack.data.x,\n\t\t\tUnpack.data.y,\n\t\t\tUnpack.data.z,\n\t\t\tUnpack.data.w);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const& v)\n\t{\n\t\tivec4 const Pack(round(clamp(v,-1.0f, 1.0f) * vec4(511.f, 511.f, 511.f, 1.f)));\n\n\t\tdetail::i10i10i10i2 Result;\n\t\tResult.data.x = Pack.x;\n\t\tResult.data.y = Pack.y;\n\t\tResult.data.z = Pack.z;\n\t\tResult.data.w = Pack.w;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackSnorm3x10_1x2(uint32 v)\n\t{\n\t\tdetail::i10i10i10i2 Unpack;\n\t\tUnpack.pack = v;\n\n\t\tvec4 const Result(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w);\n\n\t\treturn clamp(Result * vec4(1.f / 511.f, 1.f / 511.f, 1.f / 511.f, 1.f), -1.0f, 1.0f);\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packUnorm3x10_1x2(vec4 const& v)\n\t{\n\t\tuvec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(1023.f, 1023.f, 1023.f, 3.f)));\n\n\t\tdetail::u10u10u10u2 Result;\n\t\tResult.data.x = Unpack.x;\n\t\tResult.data.y = Unpack.y;\n\t\tResult.data.z = Unpack.z;\n\t\tResult.data.w = Unpack.w;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackUnorm3x10_1x2(uint32 v)\n\t{\n\t\tvec4 const ScaleFactors(1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 3.f);\n\n\t\tdetail::u10u10u10u2 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactors;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packF2x11_1x10(vec3 const& v)\n\t{\n\t\treturn\n\t\t\t((detail::floatTo11bit(v.x) & ((1 << 11) - 1)) <<  0) |\n\t\t\t((detail::floatTo11bit(v.y) & ((1 << 11) - 1)) << 11) |\n\t\t\t((detail::floatTo10bit(v.z) & ((1 << 10) - 1)) << 22);\n\t}\n\n\tGLM_FUNC_QUALIFIER vec3 unpackF2x11_1x10(uint32 v)\n\t{\n\t\treturn vec3(\n\t\t\tdetail::packed11bitToFloat(v >> 0),\n\t\t\tdetail::packed11bitToFloat(v >> 11),\n\t\t\tdetail::packed10bitToFloat(v >> 22));\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packF3x9_E1x5(vec3 const& v)\n\t{\n\t\tfloat const SharedExpMax = (pow(2.0f, 9.0f - 1.0f) / pow(2.0f, 9.0f)) * pow(2.0f, 31.f - 15.f);\n\t\tvec3 const Color = clamp(v, 0.0f, SharedExpMax);\n\t\tfloat const MaxColor = max(Color.x, max(Color.y, Color.z));\n\n\t\tfloat const ExpSharedP = max(-15.f - 1.f, floor(log2(MaxColor))) + 1.0f + 15.f;\n\t\tfloat const MaxShared = floor(MaxColor / pow(2.0f, (ExpSharedP - 15.f - 9.f)) + 0.5f);\n\t\tfloat const ExpShared = equal(MaxShared, pow(2.0f, 9.0f), epsilon<float>()) ? ExpSharedP + 1.0f : ExpSharedP;\n\n\t\tuvec3 const ColorComp(floor(Color / pow(2.f, (ExpShared - 15.f - 9.f)) + 0.5f));\n\n\t\tdetail::u9u9u9e5 Unpack;\n\t\tUnpack.data.x = ColorComp.x;\n\t\tUnpack.data.y = ColorComp.y;\n\t\tUnpack.data.z = ColorComp.z;\n\t\tUnpack.data.w = uint(ExpShared);\n\t\treturn Unpack.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec3 unpackF3x9_E1x5(uint32 v)\n\t{\n\t\tdetail::u9u9u9e5 Unpack;\n\t\tUnpack.pack = v;\n\n\t\treturn vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * pow(2.0f, Unpack.data.w - 15.f - 9.f);\n\t}\n\n\t// Based on Brian Karis http://graphicrants.blogspot.fr/2009/04/rgbm-color-encoding.html\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> packRGBM(vec<3, T, Q> const& rgb)\n\t{\n\t\tvec<3, T, Q> const Color(rgb * static_cast<T>(1.0 / 6.0));\n\t\tT Alpha = clamp(max(max(Color.x, Color.y), max(Color.z, static_cast<T>(1e-6))), static_cast<T>(0), static_cast<T>(1));\n\t\tAlpha = ceil(Alpha * static_cast<T>(255.0)) / static_cast<T>(255.0);\n\t\treturn vec<4, T, Q>(Color / Alpha, Alpha);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> unpackRGBM(vec<4, T, Q> const& rgbm)\n\t{\n\t\treturn vec<3, T, Q>(rgbm.x, rgbm.y, rgbm.z) * rgbm.w * static_cast<T>(6);\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, uint16, Q> packHalf(vec<L, float, Q> const& v)\n\t{\n\t\treturn detail::compute_half<L, Q>::pack(v);\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, float, Q> unpackHalf(vec<L, uint16, Q> const& v)\n\t{\n\t\treturn detail::compute_half<L, Q>::unpack(v);\n\t}\n\n\ttemplate<typename uintType, length_t L, typename floatType, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, uintType, Q> packUnorm(vec<L, floatType, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<uintType>::is_integer, \"uintType must be an integer type\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, \"floatType must be a floating point type\");\n\n\t\treturn vec<L, uintType, Q>(round(clamp(v, static_cast<floatType>(0), static_cast<floatType>(1)) * static_cast<floatType>(std::numeric_limits<uintType>::max())));\n\t}\n\n\ttemplate<typename floatType, length_t L, typename uintType, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, floatType, Q> unpackUnorm(vec<L, uintType, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<uintType>::is_integer, \"uintType must be an integer type\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, \"floatType must be a floating point type\");\n\n\t\treturn vec<L, float, Q>(v) * (static_cast<floatType>(1) / static_cast<floatType>(std::numeric_limits<uintType>::max()));\n\t}\n\n\ttemplate<typename intType, length_t L, typename floatType, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, intType, Q> packSnorm(vec<L, floatType, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<intType>::is_integer, \"uintType must be an integer type\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, \"floatType must be a floating point type\");\n\n\t\treturn vec<L, intType, Q>(round(clamp(v , static_cast<floatType>(-1), static_cast<floatType>(1)) * static_cast<floatType>(std::numeric_limits<intType>::max())));\n\t}\n\n\ttemplate<typename floatType, length_t L, typename intType, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, floatType, Q> unpackSnorm(vec<L, intType, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<intType>::is_integer, \"uintType must be an integer type\");\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, \"floatType must be a floating point type\");\n\n\t\treturn clamp(vec<L, floatType, Q>(v) * (static_cast<floatType>(1) / static_cast<floatType>(std::numeric_limits<intType>::max())), static_cast<floatType>(-1), static_cast<floatType>(1));\n\t}\n\n\tGLM_FUNC_QUALIFIER uint8 packUnorm2x4(vec2 const& v)\n\t{\n\t\tu32vec2 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f));\n\t\tdetail::u4u4 Result;\n\t\tResult.data.x = Unpack.x;\n\t\tResult.data.y = Unpack.y;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec2 unpackUnorm2x4(uint8 v)\n\t{\n\t\tfloat const ScaleFactor(1.f / 15.f);\n\t\tdetail::u4u4 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn vec2(Unpack.data.x, Unpack.data.y) * ScaleFactor;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packUnorm4x4(vec4 const& v)\n\t{\n\t\tu32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f));\n\t\tdetail::u4u4u4u4 Result;\n\t\tResult.data.x = Unpack.x;\n\t\tResult.data.y = Unpack.y;\n\t\tResult.data.z = Unpack.z;\n\t\tResult.data.w = Unpack.w;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackUnorm4x4(uint16 v)\n\t{\n\t\tfloat const ScaleFactor(1.f / 15.f);\n\t\tdetail::u4u4u4u4 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packUnorm1x5_1x6_1x5(vec3 const& v)\n\t{\n\t\tu32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(31.f, 63.f, 31.f)));\n\t\tdetail::u5u6u5 Result;\n\t\tResult.data.x = Unpack.x;\n\t\tResult.data.y = Unpack.y;\n\t\tResult.data.z = Unpack.z;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec3 unpackUnorm1x5_1x6_1x5(uint16 v)\n\t{\n\t\tvec3 const ScaleFactor(1.f / 31.f, 1.f / 63.f, 1.f / 31.f);\n\t\tdetail::u5u6u5 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packUnorm3x5_1x1(vec4 const& v)\n\t{\n\t\tu32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(31.f, 31.f, 31.f, 1.f)));\n\t\tdetail::u5u5u5u1 Result;\n\t\tResult.data.x = Unpack.x;\n\t\tResult.data.y = Unpack.y;\n\t\tResult.data.z = Unpack.z;\n\t\tResult.data.w = Unpack.w;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec4 unpackUnorm3x5_1x1(uint16 v)\n\t{\n\t\tvec4 const ScaleFactor(1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f);\n\t\tdetail::u5u5u5u1 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint8 packUnorm2x3_1x2(vec3 const& v)\n\t{\n\t\tu32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(7.f, 7.f, 3.f)));\n\t\tdetail::u3u3u2 Result;\n\t\tResult.data.x = Unpack.x;\n\t\tResult.data.y = Unpack.y;\n\t\tResult.data.z = Unpack.z;\n\t\treturn Result.pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER vec3 unpackUnorm2x3_1x2(uint8 v)\n\t{\n\t\tvec3 const ScaleFactor(1.f / 7.f, 1.f / 7.f, 1.f / 3.f);\n\t\tdetail::u3u3u2 Unpack;\n\t\tUnpack.pack = v;\n\t\treturn vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor;\n\t}\n\n\tGLM_FUNC_QUALIFIER int16 packInt2x8(i8vec2 const& v)\n\t{\n\t\tint16 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER i8vec2 unpackInt2x8(int16 p)\n\t{\n\t\ti8vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint16 packUint2x8(u8vec2 const& v)\n\t{\n\t\tuint16 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER u8vec2 unpackUint2x8(uint16 p)\n\t{\n\t\tu8vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER int32 packInt4x8(i8vec4 const& v)\n\t{\n\t\tint32 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER i8vec4 unpackInt4x8(int32 p)\n\t{\n\t\ti8vec4 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint32 packUint4x8(u8vec4 const& v)\n\t{\n\t\tuint32 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER u8vec4 unpackUint4x8(uint32 p)\n\t{\n\t\tu8vec4 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER int packInt2x16(i16vec2 const& v)\n\t{\n\t\tint Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER i16vec2 unpackInt2x16(int p)\n\t{\n\t\ti16vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 packInt4x16(i16vec4 const& v)\n\t{\n\t\tint64 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER i16vec4 unpackInt4x16(int64 p)\n\t{\n\t\ti16vec4 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint packUint2x16(u16vec2 const& v)\n\t{\n\t\tuint Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER u16vec2 unpackUint2x16(uint p)\n\t{\n\t\tu16vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 packUint4x16(u16vec4 const& v)\n\t{\n\t\tuint64 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER u16vec4 unpackUint4x16(uint64 p)\n\t{\n\t\tu16vec4 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 packInt2x32(i32vec2 const& v)\n\t{\n\t\tint64 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER i32vec2 unpackInt2x32(int64 p)\n\t{\n\t\ti32vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint64 packUint2x32(u32vec2 const& v)\n\t{\n\t\tuint64 Pack = 0;\n\t\tmemcpy(&Pack, &v, sizeof(Pack));\n\t\treturn Pack;\n\t}\n\n\tGLM_FUNC_QUALIFIER u32vec2 unpackUint2x32(uint64 p)\n\t{\n\t\tu32vec2 Unpack;\n\t\tmemcpy(&Unpack, &p, sizeof(Unpack));\n\t\treturn Unpack;\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtc/quaternion.hpp",
    "content": "/// @ref gtc_quaternion\n/// @file glm/gtc/quaternion.hpp\n///\n/// @see core (dependence)\n/// @see gtc_constants (dependence)\n///\n/// @defgroup gtc_quaternion GLM_GTC_quaternion\n/// @ingroup gtc\n///\n/// Include <glm/gtc/quaternion.hpp> to use the features of this extension.\n///\n/// Defines a templated quaternion type and several quaternion operations.\n\n#pragma once\n\n// Dependency:\n#include \"../gtc/constants.hpp\"\n#include \"../gtc/matrix_transform.hpp\"\n#include \"../ext/vector_relational.hpp\"\n#include \"../ext/quaternion_common.hpp\"\n#include \"../ext/quaternion_float.hpp\"\n#include \"../ext/quaternion_float_precision.hpp\"\n#include \"../ext/quaternion_double.hpp\"\n#include \"../ext/quaternion_double_precision.hpp\"\n#include \"../ext/quaternion_relational.hpp\"\n#include \"../ext/quaternion_geometric.hpp\"\n#include \"../ext/quaternion_trigonometric.hpp\"\n#include \"../ext/quaternion_transform.hpp\"\n#include \"../detail/type_mat3x3.hpp\"\n#include \"../detail/type_mat4x4.hpp\"\n#include \"../detail/type_vec3.hpp\"\n#include \"../detail/type_vec4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_quaternion extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_quaternion\n\t/// @{\n\n\t/// Returns euler angles, pitch as x, yaw as y, roll as z.\n\t/// The result is expressed in radians.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> eulerAngles(qua<T, Q> const& x);\n\n\t/// Returns roll value of euler angles expressed in radians.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T roll(qua<T, Q> const& x);\n\n\t/// Returns pitch value of euler angles expressed in radians.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T pitch(qua<T, Q> const& x);\n\n\t/// Returns yaw value of euler angles expressed in radians.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T yaw(qua<T, Q> const& x);\n\n\t/// Converts a quaternion to a 3 * 3 matrix.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> mat3_cast(qua<T, Q> const& x);\n\n\t/// Converts a quaternion to a 4 * 4 matrix.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> mat4_cast(qua<T, Q> const& x);\n\n\t/// Converts a pure rotation 3 * 3 matrix to a quaternion.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> quat_cast(mat<3, 3, T, Q> const& x);\n\n\t/// Converts a pure rotation 4 * 4 matrix to a quaternion.\n\t///\n\t/// @tparam T Floating-point scalar types.\n\t///\n\t/// @see gtc_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> quat_cast(mat<4, 4, T, Q> const& x);\n\n\t/// Returns the component-wise comparison result of x < y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_relational\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> lessThan(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x <= y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_relational\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> lessThanEqual(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x > y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_relational\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> greaterThan(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x >= y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_quaternion_relational\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, bool, Q> greaterThanEqual(qua<T, Q> const& x, qua<T, Q> const& y);\n\n\t/// Build a look at quaternion based on the default handedness.\n\t///\n\t/// @param direction Desired forward direction. Needs to be normalized.\n\t/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> quatLookAt(\n\t\tvec<3, T, Q> const& direction,\n\t\tvec<3, T, Q> const& up);\n\n\t/// Build a right-handed look at quaternion.\n\t///\n\t/// @param direction Desired forward direction onto which the -z-axis gets mapped. Needs to be normalized.\n\t/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> quatLookAtRH(\n\t\tvec<3, T, Q> const& direction,\n\t\tvec<3, T, Q> const& up);\n\n\t/// Build a left-handed look at quaternion.\n\t///\n\t/// @param direction Desired forward direction onto which the +z-axis gets mapped. Needs to be normalized.\n\t/// @param up Up vector, how the camera is oriented. Typically (0, 1, 0).\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> quatLookAtLH(\n\t\tvec<3, T, Q> const& direction,\n\t\tvec<3, T, Q> const& up);\n\t/// @}\n} //namespace glm\n\n#include \"quaternion.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/quaternion.inl",
    "content": "#include \"../trigonometric.hpp\"\n#include \"../geometric.hpp\"\n#include \"../exponential.hpp\"\n#include \"epsilon.hpp\"\n#include <limits>\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> eulerAngles(qua<T, Q> const& x)\n\t{\n\t\treturn vec<3, T, Q>(pitch(x), yaw(x), roll(x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T roll(qua<T, Q> const& q)\n\t{\n\t\treturn static_cast<T>(atan(static_cast<T>(2) * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T pitch(qua<T, Q> const& q)\n\t{\n\t\t//return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z));\n\t\tT const y = static_cast<T>(2) * (q.y * q.z + q.w * q.x);\n\t\tT const x = q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z;\n\n\t\tif(all(equal(vec<2, T, Q>(x, y), vec<2, T, Q>(0), epsilon<T>()))) //avoid atan2(0,0) - handle singularity - Matiis\n\t\t\treturn static_cast<T>(static_cast<T>(2) * atan(q.x, q.w));\n\n\t\treturn static_cast<T>(atan(y, x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T yaw(qua<T, Q> const& q)\n\t{\n\t\treturn asin(clamp(static_cast<T>(-2) * (q.x * q.z - q.w * q.y), static_cast<T>(-1), static_cast<T>(1)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> mat3_cast(qua<T, Q> const& q)\n\t{\n\t\tmat<3, 3, T, Q> Result(T(1));\n\t\tT qxx(q.x * q.x);\n\t\tT qyy(q.y * q.y);\n\t\tT qzz(q.z * q.z);\n\t\tT qxz(q.x * q.z);\n\t\tT qxy(q.x * q.y);\n\t\tT qyz(q.y * q.z);\n\t\tT qwx(q.w * q.x);\n\t\tT qwy(q.w * q.y);\n\t\tT qwz(q.w * q.z);\n\n\t\tResult[0][0] = T(1) - T(2) * (qyy +  qzz);\n\t\tResult[0][1] = T(2) * (qxy + qwz);\n\t\tResult[0][2] = T(2) * (qxz - qwy);\n\n\t\tResult[1][0] = T(2) * (qxy - qwz);\n\t\tResult[1][1] = T(1) - T(2) * (qxx +  qzz);\n\t\tResult[1][2] = T(2) * (qyz + qwx);\n\n\t\tResult[2][0] = T(2) * (qxz + qwy);\n\t\tResult[2][1] = T(2) * (qyz - qwx);\n\t\tResult[2][2] = T(1) - T(2) * (qxx +  qyy);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> mat4_cast(qua<T, Q> const& q)\n\t{\n\t\treturn mat<4, 4, T, Q>(mat3_cast(q));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> quat_cast(mat<3, 3, T, Q> const& m)\n\t{\n\t\tT fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2];\n\t\tT fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2];\n\t\tT fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1];\n\t\tT fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2];\n\n\t\tint biggestIndex = 0;\n\t\tT fourBiggestSquaredMinus1 = fourWSquaredMinus1;\n\t\tif(fourXSquaredMinus1 > fourBiggestSquaredMinus1)\n\t\t{\n\t\t\tfourBiggestSquaredMinus1 = fourXSquaredMinus1;\n\t\t\tbiggestIndex = 1;\n\t\t}\n\t\tif(fourYSquaredMinus1 > fourBiggestSquaredMinus1)\n\t\t{\n\t\t\tfourBiggestSquaredMinus1 = fourYSquaredMinus1;\n\t\t\tbiggestIndex = 2;\n\t\t}\n\t\tif(fourZSquaredMinus1 > fourBiggestSquaredMinus1)\n\t\t{\n\t\t\tfourBiggestSquaredMinus1 = fourZSquaredMinus1;\n\t\t\tbiggestIndex = 3;\n\t\t}\n\n\t\tT biggestVal = sqrt(fourBiggestSquaredMinus1 + static_cast<T>(1)) * static_cast<T>(0.5);\n\t\tT mult = static_cast<T>(0.25) / biggestVal;\n\n\t\tswitch(biggestIndex)\n\t\t{\n\t\tcase 0:\n\t\t\treturn qua<T, Q>(biggestVal, (m[1][2] - m[2][1]) * mult, (m[2][0] - m[0][2]) * mult, (m[0][1] - m[1][0]) * mult);\n\t\tcase 1:\n\t\t\treturn qua<T, Q>((m[1][2] - m[2][1]) * mult, biggestVal, (m[0][1] + m[1][0]) * mult, (m[2][0] + m[0][2]) * mult);\n\t\tcase 2:\n\t\t\treturn qua<T, Q>((m[2][0] - m[0][2]) * mult, (m[0][1] + m[1][0]) * mult, biggestVal, (m[1][2] + m[2][1]) * mult);\n\t\tcase 3:\n\t\t\treturn qua<T, Q>((m[0][1] - m[1][0]) * mult, (m[2][0] + m[0][2]) * mult, (m[1][2] + m[2][1]) * mult, biggestVal);\n\t\tdefault: // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity.\n\t\t\tassert(false);\n\t\t\treturn qua<T, Q>(1, 0, 0, 0);\n\t\t}\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> quat_cast(mat<4, 4, T, Q> const& m4)\n\t{\n\t\treturn quat_cast(mat<3, 3, T, Q>(m4));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> lessThan(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tvec<4, bool, Q> Result;\n\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\tResult[i] = x[i] < y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> lessThanEqual(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tvec<4, bool, Q> Result;\n\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\tResult[i] = x[i] <= y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThan(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tvec<4, bool, Q> Result;\n\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\tResult[i] = x[i] > y[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> greaterThanEqual(qua<T, Q> const& x, qua<T, Q> const& y)\n\t{\n\t\tvec<4, bool, Q> Result;\n\t\tfor(length_t i = 0; i < x.length(); ++i)\n\t\t\tResult[i] = x[i] >= y[i];\n\t\treturn Result;\n\t}\n\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> quatLookAt(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)\n\t{\n#\t\tif GLM_CONFIG_CLIP_CONTROL & GLM_CLIP_CONTROL_LH_BIT\n\t\t\treturn quatLookAtLH(direction, up);\n#\t\telse\n\t\t\treturn quatLookAtRH(direction, up);\n# \t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> quatLookAtRH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)\n\t{\n\t\tmat<3, 3, T, Q> Result;\n\n\t\tResult[2] = -direction;\n\t\tvec<3, T, Q> const& Right = cross(up, Result[2]);\n\t\tResult[0] = Right * inversesqrt(max(static_cast<T>(0.00001), dot(Right, Right)));\n\t\tResult[1] = cross(Result[2], Result[0]);\n\n\t\treturn quat_cast(Result);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> quatLookAtLH(vec<3, T, Q> const& direction, vec<3, T, Q> const& up)\n\t{\n\t\tmat<3, 3, T, Q> Result;\n\n\t\tResult[2] = direction;\n\t\tvec<3, T, Q> const& Right = cross(up, Result[2]);\n\t\tResult[0] = Right * inversesqrt(max(static_cast<T>(0.00001), dot(Right, Right)));\n\t\tResult[1] = cross(Result[2], Result[0]);\n\n\t\treturn quat_cast(Result);\n\t}\n}//namespace glm\n\n#if GLM_CONFIG_SIMD == GLM_ENABLE\n#\tinclude \"quaternion_simd.inl\"\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/gtc/quaternion_simd.inl",
    "content": ""
  },
  {
    "path": "lib/gli/glm/gtc/random.hpp",
    "content": "/// @ref gtc_random\n/// @file glm/gtc/random.hpp\n///\n/// @see core (dependence)\n/// @see gtx_random (extended)\n///\n/// @defgroup gtc_random GLM_GTC_random\n/// @ingroup gtc\n///\n/// Include <glm/gtc/random.hpp> to use the features of this extension.\n///\n/// Generate random number from various distribution methods.\n\n#pragma once\n\n// Dependency:\n#include \"../ext/scalar_int_sized.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_random extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_random\n\t/// @{\n\n\t/// Generate random numbers in the interval [Min, Max], according a linear distribution\n\t///\n\t/// @param Min Minimum value included in the sampling\n\t/// @param Max Maximum value included in the sampling\n\t/// @tparam genType Value type. Currently supported: float or double scalars.\n\t/// @see gtc_random\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType linearRand(genType Min, genType Max);\n\n\t/// Generate random numbers in the interval [Min, Max], according a linear distribution\n\t///\n\t/// @param Min Minimum value included in the sampling\n\t/// @param Max Maximum value included in the sampling\n\t/// @tparam T Value type. Currently supported: float or double.\n\t///\n\t/// @see gtc_random\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> linearRand(vec<L, T, Q> const& Min, vec<L, T, Q> const& Max);\n\n\t/// Generate random numbers in the interval [Min, Max], according a gaussian distribution\n\t///\n\t/// @see gtc_random\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType gaussRand(genType Mean, genType Deviation);\n\n\t/// Generate a random 2D vector which coordinates are regulary distributed on a circle of a given radius\n\t///\n\t/// @see gtc_random\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<2, T, defaultp> circularRand(T Radius);\n\n\t/// Generate a random 3D vector which coordinates are regulary distributed on a sphere of a given radius\n\t///\n\t/// @see gtc_random\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<3, T, defaultp> sphericalRand(T Radius);\n\n\t/// Generate a random 2D vector which coordinates are regulary distributed within the area of a disk of a given radius\n\t///\n\t/// @see gtc_random\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<2, T, defaultp> diskRand(T Radius);\n\n\t/// Generate a random 3D vector which coordinates are regulary distributed within the volume of a ball of a given radius\n\t///\n\t/// @see gtc_random\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<3, T, defaultp> ballRand(T Radius);\n\n\t/// @}\n}//namespace glm\n\n#include \"random.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/random.inl",
    "content": "#include \"../geometric.hpp\"\n#include \"../exponential.hpp\"\n#include \"../trigonometric.hpp\"\n#include \"../detail/type_vec1.hpp\"\n#include <cstdlib>\n#include <ctime>\n#include <cassert>\n#include <cmath>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate <length_t L, typename T, qualifier Q>\n\tstruct compute_rand\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call();\n\t};\n\n\ttemplate <qualifier P>\n\tstruct compute_rand<1, uint8, P>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<1, uint8, P> call()\n\t\t{\n\t\t\treturn vec<1, uint8, P>(\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max());\n\t\t}\n\t};\n\n\ttemplate <qualifier P>\n\tstruct compute_rand<2, uint8, P>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<2, uint8, P> call()\n\t\t{\n\t\t\treturn vec<2, uint8, P>(\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max(),\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max());\n\t\t}\n\t};\n\n\ttemplate <qualifier P>\n\tstruct compute_rand<3, uint8, P>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, uint8, P> call()\n\t\t{\n\t\t\treturn vec<3, uint8, P>(\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max(),\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max(),\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max());\n\t\t}\n\t};\n\n\ttemplate <qualifier P>\n\tstruct compute_rand<4, uint8, P>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, uint8, P> call()\n\t\t{\n\t\t\treturn vec<4, uint8, P>(\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max(),\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max(),\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max(),\n\t\t\t\tstd::rand() % std::numeric_limits<uint8>::max());\n\t\t}\n\t};\n\n\ttemplate <length_t L, qualifier Q>\n\tstruct compute_rand<L, uint16, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint16, Q> call()\n\t\t{\n\t\t\treturn\n\t\t\t\t(vec<L, uint16, Q>(compute_rand<L, uint8, Q>::call()) << static_cast<uint16>(8)) |\n\t\t\t\t(vec<L, uint16, Q>(compute_rand<L, uint8, Q>::call()) << static_cast<uint16>(0));\n\t\t}\n\t};\n\n\ttemplate <length_t L, qualifier Q>\n\tstruct compute_rand<L, uint32, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint32, Q> call()\n\t\t{\n\t\t\treturn\n\t\t\t\t(vec<L, uint32, Q>(compute_rand<L, uint16, Q>::call()) << static_cast<uint32>(16)) |\n\t\t\t\t(vec<L, uint32, Q>(compute_rand<L, uint16, Q>::call()) << static_cast<uint32>(0));\n\t\t}\n\t};\n\n\ttemplate <length_t L, qualifier Q>\n\tstruct compute_rand<L, uint64, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint64, Q> call()\n\t\t{\n\t\t\treturn\n\t\t\t\t(vec<L, uint64, Q>(compute_rand<L, uint32, Q>::call()) << static_cast<uint64>(32)) |\n\t\t\t\t(vec<L, uint64, Q>(compute_rand<L, uint32, Q>::call()) << static_cast<uint64>(0));\n\t\t}\n\t};\n\n\ttemplate <length_t L, typename T, qualifier Q>\n\tstruct compute_linearRand\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& Min, vec<L, T, Q> const& Max);\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, int8, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, int8, Q> call(vec<L, int8, Q> const& Min, vec<L, int8, Q> const& Max)\n\t\t{\n\t\t\treturn (vec<L, int8, Q>(compute_rand<L, uint8, Q>::call() % vec<L, uint8, Q>(Max + static_cast<int8>(1) - Min))) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, uint8, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint8, Q> call(vec<L, uint8, Q> const& Min, vec<L, uint8, Q> const& Max)\n\t\t{\n\t\t\treturn (compute_rand<L, uint8, Q>::call() % (Max + static_cast<uint8>(1) - Min)) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, int16, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, int16, Q> call(vec<L, int16, Q> const& Min, vec<L, int16, Q> const& Max)\n\t\t{\n\t\t\treturn (vec<L, int16, Q>(compute_rand<L, uint16, Q>::call() % vec<L, uint16, Q>(Max + static_cast<int16>(1) - Min))) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, uint16, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint16, Q> call(vec<L, uint16, Q> const& Min, vec<L, uint16, Q> const& Max)\n\t\t{\n\t\t\treturn (compute_rand<L, uint16, Q>::call() % (Max + static_cast<uint16>(1) - Min)) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, int32, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, int32, Q> call(vec<L, int32, Q> const& Min, vec<L, int32, Q> const& Max)\n\t\t{\n\t\t\treturn (vec<L, int32, Q>(compute_rand<L, uint32, Q>::call() % vec<L, uint32, Q>(Max + static_cast<int32>(1) - Min))) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, uint32, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint32, Q> call(vec<L, uint32, Q> const& Min, vec<L, uint32, Q> const& Max)\n\t\t{\n\t\t\treturn (compute_rand<L, uint32, Q>::call() % (Max + static_cast<uint32>(1) - Min)) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, int64, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, int64, Q> call(vec<L, int64, Q> const& Min, vec<L, int64, Q> const& Max)\n\t\t{\n\t\t\treturn (vec<L, int64, Q>(compute_rand<L, uint64, Q>::call() % vec<L, uint64, Q>(Max + static_cast<int64>(1) - Min))) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, uint64, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, uint64, Q> call(vec<L, uint64, Q> const& Min, vec<L, uint64, Q> const& Max)\n\t\t{\n\t\t\treturn (compute_rand<L, uint64, Q>::call() % (Max + static_cast<uint64>(1) - Min)) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, float, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, float, Q> call(vec<L, float, Q> const& Min, vec<L, float, Q> const& Max)\n\t\t{\n\t\t\treturn vec<L, float, Q>(compute_rand<L, uint32, Q>::call()) / static_cast<float>(std::numeric_limits<uint32>::max()) * (Max - Min) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, double, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, double, Q> call(vec<L, double, Q> const& Min, vec<L, double, Q> const& Max)\n\t\t{\n\t\t\treturn vec<L, double, Q>(compute_rand<L, uint64, Q>::call()) / static_cast<double>(std::numeric_limits<uint64>::max()) * (Max - Min) + Min;\n\t\t}\n\t};\n\n\ttemplate<length_t L, qualifier Q>\n\tstruct compute_linearRand<L, long double, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, long double, Q> call(vec<L, long double, Q> const& Min, vec<L, long double, Q> const& Max)\n\t\t{\n\t\t\treturn vec<L, long double, Q>(compute_rand<L, uint64, Q>::call()) / static_cast<long double>(std::numeric_limits<uint64>::max()) * (Max - Min) + Min;\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType linearRand(genType Min, genType Max)\n\t{\n\t\treturn detail::compute_linearRand<1, genType, highp>::call(\n\t\t\tvec<1, genType, highp>(Min),\n\t\t\tvec<1, genType, highp>(Max)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> linearRand(vec<L, T, Q> const& Min, vec<L, T, Q> const& Max)\n\t{\n\t\treturn detail::compute_linearRand<L, T, Q>::call(Min, Max);\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType gaussRand(genType Mean, genType Deviation)\n\t{\n\t\tgenType w, x1, x2;\n\n\t\tdo\n\t\t{\n\t\t\tx1 = linearRand(genType(-1), genType(1));\n\t\t\tx2 = linearRand(genType(-1), genType(1));\n\n\t\t\tw = x1 * x1 + x2 * x2;\n\t\t} while(w > genType(1));\n\n\t\treturn static_cast<genType>(x2 * Deviation * Deviation * sqrt((genType(-2) * log(w)) / w) + Mean);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> gaussRand(vec<L, T, Q> const& Mean, vec<L, T, Q> const& Deviation)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(gaussRand, Mean, Deviation);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<2, T, defaultp> diskRand(T Radius)\n\t{\n\t\tassert(Radius > static_cast<T>(0));\n\n\t\tvec<2, T, defaultp> Result(T(0));\n\t\tT LenRadius(T(0));\n\n\t\tdo\n\t\t{\n\t\t\tResult = linearRand(\n\t\t\t\tvec<2, T, defaultp>(-Radius),\n\t\t\t\tvec<2, T, defaultp>(Radius));\n\t\t\tLenRadius = length(Result);\n\t\t}\n\t\twhile(LenRadius > Radius);\n\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<3, T, defaultp> ballRand(T Radius)\n\t{\n\t\tassert(Radius > static_cast<T>(0));\n\n\t\tvec<3, T, defaultp> Result(T(0));\n\t\tT LenRadius(T(0));\n\n\t\tdo\n\t\t{\n\t\t\tResult = linearRand(\n\t\t\t\tvec<3, T, defaultp>(-Radius),\n\t\t\t\tvec<3, T, defaultp>(Radius));\n\t\t\tLenRadius = length(Result);\n\t\t}\n\t\twhile(LenRadius > Radius);\n\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<2, T, defaultp> circularRand(T Radius)\n\t{\n\t\tassert(Radius > static_cast<T>(0));\n\n\t\tT a = linearRand(T(0), static_cast<T>(6.283185307179586476925286766559));\n\t\treturn vec<2, T, defaultp>(glm::cos(a), glm::sin(a)) * Radius;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<3, T, defaultp> sphericalRand(T Radius)\n\t{\n\t\tassert(Radius > static_cast<T>(0));\n\n\t\tT theta = linearRand(T(0), T(6.283185307179586476925286766559f));\n\t\tT phi = std::acos(linearRand(T(-1.0f), T(1.0f)));\n\n\t\tT x = std::sin(phi) * std::cos(theta);\n\t\tT y = std::sin(phi) * std::sin(theta);\n\t\tT z = std::cos(phi);\n\n\t\treturn vec<3, T, defaultp>(x, y, z) * Radius;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/reciprocal.hpp",
    "content": "/// @ref gtc_reciprocal\n/// @file glm/gtc/reciprocal.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_reciprocal GLM_GTC_reciprocal\n/// @ingroup gtc\n///\n/// Include <glm/gtc/reciprocal.hpp> to use the features of this extension.\n///\n/// Define secant, cosecant and cotangent functions.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_reciprocal extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_reciprocal\n\t/// @{\n\n\t/// Secant function.\n\t/// hypotenuse / adjacent or 1 / cos(x)\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType sec(genType angle);\n\n\t/// Cosecant function.\n\t/// hypotenuse / opposite or 1 / sin(x)\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType csc(genType angle);\n\n\t/// Cotangent function.\n\t/// adjacent / opposite or 1 / tan(x)\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType cot(genType angle);\n\n\t/// Inverse secant function.\n\t///\n\t/// @return Return an angle expressed in radians.\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType asec(genType x);\n\n\t/// Inverse cosecant function.\n\t///\n\t/// @return Return an angle expressed in radians.\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType acsc(genType x);\n\n\t/// Inverse cotangent function.\n\t///\n\t/// @return Return an angle expressed in radians.\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType acot(genType x);\n\n\t/// Secant hyperbolic function.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType sech(genType angle);\n\n\t/// Cosecant hyperbolic function.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType csch(genType angle);\n\n\t/// Cotangent hyperbolic function.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType coth(genType angle);\n\n\t/// Inverse secant hyperbolic function.\n\t///\n\t/// @return Return an angle expressed in radians.\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType asech(genType x);\n\n\t/// Inverse cosecant hyperbolic function.\n\t///\n\t/// @return Return an angle expressed in radians.\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType acsch(genType x);\n\n\t/// Inverse cotangent hyperbolic function.\n\t///\n\t/// @return Return an angle expressed in radians.\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see gtc_reciprocal\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType acoth(genType x);\n\n\t/// @}\n}//namespace glm\n\n#include \"reciprocal.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/reciprocal.inl",
    "content": "/// @ref gtc_reciprocal\n\n#include \"../trigonometric.hpp\"\n#include <limits>\n\nnamespace glm\n{\n\t// sec\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType sec(genType angle)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'sec' only accept floating-point values\");\n\t\treturn genType(1) / glm::cos(angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> sec(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'sec' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(sec, x);\n\t}\n\n\t// csc\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType csc(genType angle)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'csc' only accept floating-point values\");\n\t\treturn genType(1) / glm::sin(angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> csc(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'csc' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(csc, x);\n\t}\n\n\t// cot\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType cot(genType angle)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'cot' only accept floating-point values\");\n\n\t\tgenType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0);\n\t\treturn glm::tan(pi_over_2 - angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> cot(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'cot' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(cot, x);\n\t}\n\n\t// asec\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType asec(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'asec' only accept floating-point values\");\n\t\treturn acos(genType(1) / x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> asec(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'asec' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(asec, x);\n\t}\n\n\t// acsc\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType acsc(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'acsc' only accept floating-point values\");\n\t\treturn asin(genType(1) / x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> acsc(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'acsc' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(acsc, x);\n\t}\n\n\t// acot\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType acot(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'acot' only accept floating-point values\");\n\n\t\tgenType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0);\n\t\treturn pi_over_2 - atan(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> acot(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'acot' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(acot, x);\n\t}\n\n\t// sech\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType sech(genType angle)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'sech' only accept floating-point values\");\n\t\treturn genType(1) / glm::cosh(angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> sech(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'sech' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(sech, x);\n\t}\n\n\t// csch\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType csch(genType angle)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'csch' only accept floating-point values\");\n\t\treturn genType(1) / glm::sinh(angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> csch(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'csch' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(csch, x);\n\t}\n\n\t// coth\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType coth(genType angle)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'coth' only accept floating-point values\");\n\t\treturn glm::cosh(angle) / glm::sinh(angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> coth(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'coth' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(coth, x);\n\t}\n\n\t// asech\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType asech(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'asech' only accept floating-point values\");\n\t\treturn acosh(genType(1) / x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> asech(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'asech' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(asech, x);\n\t}\n\n\t// acsch\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType acsch(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'acsch' only accept floating-point values\");\n\t\treturn asinh(genType(1) / x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> acsch(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'acsch' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(acsch, x);\n\t}\n\n\t// acoth\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType acoth(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'acoth' only accept floating-point values\");\n\t\treturn atanh(genType(1) / x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> acoth(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'acoth' only accept floating-point inputs\");\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(acoth, x);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/round.hpp",
    "content": "/// @ref gtc_round\n/// @file glm/gtc/round.hpp\n///\n/// @see core (dependence)\n/// @see gtc_round (dependence)\n///\n/// @defgroup gtc_round GLM_GTC_round\n/// @ingroup gtc\n///\n/// Include <glm/gtc/round.hpp> to use the features of this extension.\n///\n/// Rounding value to specific boundings\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_vectorize.hpp\"\n#include \"../vector_relational.hpp\"\n#include \"../common.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_round extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_round\n\t/// @{\n\n\t/// Return the power of two number which value is just higher the input value,\n\t/// round up to a power of two.\n\t///\n\t/// @see gtc_round\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType v);\n\n\t/// Return the power of two number which value is just higher the input value,\n\t/// round up to a power of two.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_round\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> ceilPowerOfTwo(vec<L, T, Q> const& v);\n\n\t/// Return the power of two number which value is just lower the input value,\n\t/// round down to a power of two.\n\t///\n\t/// @see gtc_round\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType v);\n\n\t/// Return the power of two number which value is just lower the input value,\n\t/// round down to a power of two.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_round\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> floorPowerOfTwo(vec<L, T, Q> const& v);\n\n\t/// Return the power of two number which value is the closet to the input value.\n\t///\n\t/// @see gtc_round\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType v);\n\n\t/// Return the power of two number which value is the closet to the input value.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_round\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> roundPowerOfTwo(vec<L, T, Q> const& v);\n\n\t/// Higher multiple number of Source.\n\t///\n\t/// @tparam genType Floating-point or integer scalar or vector types.\n\t///\n\t/// @param v Source value to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see gtc_round\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType ceilMultiple(genType v, genType Multiple);\n\n\t/// Higher multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see gtc_round\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> ceilMultiple(vec<L, T, Q> const& v, vec<L, T, Q> const& Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam genType Floating-point or integer scalar or vector types.\n\t///\n\t/// @param v Source value to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see gtc_round\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType floorMultiple(genType v, genType Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see gtc_round\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> floorMultiple(vec<L, T, Q> const& v, vec<L, T, Q> const& Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam genType Floating-point or integer scalar or vector types.\n\t///\n\t/// @param v Source value to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see gtc_round\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType roundMultiple(genType v, genType Multiple);\n\n\t/// Lower multiple number of Source.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @param v Source values to which is applied the function\n\t/// @param Multiple Must be a null or positive value\n\t///\n\t/// @see gtc_round\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> roundMultiple(vec<L, T, Q> const& v, vec<L, T, Q> const& Multiple);\n\n\t/// @}\n} //namespace glm\n\n#include \"round.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/round.inl",
    "content": "/// @ref gtc_round\n\n#include \"../integer.hpp\"\n#include \"../ext/vector_integer.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<bool is_float, bool is_signed>\n\tstruct compute_roundMultiple {};\n\n\ttemplate<>\n\tstruct compute_roundMultiple<true, true>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif (Source >= genType(0))\n\t\t\t\treturn Source - std::fmod(Source, Multiple);\n\t\t\telse\n\t\t\t{\n\t\t\t\tgenType Tmp = Source + genType(1);\n\t\t\t\treturn Tmp - std::fmod(Tmp, Multiple) - Multiple;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct compute_roundMultiple<false, false>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif (Source >= genType(0))\n\t\t\t\treturn Source - Source % Multiple;\n\t\t\telse\n\t\t\t{\n\t\t\t\tgenType Tmp = Source + genType(1);\n\t\t\t\treturn Tmp - Tmp % Multiple - Multiple;\n\t\t\t}\n\t\t}\n\t};\n\n\ttemplate<>\n\tstruct compute_roundMultiple<false, true>\n\t{\n\t\ttemplate<typename genType>\n\t\tGLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)\n\t\t{\n\t\t\tif (Source >= genType(0))\n\t\t\t\treturn Source - Source % Multiple;\n\t\t\telse\n\t\t\t{\n\t\t\t\tgenType Tmp = Source + genType(1);\n\t\t\t\treturn Tmp - Tmp % Multiple - Multiple;\n\t\t\t}\n\t\t}\n\t};\n}//namespace detail\n\n\t//////////////////\n\t// ceilPowerOfTwo\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value)\n\t{\n\t\treturn detail::compute_ceilPowerOfTwo<1, genType, defaultp, std::numeric_limits<genType>::is_signed>::call(vec<1, genType, defaultp>(value)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> ceilPowerOfTwo(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::compute_ceilPowerOfTwo<L, T, Q, std::numeric_limits<T>::is_signed>::call(v);\n\t}\n\n\t///////////////////\n\t// floorPowerOfTwo\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value)\n\t{\n\t\treturn isPowerOfTwo(value) ? value : static_cast<genType>(1) << findMSB(value);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> floorPowerOfTwo(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(floorPowerOfTwo, v);\n\t}\n\n\t///////////////////\n\t// roundPowerOfTwo\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value)\n\t{\n\t\tif(isPowerOfTwo(value))\n\t\t\treturn value;\n\n\t\tgenIUType const prev = static_cast<genIUType>(1) << findMSB(value);\n\t\tgenIUType const next = prev << static_cast<genIUType>(1);\n\t\treturn (next - value) < (value - prev) ? next : prev;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> roundPowerOfTwo(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(roundPowerOfTwo, v);\n\t}\n\n\t//////////////////////\n\t// ceilMultiple\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple)\n\t{\n\t\treturn detail::compute_ceilMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> ceilMultiple(vec<L, T, Q> const& Source, vec<L, T, Q> const& Multiple)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(ceilMultiple, Source, Multiple);\n\t}\n\n\t//////////////////////\n\t// floorMultiple\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple)\n\t{\n\t\treturn detail::compute_floorMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> floorMultiple(vec<L, T, Q> const& Source, vec<L, T, Q> const& Multiple)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(floorMultiple, Source, Multiple);\n\t}\n\n\t//////////////////////\n\t// roundMultiple\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple)\n\t{\n\t\treturn detail::compute_roundMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> roundMultiple(vec<L, T, Q> const& Source, vec<L, T, Q> const& Multiple)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(roundMultiple, Source, Multiple);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/type_aligned.hpp",
    "content": "/// @ref gtc_type_aligned\n/// @file glm/gtc/type_aligned.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_type_aligned GLM_GTC_type_aligned\n/// @ingroup gtc\n///\n/// Include <glm/gtc/type_aligned.hpp> to use the features of this extension.\n///\n/// Aligned types allowing SIMD optimizations of vectors and matrices types\n\n#pragma once\n\n#if (GLM_CONFIG_ALIGNED_GENTYPES == GLM_DISABLE)\n#\terror \"GLM: Aligned gentypes require to enable C++ language extensions. Define GLM_FORCE_ALIGNED_GENTYPES before including GLM headers to use aligned types.\"\n#endif\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n# pragma message(\"GLM: GLM_GTC_type_aligned extension included\")\n#endif\n\n#include \"../mat4x4.hpp\"\n#include \"../mat4x3.hpp\"\n#include \"../mat4x2.hpp\"\n#include \"../mat3x4.hpp\"\n#include \"../mat3x3.hpp\"\n#include \"../mat3x2.hpp\"\n#include \"../mat2x4.hpp\"\n#include \"../mat2x3.hpp\"\n#include \"../mat2x2.hpp\"\n#include \"../gtc/vec1.hpp\"\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup gtc_type_aligned\n\t/// @{\n\n\t// -- *vec1 --\n\n\t/// 1 component vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, aligned_highp>\taligned_highp_vec1;\n\n\t/// 1 component vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, aligned_mediump>\taligned_mediump_vec1;\n\n\t/// 1 component vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, aligned_lowp>\t\taligned_lowp_vec1;\n\n\t/// 1 component vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, aligned_highp>\taligned_highp_dvec1;\n\n\t/// 1 component vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, aligned_mediump>\taligned_mediump_dvec1;\n\n\t/// 1 component vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, aligned_lowp>\taligned_lowp_dvec1;\n\n\t/// 1 component vector aligned in memory of signed integer numbers.\n\ttypedef vec<1, int, aligned_highp>\t\taligned_highp_ivec1;\n\n\t/// 1 component vector aligned in memory of signed integer numbers.\n\ttypedef vec<1, int, aligned_mediump>\taligned_mediump_ivec1;\n\n\t/// 1 component vector aligned in memory of signed integer numbers.\n\ttypedef vec<1, int, aligned_lowp>\t\taligned_lowp_ivec1;\n\n\t/// 1 component vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<1, uint, aligned_highp>\t\taligned_highp_uvec1;\n\n\t/// 1 component vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<1, uint, aligned_mediump>\taligned_mediump_uvec1;\n\n\t/// 1 component vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<1, uint, aligned_lowp>\t\taligned_lowp_uvec1;\n\n\t/// 1 component vector aligned in memory of bool values.\n\ttypedef vec<1, bool, aligned_highp>\t\taligned_highp_bvec1;\n\n\t/// 1 component vector aligned in memory of bool values.\n\ttypedef vec<1, bool, aligned_mediump>\taligned_mediump_bvec1;\n\n\t/// 1 component vector aligned in memory of bool values.\n\ttypedef vec<1, bool, aligned_lowp>\t\taligned_lowp_bvec1;\n\n\t/// 1 component vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, packed_highp>\t\tpacked_highp_vec1;\n\n\t/// 1 component vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, packed_mediump>\tpacked_mediump_vec1;\n\n\t/// 1 component vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<1, float, packed_lowp>\t\tpacked_lowp_vec1;\n\n\t/// 1 component vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, packed_highp>\tpacked_highp_dvec1;\n\n\t/// 1 component vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, packed_mediump>\tpacked_mediump_dvec1;\n\n\t/// 1 component vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<1, double, packed_lowp>\t\tpacked_lowp_dvec1;\n\n\t/// 1 component vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<1, int, packed_highp>\t\tpacked_highp_ivec1;\n\n\t/// 1 component vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<1, int, packed_mediump>\t\tpacked_mediump_ivec1;\n\n\t/// 1 component vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<1, int, packed_lowp>\t\tpacked_lowp_ivec1;\n\n\t/// 1 component vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<1, uint, packed_highp>\t\tpacked_highp_uvec1;\n\n\t/// 1 component vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<1, uint, packed_mediump>\tpacked_mediump_uvec1;\n\n\t/// 1 component vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<1, uint, packed_lowp>\t\tpacked_lowp_uvec1;\n\n\t/// 1 component vector tightly packed in memory of bool values.\n\ttypedef vec<1, bool, packed_highp>\t\tpacked_highp_bvec1;\n\n\t/// 1 component vector tightly packed in memory of bool values.\n\ttypedef vec<1, bool, packed_mediump>\tpacked_mediump_bvec1;\n\n\t/// 1 component vector tightly packed in memory of bool values.\n\ttypedef vec<1, bool, packed_lowp>\t\tpacked_lowp_bvec1;\n\n\t// -- *vec2 --\n\n\t/// 2 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<2, float, aligned_highp>\taligned_highp_vec2;\n\n\t/// 2 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<2, float, aligned_mediump>\taligned_mediump_vec2;\n\n\t/// 2 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<2, float, aligned_lowp>\t\taligned_lowp_vec2;\n\n\t/// 2 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<2, double, aligned_highp>\taligned_highp_dvec2;\n\n\t/// 2 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<2, double, aligned_mediump>\taligned_mediump_dvec2;\n\n\t/// 2 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<2, double, aligned_lowp>\taligned_lowp_dvec2;\n\n\t/// 2 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<2, int, aligned_highp>\t\taligned_highp_ivec2;\n\n\t/// 2 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<2, int, aligned_mediump>\taligned_mediump_ivec2;\n\n\t/// 2 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<2, int, aligned_lowp>\t\taligned_lowp_ivec2;\n\n\t/// 2 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<2, uint, aligned_highp>\t\taligned_highp_uvec2;\n\n\t/// 2 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<2, uint, aligned_mediump>\taligned_mediump_uvec2;\n\n\t/// 2 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<2, uint, aligned_lowp>\t\taligned_lowp_uvec2;\n\n\t/// 2 components vector aligned in memory of bool values.\n\ttypedef vec<2, bool, aligned_highp>\t\taligned_highp_bvec2;\n\n\t/// 2 components vector aligned in memory of bool values.\n\ttypedef vec<2, bool, aligned_mediump>\taligned_mediump_bvec2;\n\n\t/// 2 components vector aligned in memory of bool values.\n\ttypedef vec<2, bool, aligned_lowp>\t\taligned_lowp_bvec2;\n\n\t/// 2 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<2, float, packed_highp>\t\tpacked_highp_vec2;\n\n\t/// 2 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<2, float, packed_mediump>\tpacked_mediump_vec2;\n\n\t/// 2 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<2, float, packed_lowp>\t\tpacked_lowp_vec2;\n\n\t/// 2 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<2, double, packed_highp>\tpacked_highp_dvec2;\n\n\t/// 2 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<2, double, packed_mediump>\tpacked_mediump_dvec2;\n\n\t/// 2 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<2, double, packed_lowp>\t\tpacked_lowp_dvec2;\n\n\t/// 2 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<2, int, packed_highp>\t\tpacked_highp_ivec2;\n\n\t/// 2 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<2, int, packed_mediump>\t\tpacked_mediump_ivec2;\n\n\t/// 2 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<2, int, packed_lowp>\t\tpacked_lowp_ivec2;\n\n\t/// 2 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<2, uint, packed_highp>\t\tpacked_highp_uvec2;\n\n\t/// 2 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<2, uint, packed_mediump>\tpacked_mediump_uvec2;\n\n\t/// 2 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<2, uint, packed_lowp>\t\tpacked_lowp_uvec2;\n\n\t/// 2 components vector tightly packed in memory of bool values.\n\ttypedef vec<2, bool, packed_highp>\t\tpacked_highp_bvec2;\n\n\t/// 2 components vector tightly packed in memory of bool values.\n\ttypedef vec<2, bool, packed_mediump>\tpacked_mediump_bvec2;\n\n\t/// 2 components vector tightly packed in memory of bool values.\n\ttypedef vec<2, bool, packed_lowp>\t\tpacked_lowp_bvec2;\n\n\t// -- *vec3 --\n\n\t/// 3 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<3, float, aligned_highp>\taligned_highp_vec3;\n\n\t/// 3 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<3, float, aligned_mediump>\taligned_mediump_vec3;\n\n\t/// 3 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<3, float, aligned_lowp>\t\taligned_lowp_vec3;\n\n\t/// 3 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<3, double, aligned_highp>\taligned_highp_dvec3;\n\n\t/// 3 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<3, double, aligned_mediump>\taligned_mediump_dvec3;\n\n\t/// 3 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<3, double, aligned_lowp>\taligned_lowp_dvec3;\n\n\t/// 3 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<3, int, aligned_highp>\t\taligned_highp_ivec3;\n\n\t/// 3 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<3, int, aligned_mediump>\taligned_mediump_ivec3;\n\n\t/// 3 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<3, int, aligned_lowp>\t\taligned_lowp_ivec3;\n\n\t/// 3 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<3, uint, aligned_highp>\t\taligned_highp_uvec3;\n\n\t/// 3 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<3, uint, aligned_mediump>\taligned_mediump_uvec3;\n\n\t/// 3 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<3, uint, aligned_lowp>\t\taligned_lowp_uvec3;\n\n\t/// 3 components vector aligned in memory of bool values.\n\ttypedef vec<3, bool, aligned_highp>\t\taligned_highp_bvec3;\n\n\t/// 3 components vector aligned in memory of bool values.\n\ttypedef vec<3, bool, aligned_mediump>\taligned_mediump_bvec3;\n\n\t/// 3 components vector aligned in memory of bool values.\n\ttypedef vec<3, bool, aligned_lowp>\t\taligned_lowp_bvec3;\n\n\t/// 3 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<3, float, packed_highp>\t\tpacked_highp_vec3;\n\n\t/// 3 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<3, float, packed_mediump>\tpacked_mediump_vec3;\n\n\t/// 3 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<3, float, packed_lowp>\t\tpacked_lowp_vec3;\n\n\t/// 3 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<3, double, packed_highp>\tpacked_highp_dvec3;\n\n\t/// 3 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<3, double, packed_mediump>\tpacked_mediump_dvec3;\n\n\t/// 3 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<3, double, packed_lowp>\t\tpacked_lowp_dvec3;\n\n\t/// 3 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<3, int, packed_highp>\t\tpacked_highp_ivec3;\n\n\t/// 3 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<3, int, packed_mediump>\t\tpacked_mediump_ivec3;\n\n\t/// 3 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<3, int, packed_lowp>\t\tpacked_lowp_ivec3;\n\n\t/// 3 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<3, uint, packed_highp>\t\tpacked_highp_uvec3;\n\n\t/// 3 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<3, uint, packed_mediump>\tpacked_mediump_uvec3;\n\n\t/// 3 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<3, uint, packed_lowp>\t\tpacked_lowp_uvec3;\n\n\t/// 3 components vector tightly packed in memory of bool values.\n\ttypedef vec<3, bool, packed_highp>\t\tpacked_highp_bvec3;\n\n\t/// 3 components vector tightly packed in memory of bool values.\n\ttypedef vec<3, bool, packed_mediump>\tpacked_mediump_bvec3;\n\n\t/// 3 components vector tightly packed in memory of bool values.\n\ttypedef vec<3, bool, packed_lowp>\t\tpacked_lowp_bvec3;\n\n\t// -- *vec4 --\n\n\t/// 4 components vector aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<4, float, aligned_highp>\taligned_highp_vec4;\n\n\t/// 4 components vector aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<4, float, aligned_mediump>\taligned_mediump_vec4;\n\n\t/// 4 components vector aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<4, float, aligned_lowp>\t\taligned_lowp_vec4;\n\n\t/// 4 components vector aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<4, double, aligned_highp>\taligned_highp_dvec4;\n\n\t/// 4 components vector aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<4, double, aligned_mediump>\taligned_mediump_dvec4;\n\n\t/// 4 components vector aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<4, double, aligned_lowp>\taligned_lowp_dvec4;\n\n\t/// 4 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<4, int, aligned_highp>\t\taligned_highp_ivec4;\n\n\t/// 4 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<4, int, aligned_mediump>\taligned_mediump_ivec4;\n\n\t/// 4 components vector aligned in memory of signed integer numbers.\n\ttypedef vec<4, int, aligned_lowp>\t\taligned_lowp_ivec4;\n\n\t/// 4 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<4, uint, aligned_highp>\t\taligned_highp_uvec4;\n\n\t/// 4 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<4, uint, aligned_mediump>\taligned_mediump_uvec4;\n\n\t/// 4 components vector aligned in memory of unsigned integer numbers.\n\ttypedef vec<4, uint, aligned_lowp>\t\taligned_lowp_uvec4;\n\n\t/// 4 components vector aligned in memory of bool values.\n\ttypedef vec<4, bool, aligned_highp>\t\taligned_highp_bvec4;\n\n\t/// 4 components vector aligned in memory of bool values.\n\ttypedef vec<4, bool, aligned_mediump>\taligned_mediump_bvec4;\n\n\t/// 4 components vector aligned in memory of bool values.\n\ttypedef vec<4, bool, aligned_lowp>\t\taligned_lowp_bvec4;\n\n\t/// 4 components vector tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<4, float, packed_highp>\t\tpacked_highp_vec4;\n\n\t/// 4 components vector tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<4, float, packed_mediump>\tpacked_mediump_vec4;\n\n\t/// 4 components vector tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<4, float, packed_lowp>\t\tpacked_lowp_vec4;\n\n\t/// 4 components vector tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef vec<4, double, packed_highp>\tpacked_highp_dvec4;\n\n\t/// 4 components vector tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef vec<4, double, packed_mediump>\tpacked_mediump_dvec4;\n\n\t/// 4 components vector tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef vec<4, double, packed_lowp>\t\tpacked_lowp_dvec4;\n\n\t/// 4 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<4, int, packed_highp>\t\tpacked_highp_ivec4;\n\n\t/// 4 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<4, int, packed_mediump>\t\tpacked_mediump_ivec4;\n\n\t/// 4 components vector tightly packed in memory of signed integer numbers.\n\ttypedef vec<4, int, packed_lowp>\t\tpacked_lowp_ivec4;\n\n\t/// 4 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<4, uint, packed_highp>\t\tpacked_highp_uvec4;\n\n\t/// 4 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<4, uint, packed_mediump>\tpacked_mediump_uvec4;\n\n\t/// 4 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef vec<4, uint, packed_lowp>\t\tpacked_lowp_uvec4;\n\n\t/// 4 components vector tightly packed in memory of bool values.\n\ttypedef vec<4, bool, packed_highp>\t\tpacked_highp_bvec4;\n\n\t/// 4 components vector tightly packed in memory of bool values.\n\ttypedef vec<4, bool, packed_mediump>\tpacked_mediump_bvec4;\n\n\t/// 4 components vector tightly packed in memory of bool values.\n\ttypedef vec<4, bool, packed_lowp>\t\tpacked_lowp_bvec4;\n\n\t// -- *mat2 --\n\n\t/// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, aligned_highp>\t\taligned_highp_mat2;\n\n\t/// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, aligned_mediump>\taligned_mediump_mat2;\n\n\t/// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, aligned_lowp>\t\taligned_lowp_mat2;\n\n\t/// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, aligned_highp>\taligned_highp_dmat2;\n\n\t/// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, aligned_mediump>\taligned_mediump_dmat2;\n\n\t/// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, aligned_lowp>\t\taligned_lowp_dmat2;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, packed_highp>\t\tpacked_highp_mat2;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, packed_mediump>\tpacked_mediump_mat2;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, packed_lowp>\t\tpacked_lowp_mat2;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, packed_highp>\t\tpacked_highp_dmat2;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, packed_mediump>\tpacked_mediump_dmat2;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, packed_lowp>\t\tpacked_lowp_dmat2;\n\n\t// -- *mat3 --\n\n\t/// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, aligned_highp>\t\taligned_highp_mat3;\n\n\t/// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, aligned_mediump>\taligned_mediump_mat3;\n\n\t/// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, aligned_lowp>\t\taligned_lowp_mat3;\n\n\t/// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, aligned_highp>\taligned_highp_dmat3;\n\n\t/// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, aligned_mediump>\taligned_mediump_dmat3;\n\n\t/// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, aligned_lowp>\t\taligned_lowp_dmat3;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, packed_highp>\t\tpacked_highp_mat3;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, packed_mediump>\tpacked_mediump_mat3;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, packed_lowp>\t\tpacked_lowp_mat3;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, packed_highp>\t\tpacked_highp_dmat3;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, packed_mediump>\tpacked_mediump_dmat3;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, packed_lowp>\t\tpacked_lowp_dmat3;\n\n\t// -- *mat4 --\n\n\t/// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, aligned_highp>\t\taligned_highp_mat4;\n\n\t/// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, aligned_mediump>\taligned_mediump_mat4;\n\n\t/// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, aligned_lowp>\t\taligned_lowp_mat4;\n\n\t/// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, aligned_highp>\taligned_highp_dmat4;\n\n\t/// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, aligned_mediump>\taligned_mediump_dmat4;\n\n\t/// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, aligned_lowp>\t\taligned_lowp_dmat4;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, packed_highp>\t\tpacked_highp_mat4;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, packed_mediump>\tpacked_mediump_mat4;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, packed_lowp>\t\tpacked_lowp_mat4;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, packed_highp>\t\tpacked_highp_dmat4;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, packed_mediump>\tpacked_mediump_dmat4;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, packed_lowp>\t\tpacked_lowp_dmat4;\n\n\t// -- *mat2x2 --\n\n\t/// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, aligned_highp>\t\taligned_highp_mat2x2;\n\n\t/// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, aligned_mediump>\taligned_mediump_mat2x2;\n\n\t/// 2 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, aligned_lowp>\t\taligned_lowp_mat2x2;\n\n\t/// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, aligned_highp>\taligned_highp_dmat2x2;\n\n\t/// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, aligned_mediump>\taligned_mediump_dmat2x2;\n\n\t/// 2 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, aligned_lowp>\t\taligned_lowp_dmat2x2;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, packed_highp>\t\tpacked_highp_mat2x2;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, packed_mediump>\tpacked_mediump_mat2x2;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, float, packed_lowp>\t\tpacked_lowp_mat2x2;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, packed_highp>\t\tpacked_highp_dmat2x2;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, packed_mediump>\tpacked_mediump_dmat2x2;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 2, double, packed_lowp>\t\tpacked_lowp_dmat2x2;\n\n\t// -- *mat2x3 --\n\n\t/// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, float, aligned_highp>\t\taligned_highp_mat2x3;\n\n\t/// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, float, aligned_mediump>\taligned_mediump_mat2x3;\n\n\t/// 2 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, float, aligned_lowp>\t\taligned_lowp_mat2x3;\n\n\t/// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, double, aligned_highp>\taligned_highp_dmat2x3;\n\n\t/// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, double, aligned_mediump>\taligned_mediump_dmat2x3;\n\n\t/// 2 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, double, aligned_lowp>\t\taligned_lowp_dmat2x3;\n\n\t/// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, float, packed_highp>\t\tpacked_highp_mat2x3;\n\n\t/// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, float, packed_mediump>\tpacked_mediump_mat2x3;\n\n\t/// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, float, packed_lowp>\t\tpacked_lowp_mat2x3;\n\n\t/// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, double, packed_highp>\t\tpacked_highp_dmat2x3;\n\n\t/// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, double, packed_mediump>\tpacked_mediump_dmat2x3;\n\n\t/// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 3, double, packed_lowp>\t\tpacked_lowp_dmat2x3;\n\n\t// -- *mat2x4 --\n\n\t/// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, float, aligned_highp>\t\taligned_highp_mat2x4;\n\n\t/// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, float, aligned_mediump>\taligned_mediump_mat2x4;\n\n\t/// 2 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, float, aligned_lowp>\t\taligned_lowp_mat2x4;\n\n\t/// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, double, aligned_highp>\taligned_highp_dmat2x4;\n\n\t/// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, double, aligned_mediump>\taligned_mediump_dmat2x4;\n\n\t/// 2 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, double, aligned_lowp>\t\taligned_lowp_dmat2x4;\n\n\t/// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, float, packed_highp>\t\tpacked_highp_mat2x4;\n\n\t/// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, float, packed_mediump>\tpacked_mediump_mat2x4;\n\n\t/// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, float, packed_lowp>\t\tpacked_lowp_mat2x4;\n\n\t/// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, double, packed_highp>\t\tpacked_highp_dmat2x4;\n\n\t/// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, double, packed_mediump>\tpacked_mediump_dmat2x4;\n\n\t/// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<2, 4, double, packed_lowp>\t\tpacked_lowp_dmat2x4;\n\n\t// -- *mat3x2 --\n\n\t/// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, float, aligned_highp>\t\taligned_highp_mat3x2;\n\n\t/// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, float, aligned_mediump>\taligned_mediump_mat3x2;\n\n\t/// 3 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, float, aligned_lowp>\t\taligned_lowp_mat3x2;\n\n\t/// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, double, aligned_highp>\taligned_highp_dmat3x2;\n\n\t/// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, double, aligned_mediump>\taligned_mediump_dmat3x2;\n\n\t/// 3 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, double, aligned_lowp>\t\taligned_lowp_dmat3x2;\n\n\t/// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, float, packed_highp>\t\tpacked_highp_mat3x2;\n\n\t/// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, float, packed_mediump>\tpacked_mediump_mat3x2;\n\n\t/// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, float, packed_lowp>\t\tpacked_lowp_mat3x2;\n\n\t/// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, double, packed_highp>\t\tpacked_highp_dmat3x2;\n\n\t/// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, double, packed_mediump>\tpacked_mediump_dmat3x2;\n\n\t/// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 2, double, packed_lowp>\t\tpacked_lowp_dmat3x2;\n\n\t// -- *mat3x3 --\n\n\t/// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, aligned_highp>\t\taligned_highp_mat3x3;\n\n\t/// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, aligned_mediump>\taligned_mediump_mat3x3;\n\n\t/// 3 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, aligned_lowp>\t\taligned_lowp_mat3x3;\n\n\t/// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, aligned_highp>\taligned_highp_dmat3x3;\n\n\t/// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, aligned_mediump>\taligned_mediump_dmat3x3;\n\n\t/// 3 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, aligned_lowp>\t\taligned_lowp_dmat3x3;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, packed_highp>\t\tpacked_highp_mat3x3;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, packed_mediump>\tpacked_mediump_mat3x3;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, float, packed_lowp>\t\tpacked_lowp_mat3x3;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, packed_highp>\t\tpacked_highp_dmat3x3;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, packed_mediump>\tpacked_mediump_dmat3x3;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 3, double, packed_lowp>\t\tpacked_lowp_dmat3x3;\n\n\t// -- *mat3x4 --\n\n\t/// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, float, aligned_highp>\t\taligned_highp_mat3x4;\n\n\t/// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, float, aligned_mediump>\taligned_mediump_mat3x4;\n\n\t/// 3 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, float, aligned_lowp>\t\taligned_lowp_mat3x4;\n\n\t/// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, double, aligned_highp>\taligned_highp_dmat3x4;\n\n\t/// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, double, aligned_mediump>\taligned_mediump_dmat3x4;\n\n\t/// 3 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, double, aligned_lowp>\t\taligned_lowp_dmat3x4;\n\n\t/// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, float, packed_highp>\t\tpacked_highp_mat3x4;\n\n\t/// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, float, packed_mediump>\tpacked_mediump_mat3x4;\n\n\t/// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, float, packed_lowp>\t\tpacked_lowp_mat3x4;\n\n\t/// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, double, packed_highp>\t\tpacked_highp_dmat3x4;\n\n\t/// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, double, packed_mediump>\tpacked_mediump_dmat3x4;\n\n\t/// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<3, 4, double, packed_lowp>\t\tpacked_lowp_dmat3x4;\n\n\t// -- *mat4x2 --\n\n\t/// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, float, aligned_highp>\t\taligned_highp_mat4x2;\n\n\t/// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, float, aligned_mediump>\taligned_mediump_mat4x2;\n\n\t/// 4 by 2 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, float, aligned_lowp>\t\taligned_lowp_mat4x2;\n\n\t/// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, double, aligned_highp>\taligned_highp_dmat4x2;\n\n\t/// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, double, aligned_mediump>\taligned_mediump_dmat4x2;\n\n\t/// 4 by 2 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, double, aligned_lowp>\t\taligned_lowp_dmat4x2;\n\n\t/// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, float, packed_highp>\t\tpacked_highp_mat4x2;\n\n\t/// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, float, packed_mediump>\tpacked_mediump_mat4x2;\n\n\t/// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, float, packed_lowp>\t\tpacked_lowp_mat4x2;\n\n\t/// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, double, packed_highp>\t\tpacked_highp_dmat4x2;\n\n\t/// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, double, packed_mediump>\tpacked_mediump_dmat4x2;\n\n\t/// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 2, double, packed_lowp>\t\tpacked_lowp_dmat4x2;\n\n\t// -- *mat4x3 --\n\n\t/// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, float, aligned_highp>\t\taligned_highp_mat4x3;\n\n\t/// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, float, aligned_mediump>\taligned_mediump_mat4x3;\n\n\t/// 4 by 3 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, float, aligned_lowp>\t\taligned_lowp_mat4x3;\n\n\t/// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, double, aligned_highp>\taligned_highp_dmat4x3;\n\n\t/// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, double, aligned_mediump>\taligned_mediump_dmat4x3;\n\n\t/// 4 by 3 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, double, aligned_lowp>\t\taligned_lowp_dmat4x3;\n\n\t/// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, float, packed_highp>\t\tpacked_highp_mat4x3;\n\n\t/// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, float, packed_mediump>\tpacked_mediump_mat4x3;\n\n\t/// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, float, packed_lowp>\t\tpacked_lowp_mat4x3;\n\n\t/// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, double, packed_highp>\t\tpacked_highp_dmat4x3;\n\n\t/// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, double, packed_mediump>\tpacked_mediump_dmat4x3;\n\n\t/// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 3, double, packed_lowp>\t\tpacked_lowp_dmat4x3;\n\n\t// -- *mat4x4 --\n\n\t/// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, aligned_highp>\t\taligned_highp_mat4x4;\n\n\t/// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, aligned_mediump>\taligned_mediump_mat4x4;\n\n\t/// 4 by 4 matrix aligned in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, aligned_lowp>\t\taligned_lowp_mat4x4;\n\n\t/// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, aligned_highp>\taligned_highp_dmat4x4;\n\n\t/// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, aligned_mediump>\taligned_mediump_dmat4x4;\n\n\t/// 4 by 4 matrix aligned in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, aligned_lowp>\t\taligned_lowp_dmat4x4;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, packed_highp>\t\tpacked_highp_mat4x4;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, packed_mediump>\tpacked_mediump_mat4x4;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, float, packed_lowp>\t\tpacked_lowp_mat4x4;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using high precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, packed_highp>\t\tpacked_highp_dmat4x4;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using medium precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, packed_mediump>\tpacked_mediump_dmat4x4;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers using low precision arithmetic in term of ULPs.\n\ttypedef mat<4, 4, double, packed_lowp>\t\tpacked_lowp_dmat4x4;\n\n\t// -- default --\n\n#if(defined(GLM_PRECISION_LOWP_FLOAT))\n\ttypedef aligned_lowp_vec1\t\t\taligned_vec1;\n\ttypedef aligned_lowp_vec2\t\t\taligned_vec2;\n\ttypedef aligned_lowp_vec3\t\t\taligned_vec3;\n\ttypedef aligned_lowp_vec4\t\t\taligned_vec4;\n\ttypedef packed_lowp_vec1\t\t\tpacked_vec1;\n\ttypedef packed_lowp_vec2\t\t\tpacked_vec2;\n\ttypedef packed_lowp_vec3\t\t\tpacked_vec3;\n\ttypedef packed_lowp_vec4\t\t\tpacked_vec4;\n\n\ttypedef aligned_lowp_mat2\t\t\taligned_mat2;\n\ttypedef aligned_lowp_mat3\t\t\taligned_mat3;\n\ttypedef aligned_lowp_mat4\t\t\taligned_mat4;\n\ttypedef packed_lowp_mat2\t\t\tpacked_mat2;\n\ttypedef packed_lowp_mat3\t\t\tpacked_mat3;\n\ttypedef packed_lowp_mat4\t\t\tpacked_mat4;\n\n\ttypedef aligned_lowp_mat2x2\t\t\taligned_mat2x2;\n\ttypedef aligned_lowp_mat2x3\t\t\taligned_mat2x3;\n\ttypedef aligned_lowp_mat2x4\t\t\taligned_mat2x4;\n\ttypedef aligned_lowp_mat3x2\t\t\taligned_mat3x2;\n\ttypedef aligned_lowp_mat3x3\t\t\taligned_mat3x3;\n\ttypedef aligned_lowp_mat3x4\t\t\taligned_mat3x4;\n\ttypedef aligned_lowp_mat4x2\t\t\taligned_mat4x2;\n\ttypedef aligned_lowp_mat4x3\t\t\taligned_mat4x3;\n\ttypedef aligned_lowp_mat4x4\t\t\taligned_mat4x4;\n\ttypedef packed_lowp_mat2x2\t\t\tpacked_mat2x2;\n\ttypedef packed_lowp_mat2x3\t\t\tpacked_mat2x3;\n\ttypedef packed_lowp_mat2x4\t\t\tpacked_mat2x4;\n\ttypedef packed_lowp_mat3x2\t\t\tpacked_mat3x2;\n\ttypedef packed_lowp_mat3x3\t\t\tpacked_mat3x3;\n\ttypedef packed_lowp_mat3x4\t\t\tpacked_mat3x4;\n\ttypedef packed_lowp_mat4x2\t\t\tpacked_mat4x2;\n\ttypedef packed_lowp_mat4x3\t\t\tpacked_mat4x3;\n\ttypedef packed_lowp_mat4x4\t\t\tpacked_mat4x4;\n#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))\n\ttypedef aligned_mediump_vec1\t\taligned_vec1;\n\ttypedef aligned_mediump_vec2\t\taligned_vec2;\n\ttypedef aligned_mediump_vec3\t\taligned_vec3;\n\ttypedef aligned_mediump_vec4\t\taligned_vec4;\n\ttypedef packed_mediump_vec1\t\t\tpacked_vec1;\n\ttypedef packed_mediump_vec2\t\t\tpacked_vec2;\n\ttypedef packed_mediump_vec3\t\t\tpacked_vec3;\n\ttypedef packed_mediump_vec4\t\t\tpacked_vec4;\n\n\ttypedef aligned_mediump_mat2\t\taligned_mat2;\n\ttypedef aligned_mediump_mat3\t\taligned_mat3;\n\ttypedef aligned_mediump_mat4\t\taligned_mat4;\n\ttypedef packed_mediump_mat2\t\t\tpacked_mat2;\n\ttypedef packed_mediump_mat3\t\t\tpacked_mat3;\n\ttypedef packed_mediump_mat4\t\t\tpacked_mat4;\n\n\ttypedef aligned_mediump_mat2x2\t\taligned_mat2x2;\n\ttypedef aligned_mediump_mat2x3\t\taligned_mat2x3;\n\ttypedef aligned_mediump_mat2x4\t\taligned_mat2x4;\n\ttypedef aligned_mediump_mat3x2\t\taligned_mat3x2;\n\ttypedef aligned_mediump_mat3x3\t\taligned_mat3x3;\n\ttypedef aligned_mediump_mat3x4\t\taligned_mat3x4;\n\ttypedef aligned_mediump_mat4x2\t\taligned_mat4x2;\n\ttypedef aligned_mediump_mat4x3\t\taligned_mat4x3;\n\ttypedef aligned_mediump_mat4x4\t\taligned_mat4x4;\n\ttypedef packed_mediump_mat2x2\t\tpacked_mat2x2;\n\ttypedef packed_mediump_mat2x3\t\tpacked_mat2x3;\n\ttypedef packed_mediump_mat2x4\t\tpacked_mat2x4;\n\ttypedef packed_mediump_mat3x2\t\tpacked_mat3x2;\n\ttypedef packed_mediump_mat3x3\t\tpacked_mat3x3;\n\ttypedef packed_mediump_mat3x4\t\tpacked_mat3x4;\n\ttypedef packed_mediump_mat4x2\t\tpacked_mat4x2;\n\ttypedef packed_mediump_mat4x3\t\tpacked_mat4x3;\n\ttypedef packed_mediump_mat4x4\t\tpacked_mat4x4;\n#else //defined(GLM_PRECISION_HIGHP_FLOAT)\n\t/// 1 component vector aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_vec1\t\t\taligned_vec1;\n\n\t/// 2 components vector aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_vec2\t\t\taligned_vec2;\n\n\t/// 3 components vector aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_vec3\t\t\taligned_vec3;\n\n\t/// 4 components vector aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_vec4 \t\t\taligned_vec4;\n\n\t/// 1 component vector tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_vec1\t\t\tpacked_vec1;\n\n\t/// 2 components vector tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_vec2\t\t\tpacked_vec2;\n\n\t/// 3 components vector tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_vec3\t\t\tpacked_vec3;\n\n\t/// 4 components vector tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_vec4\t\t\tpacked_vec4;\n\n\t/// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat2\t\t\taligned_mat2;\n\n\t/// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat3\t\t\taligned_mat3;\n\n\t/// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat4\t\t\taligned_mat4;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat2\t\t\tpacked_mat2;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat3\t\t\tpacked_mat3;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat4\t\t\tpacked_mat4;\n\n\t/// 2 by 2 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat2x2\t\taligned_mat2x2;\n\n\t/// 2 by 3 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat2x3\t\taligned_mat2x3;\n\n\t/// 2 by 4 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat2x4\t\taligned_mat2x4;\n\n\t/// 3 by 2 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat3x2\t\taligned_mat3x2;\n\n\t/// 3 by 3 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat3x3\t\taligned_mat3x3;\n\n\t/// 3 by 4 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat3x4\t\taligned_mat3x4;\n\n\t/// 4 by 2 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat4x2\t\taligned_mat4x2;\n\n\t/// 4 by 3 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat4x3\t\taligned_mat4x3;\n\n\t/// 4 by 4 matrix tightly aligned in memory of single-precision floating-point numbers.\n\ttypedef aligned_highp_mat4x4\t\taligned_mat4x4;\n\n\t/// 2 by 2 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat2x2\t\t\tpacked_mat2x2;\n\n\t/// 2 by 3 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat2x3\t\t\tpacked_mat2x3;\n\n\t/// 2 by 4 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat2x4\t\t\tpacked_mat2x4;\n\n\t/// 3 by 2 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat3x2\t\t\tpacked_mat3x2;\n\n\t/// 3 by 3 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat3x3\t\t\tpacked_mat3x3;\n\n\t/// 3 by 4 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat3x4\t\t\tpacked_mat3x4;\n\n\t/// 4 by 2 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat4x2\t\t\tpacked_mat4x2;\n\n\t/// 4 by 3 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat4x3\t\t\tpacked_mat4x3;\n\n\t/// 4 by 4 matrix tightly packed in memory of single-precision floating-point numbers.\n\ttypedef packed_highp_mat4x4\t\t\tpacked_mat4x4;\n#endif//GLM_PRECISION\n\n#if(defined(GLM_PRECISION_LOWP_DOUBLE))\n\ttypedef aligned_lowp_dvec1\t\t\taligned_dvec1;\n\ttypedef aligned_lowp_dvec2\t\t\taligned_dvec2;\n\ttypedef aligned_lowp_dvec3\t\t\taligned_dvec3;\n\ttypedef aligned_lowp_dvec4\t\t\taligned_dvec4;\n\ttypedef packed_lowp_dvec1\t\t\tpacked_dvec1;\n\ttypedef packed_lowp_dvec2\t\t\tpacked_dvec2;\n\ttypedef packed_lowp_dvec3\t\t\tpacked_dvec3;\n\ttypedef packed_lowp_dvec4\t\t\tpacked_dvec4;\n\n\ttypedef aligned_lowp_dmat2\t\t\taligned_dmat2;\n\ttypedef aligned_lowp_dmat3\t\t\taligned_dmat3;\n\ttypedef aligned_lowp_dmat4\t\t\taligned_dmat4;\n\ttypedef packed_lowp_dmat2\t\t\tpacked_dmat2;\n\ttypedef packed_lowp_dmat3\t\t\tpacked_dmat3;\n\ttypedef packed_lowp_dmat4\t\t\tpacked_dmat4;\n\n\ttypedef aligned_lowp_dmat2x2\t\taligned_dmat2x2;\n\ttypedef aligned_lowp_dmat2x3\t\taligned_dmat2x3;\n\ttypedef aligned_lowp_dmat2x4\t\taligned_dmat2x4;\n\ttypedef aligned_lowp_dmat3x2\t\taligned_dmat3x2;\n\ttypedef aligned_lowp_dmat3x3\t\taligned_dmat3x3;\n\ttypedef aligned_lowp_dmat3x4\t\taligned_dmat3x4;\n\ttypedef aligned_lowp_dmat4x2\t\taligned_dmat4x2;\n\ttypedef aligned_lowp_dmat4x3\t\taligned_dmat4x3;\n\ttypedef aligned_lowp_dmat4x4\t\taligned_dmat4x4;\n\ttypedef packed_lowp_dmat2x2\t\t\tpacked_dmat2x2;\n\ttypedef packed_lowp_dmat2x3\t\t\tpacked_dmat2x3;\n\ttypedef packed_lowp_dmat2x4\t\t\tpacked_dmat2x4;\n\ttypedef packed_lowp_dmat3x2\t\t\tpacked_dmat3x2;\n\ttypedef packed_lowp_dmat3x3\t\t\tpacked_dmat3x3;\n\ttypedef packed_lowp_dmat3x4\t\t\tpacked_dmat3x4;\n\ttypedef packed_lowp_dmat4x2\t\t\tpacked_dmat4x2;\n\ttypedef packed_lowp_dmat4x3\t\t\tpacked_dmat4x3;\n\ttypedef packed_lowp_dmat4x4\t\t\tpacked_dmat4x4;\n#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE))\n\ttypedef aligned_mediump_dvec1\t\taligned_dvec1;\n\ttypedef aligned_mediump_dvec2\t\taligned_dvec2;\n\ttypedef aligned_mediump_dvec3\t\taligned_dvec3;\n\ttypedef aligned_mediump_dvec4\t\taligned_dvec4;\n\ttypedef packed_mediump_dvec1\t\tpacked_dvec1;\n\ttypedef packed_mediump_dvec2\t\tpacked_dvec2;\n\ttypedef packed_mediump_dvec3\t\tpacked_dvec3;\n\ttypedef packed_mediump_dvec4\t\tpacked_dvec4;\n\n\ttypedef aligned_mediump_dmat2\t\taligned_dmat2;\n\ttypedef aligned_mediump_dmat3\t\taligned_dmat3;\n\ttypedef aligned_mediump_dmat4\t\taligned_dmat4;\n\ttypedef packed_mediump_dmat2\t\tpacked_dmat2;\n\ttypedef packed_mediump_dmat3\t\tpacked_dmat3;\n\ttypedef packed_mediump_dmat4\t\tpacked_dmat4;\n\n\ttypedef aligned_mediump_dmat2x2\t\taligned_dmat2x2;\n\ttypedef aligned_mediump_dmat2x3\t\taligned_dmat2x3;\n\ttypedef aligned_mediump_dmat2x4\t\taligned_dmat2x4;\n\ttypedef aligned_mediump_dmat3x2\t\taligned_dmat3x2;\n\ttypedef aligned_mediump_dmat3x3\t\taligned_dmat3x3;\n\ttypedef aligned_mediump_dmat3x4\t\taligned_dmat3x4;\n\ttypedef aligned_mediump_dmat4x2\t\taligned_dmat4x2;\n\ttypedef aligned_mediump_dmat4x3\t\taligned_dmat4x3;\n\ttypedef aligned_mediump_dmat4x4\t\taligned_dmat4x4;\n\ttypedef packed_mediump_dmat2x2\t\tpacked_dmat2x2;\n\ttypedef packed_mediump_dmat2x3\t\tpacked_dmat2x3;\n\ttypedef packed_mediump_dmat2x4\t\tpacked_dmat2x4;\n\ttypedef packed_mediump_dmat3x2\t\tpacked_dmat3x2;\n\ttypedef packed_mediump_dmat3x3\t\tpacked_dmat3x3;\n\ttypedef packed_mediump_dmat3x4\t\tpacked_dmat3x4;\n\ttypedef packed_mediump_dmat4x2\t\tpacked_dmat4x2;\n\ttypedef packed_mediump_dmat4x3\t\tpacked_dmat4x3;\n\ttypedef packed_mediump_dmat4x4\t\tpacked_dmat4x4;\n#else //defined(GLM_PRECISION_HIGHP_DOUBLE)\n\t/// 1 component vector aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dvec1\t\t\taligned_dvec1;\n\n\t/// 2 components vector aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dvec2\t\t\taligned_dvec2;\n\n\t/// 3 components vector aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dvec3\t\t\taligned_dvec3;\n\n\t/// 4 components vector aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dvec4\t\t\taligned_dvec4;\n\n\t/// 1 component vector tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dvec1\t\t\tpacked_dvec1;\n\n\t/// 2 components vector tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dvec2\t\t\tpacked_dvec2;\n\n\t/// 3 components vector tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dvec3\t\t\tpacked_dvec3;\n\n\t/// 4 components vector tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dvec4\t\t\tpacked_dvec4;\n\n\t/// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat2\t\t\taligned_dmat2;\n\n\t/// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat3\t\t\taligned_dmat3;\n\n\t/// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat4\t\t\taligned_dmat4;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat2\t\t\tpacked_dmat2;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat3\t\t\tpacked_dmat3;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat4\t\t\tpacked_dmat4;\n\n\t/// 2 by 2 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat2x2\t\taligned_dmat2x2;\n\n\t/// 2 by 3 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat2x3\t\taligned_dmat2x3;\n\n\t/// 2 by 4 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat2x4\t\taligned_dmat2x4;\n\n\t/// 3 by 2 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat3x2\t\taligned_dmat3x2;\n\n\t/// 3 by 3 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat3x3\t\taligned_dmat3x3;\n\n\t/// 3 by 4 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat3x4\t\taligned_dmat3x4;\n\n\t/// 4 by 2 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat4x2\t\taligned_dmat4x2;\n\n\t/// 4 by 3 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat4x3\t\taligned_dmat4x3;\n\n\t/// 4 by 4 matrix tightly aligned in memory of double-precision floating-point numbers.\n\ttypedef aligned_highp_dmat4x4\t\taligned_dmat4x4;\n\n\t/// 2 by 2 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat2x2\t\tpacked_dmat2x2;\n\n\t/// 2 by 3 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat2x3\t\tpacked_dmat2x3;\n\n\t/// 2 by 4 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat2x4\t\tpacked_dmat2x4;\n\n\t/// 3 by 2 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat3x2\t\tpacked_dmat3x2;\n\n\t/// 3 by 3 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat3x3\t\tpacked_dmat3x3;\n\n\t/// 3 by 4 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat3x4\t\tpacked_dmat3x4;\n\n\t/// 4 by 2 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat4x2\t\tpacked_dmat4x2;\n\n\t/// 4 by 3 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat4x3\t\tpacked_dmat4x3;\n\n\t/// 4 by 4 matrix tightly packed in memory of double-precision floating-point numbers.\n\ttypedef packed_highp_dmat4x4\t\tpacked_dmat4x4;\n#endif//GLM_PRECISION\n\n#if(defined(GLM_PRECISION_LOWP_INT))\n\ttypedef aligned_lowp_ivec1\t\t\taligned_ivec1;\n\ttypedef aligned_lowp_ivec2\t\t\taligned_ivec2;\n\ttypedef aligned_lowp_ivec3\t\t\taligned_ivec3;\n\ttypedef aligned_lowp_ivec4\t\t\taligned_ivec4;\n#elif(defined(GLM_PRECISION_MEDIUMP_INT))\n\ttypedef aligned_mediump_ivec1\t\taligned_ivec1;\n\ttypedef aligned_mediump_ivec2\t\taligned_ivec2;\n\ttypedef aligned_mediump_ivec3\t\taligned_ivec3;\n\ttypedef aligned_mediump_ivec4\t\taligned_ivec4;\n#else //defined(GLM_PRECISION_HIGHP_INT)\n\t/// 1 component vector aligned in memory of signed integer numbers.\n\ttypedef aligned_highp_ivec1\t\t\taligned_ivec1;\n\n\t/// 2 components vector aligned in memory of signed integer numbers.\n\ttypedef aligned_highp_ivec2\t\t\taligned_ivec2;\n\n\t/// 3 components vector aligned in memory of signed integer numbers.\n\ttypedef aligned_highp_ivec3\t\t\taligned_ivec3;\n\n\t/// 4 components vector aligned in memory of signed integer numbers.\n\ttypedef aligned_highp_ivec4\t\t\taligned_ivec4;\n\n\t/// 1 component vector tightly packed in memory of signed integer numbers.\n\ttypedef packed_highp_ivec1\t\t\tpacked_ivec1;\n\n\t/// 2 components vector tightly packed in memory of signed integer numbers.\n\ttypedef packed_highp_ivec2\t\t\tpacked_ivec2;\n\n\t/// 3 components vector tightly packed in memory of signed integer numbers.\n\ttypedef packed_highp_ivec3\t\t\tpacked_ivec3;\n\n\t/// 4 components vector tightly packed in memory of signed integer numbers.\n\ttypedef packed_highp_ivec4\t\t\tpacked_ivec4;\n#endif//GLM_PRECISION\n\n\t// -- Unsigned integer definition --\n\n#if(defined(GLM_PRECISION_LOWP_UINT))\n\ttypedef aligned_lowp_uvec1\t\t\taligned_uvec1;\n\ttypedef aligned_lowp_uvec2\t\t\taligned_uvec2;\n\ttypedef aligned_lowp_uvec3\t\t\taligned_uvec3;\n\ttypedef aligned_lowp_uvec4\t\t\taligned_uvec4;\n#elif(defined(GLM_PRECISION_MEDIUMP_UINT))\n\ttypedef aligned_mediump_uvec1\t\taligned_uvec1;\n\ttypedef aligned_mediump_uvec2\t\taligned_uvec2;\n\ttypedef aligned_mediump_uvec3\t\taligned_uvec3;\n\ttypedef aligned_mediump_uvec4\t\taligned_uvec4;\n#else //defined(GLM_PRECISION_HIGHP_UINT)\n\t/// 1 component vector aligned in memory of unsigned integer numbers.\n\ttypedef aligned_highp_uvec1\t\t\taligned_uvec1;\n\n\t/// 2 components vector aligned in memory of unsigned integer numbers.\n\ttypedef aligned_highp_uvec2\t\t\taligned_uvec2;\n\n\t/// 3 components vector aligned in memory of unsigned integer numbers.\n\ttypedef aligned_highp_uvec3\t\t\taligned_uvec3;\n\n\t/// 4 components vector aligned in memory of unsigned integer numbers.\n\ttypedef aligned_highp_uvec4\t\t\taligned_uvec4;\n\n\t/// 1 component vector tightly packed in memory of unsigned integer numbers.\n\ttypedef packed_highp_uvec1\t\t\tpacked_uvec1;\n\n\t/// 2 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef packed_highp_uvec2\t\t\tpacked_uvec2;\n\n\t/// 3 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef packed_highp_uvec3\t\t\tpacked_uvec3;\n\n\t/// 4 components vector tightly packed in memory of unsigned integer numbers.\n\ttypedef packed_highp_uvec4\t\t\tpacked_uvec4;\n#endif//GLM_PRECISION\n\n#if(defined(GLM_PRECISION_LOWP_BOOL))\n\ttypedef aligned_lowp_bvec1\t\t\taligned_bvec1;\n\ttypedef aligned_lowp_bvec2\t\t\taligned_bvec2;\n\ttypedef aligned_lowp_bvec3\t\t\taligned_bvec3;\n\ttypedef aligned_lowp_bvec4\t\t\taligned_bvec4;\n#elif(defined(GLM_PRECISION_MEDIUMP_BOOL))\n\ttypedef aligned_mediump_bvec1\t\taligned_bvec1;\n\ttypedef aligned_mediump_bvec2\t\taligned_bvec2;\n\ttypedef aligned_mediump_bvec3\t\taligned_bvec3;\n\ttypedef aligned_mediump_bvec4\t\taligned_bvec4;\n#else //defined(GLM_PRECISION_HIGHP_BOOL)\n\t/// 1 component vector aligned in memory of bool values.\n\ttypedef aligned_highp_bvec1\t\t\taligned_bvec1;\n\n\t/// 2 components vector aligned in memory of bool values.\n\ttypedef aligned_highp_bvec2\t\t\taligned_bvec2;\n\n\t/// 3 components vector aligned in memory of bool values.\n\ttypedef aligned_highp_bvec3\t\t\taligned_bvec3;\n\n\t/// 4 components vector aligned in memory of bool values.\n\ttypedef aligned_highp_bvec4\t\t\taligned_bvec4;\n\n\t/// 1 components vector tightly packed in memory of bool values.\n\ttypedef packed_highp_bvec1\t\t\tpacked_bvec1;\n\n\t/// 2 components vector tightly packed in memory of bool values.\n\ttypedef packed_highp_bvec2\t\t\tpacked_bvec2;\n\n\t/// 3 components vector tightly packed in memory of bool values.\n\ttypedef packed_highp_bvec3\t\t\tpacked_bvec3;\n\n\t/// 4 components vector tightly packed in memory of bool values.\n\ttypedef packed_highp_bvec4\t\t\tpacked_bvec4;\n#endif//GLM_PRECISION\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtc/type_precision.hpp",
    "content": "/// @ref gtc_type_precision\n/// @file glm/gtc/type_precision.hpp\n///\n/// @see core (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtc_type_precision GLM_GTC_type_precision\n/// @ingroup gtc\n///\n/// Include <glm/gtc/type_precision.hpp> to use the features of this extension.\n///\n/// Defines specific C++-based qualifier types.\n\n#pragma once\n\n// Dependency:\n#include \"../gtc/quaternion.hpp\"\n#include \"../gtc/vec1.hpp\"\n#include \"../ext/vector_int1_sized.hpp\"\n#include \"../ext/vector_int2_sized.hpp\"\n#include \"../ext/vector_int3_sized.hpp\"\n#include \"../ext/vector_int4_sized.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n#include \"../ext/vector_uint1_sized.hpp\"\n#include \"../ext/vector_uint2_sized.hpp\"\n#include \"../ext/vector_uint3_sized.hpp\"\n#include \"../ext/vector_uint4_sized.hpp\"\n#include \"../ext/scalar_uint_sized.hpp\"\n#include \"../detail/type_vec2.hpp\"\n#include \"../detail/type_vec3.hpp\"\n#include \"../detail/type_vec4.hpp\"\n#include \"../detail/type_mat2x2.hpp\"\n#include \"../detail/type_mat2x3.hpp\"\n#include \"../detail/type_mat2x4.hpp\"\n#include \"../detail/type_mat3x2.hpp\"\n#include \"../detail/type_mat3x3.hpp\"\n#include \"../detail/type_mat3x4.hpp\"\n#include \"../detail/type_mat4x2.hpp\"\n#include \"../detail/type_mat4x3.hpp\"\n#include \"../detail/type_mat4x4.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_type_precision extension included\")\n#endif\n\nnamespace glm\n{\n\t///////////////////////////\n\t// Signed int vector types\n\n\t/// @addtogroup gtc_type_precision\n\t/// @{\n\n\t/// Low qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 lowp_int8;\n\n\t/// Low qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 lowp_int16;\n\n\t/// Low qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 lowp_int32;\n\n\t/// Low qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 lowp_int64;\n\n\t/// Low qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 lowp_int8_t;\n\n\t/// Low qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 lowp_int16_t;\n\n\t/// Low qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 lowp_int32_t;\n\n\t/// Low qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 lowp_int64_t;\n\n\t/// Low qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 lowp_i8;\n\n\t/// Low qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 lowp_i16;\n\n\t/// Low qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 lowp_i32;\n\n\t/// Low qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 lowp_i64;\n\n\t/// Medium qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 mediump_int8;\n\n\t/// Medium qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 mediump_int16;\n\n\t/// Medium qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 mediump_int32;\n\n\t/// Medium qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 mediump_int64;\n\n\t/// Medium qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 mediump_int8_t;\n\n\t/// Medium qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 mediump_int16_t;\n\n\t/// Medium qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 mediump_int32_t;\n\n\t/// Medium qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 mediump_int64_t;\n\n\t/// Medium qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 mediump_i8;\n\n\t/// Medium qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 mediump_i16;\n\n\t/// Medium qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 mediump_i32;\n\n\t/// Medium qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 mediump_i64;\n\n\t/// High qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 highp_int8;\n\n\t/// High qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 highp_int16;\n\n\t/// High qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 highp_int32;\n\n\t/// High qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 highp_int64;\n\n\t/// High qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 highp_int8_t;\n\n\t/// High qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 highp_int16_t;\n\n\t/// 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 highp_int32_t;\n\n\t/// High qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 highp_int64_t;\n\n\t/// High qualifier 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 highp_i8;\n\n\t/// High qualifier 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 highp_i16;\n\n\t/// High qualifier 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 highp_i32;\n\n\t/// High qualifier 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 highp_i64;\n\n\n#if GLM_HAS_EXTENDED_INTEGER_TYPE\n\tusing std::int8_t;\n\tusing std::int16_t;\n\tusing std::int32_t;\n\tusing std::int64_t;\n#else\n\t/// 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 int8_t;\n\n\t/// 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 int16_t;\n\n\t/// 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 int32_t;\n\n\t/// 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 int64_t;\n#endif\n\n\t/// 8 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int8 i8;\n\n\t/// 16 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int16 i16;\n\n\t/// 32 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int32 i32;\n\n\t/// 64 bit signed integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::int64 i64;\n\n\t/////////////////////////////\n\t// Unsigned int vector types\n\n\t/// Low qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 lowp_uint8;\n\n\t/// Low qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 lowp_uint16;\n\n\t/// Low qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 lowp_uint32;\n\n\t/// Low qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 lowp_uint64;\n\n\t/// Low qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 lowp_uint8_t;\n\n\t/// Low qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 lowp_uint16_t;\n\n\t/// Low qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 lowp_uint32_t;\n\n\t/// Low qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 lowp_uint64_t;\n\n\t/// Low qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 lowp_u8;\n\n\t/// Low qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 lowp_u16;\n\n\t/// Low qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 lowp_u32;\n\n\t/// Low qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 lowp_u64;\n\n\t/// Medium qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 mediump_uint8;\n\n\t/// Medium qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 mediump_uint16;\n\n\t/// Medium qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 mediump_uint32;\n\n\t/// Medium qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 mediump_uint64;\n\n\t/// Medium qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 mediump_uint8_t;\n\n\t/// Medium qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 mediump_uint16_t;\n\n\t/// Medium qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 mediump_uint32_t;\n\n\t/// Medium qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 mediump_uint64_t;\n\n\t/// Medium qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 mediump_u8;\n\n\t/// Medium qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 mediump_u16;\n\n\t/// Medium qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 mediump_u32;\n\n\t/// Medium qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 mediump_u64;\n\n\t/// High qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 highp_uint8;\n\n\t/// High qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 highp_uint16;\n\n\t/// High qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 highp_uint32;\n\n\t/// High qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 highp_uint64;\n\n\t/// High qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 highp_uint8_t;\n\n\t/// High qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 highp_uint16_t;\n\n\t/// High qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 highp_uint32_t;\n\n\t/// High qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 highp_uint64_t;\n\n\t/// High qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 highp_u8;\n\n\t/// High qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 highp_u16;\n\n\t/// High qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 highp_u32;\n\n\t/// High qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 highp_u64;\n\n#if GLM_HAS_EXTENDED_INTEGER_TYPE\n\tusing std::uint8_t;\n\tusing std::uint16_t;\n\tusing std::uint32_t;\n\tusing std::uint64_t;\n#else\n\t/// Default qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 uint8_t;\n\n\t/// Default qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 uint16_t;\n\n\t/// Default qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 uint32_t;\n\n\t/// Default qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 uint64_t;\n#endif\n\n\t/// Default qualifier 8 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint8 u8;\n\n\t/// Default qualifier 16 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint16 u16;\n\n\t/// Default qualifier 32 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint32 u32;\n\n\t/// Default qualifier 64 bit unsigned integer type.\n\t/// @see gtc_type_precision\n\ttypedef detail::uint64 u64;\n\n\n\n\n\n\t//////////////////////\n\t// Float vector types\n\n\t/// Single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float float32;\n\n\t/// Double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef double float64;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_float32;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_float64;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_float32_t;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_float64_t;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_f32;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_f64;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_float32;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_float64;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_float32_t;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_float64_t;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_f32;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_f64;\n\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_float32;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_float64;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_float32_t;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_float64_t;\n\n\t/// Low 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 lowp_f32;\n\n\t/// Low 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 lowp_f64;\n\n\n\t/// Medium 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 mediump_float32;\n\n\t/// Medium 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 mediump_float64;\n\n\t/// Medium 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 mediump_float32_t;\n\n\t/// Medium 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 mediump_float64_t;\n\n\t/// Medium 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 mediump_f32;\n\n\t/// Medium 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 mediump_f64;\n\n\n\t/// High 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 highp_float32;\n\n\t/// High 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 highp_float64;\n\n\t/// High 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 highp_float32_t;\n\n\t/// High 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 highp_float64_t;\n\n\t/// High 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 highp_f32;\n\n\t/// High 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float64 highp_f64;\n\n\n#if(defined(GLM_PRECISION_LOWP_FLOAT))\n\t/// Default 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef lowp_float32_t float32_t;\n\n\t/// Default 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef lowp_float64_t float64_t;\n\n\t/// Default 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f32 f32;\n\n\t/// Default 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f64 f64;\n\n#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))\n\t/// Default 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef mediump_float32 float32_t;\n\n\t/// Default 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef mediump_float64 float64_t;\n\n\t/// Default 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef mediump_float32 f32;\n\n\t/// Default 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef mediump_float64 f64;\n\n#else//(defined(GLM_PRECISION_HIGHP_FLOAT))\n\n\t/// Default 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef highp_float32_t float32_t;\n\n\t/// Default 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef highp_float64_t float64_t;\n\n\t/// Default 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef highp_float32_t f32;\n\n\t/// Default 64 bit double-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef highp_float64_t f64;\n#endif\n\n\n\t/// Low single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, float, lowp> lowp_fvec1;\n\n\t/// Low single-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, float, lowp> lowp_fvec2;\n\n\t/// Low single-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, float, lowp> lowp_fvec3;\n\n\t/// Low single-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, float, lowp> lowp_fvec4;\n\n\n\t/// Medium single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, float, mediump> mediump_fvec1;\n\n\t/// Medium Single-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, float, mediump> mediump_fvec2;\n\n\t/// Medium Single-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, float, mediump> mediump_fvec3;\n\n\t/// Medium Single-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, float, mediump> mediump_fvec4;\n\n\n\t/// High single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, float, highp> highp_fvec1;\n\n\t/// High Single-qualifier floating-point vector of 2 components.\n\t/// @see core_precision\n\ttypedef vec<2, float, highp> highp_fvec2;\n\n\t/// High Single-qualifier floating-point vector of 3 components.\n\t/// @see core_precision\n\ttypedef vec<3, float, highp> highp_fvec3;\n\n\t/// High Single-qualifier floating-point vector of 4 components.\n\t/// @see core_precision\n\ttypedef vec<4, float, highp> highp_fvec4;\n\n\n\t/// Low single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f32, lowp> lowp_f32vec1;\n\n\t/// Low single-qualifier floating-point vector of 2 components.\n\t/// @see core_precision\n\ttypedef vec<2, f32, lowp> lowp_f32vec2;\n\n\t/// Low single-qualifier floating-point vector of 3 components.\n\t/// @see core_precision\n\ttypedef vec<3, f32, lowp> lowp_f32vec3;\n\n\t/// Low single-qualifier floating-point vector of 4 components.\n\t/// @see core_precision\n\ttypedef vec<4, f32, lowp> lowp_f32vec4;\n\n\t/// Medium single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f32, mediump> mediump_f32vec1;\n\n\t/// Medium single-qualifier floating-point vector of 2 components.\n\t/// @see core_precision\n\ttypedef vec<2, f32, mediump> mediump_f32vec2;\n\n\t/// Medium single-qualifier floating-point vector of 3 components.\n\t/// @see core_precision\n\ttypedef vec<3, f32, mediump> mediump_f32vec3;\n\n\t/// Medium single-qualifier floating-point vector of 4 components.\n\t/// @see core_precision\n\ttypedef vec<4, f32, mediump> mediump_f32vec4;\n\n\t/// High single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f32, highp> highp_f32vec1;\n\n\t/// High single-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, f32, highp> highp_f32vec2;\n\n\t/// High single-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, f32, highp> highp_f32vec3;\n\n\t/// High single-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, f32, highp> highp_f32vec4;\n\n\n\t/// Low double-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f64, lowp> lowp_f64vec1;\n\n\t/// Low double-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, f64, lowp> lowp_f64vec2;\n\n\t/// Low double-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, f64, lowp> lowp_f64vec3;\n\n\t/// Low double-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, f64, lowp> lowp_f64vec4;\n\n\t/// Medium double-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f64, mediump> mediump_f64vec1;\n\n\t/// Medium double-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, f64, mediump> mediump_f64vec2;\n\n\t/// Medium double-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, f64, mediump> mediump_f64vec3;\n\n\t/// Medium double-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, f64, mediump> mediump_f64vec4;\n\n\t/// High double-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f64, highp> highp_f64vec1;\n\n\t/// High double-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, f64, highp> highp_f64vec2;\n\n\t/// High double-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, f64, highp> highp_f64vec3;\n\n\t/// High double-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, f64, highp> highp_f64vec4;\n\n\n\n\t//////////////////////\n\t// Float matrix types\n\n\t/// Low single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef lowp_f32 lowp_fmat1x1;\n\n\t/// Low single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, lowp> lowp_fmat2x2;\n\n\t/// Low single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, lowp> lowp_fmat2x3;\n\n\t/// Low single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, lowp> lowp_fmat2x4;\n\n\t/// Low single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, lowp> lowp_fmat3x2;\n\n\t/// Low single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, lowp> lowp_fmat3x3;\n\n\t/// Low single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, lowp> lowp_fmat3x4;\n\n\t/// Low single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, lowp> lowp_fmat4x2;\n\n\t/// Low single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, lowp> lowp_fmat4x3;\n\n\t/// Low single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, lowp> lowp_fmat4x4;\n\n\t/// Low single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef lowp_fmat1x1 lowp_fmat1;\n\n\t/// Low single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_fmat2x2 lowp_fmat2;\n\n\t/// Low single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_fmat3x3 lowp_fmat3;\n\n\t/// Low single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_fmat4x4 lowp_fmat4;\n\n\n\t/// Medium single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef mediump_f32 mediump_fmat1x1;\n\n\t/// Medium single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, mediump> mediump_fmat2x2;\n\n\t/// Medium single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, mediump> mediump_fmat2x3;\n\n\t/// Medium single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, mediump> mediump_fmat2x4;\n\n\t/// Medium single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, mediump> mediump_fmat3x2;\n\n\t/// Medium single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, mediump> mediump_fmat3x3;\n\n\t/// Medium single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, mediump> mediump_fmat3x4;\n\n\t/// Medium single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, mediump> mediump_fmat4x2;\n\n\t/// Medium single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, mediump> mediump_fmat4x3;\n\n\t/// Medium single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, mediump> mediump_fmat4x4;\n\n\t/// Medium single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef mediump_fmat1x1 mediump_fmat1;\n\n\t/// Medium single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_fmat2x2 mediump_fmat2;\n\n\t/// Medium single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_fmat3x3 mediump_fmat3;\n\n\t/// Medium single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_fmat4x4 mediump_fmat4;\n\n\n\t/// High single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef highp_f32 highp_fmat1x1;\n\n\t/// High single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, highp> highp_fmat2x2;\n\n\t/// High single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, highp> highp_fmat2x3;\n\n\t/// High single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, highp> highp_fmat2x4;\n\n\t/// High single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, highp> highp_fmat3x2;\n\n\t/// High single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, highp> highp_fmat3x3;\n\n\t/// High single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, highp> highp_fmat3x4;\n\n\t/// High single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, highp> highp_fmat4x2;\n\n\t/// High single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, highp> highp_fmat4x3;\n\n\t/// High single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, highp> highp_fmat4x4;\n\n\t/// High single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef highp_fmat1x1 highp_fmat1;\n\n\t/// High single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_fmat2x2 highp_fmat2;\n\n\t/// High single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_fmat3x3 highp_fmat3;\n\n\t/// High single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_fmat4x4 highp_fmat4;\n\n\n\t/// Low single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f32 lowp_f32mat1x1;\n\n\t/// Low single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, lowp> lowp_f32mat2x2;\n\n\t/// Low single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, lowp> lowp_f32mat2x3;\n\n\t/// Low single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, lowp> lowp_f32mat2x4;\n\n\t/// Low single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, lowp> lowp_f32mat3x2;\n\n\t/// Low single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, lowp> lowp_f32mat3x3;\n\n\t/// Low single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, lowp> lowp_f32mat3x4;\n\n\t/// Low single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, lowp> lowp_f32mat4x2;\n\n\t/// Low single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, lowp> lowp_f32mat4x3;\n\n\t/// Low single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, lowp> lowp_f32mat4x4;\n\n\t/// Low single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef detail::tmat1x1<f32, lowp> lowp_f32mat1;\n\n\t/// Low single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f32mat2x2 lowp_f32mat2;\n\n\t/// Low single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f32mat3x3 lowp_f32mat3;\n\n\t/// Low single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f32mat4x4 lowp_f32mat4;\n\n\n\t/// High single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f32 mediump_f32mat1x1;\n\n\t/// Low single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, mediump> mediump_f32mat2x2;\n\n\t/// Medium single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, mediump> mediump_f32mat2x3;\n\n\t/// Medium single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, mediump> mediump_f32mat2x4;\n\n\t/// Medium single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, mediump> mediump_f32mat3x2;\n\n\t/// Medium single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, mediump> mediump_f32mat3x3;\n\n\t/// Medium single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, mediump> mediump_f32mat3x4;\n\n\t/// Medium single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, mediump> mediump_f32mat4x2;\n\n\t/// Medium single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, mediump> mediump_f32mat4x3;\n\n\t/// Medium single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, mediump> mediump_f32mat4x4;\n\n\t/// Medium single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef detail::tmat1x1<f32, mediump> f32mat1;\n\n\t/// Medium single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_f32mat2x2 mediump_f32mat2;\n\n\t/// Medium single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_f32mat3x3 mediump_f32mat3;\n\n\t/// Medium single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_f32mat4x4 mediump_f32mat4;\n\n\n\t/// High single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f32 highp_f32mat1x1;\n\n\t/// High single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, highp> highp_f32mat2x2;\n\n\t/// High single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, highp> highp_f32mat2x3;\n\n\t/// High single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, highp> highp_f32mat2x4;\n\n\t/// High single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, highp> highp_f32mat3x2;\n\n\t/// High single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, highp> highp_f32mat3x3;\n\n\t/// High single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, highp> highp_f32mat3x4;\n\n\t/// High single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, highp> highp_f32mat4x2;\n\n\t/// High single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, highp> highp_f32mat4x3;\n\n\t/// High single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, highp> highp_f32mat4x4;\n\n\t/// High single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef detail::tmat1x1<f32, highp> f32mat1;\n\n\t/// High single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_f32mat2x2 highp_f32mat2;\n\n\t/// High single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_f32mat3x3 highp_f32mat3;\n\n\t/// High single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_f32mat4x4 highp_f32mat4;\n\n\n\t/// Low double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f64 lowp_f64mat1x1;\n\n\t/// Low double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f64, lowp> lowp_f64mat2x2;\n\n\t/// Low double-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f64, lowp> lowp_f64mat2x3;\n\n\t/// Low double-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f64, lowp> lowp_f64mat2x4;\n\n\t/// Low double-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f64, lowp> lowp_f64mat3x2;\n\n\t/// Low double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f64, lowp> lowp_f64mat3x3;\n\n\t/// Low double-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f64, lowp> lowp_f64mat3x4;\n\n\t/// Low double-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f64, lowp> lowp_f64mat4x2;\n\n\t/// Low double-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f64, lowp> lowp_f64mat4x3;\n\n\t/// Low double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f64, lowp> lowp_f64mat4x4;\n\n\t/// Low double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef lowp_f64mat1x1 lowp_f64mat1;\n\n\t/// Low double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f64mat2x2 lowp_f64mat2;\n\n\t/// Low double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f64mat3x3 lowp_f64mat3;\n\n\t/// Low double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef lowp_f64mat4x4 lowp_f64mat4;\n\n\n\t/// Medium double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f64 Highp_f64mat1x1;\n\n\t/// Medium double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f64, mediump> mediump_f64mat2x2;\n\n\t/// Medium double-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f64, mediump> mediump_f64mat2x3;\n\n\t/// Medium double-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f64, mediump> mediump_f64mat2x4;\n\n\t/// Medium double-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f64, mediump> mediump_f64mat3x2;\n\n\t/// Medium double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f64, mediump> mediump_f64mat3x3;\n\n\t/// Medium double-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f64, mediump> mediump_f64mat3x4;\n\n\t/// Medium double-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f64, mediump> mediump_f64mat4x2;\n\n\t/// Medium double-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f64, mediump> mediump_f64mat4x3;\n\n\t/// Medium double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f64, mediump> mediump_f64mat4x4;\n\n\t/// Medium double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef mediump_f64mat1x1 mediump_f64mat1;\n\n\t/// Medium double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_f64mat2x2 mediump_f64mat2;\n\n\t/// Medium double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_f64mat3x3 mediump_f64mat3;\n\n\t/// Medium double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mediump_f64mat4x4 mediump_f64mat4;\n\n\t/// High double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f64 highp_f64mat1x1;\n\n\t/// High double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f64, highp> highp_f64mat2x2;\n\n\t/// High double-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f64, highp> highp_f64mat2x3;\n\n\t/// High double-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f64, highp> highp_f64mat2x4;\n\n\t/// High double-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f64, highp> highp_f64mat3x2;\n\n\t/// High double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f64, highp> highp_f64mat3x3;\n\n\t/// High double-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f64, highp> highp_f64mat3x4;\n\n\t/// High double-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f64, highp> highp_f64mat4x2;\n\n\t/// High double-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f64, highp> highp_f64mat4x3;\n\n\t/// High double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f64, highp> highp_f64mat4x4;\n\n\t/// High double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef highp_f64mat1x1 highp_f64mat1;\n\n\t/// High double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_f64mat2x2 highp_f64mat2;\n\n\t/// High double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_f64mat3x3 highp_f64mat3;\n\n\t/// High double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef highp_f64mat4x4 highp_f64mat4;\n\n\n\t/////////////////////////////\n\t// Signed int vector types\n\n\t/// Low qualifier signed integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, int, lowp>\t\tlowp_ivec1;\n\n\t/// Low qualifier signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, int, lowp>\t\tlowp_ivec2;\n\n\t/// Low qualifier signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, int, lowp>\t\tlowp_ivec3;\n\n\t/// Low qualifier signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, int, lowp>\t\tlowp_ivec4;\n\n\n\t/// Medium qualifier signed integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, int, mediump>\tmediump_ivec1;\n\n\t/// Medium qualifier signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, int, mediump>\tmediump_ivec2;\n\n\t/// Medium qualifier signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, int, mediump>\tmediump_ivec3;\n\n\t/// Medium qualifier signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, int, mediump>\tmediump_ivec4;\n\n\n\t/// High qualifier signed integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, int, highp>\t\thighp_ivec1;\n\n\t/// High qualifier signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, int, highp>\t\thighp_ivec2;\n\n\t/// High qualifier signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, int, highp>\t\thighp_ivec3;\n\n\t/// High qualifier signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, int, highp>\t\thighp_ivec4;\n\n\n\t/// Low qualifier 8 bit signed integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i8, lowp>\t\tlowp_i8vec1;\n\n\t/// Low qualifier 8 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i8, lowp>\t\tlowp_i8vec2;\n\n\t/// Low qualifier 8 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i8, lowp>\t\tlowp_i8vec3;\n\n\t/// Low qualifier 8 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i8, lowp>\t\tlowp_i8vec4;\n\n\n\t/// Medium qualifier 8 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i8, mediump>\t\tmediump_i8vec1;\n\n\t/// Medium qualifier 8 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i8, mediump>\t\tmediump_i8vec2;\n\n\t/// Medium qualifier 8 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i8, mediump>\t\tmediump_i8vec3;\n\n\t/// Medium qualifier 8 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i8, mediump>\t\tmediump_i8vec4;\n\n\n\t/// High qualifier 8 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i8, highp>\t\thighp_i8vec1;\n\n\t/// High qualifier 8 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i8, highp>\t\thighp_i8vec2;\n\n\t/// High qualifier 8 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i8, highp>\t\thighp_i8vec3;\n\n\t/// High qualifier 8 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i8, highp>\t\thighp_i8vec4;\n\n\n\t/// Low qualifier 16 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i16, lowp>\t\tlowp_i16vec1;\n\n\t/// Low qualifier 16 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i16, lowp>\t\tlowp_i16vec2;\n\n\t/// Low qualifier 16 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i16, lowp>\t\tlowp_i16vec3;\n\n\t/// Low qualifier 16 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i16, lowp>\t\tlowp_i16vec4;\n\n\n\t/// Medium qualifier 16 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i16, mediump>\tmediump_i16vec1;\n\n\t/// Medium qualifier 16 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i16, mediump>\tmediump_i16vec2;\n\n\t/// Medium qualifier 16 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i16, mediump>\tmediump_i16vec3;\n\n\t/// Medium qualifier 16 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i16, mediump>\tmediump_i16vec4;\n\n\n\t/// High qualifier 16 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i16, highp>\t\thighp_i16vec1;\n\n\t/// High qualifier 16 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i16, highp>\t\thighp_i16vec2;\n\n\t/// High qualifier 16 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i16, highp>\t\thighp_i16vec3;\n\n\t/// High qualifier 16 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i16, highp>\t\thighp_i16vec4;\n\n\n\t/// Low qualifier 32 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i32, lowp>\t\tlowp_i32vec1;\n\n\t/// Low qualifier 32 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i32, lowp>\t\tlowp_i32vec2;\n\n\t/// Low qualifier 32 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i32, lowp>\t\tlowp_i32vec3;\n\n\t/// Low qualifier 32 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i32, lowp>\t\tlowp_i32vec4;\n\n\n\t/// Medium qualifier 32 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i32, mediump>\tmediump_i32vec1;\n\n\t/// Medium qualifier 32 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i32, mediump>\tmediump_i32vec2;\n\n\t/// Medium qualifier 32 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i32, mediump>\tmediump_i32vec3;\n\n\t/// Medium qualifier 32 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i32, mediump>\tmediump_i32vec4;\n\n\n\t/// High qualifier 32 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i32, highp>\t\thighp_i32vec1;\n\n\t/// High qualifier 32 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i32, highp>\t\thighp_i32vec2;\n\n\t/// High qualifier 32 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i32, highp>\t\thighp_i32vec3;\n\n\t/// High qualifier 32 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i32, highp>\t\thighp_i32vec4;\n\n\n\t/// Low qualifier 64 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i64, lowp>\t\tlowp_i64vec1;\n\n\t/// Low qualifier 64 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i64, lowp>\t\tlowp_i64vec2;\n\n\t/// Low qualifier 64 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i64, lowp>\t\tlowp_i64vec3;\n\n\t/// Low qualifier 64 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i64, lowp>\t\tlowp_i64vec4;\n\n\n\t/// Medium qualifier 64 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i64, mediump>\tmediump_i64vec1;\n\n\t/// Medium qualifier 64 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i64, mediump>\tmediump_i64vec2;\n\n\t/// Medium qualifier 64 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i64, mediump>\tmediump_i64vec3;\n\n\t/// Medium qualifier 64 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i64, mediump>\tmediump_i64vec4;\n\n\n\t/// High qualifier 64 bit signed integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, i64, highp>\t\thighp_i64vec1;\n\n\t/// High qualifier 64 bit signed integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, i64, highp>\t\thighp_i64vec2;\n\n\t/// High qualifier 64 bit signed integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, i64, highp>\t\thighp_i64vec3;\n\n\t/// High qualifier 64 bit signed integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, i64, highp>\t\thighp_i64vec4;\n\n\n\t/////////////////////////////\n\t// Unsigned int vector types\n\n\t/// Low qualifier unsigned integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, uint, lowp>\t\tlowp_uvec1;\n\n\t/// Low qualifier unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, uint, lowp>\t\tlowp_uvec2;\n\n\t/// Low qualifier unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, uint, lowp>\t\tlowp_uvec3;\n\n\t/// Low qualifier unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, uint, lowp>\t\tlowp_uvec4;\n\n\n\t/// Medium qualifier unsigned integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, uint, mediump>\tmediump_uvec1;\n\n\t/// Medium qualifier unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, uint, mediump>\tmediump_uvec2;\n\n\t/// Medium qualifier unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, uint, mediump>\tmediump_uvec3;\n\n\t/// Medium qualifier unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, uint, mediump>\tmediump_uvec4;\n\n\n\t/// High qualifier unsigned integer vector of 1 component type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, uint, highp>\t\thighp_uvec1;\n\n\t/// High qualifier unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, uint, highp>\t\thighp_uvec2;\n\n\t/// High qualifier unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, uint, highp>\t\thighp_uvec3;\n\n\t/// High qualifier unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, uint, highp>\t\thighp_uvec4;\n\n\n\t/// Low qualifier 8 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u8, lowp>\t\tlowp_u8vec1;\n\n\t/// Low qualifier 8 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u8, lowp>\t\tlowp_u8vec2;\n\n\t/// Low qualifier 8 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u8, lowp>\t\tlowp_u8vec3;\n\n\t/// Low qualifier 8 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u8, lowp>\t\tlowp_u8vec4;\n\n\n\t/// Medium qualifier 8 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u8, mediump>\t\tmediump_u8vec1;\n\n\t/// Medium qualifier 8 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u8, mediump>\t\tmediump_u8vec2;\n\n\t/// Medium qualifier 8 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u8, mediump>\t\tmediump_u8vec3;\n\n\t/// Medium qualifier 8 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u8, mediump>\t\tmediump_u8vec4;\n\n\n\t/// High qualifier 8 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u8, highp>\t\thighp_u8vec1;\n\n\t/// High qualifier 8 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u8, highp>\t\thighp_u8vec2;\n\n\t/// High qualifier 8 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u8, highp>\t\thighp_u8vec3;\n\n\t/// High qualifier 8 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u8, highp>\t\thighp_u8vec4;\n\n\n\t/// Low qualifier 16 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u16, lowp>\t\tlowp_u16vec1;\n\n\t/// Low qualifier 16 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u16, lowp>\t\tlowp_u16vec2;\n\n\t/// Low qualifier 16 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u16, lowp>\t\tlowp_u16vec3;\n\n\t/// Low qualifier 16 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u16, lowp>\t\tlowp_u16vec4;\n\n\n\t/// Medium qualifier 16 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u16, mediump>\tmediump_u16vec1;\n\n\t/// Medium qualifier 16 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u16, mediump>\tmediump_u16vec2;\n\n\t/// Medium qualifier 16 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u16, mediump>\tmediump_u16vec3;\n\n\t/// Medium qualifier 16 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u16, mediump>\tmediump_u16vec4;\n\n\n\t/// High qualifier 16 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u16, highp>\t\thighp_u16vec1;\n\n\t/// High qualifier 16 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u16, highp>\t\thighp_u16vec2;\n\n\t/// High qualifier 16 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u16, highp>\t\thighp_u16vec3;\n\n\t/// High qualifier 16 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u16, highp>\t\thighp_u16vec4;\n\n\n\t/// Low qualifier 32 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u32, lowp>\t\tlowp_u32vec1;\n\n\t/// Low qualifier 32 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u32, lowp>\t\tlowp_u32vec2;\n\n\t/// Low qualifier 32 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u32, lowp>\t\tlowp_u32vec3;\n\n\t/// Low qualifier 32 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u32, lowp>\t\tlowp_u32vec4;\n\n\n\t/// Medium qualifier 32 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u32, mediump>\tmediump_u32vec1;\n\n\t/// Medium qualifier 32 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u32, mediump>\tmediump_u32vec2;\n\n\t/// Medium qualifier 32 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u32, mediump>\tmediump_u32vec3;\n\n\t/// Medium qualifier 32 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u32, mediump>\tmediump_u32vec4;\n\n\n\t/// High qualifier 32 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u32, highp>\t\thighp_u32vec1;\n\n\t/// High qualifier 32 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u32, highp>\t\thighp_u32vec2;\n\n\t/// High qualifier 32 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u32, highp>\t\thighp_u32vec3;\n\n\t/// High qualifier 32 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u32, highp>\t\thighp_u32vec4;\n\n\n\t/// Low qualifier 64 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u64, lowp>\t\tlowp_u64vec1;\n\n\t/// Low qualifier 64 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u64, lowp>\t\tlowp_u64vec2;\n\n\t/// Low qualifier 64 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u64, lowp>\t\tlowp_u64vec3;\n\n\t/// Low qualifier 64 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u64, lowp>\t\tlowp_u64vec4;\n\n\n\t/// Medium qualifier 64 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u64, mediump>\tmediump_u64vec1;\n\n\t/// Medium qualifier 64 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u64, mediump>\tmediump_u64vec2;\n\n\t/// Medium qualifier 64 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u64, mediump>\tmediump_u64vec3;\n\n\t/// Medium qualifier 64 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u64, mediump>\tmediump_u64vec4;\n\n\n\t/// High qualifier 64 bit unsigned integer scalar type.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, u64, highp>\t\thighp_u64vec1;\n\n\t/// High qualifier 64 bit unsigned integer vector of 2 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, u64, highp>\t\thighp_u64vec2;\n\n\t/// High qualifier 64 bit unsigned integer vector of 3 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, u64, highp>\t\thighp_u64vec3;\n\n\t/// High qualifier 64 bit unsigned integer vector of 4 components type.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, u64, highp>\t\thighp_u64vec4;\n\n\n\t//////////////////////\n\t// Float vector types\n\n\t/// 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 float32_t;\n\n\t/// 32 bit single-qualifier floating-point scalar.\n\t/// @see gtc_type_precision\n\ttypedef float32 f32;\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t\t/// 64 bit double-qualifier floating-point scalar.\n\t\t/// @see gtc_type_precision\n\t\ttypedef float64 float64_t;\n\n\t\t/// 64 bit double-qualifier floating-point scalar.\n\t\t/// @see gtc_type_precision\n\t\ttypedef float64 f64;\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\t/// Single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, float, defaultp> fvec1;\n\n\t/// Single-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, float, defaultp> fvec2;\n\n\t/// Single-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, float, defaultp> fvec3;\n\n\t/// Single-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, float, defaultp> fvec4;\n\n\n\t/// Single-qualifier floating-point vector of 1 component.\n\t/// @see gtc_type_precision\n\ttypedef vec<1, f32, defaultp> f32vec1;\n\n\t/// Single-qualifier floating-point vector of 2 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<2, f32, defaultp> f32vec2;\n\n\t/// Single-qualifier floating-point vector of 3 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<3, f32, defaultp> f32vec3;\n\n\t/// Single-qualifier floating-point vector of 4 components.\n\t/// @see gtc_type_precision\n\ttypedef vec<4, f32, defaultp> f32vec4;\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\t\t/// Double-qualifier floating-point vector of 1 component.\n\t\t/// @see gtc_type_precision\n\t\ttypedef vec<1, f64, defaultp> f64vec1;\n\n\t\t/// Double-qualifier floating-point vector of 2 components.\n\t\t/// @see gtc_type_precision\n\t\ttypedef vec<2, f64, defaultp> f64vec2;\n\n\t\t/// Double-qualifier floating-point vector of 3 components.\n\t\t/// @see gtc_type_precision\n\t\ttypedef vec<3, f64, defaultp> f64vec3;\n\n\t\t/// Double-qualifier floating-point vector of 4 components.\n\t\t/// @see gtc_type_precision\n\t\ttypedef vec<4, f64, defaultp> f64vec4;\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\n\t//////////////////////\n\t// Float matrix types\n\n\t/// Single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef detail::tmat1x1<f32> fmat1;\n\n\t/// Single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, defaultp> fmat2;\n\n\t/// Single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, defaultp> fmat3;\n\n\t/// Single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, defaultp> fmat4;\n\n\n\t/// Single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f32 fmat1x1;\n\n\t/// Single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, defaultp> fmat2x2;\n\n\t/// Single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, defaultp> fmat2x3;\n\n\t/// Single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, defaultp> fmat2x4;\n\n\t/// Single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, defaultp> fmat3x2;\n\n\t/// Single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, defaultp> fmat3x3;\n\n\t/// Single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, defaultp> fmat3x4;\n\n\t/// Single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, defaultp> fmat4x2;\n\n\t/// Single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, defaultp> fmat4x3;\n\n\t/// Single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, defaultp> fmat4x4;\n\n\n\t/// Single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef detail::tmat1x1<f32, defaultp> f32mat1;\n\n\t/// Single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, defaultp> f32mat2;\n\n\t/// Single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, defaultp> f32mat3;\n\n\t/// Single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, defaultp> f32mat4;\n\n\n\t/// Single-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f32 f32mat1x1;\n\n\t/// Single-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f32, defaultp> f32mat2x2;\n\n\t/// Single-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f32, defaultp> f32mat2x3;\n\n\t/// Single-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f32, defaultp> f32mat2x4;\n\n\t/// Single-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f32, defaultp> f32mat3x2;\n\n\t/// Single-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f32, defaultp> f32mat3x3;\n\n\t/// Single-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f32, defaultp> f32mat3x4;\n\n\t/// Single-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f32, defaultp> f32mat4x2;\n\n\t/// Single-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f32, defaultp> f32mat4x3;\n\n\t/// Single-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f32, defaultp> f32mat4x4;\n\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t/// Double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef detail::tmat1x1<f64, defaultp> f64mat1;\n\n\t/// Double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f64, defaultp> f64mat2;\n\n\t/// Double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f64, defaultp> f64mat3;\n\n\t/// Double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f64, defaultp> f64mat4;\n\n\n\t/// Double-qualifier floating-point 1x1 matrix.\n\t/// @see gtc_type_precision\n\t//typedef f64 f64mat1x1;\n\n\t/// Double-qualifier floating-point 2x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 2, f64, defaultp> f64mat2x2;\n\n\t/// Double-qualifier floating-point 2x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 3, f64, defaultp> f64mat2x3;\n\n\t/// Double-qualifier floating-point 2x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<2, 4, f64, defaultp> f64mat2x4;\n\n\t/// Double-qualifier floating-point 3x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 2, f64, defaultp> f64mat3x2;\n\n\t/// Double-qualifier floating-point 3x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 3, f64, defaultp> f64mat3x3;\n\n\t/// Double-qualifier floating-point 3x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<3, 4, f64, defaultp> f64mat3x4;\n\n\t/// Double-qualifier floating-point 4x2 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 2, f64, defaultp> f64mat4x2;\n\n\t/// Double-qualifier floating-point 4x3 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 3, f64, defaultp> f64mat4x3;\n\n\t/// Double-qualifier floating-point 4x4 matrix.\n\t/// @see gtc_type_precision\n\ttypedef mat<4, 4, f64, defaultp> f64mat4x4;\n\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\t//////////////////////////\n\t// Quaternion types\n\n\t/// Single-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f32, defaultp> f32quat;\n\n\t/// Low single-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f32, lowp> lowp_f32quat;\n\n\t/// Low double-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f64, lowp> lowp_f64quat;\n\n\t/// Medium single-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f32, mediump> mediump_f32quat;\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t/// Medium double-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f64, mediump> mediump_f64quat;\n\n\t/// High single-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f32, highp> highp_f32quat;\n\n\t/// High double-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f64, highp> highp_f64quat;\n\n\t/// Double-qualifier floating-point quaternion.\n\t/// @see gtc_type_precision\n\ttypedef qua<f64, defaultp> f64quat;\n\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\t/// @}\n}//namespace glm\n\n#include \"type_precision.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/type_precision.inl",
    "content": "/// @ref gtc_precision\n\nnamespace glm\n{\n\n}\n"
  },
  {
    "path": "lib/gli/glm/gtc/type_ptr.hpp",
    "content": "/// @ref gtc_type_ptr\n/// @file glm/gtc/type_ptr.hpp\n///\n/// @see core (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtc_type_ptr GLM_GTC_type_ptr\n/// @ingroup gtc\n///\n/// Include <glm/gtc/type_ptr.hpp> to use the features of this extension.\n///\n/// Handles the interaction between pointers and vector, matrix types.\n///\n/// This extension defines an overloaded function, glm::value_ptr. It returns\n/// a pointer to the memory layout of the object. Matrix types store their values\n/// in column-major order.\n///\n/// This is useful for uploading data to matrices or copying data to buffer objects.\n///\n/// Example:\n/// @code\n/// #include <glm/glm.hpp>\n/// #include <glm/gtc/type_ptr.hpp>\n///\n/// glm::vec3 aVector(3);\n/// glm::mat4 someMatrix(1.0);\n///\n/// glUniform3fv(uniformLoc, 1, glm::value_ptr(aVector));\n/// glUniformMatrix4fv(uniformMatrixLoc, 1, GL_FALSE, glm::value_ptr(someMatrix));\n/// @endcode\n///\n/// <glm/gtc/type_ptr.hpp> need to be included to use the features of this extension.\n\n#pragma once\n\n// Dependency:\n#include \"../gtc/quaternion.hpp\"\n#include \"../gtc/vec1.hpp\"\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../mat2x2.hpp\"\n#include \"../mat2x3.hpp\"\n#include \"../mat2x4.hpp\"\n#include \"../mat3x2.hpp\"\n#include \"../mat3x3.hpp\"\n#include \"../mat3x4.hpp\"\n#include \"../mat4x2.hpp\"\n#include \"../mat4x3.hpp\"\n#include \"../mat4x4.hpp\"\n#include <cstring>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_type_ptr extension included\")\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtc_type_ptr\n\t/// @{\n\n\t/// Return the constant address to the data of the input parameter.\n\t/// @see gtc_type_ptr\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::value_type const * value_ptr(genType const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<1, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<2, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<3, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<1, T, Q> make_vec1(vec<4, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<1, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<2, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<3, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<2, T, Q> make_vec2(vec<4, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<1, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<2, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<3, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> make_vec3(vec<4, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<1, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<2, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<3, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> make_vec4(vec<4, T, Q> const& v);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<2, T, defaultp> make_vec2(T const * const ptr);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<3, T, defaultp> make_vec3(T const * const ptr);\n\n\t/// Build a vector from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL vec<4, T, defaultp> make_vec4(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2x2(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<2, 3, T, defaultp> make_mat2x3(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<2, 4, T, defaultp> make_mat2x4(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<3, 2, T, defaultp> make_mat3x2(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3x3(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<3, 4, T, defaultp> make_mat3x4(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 2, T, defaultp> make_mat4x2(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 3, T, defaultp> make_mat4x3(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4x4(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<2, 2, T, defaultp> make_mat2(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<3, 3, T, defaultp> make_mat3(T const * const ptr);\n\n\t/// Build a matrix from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> make_mat4(T const * const ptr);\n\n\t/// Build a quaternion from a pointer.\n\t/// @see gtc_type_ptr\n\ttemplate<typename T>\n\tGLM_FUNC_DECL qua<T, defaultp> make_quat(T const * const ptr);\n\n\t/// @}\n}//namespace glm\n\n#include \"type_ptr.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/type_ptr.inl",
    "content": "/// @ref gtc_type_ptr\n\n#include <cstring>\n\nnamespace glm\n{\n\t/// @addtogroup gtc_type_ptr\n\t/// @{\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(vec<2, T, Q> const& v)\n\t{\n\t\treturn &(v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(vec<2, T, Q>& v)\n\t{\n\t\treturn &(v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const * value_ptr(vec<3, T, Q> const& v)\n\t{\n\t\treturn &(v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(vec<3, T, Q>& v)\n\t{\n\t\treturn &(v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(vec<4, T, Q> const& v)\n\t{\n\t\treturn &(v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(vec<4, T, Q>& v)\n\t{\n\t\treturn &(v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<2, 2, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 3, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<3, 3, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<4, 4, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 3, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<2, 3, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 2, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<3, 2, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<2, 4, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<2, 4, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 2, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<4, 2, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<3, 4, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(mat<3, 4, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const* value_ptr(mat<4, 3, T, Q> const& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T * value_ptr(mat<4, 3, T, Q>& m)\n\t{\n\t\treturn &(m[0].x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T const * value_ptr(qua<T, Q> const& q)\n\t{\n\t\treturn &(q[0]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T* value_ptr(qua<T, Q>& q)\n\t{\n\t\treturn &(q[0]);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<1, T, Q> make_vec1(vec<1, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<1, T, Q> make_vec1(vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(v);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<1, T, Q> make_vec1(vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(v);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<1, T, Q> make_vec1(vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<1, T, Q>(v);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<2, T, Q> make_vec2(vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(v.x, static_cast<T>(0));\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<2, T, Q> make_vec2(vec<2, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<2, T, Q> make_vec2(vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(v);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<2, T, Q> make_vec2(vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<2, T, Q>(v);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<3, T, Q> make_vec3(vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(v.x, static_cast<T>(0), static_cast<T>(0));\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<3, T, Q> make_vec3(vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(v.x, v.y, static_cast<T>(0));\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<3, T, Q> make_vec3(vec<3, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<3, T, Q> make_vec3(vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<3, T, Q>(v);\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<4, T, Q> make_vec4(vec<1, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(v.x, static_cast<T>(0), static_cast<T>(0), static_cast<T>(1));\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<4, T, Q> make_vec4(vec<2, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(v.x, v.y, static_cast<T>(0), static_cast<T>(1));\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<4, T, Q> make_vec4(vec<3, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(v.x, v.y, v.z, static_cast<T>(1));\n\t}\n\n\ttemplate <typename T, qualifier Q>\n\tinline vec<4, T, Q> make_vec4(vec<4, T, Q> const& v)\n\t{\n\t\treturn v;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<2, T, defaultp> make_vec2(T const *const ptr)\n\t{\n\t\tvec<2, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(vec<2, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<3, T, defaultp> make_vec3(T const *const ptr)\n\t{\n\t\tvec<3, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(vec<3, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER vec<4, T, defaultp> make_vec4(T const *const ptr)\n\t{\n\t\tvec<4, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(vec<4, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2x2(T const *const ptr)\n\t{\n\t\tmat<2, 2, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<2, 2, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, defaultp> make_mat2x3(T const *const ptr)\n\t{\n\t\tmat<2, 3, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<2, 3, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, defaultp> make_mat2x4(T const *const ptr)\n\t{\n\t\tmat<2, 4, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<2, 4, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, defaultp> make_mat3x2(T const *const ptr)\n\t{\n\t\tmat<3, 2, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<3, 2, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3x3(T const *const ptr)\n\t{\n\t\tmat<3, 3, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<3, 3, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, defaultp> make_mat3x4(T const *const ptr)\n\t{\n\t\tmat<3, 4, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<3, 4, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, defaultp> make_mat4x2(T const *const ptr)\n\t{\n\t\tmat<4, 2, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<4, 2, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, defaultp> make_mat4x3(T const *const ptr)\n\t{\n\t\tmat<4, 3, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<4, 3, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4x4(T const *const ptr)\n\t{\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(mat<4, 4, T, defaultp>));\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> make_mat2(T const *const ptr)\n\t{\n\t\treturn make_mat2x2(ptr);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> make_mat3(T const *const ptr)\n\t{\n\t\treturn make_mat3x3(ptr);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> make_mat4(T const *const ptr)\n\t{\n\t\treturn make_mat4x4(ptr);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER qua<T, defaultp> make_quat(T const *const ptr)\n\t{\n\t\tqua<T, defaultp> Result;\n\t\tmemcpy(value_ptr(Result), ptr, sizeof(qua<T, defaultp>));\n\t\treturn Result;\n\t}\n\n\t/// @}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtc/ulp.hpp",
    "content": "/// @ref gtc_ulp\n/// @file glm/gtc/ulp.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_ulp GLM_GTC_ulp\n/// @ingroup gtc\n///\n/// Include <glm/gtc/ulp.hpp> to use the features of this extension.\n///\n/// Allow the measurement of the accuracy of a function against a reference\n/// implementation. This extension works on floating-point data and provide results\n/// in ULP.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/_vectorize.hpp\"\n#include \"../ext/scalar_int_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_ulp extension included\")\n#endif\n\nnamespace glm\n{\n\t/// Return the next ULP value(s) after the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see gtc_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType next_float(genType x);\n\n\t/// Return the previous ULP value(s) before the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see gtc_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType prev_float(genType x);\n\n\t/// Return the value(s) ULP distance after the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see gtc_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType next_float(genType x, int ULPs);\n\n\t/// Return the value(s) ULP distance before the input value(s).\n\t///\n\t/// @tparam genType A floating-point scalar type.\n\t///\n\t/// @see gtc_ulp\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType prev_float(genType x, int ULPs);\n\n\t/// Return the distance in the number of ULP between 2 single-precision floating-point scalars.\n\t///\n\t/// @see gtc_ulp\n\tGLM_FUNC_DECL int float_distance(float x, float y);\n\n\t/// Return the distance in the number of ULP between 2 double-precision floating-point scalars.\n\t///\n\t/// @see gtc_ulp\n\tGLM_FUNC_DECL int64 float_distance(double x, double y);\n\n\t/// Return the next ULP value(s) after the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> next_float(vec<L, T, Q> const& x);\n\n\t/// Return the value(s) ULP distance after the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> next_float(vec<L, T, Q> const& x, int ULPs);\n\n\t/// Return the value(s) ULP distance after the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> next_float(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs);\n\n\t/// Return the previous ULP value(s) before the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prev_float(vec<L, T, Q> const& x);\n\n\t/// Return the value(s) ULP distance before the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prev_float(vec<L, T, Q> const& x, int ULPs);\n\n\t/// Return the value(s) ULP distance before the input value(s).\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> prev_float(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs);\n\n\t/// Return the distance in the number of ULP between 2 single-precision floating-point scalars.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> float_distance(vec<L, float, Q> const& x, vec<L, float, Q> const& y);\n\n\t/// Return the distance in the number of ULP between 2 double-precision floating-point scalars.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see gtc_ulp\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int64, Q> float_distance(vec<L, double, Q> const& x, vec<L, double, Q> const& y);\n\n\t/// @}\n}//namespace glm\n\n#include \"ulp.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtc/ulp.inl",
    "content": "/// @ref gtc_ulp\n\n#include \"../ext/scalar_ulp.hpp\"\n\nnamespace glm\n{\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER float next_float(float x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\treturn std::nextafter(x, std::numeric_limits<float>::max());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\treturn detail::nextafterf(x, FLT_MAX);\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\treturn __builtin_nextafterf(x, FLT_MAX);\n#\t\telse\n\t\treturn nextafterf(x, FLT_MAX);\n#\t\tendif\n\t}\n\n\ttemplate<>\n\tGLM_FUNC_QUALIFIER double next_float(double x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\treturn std::nextafter(x, std::numeric_limits<double>::max());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\treturn detail::nextafter(x, std::numeric_limits<double>::max());\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\treturn __builtin_nextafter(x, DBL_MAX);\n#\t\telse\n\t\treturn nextafter(x, DBL_MAX);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T next_float(T x, int ULPs)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'next_float' only accept floating-point input\");\n\t\tassert(ULPs >= 0);\n\n\t\tT temp = x;\n\t\tfor (int i = 0; i < ULPs; ++i)\n\t\t\ttemp = next_float(temp);\n\t\treturn temp;\n\t}\n\n\tGLM_FUNC_QUALIFIER float prev_float(float x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\treturn std::nextafter(x, std::numeric_limits<float>::min());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\treturn detail::nextafterf(x, FLT_MIN);\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\treturn __builtin_nextafterf(x, FLT_MIN);\n#\t\telse\n\t\treturn nextafterf(x, FLT_MIN);\n#\t\tendif\n\t}\n\n\tGLM_FUNC_QUALIFIER double prev_float(double x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\treturn std::nextafter(x, std::numeric_limits<double>::min());\n#\t\telif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))\n\t\treturn _nextafter(x, DBL_MIN);\n#\t\telif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n\t\treturn __builtin_nextafter(x, DBL_MIN);\n#\t\telse\n\t\treturn nextafter(x, DBL_MIN);\n#\t\tendif\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T prev_float(T x, int ULPs)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'prev_float' only accept floating-point input\");\n\t\tassert(ULPs >= 0);\n\n\t\tT temp = x;\n\t\tfor (int i = 0; i < ULPs; ++i)\n\t\t\ttemp = prev_float(temp);\n\t\treturn temp;\n\t}\n\n\tGLM_FUNC_QUALIFIER int float_distance(float x, float y)\n\t{\n\t\tdetail::float_t<float> const a(x);\n\t\tdetail::float_t<float> const b(y);\n\n\t\treturn abs(a.i - b.i);\n\t}\n\n\tGLM_FUNC_QUALIFIER int64 float_distance(double x, double y)\n\t{\n\t\tdetail::float_t<double> const a(x);\n\t\tdetail::float_t<double> const b(y);\n\n\t\treturn abs(a.i - b.i);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> next_float(vec<L, T, Q> const& x)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = next_float(x[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> next_float(vec<L, T, Q> const& x, int ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = next_float(x[i], ULPs);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> next_float(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = next_float(x[i], ULPs[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prev_float(vec<L, T, Q> const& x)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = prev_float(x[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prev_float(vec<L, T, Q> const& x, int ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = prev_float(x[i], ULPs);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> prev_float(vec<L, T, Q> const& x, vec<L, int, Q> const& ULPs)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = prev_float(x[i], ULPs[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int, Q> float_distance(vec<L, float, Q> const& x, vec<L, float, Q> const& y)\n\t{\n\t\tvec<L, int, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = float_distance(x[i], y[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, int64, Q> float_distance(vec<L, double, Q> const& x, vec<L, double, Q> const& y)\n\t{\n\t\tvec<L, int64, Q> Result;\n\t\tfor (length_t i = 0, n = Result.length(); i < n; ++i)\n\t\t\tResult[i] = float_distance(x[i], y[i]);\n\t\treturn Result;\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtc/vec1.hpp",
    "content": "/// @ref gtc_vec1\n/// @file glm/gtc/vec1.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtc_vec1 GLM_GTC_vec1\n/// @ingroup gtc\n///\n/// Include <glm/gtc/vec1.hpp> to use the features of this extension.\n///\n/// Add vec1, ivec1, uvec1 and bvec1 types.\n\n#pragma once\n\n// Dependency:\n#include \"../ext/vector_bool1.hpp\"\n#include \"../ext/vector_bool1_precision.hpp\"\n#include \"../ext/vector_float1.hpp\"\n#include \"../ext/vector_float1_precision.hpp\"\n#include \"../ext/vector_double1.hpp\"\n#include \"../ext/vector_double1_precision.hpp\"\n#include \"../ext/vector_int1.hpp\"\n#include \"../ext/vector_int1_sized.hpp\"\n#include \"../ext/vector_uint1.hpp\"\n#include \"../ext/vector_uint1_sized.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tpragma message(\"GLM: GLM_GTC_vec1 extension included\")\n#endif\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/associated_min_max.hpp",
    "content": "/// @ref gtx_associated_min_max\n/// @file glm/gtx/associated_min_max.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_associated_min_max GLM_GTX_associated_min_max\n/// @ingroup gtx\n///\n/// Include <glm/gtx/associated_min_max.hpp> to use the features of this extension.\n///\n/// @brief Min and max functions that return associated values not the compared onces.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_associated_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_associated_min_max extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_associated_min_max\n\t/// @{\n\n\t/// Minimum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL U associatedMin(T x, U a, T y, U b);\n\n\t/// Minimum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<2, U, Q> associatedMin(\n\t\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\t\tvec<L, T, Q> const& y, vec<L, U, Q> const& b);\n\n\t/// Minimum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMin(\n\t\tT x, const vec<L, U, Q>& a,\n\t\tT y, const vec<L, U, Q>& b);\n\n\t/// Minimum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMin(\n\t\tvec<L, T, Q> const& x, U a,\n\t\tvec<L, T, Q> const& y, U b);\n\n\t/// Minimum comparison between 3 variables and returns 3 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<typename T, typename U>\n\tGLM_FUNC_DECL U associatedMin(\n\t\tT x, U a,\n\t\tT y, U b,\n\t\tT z, U c);\n\n\t/// Minimum comparison between 3 variables and returns 3 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMin(\n\t\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\t\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\t\tvec<L, T, Q> const& z, vec<L, U, Q> const& c);\n\n\t/// Minimum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<typename T, typename U>\n\tGLM_FUNC_DECL U associatedMin(\n\t\tT x, U a,\n\t\tT y, U b,\n\t\tT z, U c,\n\t\tT w, U d);\n\n\t/// Minimum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMin(\n\t\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\t\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\t\tvec<L, T, Q> const& z, vec<L, U, Q> const& c,\n\t\tvec<L, T, Q> const& w, vec<L, U, Q> const& d);\n\n\t/// Minimum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMin(\n\t\tT x, vec<L, U, Q> const& a,\n\t\tT y, vec<L, U, Q> const& b,\n\t\tT z, vec<L, U, Q> const& c,\n\t\tT w, vec<L, U, Q> const& d);\n\n\t/// Minimum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMin(\n\t\tvec<L, T, Q> const& x, U a,\n\t\tvec<L, T, Q> const& y, U b,\n\t\tvec<L, T, Q> const& z, U c,\n\t\tvec<L, T, Q> const& w, U d);\n\n\t/// Maximum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<typename T, typename U>\n\tGLM_FUNC_DECL U associatedMax(T x, U a, T y, U b);\n\n\t/// Maximum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<2, U, Q> associatedMax(\n\t\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\t\tvec<L, T, Q> const& y, vec<L, U, Q> const& b);\n\n\t/// Maximum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> associatedMax(\n\t\tT x, vec<L, U, Q> const& a,\n\t\tT y, vec<L, U, Q> const& b);\n\n\t/// Maximum comparison between 2 variables and returns 2 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMax(\n\t\tvec<L, T, Q> const& x, U a,\n\t\tvec<L, T, Q> const& y, U b);\n\n\t/// Maximum comparison between 3 variables and returns 3 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<typename T, typename U>\n\tGLM_FUNC_DECL U associatedMax(\n\t\tT x, U a,\n\t\tT y, U b,\n\t\tT z, U c);\n\n\t/// Maximum comparison between 3 variables and returns 3 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMax(\n\t\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\t\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\t\tvec<L, T, Q> const& z, vec<L, U, Q> const& c);\n\n\t/// Maximum comparison between 3 variables and returns 3 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> associatedMax(\n\t\tT x, vec<L, U, Q> const& a,\n\t\tT y, vec<L, U, Q> const& b,\n\t\tT z, vec<L, U, Q> const& c);\n\n\t/// Maximum comparison between 3 variables and returns 3 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMax(\n\t\tvec<L, T, Q> const& x, U a,\n\t\tvec<L, T, Q> const& y, U b,\n\t\tvec<L, T, Q> const& z, U c);\n\n\t/// Maximum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<typename T, typename U>\n\tGLM_FUNC_DECL U associatedMax(\n\t\tT x, U a,\n\t\tT y, U b,\n\t\tT z, U c,\n\t\tT w, U d);\n\n\t/// Maximum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMax(\n\t\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\t\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\t\tvec<L, T, Q> const& z, vec<L, U, Q> const& c,\n\t\tvec<L, T, Q> const& w, vec<L, U, Q> const& d);\n\n\t/// Maximum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMax(\n\t\tT x, vec<L, U, Q> const& a,\n\t\tT y, vec<L, U, Q> const& b,\n\t\tT z, vec<L, U, Q> const& c,\n\t\tT w, vec<L, U, Q> const& d);\n\n\t/// Maximum comparison between 4 variables and returns 4 associated variable values\n\t/// @see gtx_associated_min_max\n\ttemplate<length_t L, typename T, typename U, qualifier Q>\n\tGLM_FUNC_DECL vec<L, U, Q> associatedMax(\n\t\tvec<L, T, Q> const& x, U a,\n\t\tvec<L, T, Q> const& y, U b,\n\t\tvec<L, T, Q> const& z, U c,\n\t\tvec<L, T, Q> const& w, U d);\n\n\t/// @}\n} //namespace glm\n\n#include \"associated_min_max.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/associated_min_max.inl",
    "content": "/// @ref gtx_associated_min_max\n\nnamespace glm{\n\n// Min comparison between 2 variables\ntemplate<typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER U associatedMin(T x, U a, T y, U b)\n{\n\treturn x < y ? a : b;\n}\n\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<2, U, Q> associatedMin\n(\n\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\tvec<L, T, Q> const& y, vec<L, U, Q> const& b\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] < y[i] ? a[i] : b[i];\n\treturn Result;\n}\n\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMin\n(\n\tT x, const vec<L, U, Q>& a,\n\tT y, const vec<L, U, Q>& b\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x < y ? a[i] : b[i];\n\treturn Result;\n}\n\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMin\n(\n\tvec<L, T, Q> const& x, U a,\n\tvec<L, T, Q> const& y, U b\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] < y[i] ? a : b;\n\treturn Result;\n}\n\n// Min comparison between 3 variables\ntemplate<typename T, typename U>\nGLM_FUNC_QUALIFIER U associatedMin\n(\n\tT x, U a,\n\tT y, U b,\n\tT z, U c\n)\n{\n\tU Result = x < y ? (x < z ? a : c) : (y < z ? b : c);\n\treturn Result;\n}\n\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMin\n(\n\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\tvec<L, T, Q> const& z, vec<L, U, Q> const& c\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] < y[i] ? (x[i] < z[i] ? a[i] : c[i]) : (y[i] < z[i] ? b[i] : c[i]);\n\treturn Result;\n}\n\n// Min comparison between 4 variables\ntemplate<typename T, typename U>\nGLM_FUNC_QUALIFIER U associatedMin\n(\n\tT x, U a,\n\tT y, U b,\n\tT z, U c,\n\tT w, U d\n)\n{\n\tT Test1 = min(x, y);\n\tT Test2 = min(z, w);\n\tU Result1 = x < y ? a : b;\n\tU Result2 = z < w ? c : d;\n\tU Result = Test1 < Test2 ? Result1 : Result2;\n\treturn Result;\n}\n\n// Min comparison between 4 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMin\n(\n\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\tvec<L, T, Q> const& z, vec<L, U, Q> const& c,\n\tvec<L, T, Q> const& w, vec<L, U, Q> const& d\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t{\n\t\tT Test1 = min(x[i], y[i]);\n\t\tT Test2 = min(z[i], w[i]);\n\t\tU Result1 = x[i] < y[i] ? a[i] : b[i];\n\t\tU Result2 = z[i] < w[i] ? c[i] : d[i];\n\t\tResult[i] = Test1 < Test2 ? Result1 : Result2;\n\t}\n\treturn Result;\n}\n\n// Min comparison between 4 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMin\n(\n\tT x, vec<L, U, Q> const& a,\n\tT y, vec<L, U, Q> const& b,\n\tT z, vec<L, U, Q> const& c,\n\tT w, vec<L, U, Q> const& d\n)\n{\n\tT Test1 = min(x, y);\n\tT Test2 = min(z, w);\n\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t{\n\t\tU Result1 = x < y ? a[i] : b[i];\n\t\tU Result2 = z < w ? c[i] : d[i];\n\t\tResult[i] = Test1 < Test2 ? Result1 : Result2;\n\t}\n\treturn Result;\n}\n\n// Min comparison between 4 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMin\n(\n\tvec<L, T, Q> const& x, U a,\n\tvec<L, T, Q> const& y, U b,\n\tvec<L, T, Q> const& z, U c,\n\tvec<L, T, Q> const& w, U d\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t{\n\t\tT Test1 = min(x[i], y[i]);\n\t\tT Test2 = min(z[i], w[i]);\n\t\tU Result1 = x[i] < y[i] ? a : b;\n\t\tU Result2 = z[i] < w[i] ? c : d;\n\t\tResult[i] = Test1 < Test2 ? Result1 : Result2;\n\t}\n\treturn Result;\n}\n\n// Max comparison between 2 variables\ntemplate<typename T, typename U>\nGLM_FUNC_QUALIFIER U associatedMax(T x, U a, T y, U b)\n{\n\treturn x > y ? a : b;\n}\n\n// Max comparison between 2 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<2, U, Q> associatedMax\n(\n\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\tvec<L, T, Q> const& y, vec<L, U, Q> const& b\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] > y[i] ? a[i] : b[i];\n\treturn Result;\n}\n\n// Max comparison between 2 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, T, Q> associatedMax\n(\n\tT x, vec<L, U, Q> const& a,\n\tT y, vec<L, U, Q> const& b\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x > y ? a[i] : b[i];\n\treturn Result;\n}\n\n// Max comparison between 2 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMax\n(\n\tvec<L, T, Q> const& x, U a,\n\tvec<L, T, Q> const& y, U b\n)\n{\n\tvec<L, T, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] > y[i] ? a : b;\n\treturn Result;\n}\n\n// Max comparison between 3 variables\ntemplate<typename T, typename U>\nGLM_FUNC_QUALIFIER U associatedMax\n(\n\tT x, U a,\n\tT y, U b,\n\tT z, U c\n)\n{\n\tU Result = x > y ? (x > z ? a : c) : (y > z ? b : c);\n\treturn Result;\n}\n\n// Max comparison between 3 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMax\n(\n\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\tvec<L, T, Q> const& z, vec<L, U, Q> const& c\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] > y[i] ? (x[i] > z[i] ? a[i] : c[i]) : (y[i] > z[i] ? b[i] : c[i]);\n\treturn Result;\n}\n\n// Max comparison between 3 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, T, Q> associatedMax\n(\n\tT x, vec<L, U, Q> const& a,\n\tT y, vec<L, U, Q> const& b,\n\tT z, vec<L, U, Q> const& c\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x > y ? (x > z ? a[i] : c[i]) : (y > z ? b[i] : c[i]);\n\treturn Result;\n}\n\n// Max comparison between 3 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMax\n(\n\tvec<L, T, Q> const& x, U a,\n\tvec<L, T, Q> const& y, U b,\n\tvec<L, T, Q> const& z, U c\n)\n{\n\tvec<L, T, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t\tResult[i] = x[i] > y[i] ? (x[i] > z[i] ? a : c) : (y[i] > z[i] ? b : c);\n\treturn Result;\n}\n\n// Max comparison between 4 variables\ntemplate<typename T, typename U>\nGLM_FUNC_QUALIFIER U associatedMax\n(\n\tT x, U a,\n\tT y, U b,\n\tT z, U c,\n\tT w, U d\n)\n{\n\tT Test1 = max(x, y);\n\tT Test2 = max(z, w);\n\tU Result1 = x > y ? a : b;\n\tU Result2 = z > w ? c : d;\n\tU Result = Test1 > Test2 ? Result1 : Result2;\n\treturn Result;\n}\n\n// Max comparison between 4 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMax\n(\n\tvec<L, T, Q> const& x, vec<L, U, Q> const& a,\n\tvec<L, T, Q> const& y, vec<L, U, Q> const& b,\n\tvec<L, T, Q> const& z, vec<L, U, Q> const& c,\n\tvec<L, T, Q> const& w, vec<L, U, Q> const& d\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t{\n\t\tT Test1 = max(x[i], y[i]);\n\t\tT Test2 = max(z[i], w[i]);\n\t\tU Result1 = x[i] > y[i] ? a[i] : b[i];\n\t\tU Result2 = z[i] > w[i] ? c[i] : d[i];\n\t\tResult[i] = Test1 > Test2 ? Result1 : Result2;\n\t}\n\treturn Result;\n}\n\n// Max comparison between 4 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMax\n(\n\tT x, vec<L, U, Q> const& a,\n\tT y, vec<L, U, Q> const& b,\n\tT z, vec<L, U, Q> const& c,\n\tT w, vec<L, U, Q> const& d\n)\n{\n\tT Test1 = max(x, y);\n\tT Test2 = max(z, w);\n\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t{\n\t\tU Result1 = x > y ? a[i] : b[i];\n\t\tU Result2 = z > w ? c[i] : d[i];\n\t\tResult[i] = Test1 > Test2 ? Result1 : Result2;\n\t}\n\treturn Result;\n}\n\n// Max comparison between 4 variables\ntemplate<length_t L, typename T, typename U, qualifier Q>\nGLM_FUNC_QUALIFIER vec<L, U, Q> associatedMax\n(\n\tvec<L, T, Q> const& x, U a,\n\tvec<L, T, Q> const& y, U b,\n\tvec<L, T, Q> const& z, U c,\n\tvec<L, T, Q> const& w, U d\n)\n{\n\tvec<L, U, Q> Result;\n\tfor(length_t i = 0, n = Result.length(); i < n; ++i)\n\t{\n\t\tT Test1 = max(x[i], y[i]);\n\t\tT Test2 = max(z[i], w[i]);\n\t\tU Result1 = x[i] > y[i] ? a : b;\n\t\tU Result2 = z[i] > w[i] ? c : d;\n\t\tResult[i] = Test1 > Test2 ? Result1 : Result2;\n\t}\n\treturn Result;\n}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/bit.hpp",
    "content": "/// @ref gtx_bit\n/// @file glm/gtx/bit.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_bit GLM_GTX_bit\n/// @ingroup gtx\n///\n/// Include <glm/gtx/bit.hpp> to use the features of this extension.\n///\n/// Allow to perform bit operations on integer values\n\n#pragma once\n\n// Dependencies\n#include \"../gtc/bitfield.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_bit is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_bit extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_bit\n\t/// @{\n\n\t/// @see gtx_bit\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType highestBitValue(genIUType Value);\n\n\t/// @see gtx_bit\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL genIUType lowestBitValue(genIUType Value);\n\n\t/// Find the highest bit set to 1 in a integer variable and return its value.\n\t///\n\t/// @see gtx_bit\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> highestBitValue(vec<L, T, Q> const& value);\n\n\t/// Return the power of two number which value is just higher the input value.\n\t/// Deprecated, use ceilPowerOfTwo from GTC_round instead\n\t///\n\t/// @see gtc_round\n\t/// @see gtx_bit\n\ttemplate<typename genIUType>\n\tGLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value);\n\n\t/// Return the power of two number which value is just higher the input value.\n\t/// Deprecated, use ceilPowerOfTwo from GTC_round instead\n\t///\n\t/// @see gtc_round\n\t/// @see gtx_bit\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_DEPRECATED GLM_FUNC_DECL vec<L, T, Q> powerOfTwoAbove(vec<L, T, Q> const& value);\n\n\t/// Return the power of two number which value is just lower the input value.\n\t/// Deprecated, use floorPowerOfTwo from GTC_round instead\n\t///\n\t/// @see gtc_round\n\t/// @see gtx_bit\n\ttemplate<typename genIUType>\n\tGLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value);\n\n\t/// Return the power of two number which value is just lower the input value.\n\t/// Deprecated, use floorPowerOfTwo from GTC_round instead\n\t///\n\t/// @see gtc_round\n\t/// @see gtx_bit\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_DEPRECATED GLM_FUNC_DECL vec<L, T, Q> powerOfTwoBelow(vec<L, T, Q> const& value);\n\n\t/// Return the power of two number which value is the closet to the input value.\n\t/// Deprecated, use roundPowerOfTwo from GTC_round instead\n\t///\n\t/// @see gtc_round\n\t/// @see gtx_bit\n\ttemplate<typename genIUType>\n\tGLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value);\n\n\t/// Return the power of two number which value is the closet to the input value.\n\t/// Deprecated, use roundPowerOfTwo from GTC_round instead\n\t///\n\t/// @see gtc_round\n\t/// @see gtx_bit\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_DEPRECATED GLM_FUNC_DECL vec<L, T, Q> powerOfTwoNearest(vec<L, T, Q> const& value);\n\n\t/// @}\n} //namespace glm\n\n\n#include \"bit.inl\"\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/bit.inl",
    "content": "/// @ref gtx_bit\n\nnamespace glm\n{\n\t///////////////////\n\t// highestBitValue\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value)\n\t{\n\t\tgenIUType tmp = Value;\n\t\tgenIUType result = genIUType(0);\n\t\twhile(tmp)\n\t\t{\n\t\t\tresult = (tmp & (~tmp + 1)); // grab lowest bit\n\t\t\ttmp &= ~result; // clear lowest bit\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> highestBitValue(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(highestBitValue, v);\n\t}\n\n\t///////////////////\n\t// lowestBitValue\n\n\ttemplate<typename genIUType>\n\tGLM_FUNC_QUALIFIER genIUType lowestBitValue(genIUType Value)\n\t{\n\t\treturn (Value & (~Value + 1));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> lowestBitValue(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(lowestBitValue, v);\n\t}\n\n\t///////////////////\n\t// powerOfTwoAbove\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType powerOfTwoAbove(genType value)\n\t{\n\t\treturn isPowerOfTwo(value) ? value : highestBitValue(value) << 1;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> powerOfTwoAbove(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(powerOfTwoAbove, v);\n\t}\n\n\t///////////////////\n\t// powerOfTwoBelow\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType powerOfTwoBelow(genType value)\n\t{\n\t\treturn isPowerOfTwo(value) ? value : highestBitValue(value);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> powerOfTwoBelow(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(powerOfTwoBelow, v);\n\t}\n\n\t/////////////////////\n\t// powerOfTwoNearest\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType powerOfTwoNearest(genType value)\n\t{\n\t\tif(isPowerOfTwo(value))\n\t\t\treturn value;\n\n\t\tgenType const prev = highestBitValue(value);\n\t\tgenType const next = prev << 1;\n\t\treturn (next - value) < (value - prev) ? next : prev;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> powerOfTwoNearest(vec<L, T, Q> const& v)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(powerOfTwoNearest, v);\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/closest_point.hpp",
    "content": "/// @ref gtx_closest_point\n/// @file glm/gtx/closest_point.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_closest_point GLM_GTX_closest_point\n/// @ingroup gtx\n///\n/// Include <glm/gtx/closest_point.hpp> to use the features of this extension.\n///\n/// Find the point on a straight line which is the closet of a point.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_closest_point extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_closest_point\n\t/// @{\n\n\t/// Find the point on a straight line which is the closet of a point.\n\t/// @see gtx_closest_point\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> closestPointOnLine(\n\t\tvec<3, T, Q> const& point,\n\t\tvec<3, T, Q> const& a,\n\t\tvec<3, T, Q> const& b);\n\n\t/// 2d lines work as well\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<2, T, Q> closestPointOnLine(\n\t\tvec<2, T, Q> const& point,\n\t\tvec<2, T, Q> const& a,\n\t\tvec<2, T, Q> const& b);\n\n\t/// @}\n}// namespace glm\n\n#include \"closest_point.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/closest_point.inl",
    "content": "/// @ref gtx_closest_point\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> closestPointOnLine\n\t(\n\t\tvec<3, T, Q> const& point,\n\t\tvec<3, T, Q> const& a,\n\t\tvec<3, T, Q> const& b\n\t)\n\t{\n\t\tT LineLength = distance(a, b);\n\t\tvec<3, T, Q> Vector = point - a;\n\t\tvec<3, T, Q> LineDirection = (b - a) / LineLength;\n\n\t\t// Project Vector to LineDirection to get the distance of point from a\n\t\tT Distance = dot(Vector, LineDirection);\n\n\t\tif(Distance <= T(0)) return a;\n\t\tif(Distance >= LineLength) return b;\n\t\treturn a + LineDirection * Distance;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> closestPointOnLine\n\t(\n\t\tvec<2, T, Q> const& point,\n\t\tvec<2, T, Q> const& a,\n\t\tvec<2, T, Q> const& b\n\t)\n\t{\n\t\tT LineLength = distance(a, b);\n\t\tvec<2, T, Q> Vector = point - a;\n\t\tvec<2, T, Q> LineDirection = (b - a) / LineLength;\n\n\t\t// Project Vector to LineDirection to get the distance of point from a\n\t\tT Distance = dot(Vector, LineDirection);\n\n\t\tif(Distance <= T(0)) return a;\n\t\tif(Distance >= LineLength) return b;\n\t\treturn a + LineDirection * Distance;\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/color_encoding.hpp",
    "content": "/// @ref gtx_color_encoding\n/// @file glm/gtx/color_encoding.hpp\n///\n/// @see core (dependence)\n/// @see gtx_color_encoding (dependence)\n///\n/// @defgroup gtx_color_encoding GLM_GTX_color_encoding\n/// @ingroup gtx\n///\n/// Include <glm/gtx/color_encoding.hpp> to use the features of this extension.\n///\n/// @brief Allow to perform bit operations on integer values\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../vec3.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTC_color_encoding is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTC_color_encoding extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_color_encoding\n\t/// @{\n\n\t/// Convert a linear sRGB color to D65 YUV.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB);\n\n\t/// Convert a linear sRGB color to D50 YUV.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB);\n\n\t/// Convert a D65 YUV color to linear sRGB.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ);\n\n\t/// Convert a D65 YUV color to D50 YUV.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ);\n\n\t/// @}\n} //namespace glm\n\n#include \"color_encoding.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/color_encoding.inl",
    "content": "/// @ref gtx_color_encoding\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD65XYZ(vec<3, T, Q> const& ColorLinearSRGB)\n\t{\n\t\tvec<3, T, Q> const M(0.490f, 0.17697f, 0.2f);\n\t\tvec<3, T, Q> const N(0.31f,  0.8124f, 0.01063f);\n\t\tvec<3, T, Q> const O(0.490f, 0.01f, 0.99f);\n\n\t\treturn (M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB) * static_cast<T>(5.650675255693055f);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> convertLinearSRGBToD50XYZ(vec<3, T, Q> const& ColorLinearSRGB)\n\t{\n\t\tvec<3, T, Q> const M(0.436030342570117f, 0.222438466210245f, 0.013897440074263f);\n\t\tvec<3, T, Q> const N(0.385101860087134f, 0.716942745571917f, 0.097076381494207f);\n\t\tvec<3, T, Q> const O(0.143067806654203f, 0.060618777416563f, 0.713926257896652f);\n\n\t\treturn M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToLinearSRGB(vec<3, T, Q> const& ColorD65XYZ)\n\t{\n\t\tvec<3, T, Q> const M(0.41847f, -0.091169f, 0.0009209f);\n\t\tvec<3, T, Q> const N(-0.15866f, 0.25243f, 0.015708f);\n\t\tvec<3, T, Q> const O(0.0009209f, -0.0025498f, 0.1786f);\n\n\t\treturn M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> convertD65XYZToD50XYZ(vec<3, T, Q> const& ColorD65XYZ)\n\t{\n\t\tvec<3, T, Q> const M(+1.047844353856414f, +0.029549007606644f, -0.009250984365223f);\n\t\tvec<3, T, Q> const N(+0.022898981050086f, +0.990508028941971f, +0.015072338237051f);\n\t\tvec<3, T, Q> const O(-0.050206647741605f, -0.017074711360960f, +0.751717835079977f);\n\n\t\treturn M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ;\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/color_space.hpp",
    "content": "/// @ref gtx_color_space\n/// @file glm/gtx/color_space.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_color_space GLM_GTX_color_space\n/// @ingroup gtx\n///\n/// Include <glm/gtx/color_space.hpp> to use the features of this extension.\n///\n/// Related to RGB to HSV conversions and operations.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_color_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_color_space extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_color_space\n\t/// @{\n\n\t/// Converts a color from HSV color space to its color in RGB color space.\n\t/// @see gtx_color_space\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rgbColor(\n\t\tvec<3, T, Q> const& hsvValue);\n\n\t/// Converts a color from RGB color space to its color in HSV color space.\n\t/// @see gtx_color_space\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> hsvColor(\n\t\tvec<3, T, Q> const& rgbValue);\n\n\t/// Build a saturation matrix.\n\t/// @see gtx_color_space\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> saturation(\n\t\tT const s);\n\n\t/// Modify the saturation of a color.\n\t/// @see gtx_color_space\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> saturation(\n\t\tT const s,\n\t\tvec<3, T, Q> const& color);\n\n\t/// Modify the saturation of a color.\n\t/// @see gtx_color_space\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> saturation(\n\t\tT const s,\n\t\tvec<4, T, Q> const& color);\n\n\t/// Compute color luminosity associating ratios (0.33, 0.59, 0.11) to RGB canals.\n\t/// @see gtx_color_space\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T luminosity(\n\t\tvec<3, T, Q> const& color);\n\n\t/// @}\n}//namespace glm\n\n#include \"color_space.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/color_space.inl",
    "content": "/// @ref gtx_color_space\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rgbColor(const vec<3, T, Q>& hsvColor)\n\t{\n\t\tvec<3, T, Q> hsv = hsvColor;\n\t\tvec<3, T, Q> rgbColor;\n\n\t\tif(hsv.y == static_cast<T>(0))\n\t\t\t// achromatic (grey)\n\t\t\trgbColor = vec<3, T, Q>(hsv.z);\n\t\telse\n\t\t{\n\t\t\tT sector = floor(hsv.x * (T(1) / T(60)));\n\t\t\tT frac = (hsv.x * (T(1) / T(60))) - sector;\n\t\t\t// factorial part of h\n\t\t\tT o = hsv.z * (T(1) - hsv.y);\n\t\t\tT p = hsv.z * (T(1) - hsv.y * frac);\n\t\t\tT q = hsv.z * (T(1) - hsv.y * (T(1) - frac));\n\n\t\t\tswitch(int(sector))\n\t\t\t{\n\t\t\tdefault:\n\t\t\tcase 0:\n\t\t\t\trgbColor.r = hsv.z;\n\t\t\t\trgbColor.g = q;\n\t\t\t\trgbColor.b = o;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\trgbColor.r = p;\n\t\t\t\trgbColor.g = hsv.z;\n\t\t\t\trgbColor.b = o;\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\trgbColor.r = o;\n\t\t\t\trgbColor.g = hsv.z;\n\t\t\t\trgbColor.b = q;\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\trgbColor.r = o;\n\t\t\t\trgbColor.g = p;\n\t\t\t\trgbColor.b = hsv.z;\n\t\t\t\tbreak;\n\t\t\tcase 4:\n\t\t\t\trgbColor.r = q;\n\t\t\t\trgbColor.g = o;\n\t\t\t\trgbColor.b = hsv.z;\n\t\t\t\tbreak;\n\t\t\tcase 5:\n\t\t\t\trgbColor.r = hsv.z;\n\t\t\t\trgbColor.g = o;\n\t\t\t\trgbColor.b = p;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn rgbColor;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> hsvColor(const vec<3, T, Q>& rgbColor)\n\t{\n\t\tvec<3, T, Q> hsv = rgbColor;\n\t\tfloat Min   = min(min(rgbColor.r, rgbColor.g), rgbColor.b);\n\t\tfloat Max   = max(max(rgbColor.r, rgbColor.g), rgbColor.b);\n\t\tfloat Delta = Max - Min;\n\n\t\thsv.z = Max;\n\n\t\tif(Max != static_cast<T>(0))\n\t\t{\n\t\t\thsv.y = Delta / hsv.z;\n\t\t\tT h = static_cast<T>(0);\n\n\t\t\tif(rgbColor.r == Max)\n\t\t\t\t// between yellow & magenta\n\t\t\t\th = static_cast<T>(0) + T(60) * (rgbColor.g - rgbColor.b) / Delta;\n\t\t\telse if(rgbColor.g == Max)\n\t\t\t\t// between cyan & yellow\n\t\t\t\th = static_cast<T>(120) + T(60) * (rgbColor.b - rgbColor.r) / Delta;\n\t\t\telse\n\t\t\t\t// between magenta & cyan\n\t\t\t\th = static_cast<T>(240) + T(60) * (rgbColor.r - rgbColor.g) / Delta;\n\n\t\t\tif(h < T(0))\n\t\t\t\thsv.x = h + T(360);\n\t\t\telse\n\t\t\t\thsv.x = h;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// If r = g = b = 0 then s = 0, h is undefined\n\t\t\thsv.y = static_cast<T>(0);\n\t\t\thsv.x = static_cast<T>(0);\n\t\t}\n\n\t\treturn hsv;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> saturation(T const s)\n\t{\n\t\tvec<3, T, defaultp> rgbw = vec<3, T, defaultp>(T(0.2126), T(0.7152), T(0.0722));\n\n\t\tvec<3, T, defaultp> const col((T(1) - s) * rgbw);\n\n\t\tmat<4, 4, T, defaultp> result(T(1));\n\t\tresult[0][0] = col.x + s;\n\t\tresult[0][1] = col.x;\n\t\tresult[0][2] = col.x;\n\t\tresult[1][0] = col.y;\n\t\tresult[1][1] = col.y + s;\n\t\tresult[1][2] = col.y;\n\t\tresult[2][0] = col.z;\n\t\tresult[2][1] = col.z;\n\t\tresult[2][2] = col.z + s;\n\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> saturation(const T s, const vec<3, T, Q>& color)\n\t{\n\t\treturn vec<3, T, Q>(saturation(s) * vec<4, T, Q>(color, T(0)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> saturation(const T s, const vec<4, T, Q>& color)\n\t{\n\t\treturn saturation(s) * color;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T luminosity(const vec<3, T, Q>& color)\n\t{\n\t\tconst vec<3, T, Q> tmp = vec<3, T, Q>(0.33, 0.59, 0.11);\n\t\treturn dot(color, tmp);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/color_space_YCoCg.hpp",
    "content": "/// @ref gtx_color_space_YCoCg\n/// @file glm/gtx/color_space_YCoCg.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_color_space_YCoCg GLM_GTX_color_space_YCoCg\n/// @ingroup gtx\n///\n/// Include <glm/gtx/color_space_YCoCg.hpp> to use the features of this extension.\n///\n/// RGB to YCoCg conversions and operations\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_color_space_YCoCg is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_color_space_YCoCg extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_color_space_YCoCg\n\t/// @{\n\n\t/// Convert a color from RGB color space to YCoCg color space.\n\t/// @see gtx_color_space_YCoCg\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rgb2YCoCg(\n\t\tvec<3, T, Q> const& rgbColor);\n\n\t/// Convert a color from YCoCg color space to RGB color space.\n\t/// @see gtx_color_space_YCoCg\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> YCoCg2rgb(\n\t\tvec<3, T, Q> const& YCoCgColor);\n\n\t/// Convert a color from RGB color space to YCoCgR color space.\n\t/// @see \"YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range\"\n\t/// @see gtx_color_space_YCoCg\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rgb2YCoCgR(\n\t\tvec<3, T, Q> const& rgbColor);\n\n\t/// Convert a color from YCoCgR color space to RGB color space.\n\t/// @see \"YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range\"\n\t/// @see gtx_color_space_YCoCg\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> YCoCgR2rgb(\n\t\tvec<3, T, Q> const& YCoCgColor);\n\n\t/// @}\n}//namespace glm\n\n#include \"color_space_YCoCg.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/color_space_YCoCg.inl",
    "content": "/// @ref gtx_color_space_YCoCg\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCg\n\t(\n\t\tvec<3, T, Q> const& rgbColor\n\t)\n\t{\n\t\tvec<3, T, Q> result;\n\t\tresult.x/*Y */ =   rgbColor.r / T(4) + rgbColor.g / T(2) + rgbColor.b / T(4);\n\t\tresult.y/*Co*/ =   rgbColor.r / T(2) + rgbColor.g * T(0) - rgbColor.b / T(2);\n\t\tresult.z/*Cg*/ = - rgbColor.r / T(4) + rgbColor.g / T(2) - rgbColor.b / T(4);\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> YCoCg2rgb\n\t(\n\t\tvec<3, T, Q> const& YCoCgColor\n\t)\n\t{\n\t\tvec<3, T, Q> result;\n\t\tresult.r = YCoCgColor.x + YCoCgColor.y - YCoCgColor.z;\n\t\tresult.g = YCoCgColor.x\t\t\t\t   + YCoCgColor.z;\n\t\tresult.b = YCoCgColor.x - YCoCgColor.y - YCoCgColor.z;\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q, bool isInteger>\n\tclass compute_YCoCgR {\n\tpublic:\n\t\tstatic GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR\n\t\t(\n\t\t\tvec<3, T, Q> const& rgbColor\n\t\t)\n\t\t{\n\t\t\tvec<3, T, Q> result;\n\t\t\tresult.x/*Y */ = rgbColor.g * static_cast<T>(0.5) + (rgbColor.r + rgbColor.b) * static_cast<T>(0.25);\n\t\t\tresult.y/*Co*/ = rgbColor.r - rgbColor.b;\n\t\t\tresult.z/*Cg*/ = rgbColor.g - (rgbColor.r + rgbColor.b) * static_cast<T>(0.5);\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb\n\t\t(\n\t\t\tvec<3, T, Q> const& YCoCgRColor\n\t\t)\n\t\t{\n\t\t\tvec<3, T, Q> result;\n\t\t\tT tmp = YCoCgRColor.x - (YCoCgRColor.z * static_cast<T>(0.5));\n\t\t\tresult.g = YCoCgRColor.z + tmp;\n\t\t\tresult.b = tmp - (YCoCgRColor.y * static_cast<T>(0.5));\n\t\t\tresult.r = result.b + YCoCgRColor.y;\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tclass compute_YCoCgR<T, Q, true> {\n\tpublic:\n\t\tstatic GLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR\n\t\t(\n\t\t\tvec<3, T, Q> const& rgbColor\n\t\t)\n\t\t{\n\t\t\tvec<3, T, Q> result;\n\t\t\tresult.y/*Co*/ = rgbColor.r - rgbColor.b;\n\t\t\tT tmp = rgbColor.b + (result.y >> 1);\n\t\t\tresult.z/*Cg*/ = rgbColor.g - tmp;\n\t\t\tresult.x/*Y */ = tmp + (result.z >> 1);\n\t\t\treturn result;\n\t\t}\n\n\t\tstatic GLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb\n\t\t(\n\t\t\tvec<3, T, Q> const& YCoCgRColor\n\t\t)\n\t\t{\n\t\t\tvec<3, T, Q> result;\n\t\t\tT tmp = YCoCgRColor.x - (YCoCgRColor.z >> 1);\n\t\t\tresult.g = YCoCgRColor.z + tmp;\n\t\t\tresult.b = tmp - (YCoCgRColor.y >> 1);\n\t\t\tresult.r = result.b + YCoCgRColor.y;\n\t\t\treturn result;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rgb2YCoCgR\n\t(\n\t\tvec<3, T, Q> const& rgbColor\n\t)\n\t{\n\t\treturn compute_YCoCgR<T, Q, std::numeric_limits<T>::is_integer>::rgb2YCoCgR(rgbColor);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> YCoCgR2rgb\n\t(\n\t\tvec<3, T, Q> const& YCoCgRColor\n\t)\n\t{\n\t\treturn compute_YCoCgR<T, Q, std::numeric_limits<T>::is_integer>::YCoCgR2rgb(YCoCgRColor);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/common.hpp",
    "content": "/// @ref gtx_common\n/// @file glm/gtx/common.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_common GLM_GTX_common\n/// @ingroup gtx\n///\n/// Include <glm/gtx/common.hpp> to use the features of this extension.\n///\n/// @brief Provide functions to increase the compatibility with Cg and HLSL languages\n\n#pragma once\n\n// Dependencies:\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../gtc/vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_common is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_common extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_common\n\t/// @{\n\n\t/// Returns true if x is a denormalized number\n\t/// Numbers whose absolute value is too small to be represented in the normal format are represented in an alternate, denormalized format.\n\t/// This format is less precise but can represent values closer to zero.\n\t///\n\t/// @tparam genType Floating-point scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/isnan.xml\">GLSL isnan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.3 Common Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::bool_type isdenormal(genType const& x);\n\n\t/// Similar to 'mod' but with a different rounding and integer support.\n\t/// Returns 'x - y * trunc(x/y)' instead of 'x - y * floor(x/y)'\n\t///\n\t/// @see <a href=\"http://stackoverflow.com/questions/7610631/glsl-mod-vs-hlsl-fmod\">GLSL mod vs HLSL fmod</a>\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml\">GLSL mod man page</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fmod(vec<L, T, Q> const& v);\n\n\t/// Returns whether vector components values are within an interval. A open interval excludes its endpoints, and is denoted with square brackets.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_relational\n\ttemplate <length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> openBounded(vec<L, T, Q> const& Value, vec<L, T, Q> const& Min, vec<L, T, Q> const& Max);\n\n\t/// Returns whether vector components values are within an interval. A closed interval includes its endpoints, and is denoted with square brackets.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see ext_vector_relational\n\ttemplate <length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> closeBounded(vec<L, T, Q> const& Value, vec<L, T, Q> const& Min, vec<L, T, Q> const& Max);\n\n\t/// @}\n}//namespace glm\n\n#include \"common.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/common.inl",
    "content": "/// @ref gtx_common\n\n#include <cmath>\n#include \"../gtc/epsilon.hpp\"\n#include \"../gtc/constants.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q, bool isFloat = true>\n\tstruct compute_fmod\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t\t{\n\t\t\treturn detail::functor2<vec, L, T, Q>::call(std::fmod, a, b);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_fmod<L, T, Q, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, T, Q> const& a, vec<L, T, Q> const& b)\n\t\t{\n\t\t\treturn a % b;\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool isdenormal(T const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isdenormal' only accept floating-point inputs\");\n\n#\t\tif GLM_HAS_CXX11_STL\n\t\t\treturn std::fpclassify(x) == FP_SUBNORMAL;\n#\t\telse\n\t\t\treturn epsilonNotEqual(x, static_cast<T>(0), epsilon<T>()) && std::fabs(x) < std::numeric_limits<T>::min();\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename vec<1, T, Q>::bool_type isdenormal\n\t(\n\t\tvec<1, T, Q> const& x\n\t)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isdenormal' only accept floating-point inputs\");\n\n\t\treturn typename vec<1, T, Q>::bool_type(\n\t\t\tisdenormal(x.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename vec<2, T, Q>::bool_type isdenormal\n\t(\n\t\tvec<2, T, Q> const& x\n\t)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isdenormal' only accept floating-point inputs\");\n\n\t\treturn typename vec<2, T, Q>::bool_type(\n\t\t\tisdenormal(x.x),\n\t\t\tisdenormal(x.y));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename vec<3, T, Q>::bool_type isdenormal\n\t(\n\t\tvec<3, T, Q> const& x\n\t)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isdenormal' only accept floating-point inputs\");\n\n\t\treturn typename vec<3, T, Q>::bool_type(\n\t\t\tisdenormal(x.x),\n\t\t\tisdenormal(x.y),\n\t\t\tisdenormal(x.z));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename vec<4, T, Q>::bool_type isdenormal\n\t(\n\t\tvec<4, T, Q> const& x\n\t)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isdenormal' only accept floating-point inputs\");\n\n\t\treturn typename vec<4, T, Q>::bool_type(\n\t\t\tisdenormal(x.x),\n\t\t\tisdenormal(x.y),\n\t\t\tisdenormal(x.z),\n\t\t\tisdenormal(x.w));\n\t}\n\n\t// fmod\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fmod(genType x, genType y)\n\t{\n\t\treturn fmod(vec<1, genType>(x), y).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmod(vec<L, T, Q> const& x, T y)\n\t{\n\t\treturn detail::compute_fmod<L, T, Q, std::numeric_limits<T>::is_iec559>::call(x, vec<L, T, Q>(y));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fmod(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\treturn detail::compute_fmod<L, T, Q, std::numeric_limits<T>::is_iec559>::call(x, y);\n\t}\n\n\ttemplate <length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> openBounded(vec<L, T, Q> const& Value, vec<L, T, Q> const& Min, vec<L, T, Q> const& Max)\n\t{\n\t\treturn greaterThan(Value, Min) && lessThan(Value, Max);\n\t}\n\n\ttemplate <length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> closeBounded(vec<L, T, Q> const& Value, vec<L, T, Q> const& Min, vec<L, T, Q> const& Max)\n\t{\n\t\treturn greaterThanEqual(Value, Min) && lessThanEqual(Value, Max);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/compatibility.hpp",
    "content": "/// @ref gtx_compatibility\n/// @file glm/gtx/compatibility.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_compatibility GLM_GTX_compatibility\n/// @ingroup gtx\n///\n/// Include <glm/gtx/compatibility.hpp> to use the features of this extension.\n///\n/// Provide functions to increase the compatibility with Cg and HLSL languages\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/quaternion.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_compatibility is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_compatibility extension included\")\n#\tendif\n#endif\n\n#if GLM_COMPILER & GLM_COMPILER_VC\n#\tinclude <cfloat>\n#elif GLM_COMPILER & GLM_COMPILER_GCC\n#\tinclude <cmath>\n#\tif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)\n#\t\tundef isfinite\n#\tendif\n#endif//GLM_COMPILER\n\nnamespace glm\n{\n\t/// @addtogroup gtx_compatibility\n\t/// @{\n\n\ttemplate<typename T> GLM_FUNC_QUALIFIER T lerp(T x, T y, T a){return mix(x, y, a);}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//!< \\brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, T a){return mix(x, y, a);}\t\t\t\t\t\t\t//!< \\brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, T a){return mix(x, y, a);}\t\t\t\t\t\t\t//!< \\brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, T a){return mix(x, y, a);}\t\t\t\t\t\t\t//!< \\brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<2, T, Q> lerp(const vec<2, T, Q>& x, const vec<2, T, Q>& y, const vec<2, T, Q>& a){return mix(x, y, a);}\t//!< \\brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<3, T, Q> lerp(const vec<3, T, Q>& x, const vec<3, T, Q>& y, const vec<3, T, Q>& a){return mix(x, y, a);}\t//!< \\brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<4, T, Q> lerp(const vec<4, T, Q>& x, const vec<4, T, Q>& y, const vec<4, T, Q>& a){return mix(x, y, a);}\t//!< \\brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)\n\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER T saturate(T x){return clamp(x, T(0), T(1));}\t\t\t\t\t\t\t\t\t\t\t\t\t\t//!< \\brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<2, T, Q> saturate(const vec<2, T, Q>& x){return clamp(x, T(0), T(1));}\t\t\t\t\t//!< \\brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<3, T, Q> saturate(const vec<3, T, Q>& x){return clamp(x, T(0), T(1));}\t\t\t\t\t//!< \\brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<4, T, Q> saturate(const vec<4, T, Q>& x){return clamp(x, T(0), T(1));}\t\t\t\t\t//!< \\brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)\n\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER T atan2(T x, T y){return atan(x, y);}\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t//!< \\brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<2, T, Q> atan2(const vec<2, T, Q>& x, const vec<2, T, Q>& y){return atan(x, y);}\t//!< \\brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<3, T, Q> atan2(const vec<3, T, Q>& x, const vec<3, T, Q>& y){return atan(x, y);}\t//!< \\brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_QUALIFIER vec<4, T, Q> atan2(const vec<4, T, Q>& x, const vec<4, T, Q>& y){return atan(x, y);}\t//!< \\brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)\n\n\ttemplate<typename genType> GLM_FUNC_DECL bool isfinite(genType const& x);\t\t\t\t\t\t\t\t\t\t\t//!< \\brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_DECL vec<1, bool, Q> isfinite(const vec<1, T, Q>& x);\t\t\t\t//!< \\brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_DECL vec<2, bool, Q> isfinite(const vec<2, T, Q>& x);\t\t\t\t//!< \\brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_DECL vec<3, bool, Q> isfinite(const vec<3, T, Q>& x);\t\t\t\t//!< \\brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)\n\ttemplate<typename T, qualifier Q> GLM_FUNC_DECL vec<4, bool, Q> isfinite(const vec<4, T, Q>& x);\t\t\t\t//!< \\brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)\n\n\ttypedef bool\t\t\t\t\t\tbool1;\t\t\t//!< \\brief boolean type with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef vec<2, bool, highp>\t\t\tbool2;\t\t\t//!< \\brief boolean type with 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<3, bool, highp>\t\t\tbool3;\t\t\t//!< \\brief boolean type with 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<4, bool, highp>\t\t\tbool4;\t\t\t//!< \\brief boolean type with 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef bool\t\t\t\t\t\tbool1x1;\t\t//!< \\brief boolean matrix with 1 x 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 2, bool, highp>\t\tbool2x2;\t\t//!< \\brief boolean matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 3, bool, highp>\t\tbool2x3;\t\t//!< \\brief boolean matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 4, bool, highp>\t\tbool2x4;\t\t//!< \\brief boolean matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 2, bool, highp>\t\tbool3x2;\t\t//!< \\brief boolean matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 3, bool, highp>\t\tbool3x3;\t\t//!< \\brief boolean matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 4, bool, highp>\t\tbool3x4;\t\t//!< \\brief boolean matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 2, bool, highp>\t\tbool4x2;\t\t//!< \\brief boolean matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 3, bool, highp>\t\tbool4x3;\t\t//!< \\brief boolean matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 4, bool, highp>\t\tbool4x4;\t\t//!< \\brief boolean matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef int\t\t\t\t\t\t\tint1;\t\t\t//!< \\brief integer vector with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef vec<2, int, highp>\t\t\tint2;\t\t\t//!< \\brief integer vector with 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<3, int, highp>\t\t\tint3;\t\t\t//!< \\brief integer vector with 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<4, int, highp>\t\t\tint4;\t\t\t//!< \\brief integer vector with 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef int\t\t\t\t\t\t\tint1x1;\t\t\t//!< \\brief integer matrix with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 2, int, highp>\t\tint2x2;\t\t\t//!< \\brief integer matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 3, int, highp>\t\tint2x3;\t\t\t//!< \\brief integer matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 4, int, highp>\t\tint2x4;\t\t\t//!< \\brief integer matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 2, int, highp>\t\tint3x2;\t\t\t//!< \\brief integer matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 3, int, highp>\t\tint3x3;\t\t\t//!< \\brief integer matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 4, int, highp>\t\tint3x4;\t\t\t//!< \\brief integer matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 2, int, highp>\t\tint4x2;\t\t\t//!< \\brief integer matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 3, int, highp>\t\tint4x3;\t\t\t//!< \\brief integer matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 4, int, highp>\t\tint4x4;\t\t\t//!< \\brief integer matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef float\t\t\t\t\t\tfloat1;\t\t\t//!< \\brief single-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef vec<2, float, highp>\t\tfloat2;\t\t\t//!< \\brief single-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<3, float, highp>\t\tfloat3;\t\t\t//!< \\brief single-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<4, float, highp>\t\tfloat4;\t\t\t//!< \\brief single-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef float\t\t\t\t\t\tfloat1x1;\t\t//!< \\brief single-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 2, float, highp>\t\tfloat2x2;\t\t//!< \\brief single-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 3, float, highp>\t\tfloat2x3;\t\t//!< \\brief single-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 4, float, highp>\t\tfloat2x4;\t\t//!< \\brief single-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 2, float, highp>\t\tfloat3x2;\t\t//!< \\brief single-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 3, float, highp>\t\tfloat3x3;\t\t//!< \\brief single-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 4, float, highp>\t\tfloat3x4;\t\t//!< \\brief single-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 2, float, highp>\t\tfloat4x2;\t\t//!< \\brief single-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 3, float, highp>\t\tfloat4x3;\t\t//!< \\brief single-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 4, float, highp>\t\tfloat4x4;\t\t//!< \\brief single-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef double\t\t\t\t\t\tdouble1;\t\t//!< \\brief double-qualifier floating-point vector with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef vec<2, double, highp>\t\tdouble2;\t\t//!< \\brief double-qualifier floating-point vector with 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<3, double, highp>\t\tdouble3;\t\t//!< \\brief double-qualifier floating-point vector with 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef vec<4, double, highp>\t\tdouble4;\t\t//!< \\brief double-qualifier floating-point vector with 4 components. (From GLM_GTX_compatibility extension)\n\n\ttypedef double\t\t\t\t\t\tdouble1x1;\t\t//!< \\brief double-qualifier floating-point matrix with 1 component. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 2, double, highp>\t\tdouble2x2;\t\t//!< \\brief double-qualifier floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 3, double, highp>\t\tdouble2x3;\t\t//!< \\brief double-qualifier floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<2, 4, double, highp>\t\tdouble2x4;\t\t//!< \\brief double-qualifier floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 2, double, highp>\t\tdouble3x2;\t\t//!< \\brief double-qualifier floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 3, double, highp>\t\tdouble3x3;\t\t//!< \\brief double-qualifier floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<3, 4, double, highp>\t\tdouble3x4;\t\t//!< \\brief double-qualifier floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 2, double, highp>\t\tdouble4x2;\t\t//!< \\brief double-qualifier floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 3, double, highp>\t\tdouble4x3;\t\t//!< \\brief double-qualifier floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)\n\ttypedef mat<4, 4, double, highp>\t\tdouble4x4;\t\t//!< \\brief double-qualifier floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)\n\n\t/// @}\n}//namespace glm\n\n#include \"compatibility.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/compatibility.inl",
    "content": "#include <limits>\n\nnamespace glm\n{\n\t// isfinite\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER bool isfinite(\n\t\tgenType const& x)\n\t{\n#\t\tif GLM_HAS_CXX11_STL\n\t\t\treturn std::isfinite(x) != 0;\n#\t\telif GLM_COMPILER & GLM_COMPILER_VC\n\t\t\treturn _finite(x) != 0;\n#\t\telif GLM_COMPILER & GLM_COMPILER_GCC && GLM_PLATFORM & GLM_PLATFORM_ANDROID\n\t\t\treturn _isfinite(x) != 0;\n#\t\telse\n\t\t\tif (std::numeric_limits<genType>::is_integer || std::denorm_absent == std::numeric_limits<genType>::has_denorm)\n\t\t\t\treturn std::numeric_limits<genType>::min() <= x && std::numeric_limits<genType>::max() >= x;\n\t\t\telse\n\t\t\t\treturn -std::numeric_limits<genType>::max() <= x && std::numeric_limits<genType>::max() >= x;\n#\t\tendif\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<1, bool, Q> isfinite(\n\t\tvec<1, T, Q> const& x)\n\t{\n\t\treturn vec<1, bool, Q>(\n\t\t\tisfinite(x.x));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, bool, Q> isfinite(\n\t\tvec<2, T, Q> const& x)\n\t{\n\t\treturn vec<2, bool, Q>(\n\t\t\tisfinite(x.x),\n\t\t\tisfinite(x.y));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, bool, Q> isfinite(\n\t\tvec<3, T, Q> const& x)\n\t{\n\t\treturn vec<3, bool, Q>(\n\t\t\tisfinite(x.x),\n\t\t\tisfinite(x.y),\n\t\t\tisfinite(x.z));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> isfinite(\n\t\tvec<4, T, Q> const& x)\n\t{\n\t\treturn vec<4, bool, Q>(\n\t\t\tisfinite(x.x),\n\t\t\tisfinite(x.y),\n\t\t\tisfinite(x.z),\n\t\t\tisfinite(x.w));\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/component_wise.hpp",
    "content": "/// @ref gtx_component_wise\n/// @file glm/gtx/component_wise.hpp\n/// @date 2007-05-21 / 2011-06-07\n/// @author Christophe Riccio\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_component_wise GLM_GTX_component_wise\n/// @ingroup gtx\n///\n/// Include <glm/gtx/component_wise.hpp> to use the features of this extension.\n///\n/// Operations between components of a type\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_component_wise is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_component_wise extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_component_wise\n\t/// @{\n\n\t/// Convert an integer vector to a normalized float vector.\n\t/// If the parameter value type is already a floating qualifier type, the value is passed through.\n\t/// @see gtx_component_wise\n\ttemplate<typename floatType, length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, floatType, Q> compNormalize(vec<L, T, Q> const& v);\n\n\t/// Convert a normalized float vector to an integer vector.\n\t/// If the parameter value type is already a floating qualifier type, the value is passed through.\n\t/// @see gtx_component_wise\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> compScale(vec<L, floatType, Q> const& v);\n\n\t/// Add all vector components together.\n\t/// @see gtx_component_wise\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::value_type compAdd(genType const& v);\n\n\t/// Multiply all vector components together.\n\t/// @see gtx_component_wise\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::value_type compMul(genType const& v);\n\n\t/// Find the minimum value between single vector components.\n\t/// @see gtx_component_wise\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::value_type compMin(genType const& v);\n\n\t/// Find the maximum value between single vector components.\n\t/// @see gtx_component_wise\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL typename genType::value_type compMax(genType const& v);\n\n\t/// @}\n}//namespace glm\n\n#include \"component_wise.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/component_wise.inl",
    "content": "/// @ref gtx_component_wise\n\n#include <limits>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q, bool isInteger, bool signedType>\n\tstruct compute_compNormalize\n\t{};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tstruct compute_compNormalize<L, T, floatType, Q, true, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, floatType, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\tfloatType const Min = static_cast<floatType>(std::numeric_limits<T>::min());\n\t\t\tfloatType const Max = static_cast<floatType>(std::numeric_limits<T>::max());\n\t\t\treturn (vec<L, floatType, Q>(v) - Min) / (Max - Min) * static_cast<floatType>(2) - static_cast<floatType>(1);\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tstruct compute_compNormalize<L, T, floatType, Q, true, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, floatType, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\treturn vec<L, floatType, Q>(v) / static_cast<floatType>(std::numeric_limits<T>::max());\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tstruct compute_compNormalize<L, T, floatType, Q, false, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, floatType, Q> call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\treturn v;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q, bool isInteger, bool signedType>\n\tstruct compute_compScale\n\t{};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tstruct compute_compScale<L, T, floatType, Q, true, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, floatType, Q> const& v)\n\t\t{\n\t\t\tfloatType const Max = static_cast<floatType>(std::numeric_limits<T>::max()) + static_cast<floatType>(0.5);\n\t\t\tvec<L, floatType, Q> const Scaled(v * Max);\n\t\t\tvec<L, T, Q> const Result(Scaled - static_cast<floatType>(0.5));\n\t\t\treturn Result;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tstruct compute_compScale<L, T, floatType, Q, true, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, floatType, Q> const& v)\n\t\t{\n\t\t\treturn vec<L, T, Q>(vec<L, floatType, Q>(v) * static_cast<floatType>(std::numeric_limits<T>::max()));\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, typename floatType, qualifier Q>\n\tstruct compute_compScale<L, T, floatType, Q, false, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<L, T, Q> call(vec<L, floatType, Q> const& v)\n\t\t{\n\t\t\treturn v;\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename floatType, length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, floatType, Q> compNormalize(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, \"'compNormalize' accepts only floating-point types for 'floatType' template parameter\");\n\n\t\treturn detail::compute_compNormalize<L, T, floatType, Q, std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed>::call(v);\n\t}\n\n\ttemplate<typename T, length_t L, typename floatType, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> compScale(vec<L, floatType, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, \"'compScale' accepts only floating-point types for 'floatType' template parameter\");\n\n\t\treturn detail::compute_compScale<L, T, floatType, Q, std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed>::call(v);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T compAdd(vec<L, T, Q> const& v)\n\t{\n\t\tT Result(0);\n\t\tfor(length_t i = 0, n = v.length(); i < n; ++i)\n\t\t\tResult += v[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T compMul(vec<L, T, Q> const& v)\n\t{\n\t\tT Result(1);\n\t\tfor(length_t i = 0, n = v.length(); i < n; ++i)\n\t\t\tResult *= v[i];\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T compMin(vec<L, T, Q> const& v)\n\t{\n\t\tT Result(v[0]);\n\t\tfor(length_t i = 1, n = v.length(); i < n; ++i)\n\t\t\tResult = min(Result, v[i]);\n\t\treturn Result;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T compMax(vec<L, T, Q> const& v)\n\t{\n\t\tT Result(v[0]);\n\t\tfor(length_t i = 1, n = v.length(); i < n; ++i)\n\t\t\tResult = max(Result, v[i]);\n\t\treturn Result;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/dual_quaternion.hpp",
    "content": "/// @ref gtx_dual_quaternion\n/// @file glm/gtx/dual_quaternion.hpp\n/// @author Maksim Vorobiev (msomeone@gmail.com)\n///\n/// @see core (dependence)\n/// @see gtc_constants (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtx_dual_quaternion GLM_GTX_dual_quaternion\n/// @ingroup gtx\n///\n/// Include <glm/gtx/dual_quaternion.hpp> to use the features of this extension.\n///\n/// Defines a templated dual-quaternion type and several dual-quaternion operations.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/constants.hpp\"\n#include \"../gtc/quaternion.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_dual_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_dual_quaternion extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_dual_quaternion\n\t/// @{\n\n\ttemplate<typename T, qualifier Q = defaultp>\n\tstruct tdualquat\n\t{\n\t\t// -- Implementation detail --\n\n\t\ttypedef T value_type;\n\t\ttypedef qua<T, Q> part_type;\n\n\t\t// -- Data --\n\n\t\tqua<T, Q> real, dual;\n\n\t\t// -- Component accesses --\n\n\t\ttypedef length_t length_type;\n\t\t/// Return the count of components of a dual quaternion\n\t\tGLM_FUNC_DECL static GLM_CONSTEXPR length_type length(){return 2;}\n\n\t\tGLM_FUNC_DECL part_type & operator[](length_type i);\n\t\tGLM_FUNC_DECL part_type const& operator[](length_type i) const;\n\n\t\t// -- Implicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR tdualquat() GLM_DEFAULT;\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat<T, Q> const& d) GLM_DEFAULT;\n\t\ttemplate<qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat<T, P> const& d);\n\n\t\t// -- Explicit basic constructors --\n\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua<T, Q> const& real);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua<T, Q> const& orientation, vec<3, T, Q> const& translation);\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR tdualquat(qua<T, Q> const& real, qua<T, Q> const& dual);\n\n\t\t// -- Conversion constructors --\n\n\t\ttemplate<typename U, qualifier P>\n\t\tGLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tdualquat(tdualquat<U, P> const& q);\n\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<2, 4, T, Q> const& holder_mat);\n\t\tGLM_FUNC_DECL GLM_EXPLICIT GLM_CONSTEXPR tdualquat(mat<3, 4, T, Q> const& aug_mat);\n\n\t\t// -- Unary arithmetic operators --\n\n\t\tGLM_FUNC_DECL tdualquat<T, Q> & operator=(tdualquat<T, Q> const& m) GLM_DEFAULT;\n\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL tdualquat<T, Q> & operator=(tdualquat<U, Q> const& m);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL tdualquat<T, Q> & operator*=(U s);\n\t\ttemplate<typename U>\n\t\tGLM_FUNC_DECL tdualquat<T, Q> & operator/=(U s);\n\t};\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator+(tdualquat<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator-(tdualquat<T, Q> const& q);\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator+(tdualquat<T, Q> const& q, tdualquat<T, Q> const& p);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator*(tdualquat<T, Q> const& q, tdualquat<T, Q> const& p);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> operator*(tdualquat<T, Q> const& q, vec<3, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> operator*(vec<3, T, Q> const& v, tdualquat<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> operator*(tdualquat<T, Q> const& q, vec<4, T, Q> const& v);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> operator*(vec<4, T, Q> const& v, tdualquat<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator*(tdualquat<T, Q> const& q, T const& s);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator*(T const& s, tdualquat<T, Q> const& q);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> operator/(tdualquat<T, Q> const& q, T const& s);\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator==(tdualquat<T, Q> const& q1, tdualquat<T, Q> const& q2);\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool operator!=(tdualquat<T, Q> const& q1, tdualquat<T, Q> const& q2);\n\n\t/// Creates an identity dual quaternion.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate <typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> dual_quat_identity();\n\n\t/// Returns the normalized quaternion.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> normalize(tdualquat<T, Q> const& q);\n\n\t/// Returns the linear interpolation of two dual quaternion.\n\t///\n\t/// @see gtc_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> lerp(tdualquat<T, Q> const& x, tdualquat<T, Q> const& y, T const& a);\n\n\t/// Returns the q inverse.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> inverse(tdualquat<T, Q> const& q);\n\n\t/// Converts a quaternion to a 2 * 4 matrix.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> mat2x4_cast(tdualquat<T, Q> const& x);\n\n\t/// Converts a quaternion to a 3 * 4 matrix.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> mat3x4_cast(tdualquat<T, Q> const& x);\n\n\t/// Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> dualquat_cast(mat<2, 4, T, Q> const& x);\n\n\t/// Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL tdualquat<T, Q> dualquat_cast(mat<3, 4, T, Q> const& x);\n\n\n\t/// Dual-quaternion of low single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<float, lowp>\t\tlowp_dualquat;\n\n\t/// Dual-quaternion of medium single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<float, mediump>\tmediump_dualquat;\n\n\t/// Dual-quaternion of high single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<float, highp>\t\thighp_dualquat;\n\n\n\t/// Dual-quaternion of low single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<float, lowp>\t\tlowp_fdualquat;\n\n\t/// Dual-quaternion of medium single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<float, mediump>\tmediump_fdualquat;\n\n\t/// Dual-quaternion of high single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<float, highp>\t\thighp_fdualquat;\n\n\n\t/// Dual-quaternion of low double-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<double, lowp>\t\tlowp_ddualquat;\n\n\t/// Dual-quaternion of medium double-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<double, mediump>\tmediump_ddualquat;\n\n\t/// Dual-quaternion of high double-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef tdualquat<double, highp>\thighp_ddualquat;\n\n\n#if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))\n\t/// Dual-quaternion of floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef highp_fdualquat\t\t\tdualquat;\n\n\t/// Dual-quaternion of single-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef highp_fdualquat\t\t\tfdualquat;\n#elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))\n\ttypedef highp_fdualquat\t\t\tdualquat;\n\ttypedef highp_fdualquat\t\t\tfdualquat;\n#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))\n\ttypedef mediump_fdualquat\t\tdualquat;\n\ttypedef mediump_fdualquat\t\tfdualquat;\n#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT))\n\ttypedef lowp_fdualquat\t\t\tdualquat;\n\ttypedef lowp_fdualquat\t\t\tfdualquat;\n#else\n#\terror \"GLM error: multiple default precision requested for single-precision floating-point types\"\n#endif\n\n\n#if(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))\n\t/// Dual-quaternion of default double-qualifier floating-point numbers.\n\t///\n\t/// @see gtx_dual_quaternion\n\ttypedef highp_ddualquat\t\t\tddualquat;\n#elif(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))\n\ttypedef highp_ddualquat\t\t\tddualquat;\n#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))\n\ttypedef mediump_ddualquat\t\tddualquat;\n#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE))\n\ttypedef lowp_ddualquat\t\t\tddualquat;\n#else\n#\terror \"GLM error: Multiple default precision requested for double-precision floating-point types\"\n#endif\n\n\t/// @}\n} //namespace glm\n\n#include \"dual_quaternion.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/dual_quaternion.inl",
    "content": "/// @ref gtx_dual_quaternion\n\n#include \"../geometric.hpp\"\n#include <limits>\n\nnamespace glm\n{\n\t// -- Component accesses --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename tdualquat<T, Q>::part_type & tdualquat<T, Q>::operator[](typename tdualquat<T, Q>::length_type i)\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\treturn (&real)[i];\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER typename tdualquat<T, Q>::part_type const& tdualquat<T, Q>::operator[](typename tdualquat<T, Q>::length_type i) const\n\t{\n\t\tassert(i >= 0 && i < this->length());\n\t\treturn (&real)[i];\n\t}\n\n\t// -- Implicit basic constructors --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat()\n#\t\t\tif GLM_CONFIG_DEFAULTED_FUNCTIONS != GLM_DISABLE\n\t\t\t: real(qua<T, Q>())\n\t\t\t, dual(qua<T, Q>(0, 0, 0, 0))\n#\t\t\tendif\n\t\t{}\n\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(tdualquat<T, Q> const& d)\n\t\t\t: real(d.real)\n\t\t\t, dual(d.dual)\n\t\t{}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(tdualquat<T, P> const& d)\n\t\t: real(d.real)\n\t\t, dual(d.dual)\n\t{}\n\n\t// -- Explicit basic constructors --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(qua<T, Q> const& r)\n\t\t: real(r), dual(qua<T, Q>(0, 0, 0, 0))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(qua<T, Q> const& q, vec<3, T, Q> const& p)\n\t\t: real(q), dual(\n\t\t\tT(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z),\n\t\t\tT(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y),\n\t\t\tT(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x),\n\t\t\tT(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w))\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(qua<T, Q> const& r, qua<T, Q> const& d)\n\t\t: real(r), dual(d)\n\t{}\n\n\t// -- Conversion constructors --\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U, qualifier P>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(tdualquat<U, P> const& q)\n\t\t: real(q.real)\n\t\t, dual(q.dual)\n\t{}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(mat<2, 4, T, Q> const& m)\n\t{\n\t\t*this = dualquat_cast(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, Q>::tdualquat(mat<3, 4, T, Q> const& m)\n\t{\n\t\t*this = dualquat_cast(m);\n\t}\n\n\t// -- Unary arithmetic operators --\n\n#\tif GLM_CONFIG_DEFAULTED_FUNCTIONS == GLM_DISABLE\n\t\ttemplate<typename T, qualifier Q>\n\t\tGLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator=(tdualquat<T, Q> const& q)\n\t\t{\n\t\t\tthis->real = q.real;\n\t\t\tthis->dual = q.dual;\n\t\t\treturn *this;\n\t\t}\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator=(tdualquat<U, Q> const& q)\n\t{\n\t\tthis->real = q.real;\n\t\tthis->dual = q.dual;\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator*=(U s)\n\t{\n\t\tthis->real *= static_cast<T>(s);\n\t\tthis->dual *= static_cast<T>(s);\n\t\treturn *this;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\ttemplate<typename U>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> & tdualquat<T, Q>::operator/=(U s)\n\t{\n\t\tthis->real /= static_cast<T>(s);\n\t\tthis->dual /= static_cast<T>(s);\n\t\treturn *this;\n\t}\n\n\t// -- Unary bit operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator+(tdualquat<T, Q> const& q)\n\t{\n\t\treturn q;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator-(tdualquat<T, Q> const& q)\n\t{\n\t\treturn tdualquat<T, Q>(-q.real, -q.dual);\n\t}\n\n\t// -- Binary operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator+(tdualquat<T, Q> const& q, tdualquat<T, Q> const& p)\n\t{\n\t\treturn tdualquat<T, Q>(q.real + p.real,q.dual + p.dual);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator*(tdualquat<T, Q> const& p, tdualquat<T, Q> const& o)\n\t{\n\t\treturn tdualquat<T, Q>(p.real * o.real,p.real * o.dual + p.dual * o.real);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> operator*(tdualquat<T, Q> const& q, vec<3, T, Q> const& v)\n\t{\n\t\tvec<3, T, Q> const real_v3(q.real.x,q.real.y,q.real.z);\n\t\tvec<3, T, Q> const dual_v3(q.dual.x,q.dual.y,q.dual.z);\n\t\treturn (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> operator*(vec<3, T, Q> const& v,\ttdualquat<T, Q> const& q)\n\t{\n\t\treturn glm::inverse(q) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> operator*(tdualquat<T, Q> const& q, vec<4, T, Q> const& v)\n\t{\n\t\treturn vec<4, T, Q>(q * vec<3, T, Q>(v), v.w);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> operator*(vec<4, T, Q> const& v,\ttdualquat<T, Q> const& q)\n\t{\n\t\treturn glm::inverse(q) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator*(tdualquat<T, Q> const& q, T const& s)\n\t{\n\t\treturn tdualquat<T, Q>(q.real * s, q.dual * s);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator*(T const& s, tdualquat<T, Q> const& q)\n\t{\n\t\treturn q * s;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> operator/(tdualquat<T, Q> const& q,\tT const& s)\n\t{\n\t\treturn tdualquat<T, Q>(q.real / s, q.dual / s);\n\t}\n\n\t// -- Boolean operators --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator==(tdualquat<T, Q> const& q1, tdualquat<T, Q> const& q2)\n\t{\n\t\treturn (q1.real == q2.real) && (q1.dual == q2.dual);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool operator!=(tdualquat<T, Q> const& q1, tdualquat<T, Q> const& q2)\n\t{\n\t\treturn (q1.real != q2.real) || (q1.dual != q2.dual);\n\t}\n\n\t// -- Operations --\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> dual_quat_identity()\n\t{\n\t\treturn tdualquat<T, Q>(\n\t\t\tqua<T, Q>(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0)),\n\t\t\tqua<T, Q>(static_cast<T>(0), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> normalize(tdualquat<T, Q> const& q)\n\t{\n\t\treturn q / length(q.real);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> lerp(tdualquat<T, Q> const& x, tdualquat<T, Q> const& y, T const& a)\n\t{\n\t\t// Dual Quaternion Linear blend aka DLB:\n\t\t// Lerp is only defined in [0, 1]\n\t\tassert(a >= static_cast<T>(0));\n\t\tassert(a <= static_cast<T>(1));\n\t\tT const k = dot(x.real,y.real) < static_cast<T>(0) ? -a : a;\n\t\tT const one(1);\n\t\treturn tdualquat<T, Q>(x * (one - a) + y * k);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> inverse(tdualquat<T, Q> const& q)\n\t{\n\t\tconst glm::qua<T, Q> real = conjugate(q.real);\n\t\tconst glm::qua<T, Q> dual = conjugate(q.dual);\n\t\treturn tdualquat<T, Q>(real, dual + (real * (-2.0f * dot(real,dual))));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> mat2x4_cast(tdualquat<T, Q> const& x)\n\t{\n\t\treturn mat<2, 4, T, Q>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w );\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> mat3x4_cast(tdualquat<T, Q> const& x)\n\t{\n\t\tqua<T, Q> r = x.real / length2(x.real);\n\n\t\tqua<T, Q> const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z);\n\t\tr *= static_cast<T>(2);\n\n\t\tT const xy = r.x * x.real.y;\n\t\tT const xz = r.x * x.real.z;\n\t\tT const yz = r.y * x.real.z;\n\t\tT const wx = r.w * x.real.x;\n\t\tT const wy = r.w * x.real.y;\n\t\tT const wz = r.w * x.real.z;\n\n\t\tvec<4, T, Q> const a(\n\t\t\trr.w + rr.x - rr.y - rr.z,\n\t\t\txy - wz,\n\t\t\txz + wy,\n\t\t\t-(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y));\n\n\t\tvec<4, T, Q> const b(\n\t\t\txy + wz,\n\t\t\trr.w + rr.y - rr.x - rr.z,\n\t\t\tyz - wx,\n\t\t\t-(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x));\n\n\t\tvec<4, T, Q> const c(\n\t\t\txz - wy,\n\t\t\tyz + wx,\n\t\t\trr.w + rr.z - rr.x - rr.y,\n\t\t\t-(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w));\n\n\t\treturn mat<3, 4, T, Q>(a, b, c);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> dualquat_cast(mat<2, 4, T, Q> const& x)\n\t{\n\t\treturn tdualquat<T, Q>(\n\t\t\tqua<T, Q>( x[0].w, x[0].x, x[0].y, x[0].z ),\n\t\t\tqua<T, Q>( x[1].w, x[1].x, x[1].y, x[1].z ));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER tdualquat<T, Q> dualquat_cast(mat<3, 4, T, Q> const& x)\n\t{\n\t\tqua<T, Q> real;\n\n\t\tT const trace = x[0].x + x[1].y + x[2].z;\n\t\tif(trace > static_cast<T>(0))\n\t\t{\n\t\t\tT const r = sqrt(T(1) + trace);\n\t\t\tT const invr = static_cast<T>(0.5) / r;\n\t\t\treal.w = static_cast<T>(0.5) * r;\n\t\t\treal.x = (x[2].y - x[1].z) * invr;\n\t\t\treal.y = (x[0].z - x[2].x) * invr;\n\t\t\treal.z = (x[1].x - x[0].y) * invr;\n\t\t}\n\t\telse if(x[0].x > x[1].y && x[0].x > x[2].z)\n\t\t{\n\t\t\tT const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z);\n\t\t\tT const invr = static_cast<T>(0.5) / r;\n\t\t\treal.x = static_cast<T>(0.5)*r;\n\t\t\treal.y = (x[1].x + x[0].y) * invr;\n\t\t\treal.z = (x[0].z + x[2].x) * invr;\n\t\t\treal.w = (x[2].y - x[1].z) * invr;\n\t\t}\n\t\telse if(x[1].y > x[2].z)\n\t\t{\n\t\t\tT const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z);\n\t\t\tT const invr = static_cast<T>(0.5) / r;\n\t\t\treal.x = (x[1].x + x[0].y) * invr;\n\t\t\treal.y = static_cast<T>(0.5) * r;\n\t\t\treal.z = (x[2].y + x[1].z) * invr;\n\t\t\treal.w = (x[0].z - x[2].x) * invr;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tT const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y);\n\t\t\tT const invr = static_cast<T>(0.5) / r;\n\t\t\treal.x = (x[0].z + x[2].x) * invr;\n\t\t\treal.y = (x[2].y + x[1].z) * invr;\n\t\t\treal.z = static_cast<T>(0.5) * r;\n\t\t\treal.w = (x[1].x - x[0].y) * invr;\n\t\t}\n\n\t\tqua<T, Q> dual;\n\t\tdual.x =  static_cast<T>(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y);\n\t\tdual.y =  static_cast<T>(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x);\n\t\tdual.z =  static_cast<T>(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w);\n\t\tdual.w = -static_cast<T>(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z);\n\t\treturn tdualquat<T, Q>(real, dual);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/easing.hpp",
    "content": "/// @ref gtx_easing\n/// @file glm/gtx/easing.hpp\n/// @author Robert Chisholm\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_easing GLM_GTX_easing\n/// @ingroup gtx\n///\n/// Include <glm/gtx/easing.hpp> to use the features of this extension.\n///\n/// Easing functions for animations and transitons\n/// All functions take a parameter x in the range [0.0,1.0]\n///\n/// Based on the AHEasing project of Warren Moore (https://github.com/warrenm/AHEasing)\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/constants.hpp\"\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_easing is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_easing extension included\")\n#\tendif\n#endif\n\nnamespace glm{\n\t/// @addtogroup gtx_easing\n\t/// @{\n\n\t/// Modelled after the line y = x\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType linearInterpolation(genType const & a);\n\n\t/// Modelled after the parabola y = x^2\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quadraticEaseIn(genType const & a);\n\n\t/// Modelled after the parabola y = -x^2 + 2x\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quadraticEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise quadratic\n\t/// y = (1/2)((2x)^2)\t\t\t\t; [0, 0.5)\n\t/// y = -(1/2)((2x-1)*(2x-3) - 1)\t; [0.5, 1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quadraticEaseInOut(genType const & a);\n\n\t/// Modelled after the cubic y = x^3\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType cubicEaseIn(genType const & a);\n\n\t/// Modelled after the cubic y = (x - 1)^3 + 1\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType cubicEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise cubic\n\t/// y = (1/2)((2x)^3)\t\t; [0, 0.5)\n\t/// y = (1/2)((2x-2)^3 + 2)\t; [0.5, 1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType cubicEaseInOut(genType const & a);\n\n\t/// Modelled after the quartic x^4\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quarticEaseIn(genType const & a);\n\n\t/// Modelled after the quartic y = 1 - (x - 1)^4\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quarticEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise quartic\n\t/// y = (1/2)((2x)^4)\t\t\t; [0, 0.5)\n\t/// y = -(1/2)((2x-2)^4 - 2)\t; [0.5, 1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quarticEaseInOut(genType const & a);\n\n\t/// Modelled after the quintic y = x^5\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quinticEaseIn(genType const & a);\n\n\t/// Modelled after the quintic y = (x - 1)^5 + 1\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quinticEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise quintic\n\t/// y = (1/2)((2x)^5)\t\t; [0, 0.5)\n\t/// y = (1/2)((2x-2)^5 + 2) ; [0.5, 1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType quinticEaseInOut(genType const & a);\n\n\t/// Modelled after quarter-cycle of sine wave\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType sineEaseIn(genType const & a);\n\n\t/// Modelled after quarter-cycle of sine wave (different phase)\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType sineEaseOut(genType const & a);\n\n\t/// Modelled after half sine wave\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType sineEaseInOut(genType const & a);\n\n\t/// Modelled after shifted quadrant IV of unit circle\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType circularEaseIn(genType const & a);\n\n\t/// Modelled after shifted quadrant II of unit circle\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType circularEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise circular function\n\t/// y = (1/2)(1 - sqrt(1 - 4x^2))\t\t\t; [0, 0.5)\n\t/// y = (1/2)(sqrt(-(2x - 3)*(2x - 1)) + 1) ; [0.5, 1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType circularEaseInOut(genType const & a);\n\n\t/// Modelled after the exponential function y = 2^(10(x - 1))\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType exponentialEaseIn(genType const & a);\n\n\t/// Modelled after the exponential function y = -2^(-10x) + 1\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType exponentialEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise exponential\n\t/// y = (1/2)2^(10(2x - 1))\t\t\t; [0,0.5)\n\t/// y = -(1/2)*2^(-10(2x - 1))) + 1 ; [0.5,1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType exponentialEaseInOut(genType const & a);\n\n\t/// Modelled after the damped sine wave y = sin(13pi/2*x)*pow(2, 10 * (x - 1))\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType elasticEaseIn(genType const & a);\n\n\t/// Modelled after the damped sine wave y = sin(-13pi/2*(x + 1))*pow(2, -10x) + 1\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType elasticEaseOut(genType const & a);\n\n\t/// Modelled after the piecewise exponentially-damped sine wave:\n\t/// y = (1/2)*sin(13pi/2*(2*x))*pow(2, 10 * ((2*x) - 1))\t\t; [0,0.5)\n\t/// y = (1/2)*(sin(-13pi/2*((2x-1)+1))*pow(2,-10(2*x-1)) + 2)\t; [0.5, 1]\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType elasticEaseInOut(genType const & a);\n\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType backEaseIn(genType const& a);\n\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType backEaseOut(genType const& a);\n\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType backEaseInOut(genType const& a);\n\n\t/// @param a parameter\n\t/// @param o Optional overshoot modifier\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType backEaseIn(genType const& a, genType const& o);\n\n\t/// @param a parameter\n\t/// @param o Optional overshoot modifier\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType backEaseOut(genType const& a, genType const& o);\n\n\t/// @param a parameter\n\t/// @param o Optional overshoot modifier\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType backEaseInOut(genType const& a, genType const& o);\n\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType bounceEaseIn(genType const& a);\n\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType bounceEaseOut(genType const& a);\n\n\t/// @see gtx_easing\n\ttemplate <typename genType>\n\tGLM_FUNC_DECL genType bounceEaseInOut(genType const& a);\n\n\t/// @}\n}//namespace glm\n\n#include \"easing.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/easing.inl",
    "content": "/// @ref gtx_easing\n\n#include <cmath>\n\nnamespace glm{\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType linearInterpolation(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn a;\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quadraticEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn a * a;\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quadraticEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn -(a * (a - static_cast<genType>(2)));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quadraticEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn static_cast<genType>(2) * a * a;\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn (-static_cast<genType>(2) * a * a) + (4 * a) - one<genType>();\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType cubicEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn a * a * a;\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType cubicEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tgenType const f = a - one<genType>();\n\t\treturn f * f * f + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType cubicEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif (a < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn static_cast<genType>(4) * a * a * a;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgenType const f = ((static_cast<genType>(2) * a) - static_cast<genType>(2));\n\t\t\treturn static_cast<genType>(0.5) * f * f * f + one<genType>();\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quarticEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn a * a * a * a;\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quarticEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tgenType const f = (a - one<genType>());\n\t\treturn f * f * f * (one<genType>() - a) + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quarticEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn static_cast<genType>(8) * a * a * a * a;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgenType const f = (a - one<genType>());\n\t\t\treturn -static_cast<genType>(8) * f * f * f * f + one<genType>();\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quinticEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn a * a * a * a * a;\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quinticEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tgenType const f = (a - one<genType>());\n\t\treturn f * f * f * f * f + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType quinticEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn static_cast<genType>(16) * a * a * a * a * a;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tgenType const f = ((static_cast<genType>(2) * a) - static_cast<genType>(2));\n\t\t\treturn static_cast<genType>(0.5) * f * f * f * f * f + one<genType>();\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType sineEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn sin((a - one<genType>()) * half_pi<genType>()) + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType sineEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn sin(a * half_pi<genType>());\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType sineEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn static_cast<genType>(0.5) * (one<genType>() - cos(a * pi<genType>()));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType circularEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn one<genType>() - sqrt(one<genType>() - (a * a));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType circularEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn sqrt((static_cast<genType>(2) - a) * a);\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType circularEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn static_cast<genType>(0.5) * (one<genType>() - std::sqrt(one<genType>() - static_cast<genType>(4) * (a * a)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn static_cast<genType>(0.5) * (std::sqrt(-((static_cast<genType>(2) * a) - static_cast<genType>(3)) * ((static_cast<genType>(2) * a) - one<genType>())) + one<genType>());\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType exponentialEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a <= zero<genType>())\n\t\t\treturn a;\n\t\telse\n\t\t{\n\t\t\tgenType const Complementary = a - one<genType>();\n\t\t\tgenType const Two = static_cast<genType>(2);\n\t\t\t\n\t\t\treturn glm::pow(Two, Complementary * static_cast<genType>(10));\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType exponentialEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a >= one<genType>())\n\t\t\treturn a;\n\t\telse\n\t\t{\n\t\t\treturn one<genType>() - glm::pow(static_cast<genType>(2), -static_cast<genType>(10) * a);\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType exponentialEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t\treturn static_cast<genType>(0.5) * glm::pow(static_cast<genType>(2), (static_cast<genType>(20) * a) - static_cast<genType>(10));\n\t\telse\n\t\t\treturn -static_cast<genType>(0.5) * glm::pow(static_cast<genType>(2), (-static_cast<genType>(20) * a) + static_cast<genType>(10)) + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType elasticEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn std::sin(static_cast<genType>(13) * half_pi<genType>() * a) * glm::pow(static_cast<genType>(2), static_cast<genType>(10) * (a - one<genType>()));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType elasticEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn std::sin(-static_cast<genType>(13) * half_pi<genType>() * (a + one<genType>())) * glm::pow(static_cast<genType>(2), -static_cast<genType>(10) * a) + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType elasticEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t\treturn static_cast<genType>(0.5) * std::sin(static_cast<genType>(13) * half_pi<genType>() * (static_cast<genType>(2) * a)) * glm::pow(static_cast<genType>(2), static_cast<genType>(10) * ((static_cast<genType>(2) * a) - one<genType>()));\n\t\telse\n\t\t\treturn static_cast<genType>(0.5) * (std::sin(-static_cast<genType>(13) * half_pi<genType>() * ((static_cast<genType>(2) * a - one<genType>()) + one<genType>())) * glm::pow(static_cast<genType>(2), -static_cast<genType>(10) * (static_cast<genType>(2) * a - one<genType>())) + static_cast<genType>(2));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType backEaseIn(genType const& a, genType const& o)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tgenType z = ((o + one<genType>()) * a) - o;\n\t\treturn (a * a * z);\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType backEaseOut(genType const& a, genType const& o)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tgenType n = a - one<genType>();\n\t\tgenType z = ((o + one<genType>()) * n) + o;\n\t\treturn (n * n * z) + one<genType>();\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a, genType const& o)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tgenType s = o * static_cast<genType>(1.525);\n\t\tgenType x = static_cast<genType>(0.5);\n\t\tgenType n = a / static_cast<genType>(0.5);\n\n\t\tif (n < static_cast<genType>(1))\n\t\t{\n\t\t\tgenType z = ((s + static_cast<genType>(1)) * n) - s;\n\t\t\tgenType m = n * n * z;\n\t\t\treturn x * m;\n\t\t}\n\t\telse \n\t\t{\n\t\t\tn -= static_cast<genType>(2);\n\t\t\tgenType z = ((s + static_cast<genType>(1)) * n) + s;\n\t\t\tgenType m = (n*n*z) + static_cast<genType>(2);\n\t\t\treturn x * m;\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType backEaseIn(genType const& a)\n\t{\n\t\treturn backEaseIn(a, static_cast<genType>(1.70158));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType backEaseOut(genType const& a)\n\t{\n\t\treturn backEaseOut(a, static_cast<genType>(1.70158));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType backEaseInOut(genType const& a)\n\t{\n\t\treturn backEaseInOut(a, static_cast<genType>(1.70158));\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType bounceEaseOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(4.0 / 11.0))\n\t\t{\n\t\t\treturn (static_cast<genType>(121) * a * a) / static_cast<genType>(16);\n\t\t}\n\t\telse if(a < static_cast<genType>(8.0 / 11.0))\n\t\t{\n\t\t\treturn (static_cast<genType>(363.0 / 40.0) * a * a) - (static_cast<genType>(99.0 / 10.0) * a) + static_cast<genType>(17.0 / 5.0);\n\t\t}\n\t\telse if(a < static_cast<genType>(9.0 / 10.0))\n\t\t{\n\t\t\treturn (static_cast<genType>(4356.0 / 361.0) * a * a) - (static_cast<genType>(35442.0 / 1805.0) * a) + static_cast<genType>(16061.0 / 1805.0);\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn (static_cast<genType>(54.0 / 5.0) * a * a) - (static_cast<genType>(513.0 / 25.0) * a) + static_cast<genType>(268.0 / 25.0);\n\t\t}\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType bounceEaseIn(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\treturn one<genType>() - bounceEaseOut(one<genType>() - a);\n\t}\n\n\ttemplate <typename genType>\n\tGLM_FUNC_QUALIFIER genType bounceEaseInOut(genType const& a)\n\t{\n\t\t// Only defined in [0, 1]\n\t\tassert(a >= zero<genType>());\n\t\tassert(a <= one<genType>());\n\n\t\tif(a < static_cast<genType>(0.5))\n\t\t{\n\t\t\treturn static_cast<genType>(0.5) * (one<genType>() - bounceEaseOut(a * static_cast<genType>(2)));\n\t\t}\n\t\telse\n\t\t{\n\t\t\treturn static_cast<genType>(0.5) * bounceEaseOut(a * static_cast<genType>(2) - one<genType>()) + static_cast<genType>(0.5);\n\t\t}\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/euler_angles.hpp",
    "content": "/// @ref gtx_euler_angles\n/// @file glm/gtx/euler_angles.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_euler_angles GLM_GTX_euler_angles\n/// @ingroup gtx\n///\n/// Include <glm/gtx/euler_angles.hpp> to use the features of this extension.\n///\n/// Build matrices from Euler angles.\n///\n/// Extraction of Euler angles from rotation matrix.\n/// Based on the original paper 2014 Mike Day - Extracting Euler Angles from a Rotation Matrix.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_euler_angles is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_euler_angles extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_euler_angles\n\t/// @{\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle X.\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleX(\n\t\tT const& angleX);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Y.\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleY(\n\t\tT const& angleY);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Z.\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZ(\n\t\tT const& angleZ);\n\n\t/// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about X-axis.\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleX(\n\t\tT const & angleX, T const & angularVelocityX);\n\n\t/// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Y-axis.\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleY(\n\t\tT const & angleY, T const & angularVelocityY);\n\n\t/// Creates a 3D 4 * 4 homogeneous derived matrix from the rotation matrix about Z-axis.\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> derivedEulerAngleZ(\n\t\tT const & angleZ, T const & angularVelocityZ);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXY(\n\t\tT const& angleX,\n\t\tT const& angleY);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYX(\n\t\tT const& angleY,\n\t\tT const& angleX);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZ(\n\t\tT const& angleX,\n\t\tT const& angleZ);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZX(\n\t\tT const& angle,\n\t\tT const& angleX);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZ(\n\t\tT const& angleY,\n\t\tT const& angleZ);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZY(\n\t\tT const& angleZ,\n\t\tT const& angleY);\n\n    /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * Z).\n    /// @see gtx_euler_angles\n    template<typename T>\n    GLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYZ(\n        T const& t1,\n        T const& t2,\n        T const& t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXZ(\n\t\tT const& yaw,\n\t\tT const& pitch,\n\t\tT const& roll);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * X).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZX(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * X).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXYX(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Y).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYXY(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * Y).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZY(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * Z).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYZ(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Z).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXZ(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z * Y).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleXZY(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z * X).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleYZX(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y * X).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZYX(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X * Y).\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> eulerAngleZXY(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<4, 4, T, defaultp> yawPitchRoll(\n\t\tT const& yaw,\n\t\tT const& pitch,\n\t\tT const& roll);\n\n\t/// Creates a 2D 2 * 2 rotation matrix from an euler angle.\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<2, 2, T, defaultp> orientate2(T const& angle);\n\n\t/// Creates a 2D 4 * 4 homogeneous rotation matrix from an euler angle.\n\t/// @see gtx_euler_angles\n\ttemplate<typename T>\n\tGLM_FUNC_DECL mat<3, 3, T, defaultp> orientate3(T const& angle);\n\n\t/// Creates a 3D 3 * 3 rotation matrix from euler angles (Y * X * Z).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> orientate3(vec<3, T, Q> const& angles);\n\n\t/// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z).\n\t/// @see gtx_euler_angles\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> orientate4(vec<3, T, Q> const& angles);\n\n    /// Extracts the (X * Y * Z) Euler angles from the rotation matrix M\n    /// @see gtx_euler_angles\n    template<typename T>\n    GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M,\n                                            T & t1,\n                                            T & t2,\n                                            T & t3);\n\n\t/// Extracts the (Y * X * Z) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (X * Z * X) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (X * Y * X) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Y * X * Y) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Y * Z * Y) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Z * Y * Z) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Z * X * Z) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (X * Z * Y) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Y * Z * X) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Z * Y * X) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// Extracts the (Z * X * Y) Euler angles from the rotation matrix M\n\t/// @see gtx_euler_angles\n\ttemplate <typename T>\n\tGLM_FUNC_DECL void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\tT & t1,\n\t\t\t\t\t\t\t\t\t\t\tT & t2,\n\t\t\t\t\t\t\t\t\t\t\tT & t3);\n\n\t/// @}\n}//namespace glm\n\n#include \"euler_angles.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/euler_angles.inl",
    "content": "/// @ref gtx_euler_angles\n\n#include \"compatibility.hpp\" // glm::atan2\n\nnamespace glm\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleX\n\t(\n\t\tT const& angleX\n\t)\n\t{\n\t\tT cosX = glm::cos(angleX);\n\t\tT sinX = glm::sin(angleX);\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\tT(1), T(0), T(0), T(0),\n\t\t\tT(0), cosX, sinX, T(0),\n\t\t\tT(0),-sinX, cosX, T(0),\n\t\t\tT(0), T(0), T(0), T(1));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleY\n\t(\n\t\tT const& angleY\n\t)\n\t{\n\t\tT cosY = glm::cos(angleY);\n\t\tT sinY = glm::sin(angleY);\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\tcosY,\tT(0),\t-sinY,\tT(0),\n\t\t\tT(0),\tT(1),\tT(0),\tT(0),\n\t\t\tsinY,\tT(0),\tcosY,\tT(0),\n\t\t\tT(0),\tT(0),\tT(0),\tT(1));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZ\n\t(\n\t\tT const& angleZ\n\t)\n\t{\n\t\tT cosZ = glm::cos(angleZ);\n\t\tT sinZ = glm::sin(angleZ);\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\tcosZ,\tsinZ,\tT(0), T(0),\n\t\t\t-sinZ,\tcosZ,\tT(0), T(0),\n\t\t\tT(0),\tT(0),\tT(1), T(0),\n\t\t\tT(0),\tT(0),\tT(0), T(1));\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleX\n\t(\n\t\tT const & angleX,\n\t\tT const & angularVelocityX\n\t)\n\t{\n\t\tT cosX = glm::cos(angleX) * angularVelocityX;\n\t\tT sinX = glm::sin(angleX) * angularVelocityX;\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\tT(0), T(0), T(0), T(0),\n\t\t\tT(0),-sinX, cosX, T(0),\n\t\t\tT(0),-cosX,-sinX, T(0),\n\t\t\tT(0), T(0), T(0), T(0));\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleY\n\t(\n\t\tT const & angleY,\n\t\tT const & angularVelocityY\n\t)\n\t{\n\t\tT cosY = glm::cos(angleY) * angularVelocityY;\n\t\tT sinY = glm::sin(angleY) * angularVelocityY;\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\t-sinY, T(0), -cosY, T(0),\n\t\t\t T(0), T(0),  T(0), T(0),\n\t\t\t cosY, T(0), -sinY, T(0),\n\t\t\t T(0), T(0),  T(0), T(0));\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> derivedEulerAngleZ\n\t(\n\t\tT const & angleZ,\n\t\tT const & angularVelocityZ\n\t)\n\t{\n\t\tT cosZ = glm::cos(angleZ) * angularVelocityZ;\n\t\tT sinZ = glm::sin(angleZ) * angularVelocityZ;\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\t-sinZ,  cosZ, T(0), T(0),\n\t\t\t-cosZ, -sinZ, T(0), T(0),\n\t\t\t T(0),  T(0), T(0), T(0),\n\t\t\t T(0),  T(0), T(0), T(0));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXY\n\t(\n\t\tT const& angleX,\n\t\tT const& angleY\n\t)\n\t{\n\t\tT cosX = glm::cos(angleX);\n\t\tT sinX = glm::sin(angleX);\n\t\tT cosY = glm::cos(angleY);\n\t\tT sinY = glm::sin(angleY);\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\tcosY,   -sinX * -sinY,  cosX * -sinY,   T(0),\n\t\t\tT(0),   cosX,           sinX,           T(0),\n\t\t\tsinY,   -sinX * cosY,   cosX * cosY,    T(0),\n\t\t\tT(0),   T(0),           T(0),           T(1));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYX\n\t(\n\t\tT const& angleY,\n\t\tT const& angleX\n\t)\n\t{\n\t\tT cosX = glm::cos(angleX);\n\t\tT sinX = glm::sin(angleX);\n\t\tT cosY = glm::cos(angleY);\n\t\tT sinY = glm::sin(angleY);\n\n\t\treturn mat<4, 4, T, defaultp>(\n\t\t\tcosY,          0,      -sinY,    T(0),\n\t\t\tsinY * sinX,  cosX, cosY * sinX, T(0),\n\t\t\tsinY * cosX, -sinX, cosY * cosX, T(0),\n\t\t\tT(0),         T(0),     T(0),    T(1));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZ\n\t(\n\t\tT const& angleX,\n\t\tT const& angleZ\n\t)\n\t{\n\t\treturn eulerAngleX(angleX) * eulerAngleZ(angleZ);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZX\n\t(\n\t\tT const& angleZ,\n\t\tT const& angleX\n\t)\n\t{\n\t\treturn eulerAngleZ(angleZ) * eulerAngleX(angleX);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZ\n\t(\n\t\tT const& angleY,\n\t\tT const& angleZ\n\t)\n\t{\n\t\treturn eulerAngleY(angleY) * eulerAngleZ(angleZ);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZY\n\t(\n\t\tT const& angleZ,\n\t\tT const& angleY\n\t)\n\t{\n\t\treturn eulerAngleZ(angleZ) * eulerAngleY(angleY);\n\t}\n\n    template<typename T>\n    GLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYZ\n    (\n     T const& t1,\n     T const& t2,\n     T const& t3\n     )\n    {\n        T c1 = glm::cos(-t1);\n        T c2 = glm::cos(-t2);\n        T c3 = glm::cos(-t3);\n        T s1 = glm::sin(-t1);\n        T s2 = glm::sin(-t2);\n        T s3 = glm::sin(-t3);\n\n        mat<4, 4, T, defaultp> Result;\n        Result[0][0] = c2 * c3;\n        Result[0][1] =-c1 * s3 + s1 * s2 * c3;\n        Result[0][2] = s1 * s3 + c1 * s2 * c3;\n        Result[0][3] = static_cast<T>(0);\n        Result[1][0] = c2 * s3;\n        Result[1][1] = c1 * c3 + s1 * s2 * s3;\n        Result[1][2] =-s1 * c3 + c1 * s2 * s3;\n        Result[1][3] = static_cast<T>(0);\n        Result[2][0] =-s2;\n        Result[2][1] = s1 * c2;\n        Result[2][2] = c1 * c2;\n        Result[2][3] = static_cast<T>(0);\n        Result[3][0] = static_cast<T>(0);\n        Result[3][1] = static_cast<T>(0);\n        Result[3][2] = static_cast<T>(0);\n        Result[3][3] = static_cast<T>(1);\n        return Result;\n    }\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXZ\n\t(\n\t\tT const& yaw,\n\t\tT const& pitch,\n\t\tT const& roll\n\t)\n\t{\n\t\tT tmp_ch = glm::cos(yaw);\n\t\tT tmp_sh = glm::sin(yaw);\n\t\tT tmp_cp = glm::cos(pitch);\n\t\tT tmp_sp = glm::sin(pitch);\n\t\tT tmp_cb = glm::cos(roll);\n\t\tT tmp_sb = glm::sin(roll);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb;\n\t\tResult[0][1] = tmp_sb * tmp_cp;\n\t\tResult[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb;\n\t\tResult[1][1] = tmp_cb * tmp_cp;\n\t\tResult[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = tmp_sh * tmp_cp;\n\t\tResult[2][1] = -tmp_sp;\n\t\tResult[2][2] = tmp_ch * tmp_cp;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZX\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c2;\n\t\tResult[0][1] = c1 * s2;\n\t\tResult[0][2] = s1 * s2;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] =-c3 * s2;\n\t\tResult[1][1] = c1 * c2 * c3 - s1 * s3;\n\t\tResult[1][2] = c1 * s3 + c2 * c3 * s1;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = s2 * s3;\n\t\tResult[2][1] =-c3 * s1 - c1 * c2 * s3;\n\t\tResult[2][2] = c1 * c3 - c2 * s1 * s3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXYX\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c2;\n\t\tResult[0][1] = s1 * s2;\n\t\tResult[0][2] =-c1 * s2;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] = s2 * s3;\n\t\tResult[1][1] = c1 * c3 - c2 * s1 * s3;\n\t\tResult[1][2] = c3 * s1 + c1 * c2 * s3;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c3 * s2;\n\t\tResult[2][1] =-c1 * s3 - c2 * c3 * s1;\n\t\tResult[2][2] = c1 * c2 * c3 - s1 * s3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYXY\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c3 - c2 * s1 * s3;\n\t\tResult[0][1] = s2* s3;\n\t\tResult[0][2] =-c3 * s1 - c1 * c2 * s3;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] = s1 * s2;\n\t\tResult[1][1] = c2;\n\t\tResult[1][2] = c1 * s2;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c1 * s3 + c2 * c3 * s1;\n\t\tResult[2][1] =-c3 * s2;\n\t\tResult[2][2] = c1 * c2 * c3 - s1 * s3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZY\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c2 * c3 - s1 * s3;\n\t\tResult[0][1] = c3 * s2;\n\t\tResult[0][2] =-c1 * s3 - c2 * c3 * s1;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] =-c1 * s2;\n\t\tResult[1][1] = c2;\n\t\tResult[1][2] = s1 * s2;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c3 * s1 + c1 * c2 * s3;\n\t\tResult[2][1] = s2 * s3;\n\t\tResult[2][2] = c1 * c3 - c2 * s1 * s3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYZ\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c2 * c3 - s1 * s3;\n\t\tResult[0][1] = c1 * s3 + c2 * c3 * s1;\n\t\tResult[0][2] =-c3 * s2;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] =-c3 * s1 - c1 * c2 * s3;\n\t\tResult[1][1] = c1 * c3 - c2 * s1 * s3;\n\t\tResult[1][2] = s2 * s3;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c1 * s2;\n\t\tResult[2][1] = s1 * s2;\n\t\tResult[2][2] = c2;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXZ\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c3 - c2 * s1 * s3;\n\t\tResult[0][1] = c3 * s1 + c1 * c2 * s3;\n\t\tResult[0][2] = s2 *s3;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] =-c1 * s3 - c2 * c3 * s1;\n\t\tResult[1][1] = c1 * c2 * c3 - s1 * s3;\n\t\tResult[1][2] = c3 * s2;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = s1 * s2;\n\t\tResult[2][1] =-c1 * s2;\n\t\tResult[2][2] = c2;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleXZY\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c2 * c3;\n\t\tResult[0][1] = s1 * s3 + c1 * c3 * s2;\n\t\tResult[0][2] = c3 * s1 * s2 - c1 * s3;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] =-s2;\n\t\tResult[1][1] = c1 * c2;\n\t\tResult[1][2] = c2 * s1;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c2 * s3;\n\t\tResult[2][1] = c1 * s2 * s3 - c3 * s1;\n\t\tResult[2][2] = c1 * c3 + s1 * s2 *s3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleYZX\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c2;\n\t\tResult[0][1] = s2;\n\t\tResult[0][2] =-c2 * s1;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] = s1 * s3 - c1 * c3 * s2;\n\t\tResult[1][1] = c2 * c3;\n\t\tResult[1][2] = c1 * s3 + c3 * s1 * s2;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c3 * s1 + c1 * s2 * s3;\n\t\tResult[2][1] =-c2 * s3;\n\t\tResult[2][2] = c1 * c3 - s1 * s2 * s3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZYX\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c2;\n\t\tResult[0][1] = c2 * s1;\n\t\tResult[0][2] =-s2;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] = c1 * s2 * s3 - c3 * s1;\n\t\tResult[1][1] = c1 * c3 + s1 * s2 * s3;\n\t\tResult[1][2] = c2 * s3;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = s1 * s3 + c1 * c3 * s2;\n\t\tResult[2][1] = c3 * s1 * s2 - c1 * s3;\n\t\tResult[2][2] = c2 * c3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> eulerAngleZXY\n\t(\n\t\tT const & t1,\n\t\tT const & t2,\n\t\tT const & t3\n\t)\n\t{\n\t\tT c1 = glm::cos(t1);\n\t\tT s1 = glm::sin(t1);\n\t\tT c2 = glm::cos(t2);\n\t\tT s2 = glm::sin(t2);\n\t\tT c3 = glm::cos(t3);\n\t\tT s3 = glm::sin(t3);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = c1 * c3 - s1 * s2 * s3;\n\t\tResult[0][1] = c3 * s1 + c1 * s2 * s3;\n\t\tResult[0][2] =-c2 * s3;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] =-c2 * s1;\n\t\tResult[1][1] = c1 * c2;\n\t\tResult[1][2] = s2;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = c1 * s3 + c3 * s1 * s2;\n\t\tResult[2][1] = s1 * s3 - c1 * c3 * s2;\n\t\tResult[2][2] = c2 * c3;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, defaultp> yawPitchRoll\n\t(\n\t\tT const& yaw,\n\t\tT const& pitch,\n\t\tT const& roll\n\t)\n\t{\n\t\tT tmp_ch = glm::cos(yaw);\n\t\tT tmp_sh = glm::sin(yaw);\n\t\tT tmp_cp = glm::cos(pitch);\n\t\tT tmp_sp = glm::sin(pitch);\n\t\tT tmp_cb = glm::cos(roll);\n\t\tT tmp_sb = glm::sin(roll);\n\n\t\tmat<4, 4, T, defaultp> Result;\n\t\tResult[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb;\n\t\tResult[0][1] = tmp_sb * tmp_cp;\n\t\tResult[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb;\n\t\tResult[0][3] = static_cast<T>(0);\n\t\tResult[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb;\n\t\tResult[1][1] = tmp_cb * tmp_cp;\n\t\tResult[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb;\n\t\tResult[1][3] = static_cast<T>(0);\n\t\tResult[2][0] = tmp_sh * tmp_cp;\n\t\tResult[2][1] = -tmp_sp;\n\t\tResult[2][2] = tmp_ch * tmp_cp;\n\t\tResult[2][3] = static_cast<T>(0);\n\t\tResult[3][0] = static_cast<T>(0);\n\t\tResult[3][1] = static_cast<T>(0);\n\t\tResult[3][2] = static_cast<T>(0);\n\t\tResult[3][3] = static_cast<T>(1);\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, defaultp> orientate2\n\t(\n\t\tT const& angle\n\t)\n\t{\n\t\tT c = glm::cos(angle);\n\t\tT s = glm::sin(angle);\n\n\t\tmat<2, 2, T, defaultp> Result;\n\t\tResult[0][0] = c;\n\t\tResult[0][1] = s;\n\t\tResult[1][0] = -s;\n\t\tResult[1][1] = c;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, defaultp> orientate3\n\t(\n\t\tT const& angle\n\t)\n\t{\n\t\tT c = glm::cos(angle);\n\t\tT s = glm::sin(angle);\n\n\t\tmat<3, 3, T, defaultp> Result;\n\t\tResult[0][0] = c;\n\t\tResult[0][1] = s;\n\t\tResult[0][2] = 0.0f;\n\t\tResult[1][0] = -s;\n\t\tResult[1][1] = c;\n\t\tResult[1][2] = 0.0f;\n\t\tResult[2][0] = 0.0f;\n\t\tResult[2][1] = 0.0f;\n\t\tResult[2][2] = 1.0f;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> orientate3\n\t(\n\t\tvec<3, T, Q> const& angles\n\t)\n\t{\n\t\treturn mat<3, 3, T, Q>(yawPitchRoll(angles.z, angles.x, angles.y));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientate4\n\t(\n\t\tvec<3, T, Q> const& angles\n\t)\n\t{\n\t\treturn yawPitchRoll(angles.z, angles.x, angles.y);\n\t}\n\n    template<typename T>\n    GLM_FUNC_DECL void extractEulerAngleXYZ(mat<4, 4, T, defaultp> const& M,\n                                            T & t1,\n                                            T & t2,\n                                            T & t3)\n    {\n        T T1 = glm::atan2<T, defaultp>(M[2][1], M[2][2]);\n        T C2 = glm::sqrt(M[0][0]*M[0][0] + M[1][0]*M[1][0]);\n        T T2 = glm::atan2<T, defaultp>(-M[2][0], C2);\n        T S1 = glm::sin(T1);\n        T C1 = glm::cos(T1);\n        T T3 = glm::atan2<T, defaultp>(S1*M[0][2] - C1*M[0][1], C1*M[1][1] - S1*M[1][2  ]);\n        t1 = -T1;\n        t2 = -T2;\n        t3 = -T3;\n    }\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleYXZ(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[2][0], M[2][2]);\n\t\tT C2 = glm::sqrt(M[0][1]*M[0][1] + M[1][1]*M[1][1]);\n\t\tT T2 = glm::atan2<T, defaultp>(-M[2][1], C2);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(S1*M[1][2] - C1*M[1][0], C1*M[0][0] - S1*M[0][2]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleXZX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[0][2], M[0][1]);\n\t\tT S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]);\n\t\tT T2 = glm::atan2<T, defaultp>(S2, M[0][0]);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(C1*M[1][2] - S1*M[1][1], C1*M[2][2] - S1*M[2][1]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleXYX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[0][1], -M[0][2]);\n\t\tT S2 = glm::sqrt(M[1][0]*M[1][0] + M[2][0]*M[2][0]);\n\t\tT T2 = glm::atan2<T, defaultp>(S2, M[0][0]);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(-C1*M[2][1] - S1*M[2][2], C1*M[1][1] + S1*M[1][2]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleYXY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[1][0], M[1][2]);\n\t\tT S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]);\n\t\tT T2 = glm::atan2<T, defaultp>(S2, M[1][1]);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(C1*M[2][0] - S1*M[2][2], C1*M[0][0] - S1*M[0][2]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleYZY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[1][2], -M[1][0]);\n\t\tT S2 = glm::sqrt(M[0][1]*M[0][1] + M[2][1]*M[2][1]);\n\t\tT T2 = glm::atan2<T, defaultp>(S2, M[1][1]);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(-S1*M[0][0] - C1*M[0][2], S1*M[2][0] + C1*M[2][2]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleZYZ(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[2][1], M[2][0]);\n\t\tT S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]);\n\t\tT T2 = glm::atan2<T, defaultp>(S2, M[2][2]);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(C1*M[0][1] - S1*M[0][0], C1*M[1][1] - S1*M[1][0]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleZXZ(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[2][0], -M[2][1]);\n\t\tT S2 = glm::sqrt(M[0][2]*M[0][2] + M[1][2]*M[1][2]);\n\t\tT T2 = glm::atan2<T, defaultp>(S2, M[2][2]);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(-C1*M[1][0] - S1*M[1][1], C1*M[0][0] + S1*M[0][1]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleXZY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[1][2], M[1][1]);\n\t\tT C2 = glm::sqrt(M[0][0]*M[0][0] + M[2][0]*M[2][0]);\n\t\tT T2 = glm::atan2<T, defaultp>(-M[1][0], C2);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(S1*M[0][1] - C1*M[0][2], C1*M[2][2] - S1*M[2][1]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleYZX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(-M[0][2], M[0][0]);\n\t\tT C2 = glm::sqrt(M[1][1]*M[1][1] + M[2][1]*M[2][1]);\n\t\tT T2 = glm::atan2<T, defaultp>(M[0][1], C2);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(S1*M[1][0] + C1*M[1][2], S1*M[2][0] + C1*M[2][2]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleZYX(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(M[0][1], M[0][0]);\n\t\tT C2 = glm::sqrt(M[1][2]*M[1][2] + M[2][2]*M[2][2]);\n\t\tT T2 = glm::atan2<T, defaultp>(-M[0][2], C2);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(S1*M[2][0] - C1*M[2][1], C1*M[1][1] - S1*M[1][0]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n\n\ttemplate <typename T>\n\tGLM_FUNC_QUALIFIER void extractEulerAngleZXY(mat<4, 4, T, defaultp> const & M,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t1,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t2,\n\t\t\t\t\t\t\t\t\t\t\t\t T & t3)\n\t{\n\t\tT T1 = glm::atan2<T, defaultp>(-M[1][0], M[1][1]);\n\t\tT C2 = glm::sqrt(M[0][2]*M[0][2] + M[2][2]*M[2][2]);\n\t\tT T2 = glm::atan2<T, defaultp>(M[1][2], C2);\n\t\tT S1 = glm::sin(T1);\n\t\tT C1 = glm::cos(T1);\n\t\tT T3 = glm::atan2<T, defaultp>(C1*M[2][0] + S1*M[2][1], C1*M[0][0] + S1*M[0][1]);\n\t\tt1 = T1;\n\t\tt2 = T2;\n\t\tt3 = T3;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/extend.hpp",
    "content": "/// @ref gtx_extend\n/// @file glm/gtx/extend.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_extend GLM_GTX_extend\n/// @ingroup gtx\n///\n/// Include <glm/gtx/extend.hpp> to use the features of this extension.\n///\n/// Extend a position from a source to a position at a defined length.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_extend extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_extend\n\t/// @{\n\n\t/// Extends of Length the Origin position using the (Source - Origin) direction.\n\t/// @see gtx_extend\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType extend(\n\t\tgenType const& Origin,\n\t\tgenType const& Source,\n\t\ttypename genType::value_type const Length);\n\n\t/// @}\n}//namespace glm\n\n#include \"extend.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/extend.inl",
    "content": "/// @ref gtx_extend\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType extend\n\t(\n\t\tgenType const& Origin,\n\t\tgenType const& Source,\n\t\tgenType const& Distance\n\t)\n\t{\n\t\treturn Origin + (Source - Origin) * Distance;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> extend\n\t(\n\t\tvec<2, T, Q> const& Origin,\n\t\tvec<2, T, Q> const& Source,\n\t\tT const& Distance\n\t)\n\t{\n\t\treturn Origin + (Source - Origin) * Distance;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> extend\n\t(\n\t\tvec<3, T, Q> const& Origin,\n\t\tvec<3, T, Q> const& Source,\n\t\tT const& Distance\n\t)\n\t{\n\t\treturn Origin + (Source - Origin) * Distance;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> extend\n\t(\n\t\tvec<4, T, Q> const& Origin,\n\t\tvec<4, T, Q> const& Source,\n\t\tT const& Distance\n\t)\n\t{\n\t\treturn Origin + (Source - Origin) * Distance;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/extended_min_max.hpp",
    "content": "/// @ref gtx_extended_min_max\n/// @file glm/gtx/extended_min_max.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_extended_min_max GLM_GTX_extented_min_max\n/// @ingroup gtx\n///\n/// Include <glm/gtx/extented_min_max.hpp> to use the features of this extension.\n///\n/// Min and max functions for 3 to 4 parameters.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../ext/vector_common.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_extented_min_max is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_extented_min_max extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_extended_min_max\n\t/// @{\n\n\t/// Return the minimum component-wise values of 3 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T min(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z);\n\n\t/// Return the minimum component-wise values of 3 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> min(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z);\n\n\t/// Return the minimum component-wise values of 3 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> min(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z);\n\n\t/// Return the minimum component-wise values of 4 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T min(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z,\n\t\tT const& w);\n\n\t/// Return the minimum component-wise values of 4 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> min(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z,\n\t\ttypename C<T>::T const& w);\n\n\t/// Return the minimum component-wise values of 4 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> min(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z,\n\t\tC<T> const& w);\n\n\t/// Return the maximum component-wise values of 3 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T max(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z);\n\n\t/// Return the maximum component-wise values of 3 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> max(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z);\n\n\t/// Return the maximum component-wise values of 3 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> max(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z);\n\n\t/// Return the maximum component-wise values of 4 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T max(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z,\n\t\tT const& w);\n\n\t/// Return the maximum component-wise values of 4 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> max(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z,\n\t\ttypename C<T>::T const& w);\n\n\t/// Return the maximum component-wise values of 4 inputs\n\t/// @see gtx_extented_min_max\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_DECL C<T> max(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z,\n\t\tC<T> const& w);\n\n\t/// @}\n}//namespace glm\n\n#include \"extended_min_max.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/extended_min_max.inl",
    "content": "/// @ref gtx_extended_min_max\n\nnamespace glm\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T min(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z)\n\t{\n\t\treturn glm::min(glm::min(x, y), z);\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> min\n\t(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z\n\t)\n\t{\n\t\treturn glm::min(glm::min(x, y), z);\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> min\n\t(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z\n\t)\n\t{\n\t\treturn glm::min(glm::min(x, y), z);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T min\n\t(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z,\n\t\tT const& w\n\t)\n\t{\n\t\treturn glm::min(glm::min(x, y), glm::min(z, w));\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> min\n\t(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z,\n\t\ttypename C<T>::T const& w\n\t)\n\t{\n\t\treturn glm::min(glm::min(x, y), glm::min(z, w));\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> min\n\t(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z,\n\t\tC<T> const& w\n\t)\n\t{\n\t\treturn glm::min(glm::min(x, y), glm::min(z, w));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T max(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z)\n\t{\n\t\treturn glm::max(glm::max(x, y), z);\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> max\n\t(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z\n\t)\n\t{\n\t\treturn glm::max(glm::max(x, y), z);\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> max\n\t(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z\n\t)\n\t{\n\t\treturn glm::max(glm::max(x, y), z);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T max\n\t(\n\t\tT const& x,\n\t\tT const& y,\n\t\tT const& z,\n\t\tT const& w\n\t)\n\t{\n\t\treturn glm::max(glm::max(x, y), glm::max(z, w));\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> max\n\t(\n\t\tC<T> const& x,\n\t\ttypename C<T>::T const& y,\n\t\ttypename C<T>::T const& z,\n\t\ttypename C<T>::T const& w\n\t)\n\t{\n\t\treturn glm::max(glm::max(x, y), glm::max(z, w));\n\t}\n\n\ttemplate<typename T, template<typename> class C>\n\tGLM_FUNC_QUALIFIER C<T> max\n\t(\n\t\tC<T> const& x,\n\t\tC<T> const& y,\n\t\tC<T> const& z,\n\t\tC<T> const& w\n\t)\n\t{\n\t\treturn glm::max(glm::max(x, y), glm::max(z, w));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/exterior_product.hpp",
    "content": "/// @ref gtx_exterior_product\n/// @file glm/gtx/exterior_product.hpp\n///\n/// @see core (dependence)\n/// @see gtx_exterior_product (dependence)\n///\n/// @defgroup gtx_exterior_product GLM_GTX_exterior_product\n/// @ingroup gtx\n///\n/// Include <glm/gtx/exterior_product.hpp> to use the features of this extension.\n///\n/// @brief Allow to perform bit operations on integer values\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_exterior_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_exterior_product extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_exterior_product\n\t/// @{\n\n\t/// Returns the cross product of x and y.\n\t///\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"https://en.wikipedia.org/wiki/Exterior_algebra#Cross_and_triple_products\">Exterior product</a>\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T cross(vec<2, T, Q> const& v, vec<2, T, Q> const& u);\n\n\t/// @}\n} //namespace glm\n\n#include \"exterior_product.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/exterior_product.inl",
    "content": "/// @ref gtx_exterior_product\n\n#include <limits>\n\nnamespace glm {\nnamespace detail\n{\n\ttemplate<typename T, qualifier Q, bool Aligned>\n\tstruct compute_cross_vec2\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<2, T, Q> const& v, vec<2, T, Q> const& u)\n\t\t{\n\t\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'cross' accepts only floating-point inputs\");\n\n\t\t\treturn v.x * u.y - u.x * v.y;\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T cross(vec<2, T, Q> const& x, vec<2, T, Q> const& y)\n\t{\n\t\treturn detail::compute_cross_vec2<T, Q, detail::is_aligned<Q>::value>::call(x, y);\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/fast_exponential.hpp",
    "content": "/// @ref gtx_fast_exponential\n/// @file glm/gtx/fast_exponential.hpp\n///\n/// @see core (dependence)\n/// @see gtx_half_float (dependence)\n///\n/// @defgroup gtx_fast_exponential GLM_GTX_fast_exponential\n/// @ingroup gtx\n///\n/// Include <glm/gtx/fast_exponential.hpp> to use the features of this extension.\n///\n/// Fast but less accurate implementations of exponential based functions.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_fast_exponential is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_fast_exponential extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_fast_exponential\n\t/// @{\n\n\t/// Faster than the common pow function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fastPow(genType x, genType y);\n\n\t/// Faster than the common pow function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastPow(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Faster than the common pow function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<typename genTypeT, typename genTypeU>\n\tGLM_FUNC_DECL genTypeT fastPow(genTypeT x, genTypeU y);\n\n\t/// Faster than the common pow function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastPow(vec<L, T, Q> const& x);\n\n\t/// Faster than the common exp function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastExp(T x);\n\n\t/// Faster than the common exp function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastExp(vec<L, T, Q> const& x);\n\n\t/// Faster than the common log function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastLog(T x);\n\n\t/// Faster than the common exp2 function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastLog(vec<L, T, Q> const& x);\n\n\t/// Faster than the common exp2 function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastExp2(T x);\n\n\t/// Faster than the common exp2 function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastExp2(vec<L, T, Q> const& x);\n\n\t/// Faster than the common log2 function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastLog2(T x);\n\n\t/// Faster than the common log2 function but less accurate.\n\t/// @see gtx_fast_exponential\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastLog2(vec<L, T, Q> const& x);\n\n\t/// @}\n}//namespace glm\n\n#include \"fast_exponential.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/fast_exponential.inl",
    "content": "/// @ref gtx_fast_exponential\n\nnamespace glm\n{\n\t// fastPow:\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastPow(genType x, genType y)\n\t{\n\t\treturn exp(y * log(x));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastPow(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\treturn exp(y * log(x));\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastPow(T x, int y)\n\t{\n\t\tT f = static_cast<T>(1);\n\t\tfor(int i = 0; i < y; ++i)\n\t\t\tf *= x;\n\t\treturn f;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastPow(vec<L, T, Q> const& x, vec<L, int, Q> const& y)\n\t{\n\t\tvec<L, T, Q> Result;\n\t\tfor(length_t i = 0, n = x.length(); i < n; ++i)\n\t\t\tResult[i] = fastPow(x[i], y[i]);\n\t\treturn Result;\n\t}\n\n\t// fastExp\n\t// Note: This function provides accurate results only for value between -1 and 1, else avoid it.\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastExp(T x)\n\t{\n\t\t// This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower.\n\t\t// return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f))));\n\t\tT x2 = x * x;\n\t\tT x3 = x2 * x;\n\t\tT x4 = x3 * x;\n\t\tT x5 = x4 * x;\n\t\treturn T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333));\n\t}\n\t/*  // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance\n\tGLM_FUNC_QUALIFIER float fastExp(float x)\n\t{\n\t\tconst float e = 2.718281828f;\n\t\tconst float IntegerPart = floor(x);\n\t\tconst float FloatPart = x - IntegerPart;\n\t\tfloat z = 1.f;\n\n\t\tfor(int i = 0; i < int(IntegerPart); ++i)\n\t\t\tz *= e;\n\n\t\tconst float x2 = FloatPart * FloatPart;\n\t\tconst float x3 = x2 * FloatPart;\n\t\tconst float x4 = x3 * FloatPart;\n\t\tconst float x5 = x4 * FloatPart;\n\t\treturn z * (1.0f + FloatPart + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f));\n\t}\n\n\t// Increase accuracy on number bigger that 1 and smaller than -1 but it's not enough for high and negative numbers\n\tGLM_FUNC_QUALIFIER float fastExp(float x)\n\t{\n\t\t// This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower.\n\t\t// return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f))));\n\t\tfloat x2 = x * x;\n\t\tfloat x3 = x2 * x;\n\t\tfloat x4 = x3 * x;\n\t\tfloat x5 = x4 * x;\n\t\tfloat x6 = x5 * x;\n\t\tfloat x7 = x6 * x;\n\t\tfloat x8 = x7 * x;\n\t\treturn 1.0f + x + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)+ (x6 * 0.00138888888888f) + (x7 * 0.000198412698f) + (x8 * 0.0000248015873f);;\n\t}\n\t*/\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastExp(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastExp, x);\n\t}\n\n\t// fastLog\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastLog(genType x)\n\t{\n\t\treturn std::log(x);\n\t}\n\n\t/* Slower than the VC7.1 function...\n\tGLM_FUNC_QUALIFIER float fastLog(float x)\n\t{\n\t\tfloat y1 = (x - 1.0f) / (x + 1.0f);\n\t\tfloat y2 = y1 * y1;\n\t\treturn 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f)));\n\t}\n\t*/\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastLog(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastLog, x);\n\t}\n\n\t//fastExp2, ln2 = 0.69314718055994530941723212145818f\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastExp2(genType x)\n\t{\n\t\treturn fastExp(0.69314718055994530941723212145818f * x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastExp2(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastExp2, x);\n\t}\n\n\t// fastLog2, ln2 = 0.69314718055994530941723212145818f\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastLog2(genType x)\n\t{\n\t\treturn fastLog(x) / 0.69314718055994530941723212145818f;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastLog2(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastLog2, x);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/fast_square_root.hpp",
    "content": "/// @ref gtx_fast_square_root\n/// @file glm/gtx/fast_square_root.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_fast_square_root GLM_GTX_fast_square_root\n/// @ingroup gtx\n///\n/// Include <glm/gtx/fast_square_root.hpp> to use the features of this extension.\n///\n/// Fast but less accurate implementations of square root based functions.\n/// - Sqrt optimisation based on Newton's method,\n/// www.gamedev.net/community/forums/topic.asp?topic id=139956\n\n#pragma once\n\n// Dependency:\n#include \"../common.hpp\"\n#include \"../exponential.hpp\"\n#include \"../geometric.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_fast_square_root is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_fast_square_root extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_fast_square_root\n\t/// @{\n\n\t/// Faster than the common sqrt function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fastSqrt(genType x);\n\n\t/// Faster than the common sqrt function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastSqrt(vec<L, T, Q> const& x);\n\n\t/// Faster than the common inversesqrt function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fastInverseSqrt(genType x);\n\n\t/// Faster than the common inversesqrt function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> fastInverseSqrt(vec<L, T, Q> const& x);\n\n\t/// Faster than the common length function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fastLength(genType x);\n\n\t/// Faster than the common length function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T fastLength(vec<L, T, Q> const& x);\n\n\t/// Faster than the common distance function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fastDistance(genType x, genType y);\n\n\t/// Faster than the common distance function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T fastDistance(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Faster than the common normalize function but less accurate.\n\t///\n\t/// @see gtx_fast_square_root extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType fastNormalize(genType const& x);\n\n\t/// @}\n}// namespace glm\n\n#include \"fast_square_root.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/fast_square_root.inl",
    "content": "/// @ref gtx_fast_square_root\n\nnamespace glm\n{\n\t// fastSqrt\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastSqrt(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'fastSqrt' only accept floating-point input\");\n\n\t\treturn genType(1) / fastInverseSqrt(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastSqrt(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastSqrt, x);\n\t}\n\n\t// fastInversesqrt\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastInverseSqrt(genType x)\n\t{\n\t\treturn detail::compute_inversesqrt<1, genType, lowp, detail::is_aligned<lowp>::value>::call(vec<1, genType, lowp>(x)).x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastInverseSqrt(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::compute_inversesqrt<L, T, Q, detail::is_aligned<Q>::value>::call(x);\n\t}\n\n\t// fastLength\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastLength(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'fastLength' only accept floating-point inputs\");\n\n\t\treturn abs(x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T fastLength(vec<L, T, Q> const& x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'fastLength' only accept floating-point inputs\");\n\n\t\treturn fastSqrt(dot(x, x));\n\t}\n\n\t// fastDistance\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastDistance(genType x, genType y)\n\t{\n\t\treturn fastLength(y - x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T fastDistance(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\treturn fastLength(y - x);\n\t}\n\n\t// fastNormalize\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType fastNormalize(genType x)\n\t{\n\t\treturn x > genType(0) ? genType(1) : -genType(1);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastNormalize(vec<L, T, Q> const& x)\n\t{\n\t\treturn x * fastInverseSqrt(dot(x, x));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/fast_trigonometry.hpp",
    "content": "/// @ref gtx_fast_trigonometry\n/// @file glm/gtx/fast_trigonometry.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_fast_trigonometry GLM_GTX_fast_trigonometry\n/// @ingroup gtx\n///\n/// Include <glm/gtx/fast_trigonometry.hpp> to use the features of this extension.\n///\n/// Fast but less accurate implementations of trigonometric functions.\n\n#pragma once\n\n// Dependency:\n#include \"../gtc/constants.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_fast_trigonometry is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_fast_trigonometry extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_fast_trigonometry\n\t/// @{\n\n\t/// Wrap an angle to [0 2pi[\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T wrapAngle(T angle);\n\n\t/// Faster than the common sin function but less accurate.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastSin(T angle);\n\n\t/// Faster than the common cos function but less accurate.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastCos(T angle);\n\n\t/// Faster than the common tan function but less accurate.\n\t/// Defined between -2pi and 2pi.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastTan(T angle);\n\n\t/// Faster than the common asin function but less accurate.\n\t/// Defined between -2pi and 2pi.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastAsin(T angle);\n\n\t/// Faster than the common acos function but less accurate.\n\t/// Defined between -2pi and 2pi.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastAcos(T angle);\n\n\t/// Faster than the common atan function but less accurate.\n\t/// Defined between -2pi and 2pi.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastAtan(T y, T x);\n\n\t/// Faster than the common atan function but less accurate.\n\t/// Defined between -2pi and 2pi.\n\t/// From GLM_GTX_fast_trigonometry extension.\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T fastAtan(T angle);\n\n\t/// @}\n}//namespace glm\n\n#include \"fast_trigonometry.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/fast_trigonometry.inl",
    "content": "/// @ref gtx_fast_trigonometry\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> taylorCos(vec<L, T, Q> const& x)\n\t{\n\t\treturn static_cast<T>(1)\n\t\t\t- (x * x) * (1.f / 2.f)\n\t\t\t+ ((x * x) * (x * x)) * (1.f / 24.f)\n\t\t\t- (((x * x) * (x * x)) * (x * x)) * (1.f / 720.f)\n\t\t\t+ (((x * x) * (x * x)) * ((x * x) * (x * x))) * (1.f / 40320.f);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T cos_52s(T x)\n\t{\n\t\tT const xx(x * x);\n\t\treturn (T(0.9999932946) + xx * (T(-0.4999124376) + xx * (T(0.0414877472) + xx * T(-0.0012712095))));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> cos_52s(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(cos_52s, x);\n\t}\n}//namespace detail\n\n\t// wrapAngle\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T wrapAngle(T angle)\n\t{\n\t\treturn abs<T>(mod<T>(angle, two_pi<T>()));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> wrapAngle(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(wrapAngle, x);\n\t}\n\n\t// cos\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastCos(T x)\n\t{\n\t\tT const angle(wrapAngle<T>(x));\n\n\t\tif(angle < half_pi<T>())\n\t\t\treturn detail::cos_52s(angle);\n\t\tif(angle < pi<T>())\n\t\t\treturn -detail::cos_52s(pi<T>() - angle);\n\t\tif(angle < (T(3) * half_pi<T>()))\n\t\t\treturn -detail::cos_52s(angle - pi<T>());\n\n\t\treturn detail::cos_52s(two_pi<T>() - angle);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastCos(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastCos, x);\n\t}\n\n\t// sin\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastSin(T x)\n\t{\n\t\treturn fastCos<T>(half_pi<T>() - x);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastSin(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastSin, x);\n\t}\n\n\t// tan\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastTan(T x)\n\t{\n\t\treturn x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastTan(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastTan, x);\n\t}\n\n\t// asin\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastAsin(T x)\n\t{\n\t\treturn x + (x * x * x * T(0.166666667)) + (x * x * x * x * x * T(0.075)) + (x * x * x * x * x * x * x * T(0.0446428571)) + (x * x * x * x * x * x * x * x * x * T(0.0303819444));// + (x * x * x * x * x * x * x * x * x * x * x * T(0.022372159));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastAsin(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastAsin, x);\n\t}\n\n\t// acos\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastAcos(T x)\n\t{\n\t\treturn T(1.5707963267948966192313216916398) - fastAsin(x); //(PI / 2)\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastAcos(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastAcos, x);\n\t}\n\n\t// atan\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastAtan(T y, T x)\n\t{\n\t\tT sgn = sign(y) * sign(x);\n\t\treturn abs(fastAtan(y / x)) * sgn;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastAtan(vec<L, T, Q> const& y, vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor2<vec, L, T, Q>::call(fastAtan, y, x);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T fastAtan(T x)\n\t{\n\t\treturn x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> fastAtan(vec<L, T, Q> const& x)\n\t{\n\t\treturn detail::functor1<vec, L, T, T, Q>::call(fastAtan, x);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/float_notmalize.inl",
    "content": "/// @ref gtx_float_normalize\n\n#include <limits>\n\nnamespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, float, Q> floatNormalize(vec<L, T, Q> const& v)\n\t{\n\t\treturn vec<L, float, Q>(v) / static_cast<float>(std::numeric_limits<T>::max());\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/functions.hpp",
    "content": "/// @ref gtx_functions\n/// @file glm/gtx/functions.hpp\n///\n/// @see core (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtx_functions GLM_GTX_functions\n/// @ingroup gtx\n///\n/// Include <glm/gtx/functions.hpp> to use the features of this extension.\n///\n/// List of useful common functions.\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n#include \"../detail/qualifier.hpp\"\n#include \"../detail/type_vec2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_functions is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_functions extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_functions\n\t/// @{\n\n\t/// 1D gauss function\n\t///\n\t/// @see gtc_epsilon\n\ttemplate<typename T>\n\tGLM_FUNC_DECL T gauss(\n\t\tT x,\n\t\tT ExpectedValue,\n\t\tT StandardDeviation);\n\n\t/// 2D gauss function\n\t///\n\t/// @see gtc_epsilon\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T gauss(\n\t\tvec<2, T, Q> const& Coord,\n\t\tvec<2, T, Q> const& ExpectedValue,\n\t\tvec<2, T, Q> const& StandardDeviation);\n\n\t/// @}\n}//namespace glm\n\n#include \"functions.inl\"\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/functions.inl",
    "content": "/// @ref gtx_functions\n\n#include \"../exponential.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T gauss\n\t(\n\t\tT x,\n\t\tT ExpectedValue,\n\t\tT StandardDeviation\n\t)\n\t{\n\t\treturn exp(-((x - ExpectedValue) * (x - ExpectedValue)) / (static_cast<T>(2) * StandardDeviation * StandardDeviation)) / (StandardDeviation * sqrt(static_cast<T>(6.28318530717958647692528676655900576)));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T gauss\n\t(\n\t\tvec<2, T, Q> const& Coord,\n\t\tvec<2, T, Q> const& ExpectedValue,\n\t\tvec<2, T, Q> const& StandardDeviation\n\t)\n\t{\n\t\tvec<2, T, Q> const Squared = ((Coord - ExpectedValue) * (Coord - ExpectedValue)) / (static_cast<T>(2) * StandardDeviation * StandardDeviation);\n\t\treturn exp(-(Squared.x + Squared.y));\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/gradient_paint.hpp",
    "content": "/// @ref gtx_gradient_paint\n/// @file glm/gtx/gradient_paint.hpp\n///\n/// @see core (dependence)\n/// @see gtx_optimum_pow (dependence)\n///\n/// @defgroup gtx_gradient_paint GLM_GTX_gradient_paint\n/// @ingroup gtx\n///\n/// Include <glm/gtx/gradient_paint.hpp> to use the features of this extension.\n///\n/// Functions that return the color of procedural gradient for specific coordinates.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtx/optimum_pow.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_gradient_paint is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_gradient_paint extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_gradient_paint\n\t/// @{\n\n\t/// Return a color from a radial gradient.\n\t/// @see - gtx_gradient_paint\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T radialGradient(\n\t\tvec<2, T, Q> const& Center,\n\t\tT const& Radius,\n\t\tvec<2, T, Q> const& Focal,\n\t\tvec<2, T, Q> const& Position);\n\n\t/// Return a color from a linear gradient.\n\t/// @see - gtx_gradient_paint\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T linearGradient(\n\t\tvec<2, T, Q> const& Point0,\n\t\tvec<2, T, Q> const& Point1,\n\t\tvec<2, T, Q> const& Position);\n\n\t/// @}\n}// namespace glm\n\n#include \"gradient_paint.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/gradient_paint.inl",
    "content": "/// @ref gtx_gradient_paint\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T radialGradient\n\t(\n\t\tvec<2, T, Q> const& Center,\n\t\tT const& Radius,\n\t\tvec<2, T, Q> const& Focal,\n\t\tvec<2, T, Q> const& Position\n\t)\n\t{\n\t\tvec<2, T, Q> F = Focal - Center;\n\t\tvec<2, T, Q> D = Position - Focal;\n\t\tT Radius2 = pow2(Radius);\n\t\tT Fx2 = pow2(F.x);\n\t\tT Fy2 = pow2(F.y);\n\n\t\tT Numerator = (D.x * F.x + D.y * F.y) + sqrt(Radius2 * (pow2(D.x) + pow2(D.y)) - pow2(D.x * F.y - D.y * F.x));\n\t\tT Denominator = Radius2 - (Fx2 + Fy2);\n\t\treturn Numerator / Denominator;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T linearGradient\n\t(\n\t\tvec<2, T, Q> const& Point0,\n\t\tvec<2, T, Q> const& Point1,\n\t\tvec<2, T, Q> const& Position\n\t)\n\t{\n\t\tvec<2, T, Q> Dist = Point1 - Point0;\n\t\treturn (Dist.x * (Position.x - Point0.x) + Dist.y * (Position.y - Point0.y)) / glm::dot(Dist, Dist);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/handed_coordinate_space.hpp",
    "content": "/// @ref gtx_handed_coordinate_space\n/// @file glm/gtx/handed_coordinate_space.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_handed_coordinate_space GLM_GTX_handed_coordinate_space\n/// @ingroup gtx\n///\n/// Include <glm/gtx/handed_coordinate_system.hpp> to use the features of this extension.\n///\n/// To know if a set of three basis vectors defines a right or left-handed coordinate system.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_handed_coordinate_space is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_handed_coordinate_space extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_handed_coordinate_space\n\t/// @{\n\n\t//! Return if a trihedron right handed or not.\n\t//! From GLM_GTX_handed_coordinate_space extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool rightHanded(\n\t\tvec<3, T, Q> const& tangent,\n\t\tvec<3, T, Q> const& binormal,\n\t\tvec<3, T, Q> const& normal);\n\n\t//! Return if a trihedron left handed or not.\n\t//! From GLM_GTX_handed_coordinate_space extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool leftHanded(\n\t\tvec<3, T, Q> const& tangent,\n\t\tvec<3, T, Q> const& binormal,\n\t\tvec<3, T, Q> const& normal);\n\n\t/// @}\n}// namespace glm\n\n#include \"handed_coordinate_space.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/handed_coordinate_space.inl",
    "content": "/// @ref gtx_handed_coordinate_space\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool rightHanded\n\t(\n\t\tvec<3, T, Q> const& tangent,\n\t\tvec<3, T, Q> const& binormal,\n\t\tvec<3, T, Q> const& normal\n\t)\n\t{\n\t\treturn dot(cross(normal, tangent), binormal) > T(0);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool leftHanded\n\t(\n\t\tvec<3, T, Q> const& tangent,\n\t\tvec<3, T, Q> const& binormal,\n\t\tvec<3, T, Q> const& normal\n\t)\n\t{\n\t\treturn dot(cross(normal, tangent), binormal) < T(0);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/hash.hpp",
    "content": "/// @ref gtx_hash\n/// @file glm/gtx/hash.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_hash GLM_GTX_hash\n/// @ingroup gtx\n///\n/// Include <glm/gtx/hash.hpp> to use the features of this extension.\n///\n/// Add std::hash support for glm types\n\n#pragma once\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_hash is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_hash extension included\")\n#\tendif\n#endif\n\n#include <functional>\n\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../gtc/vec1.hpp\"\n\n#include \"../gtc/quaternion.hpp\"\n#include \"../gtx/dual_quaternion.hpp\"\n\n#include \"../mat2x2.hpp\"\n#include \"../mat2x3.hpp\"\n#include \"../mat2x4.hpp\"\n\n#include \"../mat3x2.hpp\"\n#include \"../mat3x3.hpp\"\n#include \"../mat3x4.hpp\"\n\n#include \"../mat4x2.hpp\"\n#include \"../mat4x3.hpp\"\n#include \"../mat4x4.hpp\"\n\n#if !GLM_HAS_CXX11_STL\n#\terror \"GLM_GTX_hash requires C++11 standard library support\"\n#endif\n\nnamespace std\n{\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::vec<1, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::vec<1, T, Q> const& v) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::vec<2, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::vec<2, T, Q> const& v) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::vec<3, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::vec<3, T, Q> const& v) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::vec<4, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::vec<4, T, Q> const& v) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::qua<T,Q>>\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::qua<T, Q> const& q) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::tdualquat<T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::tdualquat<T,Q> const& q) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<2, 2, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<2, 2, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<2, 3, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<2, 3, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<2, 4, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<2, 4, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<3, 2, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<3, 2, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<3, 3, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<3, 3, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<3, 4, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<3, 4, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<4, 2, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<4, 2, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<4, 3, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<4, 3, T,Q> const& m) const;\n\t};\n\n\ttemplate<typename T, glm::qualifier Q>\n\tstruct hash<glm::mat<4, 4, T,Q> >\n\t{\n\t\tGLM_FUNC_DECL size_t operator()(glm::mat<4, 4, T,Q> const& m) const;\n\t};\n} // namespace std\n\n#include \"hash.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/hash.inl",
    "content": "/// @ref gtx_hash\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_hash GLM_GTX_hash\n/// @ingroup gtx\n///\n/// @brief Add std::hash support for glm types\n///\n/// <glm/gtx/hash.inl> need to be included to use the features of this extension.\n\nnamespace glm {\nnamespace detail\n{\n\tGLM_INLINE void hash_combine(size_t &seed, size_t hash)\n\t{\n\t\thash += 0x9e3779b9 + (seed << 6) + (seed >> 2);\n\t\tseed ^= hash;\n\t}\n}}\n\nnamespace std\n{\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::vec<1, T, Q>>::operator()(glm::vec<1, T, Q> const& v) const\n\t{\n\t\thash<T> hasher;\n\t\treturn hasher(v.x);\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::vec<2, T, Q>>::operator()(glm::vec<2, T, Q> const& v) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<T> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(v.x));\n\t\tglm::detail::hash_combine(seed, hasher(v.y));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::vec<3, T, Q>>::operator()(glm::vec<3, T, Q> const& v) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<T> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(v.x));\n\t\tglm::detail::hash_combine(seed, hasher(v.y));\n\t\tglm::detail::hash_combine(seed, hasher(v.z));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::vec<4, T, Q>>::operator()(glm::vec<4, T, Q> const& v) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<T> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(v.x));\n\t\tglm::detail::hash_combine(seed, hasher(v.y));\n\t\tglm::detail::hash_combine(seed, hasher(v.z));\n\t\tglm::detail::hash_combine(seed, hasher(v.w));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::qua<T, Q>>::operator()(glm::qua<T,Q> const& q) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<T> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(q.x));\n\t\tglm::detail::hash_combine(seed, hasher(q.y));\n\t\tglm::detail::hash_combine(seed, hasher(q.z));\n\t\tglm::detail::hash_combine(seed, hasher(q.w));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::tdualquat<T, Q>>::operator()(glm::tdualquat<T, Q> const& q) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::qua<T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(q.real));\n\t\tglm::detail::hash_combine(seed, hasher(q.dual));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<2, 2, T, Q>>::operator()(glm::mat<2, 2, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<2, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<2, 3, T, Q>>::operator()(glm::mat<2, 3, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<3, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<2, 4, T, Q>>::operator()(glm::mat<2, 4, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<4, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<3, 2, T, Q>>::operator()(glm::mat<3, 2, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<2, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\tglm::detail::hash_combine(seed, hasher(m[2]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<3, 3, T, Q>>::operator()(glm::mat<3, 3, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<3, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\tglm::detail::hash_combine(seed, hasher(m[2]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<3, 4, T, Q>>::operator()(glm::mat<3, 4, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<4, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\tglm::detail::hash_combine(seed, hasher(m[2]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<4, 2, T,Q>>::operator()(glm::mat<4, 2, T,Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<2, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\tglm::detail::hash_combine(seed, hasher(m[2]));\n\t\tglm::detail::hash_combine(seed, hasher(m[3]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<4, 3, T,Q>>::operator()(glm::mat<4, 3, T,Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<3, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\tglm::detail::hash_combine(seed, hasher(m[2]));\n\t\tglm::detail::hash_combine(seed, hasher(m[3]));\n\t\treturn seed;\n\t}\n\n\ttemplate<typename T, glm::qualifier Q>\n\tGLM_FUNC_QUALIFIER size_t hash<glm::mat<4, 4, T,Q>>::operator()(glm::mat<4, 4, T, Q> const& m) const\n\t{\n\t\tsize_t seed = 0;\n\t\thash<glm::vec<4, T, Q>> hasher;\n\t\tglm::detail::hash_combine(seed, hasher(m[0]));\n\t\tglm::detail::hash_combine(seed, hasher(m[1]));\n\t\tglm::detail::hash_combine(seed, hasher(m[2]));\n\t\tglm::detail::hash_combine(seed, hasher(m[3]));\n\t\treturn seed;\n\t}\n}\n"
  },
  {
    "path": "lib/gli/glm/gtx/integer.hpp",
    "content": "/// @ref gtx_integer\n/// @file glm/gtx/integer.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_integer GLM_GTX_integer\n/// @ingroup gtx\n///\n/// Include <glm/gtx/integer.hpp> to use the features of this extension.\n///\n/// Add support for integer for core functions\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/integer.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_integer is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_integer extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_integer\n\t/// @{\n\n\t//! Returns x raised to the y power.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL int pow(int x, uint y);\n\n\t//! Returns the positive square root of x.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL int sqrt(int x);\n\n\t//! Returns the floor log2 of x.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL unsigned int floor_log2(unsigned int x);\n\n\t//! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL int mod(int x, int y);\n\n\t//! Return the factorial value of a number (!12 max, integer only)\n\t//! From GLM_GTX_integer extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType factorial(genType const& x);\n\n\t//! 32bit signed integer.\n\t//! From GLM_GTX_integer extension.\n\ttypedef signed int\t\t\t\t\tsint;\n\n\t//! Returns x raised to the y power.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL uint pow(uint x, uint y);\n\n\t//! Returns the positive square root of x.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL uint sqrt(uint x);\n\n\t//! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL uint mod(uint x, uint y);\n\n\t//! Returns the number of leading zeros.\n\t//! From GLM_GTX_integer extension.\n\tGLM_FUNC_DECL uint nlz(uint x);\n\n\t/// @}\n}//namespace glm\n\n#include \"integer.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/integer.inl",
    "content": "/// @ref gtx_integer\n\nnamespace glm\n{\n\t// pow\n\tGLM_FUNC_QUALIFIER int pow(int x, uint y)\n\t{\n\t\tif(y == 0)\n\t\t\treturn x >= 0 ? 1 : -1;\n\n\t\tint result = x;\n\t\tfor(uint i = 1; i < y; ++i)\n\t\t\tresult *= x;\n\t\treturn result;\n\t}\n\n\t// sqrt: From Christopher J. Musial, An integer square root, Graphics Gems, 1990, page 387\n\tGLM_FUNC_QUALIFIER int sqrt(int x)\n\t{\n\t\tif(x <= 1) return x;\n\n\t\tint NextTrial = x >> 1;\n\t\tint CurrentAnswer;\n\n\t\tdo\n\t\t{\n\t\t\tCurrentAnswer = NextTrial;\n\t\t\tNextTrial = (NextTrial + x / NextTrial) >> 1;\n\t\t} while(NextTrial < CurrentAnswer);\n\n\t\treturn CurrentAnswer;\n\t}\n\n// Henry Gordon Dietz: http://aggregate.org/MAGIC/\nnamespace detail\n{\n\tGLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x)\n\t{\n\t\t/* 32-bit recursive reduction using SWAR...\n\t\tbut first step is mapping 2-bit values\n\t\tinto sum of 2 1-bit values in sneaky way\n\t\t*/\n\t\tx -= ((x >> 1) & 0x55555555);\n\t\tx = (((x >> 2) & 0x33333333) + (x & 0x33333333));\n\t\tx = (((x >> 4) + x) & 0x0f0f0f0f);\n\t\tx += (x >> 8);\n\t\tx += (x >> 16);\n\t\treturn(x & 0x0000003f);\n\t}\n}//namespace detail\n\n\t// Henry Gordon Dietz: http://aggregate.org/MAGIC/\n/*\n\tGLM_FUNC_QUALIFIER unsigned int floor_log2(unsigned int x)\n\t{\n\t\tx |= (x >> 1);\n\t\tx |= (x >> 2);\n\t\tx |= (x >> 4);\n\t\tx |= (x >> 8);\n\t\tx |= (x >> 16);\n\n\t\treturn _detail::ones32(x) >> 1;\n\t}\n*/\n\t// mod\n\tGLM_FUNC_QUALIFIER int mod(int x, int y)\n\t{\n\t\treturn ((x % y) + y) % y;\n\t}\n\n\t// factorial (!12 max, integer only)\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType factorial(genType const& x)\n\t{\n\t\tgenType Temp = x;\n\t\tgenType Result;\n\t\tfor(Result = 1; Temp > 1; --Temp)\n\t\t\tResult *= Temp;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> factorial(\n\t\tvec<2, T, Q> const& x)\n\t{\n\t\treturn vec<2, T, Q>(\n\t\t\tfactorial(x.x),\n\t\t\tfactorial(x.y));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> factorial(\n\t\tvec<3, T, Q> const& x)\n\t{\n\t\treturn vec<3, T, Q>(\n\t\t\tfactorial(x.x),\n\t\t\tfactorial(x.y),\n\t\t\tfactorial(x.z));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> factorial(\n\t\tvec<4, T, Q> const& x)\n\t{\n\t\treturn vec<4, T, Q>(\n\t\t\tfactorial(x.x),\n\t\t\tfactorial(x.y),\n\t\t\tfactorial(x.z),\n\t\t\tfactorial(x.w));\n\t}\n\n\tGLM_FUNC_QUALIFIER uint pow(uint x, uint y)\n\t{\n\t\tif (y == 0)\n\t\t\treturn 1u;\n\n\t\tuint result = x;\n\t\tfor(uint i = 1; i < y; ++i)\n\t\t\tresult *= x;\n\t\treturn result;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint sqrt(uint x)\n\t{\n\t\tif(x <= 1) return x;\n\n\t\tuint NextTrial = x >> 1;\n\t\tuint CurrentAnswer;\n\n\t\tdo\n\t\t{\n\t\t\tCurrentAnswer = NextTrial;\n\t\t\tNextTrial = (NextTrial + x / NextTrial) >> 1;\n\t\t} while(NextTrial < CurrentAnswer);\n\n\t\treturn CurrentAnswer;\n\t}\n\n\tGLM_FUNC_QUALIFIER uint mod(uint x, uint y)\n\t{\n\t\treturn x - y * (x / y);\n\t}\n\n#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC))\n\n\tGLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x)\n\t{\n\t\treturn 31u - findMSB(x);\n\t}\n\n#else\n\n\t// Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt\n\tGLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x)\n\t{\n\t\tint y, m, n;\n\n\t\ty = -int(x >> 16);      // If left half of x is 0,\n\t\tm = (y >> 16) & 16;  // set n = 16.  If left half\n\t\tn = 16 - m;          // is nonzero, set n = 0 and\n\t\tx = x >> m;          // shift x right 16.\n\t\t\t\t\t\t\t// Now x is of the form 0000xxxx.\n\t\ty = x - 0x100;       // If positions 8-15 are 0,\n\t\tm = (y >> 16) & 8;   // add 8 to n and shift x left 8.\n\t\tn = n + m;\n\t\tx = x << m;\n\n\t\ty = x - 0x1000;      // If positions 12-15 are 0,\n\t\tm = (y >> 16) & 4;   // add 4 to n and shift x left 4.\n\t\tn = n + m;\n\t\tx = x << m;\n\n\t\ty = x - 0x4000;      // If positions 14-15 are 0,\n\t\tm = (y >> 16) & 2;   // add 2 to n and shift x left 2.\n\t\tn = n + m;\n\t\tx = x << m;\n\n\t\ty = x >> 14;         // Set y = 0, 1, 2, or 3.\n\t\tm = y & ~(y >> 1);   // Set m = 0, 1, 2, or 2 resp.\n\t\treturn unsigned(n + 2 - m);\n\t}\n\n#endif//(GLM_COMPILER)\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/intersect.hpp",
    "content": "/// @ref gtx_intersect\n/// @file glm/gtx/intersect.hpp\n///\n/// @see core (dependence)\n/// @see gtx_closest_point (dependence)\n///\n/// @defgroup gtx_intersect GLM_GTX_intersect\n/// @ingroup gtx\n///\n/// Include <glm/gtx/intersect.hpp> to use the features of this extension.\n///\n/// Add intersection functions\n\n#pragma once\n\n// Dependency:\n#include <cfloat>\n#include <limits>\n#include \"../glm.hpp\"\n#include \"../geometric.hpp\"\n#include \"../gtx/closest_point.hpp\"\n#include \"../gtx/vector_query.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_closest_point is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_closest_point extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_intersect\n\t/// @{\n\n\t//! Compute the intersection of a ray and a plane.\n\t//! Ray direction and plane normal must be unit length.\n\t//! From GLM_GTX_intersect extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool intersectRayPlane(\n\t\tgenType const& orig, genType const& dir,\n\t\tgenType const& planeOrig, genType const& planeNormal,\n\t\ttypename genType::value_type & intersectionDistance);\n\n\t//! Compute the intersection of a ray and a triangle.\n\t/// Based om Tomas Möller implementation http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/\n\t//! From GLM_GTX_intersect extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool intersectRayTriangle(\n\t\tvec<3, T, Q> const& orig, vec<3, T, Q> const& dir,\n\t\tvec<3, T, Q> const& v0, vec<3, T, Q> const& v1, vec<3, T, Q> const& v2,\n\t\tvec<2, T, Q>& baryPosition, T& distance);\n\n\t//! Compute the intersection of a line and a triangle.\n\t//! From GLM_GTX_intersect extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool intersectLineTriangle(\n\t\tgenType const& orig, genType const& dir,\n\t\tgenType const& vert0, genType const& vert1, genType const& vert2,\n\t\tgenType & position);\n\n\t//! Compute the intersection distance of a ray and a sphere.\n\t//! The ray direction vector is unit length.\n\t//! From GLM_GTX_intersect extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool intersectRaySphere(\n\t\tgenType const& rayStarting, genType const& rayNormalizedDirection,\n\t\tgenType const& sphereCenter, typename genType::value_type const sphereRadiusSquered,\n\t\ttypename genType::value_type & intersectionDistance);\n\n\t//! Compute the intersection of a ray and a sphere.\n\t//! From GLM_GTX_intersect extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool intersectRaySphere(\n\t\tgenType const& rayStarting, genType const& rayNormalizedDirection,\n\t\tgenType const& sphereCenter, const typename genType::value_type sphereRadius,\n\t\tgenType & intersectionPosition, genType & intersectionNormal);\n\n\t//! Compute the intersection of a line and a sphere.\n\t//! From GLM_GTX_intersect extension\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL bool intersectLineSphere(\n\t\tgenType const& point0, genType const& point1,\n\t\tgenType const& sphereCenter, typename genType::value_type sphereRadius,\n\t\tgenType & intersectionPosition1, genType & intersectionNormal1,\n\t\tgenType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType());\n\n\t/// @}\n}//namespace glm\n\n#include \"intersect.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/intersect.inl",
    "content": "/// @ref gtx_intersect\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER bool intersectRayPlane\n\t(\n\t\tgenType const& orig, genType const& dir,\n\t\tgenType const& planeOrig, genType const& planeNormal,\n\t\ttypename genType::value_type & intersectionDistance\n\t)\n\t{\n\t\ttypename genType::value_type d = glm::dot(dir, planeNormal);\n\t\ttypename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();\n\n\t\tif(glm::abs(d) > Epsilon)  // if dir and planeNormal are not perpendicular\n\t\t{\n\t\t\ttypename genType::value_type const tmp_intersectionDistance = \tglm::dot(planeOrig - orig, planeNormal) / d;\n\t\t\tif (tmp_intersectionDistance > static_cast<typename genType::value_type>(0)) { // allow only intersections\n\t\t\t\tintersectionDistance = tmp_intersectionDistance;\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool intersectRayTriangle\n\t(\n\t\tvec<3, T, Q> const& orig, vec<3, T, Q> const& dir,\n\t\tvec<3, T, Q> const& vert0, vec<3, T, Q> const& vert1, vec<3, T, Q> const& vert2,\n\t\tvec<2, T, Q>& baryPosition, T& distance\n\t)\n\t{\n\t\t// find vectors for two edges sharing vert0\n\t\tvec<3, T, Q> const edge1 = vert1 - vert0;\n\t\tvec<3, T, Q> const edge2 = vert2 - vert0;\n\n\t\t// begin calculating determinant - also used to calculate U parameter\n\t\tvec<3, T, Q> const p = glm::cross(dir, edge2);\n\n\t\t// if determinant is near zero, ray lies in plane of triangle\n\t\tT const det = glm::dot(edge1, p);\n\n\t\tvec<3, T, Q> Perpendicular(0);\n\n\t\tif(det > std::numeric_limits<T>::epsilon())\n\t\t{\n\t\t\t// calculate distance from vert0 to ray origin\n\t\t\tvec<3, T, Q> const dist = orig - vert0;\n\n\t\t\t// calculate U parameter and test bounds\n\t\t\tbaryPosition.x = glm::dot(dist, p);\n\t\t\tif(baryPosition.x < static_cast<T>(0) || baryPosition.x > det)\n\t\t\t\treturn false;\n\n\t\t\t// prepare to test V parameter\n\t\t\tPerpendicular = glm::cross(dist, edge1);\n\n\t\t\t// calculate V parameter and test bounds\n\t\t\tbaryPosition.y = glm::dot(dir, Perpendicular);\n\t\t\tif((baryPosition.y < static_cast<T>(0)) || ((baryPosition.x + baryPosition.y) > det))\n\t\t\t\treturn false;\n\t\t}\n\t\telse if(det < -std::numeric_limits<T>::epsilon())\n\t\t{\n\t\t\t// calculate distance from vert0 to ray origin\n\t\t\tvec<3, T, Q> const dist = orig - vert0;\n\n\t\t\t// calculate U parameter and test bounds\n\t\t\tbaryPosition.x = glm::dot(dist, p);\n\t\t\tif((baryPosition.x > static_cast<T>(0)) || (baryPosition.x < det))\n\t\t\t\treturn false;\n\n\t\t\t// prepare to test V parameter\n\t\t\tPerpendicular = glm::cross(dist, edge1);\n\n\t\t\t// calculate V parameter and test bounds\n\t\t\tbaryPosition.y = glm::dot(dir, Perpendicular);\n\t\t\tif((baryPosition.y > static_cast<T>(0)) || (baryPosition.x + baryPosition.y < det))\n\t\t\t\treturn false;\n\t\t}\n\t\telse\n\t\t\treturn false; // ray is parallel to the plane of the triangle\n\n\t\tT inv_det = static_cast<T>(1) / det;\n\n\t\t// calculate distance, ray intersects triangle\n\t\tdistance = glm::dot(edge2, Perpendicular) * inv_det;\n\t\tbaryPosition *= inv_det;\n\n\t\treturn true;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER bool intersectLineTriangle\n\t(\n\t\tgenType const& orig, genType const& dir,\n\t\tgenType const& vert0, genType const& vert1, genType const& vert2,\n\t\tgenType & position\n\t)\n\t{\n\t\ttypename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();\n\n\t\tgenType edge1 = vert1 - vert0;\n\t\tgenType edge2 = vert2 - vert0;\n\n\t\tgenType Perpendicular = cross(dir, edge2);\n\n\t\tfloat det = dot(edge1, Perpendicular);\n\n\t\tif (det > -Epsilon && det < Epsilon)\n\t\t\treturn false;\n\t\ttypename genType::value_type inv_det = typename genType::value_type(1) / det;\n\n\t\tgenType Tengant = orig - vert0;\n\n\t\tposition.y = dot(Tengant, Perpendicular) * inv_det;\n\t\tif (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1))\n\t\t\treturn false;\n\n\t\tgenType Cotengant = cross(Tengant, edge1);\n\n\t\tposition.z = dot(dir, Cotengant) * inv_det;\n\t\tif (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1))\n\t\t\treturn false;\n\n\t\tposition.x = dot(edge2, Cotengant) * inv_det;\n\n\t\treturn true;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER bool intersectRaySphere\n\t(\n\t\tgenType const& rayStarting, genType const& rayNormalizedDirection,\n\t\tgenType const& sphereCenter, const typename genType::value_type sphereRadiusSquered,\n\t\ttypename genType::value_type & intersectionDistance\n\t)\n\t{\n\t\ttypename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();\n\t\tgenType diff = sphereCenter - rayStarting;\n\t\ttypename genType::value_type t0 = dot(diff, rayNormalizedDirection);\n\t\ttypename genType::value_type dSquared = dot(diff, diff) - t0 * t0;\n\t\tif( dSquared > sphereRadiusSquered )\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\ttypename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared );\n\t\tintersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1;\n\t\treturn intersectionDistance > Epsilon;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER bool intersectRaySphere\n\t(\n\t\tgenType const& rayStarting, genType const& rayNormalizedDirection,\n\t\tgenType const& sphereCenter, const typename genType::value_type sphereRadius,\n\t\tgenType & intersectionPosition, genType & intersectionNormal\n\t)\n\t{\n\t\ttypename genType::value_type distance;\n\t\tif( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) )\n\t\t{\n\t\t\tintersectionPosition = rayStarting + rayNormalizedDirection * distance;\n\t\t\tintersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius;\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER bool intersectLineSphere\n\t(\n\t\tgenType const& point0, genType const& point1,\n\t\tgenType const& sphereCenter, typename genType::value_type sphereRadius,\n\t\tgenType & intersectionPoint1, genType & intersectionNormal1,\n\t\tgenType & intersectionPoint2, genType & intersectionNormal2\n\t)\n\t{\n\t\ttypename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();\n\t\tgenType dir = normalize(point1 - point0);\n\t\tgenType diff = sphereCenter - point0;\n\t\ttypename genType::value_type t0 = dot(diff, dir);\n\t\ttypename genType::value_type dSquared = dot(diff, diff) - t0 * t0;\n\t\tif( dSquared > sphereRadius * sphereRadius )\n\t\t{\n\t\t\treturn false;\n\t\t}\n\t\ttypename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared );\n\t\tif( t0 < t1 + Epsilon )\n\t\t\tt1 = -t1;\n\t\tintersectionPoint1 = point0 + dir * (t0 - t1);\n\t\tintersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius;\n\t\tintersectionPoint2 = point0 + dir * (t0 + t1);\n\t\tintersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius;\n\t\treturn true;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/io.hpp",
    "content": "/// @ref gtx_io\n/// @file glm/gtx/io.hpp\n/// @author Jan P Springer (regnirpsj@gmail.com)\n///\n/// @see core (dependence)\n/// @see gtc_matrix_access (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtx_io GLM_GTX_io\n/// @ingroup gtx\n///\n/// Include <glm/gtx/io.hpp> to use the features of this extension.\n///\n/// std::[w]ostream support for glm types\n///\n/// std::[w]ostream support for glm types + qualifier/width/etc. manipulators\n/// based on howard hinnant's std::chrono io proposal\n/// [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html]\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtx/quaternion.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_io is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_io extension included\")\n#\tendif\n#endif\n\n#include <iosfwd>  // std::basic_ostream<> (fwd)\n#include <locale>  // std::locale, std::locale::facet, std::locale::id\n#include <utility> // std::pair<>\n\nnamespace glm\n{\n\t/// @addtogroup gtx_io\n\t/// @{\n\n\tnamespace io\n\t{\n\t\tenum order_type { column_major, row_major};\n\n\t\ttemplate<typename CTy>\n\t\tclass format_punct : public std::locale::facet\n\t\t{\n\t\t\ttypedef CTy char_type;\n\n\t\tpublic:\n\n\t\t\tstatic std::locale::id id;\n\n\t\t\tbool       formatted;\n\t\t\tunsigned   precision;\n\t\t\tunsigned   width;\n\t\t\tchar_type  separator;\n\t\t\tchar_type  delim_left;\n\t\t\tchar_type  delim_right;\n\t\t\tchar_type  space;\n\t\t\tchar_type  newline;\n\t\t\torder_type order;\n\n\t\t\tGLM_FUNC_DECL explicit format_punct(size_t a = 0);\n\t\t\tGLM_FUNC_DECL explicit format_punct(format_punct const&);\n\t\t};\n\n\t\ttemplate<typename CTy, typename CTr = std::char_traits<CTy> >\n\t\tclass basic_state_saver {\n\n\t\tpublic:\n\n\t\t\tGLM_FUNC_DECL explicit basic_state_saver(std::basic_ios<CTy,CTr>&);\n\t\t\tGLM_FUNC_DECL ~basic_state_saver();\n\n\t\tprivate:\n\n\t\t\ttypedef ::std::basic_ios<CTy,CTr>      state_type;\n\t\t\ttypedef typename state_type::char_type char_type;\n\t\t\ttypedef ::std::ios_base::fmtflags      flags_type;\n\t\t\ttypedef ::std::streamsize              streamsize_type;\n\t\t\ttypedef ::std::locale const            locale_type;\n\n\t\t\tstate_type&     state_;\n\t\t\tflags_type      flags_;\n\t\t\tstreamsize_type precision_;\n\t\t\tstreamsize_type width_;\n\t\t\tchar_type       fill_;\n\t\t\tlocale_type     locale_;\n\n\t\t\tGLM_FUNC_DECL basic_state_saver& operator=(basic_state_saver const&);\n\t\t};\n\n\t\ttypedef basic_state_saver<char>     state_saver;\n\t\ttypedef basic_state_saver<wchar_t> wstate_saver;\n\n\t\ttemplate<typename CTy, typename CTr = std::char_traits<CTy> >\n\t\tclass basic_format_saver\n\t\t{\n\t\tpublic:\n\n\t\t\tGLM_FUNC_DECL explicit basic_format_saver(std::basic_ios<CTy,CTr>&);\n\t\t\tGLM_FUNC_DECL ~basic_format_saver();\n\n\t\tprivate:\n\n\t\t\tbasic_state_saver<CTy> const bss_;\n\n\t\t\tGLM_FUNC_DECL basic_format_saver& operator=(basic_format_saver const&);\n\t\t};\n\n\t\ttypedef basic_format_saver<char>     format_saver;\n\t\ttypedef basic_format_saver<wchar_t> wformat_saver;\n\n\t\tstruct precision\n\t\t{\n\t\t\tunsigned value;\n\n\t\t\tGLM_FUNC_DECL explicit precision(unsigned);\n\t\t};\n\n\t\tstruct width\n\t\t{\n\t\t\tunsigned value;\n\n\t\t\tGLM_FUNC_DECL explicit width(unsigned);\n\t\t};\n\n\t\ttemplate<typename CTy>\n\t\tstruct delimeter\n\t\t{\n\t\t\tCTy value[3];\n\n\t\t\tGLM_FUNC_DECL explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ',');\n\t\t};\n\n\t\tstruct order\n\t\t{\n\t\t\torder_type value;\n\n\t\t\tGLM_FUNC_DECL explicit order(order_type);\n\t\t};\n\n\t\t// functions, inlined (inline)\n\n\t\ttemplate<typename FTy, typename CTy, typename CTr>\n\t\tFTy const& get_facet(std::basic_ios<CTy,CTr>&);\n\t\ttemplate<typename FTy, typename CTy, typename CTr>\n\t\tstd::basic_ios<CTy,CTr>& formatted(std::basic_ios<CTy,CTr>&);\n\t\ttemplate<typename FTy, typename CTy, typename CTr>\n\t\tstd::basic_ios<CTy,CTr>& unformattet(std::basic_ios<CTy,CTr>&);\n\n\t\ttemplate<typename CTy, typename CTr>\n\t\tstd::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, precision const&);\n\t\ttemplate<typename CTy, typename CTr>\n\t\tstd::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, width const&);\n\t\ttemplate<typename CTy, typename CTr>\n\t\tstd::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, delimeter<CTy> const&);\n\t\ttemplate<typename CTy, typename CTr>\n\t\tstd::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, order const&);\n\t}//namespace io\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, qua<T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, vec<1, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, vec<2, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, vec<3, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, vec<4, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<2, 2, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<2, 3, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<2, 4, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<3, 2, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<3, 3, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<3, 4, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<4, 2, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<4, 3, T, Q> const&);\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, mat<4, 4, T, Q> const&);\n\n  template<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_DECL std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr> &,\n                                                         std::pair<mat<4, 4, T, Q> const, mat<4, 4, T, Q> const> const&);\n\n\t/// @}\n}//namespace glm\n\n#include \"io.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/io.inl",
    "content": "/// @ref gtx_io\n/// @author Jan P Springer (regnirpsj@gmail.com)\n\n#include <iomanip>                  // std::fixed, std::setfill<>, std::setprecision, std::right, std::setw\n#include <ostream>                  // std::basic_ostream<>\n#include \"../gtc/matrix_access.hpp\" // glm::col, glm::row\n#include \"../gtx/type_trait.hpp\"    // glm::type<>\n\nnamespace glm{\nnamespace io\n{\n\ttemplate<typename CTy>\n\tGLM_FUNC_QUALIFIER format_punct<CTy>::format_punct(size_t a)\n\t\t: std::locale::facet(a)\n\t\t, formatted(true)\n\t\t, precision(3)\n\t\t, width(1 + 4 + 1 + precision)\n\t\t, separator(',')\n\t\t, delim_left('[')\n\t\t, delim_right(']')\n\t\t, space(' ')\n\t\t, newline('\\n')\n\t\t, order(column_major)\n\t{}\n\n\ttemplate<typename CTy>\n\tGLM_FUNC_QUALIFIER format_punct<CTy>::format_punct(format_punct const& a)\n\t\t: std::locale::facet(0)\n\t\t, formatted(a.formatted)\n\t\t, precision(a.precision)\n\t\t, width(a.width)\n\t\t, separator(a.separator)\n\t\t, delim_left(a.delim_left)\n\t\t, delim_right(a.delim_right)\n\t\t, space(a.space)\n\t\t, newline(a.newline)\n\t\t, order(a.order)\n\t{}\n\n\ttemplate<typename CTy> std::locale::id format_punct<CTy>::id;\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER basic_state_saver<CTy, CTr>::basic_state_saver(std::basic_ios<CTy, CTr>& a)\n\t\t: state_(a)\n\t\t, flags_(a.flags())\n\t\t, precision_(a.precision())\n\t\t, width_(a.width())\n\t\t, fill_(a.fill())\n\t\t, locale_(a.getloc())\n\t{}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER basic_state_saver<CTy, CTr>::~basic_state_saver()\n\t{\n\t\tstate_.imbue(locale_);\n\t\tstate_.fill(fill_);\n\t\tstate_.width(width_);\n\t\tstate_.precision(precision_);\n\t\tstate_.flags(flags_);\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER basic_format_saver<CTy, CTr>::basic_format_saver(std::basic_ios<CTy, CTr>& a)\n\t\t: bss_(a)\n\t{\n\t\ta.imbue(std::locale(a.getloc(), new format_punct<CTy>(get_facet<format_punct<CTy> >(a))));\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER\n\tbasic_format_saver<CTy, CTr>::~basic_format_saver()\n\t{}\n\n\tGLM_FUNC_QUALIFIER precision::precision(unsigned a)\n\t\t: value(a)\n\t{}\n\n\tGLM_FUNC_QUALIFIER width::width(unsigned a)\n\t\t: value(a)\n\t{}\n\n\ttemplate<typename CTy>\n\tGLM_FUNC_QUALIFIER delimeter<CTy>::delimeter(CTy a, CTy b, CTy c)\n\t\t: value()\n\t{\n\t\tvalue[0] = a;\n\t\tvalue[1] = b;\n\t\tvalue[2] = c;\n\t}\n\n\tGLM_FUNC_QUALIFIER order::order(order_type a)\n\t\t: value(a)\n\t{}\n\n\ttemplate<typename FTy, typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios<CTy, CTr>& ios)\n\t{\n\t\tif(!std::has_facet<FTy>(ios.getloc()))\n\t\t\tios.imbue(std::locale(ios.getloc(), new FTy));\n\n\t\treturn std::use_facet<FTy>(ios.getloc());\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER std::basic_ios<CTy, CTr>& formatted(std::basic_ios<CTy, CTr>& ios)\n\t{\n\t\tconst_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(ios)).formatted = true;\n\t\treturn ios;\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER std::basic_ios<CTy, CTr>& unformatted(std::basic_ios<CTy, CTr>& ios)\n\t{\n\t\tconst_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(ios)).formatted = false;\n\t\treturn ios;\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, precision const& a)\n\t{\n\t\tconst_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)).precision = a.value;\n\t\treturn os;\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, width const& a)\n\t{\n\t\tconst_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)).width = a.value;\n\t\treturn os;\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER  std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, delimeter<CTy> const& a)\n\t{\n\t\tformat_punct<CTy> & fmt(const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)));\n\n\t\tfmt.delim_left  = a.value[0];\n\t\tfmt.delim_right = a.value[1];\n\t\tfmt.separator   = a.value[2];\n\n\t\treturn os;\n\t}\n\n\ttemplate<typename CTy, typename CTr>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, order const& a)\n\t{\n\t\tconst_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)).order = a.value;\n\t\treturn os;\n\t}\n} // namespace io\n\nnamespace detail\n{\n\ttemplate<typename CTy, typename CTr, typename V>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&\n\tprint_vector_on(std::basic_ostream<CTy, CTr>& os, V const& a)\n\t{\n\t\ttypename std::basic_ostream<CTy, CTr>::sentry const cerberus(os);\n\n\t\tif(cerberus)\n\t\t{\n\t\t\tio::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy> >(os));\n\n\t\t\tlength_t const& components(type<V>::components);\n\n\t\t\tif(fmt.formatted)\n\t\t\t{\n\t\t\t\tio::basic_state_saver<CTy> const bss(os);\n\n\t\t\t\tos << std::fixed << std::right << std::setprecision(fmt.precision) << std::setfill(fmt.space) << fmt.delim_left;\n\n\t\t\t\tfor(length_t i(0); i < components; ++i)\n\t\t\t\t{\n\t\t\t\t\tos << std::setw(fmt.width) << a[i];\n\t\t\t\t\tif(components-1 != i)\n\t\t\t\t\t\tos << fmt.separator;\n\t\t\t\t}\n\n\t\t\t\tos << fmt.delim_right;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tfor(length_t i(0); i < components; ++i)\n\t\t\t\t{\n\t\t\t\t\tos << a[i];\n\n\t\t\t\t\tif(components-1 != i)\n\t\t\t\t\t\tos << fmt.space;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn os;\n\t}\n}//namespace detail\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, qua<T, Q> const& a)\n\t{\n\t\treturn detail::print_vector_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, vec<1, T, Q> const& a)\n\t{\n\t\treturn detail::print_vector_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, vec<2, T, Q> const& a)\n\t{\n\t\treturn detail::print_vector_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, vec<3, T, Q> const& a)\n\t{\n\t\treturn detail::print_vector_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, vec<4, T, Q> const& a)\n\t{\n\t\treturn detail::print_vector_on(os, a);\n\t}\n\nnamespace detail\n{\n\ttemplate<typename CTy, typename CTr, template<length_t, length_t, typename, qualifier> class M, length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& print_matrix_on(std::basic_ostream<CTy, CTr>& os, M<C, R, T, Q> const& a)\n\t{\n\t\ttypename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);\n\n\t\tif(cerberus)\n\t\t{\n\t\t\tio::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy> >(os));\n\n\t\t\tlength_t const& cols(type<M<C, R, T, Q> >::cols);\n\t\t\tlength_t const& rows(type<M<C, R, T, Q> >::rows);\n\n\t\t\tif(fmt.formatted)\n\t\t\t{\n\t\t\t\tos << fmt.newline << fmt.delim_left;\n\n\t\t\t\tswitch(fmt.order)\n\t\t\t\t{\n\t\t\t\t\tcase io::column_major:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(length_t i(0); i < rows; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif (0 != i)\n\t\t\t\t\t\t\t\tos << fmt.space;\n\n\t\t\t\t\t\t\tos << row(a, i);\n\n\t\t\t\t\t\t\tif(rows-1 != i)\n\t\t\t\t\t\t\t\tos << fmt.newline;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase io::row_major:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(length_t i(0); i < cols; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(0 != i)\n\t\t\t\t\t\t\t\tos << fmt.space;\n\n\t\t\t\t\t\t\tos << column(a, i);\n\n\t\t\t\t\t\t\tif(cols-1 != i)\n\t\t\t\t\t\t\t\tos << fmt.newline;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tos << fmt.delim_right;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tswitch (fmt.order)\n\t\t\t\t{\n\t\t\t\t\tcase io::column_major:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(length_t i(0); i < cols; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tos << column(a, i);\n\n\t\t\t\t\t\t\tif(cols - 1 != i)\n\t\t\t\t\t\t\t\tos << fmt.space;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase io::row_major:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor (length_t i(0); i < rows; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tos << row(a, i);\n\n\t\t\t\t\t\t\tif (rows-1 != i)\n\t\t\t\t\t\t\t\tos << fmt.space;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn os;\n\t}\n}//namespace detail\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, mat<2, 2, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, mat<2, 3, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, mat<2, 4, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, mat<3, 2, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, mat<3, 3, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, mat<3, 4, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, mat<4, 2, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, mat<4, 3, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, mat<4, 4, T, Q> const& a)\n\t{\n\t\treturn detail::print_matrix_on(os, a);\n\t}\n\nnamespace detail\n{\n\ttemplate<typename CTy, typename CTr, template<length_t, length_t, typename, qualifier> class M, length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& print_matrix_pair_on(std::basic_ostream<CTy, CTr>& os, std::pair<M<C, R, T, Q> const, M<C, R, T, Q> const> const& a)\n\t{\n\t\ttypename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);\n\n\t\tif(cerberus)\n\t\t{\n\t\t\tio::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy> >(os));\n\t\t\tM<C, R, T, Q> const& ml(a.first);\n\t\t\tM<C, R, T, Q> const& mr(a.second);\n\t\t\tlength_t const& cols(type<M<C, R, T, Q> >::cols);\n\t\t\tlength_t const& rows(type<M<C, R, T, Q> >::rows);\n\n\t\t\tif(fmt.formatted)\n\t\t\t{\n\t\t\t\tos << fmt.newline << fmt.delim_left;\n\n\t\t\t\tswitch(fmt.order)\n\t\t\t\t{\n\t\t\t\t\tcase io::column_major:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(length_t i(0); i < rows; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(0 != i)\n\t\t\t\t\t\t\t\tos << fmt.space;\n\n\t\t\t\t\t\t\tos << row(ml, i) << ((rows-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << row(mr, i);\n\n\t\t\t\t\t\t\tif(rows-1 != i)\n\t\t\t\t\t\t\t\tos << fmt.newline;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t\tcase io::row_major:\n\t\t\t\t\t{\n\t\t\t\t\t\tfor(length_t i(0); i < cols; ++i)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tif(0 != i)\n\t\t\t\t\t\t\t\tos << fmt.space;\n\n\t\t\t\t\t\t\tos << column(ml, i) << ((cols-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << column(mr, i);\n\n\t\t\t\t\t\t\tif(cols-1 != i)\n\t\t\t\t\t\t\t\tos << fmt.newline;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\tos << fmt.delim_right;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tos << ml << fmt.space << mr;\n\t\t\t}\n\t\t}\n\n\t\treturn os;\n\t}\n}//namespace detail\n\n\ttemplate<typename CTy, typename CTr, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(\n\t\tstd::basic_ostream<CTy, CTr> & os,\n\t\tstd::pair<mat<4, 4, T, Q> const,\n\t\tmat<4, 4, T, Q> const> const& a)\n\t{\n\t\treturn detail::print_matrix_pair_on(os, a);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/log_base.hpp",
    "content": "/// @ref gtx_log_base\n/// @file glm/gtx/log_base.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_log_base GLM_GTX_log_base\n/// @ingroup gtx\n///\n/// Include <glm/gtx/log_base.hpp> to use the features of this extension.\n///\n/// Logarithm for any base. base can be a vector or a scalar.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_log_base is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_log_base extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_log_base\n\t/// @{\n\n\t/// Logarithm for any base.\n\t/// From GLM_GTX_log_base.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType log(\n\t\tgenType const& x,\n\t\tgenType const& base);\n\n\t/// Logarithm for any base.\n\t/// From GLM_GTX_log_base.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> sign(\n\t\tvec<L, T, Q> const& x,\n\t\tvec<L, T, Q> const& base);\n\n\t/// @}\n}//namespace glm\n\n#include \"log_base.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/log_base.inl",
    "content": "/// @ref gtx_log_base\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType log(genType const& x, genType const& base)\n\t{\n\t\treturn glm::log(x) / glm::log(base);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, T, Q> log(vec<L, T, Q> const& x, vec<L, T, Q> const& base)\n\t{\n\t\treturn glm::log(x) / glm::log(base);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_cross_product.hpp",
    "content": "/// @ref gtx_matrix_cross_product\n/// @file glm/gtx/matrix_cross_product.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_matrix_cross_product GLM_GTX_matrix_cross_product\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_cross_product.hpp> to use the features of this extension.\n///\n/// Build cross product matrices\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_cross_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_cross_product extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_cross_product\n\t/// @{\n\n\t//! Build a cross product matrix.\n\t//! From GLM_GTX_matrix_cross_product extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> matrixCross3(\n\t\tvec<3, T, Q> const& x);\n\n\t//! Build a cross product matrix.\n\t//! From GLM_GTX_matrix_cross_product extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> matrixCross4(\n\t\tvec<3, T, Q> const& x);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_cross_product.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_cross_product.inl",
    "content": "/// @ref gtx_matrix_cross_product\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> matrixCross3\n\t(\n\t\tvec<3, T, Q> const& x\n\t)\n\t{\n\t\tmat<3, 3, T, Q> Result(T(0));\n\t\tResult[0][1] = x.z;\n\t\tResult[1][0] = -x.z;\n\t\tResult[0][2] = -x.y;\n\t\tResult[2][0] = x.y;\n\t\tResult[1][2] = x.x;\n\t\tResult[2][1] = -x.x;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> matrixCross4\n\t(\n\t\tvec<3, T, Q> const& x\n\t)\n\t{\n\t\tmat<4, 4, T, Q> Result(T(0));\n\t\tResult[0][1] = x.z;\n\t\tResult[1][0] = -x.z;\n\t\tResult[0][2] = -x.y;\n\t\tResult[2][0] = x.y;\n\t\tResult[1][2] = x.x;\n\t\tResult[2][1] = -x.x;\n\t\treturn Result;\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_decompose.hpp",
    "content": "/// @ref gtx_matrix_decompose\n/// @file glm/gtx/matrix_decompose.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_matrix_decompose GLM_GTX_matrix_decompose\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_decompose.hpp> to use the features of this extension.\n///\n/// Decomposes a model matrix to translations, rotation and scale components\n\n#pragma once\n\n// Dependencies\n#include \"../mat4x4.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../geometric.hpp\"\n#include \"../gtc/quaternion.hpp\"\n#include \"../gtc/matrix_transform.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_decompose is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_decompose extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_decompose\n\t/// @{\n\n\t/// Decomposes a model matrix to translations, rotation and scale components\n\t/// @see gtx_matrix_decompose\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool decompose(\n\t\tmat<4, 4, T, Q> const& modelMatrix,\n\t\tvec<3, T, Q> & scale, qua<T, Q> & orientation, vec<3, T, Q> & translation, vec<3, T, Q> & skew, vec<4, T, Q> & perspective);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_decompose.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_decompose.inl",
    "content": "/// @ref gtx_matrix_decompose\n\n#include \"../gtc/constants.hpp\"\n#include \"../gtc/epsilon.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\t/// Make a linear combination of two vectors and return the result.\n\t// result = (a * ascl) + (b * bscl)\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> combine(\n\t\tvec<3, T, Q> const& a,\n\t\tvec<3, T, Q> const& b,\n\t\tT ascl, T bscl)\n\t{\n\t\treturn (a * ascl) + (b * bscl);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> scale(vec<3, T, Q> const& v, T desiredLength)\n\t{\n\t\treturn v * desiredLength / length(v);\n\t}\n}//namespace detail\n\n\t// Matrix decompose\n\t// http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp\n\t// Decomposes the mode matrix to translations,rotation scale components\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool decompose(mat<4, 4, T, Q> const& ModelMatrix, vec<3, T, Q> & Scale, qua<T, Q> & Orientation, vec<3, T, Q> & Translation, vec<3, T, Q> & Skew, vec<4, T, Q> & Perspective)\n\t{\n\t\tmat<4, 4, T, Q> LocalMatrix(ModelMatrix);\n\n\t\t// Normalize the matrix.\n\t\tif(epsilonEqual(LocalMatrix[3][3], static_cast<T>(0), epsilon<T>()))\n\t\t\treturn false;\n\n\t\tfor(length_t i = 0; i < 4; ++i)\n\t\tfor(length_t j = 0; j < 4; ++j)\n\t\t\tLocalMatrix[i][j] /= LocalMatrix[3][3];\n\n\t\t// perspectiveMatrix is used to solve for perspective, but it also provides\n\t\t// an easy way to test for singularity of the upper 3x3 component.\n\t\tmat<4, 4, T, Q> PerspectiveMatrix(LocalMatrix);\n\n\t\tfor(length_t i = 0; i < 3; i++)\n\t\t\tPerspectiveMatrix[i][3] = static_cast<T>(0);\n\t\tPerspectiveMatrix[3][3] = static_cast<T>(1);\n\n\t\t/// TODO: Fixme!\n\t\tif(epsilonEqual(determinant(PerspectiveMatrix), static_cast<T>(0), epsilon<T>()))\n\t\t\treturn false;\n\n\t\t// First, isolate perspective.  This is the messiest.\n\t\tif(\n\t\t\tepsilonNotEqual(LocalMatrix[0][3], static_cast<T>(0), epsilon<T>()) ||\n\t\t\tepsilonNotEqual(LocalMatrix[1][3], static_cast<T>(0), epsilon<T>()) ||\n\t\t\tepsilonNotEqual(LocalMatrix[2][3], static_cast<T>(0), epsilon<T>()))\n\t\t{\n\t\t\t// rightHandSide is the right hand side of the equation.\n\t\t\tvec<4, T, Q> RightHandSide;\n\t\t\tRightHandSide[0] = LocalMatrix[0][3];\n\t\t\tRightHandSide[1] = LocalMatrix[1][3];\n\t\t\tRightHandSide[2] = LocalMatrix[2][3];\n\t\t\tRightHandSide[3] = LocalMatrix[3][3];\n\n\t\t\t// Solve the equation by inverting PerspectiveMatrix and multiplying\n\t\t\t// rightHandSide by the inverse.  (This is the easiest way, not\n\t\t\t// necessarily the best.)\n\t\t\tmat<4, 4, T, Q> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);//   inverse(PerspectiveMatrix, inversePerspectiveMatrix);\n\t\t\tmat<4, 4, T, Q> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);//   transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);\n\n\t\t\tPerspective = TransposedInversePerspectiveMatrix * RightHandSide;\n\t\t\t//  v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);\n\n\t\t\t// Clear the perspective partition\n\t\t\tLocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast<T>(0);\n\t\t\tLocalMatrix[3][3] = static_cast<T>(1);\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// No perspective.\n\t\t\tPerspective = vec<4, T, Q>(0, 0, 0, 1);\n\t\t}\n\n\t\t// Next take care of translation (easy).\n\t\tTranslation = vec<3, T, Q>(LocalMatrix[3]);\n\t\tLocalMatrix[3] = vec<4, T, Q>(0, 0, 0, LocalMatrix[3].w);\n\n\t\tvec<3, T, Q> Row[3], Pdum3;\n\n\t\t// Now get scale and shear.\n\t\tfor(length_t i = 0; i < 3; ++i)\n\t\tfor(length_t j = 0; j < 3; ++j)\n\t\t\tRow[i][j] = LocalMatrix[i][j];\n\n\t\t// Compute X scale factor and normalize first row.\n\t\tScale.x = length(Row[0]);// v3Length(Row[0]);\n\n\t\tRow[0] = detail::scale(Row[0], static_cast<T>(1));\n\n\t\t// Compute XY shear factor and make 2nd row orthogonal to 1st.\n\t\tSkew.z = dot(Row[0], Row[1]);\n\t\tRow[1] = detail::combine(Row[1], Row[0], static_cast<T>(1), -Skew.z);\n\n\t\t// Now, compute Y scale and normalize 2nd row.\n\t\tScale.y = length(Row[1]);\n\t\tRow[1] = detail::scale(Row[1], static_cast<T>(1));\n\t\tSkew.z /= Scale.y;\n\n\t\t// Compute XZ and YZ shears, orthogonalize 3rd row.\n\t\tSkew.y = glm::dot(Row[0], Row[2]);\n\t\tRow[2] = detail::combine(Row[2], Row[0], static_cast<T>(1), -Skew.y);\n\t\tSkew.x = glm::dot(Row[1], Row[2]);\n\t\tRow[2] = detail::combine(Row[2], Row[1], static_cast<T>(1), -Skew.x);\n\n\t\t// Next, get Z scale and normalize 3rd row.\n\t\tScale.z = length(Row[2]);\n\t\tRow[2] = detail::scale(Row[2], static_cast<T>(1));\n\t\tSkew.y /= Scale.z;\n\t\tSkew.x /= Scale.z;\n\n\t\t// At this point, the matrix (in rows[]) is orthonormal.\n\t\t// Check for a coordinate system flip.  If the determinant\n\t\t// is -1, then negate the matrix and the scaling factors.\n\t\tPdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3);\n\t\tif(dot(Row[0], Pdum3) < 0)\n\t\t{\n\t\t\tfor(length_t i = 0; i < 3; i++)\n\t\t\t{\n\t\t\t\tScale[i] *= static_cast<T>(-1);\n\t\t\t\tRow[i] *= static_cast<T>(-1);\n\t\t\t}\n\t\t}\n\n\t\t// Now, get the rotations out, as described in the gem.\n\n\t\t// FIXME - Add the ability to return either quaternions (which are\n\t\t// easier to recompose with) or Euler angles (rx, ry, rz), which\n\t\t// are easier for authors to deal with. The latter will only be useful\n\t\t// when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I\n\t\t// will leave the Euler angle code here for now.\n\n\t\t// ret.rotateY = asin(-Row[0][2]);\n\t\t// if (cos(ret.rotateY) != 0) {\n\t\t//     ret.rotateX = atan2(Row[1][2], Row[2][2]);\n\t\t//     ret.rotateZ = atan2(Row[0][1], Row[0][0]);\n\t\t// } else {\n\t\t//     ret.rotateX = atan2(-Row[2][0], Row[1][1]);\n\t\t//     ret.rotateZ = 0;\n\t\t// }\n\n\t\tint i, j, k = 0;\n\t\tT root, trace = Row[0].x + Row[1].y + Row[2].z;\n\t\tif(trace > static_cast<T>(0))\n\t\t{\n\t\t\troot = sqrt(trace + static_cast<T>(1.0));\n\t\t\tOrientation.w = static_cast<T>(0.5) * root;\n\t\t\troot = static_cast<T>(0.5) / root;\n\t\t\tOrientation.x = root * (Row[1].z - Row[2].y);\n\t\t\tOrientation.y = root * (Row[2].x - Row[0].z);\n\t\t\tOrientation.z = root * (Row[0].y - Row[1].x);\n\t\t} // End if > 0\n\t\telse\n\t\t{\n\t\t\tstatic int Next[3] = {1, 2, 0};\n\t\t\ti = 0;\n\t\t\tif(Row[1].y > Row[0].x) i = 1;\n\t\t\tif(Row[2].z > Row[i][i]) i = 2;\n\t\t\tj = Next[i];\n\t\t\tk = Next[j];\n\n\t\t\troot = sqrt(Row[i][i] - Row[j][j] - Row[k][k] + static_cast<T>(1.0));\n\n\t\t\tOrientation[i] = static_cast<T>(0.5) * root;\n\t\t\troot = static_cast<T>(0.5) / root;\n\t\t\tOrientation[j] = root * (Row[i][j] + Row[j][i]);\n\t\t\tOrientation[k] = root * (Row[i][k] + Row[k][i]);\n\t\t\tOrientation.w = root * (Row[j][k] - Row[k][j]);\n\t\t} // End if <= 0\n\n\t\treturn true;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_factorisation.hpp",
    "content": "/// @ref gtx_matrix_factorisation\n/// @file glm/gtx/matrix_factorisation.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_matrix_factorisation GLM_GTX_matrix_factorisation\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_factorisation.hpp> to use the features of this extension.\n///\n/// Functions to factor matrices in various forms\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_factorisation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_factorisation extension included\")\n#\tendif\n#endif\n\n/*\nSuggestions:\n - Move helper functions flipud and fliplr to another file: They may be helpful in more general circumstances.\n - Implement other types of matrix factorisation, such as: QL and LQ, L(D)U, eigendecompositions, etc...\n*/\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_factorisation\n\t/// @{\n\n\t/// Flips the matrix rows up and down.\n\t///\n\t/// From GLM_GTX_matrix_factorisation extension.\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<C, R, T, Q> flipud(mat<C, R, T, Q> const& in);\n\n\t/// Flips the matrix columns right and left.\n\t///\n\t/// From GLM_GTX_matrix_factorisation extension.\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<C, R, T, Q> fliplr(mat<C, R, T, Q> const& in);\n\n\t/// Performs QR factorisation of a matrix.\n\t/// Returns 2 matrices, q and r, such that the columns of q are orthonormal and span the same subspace than those of the input matrix, r is an upper triangular matrix, and q*r=in.\n\t/// Given an n-by-m input matrix, q has dimensions min(n,m)-by-m, and r has dimensions n-by-min(n,m).\n\t///\n\t/// From GLM_GTX_matrix_factorisation extension.\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL void qr_decompose(mat<C, R, T, Q> const& in, mat<(C < R ? C : R), R, T, Q>& q, mat<C, (C < R ? C : R), T, Q>& r);\n\n\t/// Performs RQ factorisation of a matrix.\n\t/// Returns 2 matrices, r and q, such that r is an upper triangular matrix, the rows of q are orthonormal and span the same subspace than those of the input matrix, and r*q=in.\n\t/// Note that in the context of RQ factorisation, the diagonal is seen as starting in the lower-right corner of the matrix, instead of the usual upper-left.\n\t/// Given an n-by-m input matrix, r has dimensions min(n,m)-by-m, and q has dimensions n-by-min(n,m).\n\t///\n\t/// From GLM_GTX_matrix_factorisation extension.\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL void rq_decompose(mat<C, R, T, Q> const& in, mat<(C < R ? C : R), R, T, Q>& r, mat<C, (C < R ? C : R), T, Q>& q);\n\n\t/// @}\n}\n\n#include \"matrix_factorisation.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_factorisation.inl",
    "content": "/// @ref gtx_matrix_factorisation\n\nnamespace glm\n{\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<C, R, T, Q> flipud(mat<C, R, T, Q> const& in)\n\t{\n\t\tmat<R, C, T, Q> tin = transpose(in);\n\t\ttin = fliplr(tin);\n\t\tmat<C, R, T, Q> out = transpose(tin);\n\n\t\treturn out;\n\t}\n\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<C, R, T, Q> fliplr(mat<C, R, T, Q> const& in)\n\t{\n\t\tmat<C, R, T, Q> out;\n\t\tfor (length_t i = 0; i < C; i++)\n\t\t{\n\t\t\tout[i] = in[(C - i) - 1];\n\t\t}\n\n\t\treturn out;\n\t}\n\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER void qr_decompose(mat<C, R, T, Q> const& in, mat<(C < R ? C : R), R, T, Q>& q, mat<C, (C < R ? C : R), T, Q>& r)\n\t{\n\t\t// Uses modified Gram-Schmidt method\n\t\t// Source: https://en.wikipedia.org/wiki/GramSchmidt_process\n\t\t// And https://en.wikipedia.org/wiki/QR_decomposition\n\n\t\t//For all the linearly independs columns of the input...\n\t\t// (there can be no more linearly independents columns than there are rows.)\n\t\tfor (length_t i = 0; i < (C < R ? C : R); i++)\n\t\t{\n\t\t\t//Copy in Q the input's i-th column.\n\t\t\tq[i] = in[i];\n\n\t\t\t//j = [0,i[\n\t\t\t// Make that column orthogonal to all the previous ones by substracting to it the non-orthogonal projection of all the previous columns.\n\t\t\t// Also: Fill the zero elements of R\n\t\t\tfor (length_t j = 0; j < i; j++)\n\t\t\t{\n\t\t\t\tq[i] -= dot(q[i], q[j])*q[j];\n\t\t\t\tr[j][i] = 0;\n\t\t\t}\n\n\t\t\t//Now, Q i-th column is orthogonal to all the previous columns. Normalize it.\n\t\t\tq[i] = normalize(q[i]);\n\n\t\t\t//j = [i,C[\n\t\t\t//Finally, compute the corresponding coefficients of R by computing the projection of the resulting column on the other columns of the input.\n\t\t\tfor (length_t j = i; j < C; j++)\n\t\t\t{\n\t\t\t\tr[j][i] = dot(in[j], q[i]);\n\t\t\t}\n\t\t}\n\t}\n\n\ttemplate <length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER void rq_decompose(mat<C, R, T, Q> const& in, mat<(C < R ? C : R), R, T, Q>& r, mat<C, (C < R ? C : R), T, Q>& q)\n\t{\n\t\t// From https://en.wikipedia.org/wiki/QR_decomposition:\n\t\t// The RQ decomposition transforms a matrix A into the product of an upper triangular matrix R (also known as right-triangular) and an orthogonal matrix Q. The only difference from QR decomposition is the order of these matrices.\n\t\t// QR decomposition is GramSchmidt orthogonalization of columns of A, started from the first column.\n\t\t// RQ decomposition is GramSchmidt orthogonalization of rows of A, started from the last row.\n\n\t\tmat<R, C, T, Q> tin = transpose(in);\n\t\ttin = fliplr(tin);\n\n\t\tmat<R, (C < R ? C : R), T, Q> tr;\n\t\tmat<(C < R ? C : R), C, T, Q> tq;\n\t\tqr_decompose(tin, tq, tr);\n\n\t\ttr = fliplr(tr);\n\t\tr = transpose(tr);\n\t\tr = fliplr(r);\n\n\t\ttq = fliplr(tq);\n\t\tq = transpose(tq);\n\t}\n} //namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_interpolation.hpp",
    "content": "/// @ref gtx_matrix_interpolation\n/// @file glm/gtx/matrix_interpolation.hpp\n/// @author Ghenadii Ursachi (the.asteroth@gmail.com)\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_matrix_interpolation GLM_GTX_matrix_interpolation\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_interpolation.hpp> to use the features of this extension.\n///\n/// Allows to directly interpolate two matrices.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_interpolation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_interpolation extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_interpolation\n\t/// @{\n\n\t/// Get the axis and angle of the rotation from a matrix.\n\t/// From GLM_GTX_matrix_interpolation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL void axisAngle(\n\t\tmat<4, 4, T, Q> const& Mat, vec<3, T, Q> & Axis, T & Angle);\n\n\t/// Build a matrix from axis and angle.\n\t/// From GLM_GTX_matrix_interpolation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> axisAngleMatrix(\n\t\tvec<3, T, Q> const& Axis, T const Angle);\n\n\t/// Extracts the rotation part of a matrix.\n\t/// From GLM_GTX_matrix_interpolation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> extractMatrixRotation(\n\t\tmat<4, 4, T, Q> const& Mat);\n\n\t/// Build a interpolation of 4 * 4 matrixes.\n\t/// From GLM_GTX_matrix_interpolation extension.\n\t/// Warning! works only with rotation and/or translation matrixes, scale will generate unexpected results.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> interpolate(\n\t\tmat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const Delta);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_interpolation.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_interpolation.inl",
    "content": "/// @ref gtx_matrix_interpolation\n\n#include \"../gtc/constants.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER void axisAngle(mat<4, 4, T, Q> const& m, vec<3, T, Q> & axis, T& angle)\n\t{\n\t\tT epsilon = static_cast<T>(0.01);\n\t\tT epsilon2 = static_cast<T>(0.1);\n\n\t\tif((abs(m[1][0] - m[0][1]) < epsilon) && (abs(m[2][0] - m[0][2]) < epsilon) && (abs(m[2][1] - m[1][2]) < epsilon))\n\t\t{\n\t\t\tif ((abs(m[1][0] + m[0][1]) < epsilon2) && (abs(m[2][0] + m[0][2]) < epsilon2) && (abs(m[2][1] + m[1][2]) < epsilon2) && (abs(m[0][0] + m[1][1] + m[2][2] - static_cast<T>(3.0)) < epsilon2))\n\t\t\t{\n\t\t\t\tangle = static_cast<T>(0.0);\n\t\t\t\taxis.x = static_cast<T>(1.0);\n\t\t\t\taxis.y = static_cast<T>(0.0);\n\t\t\t\taxis.z = static_cast<T>(0.0);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tangle = static_cast<T>(3.1415926535897932384626433832795);\n\t\t\tT xx = (m[0][0] + static_cast<T>(1.0)) * static_cast<T>(0.5);\n\t\t\tT yy = (m[1][1] + static_cast<T>(1.0)) * static_cast<T>(0.5);\n\t\t\tT zz = (m[2][2] + static_cast<T>(1.0)) * static_cast<T>(0.5);\n\t\t\tT xy = (m[1][0] + m[0][1]) * static_cast<T>(0.25);\n\t\t\tT xz = (m[2][0] + m[0][2]) * static_cast<T>(0.25);\n\t\t\tT yz = (m[2][1] + m[1][2]) * static_cast<T>(0.25);\n\t\t\tif((xx > yy) && (xx > zz))\n\t\t\t{\n\t\t\t\tif(xx < epsilon)\n\t\t\t\t{\n\t\t\t\t\taxis.x = static_cast<T>(0.0);\n\t\t\t\t\taxis.y = static_cast<T>(0.7071);\n\t\t\t\t\taxis.z = static_cast<T>(0.7071);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taxis.x = sqrt(xx);\n\t\t\t\t\taxis.y = xy / axis.x;\n\t\t\t\t\taxis.z = xz / axis.x;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (yy > zz)\n\t\t\t{\n\t\t\t\tif(yy < epsilon)\n\t\t\t\t{\n\t\t\t\t\taxis.x = static_cast<T>(0.7071);\n\t\t\t\t\taxis.y = static_cast<T>(0.0);\n\t\t\t\t\taxis.z = static_cast<T>(0.7071);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taxis.y = sqrt(yy);\n\t\t\t\t\taxis.x = xy / axis.y;\n\t\t\t\t\taxis.z = yz / axis.y;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (zz < epsilon)\n\t\t\t\t{\n\t\t\t\t\taxis.x = static_cast<T>(0.7071);\n\t\t\t\t\taxis.y = static_cast<T>(0.7071);\n\t\t\t\t\taxis.z = static_cast<T>(0.0);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\taxis.z = sqrt(zz);\n\t\t\t\t\taxis.x = xz / axis.z;\n\t\t\t\t\taxis.y = yz / axis.z;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tT s = sqrt((m[2][1] - m[1][2]) * (m[2][1] - m[1][2]) + (m[2][0] - m[0][2]) * (m[2][0] - m[0][2]) + (m[1][0] - m[0][1]) * (m[1][0] - m[0][1]));\n\t\tif (glm::abs(s) < T(0.001))\n\t\t\ts = static_cast<T>(1);\n\t\tT const angleCos = (m[0][0] + m[1][1] + m[2][2] - static_cast<T>(1)) * static_cast<T>(0.5);\n\t\tif(angleCos - static_cast<T>(1) < epsilon)\n\t\t\tangle = pi<T>() * static_cast<T>(0.25);\n\t\telse\n\t\t\tangle = acos(angleCos);\n\t\taxis.x = (m[1][2] - m[2][1]) / s;\n\t\taxis.y = (m[2][0] - m[0][2]) / s;\n\t\taxis.z = (m[0][1] - m[1][0]) / s;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> axisAngleMatrix(vec<3, T, Q> const& axis, T const angle)\n\t{\n\t\tT c = cos(angle);\n\t\tT s = sin(angle);\n\t\tT t = static_cast<T>(1) - c;\n\t\tvec<3, T, Q> n = normalize(axis);\n\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tt * n.x * n.x + c,          t * n.x * n.y + n.z * s,    t * n.x * n.z - n.y * s,    static_cast<T>(0.0),\n\t\t\tt * n.x * n.y - n.z * s,    t * n.y * n.y + c,          t * n.y * n.z + n.x * s,    static_cast<T>(0.0),\n\t\t\tt * n.x * n.z + n.y * s,    t * n.y * n.z - n.x * s,    t * n.z * n.z + c,          static_cast<T>(0.0),\n\t\t\tstatic_cast<T>(0.0),        static_cast<T>(0.0),        static_cast<T>(0.0),        static_cast<T>(1.0));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> extractMatrixRotation(mat<4, 4, T, Q> const& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(\n\t\t\tm[0][0], m[0][1], m[0][2], static_cast<T>(0.0),\n\t\t\tm[1][0], m[1][1], m[1][2], static_cast<T>(0.0),\n\t\t\tm[2][0], m[2][1], m[2][2], static_cast<T>(0.0),\n\t\t\tstatic_cast<T>(0.0), static_cast<T>(0.0), static_cast<T>(0.0), static_cast<T>(1.0));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> interpolate(mat<4, 4, T, Q> const& m1, mat<4, 4, T, Q> const& m2, T const delta)\n\t{\n\t\tmat<4, 4, T, Q> m1rot = extractMatrixRotation(m1);\n\t\tmat<4, 4, T, Q> dltRotation = m2 * transpose(m1rot);\n\t\tvec<3, T, Q> dltAxis;\n\t\tT dltAngle;\n\t\taxisAngle(dltRotation, dltAxis, dltAngle);\n\t\tmat<4, 4, T, Q> out = axisAngleMatrix(dltAxis, dltAngle * delta) * m1rot;\n\t\tout[3][0] = m1[3][0] + delta * (m2[3][0] - m1[3][0]);\n\t\tout[3][1] = m1[3][1] + delta * (m2[3][1] - m1[3][1]);\n\t\tout[3][2] = m1[3][2] + delta * (m2[3][2] - m1[3][2]);\n\t\treturn out;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_major_storage.hpp",
    "content": "/// @ref gtx_matrix_major_storage\n/// @file glm/gtx/matrix_major_storage.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_matrix_major_storage GLM_GTX_matrix_major_storage\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_major_storage.hpp> to use the features of this extension.\n///\n/// Build matrices with specific matrix order, row or column\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_major_storage is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_major_storage extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_major_storage\n\t/// @{\n\n\t//! Build a row major matrix from row vectors.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2(\n\t\tvec<2, T, Q> const& v1,\n\t\tvec<2, T, Q> const& v2);\n\n\t//! Build a row major matrix from other matrix.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> rowMajor2(\n\t\tmat<2, 2, T, Q> const& m);\n\n\t//! Build a row major matrix from row vectors.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3(\n\t\tvec<3, T, Q> const& v1,\n\t\tvec<3, T, Q> const& v2,\n\t\tvec<3, T, Q> const& v3);\n\n\t//! Build a row major matrix from other matrix.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> rowMajor3(\n\t\tmat<3, 3, T, Q> const& m);\n\n\t//! Build a row major matrix from row vectors.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4(\n\t\tvec<4, T, Q> const& v1,\n\t\tvec<4, T, Q> const& v2,\n\t\tvec<4, T, Q> const& v3,\n\t\tvec<4, T, Q> const& v4);\n\n\t//! Build a row major matrix from other matrix.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> rowMajor4(\n\t\tmat<4, 4, T, Q> const& m);\n\n\t//! Build a column major matrix from column vectors.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> colMajor2(\n\t\tvec<2, T, Q> const& v1,\n\t\tvec<2, T, Q> const& v2);\n\n\t//! Build a column major matrix from other matrix.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> colMajor2(\n\t\tmat<2, 2, T, Q> const& m);\n\n\t//! Build a column major matrix from column vectors.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> colMajor3(\n\t\tvec<3, T, Q> const& v1,\n\t\tvec<3, T, Q> const& v2,\n\t\tvec<3, T, Q> const& v3);\n\n\t//! Build a column major matrix from other matrix.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> colMajor3(\n\t\tmat<3, 3, T, Q> const& m);\n\n\t//! Build a column major matrix from column vectors.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> colMajor4(\n\t\tvec<4, T, Q> const& v1,\n\t\tvec<4, T, Q> const& v2,\n\t\tvec<4, T, Q> const& v3,\n\t\tvec<4, T, Q> const& v4);\n\n\t//! Build a column major matrix from other matrix.\n\t//! From GLM_GTX_matrix_major_storage extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> colMajor4(\n\t\tmat<4, 4, T, Q> const& m);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_major_storage.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_major_storage.inl",
    "content": "/// @ref gtx_matrix_major_storage\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2\n\t(\n\t\tvec<2, T, Q> const& v1,\n\t\tvec<2, T, Q> const& v2\n\t)\n\t{\n\t\tmat<2, 2, T, Q> Result;\n\t\tResult[0][0] = v1.x;\n\t\tResult[1][0] = v1.y;\n\t\tResult[0][1] = v2.x;\n\t\tResult[1][1] = v2.y;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> rowMajor2(\n\t\tconst mat<2, 2, T, Q>& m)\n\t{\n\t\tmat<2, 2, T, Q> Result;\n\t\tResult[0][0] = m[0][0];\n\t\tResult[0][1] = m[1][0];\n\t\tResult[1][0] = m[0][1];\n\t\tResult[1][1] = m[1][1];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3(\n\t\tconst vec<3, T, Q>& v1,\n\t\tconst vec<3, T, Q>& v2,\n\t\tconst vec<3, T, Q>& v3)\n\t{\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0][0] = v1.x;\n\t\tResult[1][0] = v1.y;\n\t\tResult[2][0] = v1.z;\n\t\tResult[0][1] = v2.x;\n\t\tResult[1][1] = v2.y;\n\t\tResult[2][1] = v2.z;\n\t\tResult[0][2] = v3.x;\n\t\tResult[1][2] = v3.y;\n\t\tResult[2][2] = v3.z;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> rowMajor3(\n\t\tconst mat<3, 3, T, Q>& m)\n\t{\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0][0] = m[0][0];\n\t\tResult[0][1] = m[1][0];\n\t\tResult[0][2] = m[2][0];\n\t\tResult[1][0] = m[0][1];\n\t\tResult[1][1] = m[1][1];\n\t\tResult[1][2] = m[2][1];\n\t\tResult[2][0] = m[0][2];\n\t\tResult[2][1] = m[1][2];\n\t\tResult[2][2] = m[2][2];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4(\n\t\tconst vec<4, T, Q>& v1,\n\t\tconst vec<4, T, Q>& v2,\n\t\tconst vec<4, T, Q>& v3,\n\t\tconst vec<4, T, Q>& v4)\n\t{\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0][0] = v1.x;\n\t\tResult[1][0] = v1.y;\n\t\tResult[2][0] = v1.z;\n\t\tResult[3][0] = v1.w;\n\t\tResult[0][1] = v2.x;\n\t\tResult[1][1] = v2.y;\n\t\tResult[2][1] = v2.z;\n\t\tResult[3][1] = v2.w;\n\t\tResult[0][2] = v3.x;\n\t\tResult[1][2] = v3.y;\n\t\tResult[2][2] = v3.z;\n\t\tResult[3][2] = v3.w;\n\t\tResult[0][3] = v4.x;\n\t\tResult[1][3] = v4.y;\n\t\tResult[2][3] = v4.z;\n\t\tResult[3][3] = v4.w;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> rowMajor4(\n\t\tconst mat<4, 4, T, Q>& m)\n\t{\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0][0] = m[0][0];\n\t\tResult[0][1] = m[1][0];\n\t\tResult[0][2] = m[2][0];\n\t\tResult[0][3] = m[3][0];\n\t\tResult[1][0] = m[0][1];\n\t\tResult[1][1] = m[1][1];\n\t\tResult[1][2] = m[2][1];\n\t\tResult[1][3] = m[3][1];\n\t\tResult[2][0] = m[0][2];\n\t\tResult[2][1] = m[1][2];\n\t\tResult[2][2] = m[2][2];\n\t\tResult[2][3] = m[3][2];\n\t\tResult[3][0] = m[0][3];\n\t\tResult[3][1] = m[1][3];\n\t\tResult[3][2] = m[2][3];\n\t\tResult[3][3] = m[3][3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2(\n\t\tconst vec<2, T, Q>& v1,\n\t\tconst vec<2, T, Q>& v2)\n\t{\n\t\treturn mat<2, 2, T, Q>(v1, v2);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> colMajor2(\n\t\tconst mat<2, 2, T, Q>& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3(\n\t\tconst vec<3, T, Q>& v1,\n\t\tconst vec<3, T, Q>& v2,\n\t\tconst vec<3, T, Q>& v3)\n\t{\n\t\treturn mat<3, 3, T, Q>(v1, v2, v3);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> colMajor3(\n\t\tconst mat<3, 3, T, Q>& m)\n\t{\n\t\treturn mat<3, 3, T, Q>(m);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4(\n\t\tconst vec<4, T, Q>& v1,\n\t\tconst vec<4, T, Q>& v2,\n\t\tconst vec<4, T, Q>& v3,\n\t\tconst vec<4, T, Q>& v4)\n\t{\n\t\treturn mat<4, 4, T, Q>(v1, v2, v3, v4);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> colMajor4(\n\t\tconst mat<4, 4, T, Q>& m)\n\t{\n\t\treturn mat<4, 4, T, Q>(m);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_operation.hpp",
    "content": "/// @ref gtx_matrix_operation\n/// @file glm/gtx/matrix_operation.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_matrix_operation GLM_GTX_matrix_operation\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_operation.hpp> to use the features of this extension.\n///\n/// Build diagonal matrices from vectors.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_operation is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_operation extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_operation\n\t/// @{\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> diagonal2x2(\n\t\tvec<2, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 3, T, Q> diagonal2x3(\n\t\tvec<2, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 4, T, Q> diagonal2x4(\n\t\tvec<2, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 2, T, Q> diagonal3x2(\n\t\tvec<2, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> diagonal3x3(\n\t\tvec<3, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 4, T, Q> diagonal3x4(\n\t\tvec<3, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 2, T, Q> diagonal4x2(\n\t\tvec<2, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 3, T, Q> diagonal4x3(\n\t\tvec<3, T, Q> const& v);\n\n\t//! Build a diagonal matrix.\n\t//! From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> diagonal4x4(\n\t\tvec<4, T, Q> const& v);\n\n\t/// Build an adjugate  matrix.\n\t/// From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m);\n\n\t/// Build an adjugate  matrix.\n\t/// From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m);\n\n\t/// Build an adjugate  matrix.\n\t/// From GLM_GTX_matrix_operation extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_operation.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_operation.inl",
    "content": "/// @ref gtx_matrix_operation\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> diagonal2x2\n\t(\n\t\tvec<2, T, Q> const& v\n\t)\n\t{\n\t\tmat<2, 2, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 3, T, Q> diagonal2x3\n\t(\n\t\tvec<2, T, Q> const& v\n\t)\n\t{\n\t\tmat<2, 3, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 4, T, Q> diagonal2x4\n\t(\n\t\tvec<2, T, Q> const& v\n\t)\n\t{\n\t\tmat<2, 4, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 2, T, Q> diagonal3x2\n\t(\n\t\tvec<2, T, Q> const& v\n\t)\n\t{\n\t\tmat<3, 2, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> diagonal3x3\n\t(\n\t\tvec<3, T, Q> const& v\n\t)\n\t{\n\t\tmat<3, 3, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\tResult[2][2] = v[2];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 4, T, Q> diagonal3x4\n\t(\n\t\tvec<3, T, Q> const& v\n\t)\n\t{\n\t\tmat<3, 4, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\tResult[2][2] = v[2];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> diagonal4x4\n\t(\n\t\tvec<4, T, Q> const& v\n\t)\n\t{\n\t\tmat<4, 4, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\tResult[2][2] = v[2];\n\t\tResult[3][3] = v[3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 3, T, Q> diagonal4x3\n\t(\n\t\tvec<3, T, Q> const& v\n\t)\n\t{\n\t\tmat<4, 3, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\tResult[2][2] = v[2];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 2, T, Q> diagonal4x2\n\t(\n\t\tvec<2, T, Q> const& v\n\t)\n\t{\n\t\tmat<4, 2, T, Q> Result(static_cast<T>(1));\n\t\tResult[0][0] = v[0];\n\t\tResult[1][1] = v[1];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<2, 2, T, Q> adjugate(mat<2, 2, T, Q> const& m)\n\t{\n\t\treturn mat<2, 2, T, Q>(\n\t\t\t+m[1][1], -m[1][0],\n\t\t\t-m[0][1], +m[0][0]);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> adjugate(mat<3, 3, T, Q> const& m)\n\t{\n\t\tT const m00 = determinant(mat<2, 2, T, Q>(m[1][1], m[2][1], m[1][2], m[2][2]));\n\t\tT const m01 = determinant(mat<2, 2, T, Q>(m[0][1], m[2][1], m[0][2], m[2][2]));\n\t\tT const m02 = determinant(mat<2, 2, T, Q>(m[0][1], m[1][1], m[0][2], m[1][2]));\n\n\t\tT const m10 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][2], m[2][2]));\n\t\tT const m11 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][2], m[2][2]));\n\t\tT const m12 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][2], m[1][2]));\n\n\t\tT const m20 = determinant(mat<2, 2, T, Q>(m[1][0], m[2][0], m[1][1], m[2][1]));\n\t\tT const m21 = determinant(mat<2, 2, T, Q>(m[0][0], m[2][0], m[0][1], m[2][1]));\n\t\tT const m22 = determinant(mat<2, 2, T, Q>(m[0][0], m[1][0], m[0][1], m[1][1]));\n\n\t\treturn mat<3, 3, T, Q>(\n\t\t\t+m00, -m01, +m02,\n\t\t\t-m10, +m11, -m12,\n\t\t\t+m20, -m21, +m22);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> adjugate(mat<4, 4, T, Q> const& m)\n\t{\n\t\tT const m00 = determinant(mat<3, 3, T, Q>(m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3]));\n\t\tT const m01 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3]));\n\t\tT const m02 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][1], m[3][3]));\n\t\tT const m03 = determinant(mat<3, 3, T, Q>(m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2]));\n\n\t\tT const m10 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[2][1], m[2][2], m[2][3], m[3][1], m[3][2], m[3][3]));\n\t\tT const m11 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[2][0], m[2][2], m[2][3], m[3][0], m[3][2], m[3][3]));\n\t\tT const m12 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[2][0], m[2][1], m[2][3], m[3][0], m[3][1], m[3][3]));\n\t\tT const m13 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[2][0], m[2][1], m[2][2], m[3][0], m[3][1], m[3][2]));\n\n\t\tT const m20 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[3][1], m[3][2], m[3][3]));\n\t\tT const m21 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[3][0], m[3][2], m[3][3]));\n\t\tT const m22 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[3][0], m[3][1], m[3][3]));\n\t\tT const m23 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[3][0], m[3][1], m[3][2]));\n\n\t\tT const m30 = determinant(mat<3, 3, T, Q>(m[0][1], m[0][2], m[0][3], m[1][1], m[1][2], m[1][3], m[2][1], m[2][2], m[2][3]));\n\t\tT const m31 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][2], m[0][3], m[1][0], m[1][2], m[1][3], m[2][0], m[2][2], m[2][3]));\n\t\tT const m32 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][3], m[1][0], m[1][1], m[1][3], m[2][0], m[2][1], m[2][3]));\n\t\tT const m33 = determinant(mat<3, 3, T, Q>(m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2], m[2][0], m[2][1], m[2][2]));\n\n\t\treturn mat<4, 4, T, Q>(\n\t\t\t+m00, -m01, +m02, -m03,\n\t\t\t-m10, +m11, -m12, +m13,\n\t\t\t+m20, -m21, +m22, -m23,\n\t\t\t-m30, +m31, -m32, +m33);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_query.hpp",
    "content": "/// @ref gtx_matrix_query\n/// @file glm/gtx/matrix_query.hpp\n///\n/// @see core (dependence)\n/// @see gtx_vector_query (dependence)\n///\n/// @defgroup gtx_matrix_query GLM_GTX_matrix_query\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_query.hpp> to use the features of this extension.\n///\n/// Query to evaluate matrix properties\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtx/vector_query.hpp\"\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_query extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_query\n\t/// @{\n\n\t/// Return whether a matrix a null matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix a null matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix is a null matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix is an identity matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<length_t C, length_t R, typename T, qualifier Q, template<length_t, length_t, typename, qualifier> class matType>\n\tGLM_FUNC_DECL bool isIdentity(matType<C, R, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix is a normalized matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix is a normalized matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix is a normalized matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon);\n\n\t/// Return whether a matrix is an orthonormalized matrix.\n\t/// From GLM_GTX_matrix_query extension.\n\ttemplate<length_t C, length_t R, typename T, qualifier Q, template<length_t, length_t, typename, qualifier> class matType>\n\tGLM_FUNC_DECL bool isOrthogonal(matType<C, R, T, Q> const& m, T const& epsilon);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_query.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_query.inl",
    "content": "/// @ref gtx_matrix_query\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNull(mat<2, 2, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result = true;\n\t\tfor(length_t i = 0; result && i < m.length() ; ++i)\n\t\t\tresult = isNull(m[i], epsilon);\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNull(mat<3, 3, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result = true;\n\t\tfor(length_t i = 0; result && i < m.length() ; ++i)\n\t\t\tresult = isNull(m[i], epsilon);\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNull(mat<4, 4, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result = true;\n\t\tfor(length_t i = 0; result && i < m.length() ; ++i)\n\t\t\tresult = isNull(m[i], epsilon);\n\t\treturn result;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isIdentity(mat<C, R, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result = true;\n\t\tfor(length_t i = 0; result && i < m[0].length() ; ++i)\n\t\t{\n\t\t\tfor(length_t j = 0; result && j < i ; ++j)\n\t\t\t\tresult = abs(m[i][j]) <= epsilon;\n\t\t\tif(result)\n\t\t\t\tresult = abs(m[i][i] - 1) <= epsilon;\n\t\t\tfor(length_t j = i + 1; result && j < m.length(); ++j)\n\t\t\t\tresult = abs(m[i][j]) <= epsilon;\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNormalized(mat<2, 2, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result(true);\n\t\tfor(length_t i = 0; result && i < m.length(); ++i)\n\t\t\tresult = isNormalized(m[i], epsilon);\n\t\tfor(length_t i = 0; result && i < m.length(); ++i)\n\t\t{\n\t\t\ttypename mat<2, 2, T, Q>::col_type v;\n\t\t\tfor(length_t j = 0; j < m.length(); ++j)\n\t\t\t\tv[j] = m[j][i];\n\t\t\tresult = isNormalized(v, epsilon);\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNormalized(mat<3, 3, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result(true);\n\t\tfor(length_t i = 0; result && i < m.length(); ++i)\n\t\t\tresult = isNormalized(m[i], epsilon);\n\t\tfor(length_t i = 0; result && i < m.length(); ++i)\n\t\t{\n\t\t\ttypename mat<3, 3, T, Q>::col_type v;\n\t\t\tfor(length_t j = 0; j < m.length(); ++j)\n\t\t\t\tv[j] = m[j][i];\n\t\t\tresult = isNormalized(v, epsilon);\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNormalized(mat<4, 4, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result(true);\n\t\tfor(length_t i = 0; result && i < m.length(); ++i)\n\t\t\tresult = isNormalized(m[i], epsilon);\n\t\tfor(length_t i = 0; result && i < m.length(); ++i)\n\t\t{\n\t\t\ttypename mat<4, 4, T, Q>::col_type v;\n\t\t\tfor(length_t j = 0; j < m.length(); ++j)\n\t\t\t\tv[j] = m[j][i];\n\t\t\tresult = isNormalized(v, epsilon);\n\t\t}\n\t\treturn result;\n\t}\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isOrthogonal(mat<C, R, T, Q> const& m, T const& epsilon)\n\t{\n\t\tbool result = true;\n\t\tfor(length_t i(0); result && i < m.length() - 1; ++i)\n\t\tfor(length_t j(i + 1); result && j < m.length(); ++j)\n\t\t\tresult = areOrthogonal(m[i], m[j], epsilon);\n\n\t\tif(result)\n\t\t{\n\t\t\tmat<C, R, T, Q> tmp = transpose(m);\n\t\t\tfor(length_t i(0); result && i < m.length() - 1 ; ++i)\n\t\t\tfor(length_t j(i + 1); result && j < m.length(); ++j)\n\t\t\t\tresult = areOrthogonal(tmp[i], tmp[j], epsilon);\n\t\t}\n\t\treturn result;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_transform_2d.hpp",
    "content": "/// @ref gtx_matrix_transform_2d\n/// @file glm/gtx/matrix_transform_2d.hpp\n/// @author Miguel Ángel Pérez Martínez\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_matrix_transform_2d GLM_GTX_matrix_transform_2d\n/// @ingroup gtx\n///\n/// Include <glm/gtx/matrix_transform_2d.hpp> to use the features of this extension.\n///\n/// Defines functions that generate common 2d transformation matrices.\n\n#pragma once\n\n// Dependency:\n#include \"../mat3x3.hpp\"\n#include \"../vec2.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_transform_2d is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_matrix_transform_2d extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_matrix_transform_2d\n\t/// @{\n\n\t/// Builds a translation 3 * 3 matrix created from a vector of 2 components.\n\t///\n\t/// @param m Input matrix multiplied by this translation matrix.\n\t/// @param v Coordinates of a translation vector.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tvec<2, T, Q> const& v);\n\n\t/// Builds a rotation 3 * 3 matrix created from an angle.\n\t///\n\t/// @param m Input matrix multiplied by this translation matrix.\n\t/// @param angle Rotation angle expressed in radians.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tT angle);\n\n\t/// Builds a scale 3 * 3 matrix created from a vector of 2 components.\n\t///\n\t/// @param m Input matrix multiplied by this translation matrix.\n\t/// @param v Coordinates of a scale vector.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tvec<2, T, Q> const& v);\n\n\t/// Builds an horizontal (parallel to the x axis) shear 3 * 3 matrix.\n\t///\n\t/// @param m Input matrix multiplied by this translation matrix.\n\t/// @param y Shear factor.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tT y);\n\n\t/// Builds a vertical (parallel to the y axis) shear 3 * 3 matrix.\n\t///\n\t/// @param m Input matrix multiplied by this translation matrix.\n\t/// @param x Shear factor.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tT x);\n\n\t/// @}\n}//namespace glm\n\n#include \"matrix_transform_2d.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/matrix_transform_2d.inl",
    "content": "/// @ref gtx_matrix_transform_2d\n/// @author Miguel Ángel Pérez Martínez\n\n#include \"../trigonometric.hpp\"\n\nnamespace glm\n{\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> translate(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tvec<2, T, Q> const& v)\n\t{\n\t\tmat<3, 3, T, Q> Result(m);\n\t\tResult[2] = m[0] * v[0] + m[1] * v[1] + m[2];\n\t\treturn Result;\n\t}\n\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> rotate(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tT angle)\n\t{\n\t\tT const a = angle;\n\t\tT const c = cos(a);\n\t\tT const s = sin(a);\n\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0] = m[0] * c + m[1] * s;\n\t\tResult[1] = m[0] * -s + m[1] * c;\n\t\tResult[2] = m[2];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> scale(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tvec<2, T, Q> const& v)\n\t{\n\t\tmat<3, 3, T, Q> Result;\n\t\tResult[0] = m[0] * v[0];\n\t\tResult[1] = m[1] * v[1];\n\t\tResult[2] = m[2];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tT y)\n\t{\n\t\tmat<3, 3, T, Q> Result(1);\n\t\tResult[0][1] = y;\n\t\treturn m * Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY(\n\t\tmat<3, 3, T, Q> const& m,\n\t\tT x)\n\t{\n\t\tmat<3, 3, T, Q> Result(1);\n\t\tResult[1][0] = x;\n\t\treturn m * Result;\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/mixed_product.hpp",
    "content": "/// @ref gtx_mixed_product\n/// @file glm/gtx/mixed_product.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_mixed_product GLM_GTX_mixed_producte\n/// @ingroup gtx\n///\n/// Include <glm/gtx/mixed_product.hpp> to use the features of this extension.\n///\n/// Mixed product of 3 vectors.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_mixed_product is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_mixed_product extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_mixed_product\n\t/// @{\n\n\t/// @brief Mixed product of 3 vectors (from GLM_GTX_mixed_product extension)\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T mixedProduct(\n\t\tvec<3, T, Q> const& v1,\n\t\tvec<3, T, Q> const& v2,\n\t\tvec<3, T, Q> const& v3);\n\n\t/// @}\n}// namespace glm\n\n#include \"mixed_product.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/mixed_product.inl",
    "content": "/// @ref gtx_mixed_product\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T mixedProduct\n\t(\n\t\tvec<3, T, Q> const& v1,\n\t\tvec<3, T, Q> const& v2,\n\t\tvec<3, T, Q> const& v3\n\t)\n\t{\n\t\treturn dot(cross(v1, v2), v3);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/norm.hpp",
    "content": "/// @ref gtx_norm\n/// @file glm/gtx/norm.hpp\n///\n/// @see core (dependence)\n/// @see gtx_quaternion (dependence)\n/// @see gtx_component_wise (dependence)\n///\n/// @defgroup gtx_norm GLM_GTX_norm\n/// @ingroup gtx\n///\n/// Include <glm/gtx/norm.hpp> to use the features of this extension.\n///\n/// Various ways to compute vector norms.\n\n#pragma once\n\n// Dependency:\n#include \"../geometric.hpp\"\n#include \"../gtx/quaternion.hpp\"\n#include \"../gtx/component_wise.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_norm is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_norm extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_norm\n\t/// @{\n\n\t/// Returns the squared length of x.\n\t/// From GLM_GTX_norm extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T length2(vec<L, T, Q> const& x);\n\n\t/// Returns the squared distance between p0 and p1, i.e., length2(p0 - p1).\n\t/// From GLM_GTX_norm extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T distance2(vec<L, T, Q> const& p0, vec<L, T, Q> const& p1);\n\n\t//! Returns the L1 norm between x and y.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y);\n\n\t//! Returns the L1 norm of v.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T l1Norm(vec<3, T, Q> const& v);\n\n\t//! Returns the L2 norm between x and y.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x, vec<3, T, Q> const& y);\n\n\t//! Returns the L2 norm of v.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T l2Norm(vec<3, T, Q> const& x);\n\n\t//! Returns the L norm between x and y.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth);\n\n\t//! Returns the L norm of v.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T lxNorm(vec<3, T, Q> const& x, unsigned int Depth);\n\n\t//! Returns the LMax norm between x and y.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y);\n\n\t//! Returns the LMax norm of v.\n\t//! From GLM_GTX_norm extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T lMaxNorm(vec<3, T, Q> const& x);\n\n\t/// @}\n}//namespace glm\n\n#include \"norm.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/norm.inl",
    "content": "/// @ref gtx_norm\n\n#include \"../detail/qualifier.hpp\"\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q, bool Aligned>\n\tstruct compute_length2\n\t{\n\t\tGLM_FUNC_QUALIFIER static T call(vec<L, T, Q> const& v)\n\t\t{\n\t\t\treturn dot(v, v);\n\t\t}\n\t};\n}//namespace detail\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType length2(genType x)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'length2' accepts only floating-point inputs\");\n\t\treturn x * x;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T length2(vec<L, T, Q> const& v)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'length2' accepts only floating-point inputs\");\n\t\treturn detail::compute_length2<L, T, Q, detail::is_aligned<Q>::value>::call(v);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER T distance2(T p0, T p1)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'distance2' accepts only floating-point inputs\");\n\t\treturn length2(p1 - p0);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T distance2(vec<L, T, Q> const& p0, vec<L, T, Q> const& p1)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'distance2' accepts only floating-point inputs\");\n\t\treturn length2(p1 - p0);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b)\n\t{\n\t\treturn abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T l1Norm(vec<3, T, Q> const& v)\n\t{\n\t\treturn abs(v.x) + abs(v.y) + abs(v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& a, vec<3, T, Q> const& b\n\t)\n\t{\n\t\treturn length(b - a);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T l2Norm(vec<3, T, Q> const& v)\n\t{\n\t\treturn length(v);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& x, vec<3, T, Q> const& y, unsigned int Depth)\n\t{\n\t\treturn pow(pow(abs(y.x - x.x), T(Depth)) + pow(abs(y.y - x.y), T(Depth)) + pow(abs(y.z - x.z), T(Depth)), T(1) / T(Depth));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T lxNorm(vec<3, T, Q> const& v, unsigned int Depth)\n\t{\n\t\treturn pow(pow(abs(v.x), T(Depth)) + pow(abs(v.y), T(Depth)) + pow(abs(v.z), T(Depth)), T(1) / T(Depth));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& a, vec<3, T, Q> const& b)\n\t{\n\t\treturn compMax(abs(b - a));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T lMaxNorm(vec<3, T, Q> const& v)\n\t{\n\t\treturn compMax(abs(v));\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/normal.hpp",
    "content": "/// @ref gtx_normal\n/// @file glm/gtx/normal.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_normal GLM_GTX_normal\n/// @ingroup gtx\n///\n/// Include <glm/gtx/normal.hpp> to use the features of this extension.\n///\n/// Compute the normal of a triangle.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_normal is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_normal extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_normal\n\t/// @{\n\n\t/// Computes triangle normal from triangle points.\n\t///\n\t/// @see gtx_normal\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> triangleNormal(vec<3, T, Q> const& p1, vec<3, T, Q> const& p2, vec<3, T, Q> const& p3);\n\n\t/// @}\n}//namespace glm\n\n#include \"normal.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/normal.inl",
    "content": "/// @ref gtx_normal\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> triangleNormal\n\t(\n\t\tvec<3, T, Q> const& p1,\n\t\tvec<3, T, Q> const& p2,\n\t\tvec<3, T, Q> const& p3\n\t)\n\t{\n\t\treturn normalize(cross(p1 - p2, p1 - p3));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/normalize_dot.hpp",
    "content": "/// @ref gtx_normalize_dot\n/// @file glm/gtx/normalize_dot.hpp\n///\n/// @see core (dependence)\n/// @see gtx_fast_square_root (dependence)\n///\n/// @defgroup gtx_normalize_dot GLM_GTX_normalize_dot\n/// @ingroup gtx\n///\n/// Include <glm/gtx/normalized_dot.hpp> to use the features of this extension.\n///\n/// Dot product of vectors that need to be normalize with a single square root.\n\n#pragma once\n\n// Dependency:\n#include \"../gtx/fast_square_root.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_normalize_dot is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_normalize_dot extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_normalize_dot\n\t/// @{\n\n\t/// Normalize parameters and returns the dot product of x and y.\n\t/// It's faster that dot(normalize(x), normalize(y)).\n\t///\n\t/// @see gtx_normalize_dot extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T normalizeDot(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Normalize parameters and returns the dot product of x and y.\n\t/// Faster that dot(fastNormalize(x), fastNormalize(y)).\n\t///\n\t/// @see gtx_normalize_dot extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T fastNormalizeDot(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// @}\n}//namespace glm\n\n#include \"normalize_dot.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/normalize_dot.inl",
    "content": "/// @ref gtx_normalize_dot\n\nnamespace glm\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T normalizeDot(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\treturn glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T fastNormalizeDot(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\treturn glm::dot(x, y) * glm::fastInverseSqrt(glm::dot(x, x) * glm::dot(y, y));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/number_precision.hpp",
    "content": "/// @ref gtx_number_precision\n/// @file glm/gtx/number_precision.hpp\n///\n/// @see core (dependence)\n/// @see gtc_type_precision (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtx_number_precision GLM_GTX_number_precision\n/// @ingroup gtx\n///\n/// Include <glm/gtx/number_precision.hpp> to use the features of this extension.\n///\n/// Defined size types.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/type_precision.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_number_precision is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_number_precision extension included\")\n#\tendif\n#endif\n\nnamespace glm{\nnamespace gtx\n{\n\t/////////////////////////////\n\t// Unsigned int vector types\n\n\t/// @addtogroup gtx_number_precision\n\t/// @{\n\n\ttypedef u8\t\t\tu8vec1;\t\t//!< \\brief 8bit unsigned integer scalar. (from GLM_GTX_number_precision extension)\n\ttypedef u16\t\t\tu16vec1;    //!< \\brief 16bit unsigned integer scalar. (from GLM_GTX_number_precision extension)\n\ttypedef u32\t\t\tu32vec1;    //!< \\brief 32bit unsigned integer scalar. (from GLM_GTX_number_precision extension)\n\ttypedef u64\t\t\tu64vec1;    //!< \\brief 64bit unsigned integer scalar. (from GLM_GTX_number_precision extension)\n\n\t//////////////////////\n\t// Float vector types\n\n\ttypedef f32\t\t\tf32vec1;    //!< \\brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension)\n\ttypedef f64\t\t\tf64vec1;    //!< \\brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension)\n\n\t//////////////////////\n\t// Float matrix types\n\n\ttypedef f32\t\t\tf32mat1;\t//!< \\brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension)\n\ttypedef f32\t\t\tf32mat1x1;\t//!< \\brief Single-qualifier floating-point scalar. (from GLM_GTX_number_precision extension)\n\ttypedef f64\t\t\tf64mat1;\t//!< \\brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension)\n\ttypedef f64\t\t\tf64mat1x1;\t//!< \\brief Double-qualifier floating-point scalar. (from GLM_GTX_number_precision extension)\n\n\t/// @}\n}//namespace gtx\n}//namespace glm\n\n#include \"number_precision.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/number_precision.inl",
    "content": "/// @ref gtx_number_precision\n\nnamespace glm\n{\n\n}\n"
  },
  {
    "path": "lib/gli/glm/gtx/optimum_pow.hpp",
    "content": "/// @ref gtx_optimum_pow\n/// @file glm/gtx/optimum_pow.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_optimum_pow GLM_GTX_optimum_pow\n/// @ingroup gtx\n///\n/// Include <glm/gtx/optimum_pow.hpp> to use the features of this extension.\n///\n/// Integer exponentiation of power functions.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_optimum_pow is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_optimum_pow extension included\")\n#\tendif\n#endif\n\nnamespace glm{\nnamespace gtx\n{\n\t/// @addtogroup gtx_optimum_pow\n\t/// @{\n\n\t/// Returns x raised to the power of 2.\n\t///\n\t/// @see gtx_optimum_pow\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType pow2(genType const& x);\n\n\t/// Returns x raised to the power of 3.\n\t///\n\t/// @see gtx_optimum_pow\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType pow3(genType const& x);\n\n\t/// Returns x raised to the power of 4.\n\t///\n\t/// @see gtx_optimum_pow\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType pow4(genType const& x);\n\n\t/// @}\n}//namespace gtx\n}//namespace glm\n\n#include \"optimum_pow.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/optimum_pow.inl",
    "content": "/// @ref gtx_optimum_pow\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType pow2(genType const& x)\n\t{\n\t\treturn x * x;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType pow3(genType const& x)\n\t{\n\t\treturn x * x * x;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType pow4(genType const& x)\n\t{\n\t\treturn (x * x) * (x * x);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/orthonormalize.hpp",
    "content": "/// @ref gtx_orthonormalize\n/// @file glm/gtx/orthonormalize.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_orthonormalize GLM_GTX_orthonormalize\n/// @ingroup gtx\n///\n/// Include <glm/gtx/orthonormalize.hpp> to use the features of this extension.\n///\n/// Orthonormalize matrices.\n\n#pragma once\n\n// Dependency:\n#include \"../vec3.hpp\"\n#include \"../mat3x3.hpp\"\n#include \"../geometric.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_orthonormalize is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_orthonormalize extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_orthonormalize\n\t/// @{\n\n\t/// Returns the orthonormalized matrix of m.\n\t///\n\t/// @see gtx_orthonormalize\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m);\n\n\t/// Orthonormalizes x according y.\n\t///\n\t/// @see gtx_orthonormalize\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y);\n\n\t/// @}\n}//namespace glm\n\n#include \"orthonormalize.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/orthonormalize.inl",
    "content": "/// @ref gtx_orthonormalize\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> orthonormalize(mat<3, 3, T, Q> const& m)\n\t{\n\t\tmat<3, 3, T, Q> r = m;\n\n\t\tr[0] = normalize(r[0]);\n\n\t\tT d0 = dot(r[0], r[1]);\n\t\tr[1] -= r[0] * d0;\n\t\tr[1] = normalize(r[1]);\n\n\t\tT d1 = dot(r[1], r[2]);\n\t\td0 = dot(r[0], r[2]);\n\t\tr[2] -= r[0] * d0 + r[1] * d1;\n\t\tr[2] = normalize(r[2]);\n\n\t\treturn r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> orthonormalize(vec<3, T, Q> const& x, vec<3, T, Q> const& y)\n\t{\n\t\treturn normalize(x - y * dot(y, x));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/perpendicular.hpp",
    "content": "/// @ref gtx_perpendicular\n/// @file glm/gtx/perpendicular.hpp\n///\n/// @see core (dependence)\n/// @see gtx_projection (dependence)\n///\n/// @defgroup gtx_perpendicular GLM_GTX_perpendicular\n/// @ingroup gtx\n///\n/// Include <glm/gtx/perpendicular.hpp> to use the features of this extension.\n///\n/// Perpendicular of a vector from other one\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtx/projection.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_perpendicular is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_perpendicular extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_perpendicular\n\t/// @{\n\n\t//! Projects x a perpendicular axis of Normal.\n\t//! From GLM_GTX_perpendicular extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType perp(genType const& x, genType const& Normal);\n\n\t/// @}\n}//namespace glm\n\n#include \"perpendicular.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/perpendicular.inl",
    "content": "/// @ref gtx_perpendicular\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType perp(genType const& x, genType const& Normal)\n\t{\n\t\treturn x - proj(x, Normal);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/polar_coordinates.hpp",
    "content": "/// @ref gtx_polar_coordinates\n/// @file glm/gtx/polar_coordinates.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_polar_coordinates GLM_GTX_polar_coordinates\n/// @ingroup gtx\n///\n/// Include <glm/gtx/polar_coordinates.hpp> to use the features of this extension.\n///\n/// Conversion from Euclidean space to polar space and revert.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_polar_coordinates is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_polar_coordinates extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_polar_coordinates\n\t/// @{\n\n\t/// Convert Euclidean to Polar coordinates, x is the latitude, y the longitude and z the xz distance.\n\t///\n\t/// @see gtx_polar_coordinates\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> polar(\n\t\tvec<3, T, Q> const& euclidean);\n\n\t/// Convert Polar to Euclidean coordinates.\n\t///\n\t/// @see gtx_polar_coordinates\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> euclidean(\n\t\tvec<2, T, Q> const& polar);\n\n\t/// @}\n}//namespace glm\n\n#include \"polar_coordinates.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/polar_coordinates.inl",
    "content": "/// @ref gtx_polar_coordinates\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> polar\n\t(\n\t\tvec<3, T, Q> const& euclidean\n\t)\n\t{\n\t\tT const Length(length(euclidean));\n\t\tvec<3, T, Q> const tmp(euclidean / Length);\n\t\tT const xz_dist(sqrt(tmp.x * tmp.x + tmp.z * tmp.z));\n\n\t\treturn vec<3, T, Q>(\n\t\t\tasin(tmp.y),\t// latitude\n\t\t\tatan(tmp.x, tmp.z),\t\t// longitude\n\t\t\txz_dist);\t\t\t\t// xz distance\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> euclidean\n\t(\n\t\tvec<2, T, Q> const& polar\n\t)\n\t{\n\t\tT const latitude(polar.x);\n\t\tT const longitude(polar.y);\n\n\t\treturn vec<3, T, Q>(\n\t\t\tcos(latitude) * sin(longitude),\n\t\t\tsin(latitude),\n\t\t\tcos(latitude) * cos(longitude));\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/projection.hpp",
    "content": "/// @ref gtx_projection\n/// @file glm/gtx/projection.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_projection GLM_GTX_projection\n/// @ingroup gtx\n///\n/// Include <glm/gtx/projection.hpp> to use the features of this extension.\n///\n/// Projection of a vector to other one\n\n#pragma once\n\n// Dependency:\n#include \"../geometric.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_projection is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_projection extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_projection\n\t/// @{\n\n\t/// Projects x on Normal.\n\t///\n\t/// @param[in] x A vector to project\n\t/// @param[in] Normal A normal that doesn't need to be of unit length.\n\t///\n\t/// @see gtx_projection\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType proj(genType const& x, genType const& Normal);\n\n\t/// @}\n}//namespace glm\n\n#include \"projection.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/projection.inl",
    "content": "/// @ref gtx_projection\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType proj(genType const& x, genType const& Normal)\n\t{\n\t\treturn glm::dot(x, Normal) / glm::dot(Normal, Normal) * Normal;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/quaternion.hpp",
    "content": "/// @ref gtx_quaternion\n/// @file glm/gtx/quaternion.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_quaternion GLM_GTX_quaternion\n/// @ingroup gtx\n///\n/// Include <glm/gtx/quaternion.hpp> to use the features of this extension.\n///\n/// Extented quaternion types and functions\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/constants.hpp\"\n#include \"../gtc/quaternion.hpp\"\n#include \"../ext/quaternion_exponential.hpp\"\n#include \"../gtx/norm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_quaternion is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_quaternion extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_quaternion\n\t/// @{\n\n\t/// Create an identity quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR qua<T, Q> quat_identity();\n\n\t/// Compute a cross product between a quaternion and a vector.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> cross(\n\t\tqua<T, Q> const& q,\n\t\tvec<3, T, Q> const& v);\n\n\t//! Compute a cross product between a vector and a quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> cross(\n\t\tvec<3, T, Q> const& v,\n\t\tqua<T, Q> const& q);\n\n\t//! Compute a point on a path according squad equation.\n\t//! q1 and q2 are control points; s1 and s2 are intermediate control points.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> squad(\n\t\tqua<T, Q> const& q1,\n\t\tqua<T, Q> const& q2,\n\t\tqua<T, Q> const& s1,\n\t\tqua<T, Q> const& s2,\n\t\tT const& h);\n\n\t//! Returns an intermediate control point for squad interpolation.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> intermediate(\n\t\tqua<T, Q> const& prev,\n\t\tqua<T, Q> const& curr,\n\t\tqua<T, Q> const& next);\n\n\t//! Returns quarternion square root.\n\t///\n\t/// @see gtx_quaternion\n\t//template<typename T, qualifier Q>\n\t//qua<T, Q> sqrt(\n\t//\tqua<T, Q> const& q);\n\n\t//! Rotates a 3 components vector by a quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rotate(\n\t\tqua<T, Q> const& q,\n\t\tvec<3, T, Q> const& v);\n\n\t/// Rotates a 4 components vector by a quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> rotate(\n\t\tqua<T, Q> const& q,\n\t\tvec<4, T, Q> const& v);\n\n\t/// Extract the real component of a quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T extractRealComponent(\n\t\tqua<T, Q> const& q);\n\n\t/// Converts a quaternion to a 3 * 3 matrix.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> toMat3(\n\t\tqua<T, Q> const& x){return mat3_cast(x);}\n\n\t/// Converts a quaternion to a 4 * 4 matrix.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> toMat4(\n\t\tqua<T, Q> const& x){return mat4_cast(x);}\n\n\t/// Converts a 3 * 3 matrix to a quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> toQuat(\n\t\tmat<3, 3, T, Q> const& x){return quat_cast(x);}\n\n\t/// Converts a 4 * 4 matrix to a quaternion.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> toQuat(\n\t\tmat<4, 4, T, Q> const& x){return quat_cast(x);}\n\n\t/// Quaternion interpolation using the rotation short path.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> shortMix(\n\t\tqua<T, Q> const& x,\n\t\tqua<T, Q> const& y,\n\t\tT const& a);\n\n\t/// Quaternion normalized linear interpolation.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> fastMix(\n\t\tqua<T, Q> const& x,\n\t\tqua<T, Q> const& y,\n\t\tT const& a);\n\n\t/// Compute the rotation between two vectors.\n\t/// @param orig vector, needs to be normalized\n\t/// @param dest vector, needs to be normalized\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> rotation(\n\t\tvec<3, T, Q> const& orig,\n\t\tvec<3, T, Q> const& dest);\n\n\t/// Returns the squared length of x.\n\t///\n\t/// @see gtx_quaternion\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR T length2(qua<T, Q> const& q);\n\n\t/// @}\n}//namespace glm\n\n#include \"quaternion.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/quaternion.inl",
    "content": "/// @ref gtx_quaternion\n\n#include <limits>\n#include \"../gtc/constants.hpp\"\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR qua<T, Q> quat_identity()\n\t{\n\t\treturn qua<T, Q>(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> cross(vec<3, T, Q> const& v, qua<T, Q> const& q)\n\t{\n\t\treturn inverse(q) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> cross(qua<T, Q> const& q, vec<3, T, Q> const& v)\n\t{\n\t\treturn q * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> squad\n\t(\n\t\tqua<T, Q> const& q1,\n\t\tqua<T, Q> const& q2,\n\t\tqua<T, Q> const& s1,\n\t\tqua<T, Q> const& s2,\n\t\tT const& h)\n\t{\n\t\treturn mix(mix(q1, q2, h), mix(s1, s2, h), static_cast<T>(2) * (static_cast<T>(1) - h) * h);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> intermediate\n\t(\n\t\tqua<T, Q> const& prev,\n\t\tqua<T, Q> const& curr,\n\t\tqua<T, Q> const& next\n\t)\n\t{\n\t\tqua<T, Q> invQuat = inverse(curr);\n\t\treturn exp((log(next * invQuat) + log(prev * invQuat)) / static_cast<T>(-4)) * curr;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rotate(qua<T, Q> const& q, vec<3, T, Q> const& v)\n\t{\n\t\treturn q * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> rotate(qua<T, Q> const& q, vec<4, T, Q> const& v)\n\t{\n\t\treturn q * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T extractRealComponent(qua<T, Q> const& q)\n\t{\n\t\tT w = static_cast<T>(1) - q.x * q.x - q.y * q.y - q.z * q.z;\n\t\tif(w < T(0))\n\t\t\treturn T(0);\n\t\telse\n\t\t\treturn -sqrt(w);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER GLM_CONSTEXPR T length2(qua<T, Q> const& q)\n\t{\n\t\treturn q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> shortMix(qua<T, Q> const& x, qua<T, Q> const& y, T const& a)\n\t{\n\t\tif(a <= static_cast<T>(0)) return x;\n\t\tif(a >= static_cast<T>(1)) return y;\n\n\t\tT fCos = dot(x, y);\n\t\tqua<T, Q> y2(y); //BUG!!! qua<T> y2;\n\t\tif(fCos < static_cast<T>(0))\n\t\t{\n\t\t\ty2 = -y;\n\t\t\tfCos = -fCos;\n\t\t}\n\n\t\t//if(fCos > 1.0f) // problem\n\t\tT k0, k1;\n\t\tif(fCos > (static_cast<T>(1) - epsilon<T>()))\n\t\t{\n\t\t\tk0 = static_cast<T>(1) - a;\n\t\t\tk1 = static_cast<T>(0) + a; //BUG!!! 1.0f + a;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tT fSin = sqrt(T(1) - fCos * fCos);\n\t\t\tT fAngle = atan(fSin, fCos);\n\t\t\tT fOneOverSin = static_cast<T>(1) / fSin;\n\t\t\tk0 = sin((static_cast<T>(1) - a) * fAngle) * fOneOverSin;\n\t\t\tk1 = sin((static_cast<T>(0) + a) * fAngle) * fOneOverSin;\n\t\t}\n\n\t\treturn qua<T, Q>(\n\t\t\tk0 * x.w + k1 * y2.w,\n\t\t\tk0 * x.x + k1 * y2.x,\n\t\t\tk0 * x.y + k1 * y2.y,\n\t\t\tk0 * x.z + k1 * y2.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> fastMix(qua<T, Q> const& x, qua<T, Q> const& y, T const& a)\n\t{\n\t\treturn glm::normalize(x * (static_cast<T>(1) - a) + (y * a));\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> rotation(vec<3, T, Q> const& orig, vec<3, T, Q> const& dest)\n\t{\n\t\tT cosTheta = dot(orig, dest);\n\t\tvec<3, T, Q> rotationAxis;\n\n\t\tif(cosTheta >= static_cast<T>(1) - epsilon<T>()) {\n\t\t\t// orig and dest point in the same direction\n\t\t\treturn quat_identity<T,Q>();\n\t\t}\n\n\t\tif(cosTheta < static_cast<T>(-1) + epsilon<T>())\n\t\t{\n\t\t\t// special case when vectors in opposite directions :\n\t\t\t// there is no \"ideal\" rotation axis\n\t\t\t// So guess one; any will do as long as it's perpendicular to start\n\t\t\t// This implementation favors a rotation around the Up axis (Y),\n\t\t\t// since it's often what you want to do.\n\t\t\trotationAxis = cross(vec<3, T, Q>(0, 0, 1), orig);\n\t\t\tif(length2(rotationAxis) < epsilon<T>()) // bad luck, they were parallel, try again!\n\t\t\t\trotationAxis = cross(vec<3, T, Q>(1, 0, 0), orig);\n\n\t\t\trotationAxis = normalize(rotationAxis);\n\t\t\treturn angleAxis(pi<T>(), rotationAxis);\n\t\t}\n\n\t\t// Implementation from Stan Melax's Game Programming Gems 1 article\n\t\trotationAxis = cross(orig, dest);\n\n\t\tT s = sqrt((T(1) + cosTheta) * static_cast<T>(2));\n\t\tT invs = static_cast<T>(1) / s;\n\n\t\treturn qua<T, Q>(\n\t\t\ts * static_cast<T>(0.5f),\n\t\t\trotationAxis.x * invs,\n\t\t\trotationAxis.y * invs,\n\t\t\trotationAxis.z * invs);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/range.hpp",
    "content": "/// @ref gtx_range\n/// @file glm/gtx/range.hpp\n/// @author Joshua Moerman\n///\n/// @defgroup gtx_range GLM_GTX_range\n/// @ingroup gtx\n///\n/// Include <glm/gtx/range.hpp> to use the features of this extension.\n///\n/// Defines begin and end for vectors and matrices. Useful for range-based for loop.\n/// The range is defined over the elements, not over columns or rows (e.g. mat4 has 16 elements).\n\n#pragma once\n\n// Dependencies\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_range is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_range extension included\")\n#\tendif\n#endif\n\n#include \"../gtc/type_ptr.hpp\"\n#include \"../gtc/vec1.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup gtx_range\n\t/// @{\n\n#\tif GLM_COMPILER & GLM_COMPILER_VC\n#\t\tpragma warning(push)\n#\t\tpragma warning(disable : 4100) // unreferenced formal parameter\n#\tendif\n\n\ttemplate<typename T, qualifier Q>\n\tinline length_t components(vec<1, T, Q> const& v)\n\t{\n\t\treturn v.length();\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tinline length_t components(vec<2, T, Q> const& v)\n\t{\n\t\treturn v.length();\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tinline length_t components(vec<3, T, Q> const& v)\n\t{\n\t\treturn v.length();\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tinline length_t components(vec<4, T, Q> const& v)\n\t{\n\t\treturn v.length();\n\t}\n\n\ttemplate<typename genType>\n\tinline length_t components(genType const& m)\n\t{\n\t\treturn m.length() * m[0].length();\n\t}\n\n\ttemplate<typename genType>\n\tinline typename genType::value_type const * begin(genType const& v)\n\t{\n\t\treturn value_ptr(v);\n\t}\n\n\ttemplate<typename genType>\n\tinline typename genType::value_type const * end(genType const& v)\n\t{\n\t\treturn begin(v) + components(v);\n\t}\n\n\ttemplate<typename genType>\n\tinline typename genType::value_type * begin(genType& v)\n\t{\n\t\treturn value_ptr(v);\n\t}\n\n\ttemplate<typename genType>\n\tinline typename genType::value_type * end(genType& v)\n\t{\n\t\treturn begin(v) + components(v);\n\t}\n\n#\tif GLM_COMPILER & GLM_COMPILER_VC\n#\t\tpragma warning(pop)\n#\tendif\n\n\t/// @}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/raw_data.hpp",
    "content": "/// @ref gtx_raw_data\n/// @file glm/gtx/raw_data.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_raw_data GLM_GTX_raw_data\n/// @ingroup gtx\n///\n/// Include <glm/gtx/raw_data.hpp> to use the features of this extension.\n///\n/// Projection of a vector to other one\n\n#pragma once\n\n// Dependencies\n#include \"../ext/scalar_uint_sized.hpp\"\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_raw_data is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_raw_data extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_raw_data\n\t/// @{\n\n\t//! Type for byte numbers.\n\t//! From GLM_GTX_raw_data extension.\n\ttypedef detail::uint8\t\tbyte;\n\n\t//! Type for word numbers.\n\t//! From GLM_GTX_raw_data extension.\n\ttypedef detail::uint16\t\tword;\n\n\t//! Type for dword numbers.\n\t//! From GLM_GTX_raw_data extension.\n\ttypedef detail::uint32\t\tdword;\n\n\t//! Type for qword numbers.\n\t//! From GLM_GTX_raw_data extension.\n\ttypedef detail::uint64\t\tqword;\n\n\t/// @}\n}// namespace glm\n\n#include \"raw_data.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/raw_data.inl",
    "content": "/// @ref gtx_raw_data\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/rotate_normalized_axis.hpp",
    "content": "/// @ref gtx_rotate_normalized_axis\n/// @file glm/gtx/rotate_normalized_axis.hpp\n///\n/// @see core (dependence)\n/// @see gtc_matrix_transform\n/// @see gtc_quaternion\n///\n/// @defgroup gtx_rotate_normalized_axis GLM_GTX_rotate_normalized_axis\n/// @ingroup gtx\n///\n/// Include <glm/gtx/rotate_normalized_axis.hpp> to use the features of this extension.\n///\n/// Quaternions and matrices rotations around normalized axis.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/epsilon.hpp\"\n#include \"../gtc/quaternion.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_rotate_normalized_axis is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_rotate_normalized_axis extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_rotate_normalized_axis\n\t/// @{\n\n\t/// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle.\n\t///\n\t/// @param m Input matrix multiplied by this rotation matrix.\n\t/// @param angle Rotation angle expressed in radians.\n\t/// @param axis Rotation axis, must be normalized.\n\t/// @tparam T Value type used to build the matrix. Currently supported: half (not recommended), float or double.\n\t///\n\t/// @see gtx_rotate_normalized_axis\n\t/// @see - rotate(T angle, T x, T y, T z)\n\t/// @see - rotate(mat<4, 4, T, Q> const& m, T angle, T x, T y, T z)\n\t/// @see - rotate(T angle, vec<3, T, Q> const& v)\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> rotateNormalizedAxis(\n\t\tmat<4, 4, T, Q> const& m,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& axis);\n\n\t/// Rotates a quaternion from a vector of 3 components normalized axis and an angle.\n\t///\n\t/// @param q Source orientation\n\t/// @param angle Angle expressed in radians.\n\t/// @param axis Normalized axis of the rotation, must be normalized.\n\t///\n\t/// @see gtx_rotate_normalized_axis\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL qua<T, Q> rotateNormalizedAxis(\n\t\tqua<T, Q> const& q,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& axis);\n\n\t/// @}\n}//namespace glm\n\n#include \"rotate_normalized_axis.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/rotate_normalized_axis.inl",
    "content": "/// @ref gtx_rotate_normalized_axis\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotateNormalizedAxis\n\t(\n\t\tmat<4, 4, T, Q> const& m,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& v\n\t)\n\t{\n\t\tT const a = angle;\n\t\tT const c = cos(a);\n\t\tT const s = sin(a);\n\n\t\tvec<3, T, Q> const axis(v);\n\n\t\tvec<3, T, Q> const temp((static_cast<T>(1) - c) * axis);\n\n\t\tmat<4, 4, T, Q> Rotate;\n\t\tRotate[0][0] = c + temp[0] * axis[0];\n\t\tRotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];\n\t\tRotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];\n\n\t\tRotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];\n\t\tRotate[1][1] = c + temp[1] * axis[1];\n\t\tRotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];\n\n\t\tRotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];\n\t\tRotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];\n\t\tRotate[2][2] = c + temp[2] * axis[2];\n\n\t\tmat<4, 4, T, Q> Result;\n\t\tResult[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];\n\t\tResult[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];\n\t\tResult[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];\n\t\tResult[3] = m[3];\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER qua<T, Q> rotateNormalizedAxis\n\t(\n\t\tqua<T, Q> const& q,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& v\n\t)\n\t{\n\t\tvec<3, T, Q> const Tmp(v);\n\n\t\tT const AngleRad(angle);\n\t\tT const Sin = sin(AngleRad * T(0.5));\n\n\t\treturn q * qua<T, Q>(cos(AngleRad * static_cast<T>(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin);\n\t\t//return gtc::quaternion::cross(q, tquat<T, Q>(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/rotate_vector.hpp",
    "content": "/// @ref gtx_rotate_vector\n/// @file glm/gtx/rotate_vector.hpp\n///\n/// @see core (dependence)\n/// @see gtx_transform (dependence)\n///\n/// @defgroup gtx_rotate_vector GLM_GTX_rotate_vector\n/// @ingroup gtx\n///\n/// Include <glm/gtx/rotate_vector.hpp> to use the features of this extension.\n///\n/// Function to directly rotate a vector\n\n#pragma once\n\n// Dependency:\n#include \"../gtx/transform.hpp\"\n#include \"../gtc/epsilon.hpp\"\n#include \"../ext/vector_relational.hpp\"\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_rotate_vector is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_rotate_vector extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_rotate_vector\n\t/// @{\n\n\t/// Returns Spherical interpolation between two vectors\n\t///\n\t/// @param x A first vector\n\t/// @param y A second vector\n\t/// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].\n\t///\n\t/// @see gtx_rotate_vector\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> slerp(\n\t\tvec<3, T, Q> const& x,\n\t\tvec<3, T, Q> const& y,\n\t\tT const& a);\n\n\t//! Rotate a two dimensional vector.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<2, T, Q> rotate(\n\t\tvec<2, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Rotate a three dimensional vector around an axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rotate(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& normal);\n\n\t//! Rotate a four dimensional vector around an axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> rotate(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& normal);\n\n\t//! Rotate a three dimensional vector around the X axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rotateX(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Rotate a three dimensional vector around the Y axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rotateY(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Rotate a three dimensional vector around the Z axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<3, T, Q> rotateZ(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Rotate a four dimensional vector around the X axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> rotateX(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Rotate a four dimensional vector around the Y axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> rotateY(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Rotate a four dimensional vector around the Z axis.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<4, T, Q> rotateZ(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle);\n\n\t//! Build a rotation matrix from a normal and a up vector.\n\t//! From GLM_GTX_rotate_vector extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> orientation(\n\t\tvec<3, T, Q> const& Normal,\n\t\tvec<3, T, Q> const& Up);\n\n\t/// @}\n}//namespace glm\n\n#include \"rotate_vector.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/rotate_vector.inl",
    "content": "/// @ref gtx_rotate_vector\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> slerp\n\t(\n\t\tvec<3, T, Q> const& x,\n\t\tvec<3, T, Q> const& y,\n\t\tT const& a\n\t)\n\t{\n\t\t// get cosine of angle between vectors (-1 -> 1)\n\t\tT CosAlpha = dot(x, y);\n\t\t// get angle (0 -> pi)\n\t\tT Alpha = acos(CosAlpha);\n\t\t// get sine of angle between vectors (0 -> 1)\n\t\tT SinAlpha = sin(Alpha);\n\t\t// this breaks down when SinAlpha = 0, i.e. Alpha = 0 or pi\n\t\tT t1 = sin((static_cast<T>(1) - a) * Alpha) / SinAlpha;\n\t\tT t2 = sin(a * Alpha) / SinAlpha;\n\n\t\t// interpolate src vectors\n\t\treturn x * t1 + y * t2;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, T, Q> rotate\n\t(\n\t\tvec<2, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<2, T, Q> Result;\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.x = v.x * Cos - v.y * Sin;\n\t\tResult.y = v.x * Sin + v.y * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rotate\n\t(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& normal\n\t)\n\t{\n\t\treturn mat<3, 3, T, Q>(glm::rotate(angle, normal)) * v;\n\t}\n\t/*\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rotateGTX(\n\t\tconst vec<3, T, Q>& x,\n\t\tT angle,\n\t\tconst vec<3, T, Q>& normal)\n\t{\n\t\tconst T Cos = cos(radians(angle));\n\t\tconst T Sin = sin(radians(angle));\n\t\treturn x * Cos + ((x * normal) * (T(1) - Cos)) * normal + cross(x, normal) * Sin;\n\t}\n\t*/\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> rotate\n\t(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle,\n\t\tvec<3, T, Q> const& normal\n\t)\n\t{\n\t\treturn rotate(angle, normal) * v;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rotateX\n\t(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<3, T, Q> Result(v);\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.y = v.y * Cos - v.z * Sin;\n\t\tResult.z = v.y * Sin + v.z * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rotateY\n\t(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<3, T, Q> Result = v;\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.x =  v.x * Cos + v.z * Sin;\n\t\tResult.z = -v.x * Sin + v.z * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, T, Q> rotateZ\n\t(\n\t\tvec<3, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<3, T, Q> Result = v;\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.x = v.x * Cos - v.y * Sin;\n\t\tResult.y = v.x * Sin + v.y * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> rotateX\n\t(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<4, T, Q> Result = v;\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.y = v.y * Cos - v.z * Sin;\n\t\tResult.z = v.y * Sin + v.z * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> rotateY\n\t(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<4, T, Q> Result = v;\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.x =  v.x * Cos + v.z * Sin;\n\t\tResult.z = -v.x * Sin + v.z * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, T, Q> rotateZ\n\t(\n\t\tvec<4, T, Q> const& v,\n\t\tT const& angle\n\t)\n\t{\n\t\tvec<4, T, Q> Result = v;\n\t\tT const Cos(cos(angle));\n\t\tT const Sin(sin(angle));\n\n\t\tResult.x = v.x * Cos - v.y * Sin;\n\t\tResult.y = v.x * Sin + v.y * Cos;\n\t\treturn Result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> orientation\n\t(\n\t\tvec<3, T, Q> const& Normal,\n\t\tvec<3, T, Q> const& Up\n\t)\n\t{\n\t\tif(all(equal(Normal, Up, epsilon<T>())))\n\t\t\treturn mat<4, 4, T, Q>(static_cast<T>(1));\n\n\t\tvec<3, T, Q> RotationAxis = cross(Up, Normal);\n\t\tT Angle = acos(dot(Normal, Up));\n\n\t\treturn rotate(Angle, RotationAxis);\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/scalar_multiplication.hpp",
    "content": "/// @ref gtx\n/// @file glm/gtx/scalar_multiplication.hpp\n/// @author Joshua Moerman\n///\n/// Include <glm/gtx/scalar_multiplication.hpp> to use the features of this extension.\n///\n/// Enables scalar multiplication for all types\n///\n/// Since GLSL is very strict about types, the following (often used) combinations do not work:\n///    double * vec4\n///    int * vec4\n///    vec4 / int\n/// So we'll fix that! Of course \"float * vec4\" should remain the same (hence the enable_if magic)\n\n#pragma once\n\n#include \"../detail/setup.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_scalar_multiplication is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_scalar_multiplication extension included\")\n#\tendif\n#endif\n\n#include \"../vec2.hpp\"\n#include \"../vec3.hpp\"\n#include \"../vec4.hpp\"\n#include \"../mat2x2.hpp\"\n#include <type_traits>\n\nnamespace glm\n{\n\ttemplate<typename T, typename Vec>\n\tusing return_type_scalar_multiplication = typename std::enable_if<\n\t\t!std::is_same<T, float>::value       // T may not be a float\n\t\t&& std::is_arithmetic<T>::value, Vec // But it may be an int or double (no vec3 or mat3, ...)\n\t>::type;\n\n#define GLM_IMPLEMENT_SCAL_MULT(Vec) \\\n\ttemplate<typename T> \\\n\treturn_type_scalar_multiplication<T, Vec> \\\n\toperator*(T const& s, Vec rh){ \\\n\t\treturn rh *= static_cast<float>(s); \\\n\t} \\\n\t \\\n\ttemplate<typename T> \\\n\treturn_type_scalar_multiplication<T, Vec> \\\n\toperator*(Vec lh, T const& s){ \\\n\t\treturn lh *= static_cast<float>(s); \\\n\t} \\\n\t \\\n\ttemplate<typename T> \\\n\treturn_type_scalar_multiplication<T, Vec> \\\n\toperator/(Vec lh, T const& s){ \\\n\t\treturn lh *= 1.0f / static_cast<float>(s); \\\n\t}\n\nGLM_IMPLEMENT_SCAL_MULT(vec2)\nGLM_IMPLEMENT_SCAL_MULT(vec3)\nGLM_IMPLEMENT_SCAL_MULT(vec4)\n\nGLM_IMPLEMENT_SCAL_MULT(mat2)\nGLM_IMPLEMENT_SCAL_MULT(mat2x3)\nGLM_IMPLEMENT_SCAL_MULT(mat2x4)\nGLM_IMPLEMENT_SCAL_MULT(mat3x2)\nGLM_IMPLEMENT_SCAL_MULT(mat3)\nGLM_IMPLEMENT_SCAL_MULT(mat3x4)\nGLM_IMPLEMENT_SCAL_MULT(mat4x2)\nGLM_IMPLEMENT_SCAL_MULT(mat4x3)\nGLM_IMPLEMENT_SCAL_MULT(mat4)\n\n#undef GLM_IMPLEMENT_SCAL_MULT\n} // namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/scalar_relational.hpp",
    "content": "/// @ref gtx_scalar_relational\n/// @file glm/gtx/scalar_relational.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_scalar_relational GLM_GTX_scalar_relational\n/// @ingroup gtx\n///\n/// Include <glm/gtx/scalar_relational.hpp> to use the features of this extension.\n///\n/// Extend a position from a source to a position at a defined length.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_extend is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_extend extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_scalar_relational\n\t/// @{\n\n\n\n\t/// @}\n}//namespace glm\n\n#include \"scalar_relational.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/scalar_relational.inl",
    "content": "/// @ref gtx_scalar_relational\n\nnamespace glm\n{\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool lessThan\n\t(\n\t\tT const& x,\n\t\tT const& y\n\t)\n\t{\n\t\treturn x < y;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool lessThanEqual\n\t(\n\t\tT const& x,\n\t\tT const& y\n\t)\n\t{\n\t\treturn x <= y;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool greaterThan\n\t(\n\t\tT const& x,\n\t\tT const& y\n\t)\n\t{\n\t\treturn x > y;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool greaterThanEqual\n\t(\n\t\tT const& x,\n\t\tT const& y\n\t)\n\t{\n\t\treturn x >= y;\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool equal\n\t(\n\t\tT const& x,\n\t\tT const& y\n\t)\n\t{\n\t\treturn detail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(x, y);\n\t}\n\n\ttemplate<typename T>\n\tGLM_FUNC_QUALIFIER bool notEqual\n\t(\n\t\tT const& x,\n\t\tT const& y\n\t)\n\t{\n\t\treturn !detail::compute_equal<T, std::numeric_limits<T>::is_iec559>::call(x, y);\n\t}\n\n\tGLM_FUNC_QUALIFIER bool any\n\t(\n\t\tbool const& x\n\t)\n\t{\n\t\treturn x;\n\t}\n\n\tGLM_FUNC_QUALIFIER bool all\n\t(\n\t\tbool const& x\n\t)\n\t{\n\t\treturn x;\n\t}\n\n\tGLM_FUNC_QUALIFIER bool not_\n\t(\n\t\tbool const& x\n\t)\n\t{\n\t\treturn !x;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/spline.hpp",
    "content": "/// @ref gtx_spline\n/// @file glm/gtx/spline.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_spline GLM_GTX_spline\n/// @ingroup gtx\n///\n/// Include <glm/gtx/spline.hpp> to use the features of this extension.\n///\n/// Spline functions\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtx/optimum_pow.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_spline is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_spline extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_spline\n\t/// @{\n\n\t/// Return a point from a catmull rom curve.\n\t/// @see gtx_spline extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType catmullRom(\n\t\tgenType const& v1,\n\t\tgenType const& v2,\n\t\tgenType const& v3,\n\t\tgenType const& v4,\n\t\ttypename genType::value_type const& s);\n\n\t/// Return a point from a hermite curve.\n\t/// @see gtx_spline extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType hermite(\n\t\tgenType const& v1,\n\t\tgenType const& t1,\n\t\tgenType const& v2,\n\t\tgenType const& t2,\n\t\ttypename genType::value_type const& s);\n\n\t/// Return a point from a cubic curve.\n\t/// @see gtx_spline extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL genType cubic(\n\t\tgenType const& v1,\n\t\tgenType const& v2,\n\t\tgenType const& v3,\n\t\tgenType const& v4,\n\t\ttypename genType::value_type const& s);\n\n\t/// @}\n}//namespace glm\n\n#include \"spline.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/spline.inl",
    "content": "/// @ref gtx_spline\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType catmullRom\n\t(\n\t\tgenType const& v1,\n\t\tgenType const& v2,\n\t\tgenType const& v3,\n\t\tgenType const& v4,\n\t\ttypename genType::value_type const& s\n\t)\n\t{\n\t\ttypename genType::value_type s2 = pow2(s);\n\t\ttypename genType::value_type s3 = pow3(s);\n\n\t\ttypename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s;\n\t\ttypename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2);\n\t\ttypename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s;\n\t\ttypename genType::value_type f4 = s3 - s2;\n\n\t\treturn (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2);\n\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType hermite\n\t(\n\t\tgenType const& v1,\n\t\tgenType const& t1,\n\t\tgenType const& v2,\n\t\tgenType const& t2,\n\t\ttypename genType::value_type const& s\n\t)\n\t{\n\t\ttypename genType::value_type s2 = pow2(s);\n\t\ttypename genType::value_type s3 = pow3(s);\n\n\t\ttypename genType::value_type f1 = typename genType::value_type(2) * s3 - typename genType::value_type(3) * s2 + typename genType::value_type(1);\n\t\ttypename genType::value_type f2 = typename genType::value_type(-2) * s3 + typename genType::value_type(3) * s2;\n\t\ttypename genType::value_type f3 = s3 - typename genType::value_type(2) * s2 + s;\n\t\ttypename genType::value_type f4 = s3 - s2;\n\n\t\treturn f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2;\n\t}\n\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType cubic\n\t(\n\t\tgenType const& v1,\n\t\tgenType const& v2,\n\t\tgenType const& v3,\n\t\tgenType const& v4,\n\t\ttypename genType::value_type const& s\n\t)\n\t{\n\t\treturn ((v1 * s + v2) * s + v3) * s + v4;\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/std_based_type.hpp",
    "content": "/// @ref gtx_std_based_type\n/// @file glm/gtx/std_based_type.hpp\n///\n/// @see core (dependence)\n/// @see gtx_extented_min_max (dependence)\n///\n/// @defgroup gtx_std_based_type GLM_GTX_std_based_type\n/// @ingroup gtx\n///\n/// Include <glm/gtx/std_based_type.hpp> to use the features of this extension.\n///\n/// Adds vector types based on STL value types.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include <cstdlib>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_std_based_type is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_std_based_type extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_std_based_type\n\t/// @{\n\n\t/// Vector type based of one std::size_t component.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<1, std::size_t, defaultp>\t\tsize1;\n\n\t/// Vector type based of two std::size_t components.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<2, std::size_t, defaultp>\t\tsize2;\n\n\t/// Vector type based of three std::size_t components.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<3, std::size_t, defaultp>\t\tsize3;\n\n\t/// Vector type based of four std::size_t components.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<4, std::size_t, defaultp>\t\tsize4;\n\n\t/// Vector type based of one std::size_t component.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<1, std::size_t, defaultp>\t\tsize1_t;\n\n\t/// Vector type based of two std::size_t components.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<2, std::size_t, defaultp>\t\tsize2_t;\n\n\t/// Vector type based of three std::size_t components.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<3, std::size_t, defaultp>\t\tsize3_t;\n\n\t/// Vector type based of four std::size_t components.\n\t/// @see GLM_GTX_std_based_type\n\ttypedef vec<4, std::size_t, defaultp>\t\tsize4_t;\n\n\t/// @}\n}//namespace glm\n\n#include \"std_based_type.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/std_based_type.inl",
    "content": "/// @ref gtx_std_based_type\n\nnamespace glm\n{\n\n}\n"
  },
  {
    "path": "lib/gli/glm/gtx/string_cast.hpp",
    "content": "/// @ref gtx_string_cast\n/// @file glm/gtx/string_cast.hpp\n///\n/// @see core (dependence)\n/// @see gtx_integer (dependence)\n/// @see gtx_quaternion (dependence)\n///\n/// @defgroup gtx_string_cast GLM_GTX_string_cast\n/// @ingroup gtx\n///\n/// Include <glm/gtx/string_cast.hpp> to use the features of this extension.\n///\n/// Setup strings for GLM type values\n///\n/// This extension is not supported with CUDA\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/type_precision.hpp\"\n#include \"../gtc/quaternion.hpp\"\n#include \"../gtx/dual_quaternion.hpp\"\n#include <string>\n#include <cmath>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_string_cast is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_string_cast extension included\")\n#\tendif\n#endif\n\n#if(GLM_COMPILER & GLM_COMPILER_CUDA)\n#\terror \"GLM_GTX_string_cast is not supported on CUDA compiler\"\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_string_cast\n\t/// @{\n\n\t/// Create a string from a GLM vector or matrix typed variable.\n\t/// @see gtx_string_cast extension.\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL std::string to_string(genType const& x);\n\n\t/// @}\n}//namespace glm\n\n#include \"string_cast.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/string_cast.inl",
    "content": "/// @ref gtx_string_cast\n\n#include <cstdarg>\n#include <cstdio>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate <typename T>\n\tstruct cast\n\t{\n\t\ttypedef T value_type;\n\t};\n\n\ttemplate <>\n\tstruct cast<float>\n\t{\n\t\ttypedef double value_type;\n\t};\n\n\tGLM_FUNC_QUALIFIER std::string format(const char* msg, ...)\n\t{\n\t\tstd::size_t const STRING_BUFFER(4096);\n\t\tchar text[STRING_BUFFER];\n\t\tva_list list;\n\n\t\tif(msg == GLM_NULLPTR)\n\t\t\treturn std::string();\n\n\t\tva_start(list, msg);\n#\t\tif (GLM_COMPILER & GLM_COMPILER_VC)\n\t\t\tvsprintf_s(text, STRING_BUFFER, msg, list);\n#\t\telse//\n\t\t\tstd::vsprintf(text, msg, list);\n#\t\tendif//\n\t\tva_end(list);\n\n\t\treturn std::string(text);\n\t}\n\n\tstatic const char* LabelTrue = \"true\";\n\tstatic const char* LabelFalse = \"false\";\n\n\ttemplate<typename T, bool isFloat = false>\n\tstruct literal\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"%d\";}\n\t};\n\n\ttemplate<typename T>\n\tstruct literal<T, true>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"%f\";}\n\t};\n\n#\tif GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC\n\ttemplate<>\n\tstruct literal<uint64_t, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"%lld\";}\n\t};\n\n\ttemplate<>\n\tstruct literal<int64_t, false>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"%lld\";}\n\t};\n#\tendif//GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC\n\n\ttemplate<typename T>\n\tstruct prefix{};\n\n\ttemplate<>\n\tstruct prefix<float>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<double>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"d\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<bool>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"b\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<uint8_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"u8\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<int8_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"i8\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<uint16_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"u16\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<int16_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"i16\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<uint32_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"u\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<int32_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"i\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<uint64_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"u64\";}\n\t};\n\n\ttemplate<>\n\tstruct prefix<int64_t>\n\t{\n\t\tGLM_FUNC_QUALIFIER static char const * value() {return \"i64\";}\n\t};\n\n\ttemplate<typename matType>\n\tstruct compute_to_string\n\t{};\n\n\ttemplate<qualifier Q>\n\tstruct compute_to_string<vec<1, bool, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<1, bool, Q> const& x)\n\t\t{\n\t\t\treturn detail::format(\"bvec1(%s)\",\n\t\t\t\tx[0] ? detail::LabelTrue : detail::LabelFalse);\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_to_string<vec<2, bool, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<2, bool, Q> const& x)\n\t\t{\n\t\t\treturn detail::format(\"bvec2(%s, %s)\",\n\t\t\t\tx[0] ? detail::LabelTrue : detail::LabelFalse,\n\t\t\t\tx[1] ? detail::LabelTrue : detail::LabelFalse);\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_to_string<vec<3, bool, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<3, bool, Q> const& x)\n\t\t{\n\t\t\treturn detail::format(\"bvec3(%s, %s, %s)\",\n\t\t\t\tx[0] ? detail::LabelTrue : detail::LabelFalse,\n\t\t\t\tx[1] ? detail::LabelTrue : detail::LabelFalse,\n\t\t\t\tx[2] ? detail::LabelTrue : detail::LabelFalse);\n\t\t}\n\t};\n\n\ttemplate<qualifier Q>\n\tstruct compute_to_string<vec<4, bool, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<4, bool, Q> const& x)\n\t\t{\n\t\t\treturn detail::format(\"bvec4(%s, %s, %s, %s)\",\n\t\t\t\tx[0] ? detail::LabelTrue : detail::LabelFalse,\n\t\t\t\tx[1] ? detail::LabelTrue : detail::LabelFalse,\n\t\t\t\tx[2] ? detail::LabelTrue : detail::LabelFalse,\n\t\t\t\tx[3] ? detail::LabelTrue : detail::LabelFalse);\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<vec<1, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<1, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%svec1(%s)\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<vec<2, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<2, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%svec2(%s, %s)\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<vec<3, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<3, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%svec3(%s, %s, %s)\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<vec<4, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(vec<4, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%svec4(%s, %s, %s, %s)\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[3]));\n\t\t}\n\t};\n\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<2, 2, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<2, 2, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat2x2((%s, %s), (%s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<2, 3, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<2, 3, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat2x3((%s, %s, %s), (%s, %s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]), static_cast<typename cast<T>::value_type>(x[0][2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]), static_cast<typename cast<T>::value_type>(x[1][2]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<2, 4, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<2, 4, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat2x4((%s, %s, %s, %s), (%s, %s, %s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]), static_cast<typename cast<T>::value_type>(x[0][2]), static_cast<typename cast<T>::value_type>(x[0][3]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]), static_cast<typename cast<T>::value_type>(x[1][2]), static_cast<typename cast<T>::value_type>(x[1][3]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<3, 2, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<3, 2, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat3x2((%s, %s), (%s, %s), (%s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2][0]), static_cast<typename cast<T>::value_type>(x[2][1]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<3, 3, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<3, 3, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat3x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]), static_cast<typename cast<T>::value_type>(x[0][2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]), static_cast<typename cast<T>::value_type>(x[1][2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2][0]), static_cast<typename cast<T>::value_type>(x[2][1]), static_cast<typename cast<T>::value_type>(x[2][2]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<3, 4, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<3, 4, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat3x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]), static_cast<typename cast<T>::value_type>(x[0][2]), static_cast<typename cast<T>::value_type>(x[0][3]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]), static_cast<typename cast<T>::value_type>(x[1][2]), static_cast<typename cast<T>::value_type>(x[1][3]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2][0]), static_cast<typename cast<T>::value_type>(x[2][1]), static_cast<typename cast<T>::value_type>(x[2][2]), static_cast<typename cast<T>::value_type>(x[2][3]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<4, 2, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<4, 2, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat4x2((%s, %s), (%s, %s), (%s, %s), (%s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2][0]), static_cast<typename cast<T>::value_type>(x[2][1]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[3][0]), static_cast<typename cast<T>::value_type>(x[3][1]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<4, 3, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<4, 3, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat4x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s), (%s, %s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]), static_cast<typename cast<T>::value_type>(x[0][2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]), static_cast<typename cast<T>::value_type>(x[1][2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2][0]), static_cast<typename cast<T>::value_type>(x[2][1]), static_cast<typename cast<T>::value_type>(x[2][2]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[3][0]), static_cast<typename cast<T>::value_type>(x[3][1]), static_cast<typename cast<T>::value_type>(x[3][2]));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<mat<4, 4, T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(mat<4, 4, T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%smat4x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[0][0]), static_cast<typename cast<T>::value_type>(x[0][1]), static_cast<typename cast<T>::value_type>(x[0][2]), static_cast<typename cast<T>::value_type>(x[0][3]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[1][0]), static_cast<typename cast<T>::value_type>(x[1][1]), static_cast<typename cast<T>::value_type>(x[1][2]), static_cast<typename cast<T>::value_type>(x[1][3]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[2][0]), static_cast<typename cast<T>::value_type>(x[2][1]), static_cast<typename cast<T>::value_type>(x[2][2]), static_cast<typename cast<T>::value_type>(x[2][3]),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x[3][0]), static_cast<typename cast<T>::value_type>(x[3][1]), static_cast<typename cast<T>::value_type>(x[3][2]), static_cast<typename cast<T>::value_type>(x[3][3]));\n\t\t}\n\t};\n\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<qua<T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(qua<T, Q> const& q)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%squat(%s, {%s, %s, %s})\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(q.w),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(q.x),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(q.y),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(q.z));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_to_string<tdualquat<T, Q> >\n\t{\n\t\tGLM_FUNC_QUALIFIER static std::string call(tdualquat<T, Q> const& x)\n\t\t{\n\t\t\tchar const * PrefixStr = prefix<T>::value();\n\t\t\tchar const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();\n\t\t\tstd::string FormatStr(detail::format(\"%sdualquat((%s, {%s, %s, %s}), (%s, {%s, %s, %s}))\",\n\t\t\t\tPrefixStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr,\n\t\t\t\tLiteralStr, LiteralStr, LiteralStr, LiteralStr));\n\n\t\t\treturn detail::format(FormatStr.c_str(),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.real.w),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.real.x),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.real.y),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.real.z),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.dual.w),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.dual.x),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.dual.y),\n\t\t\t\tstatic_cast<typename cast<T>::value_type>(x.dual.z));\n\t\t}\n\t};\n\n}//namespace detail\n\ntemplate<class matType>\nGLM_FUNC_QUALIFIER std::string to_string(matType const& x)\n{\n\treturn detail::compute_to_string<matType>::call(x);\n}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/texture.hpp",
    "content": "/// @ref gtx_texture\n/// @file glm/gtx/texture.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_texture GLM_GTX_texture\n/// @ingroup gtx\n///\n/// Include <glm/gtx/texture.hpp> to use the features of this extension.\n///\n/// Wrapping mode of texture coordinates.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/integer.hpp\"\n#include \"../gtx/component_wise.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_texture is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_texture extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_texture\n\t/// @{\n\n\t/// Compute the number of mipmaps levels necessary to create a mipmap complete texture\n\t///\n\t/// @param Extent Extent of the texture base level mipmap\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point or signed integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\ttemplate <length_t L, typename T, qualifier Q>\n\tT levels(vec<L, T, Q> const& Extent);\n\n\t/// @}\n}// namespace glm\n\n#include \"texture.inl\"\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/texture.inl",
    "content": "/// @ref gtx_texture\n\nnamespace glm\n{\n\ttemplate <length_t L, typename T, qualifier Q>\n\tinline T levels(vec<L, T, Q> const& Extent)\n\t{\n\t\treturn glm::log2(compMax(Extent)) + static_cast<T>(1);\n\t}\n\n\ttemplate <typename T>\n\tinline T levels(T Extent)\n\t{\n\t\treturn vec<1, T, defaultp>(Extent).x;\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/transform.hpp",
    "content": "/// @ref gtx_transform\n/// @file glm/gtx/transform.hpp\n///\n/// @see core (dependence)\n/// @see gtc_matrix_transform (dependence)\n/// @see gtx_transform\n/// @see gtx_transform2\n///\n/// @defgroup gtx_transform GLM_GTX_transform\n/// @ingroup gtx\n///\n/// Include <glm/gtx/transform.hpp> to use the features of this extension.\n///\n/// Add transformation matrices\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/matrix_transform.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_transform is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_transform extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_transform\n\t/// @{\n\n\t/// Transforms a matrix with a translation 4 * 4 matrix created from 3 scalars.\n\t/// @see gtc_matrix_transform\n\t/// @see gtx_transform\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> translate(\n\t\tvec<3, T, Q> const& v);\n\n\t/// Builds a rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians.\n\t/// @see gtc_matrix_transform\n\t/// @see gtx_transform\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> rotate(\n\t\tT angle,\n\t\tvec<3, T, Q> const& v);\n\n\t/// Transforms a matrix with a scale 4 * 4 matrix created from a vector of 3 components.\n\t/// @see gtc_matrix_transform\n\t/// @see gtx_transform\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> scale(\n\t\tvec<3, T, Q> const& v);\n\n\t/// @}\n}// namespace glm\n\n#include \"transform.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/transform.inl",
    "content": "/// @ref gtx_transform\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> translate(vec<3, T, Q> const& v)\n\t{\n\t\treturn translate(mat<4, 4, T, Q>(static_cast<T>(1)), v);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> rotate(T angle, vec<3, T, Q> const& v)\n\t{\n\t\treturn rotate(mat<4, 4, T, Q>(static_cast<T>(1)), angle, v);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> scale(vec<3, T, Q> const& v)\n\t{\n\t\treturn scale(mat<4, 4, T, Q>(static_cast<T>(1)), v);\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/transform2.hpp",
    "content": "/// @ref gtx_transform2\n/// @file glm/gtx/transform2.hpp\n///\n/// @see core (dependence)\n/// @see gtx_transform (dependence)\n///\n/// @defgroup gtx_transform2 GLM_GTX_transform2\n/// @ingroup gtx\n///\n/// Include <glm/gtx/transform2.hpp> to use the features of this extension.\n///\n/// Add extra transformation matrices\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtx/transform.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_transform2 is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_transform2 extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_transform2\n\t/// @{\n\n\t//! Transforms a matrix with a shearing on X axis.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T y);\n\n\t//! Transforms a matrix with a shearing on Y axis.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T x);\n\n\t//! Transforms a matrix with a shearing on X axis\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T y, T z);\n\n\t//! Transforms a matrix with a shearing on Y axis.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T x, T z);\n\n\t//! Transforms a matrix with a shearing on Z axis.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T x, T y);\n\n\t//template<typename T> GLM_FUNC_QUALIFIER mat<4, 4, T, Q> shear(const mat<4, 4, T, Q> & m, shearPlane, planePoint, angle)\n\t// Identity + tan(angle) * cross(Normal, OnPlaneVector)     0\n\t// - dot(PointOnPlane, normal) * OnPlaneVector              1\n\n\t// Reflect functions seem to don't work\n\t//template<typename T> mat<3, 3, T, Q> reflect2D(const mat<3, 3, T, Q> & m, const vec<3, T, Q>& normal){return reflect2DGTX(m, normal);}\t\t\t\t\t\t\t\t\t//!< \\brief Build a reflection matrix (from GLM_GTX_transform2 extension)\n\t//template<typename T> mat<4, 4, T, Q> reflect3D(const mat<4, 4, T, Q> & m, const vec<3, T, Q>& normal){return reflect3DGTX(m, normal);}\t\t\t\t\t\t\t\t\t//!< \\brief Build a reflection matrix (from GLM_GTX_transform2 extension)\n\n\t//! Build planar projection matrix along normal axis.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<3, 3, T, Q> proj2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal);\n\n\t//! Build planar projection matrix along normal axis.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> proj3D(mat<4, 4, T, Q> const & m, vec<3, T, Q> const& normal);\n\n\t//! Build a scale bias matrix.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(T scale, T bias);\n\n\t//! Build a scale bias matrix.\n\t//! From GLM_GTX_transform2 extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias);\n\n\t/// @}\n}// namespace glm\n\n#include \"transform2.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/transform2.inl",
    "content": "/// @ref gtx_transform2\n\nnamespace glm\n{\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearX2D(mat<3, 3, T, Q> const& m, T s)\n\t{\n\t\tmat<3, 3, T, Q> r(1);\n\t\tr[1][0] = s;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> shearY2D(mat<3, 3, T, Q> const& m, T s)\n\t{\n\t\tmat<3, 3, T, Q> r(1);\n\t\tr[0][1] = s;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearX3D(mat<4, 4, T, Q> const& m, T s, T t)\n\t{\n\t\tmat<4, 4, T, Q> r(1);\n\t\tr[0][1] = s;\n\t\tr[0][2] = t;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearY3D(mat<4, 4, T, Q> const& m, T s, T t)\n\t{\n\t\tmat<4, 4, T, Q> r(1);\n\t\tr[1][0] = s;\n\t\tr[1][2] = t;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> shearZ3D(mat<4, 4, T, Q> const& m, T s, T t)\n\t{\n\t\tmat<4, 4, T, Q> r(1);\n\t\tr[2][0] = s;\n\t\tr[2][1] = t;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> reflect2D(mat<3, 3, T, Q> const& m, vec<3, T, Q> const& normal)\n\t{\n\t\tmat<3, 3, T, Q> r(static_cast<T>(1));\n\t\tr[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;\n\t\tr[0][1] = -static_cast<T>(2) * normal.x * normal.y;\n\t\tr[1][0] = -static_cast<T>(2) * normal.x * normal.y;\n\t\tr[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> reflect3D(mat<4, 4, T, Q> const& m, vec<3, T, Q> const& normal)\n\t{\n\t\tmat<4, 4, T, Q> r(static_cast<T>(1));\n\t\tr[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;\n\t\tr[0][1] = -static_cast<T>(2) * normal.x * normal.y;\n\t\tr[0][2] = -static_cast<T>(2) * normal.x * normal.z;\n\n\t\tr[1][0] = -static_cast<T>(2) * normal.x * normal.y;\n\t\tr[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;\n\t\tr[1][2] = -static_cast<T>(2) * normal.y * normal.z;\n\n\t\tr[2][0] = -static_cast<T>(2) * normal.x * normal.z;\n\t\tr[2][1] = -static_cast<T>(2) * normal.y * normal.z;\n\t\tr[2][2] = static_cast<T>(1) - static_cast<T>(2) * normal.z * normal.z;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<3, 3, T, Q> proj2D(\n\t\tconst mat<3, 3, T, Q>& m,\n\t\tconst vec<3, T, Q>& normal)\n\t{\n\t\tmat<3, 3, T, Q> r(static_cast<T>(1));\n\t\tr[0][0] = static_cast<T>(1) - normal.x * normal.x;\n\t\tr[0][1] = - normal.x * normal.y;\n\t\tr[1][0] = - normal.x * normal.y;\n\t\tr[1][1] = static_cast<T>(1) - normal.y * normal.y;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> proj3D(\n\t\tconst mat<4, 4, T, Q>& m,\n\t\tconst vec<3, T, Q>& normal)\n\t{\n\t\tmat<4, 4, T, Q> r(static_cast<T>(1));\n\t\tr[0][0] = static_cast<T>(1) - normal.x * normal.x;\n\t\tr[0][1] = - normal.x * normal.y;\n\t\tr[0][2] = - normal.x * normal.z;\n\t\tr[1][0] = - normal.x * normal.y;\n\t\tr[1][1] = static_cast<T>(1) - normal.y * normal.y;\n\t\tr[1][2] = - normal.y * normal.z;\n\t\tr[2][0] = - normal.x * normal.z;\n\t\tr[2][1] = - normal.y * normal.z;\n\t\tr[2][2] = static_cast<T>(1) - normal.z * normal.z;\n\t\treturn m * r;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(T scale, T bias)\n\t{\n\t\tmat<4, 4, T, Q> result;\n\t\tresult[3] = vec<4, T, Q>(vec<3, T, Q>(bias), static_cast<T>(1));\n\t\tresult[0][0] = scale;\n\t\tresult[1][1] = scale;\n\t\tresult[2][2] = scale;\n\t\treturn result;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER mat<4, 4, T, Q> scaleBias(mat<4, 4, T, Q> const& m, T scale, T bias)\n\t{\n\t\treturn m * scaleBias(scale, bias);\n\t}\n}//namespace glm\n\n"
  },
  {
    "path": "lib/gli/glm/gtx/type_aligned.hpp",
    "content": "/// @ref gtx_type_aligned\n/// @file glm/gtx/type_aligned.hpp\n///\n/// @see core (dependence)\n/// @see gtc_quaternion (dependence)\n///\n/// @defgroup gtx_type_aligned GLM_GTX_type_aligned\n/// @ingroup gtx\n///\n/// Include <glm/gtx/type_aligned.hpp> to use the features of this extension.\n///\n/// Defines aligned types.\n\n#pragma once\n\n// Dependency:\n#include \"../gtc/type_precision.hpp\"\n#include \"../gtc/quaternion.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_type_aligned is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_type_aligned extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t///////////////////////////\n\t// Signed int vector types\n\n\t/// @addtogroup gtx_type_aligned\n\t/// @{\n\n\t/// Low qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int8, aligned_lowp_int8, 1);\n\n\t/// Low qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int16, aligned_lowp_int16, 2);\n\n\t/// Low qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int32, aligned_lowp_int32, 4);\n\n\t/// Low qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int64, aligned_lowp_int64, 8);\n\n\n\t/// Low qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int8_t, aligned_lowp_int8_t, 1);\n\n\t/// Low qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int16_t, aligned_lowp_int16_t, 2);\n\n\t/// Low qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int32_t, aligned_lowp_int32_t, 4);\n\n\t/// Low qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_int64_t, aligned_lowp_int64_t, 8);\n\n\n\t/// Low qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_i8, aligned_lowp_i8, 1);\n\n\t/// Low qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_i16, aligned_lowp_i16, 2);\n\n\t/// Low qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_i32, aligned_lowp_i32, 4);\n\n\t/// Low qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_i64, aligned_lowp_i64, 8);\n\n\n\t/// Medium qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int8, aligned_mediump_int8, 1);\n\n\t/// Medium qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int16, aligned_mediump_int16, 2);\n\n\t/// Medium qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int32, aligned_mediump_int32, 4);\n\n\t/// Medium qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int64, aligned_mediump_int64, 8);\n\n\n\t/// Medium qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int8_t, aligned_mediump_int8_t, 1);\n\n\t/// Medium qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int16_t, aligned_mediump_int16_t, 2);\n\n\t/// Medium qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int32_t, aligned_mediump_int32_t, 4);\n\n\t/// Medium qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_int64_t, aligned_mediump_int64_t, 8);\n\n\n\t/// Medium qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_i8, aligned_mediump_i8, 1);\n\n\t/// Medium qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_i16, aligned_mediump_i16, 2);\n\n\t/// Medium qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_i32, aligned_mediump_i32, 4);\n\n\t/// Medium qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_i64, aligned_mediump_i64, 8);\n\n\n\t/// High qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int8, aligned_highp_int8, 1);\n\n\t/// High qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int16, aligned_highp_int16, 2);\n\n\t/// High qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int32, aligned_highp_int32, 4);\n\n\t/// High qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int64, aligned_highp_int64, 8);\n\n\n\t/// High qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int8_t, aligned_highp_int8_t, 1);\n\n\t/// High qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int16_t, aligned_highp_int16_t, 2);\n\n\t/// High qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int32_t, aligned_highp_int32_t, 4);\n\n\t/// High qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_int64_t, aligned_highp_int64_t, 8);\n\n\n\t/// High qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_i8, aligned_highp_i8, 1);\n\n\t/// High qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_i16, aligned_highp_i16, 2);\n\n\t/// High qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_i32, aligned_highp_i32, 4);\n\n\t/// High qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_i64, aligned_highp_i64, 8);\n\n\n\t/// Default qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int8, aligned_int8, 1);\n\n\t/// Default qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int16, aligned_int16, 2);\n\n\t/// Default qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int32, aligned_int32, 4);\n\n\t/// Default qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int64, aligned_int64, 8);\n\n\n\t/// Default qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int8_t, aligned_int8_t, 1);\n\n\t/// Default qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int16_t, aligned_int16_t, 2);\n\n\t/// Default qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int32_t, aligned_int32_t, 4);\n\n\t/// Default qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(int64_t, aligned_int64_t, 8);\n\n\n\t/// Default qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i8, aligned_i8, 1);\n\n\t/// Default qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i16, aligned_i16, 2);\n\n\t/// Default qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i32, aligned_i32, 4);\n\n\t/// Default qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i64, aligned_i64, 8);\n\n\n\t/// Default qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(ivec1, aligned_ivec1, 4);\n\n\t/// Default qualifier 32 bit signed integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(ivec2, aligned_ivec2, 8);\n\n\t/// Default qualifier 32 bit signed integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(ivec3, aligned_ivec3, 16);\n\n\t/// Default qualifier 32 bit signed integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(ivec4, aligned_ivec4, 16);\n\n\n\t/// Default qualifier 8 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i8vec1, aligned_i8vec1, 1);\n\n\t/// Default qualifier 8 bit signed integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i8vec2, aligned_i8vec2, 2);\n\n\t/// Default qualifier 8 bit signed integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i8vec3, aligned_i8vec3, 4);\n\n\t/// Default qualifier 8 bit signed integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i8vec4, aligned_i8vec4, 4);\n\n\n\t/// Default qualifier 16 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i16vec1, aligned_i16vec1, 2);\n\n\t/// Default qualifier 16 bit signed integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i16vec2, aligned_i16vec2, 4);\n\n\t/// Default qualifier 16 bit signed integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i16vec3, aligned_i16vec3, 8);\n\n\t/// Default qualifier 16 bit signed integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i16vec4, aligned_i16vec4, 8);\n\n\n\t/// Default qualifier 32 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i32vec1, aligned_i32vec1, 4);\n\n\t/// Default qualifier 32 bit signed integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i32vec2, aligned_i32vec2, 8);\n\n\t/// Default qualifier 32 bit signed integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i32vec3, aligned_i32vec3, 16);\n\n\t/// Default qualifier 32 bit signed integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i32vec4, aligned_i32vec4, 16);\n\n\n\t/// Default qualifier 64 bit signed integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i64vec1, aligned_i64vec1, 8);\n\n\t/// Default qualifier 64 bit signed integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i64vec2, aligned_i64vec2, 16);\n\n\t/// Default qualifier 64 bit signed integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i64vec3, aligned_i64vec3, 32);\n\n\t/// Default qualifier 64 bit signed integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(i64vec4, aligned_i64vec4, 32);\n\n\n\t/////////////////////////////\n\t// Unsigned int vector types\n\n\t/// Low qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint8, aligned_lowp_uint8, 1);\n\n\t/// Low qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint16, aligned_lowp_uint16, 2);\n\n\t/// Low qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint32, aligned_lowp_uint32, 4);\n\n\t/// Low qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint64, aligned_lowp_uint64, 8);\n\n\n\t/// Low qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint8_t, aligned_lowp_uint8_t, 1);\n\n\t/// Low qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint16_t, aligned_lowp_uint16_t, 2);\n\n\t/// Low qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint32_t, aligned_lowp_uint32_t, 4);\n\n\t/// Low qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_uint64_t, aligned_lowp_uint64_t, 8);\n\n\n\t/// Low qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_u8, aligned_lowp_u8, 1);\n\n\t/// Low qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_u16, aligned_lowp_u16, 2);\n\n\t/// Low qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_u32, aligned_lowp_u32, 4);\n\n\t/// Low qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(lowp_u64, aligned_lowp_u64, 8);\n\n\n\t/// Medium qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint8, aligned_mediump_uint8, 1);\n\n\t/// Medium qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint16, aligned_mediump_uint16, 2);\n\n\t/// Medium qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint32, aligned_mediump_uint32, 4);\n\n\t/// Medium qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint64, aligned_mediump_uint64, 8);\n\n\n\t/// Medium qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint8_t, aligned_mediump_uint8_t, 1);\n\n\t/// Medium qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint16_t, aligned_mediump_uint16_t, 2);\n\n\t/// Medium qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint32_t, aligned_mediump_uint32_t, 4);\n\n\t/// Medium qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_uint64_t, aligned_mediump_uint64_t, 8);\n\n\n\t/// Medium qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_u8, aligned_mediump_u8, 1);\n\n\t/// Medium qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_u16, aligned_mediump_u16, 2);\n\n\t/// Medium qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_u32, aligned_mediump_u32, 4);\n\n\t/// Medium qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mediump_u64, aligned_mediump_u64, 8);\n\n\n\t/// High qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint8, aligned_highp_uint8, 1);\n\n\t/// High qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint16, aligned_highp_uint16, 2);\n\n\t/// High qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint32, aligned_highp_uint32, 4);\n\n\t/// High qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint64, aligned_highp_uint64, 8);\n\n\n\t/// High qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint8_t, aligned_highp_uint8_t, 1);\n\n\t/// High qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint16_t, aligned_highp_uint16_t, 2);\n\n\t/// High qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint32_t, aligned_highp_uint32_t, 4);\n\n\t/// High qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_uint64_t, aligned_highp_uint64_t, 8);\n\n\n\t/// High qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_u8, aligned_highp_u8, 1);\n\n\t/// High qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_u16, aligned_highp_u16, 2);\n\n\t/// High qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_u32, aligned_highp_u32, 4);\n\n\t/// High qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(highp_u64, aligned_highp_u64, 8);\n\n\n\t/// Default qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint8, aligned_uint8, 1);\n\n\t/// Default qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint16, aligned_uint16, 2);\n\n\t/// Default qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint32, aligned_uint32, 4);\n\n\t/// Default qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint64, aligned_uint64, 8);\n\n\n\t/// Default qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint8_t, aligned_uint8_t, 1);\n\n\t/// Default qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint16_t, aligned_uint16_t, 2);\n\n\t/// Default qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint32_t, aligned_uint32_t, 4);\n\n\t/// Default qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uint64_t, aligned_uint64_t, 8);\n\n\n\t/// Default qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u8, aligned_u8, 1);\n\n\t/// Default qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u16, aligned_u16, 2);\n\n\t/// Default qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u32, aligned_u32, 4);\n\n\t/// Default qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u64, aligned_u64, 8);\n\n\n\t/// Default qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uvec1, aligned_uvec1, 4);\n\n\t/// Default qualifier 32 bit unsigned integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uvec2, aligned_uvec2, 8);\n\n\t/// Default qualifier 32 bit unsigned integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uvec3, aligned_uvec3, 16);\n\n\t/// Default qualifier 32 bit unsigned integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(uvec4, aligned_uvec4, 16);\n\n\n\t/// Default qualifier 8 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u8vec1, aligned_u8vec1, 1);\n\n\t/// Default qualifier 8 bit unsigned integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u8vec2, aligned_u8vec2, 2);\n\n\t/// Default qualifier 8 bit unsigned integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u8vec3, aligned_u8vec3, 4);\n\n\t/// Default qualifier 8 bit unsigned integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u8vec4, aligned_u8vec4, 4);\n\n\n\t/// Default qualifier 16 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u16vec1, aligned_u16vec1, 2);\n\n\t/// Default qualifier 16 bit unsigned integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u16vec2, aligned_u16vec2, 4);\n\n\t/// Default qualifier 16 bit unsigned integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u16vec3, aligned_u16vec3, 8);\n\n\t/// Default qualifier 16 bit unsigned integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u16vec4, aligned_u16vec4, 8);\n\n\n\t/// Default qualifier 32 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u32vec1, aligned_u32vec1, 4);\n\n\t/// Default qualifier 32 bit unsigned integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u32vec2, aligned_u32vec2, 8);\n\n\t/// Default qualifier 32 bit unsigned integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u32vec3, aligned_u32vec3, 16);\n\n\t/// Default qualifier 32 bit unsigned integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u32vec4, aligned_u32vec4, 16);\n\n\n\t/// Default qualifier 64 bit unsigned integer aligned scalar type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u64vec1, aligned_u64vec1, 8);\n\n\t/// Default qualifier 64 bit unsigned integer aligned vector of 2 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u64vec2, aligned_u64vec2, 16);\n\n\t/// Default qualifier 64 bit unsigned integer aligned vector of 3 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u64vec3, aligned_u64vec3, 32);\n\n\t/// Default qualifier 64 bit unsigned integer aligned vector of 4 components type.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(u64vec4, aligned_u64vec4, 32);\n\n\n\t//////////////////////\n\t// Float vector types\n\n\t/// 32 bit single-qualifier floating-point aligned scalar.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(float32, aligned_float32, 4);\n\n\t/// 32 bit single-qualifier floating-point aligned scalar.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(float32_t, aligned_float32_t, 4);\n\n\t/// 32 bit single-qualifier floating-point aligned scalar.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(float32, aligned_f32, 4);\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t/// 64 bit double-qualifier floating-point aligned scalar.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(float64, aligned_float64, 8);\n\n\t/// 64 bit double-qualifier floating-point aligned scalar.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(float64_t, aligned_float64_t, 8);\n\n\t/// 64 bit double-qualifier floating-point aligned scalar.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(float64, aligned_f64, 8);\n\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\n\t/// Single-qualifier floating-point aligned vector of 1 component.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(vec1, aligned_vec1, 4);\n\n\t/// Single-qualifier floating-point aligned vector of 2 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(vec2, aligned_vec2, 8);\n\n\t/// Single-qualifier floating-point aligned vector of 3 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(vec3, aligned_vec3, 16);\n\n\t/// Single-qualifier floating-point aligned vector of 4 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(vec4, aligned_vec4, 16);\n\n\n\t/// Single-qualifier floating-point aligned vector of 1 component.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fvec1, aligned_fvec1, 4);\n\n\t/// Single-qualifier floating-point aligned vector of 2 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fvec2, aligned_fvec2, 8);\n\n\t/// Single-qualifier floating-point aligned vector of 3 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fvec3, aligned_fvec3, 16);\n\n\t/// Single-qualifier floating-point aligned vector of 4 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fvec4, aligned_fvec4, 16);\n\n\n\t/// Single-qualifier floating-point aligned vector of 1 component.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32vec1, aligned_f32vec1, 4);\n\n\t/// Single-qualifier floating-point aligned vector of 2 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32vec2, aligned_f32vec2, 8);\n\n\t/// Single-qualifier floating-point aligned vector of 3 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32vec3, aligned_f32vec3, 16);\n\n\t/// Single-qualifier floating-point aligned vector of 4 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32vec4, aligned_f32vec4, 16);\n\n\n\t/// Double-qualifier floating-point aligned vector of 1 component.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(dvec1, aligned_dvec1, 8);\n\n\t/// Double-qualifier floating-point aligned vector of 2 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(dvec2, aligned_dvec2, 16);\n\n\t/// Double-qualifier floating-point aligned vector of 3 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(dvec3, aligned_dvec3, 32);\n\n\t/// Double-qualifier floating-point aligned vector of 4 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(dvec4, aligned_dvec4, 32);\n\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t/// Double-qualifier floating-point aligned vector of 1 component.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64vec1, aligned_f64vec1, 8);\n\n\t/// Double-qualifier floating-point aligned vector of 2 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64vec2, aligned_f64vec2, 16);\n\n\t/// Double-qualifier floating-point aligned vector of 3 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64vec3, aligned_f64vec3, 32);\n\n\t/// Double-qualifier floating-point aligned vector of 4 components.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64vec4, aligned_f64vec4, 32);\n\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\t//////////////////////\n\t// Float matrix types\n\n\t/// Single-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef detail::tmat1<f32> mat1;\n\n\t/// Single-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mat2, aligned_mat2, 16);\n\n\t/// Single-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mat3, aligned_mat3, 16);\n\n\t/// Single-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mat4, aligned_mat4, 16);\n\n\n\t/// Single-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef detail::tmat1x1<f32> mat1;\n\n\t/// Single-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mat2x2, aligned_mat2x2, 16);\n\n\t/// Single-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mat3x3, aligned_mat3x3, 16);\n\n\t/// Single-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(mat4x4, aligned_mat4x4, 16);\n\n\n\t/// Single-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef detail::tmat1x1<f32> fmat1;\n\n\t/// Single-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2, 16);\n\n\t/// Single-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3, 16);\n\n\t/// Single-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4, 16);\n\n\n\t/// Single-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef f32 fmat1x1;\n\n\t/// Single-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2x2, 16);\n\n\t/// Single-qualifier floating-point aligned 2x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat2x3, aligned_fmat2x3, 16);\n\n\t/// Single-qualifier floating-point aligned 2x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat2x4, aligned_fmat2x4, 16);\n\n\t/// Single-qualifier floating-point aligned 3x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat3x2, aligned_fmat3x2, 16);\n\n\t/// Single-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3x3, 16);\n\n\t/// Single-qualifier floating-point aligned 3x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat3x4, aligned_fmat3x4, 16);\n\n\t/// Single-qualifier floating-point aligned 4x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat4x2, aligned_fmat4x2, 16);\n\n\t/// Single-qualifier floating-point aligned 4x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat4x3, aligned_fmat4x3, 16);\n\n\t/// Single-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4x4, 16);\n\n\n\t/// Single-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef detail::tmat1x1<f32, defaultp> f32mat1;\n\n\t/// Single-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2, 16);\n\n\t/// Single-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3, 16);\n\n\t/// Single-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4, 16);\n\n\n\t/// Single-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef f32 f32mat1x1;\n\n\t/// Single-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2x2, 16);\n\n\t/// Single-qualifier floating-point aligned 2x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat2x3, aligned_f32mat2x3, 16);\n\n\t/// Single-qualifier floating-point aligned 2x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat2x4, aligned_f32mat2x4, 16);\n\n\t/// Single-qualifier floating-point aligned 3x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat3x2, aligned_f32mat3x2, 16);\n\n\t/// Single-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3x3, 16);\n\n\t/// Single-qualifier floating-point aligned 3x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat3x4, aligned_f32mat3x4, 16);\n\n\t/// Single-qualifier floating-point aligned 4x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat4x2, aligned_f32mat4x2, 16);\n\n\t/// Single-qualifier floating-point aligned 4x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat4x3, aligned_f32mat4x3, 16);\n\n\t/// Single-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4x4, 16);\n\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t/// Double-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef detail::tmat1x1<f64, defaultp> f64mat1;\n\n\t/// Double-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2, 32);\n\n\t/// Double-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3, 32);\n\n\t/// Double-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4, 32);\n\n\n\t/// Double-qualifier floating-point aligned 1x1 matrix.\n\t/// @see gtx_type_aligned\n\t//typedef f64 f64mat1x1;\n\n\t/// Double-qualifier floating-point aligned 2x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2x2, 32);\n\n\t/// Double-qualifier floating-point aligned 2x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat2x3, aligned_f64mat2x3, 32);\n\n\t/// Double-qualifier floating-point aligned 2x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat2x4, aligned_f64mat2x4, 32);\n\n\t/// Double-qualifier floating-point aligned 3x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat3x2, aligned_f64mat3x2, 32);\n\n\t/// Double-qualifier floating-point aligned 3x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3x3, 32);\n\n\t/// Double-qualifier floating-point aligned 3x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat3x4, aligned_f64mat3x4, 32);\n\n\t/// Double-qualifier floating-point aligned 4x2 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat4x2, aligned_f64mat4x2, 32);\n\n\t/// Double-qualifier floating-point aligned 4x3 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat4x3, aligned_f64mat4x3, 32);\n\n\t/// Double-qualifier floating-point aligned 4x4 matrix.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4x4, 32);\n\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\n\t//////////////////////////\n\t// Quaternion types\n\n\t/// Single-qualifier floating-point aligned quaternion.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(quat, aligned_quat, 16);\n\n\t/// Single-qualifier floating-point aligned quaternion.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(quat, aligned_fquat, 16);\n\n\t/// Double-qualifier floating-point aligned quaternion.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(dquat, aligned_dquat, 32);\n\n\t/// Single-qualifier floating-point aligned quaternion.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f32quat, aligned_f32quat, 16);\n\n#\tifndef GLM_FORCE_SINGLE_ONLY\n\n\t/// Double-qualifier floating-point aligned quaternion.\n\t/// @see gtx_type_aligned\n\tGLM_ALIGNED_TYPEDEF(f64quat, aligned_f64quat, 32);\n\n#\tendif//GLM_FORCE_SINGLE_ONLY\n\n\t/// @}\n}//namespace glm\n\n#include \"type_aligned.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/type_aligned.inl",
    "content": "/// @ref gtc_type_aligned\n\nnamespace glm\n{\n\n}\n"
  },
  {
    "path": "lib/gli/glm/gtx/type_trait.hpp",
    "content": "/// @ref gtx_type_trait\n/// @file glm/gtx/type_trait.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_type_trait GLM_GTX_type_trait\n/// @ingroup gtx\n///\n/// Include <glm/gtx/type_trait.hpp> to use the features of this extension.\n///\n/// Defines traits for each type.\n\n#pragma once\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_type_trait is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_type_trait extension included\")\n#\tendif\n#endif\n\n// Dependency:\n#include \"../detail/qualifier.hpp\"\n#include \"../gtc/quaternion.hpp\"\n#include \"../gtx/dual_quaternion.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup gtx_type_trait\n\t/// @{\n\n\ttemplate<typename T>\n\tstruct type\n\t{\n\t\tstatic bool const is_vec = false;\n\t\tstatic bool const is_mat = false;\n\t\tstatic bool const is_quat = false;\n\t\tstatic length_t const components = 0;\n\t\tstatic length_t const cols = 0;\n\t\tstatic length_t const rows = 0;\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct type<vec<L, T, Q> >\n\t{\n\t\tstatic bool const is_vec = true;\n\t\tstatic bool const is_mat = false;\n\t\tstatic bool const is_quat = false;\n\t\tstatic length_t const components = L;\n\t};\n\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tstruct type<mat<C, R, T, Q> >\n\t{\n\t\tstatic bool const is_vec = false;\n\t\tstatic bool const is_mat = true;\n\t\tstatic bool const is_quat = false;\n\t\tstatic length_t const components = C;\n\t\tstatic length_t const cols = C;\n\t\tstatic length_t const rows = R;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct type<qua<T, Q> >\n\t{\n\t\tstatic bool const is_vec = false;\n\t\tstatic bool const is_mat = false;\n\t\tstatic bool const is_quat = true;\n\t\tstatic length_t const components = 4;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct type<tdualquat<T, Q> >\n\t{\n\t\tstatic bool const is_vec = false;\n\t\tstatic bool const is_mat = false;\n\t\tstatic bool const is_quat = true;\n\t\tstatic length_t const components = 8;\n\t};\n\n\t/// @}\n}//namespace glm\n\n#include \"type_trait.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/type_trait.inl",
    "content": "/// @ref gtx_type_trait\n\nnamespace glm\n{\n\ttemplate<typename T>\n\tbool const type<T>::is_vec;\n\ttemplate<typename T>\n\tbool const type<T>::is_mat;\n\ttemplate<typename T>\n\tbool const type<T>::is_quat;\n\ttemplate<typename T>\n\tlength_t const type<T>::components;\n\ttemplate<typename T>\n\tlength_t const type<T>::cols;\n\ttemplate<typename T>\n\tlength_t const type<T>::rows;\n\n\t// vec\n\ttemplate<length_t L, typename T, qualifier Q>\n\tbool const type<vec<L, T, Q> >::is_vec;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tbool const type<vec<L, T, Q> >::is_mat;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tbool const type<vec<L, T, Q> >::is_quat;\n\ttemplate<length_t L, typename T, qualifier Q>\n\tlength_t const type<vec<L, T, Q> >::components;\n\n\t// mat\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tbool const type<mat<C, R, T, Q> >::is_vec;\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tbool const type<mat<C, R, T, Q> >::is_mat;\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tbool const type<mat<C, R, T, Q> >::is_quat;\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tlength_t const type<mat<C, R, T, Q> >::components;\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tlength_t const type<mat<C, R, T, Q> >::cols;\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tlength_t const type<mat<C, R, T, Q> >::rows;\n\n\t// tquat\n\ttemplate<typename T, qualifier Q>\n\tbool const type<qua<T, Q> >::is_vec;\n\ttemplate<typename T, qualifier Q>\n\tbool const type<qua<T, Q> >::is_mat;\n\ttemplate<typename T, qualifier Q>\n\tbool const type<qua<T, Q> >::is_quat;\n\ttemplate<typename T, qualifier Q>\n\tlength_t const type<qua<T, Q> >::components;\n\n\t// tdualquat\n\ttemplate<typename T, qualifier Q>\n\tbool const type<tdualquat<T, Q> >::is_vec;\n\ttemplate<typename T, qualifier Q>\n\tbool const type<tdualquat<T, Q> >::is_mat;\n\ttemplate<typename T, qualifier Q>\n\tbool const type<tdualquat<T, Q> >::is_quat;\n\ttemplate<typename T, qualifier Q>\n\tlength_t const type<tdualquat<T, Q> >::components;\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/vec_swizzle.hpp",
    "content": "/// @ref gtx_vec_swizzle\n/// @file glm/gtx/vec_swizzle.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_vec_swizzle GLM_GTX_vec_swizzle\n/// @ingroup gtx\n///\n/// Include <glm/gtx/vec_swizzle.hpp> to use the features of this extension.\n///\n/// Functions to perform swizzle operation.\n\n#pragma once\n\n#include \"../glm.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_vec_swizzle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_vec_swizzle extension included\")\n#\tendif\n#endif\n\nnamespace glm {\n\t// xx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<1, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.x);\n\t}\n\n\t// xy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.y);\n\t}\n\n\t// xz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.z);\n\t}\n\n\t// xw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> xw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.x, v.w);\n\t}\n\n\t// yx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.x);\n\t}\n\n\t// yy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.y);\n\t}\n\n\t// yz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.z);\n\t}\n\n\t// yw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> yw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.y, v.w);\n\t}\n\n\t// zx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.x);\n\t}\n\n\t// zy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.y);\n\t}\n\n\t// zz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.z);\n\t}\n\n\t// zw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> zw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.z, v.w);\n\t}\n\n\t// wx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> wx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.w, v.x);\n\t}\n\n\t// wy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> wy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.w, v.y);\n\t}\n\n\t// wz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> wz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.w, v.z);\n\t}\n\n\t// ww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<2, T, Q> ww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<2, T, Q>(v.w, v.w);\n\t}\n\n\t// xxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<1, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.x);\n\t}\n\n\t// xxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.y);\n\t}\n\n\t// xxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.z);\n\t}\n\n\t// xxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.x, v.w);\n\t}\n\n\t// xyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.x);\n\t}\n\n\t// xyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.y);\n\t}\n\n\t// xyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.z);\n\t}\n\n\t// xyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.y, v.w);\n\t}\n\n\t// xzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.x);\n\t}\n\n\t// xzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.y);\n\t}\n\n\t// xzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.z);\n\t}\n\n\t// xzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.z, v.w);\n\t}\n\n\t// xwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.w, v.x);\n\t}\n\n\t// xwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.w, v.y);\n\t}\n\n\t// xwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.w, v.z);\n\t}\n\n\t// xww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> xww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.x, v.w, v.w);\n\t}\n\n\t// yxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.x);\n\t}\n\n\t// yxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.y);\n\t}\n\n\t// yxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.z);\n\t}\n\n\t// yxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.x, v.w);\n\t}\n\n\t// yyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.x);\n\t}\n\n\t// yyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.y);\n\t}\n\n\t// yyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.z);\n\t}\n\n\t// yyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.y, v.w);\n\t}\n\n\t// yzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.x);\n\t}\n\n\t// yzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.y);\n\t}\n\n\t// yzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.z);\n\t}\n\n\t// yzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.z, v.w);\n\t}\n\n\t// ywx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> ywx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.w, v.x);\n\t}\n\n\t// ywy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> ywy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.w, v.y);\n\t}\n\n\t// ywz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> ywz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.w, v.z);\n\t}\n\n\t// yww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> yww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.y, v.w, v.w);\n\t}\n\n\t// zxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.x);\n\t}\n\n\t// zxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.y);\n\t}\n\n\t// zxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.z);\n\t}\n\n\t// zxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.x, v.w);\n\t}\n\n\t// zyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.x);\n\t}\n\n\t// zyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.y);\n\t}\n\n\t// zyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.z);\n\t}\n\n\t// zyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.y, v.w);\n\t}\n\n\t// zzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.x);\n\t}\n\n\t// zzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.y);\n\t}\n\n\t// zzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.z);\n\t}\n\n\t// zzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.z, v.w);\n\t}\n\n\t// zwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.w, v.x);\n\t}\n\n\t// zwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.w, v.y);\n\t}\n\n\t// zwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.w, v.z);\n\t}\n\n\t// zww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> zww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.z, v.w, v.w);\n\t}\n\n\t// wxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.x, v.x);\n\t}\n\n\t// wxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.x, v.y);\n\t}\n\n\t// wxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.x, v.z);\n\t}\n\n\t// wxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.x, v.w);\n\t}\n\n\t// wyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.y, v.x);\n\t}\n\n\t// wyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.y, v.y);\n\t}\n\n\t// wyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.y, v.z);\n\t}\n\n\t// wyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.y, v.w);\n\t}\n\n\t// wzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.z, v.x);\n\t}\n\n\t// wzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.z, v.y);\n\t}\n\n\t// wzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.z, v.z);\n\t}\n\n\t// wzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.z, v.w);\n\t}\n\n\t// wwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.w, v.x);\n\t}\n\n\t// wwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.w, v.y);\n\t}\n\n\t// wwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> wwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.w, v.z);\n\t}\n\n\t// www\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<3, T, Q> www(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<3, T, Q>(v.w, v.w, v.w);\n\t}\n\n\t// xxxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<1, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.x);\n\t}\n\n\t// xxxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.y);\n\t}\n\n\t// xxxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.z);\n\t}\n\n\t// xxxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.x, v.w);\n\t}\n\n\t// xxyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.x);\n\t}\n\n\t// xxyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.y);\n\t}\n\n\t// xxyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.z);\n\t}\n\n\t// xxyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.y, v.w);\n\t}\n\n\t// xxzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.x);\n\t}\n\n\t// xxzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.y);\n\t}\n\n\t// xxzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.z);\n\t}\n\n\t// xxzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.z, v.w);\n\t}\n\n\t// xxwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.w, v.x);\n\t}\n\n\t// xxwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.w, v.y);\n\t}\n\n\t// xxwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.w, v.z);\n\t}\n\n\t// xxww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xxww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.x, v.w, v.w);\n\t}\n\n\t// xyxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.x);\n\t}\n\n\t// xyxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.y);\n\t}\n\n\t// xyxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.z);\n\t}\n\n\t// xyxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.x, v.w);\n\t}\n\n\t// xyyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.x);\n\t}\n\n\t// xyyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.y);\n\t}\n\n\t// xyyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.z);\n\t}\n\n\t// xyyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.y, v.w);\n\t}\n\n\t// xyzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.x);\n\t}\n\n\t// xyzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.y);\n\t}\n\n\t// xyzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.z);\n\t}\n\n\t// xyzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.z, v.w);\n\t}\n\n\t// xywx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xywx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.w, v.x);\n\t}\n\n\t// xywy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xywy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.w, v.y);\n\t}\n\n\t// xywz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xywz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.w, v.z);\n\t}\n\n\t// xyww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xyww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.y, v.w, v.w);\n\t}\n\n\t// xzxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.x);\n\t}\n\n\t// xzxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.y);\n\t}\n\n\t// xzxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.z);\n\t}\n\n\t// xzxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.x, v.w);\n\t}\n\n\t// xzyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.x);\n\t}\n\n\t// xzyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.y);\n\t}\n\n\t// xzyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.z);\n\t}\n\n\t// xzyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.y, v.w);\n\t}\n\n\t// xzzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.x);\n\t}\n\n\t// xzzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.y);\n\t}\n\n\t// xzzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.z);\n\t}\n\n\t// xzzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.z, v.w);\n\t}\n\n\t// xzwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.w, v.x);\n\t}\n\n\t// xzwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.w, v.y);\n\t}\n\n\t// xzwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.w, v.z);\n\t}\n\n\t// xzww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xzww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.z, v.w, v.w);\n\t}\n\n\t// xwxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.x, v.x);\n\t}\n\n\t// xwxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.x, v.y);\n\t}\n\n\t// xwxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.x, v.z);\n\t}\n\n\t// xwxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.x, v.w);\n\t}\n\n\t// xwyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.y, v.x);\n\t}\n\n\t// xwyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.y, v.y);\n\t}\n\n\t// xwyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.y, v.z);\n\t}\n\n\t// xwyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.y, v.w);\n\t}\n\n\t// xwzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.z, v.x);\n\t}\n\n\t// xwzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.z, v.y);\n\t}\n\n\t// xwzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.z, v.z);\n\t}\n\n\t// xwzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.z, v.w);\n\t}\n\n\t// xwwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.w, v.x);\n\t}\n\n\t// xwwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.w, v.y);\n\t}\n\n\t// xwwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.w, v.z);\n\t}\n\n\t// xwww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> xwww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.x, v.w, v.w, v.w);\n\t}\n\n\t// yxxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.x);\n\t}\n\n\t// yxxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.y);\n\t}\n\n\t// yxxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.z);\n\t}\n\n\t// yxxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.x, v.w);\n\t}\n\n\t// yxyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.x);\n\t}\n\n\t// yxyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.y);\n\t}\n\n\t// yxyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.z);\n\t}\n\n\t// yxyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.y, v.w);\n\t}\n\n\t// yxzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.x);\n\t}\n\n\t// yxzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.y);\n\t}\n\n\t// yxzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.z);\n\t}\n\n\t// yxzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.z, v.w);\n\t}\n\n\t// yxwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.w, v.x);\n\t}\n\n\t// yxwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.w, v.y);\n\t}\n\n\t// yxwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.w, v.z);\n\t}\n\n\t// yxww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yxww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.x, v.w, v.w);\n\t}\n\n\t// yyxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.x);\n\t}\n\n\t// yyxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.y);\n\t}\n\n\t// yyxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.z);\n\t}\n\n\t// yyxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.x, v.w);\n\t}\n\n\t// yyyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.x);\n\t}\n\n\t// yyyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<2, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.y);\n\t}\n\n\t// yyyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.z);\n\t}\n\n\t// yyyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.y, v.w);\n\t}\n\n\t// yyzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.x);\n\t}\n\n\t// yyzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.y);\n\t}\n\n\t// yyzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.z);\n\t}\n\n\t// yyzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.z, v.w);\n\t}\n\n\t// yywx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yywx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.w, v.x);\n\t}\n\n\t// yywy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yywy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.w, v.y);\n\t}\n\n\t// yywz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yywz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.w, v.z);\n\t}\n\n\t// yyww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yyww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.y, v.w, v.w);\n\t}\n\n\t// yzxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.x);\n\t}\n\n\t// yzxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.y);\n\t}\n\n\t// yzxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.z);\n\t}\n\n\t// yzxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.x, v.w);\n\t}\n\n\t// yzyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.x);\n\t}\n\n\t// yzyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.y);\n\t}\n\n\t// yzyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.z);\n\t}\n\n\t// yzyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.y, v.w);\n\t}\n\n\t// yzzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.x);\n\t}\n\n\t// yzzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.y);\n\t}\n\n\t// yzzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.z);\n\t}\n\n\t// yzzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.z, v.w);\n\t}\n\n\t// yzwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.w, v.x);\n\t}\n\n\t// yzwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.w, v.y);\n\t}\n\n\t// yzwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.w, v.z);\n\t}\n\n\t// yzww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> yzww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.z, v.w, v.w);\n\t}\n\n\t// ywxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.x, v.x);\n\t}\n\n\t// ywxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.x, v.y);\n\t}\n\n\t// ywxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.x, v.z);\n\t}\n\n\t// ywxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.x, v.w);\n\t}\n\n\t// ywyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.y, v.x);\n\t}\n\n\t// ywyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.y, v.y);\n\t}\n\n\t// ywyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.y, v.z);\n\t}\n\n\t// ywyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.y, v.w);\n\t}\n\n\t// ywzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.z, v.x);\n\t}\n\n\t// ywzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.z, v.y);\n\t}\n\n\t// ywzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.z, v.z);\n\t}\n\n\t// ywzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.z, v.w);\n\t}\n\n\t// ywwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.w, v.x);\n\t}\n\n\t// ywwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.w, v.y);\n\t}\n\n\t// ywwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.w, v.z);\n\t}\n\n\t// ywww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> ywww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.y, v.w, v.w, v.w);\n\t}\n\n\t// zxxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.x);\n\t}\n\n\t// zxxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.y);\n\t}\n\n\t// zxxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.z);\n\t}\n\n\t// zxxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.x, v.w);\n\t}\n\n\t// zxyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.x);\n\t}\n\n\t// zxyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.y);\n\t}\n\n\t// zxyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.z);\n\t}\n\n\t// zxyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.y, v.w);\n\t}\n\n\t// zxzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.x);\n\t}\n\n\t// zxzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.y);\n\t}\n\n\t// zxzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.z);\n\t}\n\n\t// zxzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.z, v.w);\n\t}\n\n\t// zxwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.w, v.x);\n\t}\n\n\t// zxwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.w, v.y);\n\t}\n\n\t// zxwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.w, v.z);\n\t}\n\n\t// zxww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zxww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.x, v.w, v.w);\n\t}\n\n\t// zyxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.x);\n\t}\n\n\t// zyxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.y);\n\t}\n\n\t// zyxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.z);\n\t}\n\n\t// zyxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.x, v.w);\n\t}\n\n\t// zyyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.x);\n\t}\n\n\t// zyyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.y);\n\t}\n\n\t// zyyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.z);\n\t}\n\n\t// zyyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.y, v.w);\n\t}\n\n\t// zyzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.x);\n\t}\n\n\t// zyzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.y);\n\t}\n\n\t// zyzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.z);\n\t}\n\n\t// zyzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.z, v.w);\n\t}\n\n\t// zywx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zywx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.w, v.x);\n\t}\n\n\t// zywy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zywy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.w, v.y);\n\t}\n\n\t// zywz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zywz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.w, v.z);\n\t}\n\n\t// zyww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zyww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.y, v.w, v.w);\n\t}\n\n\t// zzxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.x);\n\t}\n\n\t// zzxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.y);\n\t}\n\n\t// zzxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.z);\n\t}\n\n\t// zzxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.x, v.w);\n\t}\n\n\t// zzyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.x);\n\t}\n\n\t// zzyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.y);\n\t}\n\n\t// zzyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.z);\n\t}\n\n\t// zzyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.y, v.w);\n\t}\n\n\t// zzzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.x);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.x);\n\t}\n\n\t// zzzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.y);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.y);\n\t}\n\n\t// zzzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<3, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.z);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.z);\n\t}\n\n\t// zzzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.z, v.w);\n\t}\n\n\t// zzwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.w, v.x);\n\t}\n\n\t// zzwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.w, v.y);\n\t}\n\n\t// zzwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.w, v.z);\n\t}\n\n\t// zzww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zzww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.z, v.w, v.w);\n\t}\n\n\t// zwxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.x, v.x);\n\t}\n\n\t// zwxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.x, v.y);\n\t}\n\n\t// zwxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.x, v.z);\n\t}\n\n\t// zwxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.x, v.w);\n\t}\n\n\t// zwyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.y, v.x);\n\t}\n\n\t// zwyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.y, v.y);\n\t}\n\n\t// zwyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.y, v.z);\n\t}\n\n\t// zwyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.y, v.w);\n\t}\n\n\t// zwzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.z, v.x);\n\t}\n\n\t// zwzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.z, v.y);\n\t}\n\n\t// zwzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.z, v.z);\n\t}\n\n\t// zwzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.z, v.w);\n\t}\n\n\t// zwwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.w, v.x);\n\t}\n\n\t// zwwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.w, v.y);\n\t}\n\n\t// zwwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.w, v.z);\n\t}\n\n\t// zwww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> zwww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.z, v.w, v.w, v.w);\n\t}\n\n\t// wxxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.x, v.x);\n\t}\n\n\t// wxxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.x, v.y);\n\t}\n\n\t// wxxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.x, v.z);\n\t}\n\n\t// wxxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.x, v.w);\n\t}\n\n\t// wxyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.y, v.x);\n\t}\n\n\t// wxyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.y, v.y);\n\t}\n\n\t// wxyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.y, v.z);\n\t}\n\n\t// wxyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.y, v.w);\n\t}\n\n\t// wxzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.z, v.x);\n\t}\n\n\t// wxzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.z, v.y);\n\t}\n\n\t// wxzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.z, v.z);\n\t}\n\n\t// wxzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.z, v.w);\n\t}\n\n\t// wxwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.w, v.x);\n\t}\n\n\t// wxwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.w, v.y);\n\t}\n\n\t// wxwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.w, v.z);\n\t}\n\n\t// wxww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wxww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.x, v.w, v.w);\n\t}\n\n\t// wyxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.x, v.x);\n\t}\n\n\t// wyxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.x, v.y);\n\t}\n\n\t// wyxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.x, v.z);\n\t}\n\n\t// wyxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.x, v.w);\n\t}\n\n\t// wyyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.y, v.x);\n\t}\n\n\t// wyyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.y, v.y);\n\t}\n\n\t// wyyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.y, v.z);\n\t}\n\n\t// wyyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.y, v.w);\n\t}\n\n\t// wyzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.z, v.x);\n\t}\n\n\t// wyzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.z, v.y);\n\t}\n\n\t// wyzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.z, v.z);\n\t}\n\n\t// wyzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.z, v.w);\n\t}\n\n\t// wywx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wywx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.w, v.x);\n\t}\n\n\t// wywy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wywy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.w, v.y);\n\t}\n\n\t// wywz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wywz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.w, v.z);\n\t}\n\n\t// wyww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wyww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.y, v.w, v.w);\n\t}\n\n\t// wzxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.x, v.x);\n\t}\n\n\t// wzxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.x, v.y);\n\t}\n\n\t// wzxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.x, v.z);\n\t}\n\n\t// wzxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.x, v.w);\n\t}\n\n\t// wzyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.y, v.x);\n\t}\n\n\t// wzyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.y, v.y);\n\t}\n\n\t// wzyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.y, v.z);\n\t}\n\n\t// wzyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.y, v.w);\n\t}\n\n\t// wzzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.z, v.x);\n\t}\n\n\t// wzzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.z, v.y);\n\t}\n\n\t// wzzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.z, v.z);\n\t}\n\n\t// wzzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.z, v.w);\n\t}\n\n\t// wzwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.w, v.x);\n\t}\n\n\t// wzwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.w, v.y);\n\t}\n\n\t// wzwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.w, v.z);\n\t}\n\n\t// wzww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wzww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.z, v.w, v.w);\n\t}\n\n\t// wwxx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwxx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.x, v.x);\n\t}\n\n\t// wwxy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwxy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.x, v.y);\n\t}\n\n\t// wwxz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwxz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.x, v.z);\n\t}\n\n\t// wwxw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwxw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.x, v.w);\n\t}\n\n\t// wwyx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwyx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.y, v.x);\n\t}\n\n\t// wwyy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwyy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.y, v.y);\n\t}\n\n\t// wwyz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwyz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.y, v.z);\n\t}\n\n\t// wwyw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwyw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.y, v.w);\n\t}\n\n\t// wwzx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwzx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.z, v.x);\n\t}\n\n\t// wwzy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwzy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.z, v.y);\n\t}\n\n\t// wwzz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwzz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.z, v.z);\n\t}\n\n\t// wwzw\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwzw(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.z, v.w);\n\t}\n\n\t// wwwx\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwwx(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.w, v.x);\n\t}\n\n\t// wwwy\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwwy(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.w, v.y);\n\t}\n\n\t// wwwz\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwwz(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.w, v.z);\n\t}\n\n\t// wwww\n\ttemplate<typename T, qualifier Q>\n\tGLM_INLINE glm::vec<4, T, Q> wwww(const glm::vec<4, T, Q> &v) {\n\t\treturn glm::vec<4, T, Q>(v.w, v.w, v.w, v.w);\n\t}\n\n}\n"
  },
  {
    "path": "lib/gli/glm/gtx/vector_angle.hpp",
    "content": "/// @ref gtx_vector_angle\n/// @file glm/gtx/vector_angle.hpp\n///\n/// @see core (dependence)\n/// @see gtx_quaternion (dependence)\n/// @see gtx_epsilon (dependence)\n///\n/// @defgroup gtx_vector_angle GLM_GTX_vector_angle\n/// @ingroup gtx\n///\n/// Include <glm/gtx/vector_angle.hpp> to use the features of this extension.\n///\n/// Compute angle between vectors\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../gtc/epsilon.hpp\"\n#include \"../gtx/quaternion.hpp\"\n#include \"../gtx/rotate_vector.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_vector_angle is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_vector_angle extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_vector_angle\n\t/// @{\n\n\t//! Returns the absolute angle between two vectors.\n\t//! Parameters need to be normalized.\n\t/// @see gtx_vector_angle extension.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL T angle(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t//! Returns the oriented angle between two 2d vectors.\n\t//! Parameters need to be normalized.\n\t/// @see gtx_vector_angle extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y);\n\n\t//! Returns the oriented angle between two 3d vectors based from a reference axis.\n\t//! Parameters need to be normalized.\n\t/// @see gtx_vector_angle extension.\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_DECL T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref);\n\n\t/// @}\n}// namespace glm\n\n#include \"vector_angle.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/vector_angle.inl",
    "content": "/// @ref gtx_vector_angle\n\nnamespace glm\n{\n\ttemplate<typename genType>\n\tGLM_FUNC_QUALIFIER genType angle\n\t(\n\t\tgenType const& x,\n\t\tgenType const& y\n\t)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, \"'angle' only accept floating-point inputs\");\n\t\treturn acos(clamp(dot(x, y), genType(-1), genType(1)));\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T angle(vec<L, T, Q> const& x, vec<L, T, Q> const& y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'angle' only accept floating-point inputs\");\n\t\treturn acos(clamp(dot(x, y), T(-1), T(1)));\n\t}\n\n\t//! \\todo epsilon is hard coded to 0.01\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T orientedAngle(vec<2, T, Q> const& x, vec<2, T, Q> const& y)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'orientedAngle' only accept floating-point inputs\");\n\t\tT const Angle(acos(clamp(dot(x, y), T(-1), T(1))));\n\n\t\tif(all(epsilonEqual(y, glm::rotate(x, Angle), T(0.0001))))\n\t\t\treturn Angle;\n\t\telse\n\t\t\treturn -Angle;\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER T orientedAngle(vec<3, T, Q> const& x, vec<3, T, Q> const& y, vec<3, T, Q> const& ref)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'orientedAngle' only accept floating-point inputs\");\n\n\t\tT const Angle(acos(clamp(dot(x, y), T(-1), T(1))));\n\t\treturn mix(Angle, -Angle, dot(ref, cross(x, y)) < T(0));\n\t}\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/vector_query.hpp",
    "content": "/// @ref gtx_vector_query\n/// @file glm/gtx/vector_query.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_vector_query GLM_GTX_vector_query\n/// @ingroup gtx\n///\n/// Include <glm/gtx/vector_query.hpp> to use the features of this extension.\n///\n/// Query informations of vector types\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include <cfloat>\n#include <limits>\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_vector_query is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_vector_query extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_vector_query\n\t/// @{\n\n\t//! Check whether two vectors are collinears.\n\t/// @see gtx_vector_query extensions.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL bool areCollinear(vec<L, T, Q> const& v0, vec<L, T, Q> const& v1, T const& epsilon);\n\n\t//! Check whether two vectors are orthogonals.\n\t/// @see gtx_vector_query extensions.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL bool areOrthogonal(vec<L, T, Q> const& v0, vec<L, T, Q> const& v1, T const& epsilon);\n\n\t//! Check whether a vector is normalized.\n\t/// @see gtx_vector_query extensions.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNormalized(vec<L, T, Q> const& v, T const& epsilon);\n\n\t//! Check whether a vector is null.\n\t/// @see gtx_vector_query extensions.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL bool isNull(vec<L, T, Q> const& v, T const& epsilon);\n\n\t//! Check whether a each component of a vector is null.\n\t/// @see gtx_vector_query extensions.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, bool, Q> isCompNull(vec<L, T, Q> const& v, T const& epsilon);\n\n\t//! Check whether two vectors are orthonormal.\n\t/// @see gtx_vector_query extensions.\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL bool areOrthonormal(vec<L, T, Q> const& v0, vec<L, T, Q> const& v1, T const& epsilon);\n\n\t/// @}\n}// namespace glm\n\n#include \"vector_query.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/vector_query.inl",
    "content": "/// @ref gtx_vector_query\n\n#include <cassert>\n\nnamespace glm{\nnamespace detail\n{\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_areCollinear{};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_areCollinear<2, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static bool call(vec<2, T, Q> const& v0, vec<2, T, Q> const& v1, T const& epsilon)\n\t\t{\n\t\t\treturn length(cross(vec<3, T, Q>(v0, static_cast<T>(0)), vec<3, T, Q>(v1, static_cast<T>(0)))) < epsilon;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_areCollinear<3, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static bool call(vec<3, T, Q> const& v0, vec<3, T, Q> const& v1, T const& epsilon)\n\t\t{\n\t\t\treturn length(cross(v0, v1)) < epsilon;\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_areCollinear<4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static bool call(vec<4, T, Q> const& v0, vec<4, T, Q> const& v1, T const& epsilon)\n\t\t{\n\t\t\treturn length(cross(vec<3, T, Q>(v0), vec<3, T, Q>(v1))) < epsilon;\n\t\t}\n\t};\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tstruct compute_isCompNull{};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_isCompNull<2, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<2, bool, Q> call(vec<2, T, Q> const& v, T const& epsilon)\n\t\t{\n\t\t\treturn vec<2, bool, Q>(\n\t\t\t\t(abs(v.x) < epsilon),\n\t\t\t\t(abs(v.y) < epsilon));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_isCompNull<3, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<3, bool, Q> call(vec<3, T, Q> const& v, T const& epsilon)\n\t\t{\n\t\t\treturn vec<3, bool, Q>(\n\t\t\t\t(abs(v.x) < epsilon),\n\t\t\t\t(abs(v.y) < epsilon),\n\t\t\t\t(abs(v.z) < epsilon));\n\t\t}\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct compute_isCompNull<4, T, Q>\n\t{\n\t\tGLM_FUNC_QUALIFIER static vec<4, bool, Q> call(vec<4, T, Q> const& v, T const& epsilon)\n\t\t{\n\t\t\treturn vec<4, bool, Q>(\n\t\t\t\t(abs(v.x) < epsilon),\n\t\t\t\t(abs(v.y) < epsilon),\n\t\t\t\t(abs(v.z) < epsilon),\n\t\t\t\t(abs(v.w) < epsilon));\n\t\t}\n\t};\n\n}//namespace detail\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool areCollinear(vec<L, T, Q> const& v0, vec<L, T, Q> const& v1, T const& epsilon)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'areCollinear' only accept floating-point inputs\");\n\n\t\treturn detail::compute_areCollinear<L, T, Q>::call(v0, v1, epsilon);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool areOrthogonal(vec<L, T, Q> const& v0, vec<L, T, Q> const& v1, T const& epsilon)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'areOrthogonal' only accept floating-point inputs\");\n\n\t\treturn abs(dot(v0, v1)) <= max(\n\t\t\tstatic_cast<T>(1),\n\t\t\tlength(v0)) * max(static_cast<T>(1), length(v1)) * epsilon;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNormalized(vec<L, T, Q> const& v, T const& epsilon)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isNormalized' only accept floating-point inputs\");\n\n\t\treturn abs(length(v) - static_cast<T>(1)) <= static_cast<T>(2) * epsilon;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool isNull(vec<L, T, Q> const& v, T const& epsilon)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isNull' only accept floating-point inputs\");\n\n\t\treturn length(v) <= epsilon;\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<L, bool, Q> isCompNull(vec<L, T, Q> const& v, T const& epsilon)\n\t{\n\t\tGLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, \"'isCompNull' only accept floating-point inputs\");\n\n\t\treturn detail::compute_isCompNull<L, T, Q>::call(v, epsilon);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<2, bool, Q> isCompNull(vec<2, T, Q> const& v, T const& epsilon)\n\t{\n\t\treturn vec<2, bool, Q>(\n\t\t\tabs(v.x) < epsilon,\n\t\t\tabs(v.y) < epsilon);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<3, bool, Q> isCompNull(vec<3, T, Q> const& v, T const& epsilon)\n\t{\n\t\treturn vec<3, bool, Q>(\n\t\t\tabs(v.x) < epsilon,\n\t\t\tabs(v.y) < epsilon,\n\t\t\tabs(v.z) < epsilon);\n\t}\n\n\ttemplate<typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER vec<4, bool, Q> isCompNull(vec<4, T, Q> const& v, T const& epsilon)\n\t{\n\t\treturn vec<4, bool, Q>(\n\t\t\tabs(v.x) < epsilon,\n\t\t\tabs(v.y) < epsilon,\n\t\t\tabs(v.z) < epsilon,\n\t\t\tabs(v.w) < epsilon);\n\t}\n\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_QUALIFIER bool areOrthonormal(vec<L, T, Q> const& v0, vec<L, T, Q> const& v1, T const& epsilon)\n\t{\n\t\treturn isNormalized(v0, epsilon) && isNormalized(v1, epsilon) && (abs(dot(v0, v1)) <= epsilon);\n\t}\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/gtx/wrap.hpp",
    "content": "/// @ref gtx_wrap\n/// @file glm/gtx/wrap.hpp\n///\n/// @see core (dependence)\n///\n/// @defgroup gtx_wrap GLM_GTX_wrap\n/// @ingroup gtx\n///\n/// Include <glm/gtx/wrap.hpp> to use the features of this extension.\n///\n/// Wrapping mode of texture coordinates.\n\n#pragma once\n\n// Dependency:\n#include \"../glm.hpp\"\n#include \"../ext/scalar_common.hpp\"\n#include \"../ext/vector_common.hpp\"\n#include \"../gtc/vec1.hpp\"\n\n#if GLM_MESSAGES == GLM_ENABLE && !defined(GLM_EXT_INCLUDED)\n#\tifndef GLM_ENABLE_EXPERIMENTAL\n#\t\tpragma message(\"GLM: GLM_GTX_wrap is an experimental extension and may change in the future. Use #define GLM_ENABLE_EXPERIMENTAL before including it, if you really want to use it.\")\n#\telse\n#\t\tpragma message(\"GLM: GLM_GTX_wrap extension included\")\n#\tendif\n#endif\n\nnamespace glm\n{\n\t/// @addtogroup gtx_wrap\n\t/// @{\n\n\t/// @}\n}// namespace glm\n\n#include \"wrap.inl\"\n"
  },
  {
    "path": "lib/gli/glm/gtx/wrap.inl",
    "content": "/// @ref gtx_wrap\n\nnamespace glm\n{\n\n}//namespace glm\n"
  },
  {
    "path": "lib/gli/glm/integer.hpp",
    "content": "/// @ref core\n/// @file glm/integer.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n///\n/// @defgroup core_func_integer Integer functions\n/// @ingroup core\n///\n/// Provides GLSL functions on integer types\n///\n/// These all operate component-wise. The description is per component.\n/// The notation [a, b] means the set of bits from bit-number a through bit-number\n/// b, inclusive. The lowest-order bit is bit 0.\n///\n/// Include <glm/integer.hpp> to use these core features.\n\n#pragma once\n\n#include \"detail/qualifier.hpp\"\n#include \"common.hpp\"\n#include \"vector_relational.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_func_integer\n\t/// @{\n\n\t/// Adds 32-bit unsigned integer x and y, returning the sum\n\t/// modulo pow(2, 32). The value carry is set to 0 if the sum was\n\t/// less than pow(2, 32), or to 1 otherwise.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/uaddCarry.xml\">GLSL uaddCarry man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, uint, Q> uaddCarry(\n\t\tvec<L, uint, Q> const& x,\n\t\tvec<L, uint, Q> const& y,\n\t\tvec<L, uint, Q> & carry);\n\n\t/// Subtracts the 32-bit unsigned integer y from x, returning\n\t/// the difference if non-negative, or pow(2, 32) plus the difference\n\t/// otherwise. The value borrow is set to 0 if x >= y, or to 1 otherwise.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/usubBorrow.xml\">GLSL usubBorrow man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL vec<L, uint, Q> usubBorrow(\n\t\tvec<L, uint, Q> const& x,\n\t\tvec<L, uint, Q> const& y,\n\t\tvec<L, uint, Q> & borrow);\n\n\t/// Multiplies 32-bit integers x and y, producing a 64-bit\n\t/// result. The 32 least-significant bits are returned in lsb.\n\t/// The 32 most-significant bits are returned in msb.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/umulExtended.xml\">GLSL umulExtended man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL void umulExtended(\n\t\tvec<L, uint, Q> const& x,\n\t\tvec<L, uint, Q> const& y,\n\t\tvec<L, uint, Q> & msb,\n\t\tvec<L, uint, Q> & lsb);\n\n\t/// Multiplies 32-bit integers x and y, producing a 64-bit\n\t/// result. The 32 least-significant bits are returned in lsb.\n\t/// The 32 most-significant bits are returned in msb.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/imulExtended.xml\">GLSL imulExtended man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL void imulExtended(\n\t\tvec<L, int, Q> const& x,\n\t\tvec<L, int, Q> const& y,\n\t\tvec<L, int, Q> & msb,\n\t\tvec<L, int, Q> & lsb);\n\n\t/// Extracts bits [offset, offset + bits - 1] from value,\n\t/// returning them in the least significant bits of the result.\n\t/// For unsigned data types, the most significant bits of the\n\t/// result will be set to zero. For signed data types, the\n\t/// most significant bits will be set to the value of bit offset + base - 1.\n\t///\n\t/// If bits is zero, the result will be zero. The result will be\n\t/// undefined if offset or bits is negative, or if the sum of\n\t/// offset and bits is greater than the number of bits used\n\t/// to store the operand.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/bitfieldExtract.xml\">GLSL bitfieldExtract man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldExtract(\n\t\tvec<L, T, Q> const& Value,\n\t\tint Offset,\n\t\tint Bits);\n\n\t/// Returns the insertion the bits least-significant bits of insert into base.\n\t///\n\t/// The result will have bits [offset, offset + bits - 1] taken\n\t/// from bits [0, bits - 1] of insert, and all other bits taken\n\t/// directly from the corresponding bits of base. If bits is\n\t/// zero, the result will simply be base. The result will be\n\t/// undefined if offset or bits is negative, or if the sum of\n\t/// offset and bits is greater than the number of bits used to\n\t/// store the operand.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/bitfieldInsert.xml\">GLSL bitfieldInsert man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldInsert(\n\t\tvec<L, T, Q> const& Base,\n\t\tvec<L, T, Q> const& Insert,\n\t\tint Offset,\n\t\tint Bits);\n\n\t/// Returns the reversal of the bits of value.\n\t/// The bit numbered n of the result will be taken from bit (bits - 1) - n of value,\n\t/// where bits is the total number of bits used to represent value.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/bitfieldReverse.xml\">GLSL bitfieldReverse man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> bitfieldReverse(vec<L, T, Q> const& v);\n\n\t/// Returns the number of bits set to 1 in the binary representation of value.\n\t///\n\t/// @tparam genType Signed or unsigned integer scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/bitCount.xml\">GLSL bitCount man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<typename genType>\n\tGLM_FUNC_DECL int bitCount(genType v);\n\n\t/// Returns the number of bits set to 1 in the binary representation of value.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar or vector types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/bitCount.xml\">GLSL bitCount man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> bitCount(vec<L, T, Q> const& v);\n\n\t/// Returns the bit number of the least significant bit set to\n\t/// 1 in the binary representation of value.\n\t/// If value is zero, -1 will be returned.\n\t///\n\t/// @tparam genIUType Signed or unsigned integer scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/findLSB.xml\">GLSL findLSB man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL int findLSB(genIUType x);\n\n\t/// Returns the bit number of the least significant bit set to\n\t/// 1 in the binary representation of value.\n\t/// If value is zero, -1 will be returned.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/findLSB.xml\">GLSL findLSB man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> findLSB(vec<L, T, Q> const& v);\n\n\t/// Returns the bit number of the most significant bit in the binary representation of value.\n\t/// For positive integers, the result will be the bit number of the most significant bit set to 1.\n\t/// For negative integers, the result will be the bit number of the most significant\n\t/// bit set to 0. For a value of zero or negative one, -1 will be returned.\n\t///\n\t/// @tparam genIUType Signed or unsigned integer scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/findMSB.xml\">GLSL findMSB man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<typename genIUType>\n\tGLM_FUNC_DECL int findMSB(genIUType x);\n\n\t/// Returns the bit number of the most significant bit in the binary representation of value.\n\t/// For positive integers, the result will be the bit number of the most significant bit set to 1.\n\t/// For negative integers, the result will be the bit number of the most significant\n\t/// bit set to 0. For a value of zero or negative one, -1 will be returned.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T Signed or unsigned integer scalar types.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/findMSB.xml\">GLSL findMSB man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, int, Q> findMSB(vec<L, T, Q> const& v);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_integer.inl\"\n"
  },
  {
    "path": "lib/gli/glm/mat2x2.hpp",
    "content": "/// @ref core\n/// @file glm/mat2x2.hpp\n\n#pragma once\n#include \"./ext/matrix_double2x2.hpp\"\n#include \"./ext/matrix_double2x2_precision.hpp\"\n#include \"./ext/matrix_float2x2.hpp\"\n#include \"./ext/matrix_float2x2_precision.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/mat2x3.hpp",
    "content": "/// @ref core\n/// @file glm/mat2x3.hpp\n\n#pragma once\n#include \"./ext/matrix_double2x3.hpp\"\n#include \"./ext/matrix_double2x3_precision.hpp\"\n#include \"./ext/matrix_float2x3.hpp\"\n#include \"./ext/matrix_float2x3_precision.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/mat2x4.hpp",
    "content": "/// @ref core\n/// @file glm/mat2x4.hpp\n\n#pragma once\n#include \"./ext/matrix_double2x4.hpp\"\n#include \"./ext/matrix_double2x4_precision.hpp\"\n#include \"./ext/matrix_float2x4.hpp\"\n#include \"./ext/matrix_float2x4_precision.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/mat3x2.hpp",
    "content": "/// @ref core\n/// @file glm/mat3x2.hpp\n\n#pragma once\n#include \"./ext/matrix_double3x2.hpp\"\n#include \"./ext/matrix_double3x2_precision.hpp\"\n#include \"./ext/matrix_float3x2.hpp\"\n#include \"./ext/matrix_float3x2_precision.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/mat3x3.hpp",
    "content": "/// @ref core\n/// @file glm/mat3x3.hpp\n\n#pragma once\n#include \"./ext/matrix_double3x3.hpp\"\n#include \"./ext/matrix_double3x3_precision.hpp\"\n#include \"./ext/matrix_float3x3.hpp\"\n#include \"./ext/matrix_float3x3_precision.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/mat3x4.hpp",
    "content": "/// @ref core\n/// @file glm/mat3x4.hpp\n\n#pragma once\n#include \"./ext/matrix_double3x4.hpp\"\n#include \"./ext/matrix_double3x4_precision.hpp\"\n#include \"./ext/matrix_float3x4.hpp\"\n#include \"./ext/matrix_float3x4_precision.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/mat4x2.hpp",
    "content": "/// @ref core\n/// @file glm/mat4x2.hpp\n\n#pragma once\n#include \"./ext/matrix_double4x2.hpp\"\n#include \"./ext/matrix_double4x2_precision.hpp\"\n#include \"./ext/matrix_float4x2.hpp\"\n#include \"./ext/matrix_float4x2_precision.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/mat4x3.hpp",
    "content": "/// @ref core\n/// @file glm/mat4x3.hpp\n\n#pragma once\n#include \"./ext/matrix_double4x3.hpp\"\n#include \"./ext/matrix_double4x3_precision.hpp\"\n#include \"./ext/matrix_float4x3.hpp\"\n#include \"./ext/matrix_float4x3_precision.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/mat4x4.hpp",
    "content": "/// @ref core\n/// @file glm/mat4x4.hpp\n\n#pragma once\n#include \"./ext/matrix_double4x4.hpp\"\n#include \"./ext/matrix_double4x4_precision.hpp\"\n#include \"./ext/matrix_float4x4.hpp\"\n#include \"./ext/matrix_float4x4_precision.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/matrix.hpp",
    "content": "/// @ref core\n/// @file glm/matrix.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>\n///\n/// @defgroup core_func_matrix Matrix functions\n/// @ingroup core\n///\n/// Provides GLSL matrix functions.\n///\n/// Include <glm/matrix.hpp> to use these core features.\n\n#pragma once\n\n// Dependencies\n#include \"detail/qualifier.hpp\"\n#include \"detail/setup.hpp\"\n#include \"vec2.hpp\"\n#include \"vec3.hpp\"\n#include \"vec4.hpp\"\n#include \"mat2x2.hpp\"\n#include \"mat2x3.hpp\"\n#include \"mat2x4.hpp\"\n#include \"mat3x2.hpp\"\n#include \"mat3x3.hpp\"\n#include \"mat3x4.hpp\"\n#include \"mat4x2.hpp\"\n#include \"mat4x3.hpp\"\n#include \"mat4x4.hpp\"\n\nnamespace glm {\nnamespace detail\n{\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tstruct outerProduct_trait{};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<2, 2, T, Q>\n\t{\n\t\ttypedef mat<2, 2, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<2, 3, T, Q>\n\t{\n\t\ttypedef mat<3, 2, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<2, 4, T, Q>\n\t{\n\t\ttypedef mat<4, 2, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<3, 2, T, Q>\n\t{\n\t\ttypedef mat<2, 3, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<3, 3, T, Q>\n\t{\n\t\ttypedef mat<3, 3, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<3, 4, T, Q>\n\t{\n\t\ttypedef mat<4, 3, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<4, 2, T, Q>\n\t{\n\t\ttypedef mat<2, 4, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<4, 3, T, Q>\n\t{\n\t\ttypedef mat<3, 4, T, Q> type;\n\t};\n\n\ttemplate<typename T, qualifier Q>\n\tstruct outerProduct_trait<4, 4, T, Q>\n\t{\n\t\ttypedef mat<4, 4, T, Q> type;\n\t};\n}//namespace detail\n\n\t /// @addtogroup core_func_matrix\n\t /// @{\n\n\t /// Multiply matrix x by matrix y component-wise, i.e.,\n\t /// result[i][j] is the scalar product of x[i][j] and y[i][j].\n\t ///\n\t /// @tparam C Integer between 1 and 4 included that qualify the number a column\n\t /// @tparam R Integer between 1 and 4 included that qualify the number a row\n\t /// @tparam T Floating-point or signed integer scalar types\n\t /// @tparam Q Value from qualifier enum\n\t ///\n\t /// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/matrixCompMult.xml\">GLSL matrixCompMult man page</a>\n\t /// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<C, R, T, Q> matrixCompMult(mat<C, R, T, Q> const& x, mat<C, R, T, Q> const& y);\n\n\t/// Treats the first parameter c as a column vector\n\t/// and the second parameter r as a row vector\n\t/// and does a linear algebraic matrix multiply c * r.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number a column\n\t/// @tparam R Integer between 1 and 4 included that qualify the number a row\n\t/// @tparam T Floating-point or signed integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/outerProduct.xml\">GLSL outerProduct man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL typename detail::outerProduct_trait<C, R, T, Q>::type outerProduct(vec<C, T, Q> const& c, vec<R, T, Q> const& r);\n\n\t/// Returns the transposed matrix of x\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number a column\n\t/// @tparam R Integer between 1 and 4 included that qualify the number a row\n\t/// @tparam T Floating-point or signed integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/transpose.xml\">GLSL transpose man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL typename mat<C, R, T, Q>::transpose_type transpose(mat<C, R, T, Q> const& x);\n\n\t/// Return the determinant of a squared matrix.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number a column\n\t/// @tparam R Integer between 1 and 4 included that qualify the number a row\n\t/// @tparam T Floating-point or signed integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/determinant.xml\">GLSL determinant man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL T determinant(mat<C, R, T, Q> const& m);\n\n\t/// Return the inverse of a squared matrix.\n\t///\n\t/// @tparam C Integer between 1 and 4 included that qualify the number a column\n\t/// @tparam R Integer between 1 and 4 included that qualify the number a row\n\t/// @tparam T Floating-point or signed integer scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/inverse.xml\">GLSL inverse man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>\n\ttemplate<length_t C, length_t R, typename T, qualifier Q>\n\tGLM_FUNC_DECL mat<C, R, T, Q> inverse(mat<C, R, T, Q> const& m);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_matrix.inl\"\n"
  },
  {
    "path": "lib/gli/glm/packing.hpp",
    "content": "/// @ref core\n/// @file glm/packing.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n/// @see gtc_packing\n///\n/// @defgroup core_func_packing Floating-Point Pack and Unpack Functions\n/// @ingroup core\n///\n/// Provides GLSL functions to pack and unpack half, single and double-precision floating point values into more compact integer types.\n///\n/// These functions do not operate component-wise, rather as described in each case.\n///\n/// Include <glm/packing.hpp> to use these core features.\n\n#pragma once\n\n#include \"./ext/vector_uint2.hpp\"\n#include \"./ext/vector_float2.hpp\"\n#include \"./ext/vector_float4.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_func_packing\n\t/// @{\n\n\t/// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm2x16: round(clamp(c, 0, +1) * 65535.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm2x16.xml\">GLSL packUnorm2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint packUnorm2x16(vec2 const& v);\n\n\t/// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packSnorm2x16: round(clamp(v, -1, +1) * 32767.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm2x16.xml\">GLSL packSnorm2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint packSnorm2x16(vec2 const& v);\n\n\t/// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packUnorm4x8:\tround(clamp(c, 0, +1) * 255.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml\">GLSL packUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint packUnorm4x8(vec4 const& v);\n\n\t/// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values.\n\t/// Then, the results are packed into the returned 32-bit unsigned integer.\n\t///\n\t/// The conversion for component c of v to fixed point is done as follows:\n\t/// packSnorm4x8:\tround(clamp(c, -1, +1) * 127.0)\n\t///\n\t/// The first component of the vector will be written to the least significant bits of the output;\n\t/// the last component will be written to the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml\">GLSL packSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint packSnorm4x8(vec4 const& v);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackUnorm2x16: f / 65535.0\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm2x16.xml\">GLSL unpackUnorm2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec2 unpackUnorm2x16(uint p);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm2x16: clamp(f / 32767.0, -1, +1)\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm2x16.xml\">GLSL unpackSnorm2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec2 unpackSnorm2x16(uint p);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackUnorm4x8: f / 255.0\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm4x8.xml\">GLSL unpackUnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec4 unpackUnorm4x8(uint p);\n\n\t/// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers.\n\t/// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.\n\t///\n\t/// The conversion for unpacked fixed-point value f to floating point is done as follows:\n\t/// unpackSnorm4x8: clamp(f / 127.0, -1, +1)\n\t///\n\t/// The first component of the returned vector will be extracted from the least significant bits of the input;\n\t/// the last component will be extracted from the most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm4x8.xml\">GLSL unpackSnorm4x8 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec4 unpackSnorm4x8(uint p);\n\n\t/// Returns a double-qualifier value obtained by packing the components of v into a 64-bit value.\n\t/// If an IEEE 754 Inf or NaN is created, it will not signal, and the resulting floating point value is unspecified.\n\t/// Otherwise, the bit- level representation of v is preserved.\n\t/// The first vector component specifies the 32 least significant bits;\n\t/// the second component specifies the 32 most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packDouble2x32.xml\">GLSL packDouble2x32 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL double packDouble2x32(uvec2 const& v);\n\n\t/// Returns a two-component unsigned integer vector representation of v.\n\t/// The bit-level representation of v is preserved.\n\t/// The first component of the vector contains the 32 least significant bits of the double;\n\t/// the second component consists the 32 most significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackDouble2x32.xml\">GLSL unpackDouble2x32 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uvec2 unpackDouble2x32(double v);\n\n\t/// Returns an unsigned integer obtained by converting the components of a two-component floating-point vector\n\t/// to the 16-bit floating-point representation found in the OpenGL Specification,\n\t/// and then packing these two 16- bit integers into a 32-bit unsigned integer.\n\t/// The first vector component specifies the 16 least-significant bits of the result;\n\t/// the second component specifies the 16 most-significant bits.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/packHalf2x16.xml\">GLSL packHalf2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL uint packHalf2x16(vec2 const& v);\n\n\t/// Returns a two-component floating-point vector with components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values,\n\t/// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification,\n\t/// and converting them to 32-bit floating-point values.\n\t/// The first component of the vector is obtained from the 16 least-significant bits of v;\n\t/// the second component is obtained from the 16 most-significant bits of v.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackHalf2x16.xml\">GLSL unpackHalf2x16 man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>\n\tGLM_FUNC_DECL vec2 unpackHalf2x16(uint v);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_packing.inl\"\n"
  },
  {
    "path": "lib/gli/glm/simd/common.h",
    "content": "/// @ref simd\n/// @file glm/simd/common.h\n\n#pragma once\n\n#include \"platform.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_add(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_add_ps(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_add(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_add_ss(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sub(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_sub_ps(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sub(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_sub_ss(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_mul(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_mul_ps(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_mul(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_mul_ss(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_div_ps(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_div(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn _mm_div_ss(a, b);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_div_lowp(glm_f32vec4 a, glm_f32vec4 b)\n{\n\treturn glm_vec4_mul(a, _mm_rcp_ps(b));\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_swizzle_xyzw(glm_f32vec4 a)\n{\n#\tif GLM_ARCH & GLM_ARCH_AVX2_BIT\n\t\treturn _mm_permute_ps(a, _MM_SHUFFLE(3, 2, 1, 0));\n#\telse\n\t\treturn _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0));\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c)\n{\n#\tif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG)\n\t\treturn _mm_fmadd_ss(a, b, c);\n#\telse\n\t\treturn _mm_add_ss(_mm_mul_ss(a, b), c);\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_fma(glm_f32vec4 a, glm_f32vec4 b, glm_f32vec4 c)\n{\n#\tif (GLM_ARCH & GLM_ARCH_AVX2_BIT) && !(GLM_COMPILER & GLM_COMPILER_CLANG)\n\t\treturn _mm_fmadd_ps(a, b, c);\n#\telse\n\t\treturn glm_vec4_add(glm_vec4_mul(a, b), c);\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_abs(glm_f32vec4 x)\n{\n\treturn _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF)));\n}\n\nGLM_FUNC_QUALIFIER glm_ivec4 glm_ivec4_abs(glm_ivec4 x)\n{\n#\tif GLM_ARCH & GLM_ARCH_SSSE3_BIT\n\t\treturn _mm_sign_epi32(x, x);\n#\telse\n\t\tglm_ivec4 const sgn0 = _mm_srai_epi32(x, 31);\n\t\tglm_ivec4 const inv0 = _mm_xor_si128(x, sgn0);\n\t\tglm_ivec4 const sub0 = _mm_sub_epi32(inv0, sgn0);\n\t\treturn sub0;\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sign(glm_vec4 x)\n{\n\tglm_vec4 const zro0 = _mm_setzero_ps();\n\tglm_vec4 const cmp0 = _mm_cmplt_ps(x, zro0);\n\tglm_vec4 const cmp1 = _mm_cmpgt_ps(x, zro0);\n\tglm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(-1.0f));\n\tglm_vec4 const and1 = _mm_and_ps(cmp1, _mm_set1_ps(1.0f));\n\tglm_vec4 const or0 = _mm_or_ps(and0, and1);\n\treturn or0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_round(glm_vec4 x)\n{\n#\tif GLM_ARCH & GLM_ARCH_SSE41_BIT\n\t\treturn _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT);\n#\telse\n\t\tglm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000)));\n\t\tglm_vec4 const and0 = _mm_and_ps(sgn0, x);\n\t\tglm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f));\n\t\tglm_vec4 const add0 = glm_vec4_add(x, or0);\n\t\tglm_vec4 const sub0 = glm_vec4_sub(add0, or0);\n\t\treturn sub0;\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_floor(glm_vec4 x)\n{\n#\tif GLM_ARCH & GLM_ARCH_SSE41_BIT\n\t\treturn _mm_floor_ps(x);\n#\telse\n\t\tglm_vec4 const rnd0 = glm_vec4_round(x);\n\t\tglm_vec4 const cmp0 = _mm_cmplt_ps(x, rnd0);\n\t\tglm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f));\n\t\tglm_vec4 const sub0 = glm_vec4_sub(rnd0, and0);\n\t\treturn sub0;\n#\tendif\n}\n\n/* trunc TODO\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_trunc(glm_vec4 x)\n{\n\treturn glm_vec4();\n}\n*/\n\n//roundEven\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_roundEven(glm_vec4 x)\n{\n\tglm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(int(0x80000000)));\n\tglm_vec4 const and0 = _mm_and_ps(sgn0, x);\n\tglm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f));\n\tglm_vec4 const add0 = glm_vec4_add(x, or0);\n\tglm_vec4 const sub0 = glm_vec4_sub(add0, or0);\n\treturn sub0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_ceil(glm_vec4 x)\n{\n#\tif GLM_ARCH & GLM_ARCH_SSE41_BIT\n\t\treturn _mm_ceil_ps(x);\n#\telse\n\t\tglm_vec4 const rnd0 = glm_vec4_round(x);\n\t\tglm_vec4 const cmp0 = _mm_cmpgt_ps(x, rnd0);\n\t\tglm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f));\n\t\tglm_vec4 const add0 = glm_vec4_add(rnd0, and0);\n\t\treturn add0;\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fract(glm_vec4 x)\n{\n\tglm_vec4 const flr0 = glm_vec4_floor(x);\n\tglm_vec4 const sub0 = glm_vec4_sub(x, flr0);\n\treturn sub0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mod(glm_vec4 x, glm_vec4 y)\n{\n\tglm_vec4 const div0 = glm_vec4_div(x, y);\n\tglm_vec4 const flr0 = glm_vec4_floor(div0);\n\tglm_vec4 const mul0 = glm_vec4_mul(y, flr0);\n\tglm_vec4 const sub0 = glm_vec4_sub(x, mul0);\n\treturn sub0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_clamp(glm_vec4 v, glm_vec4 minVal, glm_vec4 maxVal)\n{\n\tglm_vec4 const min0 = _mm_min_ps(v, maxVal);\n\tglm_vec4 const max0 = _mm_max_ps(min0, minVal);\n\treturn max0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mix(glm_vec4 v1, glm_vec4 v2, glm_vec4 a)\n{\n\tglm_vec4 const sub0 = glm_vec4_sub(_mm_set1_ps(1.0f), a);\n\tglm_vec4 const mul0 = glm_vec4_mul(v1, sub0);\n\tglm_vec4 const mad0 = glm_vec4_fma(v2, a, mul0);\n\treturn mad0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_step(glm_vec4 edge, glm_vec4 x)\n{\n\tglm_vec4 const cmp = _mm_cmple_ps(x, edge);\n\treturn _mm_movemask_ps(cmp) == 0 ? _mm_set1_ps(1.0f) : _mm_setzero_ps();\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_smoothstep(glm_vec4 edge0, glm_vec4 edge1, glm_vec4 x)\n{\n\tglm_vec4 const sub0 = glm_vec4_sub(x, edge0);\n\tglm_vec4 const sub1 = glm_vec4_sub(edge1, edge0);\n\tglm_vec4 const div0 = glm_vec4_sub(sub0, sub1);\n\tglm_vec4 const clp0 = glm_vec4_clamp(div0, _mm_setzero_ps(), _mm_set1_ps(1.0f));\n\tglm_vec4 const mul0 = glm_vec4_mul(_mm_set1_ps(2.0f), clp0);\n\tglm_vec4 const sub2 = glm_vec4_sub(_mm_set1_ps(3.0f), mul0);\n\tglm_vec4 const mul1 = glm_vec4_mul(clp0, clp0);\n\tglm_vec4 const mul2 = glm_vec4_mul(mul1, sub2);\n\treturn mul2;\n}\n\n// Agner Fog method\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_nan(glm_vec4 x)\n{\n\tglm_ivec4 const t1 = _mm_castps_si128(x);\t\t\t\t\t\t// reinterpret as 32-bit integer\n\tglm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1));\t// shift out sign bit\n\tglm_ivec4 const t3 = _mm_set1_epi32(int(0xFF000000));\t\t\t\t// exponent mask\n\tglm_ivec4 const t4 = _mm_and_si128(t2, t3);\t\t\t\t\t\t// exponent\n\tglm_ivec4 const t5 = _mm_andnot_si128(t3, t2);\t\t\t\t\t// fraction\n\tglm_ivec4 const Equal = _mm_cmpeq_epi32(t3, t4);\n\tglm_ivec4 const Nequal = _mm_cmpeq_epi32(t5, _mm_setzero_si128());\n\tglm_ivec4 const And = _mm_and_si128(Equal, Nequal);\n\treturn _mm_castsi128_ps(And);\t\t\t\t\t\t\t\t\t// exponent = all 1s and fraction != 0\n}\n\n// Agner Fog method\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_inf(glm_vec4 x)\n{\n\tglm_ivec4 const t1 = _mm_castps_si128(x);\t\t\t\t\t\t\t\t\t\t// reinterpret as 32-bit integer\n\tglm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1));\t\t\t\t\t// shift out sign bit\n\treturn _mm_castsi128_ps(_mm_cmpeq_epi32(t2, _mm_set1_epi32(int(0xFF000000))));\t\t// exponent is all 1s, fraction is 0\n}\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/exponential.h",
    "content": "/// @ref simd\n/// @file glm/simd/experimental.h\n\n#pragma once\n\n#include \"platform.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec1_sqrt_lowp(glm_f32vec4 x)\n{\n\treturn _mm_mul_ss(_mm_rsqrt_ss(x), x);\n}\n\nGLM_FUNC_QUALIFIER glm_f32vec4 glm_vec4_sqrt_lowp(glm_f32vec4 x)\n{\n\treturn _mm_mul_ps(_mm_rsqrt_ps(x), x);\n}\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/geometric.h",
    "content": "/// @ref simd\n/// @file glm/simd/geometric.h\n\n#pragma once\n\n#include \"common.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nGLM_FUNC_DECL glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2);\nGLM_FUNC_DECL glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2);\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_length(glm_vec4 x)\n{\n\tglm_vec4 const dot0 = glm_vec4_dot(x, x);\n\tglm_vec4 const sqt0 = _mm_sqrt_ps(dot0);\n\treturn sqt0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_distance(glm_vec4 p0, glm_vec4 p1)\n{\n\tglm_vec4 const sub0 = _mm_sub_ps(p0, p1);\n\tglm_vec4 const len0 = glm_vec4_length(sub0);\n\treturn len0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2)\n{\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\t\treturn _mm_dp_ps(v1, v2, 0xff);\n#\telif GLM_ARCH & GLM_ARCH_SSE3_BIT\n\t\tglm_vec4 const mul0 = _mm_mul_ps(v1, v2);\n\t\tglm_vec4 const hadd0 = _mm_hadd_ps(mul0, mul0);\n\t\tglm_vec4 const hadd1 = _mm_hadd_ps(hadd0, hadd0);\n\t\treturn hadd1;\n#\telse\n\t\tglm_vec4 const mul0 = _mm_mul_ps(v1, v2);\n\t\tglm_vec4 const swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1));\n\t\tglm_vec4 const add0 = _mm_add_ps(mul0, swp0);\n\t\tglm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3));\n\t\tglm_vec4 const add1 = _mm_add_ps(add0, swp1);\n\t\treturn add1;\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2)\n{\n#\tif GLM_ARCH & GLM_ARCH_AVX_BIT\n\t\treturn _mm_dp_ps(v1, v2, 0xff);\n#\telif GLM_ARCH & GLM_ARCH_SSE3_BIT\n\t\tglm_vec4 const mul0 = _mm_mul_ps(v1, v2);\n\t\tglm_vec4 const had0 = _mm_hadd_ps(mul0, mul0);\n\t\tglm_vec4 const had1 = _mm_hadd_ps(had0, had0);\n\t\treturn had1;\n#\telse\n\t\tglm_vec4 const mul0 = _mm_mul_ps(v1, v2);\n\t\tglm_vec4 const mov0 = _mm_movehl_ps(mul0, mul0);\n\t\tglm_vec4 const add0 = _mm_add_ps(mov0, mul0);\n\t\tglm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, 1);\n\t\tglm_vec4 const add1 = _mm_add_ss(add0, swp1);\n\t\treturn add1;\n#\tendif\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_cross(glm_vec4 v1, glm_vec4 v2)\n{\n\tglm_vec4 const swp0 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1));\n\tglm_vec4 const swp1 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 1, 0, 2));\n\tglm_vec4 const swp2 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1));\n\tglm_vec4 const swp3 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 1, 0, 2));\n\tglm_vec4 const mul0 = _mm_mul_ps(swp0, swp3);\n\tglm_vec4 const mul1 = _mm_mul_ps(swp1, swp2);\n\tglm_vec4 const sub0 = _mm_sub_ps(mul0, mul1);\n\treturn sub0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_normalize(glm_vec4 v)\n{\n\tglm_vec4 const dot0 = glm_vec4_dot(v, v);\n\tglm_vec4 const isr0 = _mm_rsqrt_ps(dot0);\n\tglm_vec4 const mul0 = _mm_mul_ps(v, isr0);\n\treturn mul0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_faceforward(glm_vec4 N, glm_vec4 I, glm_vec4 Nref)\n{\n\tglm_vec4 const dot0 = glm_vec4_dot(Nref, I);\n\tglm_vec4 const sgn0 = glm_vec4_sign(dot0);\n\tglm_vec4 const mul0 = _mm_mul_ps(sgn0, _mm_set1_ps(-1.0f));\n\tglm_vec4 const mul1 = _mm_mul_ps(N, mul0);\n\treturn mul1;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_vec4_reflect(glm_vec4 I, glm_vec4 N)\n{\n\tglm_vec4 const dot0 = glm_vec4_dot(N, I);\n\tglm_vec4 const mul0 = _mm_mul_ps(N, dot0);\n\tglm_vec4 const mul1 = _mm_mul_ps(mul0, _mm_set1_ps(2.0f));\n\tglm_vec4 const sub0 = _mm_sub_ps(I, mul1);\n\treturn sub0;\n}\n\nGLM_FUNC_QUALIFIER __m128 glm_vec4_refract(glm_vec4 I, glm_vec4 N, glm_vec4 eta)\n{\n\tglm_vec4 const dot0 = glm_vec4_dot(N, I);\n\tglm_vec4 const mul0 = _mm_mul_ps(eta, eta);\n\tglm_vec4 const mul1 = _mm_mul_ps(dot0, dot0);\n\tglm_vec4 const sub0 = _mm_sub_ps(_mm_set1_ps(1.0f), mul0);\n\tglm_vec4 const sub1 = _mm_sub_ps(_mm_set1_ps(1.0f), mul1);\n\tglm_vec4 const mul2 = _mm_mul_ps(sub0, sub1);\n\n\tif(_mm_movemask_ps(_mm_cmplt_ss(mul2, _mm_set1_ps(0.0f))) == 0)\n\t\treturn _mm_set1_ps(0.0f);\n\n\tglm_vec4 const sqt0 = _mm_sqrt_ps(mul2);\n\tglm_vec4 const mad0 = glm_vec4_fma(eta, dot0, sqt0);\n\tglm_vec4 const mul4 = _mm_mul_ps(mad0, N);\n\tglm_vec4 const mul5 = _mm_mul_ps(eta, I);\n\tglm_vec4 const sub2 = _mm_sub_ps(mul5, mul4);\n\n\treturn sub2;\n}\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/integer.h",
    "content": "/// @ref simd\n/// @file glm/simd/integer.h\n\n#pragma once\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nGLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave(glm_uvec4 x)\n{\n\tglm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF);\n\tglm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF);\n\tglm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F);\n\tglm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333);\n\tglm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555);\n\n\tglm_uvec4 Reg1;\n\tglm_uvec4 Reg2;\n\n\t// REG1 = x;\n\t// REG2 = y;\n\t//Reg1 = _mm_unpacklo_epi64(x, y);\n\tReg1 = x;\n\n\t//REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF);\n\t//REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF);\n\tReg2 = _mm_slli_si128(Reg1, 2);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask4);\n\n\t//REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0x00FF00FF00FF00FF);\n\t//REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0x00FF00FF00FF00FF);\n\tReg2 = _mm_slli_si128(Reg1, 1);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask3);\n\n\t//REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F);\n\t//REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F);\n\tReg2 = _mm_slli_epi32(Reg1, 4);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask2);\n\n\t//REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x3333333333333333);\n\t//REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x3333333333333333);\n\tReg2 = _mm_slli_epi32(Reg1, 2);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask1);\n\n\t//REG1 = ((REG1 <<  1) | REG1) & glm::uint64(0x5555555555555555);\n\t//REG2 = ((REG2 <<  1) | REG2) & glm::uint64(0x5555555555555555);\n\tReg2 = _mm_slli_epi32(Reg1, 1);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask0);\n\n\t//return REG1 | (REG2 << 1);\n\tReg2 = _mm_slli_epi32(Reg1, 1);\n\tReg2 = _mm_srli_si128(Reg2, 8);\n\tReg1 = _mm_or_si128(Reg1, Reg2);\n\n\treturn Reg1;\n}\n\nGLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave2(glm_uvec4 x, glm_uvec4 y)\n{\n\tglm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF);\n\tglm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF);\n\tglm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F);\n\tglm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333);\n\tglm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555);\n\n\tglm_uvec4 Reg1;\n\tglm_uvec4 Reg2;\n\n\t// REG1 = x;\n\t// REG2 = y;\n\tReg1 = _mm_unpacklo_epi64(x, y);\n\n\t//REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF);\n\t//REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF);\n\tReg2 = _mm_slli_si128(Reg1, 2);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask4);\n\n\t//REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0x00FF00FF00FF00FF);\n\t//REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0x00FF00FF00FF00FF);\n\tReg2 = _mm_slli_si128(Reg1, 1);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask3);\n\n\t//REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F);\n\t//REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F);\n\tReg2 = _mm_slli_epi32(Reg1, 4);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask2);\n\n\t//REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x3333333333333333);\n\t//REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x3333333333333333);\n\tReg2 = _mm_slli_epi32(Reg1, 2);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask1);\n\n\t//REG1 = ((REG1 <<  1) | REG1) & glm::uint64(0x5555555555555555);\n\t//REG2 = ((REG2 <<  1) | REG2) & glm::uint64(0x5555555555555555);\n\tReg2 = _mm_slli_epi32(Reg1, 1);\n\tReg1 = _mm_or_si128(Reg2, Reg1);\n\tReg1 = _mm_and_si128(Reg1, Mask0);\n\n\t//return REG1 | (REG2 << 1);\n\tReg2 = _mm_slli_epi32(Reg1, 1);\n\tReg2 = _mm_srli_si128(Reg2, 8);\n\tReg1 = _mm_or_si128(Reg1, Reg2);\n\n\treturn Reg1;\n}\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/matrix.h",
    "content": "/// @ref simd\n/// @file glm/simd/matrix.h\n\n#pragma once\n\n#include \"geometric.h\"\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\nGLM_FUNC_QUALIFIER void glm_mat4_matrixCompMult(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])\n{\n\tout[0] = _mm_mul_ps(in1[0], in2[0]);\n\tout[1] = _mm_mul_ps(in1[1], in2[1]);\n\tout[2] = _mm_mul_ps(in1[2], in2[2]);\n\tout[3] = _mm_mul_ps(in1[3], in2[3]);\n}\n\nGLM_FUNC_QUALIFIER void glm_mat4_add(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])\n{\n\tout[0] = _mm_add_ps(in1[0], in2[0]);\n\tout[1] = _mm_add_ps(in1[1], in2[1]);\n\tout[2] = _mm_add_ps(in1[2], in2[2]);\n\tout[3] = _mm_add_ps(in1[3], in2[3]);\n}\n\nGLM_FUNC_QUALIFIER void glm_mat4_sub(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])\n{\n\tout[0] = _mm_sub_ps(in1[0], in2[0]);\n\tout[1] = _mm_sub_ps(in1[1], in2[1]);\n\tout[2] = _mm_sub_ps(in1[2], in2[2]);\n\tout[3] = _mm_sub_ps(in1[3], in2[3]);\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_mat4_mul_vec4(glm_vec4 const m[4], glm_vec4 v)\n{\n\t__m128 v0 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 v1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));\n\t__m128 v2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));\n\t__m128 v3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3));\n\n\t__m128 m0 = _mm_mul_ps(m[0], v0);\n\t__m128 m1 = _mm_mul_ps(m[1], v1);\n\t__m128 m2 = _mm_mul_ps(m[2], v2);\n\t__m128 m3 = _mm_mul_ps(m[3], v3);\n\n\t__m128 a0 = _mm_add_ps(m0, m1);\n\t__m128 a1 = _mm_add_ps(m2, m3);\n\t__m128 a2 = _mm_add_ps(a0, a1);\n\n\treturn a2;\n}\n\nGLM_FUNC_QUALIFIER __m128 glm_vec4_mul_mat4(glm_vec4 v, glm_vec4 const m[4])\n{\n\t__m128 i0 = m[0];\n\t__m128 i1 = m[1];\n\t__m128 i2 = m[2];\n\t__m128 i3 = m[3];\n\n\t__m128 m0 = _mm_mul_ps(v, i0);\n\t__m128 m1 = _mm_mul_ps(v, i1);\n\t__m128 m2 = _mm_mul_ps(v, i2);\n\t__m128 m3 = _mm_mul_ps(v, i3);\n\n\t__m128 u0 = _mm_unpacklo_ps(m0, m1);\n\t__m128 u1 = _mm_unpackhi_ps(m0, m1);\n\t__m128 a0 = _mm_add_ps(u0, u1);\n\n\t__m128 u2 = _mm_unpacklo_ps(m2, m3);\n\t__m128 u3 = _mm_unpackhi_ps(m2, m3);\n\t__m128 a1 = _mm_add_ps(u2, u3);\n\n\t__m128 f0 = _mm_movelh_ps(a0, a1);\n\t__m128 f1 = _mm_movehl_ps(a1, a0);\n\t__m128 f2 = _mm_add_ps(f0, f1);\n\n\treturn f2;\n}\n\nGLM_FUNC_QUALIFIER void glm_mat4_mul(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])\n{\n\t{\n\t\t__m128 e0 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 e1 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 e2 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 e3 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 m0 = _mm_mul_ps(in1[0], e0);\n\t\t__m128 m1 = _mm_mul_ps(in1[1], e1);\n\t\t__m128 m2 = _mm_mul_ps(in1[2], e2);\n\t\t__m128 m3 = _mm_mul_ps(in1[3], e3);\n\n\t\t__m128 a0 = _mm_add_ps(m0, m1);\n\t\t__m128 a1 = _mm_add_ps(m2, m3);\n\t\t__m128 a2 = _mm_add_ps(a0, a1);\n\n\t\tout[0] = a2;\n\t}\n\n\t{\n\t\t__m128 e0 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 e1 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 e2 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 e3 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 m0 = _mm_mul_ps(in1[0], e0);\n\t\t__m128 m1 = _mm_mul_ps(in1[1], e1);\n\t\t__m128 m2 = _mm_mul_ps(in1[2], e2);\n\t\t__m128 m3 = _mm_mul_ps(in1[3], e3);\n\n\t\t__m128 a0 = _mm_add_ps(m0, m1);\n\t\t__m128 a1 = _mm_add_ps(m2, m3);\n\t\t__m128 a2 = _mm_add_ps(a0, a1);\n\n\t\tout[1] = a2;\n\t}\n\n\t{\n\t\t__m128 e0 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 e1 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 e2 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 e3 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 m0 = _mm_mul_ps(in1[0], e0);\n\t\t__m128 m1 = _mm_mul_ps(in1[1], e1);\n\t\t__m128 m2 = _mm_mul_ps(in1[2], e2);\n\t\t__m128 m3 = _mm_mul_ps(in1[3], e3);\n\n\t\t__m128 a0 = _mm_add_ps(m0, m1);\n\t\t__m128 a1 = _mm_add_ps(m2, m3);\n\t\t__m128 a2 = _mm_add_ps(a0, a1);\n\n\t\tout[2] = a2;\n\t}\n\n\t{\n\t\t//(__m128&)_mm_shuffle_epi32(__m128i&)in2[0], _MM_SHUFFLE(3, 3, 3, 3))\n\t\t__m128 e0 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 e1 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 e2 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 e3 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 m0 = _mm_mul_ps(in1[0], e0);\n\t\t__m128 m1 = _mm_mul_ps(in1[1], e1);\n\t\t__m128 m2 = _mm_mul_ps(in1[2], e2);\n\t\t__m128 m3 = _mm_mul_ps(in1[3], e3);\n\n\t\t__m128 a0 = _mm_add_ps(m0, m1);\n\t\t__m128 a1 = _mm_add_ps(m2, m3);\n\t\t__m128 a2 = _mm_add_ps(a0, a1);\n\n\t\tout[3] = a2;\n\t}\n}\n\nGLM_FUNC_QUALIFIER void glm_mat4_transpose(glm_vec4 const in[4], glm_vec4 out[4])\n{\n\t__m128 tmp0 = _mm_shuffle_ps(in[0], in[1], 0x44);\n\t__m128 tmp2 = _mm_shuffle_ps(in[0], in[1], 0xEE);\n\t__m128 tmp1 = _mm_shuffle_ps(in[2], in[3], 0x44);\n\t__m128 tmp3 = _mm_shuffle_ps(in[2], in[3], 0xEE);\n\n\tout[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88);\n\tout[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD);\n\tout[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88);\n\tout[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD);\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_highp(glm_vec4 const in[4])\n{\n\t__m128 Fac0;\n\t{\n\t\t//\tvalType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t//\tvalType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t//\tvalType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];\n\t\t//\tvalType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac0 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac1;\n\t{\n\t\t//\tvalType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t//\tvalType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t//\tvalType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];\n\t\t//\tvalType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac1 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\n\t__m128 Fac2;\n\t{\n\t\t//\tvalType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t//\tvalType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t//\tvalType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];\n\t\t//\tvalType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac2 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac3;\n\t{\n\t\t//\tvalType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t//\tvalType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t//\tvalType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];\n\t\t//\tvalType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac3 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac4;\n\t{\n\t\t//\tvalType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t//\tvalType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t//\tvalType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];\n\t\t//\tvalType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac4 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac5;\n\t{\n\t\t//\tvalType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t//\tvalType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t//\tvalType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];\n\t\t//\tvalType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac5 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);\n\t__m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);\n\n\t// m[1][0]\n\t// m[0][0]\n\t// m[0][0]\n\t// m[0][0]\n\t__m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][1]\n\t// m[0][1]\n\t// m[0][1]\n\t// m[0][1]\n\t__m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1));\n\t__m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][2]\n\t// m[0][2]\n\t// m[0][2]\n\t// m[0][2]\n\t__m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2));\n\t__m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][3]\n\t// m[0][3]\n\t// m[0][3]\n\t// m[0][3]\n\t__m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3));\n\t__m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// col0\n\t// + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]),\n\t// - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]),\n\t// + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]),\n\t// - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]),\n\t__m128 Mul00 = _mm_mul_ps(Vec1, Fac0);\n\t__m128 Mul01 = _mm_mul_ps(Vec2, Fac1);\n\t__m128 Mul02 = _mm_mul_ps(Vec3, Fac2);\n\t__m128 Sub00 = _mm_sub_ps(Mul00, Mul01);\n\t__m128 Add00 = _mm_add_ps(Sub00, Mul02);\n\t__m128 Inv0 = _mm_mul_ps(SignB, Add00);\n\n\t// col1\n\t// - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]),\n\t// + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]),\n\t// - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]),\n\t// + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]),\n\t__m128 Mul03 = _mm_mul_ps(Vec0, Fac0);\n\t__m128 Mul04 = _mm_mul_ps(Vec2, Fac3);\n\t__m128 Mul05 = _mm_mul_ps(Vec3, Fac4);\n\t__m128 Sub01 = _mm_sub_ps(Mul03, Mul04);\n\t__m128 Add01 = _mm_add_ps(Sub01, Mul05);\n\t__m128 Inv1 = _mm_mul_ps(SignA, Add01);\n\n\t// col2\n\t// + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]),\n\t// - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]),\n\t// + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]),\n\t// - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]),\n\t__m128 Mul06 = _mm_mul_ps(Vec0, Fac1);\n\t__m128 Mul07 = _mm_mul_ps(Vec1, Fac3);\n\t__m128 Mul08 = _mm_mul_ps(Vec3, Fac5);\n\t__m128 Sub02 = _mm_sub_ps(Mul06, Mul07);\n\t__m128 Add02 = _mm_add_ps(Sub02, Mul08);\n\t__m128 Inv2 = _mm_mul_ps(SignB, Add02);\n\n\t// col3\n\t// - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]),\n\t// + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]),\n\t// - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]),\n\t// + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3]));\n\t__m128 Mul09 = _mm_mul_ps(Vec0, Fac2);\n\t__m128 Mul10 = _mm_mul_ps(Vec1, Fac4);\n\t__m128 Mul11 = _mm_mul_ps(Vec2, Fac5);\n\t__m128 Sub03 = _mm_sub_ps(Mul09, Mul10);\n\t__m128 Add03 = _mm_add_ps(Sub03, Mul11);\n\t__m128 Inv3 = _mm_mul_ps(SignA, Add03);\n\n\t__m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));\n\n\t//\tvalType Determinant = m[0][0] * Inverse[0][0]\n\t//\t\t\t\t\t\t+ m[0][1] * Inverse[1][0]\n\t//\t\t\t\t\t\t+ m[0][2] * Inverse[2][0]\n\t//\t\t\t\t\t\t+ m[0][3] * Inverse[3][0];\n\t__m128 Det0 = glm_vec4_dot(in[0], Row2);\n\treturn Det0;\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_lowp(glm_vec4 const m[4])\n{\n\t// _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(\n\n\t//T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t//T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t//T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t//T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t//T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t//T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\n\t// First 2 columns\n \t__m128 Swp2A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 1, 1, 2)));\n \t__m128 Swp3A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(3, 2, 3, 3)));\n\t__m128 MulA = _mm_mul_ps(Swp2A, Swp3A);\n\n\t// Second 2 columns\n\t__m128 Swp2B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(3, 2, 3, 3)));\n\t__m128 Swp3B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(0, 1, 1, 2)));\n\t__m128 MulB = _mm_mul_ps(Swp2B, Swp3B);\n\n\t// Columns subtraction\n\t__m128 SubE = _mm_sub_ps(MulA, MulB);\n\n\t// Last 2 rows\n\t__m128 Swp2C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 0, 1, 2)));\n\t__m128 Swp3C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(1, 2, 0, 0)));\n\t__m128 MulC = _mm_mul_ps(Swp2C, Swp3C);\n\t__m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC);\n\n\t//vec<4, T, Q> DetCof(\n\t//\t+ (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),\n\t//\t- (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),\n\t//\t+ (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),\n\t//\t- (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));\n\n\t__m128 SubFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubE), _MM_SHUFFLE(2, 1, 0, 0)));\n\t__m128 SwpFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(0, 0, 0, 1)));\n\t__m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA);\n\n\t__m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1));\n\t__m128 SubFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpB), _MM_SHUFFLE(3, 1, 1, 0)));//SubF[0], SubE[3], SubE[3], SubE[1];\n\t__m128 SwpFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(1, 1, 2, 2)));\n\t__m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB);\n\n\t__m128 SubRes = _mm_sub_ps(MulFacA, MulFacB);\n\n\t__m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2));\n\t__m128 SubFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpC), _MM_SHUFFLE(3, 3, 2, 0)));\n\t__m128 SwpFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(2, 3, 3, 3)));\n\t__m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC);\n\n\t__m128 AddRes = _mm_add_ps(SubRes, MulFacC);\n\t__m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f));\n\n\t//return m[0][0] * DetCof[0]\n\t//\t + m[0][1] * DetCof[1]\n\t//\t + m[0][2] * DetCof[2]\n\t//\t + m[0][3] * DetCof[3];\n\n\treturn glm_vec4_dot(m[0], DetCof);\n}\n\nGLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant(glm_vec4 const m[4])\n{\n\t// _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(add)\n\n\t//T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t//T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t//T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t//T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t//T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t//T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\n\t// First 2 columns\n \t__m128 Swp2A = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 1, 1, 2));\n \t__m128 Swp3A = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(3, 2, 3, 3));\n\t__m128 MulA = _mm_mul_ps(Swp2A, Swp3A);\n\n\t// Second 2 columns\n\t__m128 Swp2B = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(3, 2, 3, 3));\n\t__m128 Swp3B = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(0, 1, 1, 2));\n\t__m128 MulB = _mm_mul_ps(Swp2B, Swp3B);\n\n\t// Columns subtraction\n\t__m128 SubE = _mm_sub_ps(MulA, MulB);\n\n\t// Last 2 rows\n\t__m128 Swp2C = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 0, 1, 2));\n\t__m128 Swp3C = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(1, 2, 0, 0));\n\t__m128 MulC = _mm_mul_ps(Swp2C, Swp3C);\n\t__m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC);\n\n\t//vec<4, T, Q> DetCof(\n\t//\t+ (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),\n\t//\t- (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),\n\t//\t+ (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),\n\t//\t- (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));\n\n\t__m128 SubFacA = _mm_shuffle_ps(SubE, SubE, _MM_SHUFFLE(2, 1, 0, 0));\n\t__m128 SwpFacA = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(0, 0, 0, 1));\n\t__m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA);\n\n\t__m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1));\n\t__m128 SubFacB = _mm_shuffle_ps(SubTmpB, SubTmpB, _MM_SHUFFLE(3, 1, 1, 0));//SubF[0], SubE[3], SubE[3], SubE[1];\n\t__m128 SwpFacB = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(1, 1, 2, 2));\n\t__m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB);\n\n\t__m128 SubRes = _mm_sub_ps(MulFacA, MulFacB);\n\n\t__m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2));\n\t__m128 SubFacC = _mm_shuffle_ps(SubTmpC, SubTmpC, _MM_SHUFFLE(3, 3, 2, 0));\n\t__m128 SwpFacC = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(2, 3, 3, 3));\n\t__m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC);\n\n\t__m128 AddRes = _mm_add_ps(SubRes, MulFacC);\n\t__m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f));\n\n\t//return m[0][0] * DetCof[0]\n\t//\t + m[0][1] * DetCof[1]\n\t//\t + m[0][2] * DetCof[2]\n\t//\t + m[0][3] * DetCof[3];\n\n\treturn glm_vec4_dot(m[0], DetCof);\n}\n\nGLM_FUNC_QUALIFIER void glm_mat4_inverse(glm_vec4 const in[4], glm_vec4 out[4])\n{\n\t__m128 Fac0;\n\t{\n\t\t//\tvalType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t//\tvalType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t//\tvalType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];\n\t\t//\tvalType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac0 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac1;\n\t{\n\t\t//\tvalType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t//\tvalType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t//\tvalType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];\n\t\t//\tvalType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac1 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\n\t__m128 Fac2;\n\t{\n\t\t//\tvalType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t//\tvalType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t//\tvalType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];\n\t\t//\tvalType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac2 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac3;\n\t{\n\t\t//\tvalType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t//\tvalType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t//\tvalType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];\n\t\t//\tvalType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac3 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac4;\n\t{\n\t\t//\tvalType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t//\tvalType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t//\tvalType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];\n\t\t//\tvalType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac4 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac5;\n\t{\n\t\t//\tvalType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t//\tvalType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t//\tvalType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];\n\t\t//\tvalType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac5 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);\n\t__m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);\n\n\t// m[1][0]\n\t// m[0][0]\n\t// m[0][0]\n\t// m[0][0]\n\t__m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][1]\n\t// m[0][1]\n\t// m[0][1]\n\t// m[0][1]\n\t__m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1));\n\t__m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][2]\n\t// m[0][2]\n\t// m[0][2]\n\t// m[0][2]\n\t__m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2));\n\t__m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][3]\n\t// m[0][3]\n\t// m[0][3]\n\t// m[0][3]\n\t__m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3));\n\t__m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// col0\n\t// + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]),\n\t// - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]),\n\t// + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]),\n\t// - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]),\n\t__m128 Mul00 = _mm_mul_ps(Vec1, Fac0);\n\t__m128 Mul01 = _mm_mul_ps(Vec2, Fac1);\n\t__m128 Mul02 = _mm_mul_ps(Vec3, Fac2);\n\t__m128 Sub00 = _mm_sub_ps(Mul00, Mul01);\n\t__m128 Add00 = _mm_add_ps(Sub00, Mul02);\n\t__m128 Inv0 = _mm_mul_ps(SignB, Add00);\n\n\t// col1\n\t// - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]),\n\t// + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]),\n\t// - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]),\n\t// + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]),\n\t__m128 Mul03 = _mm_mul_ps(Vec0, Fac0);\n\t__m128 Mul04 = _mm_mul_ps(Vec2, Fac3);\n\t__m128 Mul05 = _mm_mul_ps(Vec3, Fac4);\n\t__m128 Sub01 = _mm_sub_ps(Mul03, Mul04);\n\t__m128 Add01 = _mm_add_ps(Sub01, Mul05);\n\t__m128 Inv1 = _mm_mul_ps(SignA, Add01);\n\n\t// col2\n\t// + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]),\n\t// - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]),\n\t// + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]),\n\t// - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]),\n\t__m128 Mul06 = _mm_mul_ps(Vec0, Fac1);\n\t__m128 Mul07 = _mm_mul_ps(Vec1, Fac3);\n\t__m128 Mul08 = _mm_mul_ps(Vec3, Fac5);\n\t__m128 Sub02 = _mm_sub_ps(Mul06, Mul07);\n\t__m128 Add02 = _mm_add_ps(Sub02, Mul08);\n\t__m128 Inv2 = _mm_mul_ps(SignB, Add02);\n\n\t// col3\n\t// - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]),\n\t// + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]),\n\t// - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]),\n\t// + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3]));\n\t__m128 Mul09 = _mm_mul_ps(Vec0, Fac2);\n\t__m128 Mul10 = _mm_mul_ps(Vec1, Fac4);\n\t__m128 Mul11 = _mm_mul_ps(Vec2, Fac5);\n\t__m128 Sub03 = _mm_sub_ps(Mul09, Mul10);\n\t__m128 Add03 = _mm_add_ps(Sub03, Mul11);\n\t__m128 Inv3 = _mm_mul_ps(SignA, Add03);\n\n\t__m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));\n\n\t//\tvalType Determinant = m[0][0] * Inverse[0][0]\n\t//\t\t\t\t\t\t+ m[0][1] * Inverse[1][0]\n\t//\t\t\t\t\t\t+ m[0][2] * Inverse[2][0]\n\t//\t\t\t\t\t\t+ m[0][3] * Inverse[3][0];\n\t__m128 Det0 = glm_vec4_dot(in[0], Row2);\n\t__m128 Rcp0 = _mm_div_ps(_mm_set1_ps(1.0f), Det0);\n\t//__m128 Rcp0 = _mm_rcp_ps(Det0);\n\n\t//\tInverse /= Determinant;\n\tout[0] = _mm_mul_ps(Inv0, Rcp0);\n\tout[1] = _mm_mul_ps(Inv1, Rcp0);\n\tout[2] = _mm_mul_ps(Inv2, Rcp0);\n\tout[3] = _mm_mul_ps(Inv3, Rcp0);\n}\n\nGLM_FUNC_QUALIFIER void glm_mat4_inverse_lowp(glm_vec4 const in[4], glm_vec4 out[4])\n{\n\t__m128 Fac0;\n\t{\n\t\t//\tvalType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t//\tvalType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];\n\t\t//\tvalType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];\n\t\t//\tvalType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac0 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac1;\n\t{\n\t\t//\tvalType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t//\tvalType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];\n\t\t//\tvalType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];\n\t\t//\tvalType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac1 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\n\t__m128 Fac2;\n\t{\n\t\t//\tvalType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t//\tvalType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];\n\t\t//\tvalType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];\n\t\t//\tvalType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac2 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac3;\n\t{\n\t\t//\tvalType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t//\tvalType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];\n\t\t//\tvalType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];\n\t\t//\tvalType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac3 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac4;\n\t{\n\t\t//\tvalType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t//\tvalType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];\n\t\t//\tvalType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];\n\t\t//\tvalType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac4 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 Fac5;\n\t{\n\t\t//\tvalType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t//\tvalType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];\n\t\t//\tvalType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];\n\t\t//\tvalType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];\n\n\t\t__m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));\n\t\t__m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));\n\n\t\t__m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));\n\t\t__m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));\n\t\t__m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));\n\n\t\t__m128 Mul00 = _mm_mul_ps(Swp00, Swp01);\n\t\t__m128 Mul01 = _mm_mul_ps(Swp02, Swp03);\n\t\tFac5 = _mm_sub_ps(Mul00, Mul01);\n\t}\n\n\t__m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);\n\t__m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);\n\n\t// m[1][0]\n\t// m[0][0]\n\t// m[0][0]\n\t// m[0][0]\n\t__m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][1]\n\t// m[0][1]\n\t// m[0][1]\n\t// m[0][1]\n\t__m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1));\n\t__m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][2]\n\t// m[0][2]\n\t// m[0][2]\n\t// m[0][2]\n\t__m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2));\n\t__m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// m[1][3]\n\t// m[0][3]\n\t// m[0][3]\n\t// m[0][3]\n\t__m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3));\n\t__m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));\n\n\t// col0\n\t// + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]),\n\t// - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]),\n\t// + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]),\n\t// - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]),\n\t__m128 Mul00 = _mm_mul_ps(Vec1, Fac0);\n\t__m128 Mul01 = _mm_mul_ps(Vec2, Fac1);\n\t__m128 Mul02 = _mm_mul_ps(Vec3, Fac2);\n\t__m128 Sub00 = _mm_sub_ps(Mul00, Mul01);\n\t__m128 Add00 = _mm_add_ps(Sub00, Mul02);\n\t__m128 Inv0 = _mm_mul_ps(SignB, Add00);\n\n\t// col1\n\t// - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]),\n\t// + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]),\n\t// - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]),\n\t// + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]),\n\t__m128 Mul03 = _mm_mul_ps(Vec0, Fac0);\n\t__m128 Mul04 = _mm_mul_ps(Vec2, Fac3);\n\t__m128 Mul05 = _mm_mul_ps(Vec3, Fac4);\n\t__m128 Sub01 = _mm_sub_ps(Mul03, Mul04);\n\t__m128 Add01 = _mm_add_ps(Sub01, Mul05);\n\t__m128 Inv1 = _mm_mul_ps(SignA, Add01);\n\n\t// col2\n\t// + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]),\n\t// - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]),\n\t// + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]),\n\t// - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]),\n\t__m128 Mul06 = _mm_mul_ps(Vec0, Fac1);\n\t__m128 Mul07 = _mm_mul_ps(Vec1, Fac3);\n\t__m128 Mul08 = _mm_mul_ps(Vec3, Fac5);\n\t__m128 Sub02 = _mm_sub_ps(Mul06, Mul07);\n\t__m128 Add02 = _mm_add_ps(Sub02, Mul08);\n\t__m128 Inv2 = _mm_mul_ps(SignB, Add02);\n\n\t// col3\n\t// - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]),\n\t// + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]),\n\t// - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]),\n\t// + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3]));\n\t__m128 Mul09 = _mm_mul_ps(Vec0, Fac2);\n\t__m128 Mul10 = _mm_mul_ps(Vec1, Fac4);\n\t__m128 Mul11 = _mm_mul_ps(Vec2, Fac5);\n\t__m128 Sub03 = _mm_sub_ps(Mul09, Mul10);\n\t__m128 Add03 = _mm_add_ps(Sub03, Mul11);\n\t__m128 Inv3 = _mm_mul_ps(SignA, Add03);\n\n\t__m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));\n\n\t//\tvalType Determinant = m[0][0] * Inverse[0][0]\n\t//\t\t\t\t\t\t+ m[0][1] * Inverse[1][0]\n\t//\t\t\t\t\t\t+ m[0][2] * Inverse[2][0]\n\t//\t\t\t\t\t\t+ m[0][3] * Inverse[3][0];\n\t__m128 Det0 = glm_vec4_dot(in[0], Row2);\n\t__m128 Rcp0 = _mm_rcp_ps(Det0);\n\t//__m128 Rcp0 = _mm_div_ps(one, Det0);\n\t//\tInverse /= Determinant;\n\tout[0] = _mm_mul_ps(Inv0, Rcp0);\n\tout[1] = _mm_mul_ps(Inv1, Rcp0);\n\tout[2] = _mm_mul_ps(Inv2, Rcp0);\n\tout[3] = _mm_mul_ps(Inv3, Rcp0);\n}\n/*\nGLM_FUNC_QUALIFIER void glm_mat4_rotate(__m128 const in[4], float Angle, float const v[3], __m128 out[4])\n{\n\tfloat a = glm::radians(Angle);\n\tfloat c = cos(a);\n\tfloat s = sin(a);\n\n\tglm::vec4 AxisA(v[0], v[1], v[2], float(0));\n\t__m128 AxisB = _mm_set_ps(AxisA.w, AxisA.z, AxisA.y, AxisA.x);\n\t__m128 AxisC = detail::sse_nrm_ps(AxisB);\n\n\t__m128 Cos0 = _mm_set_ss(c);\n\t__m128 CosA = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 Sin0 = _mm_set_ss(s);\n\t__m128 SinA = _mm_shuffle_ps(Sin0, Sin0, _MM_SHUFFLE(0, 0, 0, 0));\n\n\t// vec<3, T, Q> temp = (valType(1) - c) * axis;\n\t__m128 Temp0 = _mm_sub_ps(one, CosA);\n\t__m128 Temp1 = _mm_mul_ps(Temp0, AxisC);\n\n\t//Rotate[0][0] = c + temp[0] * axis[0];\n\t//Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];\n\t//Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];\n\t__m128 Axis0 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(0, 0, 0, 0));\n\t__m128 TmpA0 = _mm_mul_ps(Axis0, AxisC);\n\t__m128 CosA0 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 1, 0));\n\t__m128 TmpA1 = _mm_add_ps(CosA0, TmpA0);\n\t__m128 SinA0 = SinA;//_mm_set_ps(0.0f, s, -s, 0.0f);\n\t__m128 TmpA2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 1, 2, 3));\n\t__m128 TmpA3 = _mm_mul_ps(SinA0, TmpA2);\n\t__m128 TmpA4 = _mm_add_ps(TmpA1, TmpA3);\n\n\t//Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];\n\t//Rotate[1][1] = c + temp[1] * axis[1];\n\t//Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];\n\t__m128 Axis1 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(1, 1, 1, 1));\n\t__m128 TmpB0 = _mm_mul_ps(Axis1, AxisC);\n\t__m128 CosA1 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 0, 1));\n\t__m128 TmpB1 = _mm_add_ps(CosA1, TmpB0);\n\t__m128 SinB0 = SinA;//_mm_set_ps(-s, 0.0f, s, 0.0f);\n\t__m128 TmpB2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 0, 3, 2));\n\t__m128 TmpB3 = _mm_mul_ps(SinA0, TmpB2);\n\t__m128 TmpB4 = _mm_add_ps(TmpB1, TmpB3);\n\n\t//Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];\n\t//Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];\n\t//Rotate[2][2] = c + temp[2] * axis[2];\n\t__m128 Axis2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(2, 2, 2, 2));\n\t__m128 TmpC0 = _mm_mul_ps(Axis2, AxisC);\n\t__m128 CosA2 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 0, 1, 1));\n\t__m128 TmpC1 = _mm_add_ps(CosA2, TmpC0);\n\t__m128 SinC0 = SinA;//_mm_set_ps(s, -s, 0.0f, 0.0f);\n\t__m128 TmpC2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 3, 0, 1));\n\t__m128 TmpC3 = _mm_mul_ps(SinA0, TmpC2);\n\t__m128 TmpC4 = _mm_add_ps(TmpC1, TmpC3);\n\n\t__m128 Result[4];\n\tResult[0] = TmpA4;\n\tResult[1] = TmpB4;\n\tResult[2] = TmpC4;\n\tResult[3] = _mm_set_ps(1, 0, 0, 0);\n\n\t//mat<4, 4, valType> Result;\n\t//Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];\n\t//Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];\n\t//Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];\n\t//Result[3] = m[3];\n\t//return Result;\n\tsse_mul_ps(in, Result, out);\n}\n*/\nGLM_FUNC_QUALIFIER void glm_mat4_outerProduct(__m128 const& c, __m128 const& r, __m128 out[4])\n{\n\tout[0] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(0, 0, 0, 0)));\n\tout[1] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(1, 1, 1, 1)));\n\tout[2] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(2, 2, 2, 2)));\n\tout[3] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 3, 3, 3)));\n}\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/neon.h",
    "content": "/// @ref simd_neon\n/// @file glm/simd/neon.h\n\n#pragma once\n\n#if GLM_ARCH & GLM_ARCH_NEON_BIT\n#include <arm_neon.h>\n\nnamespace glm {\n\tnamespace neon {\n\t\tstatic inline float32x4_t dupq_lane(float32x4_t vsrc, int lane) {\n\t\t\tswitch(lane) {\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\t\tcase 0: return vdupq_laneq_f32(vsrc, 0);\n\t\t\t\tcase 1: return vdupq_laneq_f32(vsrc, 1);\n\t\t\t\tcase 2: return vdupq_laneq_f32(vsrc, 2);\n\t\t\t\tcase 3: return vdupq_laneq_f32(vsrc, 3);\n#else\n\t\t\t\tcase 0: return vdupq_n_f32(vgetq_lane_f32(vsrc, 0));\n\t\t\t\tcase 1: return vdupq_n_f32(vgetq_lane_f32(vsrc, 1));\n\t\t\t\tcase 2: return vdupq_n_f32(vgetq_lane_f32(vsrc, 2));\n\t\t\t\tcase 3: return vdupq_n_f32(vgetq_lane_f32(vsrc, 3));\n#endif\n\t\t\t}\n\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\treturn vdupq_n_f32(0.0f);\n\t\t}\n\n\t\tstatic inline float32x2_t dup_lane(float32x4_t vsrc, int lane) {\n\t\t\tswitch(lane) {\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\t\tcase 0: return vdup_laneq_f32(vsrc, 0);\n\t\t\t\tcase 1: return vdup_laneq_f32(vsrc, 1);\n\t\t\t\tcase 2: return vdup_laneq_f32(vsrc, 2);\n\t\t\t\tcase 3: return vdup_laneq_f32(vsrc, 3);\n#else\n\t\t\t\tcase 0: return vdup_n_f32(vgetq_lane_f32(vsrc, 0));\n\t\t\t\tcase 1: return vdup_n_f32(vgetq_lane_f32(vsrc, 1));\n\t\t\t\tcase 2: return vdup_n_f32(vgetq_lane_f32(vsrc, 2));\n\t\t\t\tcase 3: return vdup_n_f32(vgetq_lane_f32(vsrc, 3));\n#endif\n\t\t\t}\n\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\treturn vdup_n_f32(0.0f);\n\t\t}\n\n\t\tstatic inline float32x4_t copy_lane(float32x4_t vdst, int dlane, float32x4_t vsrc, int slane) {\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tswitch(dlane) {\n\t\t\t\tcase 0:\n\t\t\t\t\tswitch(slane) {\n\t\t\t\t\t\tcase 0: return vcopyq_laneq_f32(vdst, 0, vsrc, 0);\n\t\t\t\t\t\tcase 1: return vcopyq_laneq_f32(vdst, 0, vsrc, 1);\n\t\t\t\t\t\tcase 2: return vcopyq_laneq_f32(vdst, 0, vsrc, 2);\n\t\t\t\t\t\tcase 3: return vcopyq_laneq_f32(vdst, 0, vsrc, 3);\n\t\t\t\t\t}\n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t\tcase 1:\n\t\t\t\t\tswitch(slane) {\n\t\t\t\t\t\tcase 0: return vcopyq_laneq_f32(vdst, 1, vsrc, 0);\n\t\t\t\t\t\tcase 1: return vcopyq_laneq_f32(vdst, 1, vsrc, 1);\n\t\t\t\t\t\tcase 2: return vcopyq_laneq_f32(vdst, 1, vsrc, 2);\n\t\t\t\t\t\tcase 3: return vcopyq_laneq_f32(vdst, 1, vsrc, 3);\n\t\t\t\t\t}\n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t\tcase 2:\n\t\t\t\t\tswitch(slane) {\n\t\t\t\t\t\tcase 0: return vcopyq_laneq_f32(vdst, 2, vsrc, 0);\n\t\t\t\t\t\tcase 1: return vcopyq_laneq_f32(vdst, 2, vsrc, 1);\n\t\t\t\t\t\tcase 2: return vcopyq_laneq_f32(vdst, 2, vsrc, 2);\n\t\t\t\t\t\tcase 3: return vcopyq_laneq_f32(vdst, 2, vsrc, 3);\n\t\t\t\t\t}\n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t\tcase 3:\n\t\t\t\t\tswitch(slane) {\n\t\t\t\t\t\tcase 0: return vcopyq_laneq_f32(vdst, 3, vsrc, 0);\n\t\t\t\t\t\tcase 1: return vcopyq_laneq_f32(vdst, 3, vsrc, 1);\n\t\t\t\t\t\tcase 2: return vcopyq_laneq_f32(vdst, 3, vsrc, 2);\n\t\t\t\t\t\tcase 3: return vcopyq_laneq_f32(vdst, 3, vsrc, 3);\n\t\t\t\t\t}\n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t}\n#else\n\n\t\t\tfloat l;\n\t\t\tswitch(slane) {\n\t\t\t\tcase 0: l = vgetq_lane_f32(vsrc, 0); break;\n\t\t\t\tcase 1: l = vgetq_lane_f32(vsrc, 1); break;\n\t\t\t\tcase 2: l = vgetq_lane_f32(vsrc, 2); break;\n\t\t\t\tcase 3: l = vgetq_lane_f32(vsrc, 3); break;\n\t\t\t\tdefault: \n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t}\n\t\t\tswitch(dlane) {\n\t\t\t\tcase 0: return vsetq_lane_f32(l, vdst, 0);\n\t\t\t\tcase 1: return vsetq_lane_f32(l, vdst, 1);\n\t\t\t\tcase 2: return vsetq_lane_f32(l, vdst, 2);\n\t\t\t\tcase 3: return vsetq_lane_f32(l, vdst, 3);\n\t\t\t}\n#endif\n\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\treturn vdupq_n_f32(0.0f);\n\t\t}\n\n\t\tstatic inline float32x4_t mul_lane(float32x4_t v, float32x4_t vlane, int lane) {\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n\t\t\tswitch(lane) { \n\t\t\t\tcase 0: return vmulq_laneq_f32(v, vlane, 0); break;\n\t\t\t\tcase 1: return vmulq_laneq_f32(v, vlane, 1); break;\n\t\t\t\tcase 2: return vmulq_laneq_f32(v, vlane, 2); break;\n\t\t\t\tcase 3: return vmulq_laneq_f32(v, vlane, 3); break;\n\t\t\t\tdefault: \n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t}\n\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\treturn vdupq_n_f32(0.0f);\n#else\n\t\t\treturn vmulq_f32(v, dupq_lane(vlane, lane));\n#endif\n\t\t}\n\n\t\tstatic inline float32x4_t madd_lane(float32x4_t acc, float32x4_t v, float32x4_t vlane, int lane) {\n#if GLM_ARCH & GLM_ARCH_ARMV8_BIT\n#ifdef GLM_CONFIG_FORCE_FMA\n#\tdefine FMADD_LANE(acc, x, y, L) do { asm volatile (\"fmla %0.4s, %1.4s, %2.4s\" : \"+w\"(acc) : \"w\"(x), \"w\"(dup_lane(y, L))); } while(0)\n#else\n#\tdefine FMADD_LANE(acc, x, y, L) do { acc = vmlaq_laneq_f32(acc, x, y, L); } while(0)\n#endif\n\n\t\t\tswitch(lane) { \n\t\t\t\tcase 0: \n\t\t\t\t\tFMADD_LANE(acc, v, vlane, 0);\n\t\t\t\t\treturn acc;\n\t\t\t\tcase 1:\n\t\t\t\t\tFMADD_LANE(acc, v, vlane, 1);\n\t\t\t\t\treturn acc;\n\t\t\t\tcase 2:\n\t\t\t\t\tFMADD_LANE(acc, v, vlane, 2);\n\t\t\t\t\treturn acc;\n\t\t\t\tcase 3:\n\t\t\t\t\tFMADD_LANE(acc, v, vlane, 3);\n\t\t\t\t\treturn acc;\n\t\t\t\tdefault: \n\t\t\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\t}\n\t\t\tassert(!\"Unreachable code executed!\");\n\t\t\treturn vdupq_n_f32(0.0f);\n#\tundef FMADD_LANE\n#else\n\t\t\treturn vaddq_f32(acc, vmulq_f32(v, dupq_lane(vlane, lane)));\n#endif\n\t\t}\n\t} //namespace neon\n} // namespace glm\n#endif // GLM_ARCH & GLM_ARCH_NEON_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/packing.h",
    "content": "/// @ref simd\n/// @file glm/simd/packing.h\n\n#pragma once\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/simd/platform.h",
    "content": "#pragma once\n\n///////////////////////////////////////////////////////////////////////////////////\n// Platform\n\n#define GLM_PLATFORM_UNKNOWN\t\t0x00000000\n#define GLM_PLATFORM_WINDOWS\t\t0x00010000\n#define GLM_PLATFORM_LINUX\t\t\t0x00020000\n#define GLM_PLATFORM_APPLE\t\t\t0x00040000\n//#define GLM_PLATFORM_IOS\t\t\t0x00080000\n#define GLM_PLATFORM_ANDROID\t\t0x00100000\n#define GLM_PLATFORM_CHROME_NACL\t0x00200000\n#define GLM_PLATFORM_UNIX\t\t\t0x00400000\n#define GLM_PLATFORM_QNXNTO\t\t\t0x00800000\n#define GLM_PLATFORM_WINCE\t\t\t0x01000000\n#define GLM_PLATFORM_CYGWIN\t\t\t0x02000000\n\n#ifdef GLM_FORCE_PLATFORM_UNKNOWN\n#\tdefine GLM_PLATFORM GLM_PLATFORM_UNKNOWN\n#elif defined(__CYGWIN__)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_CYGWIN\n#elif defined(__QNXNTO__)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_QNXNTO\n#elif defined(__APPLE__)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_APPLE\n#elif defined(WINCE)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_WINCE\n#elif defined(_WIN32)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_WINDOWS\n#elif defined(__native_client__)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_CHROME_NACL\n#elif defined(__ANDROID__)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_ANDROID\n#elif defined(__linux)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_LINUX\n#elif defined(__unix)\n#\tdefine GLM_PLATFORM GLM_PLATFORM_UNIX\n#else\n#\tdefine GLM_PLATFORM GLM_PLATFORM_UNKNOWN\n#endif//\n\n///////////////////////////////////////////////////////////////////////////////////\n// Compiler\n\n#define GLM_COMPILER_UNKNOWN\t\t0x00000000\n\n// Intel\n#define GLM_COMPILER_INTEL\t\t\t0x00100000\n#define GLM_COMPILER_INTEL14\t\t0x00100040\n#define GLM_COMPILER_INTEL15\t\t0x00100050\n#define GLM_COMPILER_INTEL16\t\t0x00100060\n#define GLM_COMPILER_INTEL17\t\t0x00100070\n\n// Visual C++ defines\n#define GLM_COMPILER_VC\t\t\t\t0x01000000\n#define GLM_COMPILER_VC12\t\t\t0x01000001\n#define GLM_COMPILER_VC14\t\t\t0x01000002\n#define GLM_COMPILER_VC15\t\t\t0x01000003\n#define GLM_COMPILER_VC15_3\t\t\t0x01000004\n#define GLM_COMPILER_VC15_5\t\t\t0x01000005\n#define GLM_COMPILER_VC15_6\t\t\t0x01000006\n#define GLM_COMPILER_VC15_7\t\t\t0x01000007\n#define GLM_COMPILER_VC15_8\t\t\t0x01000008\n#define GLM_COMPILER_VC15_9\t\t\t0x01000009\n#define GLM_COMPILER_VC16\t\t\t0x0100000A\n\n// GCC defines\n#define GLM_COMPILER_GCC\t\t\t0x02000000\n#define GLM_COMPILER_GCC46\t\t\t0x020000D0\n#define GLM_COMPILER_GCC47\t\t\t0x020000E0\n#define GLM_COMPILER_GCC48\t\t\t0x020000F0\n#define GLM_COMPILER_GCC49\t\t\t0x02000100\n#define GLM_COMPILER_GCC5\t\t\t0x02000200\n#define GLM_COMPILER_GCC6\t\t\t0x02000300\n#define GLM_COMPILER_GCC7\t\t\t0x02000400\n#define GLM_COMPILER_GCC8\t\t\t0x02000500\n\n// CUDA\n#define GLM_COMPILER_CUDA\t\t\t0x10000000\n#define GLM_COMPILER_CUDA75\t\t\t0x10000001\n#define GLM_COMPILER_CUDA80\t\t\t0x10000002\n#define GLM_COMPILER_CUDA90\t\t\t0x10000004\n\n// SYCL\n#define GLM_COMPILER_SYCL\t\t\t0x00300000\n\n// Clang\n#define GLM_COMPILER_CLANG\t\t\t0x20000000\n#define GLM_COMPILER_CLANG34\t\t0x20000050\n#define GLM_COMPILER_CLANG35\t\t0x20000060\n#define GLM_COMPILER_CLANG36\t\t0x20000070\n#define GLM_COMPILER_CLANG37\t\t0x20000080\n#define GLM_COMPILER_CLANG38\t\t0x20000090\n#define GLM_COMPILER_CLANG39\t\t0x200000A0\n#define GLM_COMPILER_CLANG40\t\t0x200000B0\n#define GLM_COMPILER_CLANG41\t\t0x200000C0\n#define GLM_COMPILER_CLANG42\t\t0x200000D0\n\n// Build model\n#define GLM_MODEL_32\t\t\t\t0x00000010\n#define GLM_MODEL_64\t\t\t\t0x00000020\n\n// Force generic C++ compiler\n#ifdef GLM_FORCE_COMPILER_UNKNOWN\n#\tdefine GLM_COMPILER GLM_COMPILER_UNKNOWN\n\n#elif defined(__INTEL_COMPILER)\n#\tif __INTEL_COMPILER >= 1700\n#\t\tdefine GLM_COMPILER GLM_COMPILER_INTEL17\n#\telif __INTEL_COMPILER >= 1600\n#\t\tdefine GLM_COMPILER GLM_COMPILER_INTEL16\n#\telif __INTEL_COMPILER >= 1500\n#\t\tdefine GLM_COMPILER GLM_COMPILER_INTEL15\n#\telif __INTEL_COMPILER >= 1400\n#\t\tdefine GLM_COMPILER GLM_COMPILER_INTEL14\n#\telif __INTEL_COMPILER < 1400\n#\t\terror \"GLM requires ICC 2013 SP1 or newer\"\n#\tendif\n\n// CUDA\n#elif defined(__CUDACC__)\n#\tif !defined(CUDA_VERSION) && !defined(GLM_FORCE_CUDA)\n#\t\tinclude <cuda.h>  // make sure version is defined since nvcc does not define it itself!\n#\tendif\n#\tif CUDA_VERSION >= 8000\n#\t\tdefine GLM_COMPILER GLM_COMPILER_CUDA80\n#\telif CUDA_VERSION >= 7500\n#\t\tdefine GLM_COMPILER GLM_COMPILER_CUDA75\n#\telif CUDA_VERSION >= 7000\n#\t\tdefine GLM_COMPILER GLM_COMPILER_CUDA70\n#\telif CUDA_VERSION < 7000\n#\t\terror \"GLM requires CUDA 7.0 or higher\"\n#\tendif\n\n// SYCL\n#elif defined(__SYCL_DEVICE_ONLY__)\n#\tdefine GLM_COMPILER GLM_COMPILER_SYCL\n\n// Clang\n#elif defined(__clang__)\n#\tif defined(__apple_build_version__)\n#\t\tif (__clang_major__ < 6)\n#\t\t\terror \"GLM requires Clang 3.4 / Apple Clang 6.0 or higher\"\n#\t\telif __clang_major__ == 6 && __clang_minor__ == 0\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG35\n#\t\telif __clang_major__ == 6 && __clang_minor__ >= 1\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG36\n#\t\telif __clang_major__ >= 7\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG37\n#\t\tendif\n#\telse\n#\t\tif ((__clang_major__ == 3) && (__clang_minor__ < 4)) || (__clang_major__ < 3)\n#\t\t\terror \"GLM requires Clang 3.4 or higher\"\n#\t\telif __clang_major__ == 3 && __clang_minor__ == 4\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG34\n#\t\telif __clang_major__ == 3 && __clang_minor__ == 5\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG35\n#\t\telif __clang_major__ == 3 && __clang_minor__ == 6\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG36\n#\t\telif __clang_major__ == 3 && __clang_minor__ == 7\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG37\n#\t\telif __clang_major__ == 3 && __clang_minor__ == 8\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG38\n#\t\telif __clang_major__ == 3 && __clang_minor__ >= 9\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG39\n#\t\telif __clang_major__ == 4 && __clang_minor__ == 0\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG40\n#\t\telif __clang_major__ == 4 && __clang_minor__ == 1\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG41\n#\t\telif __clang_major__ == 4 && __clang_minor__ >= 2\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG42\n#\t\telif __clang_major__ >= 4\n#\t\t\tdefine GLM_COMPILER GLM_COMPILER_CLANG42\n#\t\tendif\n#\tendif\n\n// Visual C++\n#elif defined(_MSC_VER)\n#\tif _MSC_VER >= 1920\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC16\n#\telif _MSC_VER >= 1916\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15_9\n#\telif _MSC_VER >= 1915\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15_8\n#\telif _MSC_VER >= 1914\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15_7\n#\telif _MSC_VER >= 1913\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15_6\n#\telif _MSC_VER >= 1912\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15_5\n#\telif _MSC_VER >= 1911\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15_3\n#\telif _MSC_VER >= 1910\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC15\n#\telif _MSC_VER >= 1900\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC14\n#\telif _MSC_VER >= 1800\n#\t\tdefine GLM_COMPILER GLM_COMPILER_VC12\n#\telif _MSC_VER < 1800\n#\t\terror \"GLM requires Visual C++ 12 - 2013 or higher\"\n#\tendif//_MSC_VER\n\n// G++\n#elif defined(__GNUC__) || defined(__MINGW32__)\n#\tif __GNUC__ >= 8\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC8\n#\telif __GNUC__ >= 7\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC7\n#\telif __GNUC__ >= 6\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC6\n#\telif __GNUC__ >= 5\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC5\n#\telif __GNUC__ == 4 && __GNUC_MINOR__ >= 9\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC49\n#\telif __GNUC__ == 4 && __GNUC_MINOR__ >= 8\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC48\n#\telif __GNUC__ == 4 && __GNUC_MINOR__ >= 7\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC47\n#\telif __GNUC__ == 4 && __GNUC_MINOR__ >= 6\n#\t\tdefine GLM_COMPILER GLM_COMPILER_GCC46\n#\telif ((__GNUC__ == 4) && (__GNUC_MINOR__ < 6)) || (__GNUC__ < 4)\n#\t\terror \"GLM requires GCC 4.6 or higher\"\n#\tendif\n\n#else\n#\tdefine GLM_COMPILER GLM_COMPILER_UNKNOWN\n#endif\n\n#ifndef GLM_COMPILER\n#\terror \"GLM_COMPILER undefined, your compiler may not be supported by GLM. Add #define GLM_COMPILER 0 to ignore this message.\"\n#endif//GLM_COMPILER\n\n///////////////////////////////////////////////////////////////////////////////////\n// Instruction sets\n\n// User defines: GLM_FORCE_PURE GLM_FORCE_INTRINSICS GLM_FORCE_SSE2 GLM_FORCE_SSE3 GLM_FORCE_AVX GLM_FORCE_AVX2 GLM_FORCE_AVX2\n\n#define GLM_ARCH_MIPS_BIT\t  (0x10000000)\n#define GLM_ARCH_PPC_BIT\t  (0x20000000)\n#define GLM_ARCH_ARM_BIT\t  (0x40000000)\n#define GLM_ARCH_ARMV8_BIT  (0x01000000)\n#define GLM_ARCH_X86_BIT\t  (0x80000000)\n\n#define GLM_ARCH_SIMD_BIT\t(0x00001000)\n\n#define GLM_ARCH_NEON_BIT\t(0x00000001)\n#define GLM_ARCH_SSE_BIT\t(0x00000002)\n#define GLM_ARCH_SSE2_BIT\t(0x00000004)\n#define GLM_ARCH_SSE3_BIT\t(0x00000008)\n#define GLM_ARCH_SSSE3_BIT\t(0x00000010)\n#define GLM_ARCH_SSE41_BIT\t(0x00000020)\n#define GLM_ARCH_SSE42_BIT\t(0x00000040)\n#define GLM_ARCH_AVX_BIT\t(0x00000080)\n#define GLM_ARCH_AVX2_BIT\t(0x00000100)\n\n#define GLM_ARCH_UNKNOWN\t(0)\n#define GLM_ARCH_X86\t\t(GLM_ARCH_X86_BIT)\n#define GLM_ARCH_SSE\t\t(GLM_ARCH_SSE_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_X86)\n#define GLM_ARCH_SSE2\t\t(GLM_ARCH_SSE2_BIT | GLM_ARCH_SSE)\n#define GLM_ARCH_SSE3\t\t(GLM_ARCH_SSE3_BIT | GLM_ARCH_SSE2)\n#define GLM_ARCH_SSSE3\t\t(GLM_ARCH_SSSE3_BIT | GLM_ARCH_SSE3)\n#define GLM_ARCH_SSE41\t\t(GLM_ARCH_SSE41_BIT | GLM_ARCH_SSSE3)\n#define GLM_ARCH_SSE42\t\t(GLM_ARCH_SSE42_BIT | GLM_ARCH_SSE41)\n#define GLM_ARCH_AVX\t\t(GLM_ARCH_AVX_BIT | GLM_ARCH_SSE42)\n#define GLM_ARCH_AVX2\t\t(GLM_ARCH_AVX2_BIT | GLM_ARCH_AVX)\n#define GLM_ARCH_ARM\t\t(GLM_ARCH_ARM_BIT)\n#define GLM_ARCH_ARMV8\t\t(GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM | GLM_ARCH_ARMV8_BIT)\n#define GLM_ARCH_NEON\t\t(GLM_ARCH_NEON_BIT | GLM_ARCH_SIMD_BIT | GLM_ARCH_ARM)\n#define GLM_ARCH_MIPS\t\t(GLM_ARCH_MIPS_BIT)\n#define GLM_ARCH_PPC\t\t(GLM_ARCH_PPC_BIT)\n\n#if defined(GLM_FORCE_ARCH_UNKNOWN) || defined(GLM_FORCE_PURE)\n#\tdefine GLM_ARCH GLM_ARCH_UNKNOWN\n#elif defined(GLM_FORCE_NEON)\n#\tif __ARM_ARCH >= 8\n#\t\tdefine GLM_ARCH (GLM_ARCH_ARMV8)\n#\telse\n#\t\tdefine GLM_ARCH (GLM_ARCH_NEON)\n#\tendif\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_AVX2)\n#\tdefine GLM_ARCH (GLM_ARCH_AVX2)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_AVX)\n#\tdefine GLM_ARCH (GLM_ARCH_AVX)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_SSE42)\n#\tdefine GLM_ARCH (GLM_ARCH_SSE42)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_SSE41)\n#\tdefine GLM_ARCH (GLM_ARCH_SSE41)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_SSSE3)\n#\tdefine GLM_ARCH (GLM_ARCH_SSSE3)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_SSE3)\n#\tdefine GLM_ARCH (GLM_ARCH_SSE3)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_SSE2)\n#\tdefine GLM_ARCH (GLM_ARCH_SSE2)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_SSE)\n#\tdefine GLM_ARCH (GLM_ARCH_SSE)\n#\tdefine GLM_FORCE_INTRINSICS\n#elif defined(GLM_FORCE_INTRINSICS) && !defined(GLM_FORCE_XYZW_ONLY)\n#\tif defined(__AVX2__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_AVX2)\n#\telif defined(__AVX__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_AVX)\n#\telif defined(__SSE4_2__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_SSE42)\n#\telif defined(__SSE4_1__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_SSE41)\n#\telif defined(__SSSE3__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_SSSE3)\n#\telif defined(__SSE3__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_SSE3)\n#\telif defined(__SSE2__) || defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86_FP)\n#\t\tdefine GLM_ARCH (GLM_ARCH_SSE2)\n#\telif defined(__i386__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_X86)\n#\telif defined(__ARM_ARCH) && (__ARM_ARCH >= 8)\n#\t\tdefine GLM_ARCH (GLM_ARCH_ARMV8)\n#\telif defined(__ARM_NEON)\n#\t\tdefine GLM_ARCH (GLM_ARCH_ARM | GLM_ARCH_NEON)\n#\telif defined(__arm__ ) || defined(_M_ARM)\n#\t\tdefine GLM_ARCH (GLM_ARCH_ARM)\n#\telif defined(__mips__ )\n#\t\tdefine GLM_ARCH (GLM_ARCH_MIPS)\n#\telif defined(__powerpc__ ) || defined(_M_PPC)\n#\t\tdefine GLM_ARCH (GLM_ARCH_PPC)\n#\telse\n#\t\tdefine GLM_ARCH (GLM_ARCH_UNKNOWN)\n#\tendif\n#else\n#\tif defined(__x86_64__) || defined(_M_X64) || defined(_M_IX86) || defined(__i386__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_X86)\n#\telif defined(__arm__) || defined(_M_ARM)\n#\t\tdefine GLM_ARCH (GLM_ARCH_ARM)\n#\telif defined(__powerpc__) || defined(_M_PPC)\n#\t\tdefine GLM_ARCH (GLM_ARCH_PPC)\n#\telif defined(__mips__)\n#\t\tdefine GLM_ARCH (GLM_ARCH_MIPS)\n#\telse\n#\t\tdefine GLM_ARCH (GLM_ARCH_UNKNOWN)\n#\tendif\n#endif\n\n#if GLM_ARCH & GLM_ARCH_AVX2_BIT\n#\tinclude <immintrin.h>\n#elif GLM_ARCH & GLM_ARCH_AVX_BIT\n#\tinclude <immintrin.h>\n#elif GLM_ARCH & GLM_ARCH_SSE42_BIT\n#\tif GLM_COMPILER & GLM_COMPILER_CLANG\n#\t\tinclude <popcntintrin.h>\n#\tendif\n#\tinclude <nmmintrin.h>\n#elif GLM_ARCH & GLM_ARCH_SSE41_BIT\n#\tinclude <smmintrin.h>\n#elif GLM_ARCH & GLM_ARCH_SSSE3_BIT\n#\tinclude <tmmintrin.h>\n#elif GLM_ARCH & GLM_ARCH_SSE3_BIT\n#\tinclude <pmmintrin.h>\n#elif GLM_ARCH & GLM_ARCH_SSE2_BIT\n#\tinclude <emmintrin.h>\n#elif GLM_ARCH & GLM_ARCH_NEON_BIT\n#\tinclude \"neon.h\"\n#endif//GLM_ARCH\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\ttypedef __m128\t\t\tglm_f32vec4;\n\ttypedef __m128i\t\t\tglm_i32vec4;\n\ttypedef __m128i\t\t\tglm_u32vec4;\n\ttypedef __m128d\t\t\tglm_f64vec2;\n\ttypedef __m128i\t\t\tglm_i64vec2;\n\ttypedef __m128i\t\t\tglm_u64vec2;\n\n\ttypedef glm_f32vec4\t\tglm_vec4;\n\ttypedef glm_i32vec4\t\tglm_ivec4;\n\ttypedef glm_u32vec4\t\tglm_uvec4;\n\ttypedef glm_f64vec2\t\tglm_dvec2;\n#endif\n\n#if GLM_ARCH & GLM_ARCH_AVX_BIT\n\ttypedef __m256d\t\t\tglm_f64vec4;\n\ttypedef glm_f64vec4\t\tglm_dvec4;\n#endif\n\n#if GLM_ARCH & GLM_ARCH_AVX2_BIT\n\ttypedef __m256i\t\t\tglm_i64vec4;\n\ttypedef __m256i\t\t\tglm_u64vec4;\n#endif\n\n#if GLM_ARCH & GLM_ARCH_NEON_BIT\n\ttypedef float32x4_t\t\t\tglm_f32vec4;\n\ttypedef int32x4_t\t\t\tglm_i32vec4;\n\ttypedef uint32x4_t\t\t\tglm_u32vec4;\n#endif\n"
  },
  {
    "path": "lib/gli/glm/simd/trigonometric.h",
    "content": "/// @ref simd\n/// @file glm/simd/trigonometric.h\n\n#pragma once\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n"
  },
  {
    "path": "lib/gli/glm/simd/vector_relational.h",
    "content": "/// @ref simd\n/// @file glm/simd/vector_relational.h\n\n#pragma once\n\n#if GLM_ARCH & GLM_ARCH_SSE2_BIT\n\n#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT\n"
  },
  {
    "path": "lib/gli/glm/trigonometric.hpp",
    "content": "/// @ref core\n/// @file glm/trigonometric.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n///\n/// @defgroup core_func_trigonometric Angle and Trigonometry Functions\n/// @ingroup core\n///\n/// Function parameters specified as angle are assumed to be in units of radians.\n/// In no case will any of these functions result in a divide by zero error. If\n/// the divisor of a ratio is 0, then results will be undefined.\n///\n/// These all operate component-wise. The description is per component.\n///\n/// Include <glm/trigonometric.hpp> to use these core features.\n///\n/// @see ext_vector_trigonometric\n\n#pragma once\n\n#include \"detail/setup.hpp\"\n#include \"detail/qualifier.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_func_trigonometric\n\t/// @{\n\n\t/// Converts degrees to radians and returns the result.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/radians.xml\">GLSL radians man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> radians(vec<L, T, Q> const& degrees);\n\n\t/// Converts radians to degrees and returns the result.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/degrees.xml\">GLSL degrees man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, T, Q> degrees(vec<L, T, Q> const& radians);\n\n\t/// The standard trigonometric sine function.\n\t/// The values returned by this function will range from [-1, 1].\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/sin.xml\">GLSL sin man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> sin(vec<L, T, Q> const& angle);\n\n\t/// The standard trigonometric cosine function.\n\t/// The values returned by this function will range from [-1, 1].\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/cos.xml\">GLSL cos man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> cos(vec<L, T, Q> const& angle);\n\n\t/// The standard trigonometric tangent function.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/tan.xml\">GLSL tan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> tan(vec<L, T, Q> const& angle);\n\n\t/// Arc sine. Returns an angle whose sine is x.\n\t/// The range of values returned by this function is [-PI/2, PI/2].\n\t/// Results are undefined if |x| > 1.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/asin.xml\">GLSL asin man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> asin(vec<L, T, Q> const& x);\n\n\t/// Arc cosine. Returns an angle whose cosine is x.\n\t/// The range of values returned by this function is [0, PI].\n\t/// Results are undefined if |x| > 1.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/acos.xml\">GLSL acos man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> acos(vec<L, T, Q> const& x);\n\n\t/// Arc tangent. Returns an angle whose tangent is y/x.\n\t/// The signs of x and y are used to determine what\n\t/// quadrant the angle is in. The range of values returned\n\t/// by this function is [-PI, PI]. Results are undefined\n\t/// if x and y are both 0.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/atan.xml\">GLSL atan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> atan(vec<L, T, Q> const& y, vec<L, T, Q> const& x);\n\n\t/// Arc tangent. Returns an angle whose tangent is y_over_x.\n\t/// The range of values returned by this function is [-PI/2, PI/2].\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/atan.xml\">GLSL atan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> atan(vec<L, T, Q> const& y_over_x);\n\n\t/// Returns the hyperbolic sine function, (exp(x) - exp(-x)) / 2\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/sinh.xml\">GLSL sinh man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> sinh(vec<L, T, Q> const& angle);\n\n\t/// Returns the hyperbolic cosine function, (exp(x) + exp(-x)) / 2\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/cosh.xml\">GLSL cosh man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> cosh(vec<L, T, Q> const& angle);\n\n\t/// Returns the hyperbolic tangent function, sinh(angle) / cosh(angle)\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/tanh.xml\">GLSL tanh man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> tanh(vec<L, T, Q> const& angle);\n\n\t/// Arc hyperbolic sine; returns the inverse of sinh.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/asinh.xml\">GLSL asinh man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> asinh(vec<L, T, Q> const& x);\n\n\t/// Arc hyperbolic cosine; returns the non-negative inverse\n\t/// of cosh. Results are undefined if x < 1.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/acosh.xml\">GLSL acosh man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> acosh(vec<L, T, Q> const& x);\n\n\t/// Arc hyperbolic tangent; returns the inverse of tanh.\n\t/// Results are undefined if abs(x) >= 1.\n\t///\n\t/// @tparam L Integer between 1 and 4 included that qualify the dimension of the vector\n\t/// @tparam T Floating-point scalar types\n\t/// @tparam Q Value from qualifier enum\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/atanh.xml\">GLSL atanh man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL vec<L, T, Q> atanh(vec<L, T, Q> const& x);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_trigonometric.inl\"\n"
  },
  {
    "path": "lib/gli/glm/vec2.hpp",
    "content": "/// @ref core\n/// @file glm/vec2.hpp\n\n#pragma once\n#include \"./ext/vector_bool2.hpp\"\n#include \"./ext/vector_bool2_precision.hpp\"\n#include \"./ext/vector_float2.hpp\"\n#include \"./ext/vector_float2_precision.hpp\"\n#include \"./ext/vector_double2.hpp\"\n#include \"./ext/vector_double2_precision.hpp\"\n#include \"./ext/vector_int2.hpp\"\n#include \"./ext/vector_int2_sized.hpp\"\n#include \"./ext/vector_uint2.hpp\"\n#include \"./ext/vector_uint2_sized.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/vec3.hpp",
    "content": "/// @ref core\n/// @file glm/vec3.hpp\n\n#pragma once\n#include \"./ext/vector_bool3.hpp\"\n#include \"./ext/vector_bool3_precision.hpp\"\n#include \"./ext/vector_float3.hpp\"\n#include \"./ext/vector_float3_precision.hpp\"\n#include \"./ext/vector_double3.hpp\"\n#include \"./ext/vector_double3_precision.hpp\"\n#include \"./ext/vector_int3.hpp\"\n#include \"./ext/vector_int3_sized.hpp\"\n#include \"./ext/vector_uint3.hpp\"\n#include \"./ext/vector_uint3_sized.hpp\"\n"
  },
  {
    "path": "lib/gli/glm/vec4.hpp",
    "content": "/// @ref core\n/// @file glm/vec4.hpp\n\n#pragma once\n#include \"./ext/vector_bool4.hpp\"\n#include \"./ext/vector_bool4_precision.hpp\"\n#include \"./ext/vector_float4.hpp\"\n#include \"./ext/vector_float4_precision.hpp\"\n#include \"./ext/vector_double4.hpp\"\n#include \"./ext/vector_double4_precision.hpp\"\n#include \"./ext/vector_int4.hpp\"\n#include \"./ext/vector_int4_sized.hpp\"\n#include \"./ext/vector_uint4.hpp\"\n#include \"./ext/vector_uint4_sized.hpp\"\n\n"
  },
  {
    "path": "lib/gli/glm/vector_relational.hpp",
    "content": "/// @ref core\n/// @file glm/vector_relational.hpp\n///\n/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n///\n/// @defgroup core_func_vector_relational Vector Relational Functions\n/// @ingroup core\n///\n/// Relational and equality operators (<, <=, >, >=, ==, !=) are defined to\n/// operate on scalars and produce scalar Boolean results. For vector results,\n/// use the following built-in functions.\n///\n/// In all cases, the sizes of all the input and return vectors for any particular\n/// call must match.\n///\n/// Include <glm/vector_relational.hpp> to use these core features.\n///\n/// @see ext_vector_relational\n\n#pragma once\n\n#include \"detail/qualifier.hpp\"\n#include \"detail/setup.hpp\"\n\nnamespace glm\n{\n\t/// @addtogroup core_func_vector_relational\n\t/// @{\n\n\t/// Returns the component-wise comparison result of x < y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T A floating-point or integer scalar type.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/lessThan.xml\">GLSL lessThan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> lessThan(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x <= y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T A floating-point or integer scalar type.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/lessThanEqual.xml\">GLSL lessThanEqual man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> lessThanEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x > y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T A floating-point or integer scalar type.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/greaterThan.xml\">GLSL greaterThan man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> greaterThan(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x >= y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T A floating-point or integer scalar type.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/greaterThanEqual.xml\">GLSL greaterThanEqual man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> greaterThanEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x == y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T A floating-point, integer or bool scalar type.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/equal.xml\">GLSL equal man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> equal(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns the component-wise comparison of result x != y.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t/// @tparam T A floating-point, integer or bool scalar type.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/notEqual.xml\">GLSL notEqual man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, typename T, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> notEqual(vec<L, T, Q> const& x, vec<L, T, Q> const& y);\n\n\t/// Returns true if any component of x is true.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/any.xml\">GLSL any man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool any(vec<L, bool, Q> const& v);\n\n\t/// Returns true if all components of x are true.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/all.xml\">GLSL all man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR bool all(vec<L, bool, Q> const& v);\n\n\t/// Returns the component-wise logical complement of x.\n\t/// /!\\ Because of language incompatibilities between C++ and GLSL, GLM defines the function not but not_ instead.\n\t///\n\t/// @tparam L An integer between 1 and 4 included that qualify the dimension of the vector.\n\t///\n\t/// @see <a href=\"http://www.opengl.org/sdk/docs/manglsl/xhtml/not.xml\">GLSL not man page</a>\n\t/// @see <a href=\"http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf\">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>\n\ttemplate<length_t L, qualifier Q>\n\tGLM_FUNC_DECL GLM_CONSTEXPR vec<L, bool, Q> not_(vec<L, bool, Q> const& v);\n\n\t/// @}\n}//namespace glm\n\n#include \"detail/func_vector_relational.inl\"\n"
  },
  {
    "path": "lib/gli/image.hpp",
    "content": "/// @brief Include to use images, a representation of a single texture level.\n/// @file gli/image.hpp\n\n#pragma once\n\n#include \"./core/storage_linear.hpp\"\n\nnamespace gli\n{\n\t/// Image, representation for a single texture level\n\tclass image\n\t{\n\tprivate:\n\t\tfriend class texture1d;\n\t\tfriend class texture2d;\n\t\tfriend class texture3d;\n\n\tpublic:\n\t\ttypedef size_t size_type;\n\t\ttypedef gli::format format_type;\n\t\ttypedef storage_linear::extent_type extent_type;\n\t\ttypedef storage_linear::data_type data_type;\n\n\t\t/// Create an empty image instance\n\t\timage();\n\n\t\t/// Create an image object and allocate an image storoge for it.\n\t\texplicit image(format_type Format, extent_type const& Extent);\n\n\t\t/// Create an image object by sharing an existing image storage_linear from another image instance.\n\t\t/// This image object is effectively an image view where format can be reinterpreted\n\t\t/// with a different compatible image format.\n\t\t/// For formats to be compatible, the block size of source and destination must match.\n\t\texplicit image(image const& Image, format_type Format);\n\n\t\t/// Return whether the image instance is empty, no storage_linear or description have been assigned to the instance.\n\t\tbool empty() const;\n\n\t\t/// Return the image instance format.\n\t\tformat_type format() const;\n\n\t\t/// Return the dimensions of an image instance: width, height and depth.\n\t\textent_type extent() const;\n\n\t\t/// Return the memory size of an image instance storage_linear in bytes.\n\t\tsize_type size() const;\n\n\t\t/// Return the number of blocks contained in an image instance storage_linear.\n\t\t/// genType size must match the block size conresponding to the image format. \n\t\ttemplate <typename genType>\n\t\tsize_type size() const;\n\n\t\t/// Return a pointer to the beginning of the image instance data.\n\t\tvoid* data();\n\n\t\t/// Return a pointer to the beginning of the image instance data.\n\t\tvoid const* data() const;\n\n\t\t/// Return a pointer of type genType which size must match the image format block size.\n\t\ttemplate <typename genType>\n\t\tgenType* data();\n\n\t\t/// Return a pointer of type genType which size must match the image format block size.\n\t\ttemplate <typename genType>\n\t\tgenType const* data() const;\n\n\t\t/// Clear the entire image storage_linear with zeros\n\t\tvoid clear();\n\n\t\t/// Clear the entire image storage_linear with Texel which type must match the image storage_linear format block size\n\t\t/// If the type of genType doesn't match the type of the image format, no conversion is performed and the data will be reinterpreted as if is was of the image format. \n\t\ttemplate <typename genType>\n\t\tvoid clear(genType const& Texel);\n\n\t\t/// Load the texel located at TexelCoord coordinates.\n\t\t/// It's an error to call this function if the format is compressed.\n\t\t/// It's an error if TexelCoord values aren't between [0, dimensions].\n\t\ttemplate <typename genType>\n\t\tgenType load(extent_type const& TexelCoord);\n\n\t\t/// Store the texel located at TexelCoord coordinates.\n\t\t/// It's an error to call this function if the format is compressed.\n\t\t/// It's an error if TexelCoord values aren't between [0, dimensions].\n\t\ttemplate <typename genType>\n\t\tvoid store(extent_type const& TexelCoord, genType const& Data);\n\n\tprivate:\n\t\t/// Create an image object by sharing an existing image storage_linear from another image instance.\n\t\t/// This image object is effectively an image view where the layer, the face and the level allows identifying\n\t\t/// a specific subset of the image storage_linear source. \n\t\t/// This image object is effectively a image view where the format can be reinterpreted\n\t\t/// with a different compatible image format.\n\t\texplicit image(\n\t\t\tstd::shared_ptr<storage_linear> Storage,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer,\n\t\t\tsize_type BaseFace,\n\t\t\tsize_type BaseLevel);\n\n\t\tstd::shared_ptr<storage_linear> Storage;\n\t\tformat_type const Format;\n\t\tsize_type const BaseLevel;\n\t\tdata_type* Data;\n\t\tsize_type const Size;\n\n\t\tdata_type* compute_data(size_type BaseLayer, size_type BaseFace, size_type BaseLevel);\n\t\tsize_type compute_size(size_type Level) const;\n\t};\n}//namespace gli\n\n#include \"./core/image.inl\"\n"
  },
  {
    "path": "lib/gli/levels.hpp",
    "content": "/// @brief Include to compute the number of mipmaps levels necessary to create a mipmap complete texture.\n/// @file gli/levels.hpp\n\n#pragma once\n\n#include \"type.hpp\"\n\nnamespace gli\n{\n\t/// Compute the number of mipmaps levels necessary to create a mipmap complete texture\n\t/// \n\t/// @param Extent Extent of the texture base level mipmap\n\t/// @tparam vecType Vector type used to express the dimensions of a texture of any kind.\n\t/// @code\n\t/// #include <gli/texture2d.hpp>\n\t/// #include <gli/levels.hpp>\n\t/// ...\n\t/// gli::texture2d::extent_type Extent(32, 10);\n\t/// gli::texture2d Texture(gli::levels(Extent));\n\t/// @endcode\n\ttemplate <length_t L, typename T, qualifier P>\n\tT levels(vec<L, T, P> const& Extent);\n/*\n\t/// Compute the number of mipmaps levels necessary to create a mipmap complete texture\n\t/// \n\t/// @param Extent Extent of the texture base level mipmap\n\t/// @code\n\t/// #include <gli/texture2d.hpp>\n\t/// #include <gli/levels.hpp>\n\t/// ...\n\t/// gli::texture2d Texture(32);\n\t/// @endcode\n\tsize_t levels(size_t Extent);\n\n\t/// Compute the number of mipmaps levels necessary to create a mipmap complete texture\n\t/// \n\t/// @param Extent Extent of the texture base level mipmap\n\t/// @code\n\t/// #include <gli/texture2d.hpp>\n\t/// #include <gli/levels.hpp>\n\t/// ...\n\t/// gli::texture2d Texture(32);\n\t/// @endcode\n\tint levels(int Extent);\n*/\n}//namespace gli\n\n#include \"./core/levels.inl\"\n"
  },
  {
    "path": "lib/gli/load.hpp",
    "content": "/// @brief Include to load DDS, KTX or KMG textures from files or memory.\n/// @file gli/load.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Loads a texture storage_linear from file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load(char const* Path);\n\n\t/// Loads a texture storage_linear from file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load(std::string const& Path);\n\n\t/// Loads a texture storage_linear from memory. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Data Data of a texture\n\t/// @param Size Size of the data\n\ttexture load(char const* Data, std::size_t Size);\n}//namespace gli\n\n#include \"./core/load.inl\"\n"
  },
  {
    "path": "lib/gli/load_dds.hpp",
    "content": "/// @brief Include to load DDS textures from files or memory.\n/// @file gli/load_dds.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Loads a texture storage_linear from DDS file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load_dds(char const* Path);\n\n\t/// Loads a texture storage_linear from DDS file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load_dds(std::string const& Path);\n\n\t/// Loads a texture storage_linear from DDS memory. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Data Pointer to the beginning of the texture container data to read\n\t/// @param Size Size of texture container Data to read\n\ttexture load_dds(char const* Data, std::size_t Size);\n}//namespace gli\n\n#include \"./core/load_dds.inl\"\n"
  },
  {
    "path": "lib/gli/load_kmg.hpp",
    "content": "/// @brief Include to load KMG textures from files or memory.\n/// @file gli/load_kmg.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Loads a texture storage_linear from KMG (Khronos Image) file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load_kmg(char const* Path);\n\n\t/// Loads a texture storage_linear from KMG (Khronos Image) file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load_kmg(std::string const& Path);\n\n\t/// Loads a texture storage_linear from KMG (Khronos Image) memory. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Data Pointer to the beginning of the texture container data to read\n\t/// @param Size Size of texture container Data to read\n\ttexture load_kmg(char const* Data, std::size_t Size);\n}//namespace gli\n\n#include \"./core/load_kmg.inl\"\n"
  },
  {
    "path": "lib/gli/load_ktx.hpp",
    "content": "/// @brief Include to load KTX textures from files or memory.\n/// @file gli/load_ktx.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Loads a texture storage_linear from KTX file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load_ktx(char const* Path);\n\n\t/// Loads a texture storage_linear from KTX file. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Path Path of the file to open including filaname and filename extension\n\ttexture load_ktx(std::string const& Path);\n\n\t/// Loads a texture storage_linear from KTX memory. Returns an empty storage_linear in case of failure.\n\t///\n\t/// @param Data Pointer to the beginning of the texture container data to read\n\t/// @param Size Size of texture container Data to read\n\ttexture load_ktx(char const* Data, std::size_t Size);\n}//namespace gli\n\n#include \"./core/load_ktx.inl\"\n"
  },
  {
    "path": "lib/gli/make_texture.hpp",
    "content": "/// @brief Helper functions to create generic texture\n/// @file gli/make_texture.hpp\n\n#pragma once\n\nnamespace gli\n{\n\t// Helper function to create a 1d texture with a specific number of levels\n\tgli::texture make_texture1d(format Format, extent1d const& Extent, size_t Levels);\n\n\t// Helper function to create a 1d texture with a complete mipmap chain\n\tgli::texture make_texture1d(format Format, extent1d const& Extent);\n\n\t// Helper function to create a 1d array texture with a specific number of levels\n\tgli::texture make_texture1d_array(format Format, extent1d const& Extent, size_t Layers, size_t Levels);\n\n\t// Helper function to create a 1d array texture with a complete mipmap chain\n\tgli::texture make_texture1d_array(format Format, extent1d const& Extent, size_t Layers);\n\n\t// Helper function to create a 2d texture with a specific number of levels\n\tgli::texture make_texture2d(format Format, extent2d const& Extent, size_t Levels);\n\n\t// Helper function to create a 2d texture with a complete mipmap chain\n\tgli::texture make_texture2d(format Format, extent2d const& Extent);\n\n\t// Helper function to create a 2d array texture with a specific number of levels\n\tgli::texture make_texture2d_array(format Format, extent2d const& Extent, size_t Layer, size_t Levels);\n\n\t// Helper function to create a 2d array texture with a complete mipmap chain\n\tgli::texture make_texture2d_array(format Format, extent2d const& Extent, size_t Layer);\n\n\t// Helper function to create a 3d texture with a specific number of levels\n\tgli::texture make_texture3d(format Format, extent3d const& Extent, size_t Levels);\n\n\t// Helper function to create a 3d texture with a complete mipmap chain\n\tgli::texture make_texture3d(format Format, extent3d const& Extent);\n\n\t// Helper function to create a cube texture with a specific number of levels\n\tgli::texture make_texture_cube(format Format, extent2d const& Extent, size_t Levels);\n\n\t// Helper function to create a cube texture with a complete mipmap chain\n\tgli::texture make_texture_cube(format Format, extent2d const& Extent);\n\n\t// Helper function to create a cube array texture with a specific number of levels\n\tgli::texture make_texture_cube_array(format Format, extent2d const& Extent, size_t Layer, size_t Levels);\n\n\t// Helper function to create a cube array texture with a complete mipmap chain\n\tgli::texture make_texture_cube_array(format Format, extent2d const& Extent, size_t Layer);\n}//namespace gli\n\n#include \"./core/make_texture.inl\"\n"
  },
  {
    "path": "lib/gli/reduce.hpp",
    "content": "/// @brief Include to perform reduction operations.\n/// @file gli/reduce.hpp\n\n#pragma once\n\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\nnamespace gli\n{\n\ttemplate <typename vec_type>\n\tstruct reduce_func\n\t{\n\t\ttypedef vec_type(*type)(vec_type const & A, vec_type const & B);\n\t};\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture1d const & In0, texture1d const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture1d_array const & In0, texture1d_array const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture2d const & In0, texture2d const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture2d_array const & In0, texture2d_array const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture3d const & In0, texture3d const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture_cube const & In0, texture_cube const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename vec_type>\n\tvec_type reduce(texture_cube_array const & In0, texture_cube_array const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function for per texel operation.\n\t/// @param ReduceFunc Pointer to a binary function to reduce texels.\n\ttemplate <typename texture_type, typename vec_type>\n\tvec_type reduce(texture_type const & In0, texture_type const & In1, typename reduce_func<vec_type>::type TexelFunc, typename reduce_func<vec_type>::type ReduceFunc);\n}//namespace gli\n\n#include \"./core/reduce.inl\"\n"
  },
  {
    "path": "lib/gli/sampler.hpp",
    "content": "/// @brief Include to use wrap modes and the sampler base class.\n/// @file gli/sampler.hpp\n\n#pragma once\n\n#include \"core/filter.hpp\"\n\nnamespace gli\n{\n\t/// Texture coordinate wrapping mode\n\tenum wrap\n\t{\n\t\tWRAP_CLAMP_TO_EDGE, WRAP_FIRST = WRAP_CLAMP_TO_EDGE,\n\t\tWRAP_CLAMP_TO_BORDER,\n\t\tWRAP_REPEAT,\n\t\tWRAP_MIRROR_REPEAT,\n\t\tWRAP_MIRROR_CLAMP_TO_EDGE,\n\t\tWRAP_MIRROR_CLAMP_TO_BORDER, WRAP_LAST = WRAP_MIRROR_CLAMP_TO_BORDER\n\t};\n\n\tenum\n\t{\n\t\tWRAP_COUNT = WRAP_LAST - WRAP_FIRST + 1\n\t};\n\n\t/// Evaluate whether the texture coordinate wrapping mode relies on border color\n\tinline bool is_border(wrap Wrap)\n\t{\n\t\treturn Wrap == WRAP_CLAMP_TO_BORDER || Wrap == WRAP_MIRROR_CLAMP_TO_BORDER;\n\t}\n\n\t/// Genetic sampler class.\n\tclass sampler\n\t{\n\tpublic:\n\t\tsampler(wrap Wrap, filter Mip, filter Min);\n\t\tvirtual ~sampler() = default;\n\n\tprotected:\n\t\ttypedef float(*wrap_type)(float const & SamplerCoord);\n\n\t\twrap_type get_func(wrap WrapMode) const;\n\n\t\twrap_type Wrap;\n\t\tfilter Mip;\n\t\tfilter Min;\n\t};\n}//namespace gli\n\n#include \"./core/sampler.inl\"\n"
  },
  {
    "path": "lib/gli/sampler1d.hpp",
    "content": "/// @brief Include to sample 1d textures.\n/// @file gli/sampler1d.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture1d.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// 1d texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam P Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler1d : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture1d texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<1, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler1d(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type const& Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type const& Level, texel_type const& Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample the sampler texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, level_type Level) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler1d<float> fsampler1D;\n\ttypedef sampler1d<double> dsampler1D;\n\ttypedef sampler1d<unsigned int> usampler1D;\n\ttypedef sampler1d<int> isampler1D;\n}//namespace gli\n\n#include \"./core/sampler1d.inl\"\n"
  },
  {
    "path": "lib/gli/sampler1d_array.hpp",
    "content": "/// @brief Include to sample 1d array textures.\n/// @file gli/sampler1d_array.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// 1d array texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam P Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler1d_array : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture1d_array texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<1, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler1d_array(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type layer, size_type Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type layer, size_type Level, texel_type const & Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample the sampler texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, size_type layer, level_type Level) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseLayer, size_type MaxLayer, size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_1D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler1d_array<float> fsampler1DArray;\n\ttypedef sampler1d_array<double> dsampler1DArray;\n\ttypedef sampler1d_array<unsigned int> usampler1DArray;\n\ttypedef sampler1d_array<int> isampler1DArray;\n\n}//namespace gli\n\n#include \"./core/sampler1d_array.inl\"\n"
  },
  {
    "path": "lib/gli/sampler2d.hpp",
    "content": "/// @brief Include to sample 2d textures.\n/// @file gli/sampler2d.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture2d.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// 2d texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam P Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler2d : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture2d texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<2, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler2d(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type const& Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type const& Level, texel_type const& Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample a texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, level_type Level) const;\n\n\t\t/// Sample a texture using specified gradiants\n\t\ttexel_type texture_grad(normalized_type const& SampleCoord, normalized_type const& dPdx, normalized_type const& dPdy) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler2d<float> fsampler2D;\n\ttypedef sampler2d<double> dsampler2D;\n\ttypedef sampler2d<unsigned int> usampler2D;\n\ttypedef sampler2d<int> isampler2D;\n\n}//namespace gli\n\n#include \"./core/sampler2d.inl\"\n"
  },
  {
    "path": "lib/gli/sampler2d_array.hpp",
    "content": "/// @brief Include to sample 2d array textures.\n/// @file gli/sampler2d_array.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// 2d array texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam Q Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler2d_array : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture2d_array texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<2, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler2d_array(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type layer, size_type Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type layer, size_type Level, texel_type const& Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample the sampler texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, size_type layer, level_type Level) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseLayer, size_type MaxLayer, size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler2d_array<float> fsampler2DArray;\n\ttypedef sampler2d_array<double> dsampler2DArray;\n\ttypedef sampler2d_array<unsigned int> usampler2DArray;\n\ttypedef sampler2d_array<int> isampler2DArray;\n\n}//namespace gli\n\n#include \"./core/sampler2d_array.inl\"\n"
  },
  {
    "path": "lib/gli/sampler3d.hpp",
    "content": "/// @brief Include to sample 3d textures.\n/// @file gli/sampler3d.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture3d.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// 3d texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam P Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler3d : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture3d texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<3, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler3d(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type const& Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type const & Level, texel_type const& Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample the sampler texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, level_type Level) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_3D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler3d<float> fsampler3D;\n\ttypedef sampler3d<double> dsampler3D;\n\ttypedef sampler3d<unsigned int> usampler3D;\n\ttypedef sampler3d<int> isampler3D;\n}//namespace gli\n\n#include \"./core/sampler3d.inl\"\n"
  },
  {
    "path": "lib/gli/sampler_cube.hpp",
    "content": "/// @brief Include to sample cube map textures.\n/// @file gli/sampler_cube.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture_cube.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// Cube map texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam P Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler_cube : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture_cube texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<2, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler_cube(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type Face, size_type Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type Face, size_type Level, texel_type const& Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample the sampler texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, size_type Face, level_type Level) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseFace, size_type MaxFace, size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler_cube<float> fsamplerCube;\n\ttypedef sampler_cube<double> dsamplerCube;\n\ttypedef sampler_cube<unsigned int> usamplerCube;\n\ttypedef sampler_cube<int> isamplerCube;\n\n}//namespace gli\n\n#include \"./core/sampler_cube.inl\"\n"
  },
  {
    "path": "lib/gli/sampler_cube_array.hpp",
    "content": "/// @brief Include to sample cube map array textures.\n/// @file gli/sampler_cube_array.hpp\n\n#pragma once\n\n#include \"sampler.hpp\"\n#include \"texture_cube_array.hpp\"\n#include \"core/mipmaps_compute.hpp\"\n#include \"core/convert_func.hpp\"\n\nnamespace gli\n{\n\t/// Cube map array texture sampler\n\t/// @tparam T Sampler can fetch, write and interpret any texture format but will expose and process the data through type T conversions.\n\t/// @tparam P Precision in term of ULPs\n\ttemplate <typename T, qualifier P = defaultp>\n\tclass sampler_cube_array : public sampler\n\t{\n\tprivate:\n\t\ttypedef typename detail::interpolate<T>::type interpolate_type;\n\n\tpublic:\n\t\ttypedef texture_cube_array texture_type;\n\t\ttypedef typename texture_type::size_type size_type;\n\t\ttypedef typename texture_type::extent_type extent_type;\n\t\ttypedef interpolate_type level_type;\n\t\ttypedef vec<2, interpolate_type, P> normalized_type;\n\t\ttypedef vec<4, T, P> texel_type;\n\n\t\tsampler_cube_array(texture_type const& Texture, wrap Wrap, filter Mip = FILTER_NEAREST, filter Min = FILTER_NEAREST, texel_type const& BorderColor = texel_type(0, 0, 0, 1));\n\n\t\t/// Access the sampler texture object\n\t\ttexture_type const& operator()() const;\n\n\t\t/// Fetch a texel from the sampler texture\n\t\ttexel_type texel_fetch(extent_type const& TexelCoord, size_type layer, size_type Face, size_type Level) const;\n\n\t\t/// Write a texel in the sampler texture\n\t\tvoid texel_write(extent_type const& TexelCoord, size_type layer, size_type Face, size_type Level, texel_type const& Texel);\n\n\t\t/// Clear the sampler texture with a uniform texel\n\t\tvoid clear(texel_type const& Texel);\n\n\t\t/// Sample the sampler texture at a specific level\n\t\ttexel_type texture_lod(normalized_type const& SampleCoord, size_type layer, size_type Face, level_type Level) const;\n\n\t\t/// Generate all the mipmaps of the sampler texture from the texture base level\n\t\tvoid generate_mipmaps(filter Minification);\n\n\t\t/// Generate the mipmaps of the sampler texture from the texture base level to the texture max level included\n\t\tvoid generate_mipmaps(size_type BaseLayer, size_type MaxLayer, size_type BaseFace, size_type MaxFace, size_type BaseLevel, size_type MaxLevel, filter Minification);\n\n\tprivate:\n\t\ttypedef typename detail::convert<texture_type, T, P>::func convert_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::fetchFunc fetch_type;\n\t\ttypedef typename detail::convert<texture_type, T, P>::writeFunc write_type;\n\t\ttypedef typename detail::filterBase<detail::DIMENSION_2D, texture_type, interpolate_type, normalized_type, fetch_type, texel_type>::filterFunc filter_type;\n\n\t\ttexture_type Texture;\n\t\tconvert_type Convert;\n\t\ttexel_type BorderColor;\n\t\tfilter_type Filter;\n\t};\n\n\ttypedef sampler_cube_array<float> fsamplerCubeArray;\n\ttypedef sampler_cube_array<double> dsamplerCubeArray;\n\ttypedef sampler_cube_array<unsigned int> usamplerCubeArray;\n\ttypedef sampler_cube_array<int> isamplerCubeArray;\n\n}//namespace gli\n\n#include \"./core/sampler_cube_array.inl\"\n"
  },
  {
    "path": "lib/gli/save.hpp",
    "content": "/// @brief Include to save DDS, KTX or KMG textures to files or memory.\n/// @file gli/save.hpp\n\n#pragma once\n\n#include \"save_dds.hpp\"\n#include \"save_ktx.hpp\"\n\nnamespace gli\n{\n\t/// Save a texture storage_linear to file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// The function use the filename extension included in the path to figure out the file container to use.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save(texture const & Texture, char const * Path);\n\n\t/// Save a texture storage_linear to file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// The function use the filename extension included in the path to figure out the file container to use.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save(texture const & Texture, std::string const & Path);\n}//namespace gli\n\n#include \"./core/save.inl\"\n"
  },
  {
    "path": "lib/gli/save_dds.hpp",
    "content": "/// @brief Include to save DDS textures to files or memory.\n/// @file gli/save_dds.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Save a texture storage_linear to a DDS file. We're assuming that the pixel data is tighty packed\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// This function ignores the filename extension in the path and save to DDS anyway but keep the requested filename extension.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_dds(texture const & Texture, char const* Path);\n\n\t/// Save a texture storage_linear to a DDS file. We're assuming that the pixel data is tighty packed\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// This function ignores the filename extension in the path and save to DDS anyway but keep the requested filename extension.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_dds(texture const & Texture, std::string const & Path);\n\n\t/// Save a texture storage_linear to a DDS file. We're assuming that the pixel data is tighty packed\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Memory Storage for the DDS container. The function resizes the containers to fit the necessary storage_linear.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_dds(texture const & Texture, std::vector<char> & Memory);\n}//namespace gli\n\n#include \"./core/save_dds.inl\"\n"
  },
  {
    "path": "lib/gli/save_kmg.hpp",
    "content": "/// @brief Include to save KMG textures to files or memory.\n/// @file gli/save_kmg.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Save a texture storage_linear to a KMG (Khronos Image) file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// This function ignores the filename extension in the path and save to KMG anyway but keep the requested filename extension.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_kmg(texture const & Texture, char const * Path);\n\n\t/// Save a texture storage_linear to a KMG (Khronos Image) file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// This function ignores the filename extension in the path and save to KMG anyway but keep the requested filename extension.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_kmg(texture const & Texture, std::string const & Path);\n\n\t/// Save a texture storage_linear to a KMG (Khronos Image) file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Memory Storage for the KMG container. The function resizes the containers to fit the necessary storage_linear.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_kmg(texture const & Texture, std::vector<char> & Memory);\n}//namespace gli\n\n#include \"./core/save_kmg.inl\"\n"
  },
  {
    "path": "lib/gli/save_ktx.hpp",
    "content": "/// @brief Include to save KTX textures to files or memory.\n/// @file gli/save_ktx.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n\nnamespace gli\n{\n\t/// Save a texture storage_linear to a KTX file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// This function ignores the filename extension in the path and save to KTX anyway but keep the requested filename extension.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_ktx(texture const & Texture, char const * Path);\n\n\t/// Save a texture storage_linear to a KTX file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Path Path for where to save the file. It must include the filaname and filename extension.\n\t/// This function ignores the filename extension in the path and save to KTX anyway but keep the requested filename extension.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_ktx(texture const & Texture, std::string const & Path);\n\n\t/// Save a texture storage_linear to a KTX file.\n\t///\n\t/// @param Texture Source texture to save\n\t/// @param Memory Storage for the KTX container. The function resizes the containers to fit the necessary storage_linear.\n\t/// @return Returns false if the function fails to save the file.\n\tbool save_ktx(texture const & Texture, std::vector<char> & Memory);\n}//namespace gli\n\n#include \"./core/save_ktx.inl\"\n"
  },
  {
    "path": "lib/gli/target.hpp",
    "content": "/// @brief Include to use the target enum and query properties of targets.\n/// @file gli/target.hpp\n\n#pragma once\n\nnamespace gli\n{\n\t/// Texture target: type/shape of the texture storage_linear\n\tenum target\n\t{\n\t\tTARGET_1D = 0, TARGET_FIRST = TARGET_1D,\n\t\tTARGET_1D_ARRAY,\n\t\tTARGET_2D,\n\t\tTARGET_2D_ARRAY,\n\t\tTARGET_3D,\n\t\tTARGET_RECT,\n\t\tTARGET_RECT_ARRAY,\n\t\tTARGET_CUBE,\n\t\tTARGET_CUBE_ARRAY, TARGET_LAST = TARGET_CUBE_ARRAY\n\t};\n\n\tenum\n\t{\n\t\tTARGET_COUNT = TARGET_LAST - TARGET_FIRST + 1,\n\t\tTARGET_INVALID = -1\n\t};\n\n\t/// Check whether a target is a 1D target\n\tinline bool is_target_1d(target Target)\n\t{\n\t\treturn Target == TARGET_1D || Target == TARGET_1D_ARRAY;\n\t}\n\n\t/// Check whether a target is an array target\n\tinline bool is_target_array(target Target)\n\t{\n\t\treturn Target == TARGET_1D_ARRAY || Target == TARGET_2D_ARRAY || Target == TARGET_CUBE_ARRAY;\n\t}\n\n\t/// Check whether a target is a cube map target\n\tinline bool is_target_cube(target Target)\n\t{\n\t\treturn Target == TARGET_CUBE || Target == TARGET_CUBE_ARRAY;\n\t}\n\t\n\t/// Check whether a target is a rectangle target\n\tinline bool is_target_rect(target Target)\n\t{\n\t\treturn Target == TARGET_RECT || Target == TARGET_RECT_ARRAY;\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/texture.hpp",
    "content": "/// @brief Include to use generic textures which can represent any texture target but they don't have target specific built-in caches making accesses slower.\n/// @file gli/texture.hpp\n\n#pragma once\n\n#include \"image.hpp\"\n#include \"target.hpp\"\n#include \"levels.hpp\"\n#include <array>\n\nnamespace gli\n{\n\t/// Genetic texture class. It can support any target.\n\tclass texture\n\t{\n\tpublic:\n\t\ttypedef size_t size_type;\n\t\ttypedef gli::target target_type;\n\t\ttypedef gli::format format_type;\n\t\ttypedef gli::swizzles swizzles_type;\n\t\ttypedef storage_linear storage_type;\n\t\ttypedef storage_type::data_type data_type;\n\t\ttypedef storage_type::extent_type extent_type;\n\n\t\t/// Create an empty texture instance\n\t\ttexture();\n\n\t\t/// Create a texture object and allocate a texture storage for it\n\t\t/// @param Target Type/Shape of the texture storage_linear\n\t\t/// @param Format Texel format\n\t\t/// @param Extent Size of the texture: width, height and depth.\n\t\t/// @param Layers Number of one-dimensional or two-dimensional images of identical size and format\n\t\t/// @param Faces 6 for cube map textures otherwise 1.\n\t\t/// @param Levels Number of images in the texture mipmap chain.\n\t\t/// @param Swizzles A mechanism to swizzle the components of a texture before they are applied according to the texture environment.\n\t\ttexture(\n\t\t\ttarget_type Target,\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tsize_type Faces,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture object by sharing an existing texture storage_type from another texture instance.\n\t\t/// This texture object is effectively a texture view where the layer, the face and the level allows identifying\n\t\t/// a specific subset of the texture storage_linear source. \n\t\t/// This texture object is effectively a texture view where the target and format can be reinterpreted\n\t\t/// with a different compatible texture target and texture format.\n\t\ttexture(\n\t\t\ttexture const& Texture,\n\t\t\ttarget_type Target,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture object by sharing an existing texture storage_type from another texture instance.\n\t\t/// This texture object is effectively a texture view where the target and format can be reinterpreted\n\t\t/// with a different compatible texture target and texture format.\n\t\ttexture(\n\t\t\ttexture const& Texture,\n\t\t\ttarget_type Target,\n\t\t\tformat_type Format,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\tvirtual ~texture(){}\n\n\t\t/// Return whether the texture instance is empty, no storage_type or description have been assigned to the instance.\n\t\tbool empty() const;\n\n\t\t/// Return the target of a texture instance.\n\t\ttarget_type target() const{return this->Target;}\n\n\t\t/// Return the texture instance format\n\t\tformat_type format() const;\n\n\t\tswizzles_type swizzles() const;\n\n\t\t/// Return the base layer of the texture instance, effectively a memory offset in the actual texture storage_type to identify where to start reading the layers. \n\t\tsize_type base_layer() const;\n\n\t\t/// Return the max layer of the texture instance, effectively a memory offset to the beginning of the last layer in the actual texture storage_type that the texture instance can access. \n\t\tsize_type max_layer() const;\n\n\t\t/// Return max_layer() - base_layer() + 1\n\t\tsize_type layers() const;\n\n\t\t/// Return the base face of the texture instance, effectively a memory offset in the actual texture storage_type to identify where to start reading the faces. \n\t\tsize_type base_face() const;\n\n\t\t/// Return the max face of the texture instance, effectively a memory offset to the beginning of the last face in the actual texture storage_type that the texture instance can access. \n\t\tsize_type max_face() const;\n\n\t\t/// Return max_face() - base_face() + 1\n\t\tsize_type faces() const;\n\n\t\t/// Return the base level of the texture instance, effectively a memory offset in the actual texture storage_type to identify where to start reading the levels. \n\t\tsize_type base_level() const;\n\n\t\t/// Return the max level of the texture instance, effectively a memory offset to the beginning of the last level in the actual texture storage_type that the texture instance can access. \n\t\tsize_type max_level() const;\n\n\t\t/// Return max_level() - base_level() + 1.\n\t\tsize_type levels() const;\n\n\t\t/// Return the size of a texture instance: width, height and depth.\n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Return the memory size of a texture instance storage_type in bytes.\n\t\tsize_type size() const;\n\n\t\t/// Return the number of blocks contained in a texture instance storage_type.\n\t\t/// genType size must match the block size conresponding to the texture format.\n\t\ttemplate <typename genType>\n\t\tsize_type size() const;\n\n\t\t/// Return the memory size of a specific level identified by Level.\n\t\tsize_type size(size_type Level) const;\n\n\t\t/// Return the memory size of a specific level identified by Level.\n\t\t/// genType size must match the block size conresponding to the texture format.\n\t\ttemplate <typename gen_type>\n\t\tsize_type size(size_type Level) const;\n\n\t\t/// Return a pointer to the beginning of the texture instance data.\n\t\tvoid* data();\n\n\t\t/// Return a pointer of type genType which size must match the texture format block size\n\t\ttemplate <typename gen_type>\n\t\tgen_type* data();\n\n\t\t/// Return a pointer to the beginning of the texture instance data.\n\t\tvoid const* data() const;\n\n\t\t/// Return a pointer of type genType which size must match the texture format block size\n\t\ttemplate <typename gen_type>\n\t\tgen_type const* data() const;\n\n\t\t/// Return a pointer to the beginning of the texture instance data.\n\t\tvoid* data(size_type Layer, size_type Face, size_type Level);\n\n\t\t/// Return a pointer to the beginning of the texture instance data.\n\t\tvoid const* const data(size_type Layer, size_type Face, size_type Level) const;\n\n\t\t/// Return a pointer of type genType which size must match the texture format block size\n\t\ttemplate <typename gen_type>\n\t\tgen_type* data(size_type Layer, size_type Face, size_type Level);\n\n\t\t/// Return a pointer of type genType which size must match the texture format block size\n\t\ttemplate <typename gen_type>\n\t\tgen_type const* const data(size_type Layer, size_type Face, size_type Level) const;\n\n\t\t/// Clear the entire texture storage_linear with zeros\n\t\tvoid clear();\n\n\t\t/// Clear the entire texture storage_linear with Texel which type must match the texture storage_linear format block size\n\t\t/// If the type of gen_type doesn't match the type of the texture format, no conversion is performed and the data will be reinterpreted as if is was of the texture format. \n\t\ttemplate <typename gen_type>\n\t\tvoid clear(gen_type const& Texel);\n\n\t\t/// Clear a specific image of a texture.\n\t\ttemplate <typename gen_type>\n\t\tvoid clear(size_type Layer, size_type Face, size_type Level, gen_type const& BlockData);\n\n\t\t/// Clear a subset of a specific image of a texture.\n\t\ttemplate <typename gen_type>\n\t\tvoid clear(size_type Layer, size_type Face, size_type Level, extent_type const& TexelOffset, extent_type const& TexelExtent, gen_type const& BlockData);\n\n\t\t/// Copy a specific image of a texture \n\t\tvoid copy(\n\t\t\ttexture const& TextureSrc,\n\t\t\tsize_t LayerSrc, size_t FaceSrc, size_t LevelSrc,\n\t\t\tsize_t LayerDst, size_t FaceDst, size_t LevelDst);\n\n\t\t/// Copy a subset of a specific image of a texture \n\t\tvoid copy(\n\t\t\ttexture const& TextureSrc,\n\t\t\tsize_t LayerSrc, size_t FaceSrc, size_t LevelSrc, extent_type const& OffsetSrc,\n\t\t\tsize_t LayerDst, size_t FaceDst, size_t LevelDst, extent_type const& OffsetDst,\n\t\t\textent_type const& Extent);\n\n\t\t/// Reorder the component in texture memory.\n\t\ttemplate <typename gen_type>\n\t\tvoid swizzle(gli::swizzles const& Swizzles);\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const & TexelCoord, size_type Layer, size_type Face, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Layer, size_type Face, size_type Level, gen_type const& Texel);\n\n\tprotected:\n\t\tstd::shared_ptr<storage_type> Storage;\n\t\ttarget_type Target;\n\t\tformat_type Format;\n\t\tsize_type BaseLayer;\n\t\tsize_type MaxLayer;\n\t\tsize_type BaseFace;\n\t\tsize_type MaxFace;\n\t\tsize_type BaseLevel;\n\t\tsize_type MaxLevel;\n\t\tswizzles_type Swizzles;\n\n\t\t// Pre compute at texture instance creation some information for faster access to texels\n\t\tstruct cache\n\t\t{\n\t\tpublic:\n\t\t\tenum ctor\n\t\t\t{\n\t\t\t\tDEFAULT\n\t\t\t};\n\n\t\t\texplicit cache(ctor)\n\t\t\t{}\n\n\t\t\tcache\n\t\t\t(\n\t\t\t\tstorage_type& Storage,\n\t\t\t\tformat_type Format,\n\t\t\t\tsize_type BaseLayer, size_type Layers,\n\t\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\t\tsize_type BaseLevel, size_type MaxLevel\n\t\t\t)\n\t\t\t\t: Faces(MaxFace - BaseFace + 1)\n\t\t\t\t, Levels(MaxLevel - BaseLevel + 1)\n\t\t\t{\n\t\t\t\tGLI_ASSERT(static_cast<size_t>(gli::levels(Storage.extent(0))) < this->ImageMemorySize.size());\n\n\t\t\t\tthis->BaseAddresses.resize(Layers * this->Faces * this->Levels);\n\n\t\t\t\tfor(size_type Layer = 0; Layer < Layers; ++Layer)\n\t\t\t\tfor(size_type Face = 0; Face < this->Faces; ++Face)\n\t\t\t\tfor(size_type Level = 0; Level < this->Levels; ++Level)\n\t\t\t\t{\n\t\t\t\t\tsize_type const Index = index_cache(Layer, Face, Level);\n\t\t\t\t\tthis->BaseAddresses[Index] = Storage.data() + Storage.base_offset(\n\t\t\t\t\t\tBaseLayer + Layer, BaseFace + Face, BaseLevel + Level);\n\t\t\t\t}\n\n\t\t\t\tfor(size_type Level = 0; Level < this->Levels; ++Level)\n\t\t\t\t{\n\t\t\t\t\textent_type const& SrcExtent = Storage.extent(BaseLevel + Level);\n\t\t\t\t\textent_type const& DstExtent = SrcExtent * block_extent(Format) / Storage.block_extent();\n\n\t\t\t\t\tthis->ImageExtent[Level] = glm::max(DstExtent, extent_type(1));\n\t\t\t\t\tthis->ImageMemorySize[Level] = Storage.level_size(BaseLevel + Level);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tthis->GlobalMemorySize = Storage.layer_size(BaseFace, MaxFace, BaseLevel, MaxLevel) * Layers;\n\t\t\t}\n\n\t\t\t// Base addresses of each images of a texture.\n\t\t\tdata_type* get_base_address(size_type Layer, size_type Face, size_type Level) const\n\t\t\t{\n\t\t\t\treturn this->BaseAddresses[index_cache(Layer, Face, Level)];\n\t\t\t}\n\n\t\t\t// In texels\n\t\t\textent_type get_extent(size_type Level) const\n\t\t\t{\n\t\t\t\treturn this->ImageExtent[Level];\n\t\t\t};\n\n\t\t\t// In bytes\n\t\t\tsize_type get_memory_size(size_type Level) const\n\t\t\t{\n\t\t\t\treturn this->ImageMemorySize[Level];\n\t\t\t};\n\n\t\t\t// In bytes\n\t\t\tsize_type get_memory_size() const\n\t\t\t{\n\t\t\t\treturn this->GlobalMemorySize;\n\t\t\t};\n\n\t\tprivate:\n\t\t\tsize_type index_cache(size_type Layer, size_type Face, size_type Level) const\n\t\t\t{\n\t\t\t\treturn ((Layer * this->Faces) + Face) * this->Levels + Level;\n\t\t\t}\n\n\t\t\tsize_type Faces;\n\t\t\tsize_type Levels;\n\t\t\tstd::vector<data_type*> BaseAddresses;\n\t\t\tstd::array<extent_type, 16> ImageExtent;\n\t\t\tstd::array<size_type, 16> ImageMemorySize;\n\t\t\tsize_type GlobalMemorySize;\n\t\t} Cache;\n\t};\n}//namespace gli\n\n#include \"./core/texture.inl\"\n\n"
  },
  {
    "path": "lib/gli/texture1d.hpp",
    "content": "/// @brief Include to use 1d textures.\n/// @file gli/texture1d.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n#include \"image.hpp\"\n\nnamespace gli\n{\n\t/// 1d texture\n\tclass texture1d : public texture\n\t{\n\tpublic:\n\t\ttypedef extent1d extent_type;\n\n\t\t/// Create an empty texture 1D\n\t\ttexture1d();\n\n\t\t/// Create a texture1d and allocate a new storage_linear\n\t\ttexture1d(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture1d and allocate a new storage_linear with a complete mipmap chain\n\t\ttexture1d(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture1d view with an existing storage_linear\n\t\texplicit texture1d(\n\t\t\ttexture const& Texture);\n\n\t\t/// Create a texture1d view with an existing storage_linear\n\t\ttexture1d(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture1d view, reference a subset of an existing texture1d instance\n\t\ttexture1d(\n\t\t\ttexture1d const& Texture,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the image identified by Level in the mipmap chain of the texture\n\t\timage operator[](size_type Level) const;\n\n\t\t/// Return the width of a texture instance \n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const& TexelCoord, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture1d.inl\"\n"
  },
  {
    "path": "lib/gli/texture1d_array.hpp",
    "content": "/// @brief Include to use 1d array textures.\n/// @file gli/texture1d_array.hpp\n\n#pragma once\n\n#include \"texture1d.hpp\"\n\nnamespace gli\n{\n\t/// 1d array texture\n\tclass texture1d_array : public texture\n\t{\n\tpublic:\n\t\ttypedef extent1d extent_type;\n\n\tpublic:\n\t\t/// Create an empty texture 1D array\n\t\ttexture1d_array();\n\n\t\t/// Create a texture1d_array and allocate a new storage_linear\n\t\ttexture1d_array(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture1d_array and allocate a new storage_linear with a complete mipmap chain\n\t\ttexture1d_array(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture1d_array view with an existing storage_linear\n\t\texplicit texture1d_array(\n\t\t\ttexture const& Texture);\n\n\t\t/// Create a texture1d_array view with an existing storage_linear\n\t\ttexture1d_array(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture view, reference a subset of an exiting storage_linear\n\t\ttexture1d_array(\n\t\t\ttexture1d_array const& Texture,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the texture identified by Layer in the texture array\n\t\ttexture1d operator[](size_type Layer) const;\n\n\t\t/// Return the width of a texture instance\n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const& TexelCoord, size_type Layer, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Layer, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture1d_array.inl\"\n"
  },
  {
    "path": "lib/gli/texture2d.hpp",
    "content": "/// @brief Include to use 2d textures.\n/// @file gli/texture2d.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n#include \"image.hpp\"\n\nnamespace gli\n{\n\t/// 2d texture\n\tclass texture2d : public texture\n\t{\n\tpublic:\n\t\ttypedef extent2d extent_type;\n\n\t\t/// Create an empty texture 2D.\n\t\ttexture2d();\n\n\t\t/// Create a texture2d and allocate a new storage_linear.\n\t\ttexture2d(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture2d and allocate a new storage_linear with a complete mipmap chain.\n\t\ttexture2d(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture2d view with an existing storage_linear.\n\t\texplicit texture2d(\n\t\t\ttexture const& Texture);\n\n\t\t/// Create a texture2d view with an existing storage_linear.\n\t\ttexture2d(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture2d view, reference a subset of an existing texture2d instance.\n\t\ttexture2d(\n\t\t\ttexture2d const& Texture,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the image identified by Level in the mipmap chain of the texture.\n\t\timage operator[](size_type Level) const;\n\n\t\t/// Return the dimensions of a texture instance: width and height.\n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const& TexelCoord, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture2d.inl\"\n"
  },
  {
    "path": "lib/gli/texture2d_array.hpp",
    "content": "/// @brief Include to use 2d array textures.\n/// @file gli/texture2d_array.hpp\n\n#pragma once\n\n#include \"texture2d.hpp\"\n\nnamespace gli\n{\n\t/// 2d array texture\n\tclass texture2d_array : public texture\n\t{\n\tpublic:\n\t\ttypedef extent2d extent_type;\n\n\tpublic:\n\t\t/// Create an empty texture 2D array\n\t\ttexture2d_array();\n\n\t\t/// Create a texture2d_array and allocate a new storage_linear\n\t\ttexture2d_array(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture2d_array and allocate a new storage_linear with a complete mipmap chain\n\t\ttexture2d_array(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture2d_array view with an existing storage_linear\n\t\texplicit texture2d_array(\n\t\t\ttexture const& Texture);\n\n\t\t/// Create a texture2d_array view with an existing storage_linear\n\t\ttexture2d_array(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture view, reference a subset of an exiting texture2d_array instance\n\t\ttexture2d_array(\n\t\t\ttexture2d_array const& Texture,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the texture identified by Layer in the texture array\n\t\ttexture2d operator[](size_type Layer) const;\n\n\t\t/// Return the dimensions of a texture instance: width and height \n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const& TexelCoord, size_type Layer, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Layer, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture2d_array.inl\"\n"
  },
  {
    "path": "lib/gli/texture3d.hpp",
    "content": "/// @brief Include to use 3d textures.\n/// @file gli/texture3d.hpp\n\n#pragma once\n\n#include \"texture.hpp\"\n#include \"image.hpp\"\n\nnamespace gli\n{\n\t/// 3d texture\n\tclass texture3d : public texture\n\t{\n\tpublic:\n\t\ttypedef extent3d extent_type;\n\n\tpublic:\n\t\t/// Create an empty texture 3D\n\t\ttexture3d();\n\n\t\t/// Create a texture3d and allocate a new storage_linear\n\t\ttexture3d(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture3d and allocate a new storage_linear with a complete mipmap chain\n\t\ttexture3d(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture3d view with an existing storage_linear\n\t\texplicit texture3d(\n\t\t\ttexture const & Texture);\n\n\t\t/// Create a texture3d view with an existing storage_linear\n\t\ttexture3d(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture3d view, reference a subset of an existing texture3d instance\n\t\ttexture3d(\n\t\t\ttexture3d const & Texture,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the image identified by Level in the mipmap chain of the texture\n\t\timage operator[](size_type Level) const;\n\n\t\t/// Return the dimensions of a texture instance: width, height and depth \n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const& TexelCoord, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture3d.inl\"\n"
  },
  {
    "path": "lib/gli/texture_cube.hpp",
    "content": "/// @brief Include to use cube map textures.\n/// @file gli/texture_cube.hpp\n\n#pragma once\n\n#include \"texture2d.hpp\"\n\nnamespace gli\n{\n\t/// Cube map texture\n\tclass texture_cube : public texture\n\t{\n\tpublic:\n\t\ttypedef extent2d extent_type;\n\n\tpublic:\n\t\t/// Create an empty texture cube\n\t\ttexture_cube();\n\n\t\t/// Create a texture_cube and allocate a new storage_linear\n\t\ttexture_cube(\n\t\t\tformat_type Format,\n\t\t\textent_type const & Extent,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture_cube and allocate a new storage_linear with a complete mipmap chain\n\t\ttexture_cube(\n\t\t\tformat_type Format,\n\t\t\textent_type const & Extent,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture_cube view with an existing storage_linear\n\t\texplicit texture_cube(\n\t\t\ttexture const& Texture);\n\n\t\t/// Create a texture_cube view with an existing storage_linear\n\t\ttexture_cube(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture_cube view, reference a subset of an existing texture_cube instance\n\t\ttexture_cube(\n\t\t\ttexture_cube const& Texture,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the texture identified by Face in the texture cube\n\t\ttexture2d operator[](size_type Face) const;\n\n\t\t/// Return the dimensions of a texture instance: width and height where both should be equal.\n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const& TexelCoord, size_type Face, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Face, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture_cube.inl\"\n"
  },
  {
    "path": "lib/gli/texture_cube_array.hpp",
    "content": "/// @brief Include to use cube map array textures.\n/// @file gli/texture_cube_array.hpp\n\n#pragma once\n\n#include \"texture_cube.hpp\"\n\nnamespace gli\n{\n\t/// Cube map array texture\n\tclass texture_cube_array : public texture\n\t{\n\tpublic:\n\t\ttypedef extent2d extent_type;\n\n\tpublic:\n\t\t/// Create an empty texture cube array\n\t\ttexture_cube_array();\n\n\t\t/// Create a texture_cube_array and allocate a new storage_linear\n\t\ttexture_cube_array(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tsize_type Levels,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture_cube_array and allocate a new storage_linear with a complete mipmap chain\n\t\ttexture_cube_array(\n\t\t\tformat_type Format,\n\t\t\textent_type const& Extent,\n\t\t\tsize_type Layers,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture_cube_array view with an existing storage_linear\n\t\texplicit texture_cube_array(\n\t\t\ttexture const& Texture);\n\n\t\t/// Reference a subset of an exiting storage_linear constructor\n\t\ttexture_cube_array(\n\t\t\ttexture const& Texture,\n\t\t\tformat_type Format,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel,\n\t\t\tswizzles_type const& Swizzles = swizzles_type(SWIZZLE_RED, SWIZZLE_GREEN, SWIZZLE_BLUE, SWIZZLE_ALPHA));\n\n\t\t/// Create a texture view, reference a subset of an exiting texture_cube_array instance\n\t\ttexture_cube_array(\n\t\t\ttexture_cube_array const& Texture,\n\t\t\tsize_type BaseLayer, size_type MaxLayer,\n\t\t\tsize_type BaseFace, size_type MaxFace,\n\t\t\tsize_type BaseLevel, size_type MaxLevel);\n\n\t\t/// Create a view of the texture identified by Layer in the texture array\n\t\ttexture_cube operator[](size_type Layer) const;\n\n\t\t/// Return the dimensions of a texture instance: width and height where both should be equal.\n\t\textent_type extent(size_type Level = 0) const;\n\n\t\t/// Fetch a texel from a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tgen_type load(extent_type const & TexelCoord, size_type Layer, size_type Face, size_type Level) const;\n\n\t\t/// Write a texel to a texture. The texture format must be uncompressed.\n\t\ttemplate <typename gen_type>\n\t\tvoid store(extent_type const& TexelCoord, size_type Layer, size_type Face, size_type Level, gen_type const& Texel);\n\t};\n}//namespace gli\n\n#include \"./core/texture_cube_array.inl\"\n\n"
  },
  {
    "path": "lib/gli/transform.hpp",
    "content": "/// @brief Include to perform arithmetic per texel between two textures.\n/// @file gli/transform.hpp\n\n#pragma once\n\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\nnamespace gli\n{\n\ttemplate <typename vec_type>\n\tstruct transform_func\n\t{\n\t\ttypedef vec_type(*type)(vec_type const & A, vec_type const & B);\n\t};\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture1d & Out, texture1d const & In0, texture1d const & In1, typename transform_func<vec_type>::type TexelFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture1d_array & Out, texture1d_array const & In0, texture1d_array const & In1, typename transform_func<vec_type>::type TexelFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture2d & Out, texture2d const & In0, texture2d const & In1, typename transform_func<vec_type>::type TexelFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture2d_array & Out, texture2d_array const & In0, texture2d_array const & In1, typename transform_func<vec_type>::type TexelFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture3d & Out, texture3d const & In0, texture3d const & In1, typename transform_func<vec_type>::type TexelFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture_cube & Out, texture_cube const & In0, texture_cube const & In1, typename transform_func<vec_type>::type TexelFunc);\n\n\t/// Compute per-texel operations using a user defined function.\n\t///\n\t/// @param Out Output texture.\n\t/// @param In0 First input texture.\n\t/// @param In1 Second input texture.\n\t/// @param TexelFunc Pointer to a binary function.\n\ttemplate <typename vec_type>\n\tvoid transform(texture_cube_array & Out, texture_cube_array const & In0, texture_cube_array const & In1, typename transform_func<vec_type>::type TexelFunc);\n\t\n}//namespace gli\n\n#include \"./core/transform.inl\"\n"
  },
  {
    "path": "lib/gli/type.hpp",
    "content": "/// @brief Include to use basic GLI types.\n/// @file gli/type.hpp\n\n#pragma once\n\n// STD\n#include <cstddef>\n\n// GLM\n#define GLM_FORCE_EXPLICIT_CTOR\n#include <glm/glm.hpp>\n#include <glm/ext/vector_int1.hpp>\n#include <glm/ext/scalar_uint_sized.hpp>\n\n#if GLM_COMPILER & GLM_COMPILER_VC\n#\tdefine GLI_FORCE_INLINE __forceinline\n#elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_APPLE_CLANG | GLM_COMPILER_LLVM)\n#\tdefine GLI_FORCE_INLINE inline __attribute__((__always_inline__))\n#else\n#\tdefine GLI_FORCE_INLINE inline\n#endif//GLM_COMPILER\n\n#define GLI_DISABLE_ASSERT 0\n\n#if defined(NDEBUG) || GLI_DISABLE_ASSERT\n#\tdefine GLI_ASSERT(test)\n#else\n#\tdefine GLI_ASSERT(test) assert((test))\n#endif\n\nnamespace gli\n{\n\tusing namespace glm;\n\n\tusing std::size_t;\n\ttypedef glm::uint8 byte;\n\n\ttypedef ivec1 extent1d;\n\ttypedef ivec2 extent2d;\n\ttypedef ivec3 extent3d;\n\ttypedef ivec4 extent4d;\n\n\ttemplate <typename T, qualifier P>\n\tinline vec<4, T, P> make_vec4(vec<1, T, P> const & v)\n\t{\n\t\treturn vec<4, T, P>(v.x, static_cast<T>(0), static_cast<T>(0), static_cast<T>(1));\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline vec<4, T, P> make_vec4(vec<2, T, P> const & v)\n\t{\n\t\treturn vec<4, T, P>(v.x, v.y, static_cast<T>(0), static_cast<T>(1));\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline vec<4, T, P> make_vec4(vec<3, T, P> const & v)\n\t{\n\t\treturn vec<4, T, P>(v.x, v.y, v.z, static_cast<T>(1));\n\t}\n\n\ttemplate <typename T, qualifier P>\n\tinline vec<4, T, P> make_vec4(vec<4, T, P> const & v)\n\t{\n\t\treturn v;\n\t}\n}//namespace gli\n"
  },
  {
    "path": "lib/gli/view.hpp",
    "content": "/// @brief Include create views of textures, either to isolate a subset or to reinterpret data without memory copy.\n/// @file gli/view.hpp\n\n#pragma once\n\n#include \"image.hpp\"\n#include \"texture.hpp\"\n#include \"texture1d.hpp\"\n#include \"texture1d_array.hpp\"\n#include \"texture2d.hpp\"\n#include \"texture2d_array.hpp\"\n#include \"texture3d.hpp\"\n#include \"texture_cube.hpp\"\n#include \"texture_cube_array.hpp\"\n\nnamespace gli\n{\n\t/// Create an image view of an existing image, sharing the same memory storage_linear.\n\timage view(image const & Image);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear.\n\ttexture view(texture const & Texture);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of layers, levels and faces.\n\ttexture view(\n\t\ttexture const & Texture,\n\t\ttexture::size_type BaseLayer, texture::size_type MaxLayer,\n\t\ttexture::size_type BaseFace, texture::size_type MaxFace,\n\t\ttexture::size_type BaseLevel, texture::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear.\n\ttemplate <typename texType>\n\ttexture view(texType const & Texture);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but a different format.\n\t/// The format must be a compatible format, a format which block size match the original format. \n\ttemplate <typename texType>\n\ttexture view(texType const & Texture, format Format);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of levels.\n\ttexture view(\n\t\ttexture1d const & Texture,\n\t\ttexture1d::size_type BaseLevel, texture1d::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of levels and layers.\n\ttexture view(\n\t\ttexture1d_array const & Texture,\n\t\ttexture1d_array::size_type BaseLayer, texture1d_array::size_type MaxLayer,\n\t\ttexture1d_array::size_type BaseLevel, texture1d_array::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of levels.\n\ttexture view(\n\t\ttexture2d const & Texture,\n\t\ttexture2d::size_type BaseLevel, texture2d::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of levels and layers.\n\ttexture view(\n\t\ttexture2d_array const & Texture,\n\t\ttexture2d_array::size_type BaseLayer, texture2d_array::size_type MaxLayer,\n\t\ttexture2d_array::size_type BaseLevel, texture2d_array::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of levels.\n\ttexture view(\n\t\ttexture3d const & Texture,\n\t\ttexture3d::size_type BaseLevel, texture3d::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of levels and faces.\n\ttexture view(\n\t\ttexture_cube const & Texture,\n\t\ttexture_cube::size_type BaseFace, texture_cube::size_type MaxFace,\n\t\ttexture_cube::size_type BaseLevel, texture_cube::size_type MaxLevel);\n\n\t/// Create a texture view of an existing texture, sharing the same memory storage_linear but giving access only to a subset of layers, levels and faces.\n\ttexture view(\n\t\ttexture_cube_array const & Texture,\n\t\ttexture_cube_array::size_type BaseLayer, texture_cube_array::size_type MaxLayer,\n\t\ttexture_cube_array::size_type BaseFace, texture_cube_array::size_type MaxFace,\n\t\ttexture_cube_array::size_type BaseLevel, texture_cube_array::size_type MaxLevel);\n}//namespace gli\n\n#include \"./core/view.inl\"\n"
  },
  {
    "path": "lib/nlohmannjson/include/nlohmann/json.hpp",
    "content": "//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n/****************************************************************************\\\n * Note on documentation: The source files contain links to the online      *\n * documentation of the public API at https://json.nlohmann.me. This URL    *\n * contains the most recent documentation and should also be applicable to  *\n * previous versions; documentation for deprecated functions is not         *\n * removed, but marked deprecated. See \"Generate documentation\" section in  *\n * file docs/README.md.                                                     *\n\\****************************************************************************/\n\n#ifndef INCLUDE_NLOHMANN_JSON_HPP_\n#define INCLUDE_NLOHMANN_JSON_HPP_\n\n#include <algorithm> // all_of, find, for_each\n#include <cstddef> // nullptr_t, ptrdiff_t, size_t\n#include <functional> // hash, less\n#include <initializer_list> // initializer_list\n#ifndef JSON_NO_IO\n    #include <iosfwd> // istream, ostream\n#endif  // JSON_NO_IO\n#include <iterator> // random_access_iterator_tag\n#include <memory> // unique_ptr\n#include <string> // string, stoi, to_string\n#include <utility> // declval, forward, move, pair, swap\n#include <vector> // vector\n\n// #include <nlohmann/adl_serializer.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <utility>\n\n// #include <nlohmann/detail/abi_macros.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// This file contains all macro definitions affecting or depending on the ABI\n\n#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK\n    #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)\n        #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0\n            #warning \"Already included a different version of the library!\"\n        #endif\n    #endif\n#endif\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3   // NOLINT(modernize-macro-to-enum)\n#define NLOHMANN_JSON_VERSION_MINOR 12  // NOLINT(modernize-macro-to-enum)\n#define NLOHMANN_JSON_VERSION_PATCH 0   // NOLINT(modernize-macro-to-enum)\n\n#ifndef JSON_DIAGNOSTICS\n    #define JSON_DIAGNOSTICS 0\n#endif\n\n#ifndef JSON_DIAGNOSTIC_POSITIONS\n    #define JSON_DIAGNOSTIC_POSITIONS 0\n#endif\n\n#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n    #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0\n#endif\n\n#if JSON_DIAGNOSTICS\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag\n#else\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS\n#endif\n\n#if JSON_DIAGNOSTIC_POSITIONS\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp\n#else\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS\n#endif\n\n#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp\n#else\n    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON\n#endif\n\n#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION\n    #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0\n#endif\n\n// Construct the namespace ABI tags component\n#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c\n#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \\\n    NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)\n\n#define NLOHMANN_JSON_ABI_TAGS                                       \\\n    NLOHMANN_JSON_ABI_TAGS_CONCAT(                                   \\\n            NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS,                       \\\n            NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \\\n            NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)\n\n// Construct the namespace version component\n#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \\\n    _v ## major ## _ ## minor ## _ ## patch\n#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \\\n    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)\n\n#if NLOHMANN_JSON_NAMESPACE_NO_VERSION\n#define NLOHMANN_JSON_NAMESPACE_VERSION\n#else\n#define NLOHMANN_JSON_NAMESPACE_VERSION                                 \\\n    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \\\n                                           NLOHMANN_JSON_VERSION_MINOR, \\\n                                           NLOHMANN_JSON_VERSION_PATCH)\n#endif\n\n// Combine namespace components\n#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b\n#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \\\n    NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)\n\n#ifndef NLOHMANN_JSON_NAMESPACE\n#define NLOHMANN_JSON_NAMESPACE               \\\n    nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \\\n            NLOHMANN_JSON_ABI_TAGS,           \\\n            NLOHMANN_JSON_NAMESPACE_VERSION)\n#endif\n\n#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN\n#define NLOHMANN_JSON_NAMESPACE_BEGIN                \\\n    namespace nlohmann                               \\\n    {                                                \\\n    inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \\\n                NLOHMANN_JSON_ABI_TAGS,              \\\n                NLOHMANN_JSON_NAMESPACE_VERSION)     \\\n    {\n#endif\n\n#ifndef NLOHMANN_JSON_NAMESPACE_END\n#define NLOHMANN_JSON_NAMESPACE_END                                     \\\n    }  /* namespace (inline namespace) NOLINT(readability/namespace) */ \\\n    }  // namespace nlohmann\n#endif\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <algorithm> // transform\n#include <array> // array\n#include <forward_list> // forward_list\n#include <iterator> // inserter, front_inserter, end\n#include <map> // map\n#ifdef JSON_HAS_CPP_17\n    #include <optional> // optional\n#endif\n#include <string> // string\n#include <tuple> // tuple, make_tuple\n#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible\n#include <unordered_map> // unordered_map\n#include <utility> // pair, declval\n#include <valarray> // valarray\n\n// #include <nlohmann/detail/exceptions.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef> // nullptr_t\n#include <exception> // exception\n#if JSON_DIAGNOSTICS\n    #include <numeric> // accumulate\n#endif\n#include <stdexcept> // runtime_error\n#include <string> // to_string\n#include <vector> // vector\n\n// #include <nlohmann/detail/value_t.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t\n#include <string> // string\n\n// #include <nlohmann/detail/macro_scope.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <utility> // declval, pair\n// #include <nlohmann/detail/meta/detected.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <type_traits>\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename ...Ts> struct make_void\n{\n    using type = void;\n};\ntemplate<typename ...Ts> using void_t = typename make_void<Ts...>::type;\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n// https://en.cppreference.com/w/cpp/experimental/is_detected\nstruct nonesuch\n{\n    nonesuch() = delete;\n    ~nonesuch() = delete;\n    nonesuch(nonesuch const&) = delete;\n    nonesuch(nonesuch const&&) = delete;\n    void operator=(nonesuch const&) = delete;\n    void operator=(nonesuch&&) = delete;\n};\n\ntemplate<class Default,\n         class AlwaysVoid,\n         template<class...> class Op,\n         class... Args>\nstruct detector\n{\n    using value_t = std::false_type;\n    using type = Default;\n};\n\ntemplate<class Default, template<class...> class Op, class... Args>\nstruct detector<Default, void_t<Op<Args...>>, Op, Args...>\n{\n    using value_t = std::true_type;\n    using type = Op<Args...>;\n};\n\ntemplate<template<class...> class Op, class... Args>\nusing is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;\n\ntemplate<template<class...> class Op, class... Args>\nstruct is_detected_lazy : is_detected<Op, Args...> { };\n\ntemplate<template<class...> class Op, class... Args>\nusing detected_t = typename detector<nonesuch, void, Op, Args...>::type;\n\ntemplate<class Default, template<class...> class Op, class... Args>\nusing detected_or = detector<Default, void, Op, Args...>;\n\ntemplate<class Default, template<class...> class Op, class... Args>\nusing detected_or_t = typename detected_or<Default, Op, Args...>::type;\n\ntemplate<class Expected, template<class...> class Op, class... Args>\nusing is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;\n\ntemplate<class To, template<class...> class Op, class... Args>\nusing is_detected_convertible =\n    std::is_convertible<detected_t<Op, Args...>, To>;\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/thirdparty/hedley/hedley.hpp>\n\n\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-FileCopyrightText: 2016 - 2021 Evan Nemerson <evan@nemerson.com>\n// SPDX-License-Identifier: MIT\n\n/* Hedley - https://nemequ.github.io/hedley\n * Created by Evan Nemerson <evan@nemerson.com>\n */\n\n#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 15)\n#if defined(JSON_HEDLEY_VERSION)\n    #undef JSON_HEDLEY_VERSION\n#endif\n#define JSON_HEDLEY_VERSION 15\n\n#if defined(JSON_HEDLEY_STRINGIFY_EX)\n    #undef JSON_HEDLEY_STRINGIFY_EX\n#endif\n#define JSON_HEDLEY_STRINGIFY_EX(x) #x\n\n#if defined(JSON_HEDLEY_STRINGIFY)\n    #undef JSON_HEDLEY_STRINGIFY\n#endif\n#define JSON_HEDLEY_STRINGIFY(x) JSON_HEDLEY_STRINGIFY_EX(x)\n\n#if defined(JSON_HEDLEY_CONCAT_EX)\n    #undef JSON_HEDLEY_CONCAT_EX\n#endif\n#define JSON_HEDLEY_CONCAT_EX(a,b) a##b\n\n#if defined(JSON_HEDLEY_CONCAT)\n    #undef JSON_HEDLEY_CONCAT\n#endif\n#define JSON_HEDLEY_CONCAT(a,b) JSON_HEDLEY_CONCAT_EX(a,b)\n\n#if defined(JSON_HEDLEY_CONCAT3_EX)\n    #undef JSON_HEDLEY_CONCAT3_EX\n#endif\n#define JSON_HEDLEY_CONCAT3_EX(a,b,c) a##b##c\n\n#if defined(JSON_HEDLEY_CONCAT3)\n    #undef JSON_HEDLEY_CONCAT3\n#endif\n#define JSON_HEDLEY_CONCAT3(a,b,c) JSON_HEDLEY_CONCAT3_EX(a,b,c)\n\n#if defined(JSON_HEDLEY_VERSION_ENCODE)\n    #undef JSON_HEDLEY_VERSION_ENCODE\n#endif\n#define JSON_HEDLEY_VERSION_ENCODE(major,minor,revision) (((major) * 1000000) + ((minor) * 1000) + (revision))\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_MAJOR)\n    #undef JSON_HEDLEY_VERSION_DECODE_MAJOR\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_MAJOR(version) ((version) / 1000000)\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_MINOR)\n    #undef JSON_HEDLEY_VERSION_DECODE_MINOR\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_MINOR(version) (((version) % 1000000) / 1000)\n\n#if defined(JSON_HEDLEY_VERSION_DECODE_REVISION)\n    #undef JSON_HEDLEY_VERSION_DECODE_REVISION\n#endif\n#define JSON_HEDLEY_VERSION_DECODE_REVISION(version) ((version) % 1000)\n\n#if defined(JSON_HEDLEY_GNUC_VERSION)\n    #undef JSON_HEDLEY_GNUC_VERSION\n#endif\n#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)\n    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)\n#elif defined(__GNUC__)\n    #define JSON_HEDLEY_GNUC_VERSION JSON_HEDLEY_VERSION_ENCODE(__GNUC__, __GNUC_MINOR__, 0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_VERSION_CHECK)\n    #undef JSON_HEDLEY_GNUC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_GNUC_VERSION)\n    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GNUC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_MSVC_VERSION)\n    #undef JSON_HEDLEY_MSVC_VERSION\n#endif\n#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 10000000, (_MSC_FULL_VER % 10000000) / 100000, (_MSC_FULL_VER % 100000) / 100)\n#elif defined(_MSC_FULL_VER) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_FULL_VER / 1000000, (_MSC_FULL_VER % 1000000) / 10000, (_MSC_FULL_VER % 10000) / 10)\n#elif defined(_MSC_VER) && !defined(__ICL)\n    #define JSON_HEDLEY_MSVC_VERSION JSON_HEDLEY_VERSION_ENCODE(_MSC_VER / 100, _MSC_VER % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_MSVC_VERSION_CHECK)\n    #undef JSON_HEDLEY_MSVC_VERSION_CHECK\n#endif\n#if !defined(JSON_HEDLEY_MSVC_VERSION)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (0)\n#elif defined(_MSC_VER) && (_MSC_VER >= 1400)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))\n#elif defined(_MSC_VER) && (_MSC_VER >= 1200)\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))\n#else\n    #define JSON_HEDLEY_MSVC_VERSION_CHECK(major,minor,patch) (_MSC_VER >= ((major * 100) + (minor)))\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_VERSION)\n    #undef JSON_HEDLEY_INTEL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && !defined(__ICL)\n    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, __INTEL_COMPILER_UPDATE)\n#elif defined(__INTEL_COMPILER) && !defined(__ICL)\n    #define JSON_HEDLEY_INTEL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_VERSION_CHECK)\n    #undef JSON_HEDLEY_INTEL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_INTEL_VERSION)\n    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_INTEL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION)\n    #undef JSON_HEDLEY_INTEL_CL_VERSION\n#endif\n#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) && defined(__ICL)\n    #define JSON_HEDLEY_INTEL_CL_VERSION JSON_HEDLEY_VERSION_ENCODE(__INTEL_COMPILER, __INTEL_COMPILER_UPDATE, 0)\n#endif\n\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION_CHECK)\n    #undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_INTEL_CL_VERSION)\n    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_INTEL_CL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_INTEL_CL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_PGI_VERSION)\n    #undef JSON_HEDLEY_PGI_VERSION\n#endif\n#if defined(__PGI) && defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)\n    #define JSON_HEDLEY_PGI_VERSION JSON_HEDLEY_VERSION_ENCODE(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)\n#endif\n\n#if defined(JSON_HEDLEY_PGI_VERSION_CHECK)\n    #undef JSON_HEDLEY_PGI_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_PGI_VERSION)\n    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PGI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_PGI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_SUNPRO_VERSION)\n    #undef JSON_HEDLEY_SUNPRO_VERSION\n#endif\n#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), (__SUNPRO_C & 0xf) * 10)\n#elif defined(__SUNPRO_C)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_C >> 8) & 0xf, (__SUNPRO_C >> 4) & 0xf, (__SUNPRO_C) & 0xf)\n#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), (__SUNPRO_CC & 0xf) * 10)\n#elif defined(__SUNPRO_CC)\n    #define JSON_HEDLEY_SUNPRO_VERSION JSON_HEDLEY_VERSION_ENCODE((__SUNPRO_CC >> 8) & 0xf, (__SUNPRO_CC >> 4) & 0xf, (__SUNPRO_CC) & 0xf)\n#endif\n\n#if defined(JSON_HEDLEY_SUNPRO_VERSION_CHECK)\n    #undef JSON_HEDLEY_SUNPRO_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_SUNPRO_VERSION)\n    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_SUNPRO_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_SUNPRO_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)\n    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION\n#endif\n#if defined(__EMSCRIPTEN__)\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION JSON_HEDLEY_VERSION_ENCODE(__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__)\n#endif\n\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK)\n    #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_EMSCRIPTEN_VERSION)\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_EMSCRIPTEN_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_ARM_VERSION)\n    #undef JSON_HEDLEY_ARM_VERSION\n#endif\n#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCOMPILER_VERSION / 1000000, (__ARMCOMPILER_VERSION % 1000000) / 10000, (__ARMCOMPILER_VERSION % 10000) / 100)\n#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ARMCC_VERSION / 1000000, (__ARMCC_VERSION % 1000000) / 10000, (__ARMCC_VERSION % 10000) / 100)\n#endif\n\n#if defined(JSON_HEDLEY_ARM_VERSION_CHECK)\n    #undef JSON_HEDLEY_ARM_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_ARM_VERSION)\n    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_ARM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_ARM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_IBM_VERSION)\n    #undef JSON_HEDLEY_IBM_VERSION\n#endif\n#if defined(__ibmxl__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__ibmxl_version__, __ibmxl_release__, __ibmxl_modification__)\n#elif defined(__xlC__) && defined(__xlC_ver__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)\n#elif defined(__xlC__)\n    #define JSON_HEDLEY_IBM_VERSION JSON_HEDLEY_VERSION_ENCODE(__xlC__ >> 8, __xlC__ & 0xff, 0)\n#endif\n\n#if defined(JSON_HEDLEY_IBM_VERSION_CHECK)\n    #undef JSON_HEDLEY_IBM_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_IBM_VERSION)\n    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IBM_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_IBM_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_VERSION)\n    #undef JSON_HEDLEY_TI_VERSION\n#endif\n#if \\\n    defined(__TI_COMPILER_VERSION__) && \\\n    ( \\\n      defined(__TMS470__) || defined(__TI_ARM__) || \\\n      defined(__MSP430__) || \\\n      defined(__TMS320C2000__) \\\n    )\n#if (__TI_COMPILER_VERSION__ >= 16000000)\n    #define JSON_HEDLEY_TI_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n#endif\n\n#if defined(JSON_HEDLEY_TI_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_VERSION)\n    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION)\n    #undef JSON_HEDLEY_TI_CL2000_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C2000__)\n    #define JSON_HEDLEY_TI_CL2000_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL2000_VERSION)\n    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL2000_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL2000_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL430_VERSION)\n    #undef JSON_HEDLEY_TI_CL430_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__MSP430__)\n    #define JSON_HEDLEY_TI_CL430_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL430_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL430_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL430_VERSION)\n    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL430_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL430_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)\n    #undef JSON_HEDLEY_TI_ARMCL_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && (defined(__TMS470__) || defined(__TI_ARM__))\n    #define JSON_HEDLEY_TI_ARMCL_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_ARMCL_VERSION)\n    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_ARMCL_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION)\n    #undef JSON_HEDLEY_TI_CL6X_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__TMS320C6X__)\n    #define JSON_HEDLEY_TI_CL6X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL6X_VERSION)\n    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL6X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL6X_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION)\n    #undef JSON_HEDLEY_TI_CL7X_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__C7000__)\n    #define JSON_HEDLEY_TI_CL7X_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CL7X_VERSION)\n    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CL7X_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CL7X_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)\n    #undef JSON_HEDLEY_TI_CLPRU_VERSION\n#endif\n#if defined(__TI_COMPILER_VERSION__) && defined(__PRU__)\n    #define JSON_HEDLEY_TI_CLPRU_VERSION JSON_HEDLEY_VERSION_ENCODE(__TI_COMPILER_VERSION__ / 1000000, (__TI_COMPILER_VERSION__ % 1000000) / 1000, (__TI_COMPILER_VERSION__ % 1000))\n#endif\n\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION_CHECK)\n    #undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TI_CLPRU_VERSION)\n    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TI_CLPRU_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_CRAY_VERSION)\n    #undef JSON_HEDLEY_CRAY_VERSION\n#endif\n#if defined(_CRAYC)\n    #if defined(_RELEASE_PATCHLEVEL)\n        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, _RELEASE_PATCHLEVEL)\n    #else\n        #define JSON_HEDLEY_CRAY_VERSION JSON_HEDLEY_VERSION_ENCODE(_RELEASE_MAJOR, _RELEASE_MINOR, 0)\n    #endif\n#endif\n\n#if defined(JSON_HEDLEY_CRAY_VERSION_CHECK)\n    #undef JSON_HEDLEY_CRAY_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_CRAY_VERSION)\n    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_CRAY_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_CRAY_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_IAR_VERSION)\n    #undef JSON_HEDLEY_IAR_VERSION\n#endif\n#if defined(__IAR_SYSTEMS_ICC__)\n    #if __VER__ > 1000\n        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE((__VER__ / 1000000), ((__VER__ / 1000) % 1000), (__VER__ % 1000))\n    #else\n        #define JSON_HEDLEY_IAR_VERSION JSON_HEDLEY_VERSION_ENCODE(__VER__ / 100, __VER__ % 100, 0)\n    #endif\n#endif\n\n#if defined(JSON_HEDLEY_IAR_VERSION_CHECK)\n    #undef JSON_HEDLEY_IAR_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_IAR_VERSION)\n    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_IAR_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_IAR_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_TINYC_VERSION)\n    #undef JSON_HEDLEY_TINYC_VERSION\n#endif\n#if defined(__TINYC__)\n    #define JSON_HEDLEY_TINYC_VERSION JSON_HEDLEY_VERSION_ENCODE(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)\n#endif\n\n#if defined(JSON_HEDLEY_TINYC_VERSION_CHECK)\n    #undef JSON_HEDLEY_TINYC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_TINYC_VERSION)\n    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_TINYC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_TINYC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_DMC_VERSION)\n    #undef JSON_HEDLEY_DMC_VERSION\n#endif\n#if defined(__DMC__)\n    #define JSON_HEDLEY_DMC_VERSION JSON_HEDLEY_VERSION_ENCODE(__DMC__ >> 8, (__DMC__ >> 4) & 0xf, __DMC__ & 0xf)\n#endif\n\n#if defined(JSON_HEDLEY_DMC_VERSION_CHECK)\n    #undef JSON_HEDLEY_DMC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_DMC_VERSION)\n    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_DMC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_DMC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_COMPCERT_VERSION)\n    #undef JSON_HEDLEY_COMPCERT_VERSION\n#endif\n#if defined(__COMPCERT_VERSION__)\n    #define JSON_HEDLEY_COMPCERT_VERSION JSON_HEDLEY_VERSION_ENCODE(__COMPCERT_VERSION__ / 10000, (__COMPCERT_VERSION__ / 100) % 100, __COMPCERT_VERSION__ % 100)\n#endif\n\n#if defined(JSON_HEDLEY_COMPCERT_VERSION_CHECK)\n    #undef JSON_HEDLEY_COMPCERT_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_COMPCERT_VERSION)\n    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_COMPCERT_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_COMPCERT_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_PELLES_VERSION)\n    #undef JSON_HEDLEY_PELLES_VERSION\n#endif\n#if defined(__POCC__)\n    #define JSON_HEDLEY_PELLES_VERSION JSON_HEDLEY_VERSION_ENCODE(__POCC__ / 100, __POCC__ % 100, 0)\n#endif\n\n#if defined(JSON_HEDLEY_PELLES_VERSION_CHECK)\n    #undef JSON_HEDLEY_PELLES_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_PELLES_VERSION)\n    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_PELLES_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_PELLES_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_MCST_LCC_VERSION)\n    #undef JSON_HEDLEY_MCST_LCC_VERSION\n#endif\n#if defined(__LCC__) && defined(__LCC_MINOR__)\n    #define JSON_HEDLEY_MCST_LCC_VERSION JSON_HEDLEY_VERSION_ENCODE(__LCC__ / 100, __LCC__ % 100, __LCC_MINOR__)\n#endif\n\n#if defined(JSON_HEDLEY_MCST_LCC_VERSION_CHECK)\n    #undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_MCST_LCC_VERSION)\n    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_MCST_LCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_MCST_LCC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_VERSION)\n    #undef JSON_HEDLEY_GCC_VERSION\n#endif\n#if \\\n    defined(JSON_HEDLEY_GNUC_VERSION) && \\\n    !defined(__clang__) && \\\n    !defined(JSON_HEDLEY_INTEL_VERSION) && \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_ARM_VERSION) && \\\n    !defined(JSON_HEDLEY_CRAY_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_ARMCL_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL430_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL2000_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL6X_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CL7X_VERSION) && \\\n    !defined(JSON_HEDLEY_TI_CLPRU_VERSION) && \\\n    !defined(__COMPCERT__) && \\\n    !defined(JSON_HEDLEY_MCST_LCC_VERSION)\n    #define JSON_HEDLEY_GCC_VERSION JSON_HEDLEY_GNUC_VERSION\n#endif\n\n#if defined(JSON_HEDLEY_GCC_VERSION_CHECK)\n    #undef JSON_HEDLEY_GCC_VERSION_CHECK\n#endif\n#if defined(JSON_HEDLEY_GCC_VERSION)\n    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (JSON_HEDLEY_GCC_VERSION >= JSON_HEDLEY_VERSION_ENCODE(major, minor, patch))\n#else\n    #define JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) (0)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_ATTRIBUTE\n#endif\n#if \\\n  defined(__has_attribute) && \\\n  ( \\\n    (!defined(JSON_HEDLEY_IAR_VERSION) || JSON_HEDLEY_IAR_VERSION_CHECK(8,5,9)) \\\n  )\n#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) __has_attribute(attribute)\n#else\n#  define JSON_HEDLEY_HAS_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE\n#endif\n#if defined(__has_attribute)\n    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE\n#endif\n#if \\\n    defined(__has_cpp_attribute) && \\\n    defined(__cplusplus) && \\\n    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0))\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS)\n    #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS\n#endif\n#if !defined(__cplusplus) || !defined(__has_cpp_attribute)\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)\n#elif \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_IAR_VERSION) && \\\n    (!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \\\n    (!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0))\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute)\n#else\n    #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#endif\n#if defined(__has_cpp_attribute) && defined(__cplusplus)\n    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) __has_cpp_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_BUILTIN)\n    #undef JSON_HEDLEY_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_HAS_BUILTIN(builtin) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_HAS_BUILTIN(builtin) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_BUILTIN)\n    #undef JSON_HEDLEY_GNUC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_BUILTIN)\n    #undef JSON_HEDLEY_GCC_HAS_BUILTIN\n#endif\n#if defined(__has_builtin)\n    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) __has_builtin(builtin)\n#else\n    #define JSON_HEDLEY_GCC_HAS_BUILTIN(builtin,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_FEATURE)\n    #undef JSON_HEDLEY_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_HAS_FEATURE(feature) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_HAS_FEATURE(feature) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_FEATURE)\n    #undef JSON_HEDLEY_GNUC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_FEATURE)\n    #undef JSON_HEDLEY_GCC_HAS_FEATURE\n#endif\n#if defined(__has_feature)\n    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) __has_feature(feature)\n#else\n    #define JSON_HEDLEY_GCC_HAS_FEATURE(feature,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_EXTENSION)\n    #undef JSON_HEDLEY_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_HAS_EXTENSION(extension) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_HAS_EXTENSION(extension) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_EXTENSION)\n    #undef JSON_HEDLEY_GNUC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_EXTENSION)\n    #undef JSON_HEDLEY_GCC_HAS_EXTENSION\n#endif\n#if defined(__has_extension)\n    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) __has_extension(extension)\n#else\n    #define JSON_HEDLEY_GCC_HAS_EXTENSION(extension,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#endif\n#if defined(__has_declspec_attribute)\n    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) __has_declspec_attribute(attribute)\n#else\n    #define JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE(attribute,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_HAS_WARNING)\n    #undef JSON_HEDLEY_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_HAS_WARNING(warning) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_HAS_WARNING(warning) (0)\n#endif\n\n#if defined(JSON_HEDLEY_GNUC_HAS_WARNING)\n    #undef JSON_HEDLEY_GNUC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_GNUC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GNUC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_GCC_HAS_WARNING)\n    #undef JSON_HEDLEY_GCC_HAS_WARNING\n#endif\n#if defined(__has_warning)\n    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) __has_warning(warning)\n#else\n    #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if \\\n    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n    defined(__clang__) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0) || \\\n    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,17) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(8,0,0) || \\\n    (JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) && defined(__C99_PRAGMA_OPERATOR))\n    #define JSON_HEDLEY_PRAGMA(value) _Pragma(#value)\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_PRAGMA(value) __pragma(value)\n#else\n    #define JSON_HEDLEY_PRAGMA(value)\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_PUSH)\n    #undef JSON_HEDLEY_DIAGNOSTIC_PUSH\n#endif\n#if defined(JSON_HEDLEY_DIAGNOSTIC_POP)\n    #undef JSON_HEDLEY_DIAGNOSTIC_POP\n#endif\n#if defined(__clang__)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"clang diagnostic push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"clang diagnostic pop\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"GCC diagnostic push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"GCC diagnostic pop\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH __pragma(warning(push))\n    #define JSON_HEDLEY_DIAGNOSTIC_POP __pragma(warning(pop))\n#elif JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"pop\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,4,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"diag_push\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"diag_pop\")\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH _Pragma(\"warning(push)\")\n    #define JSON_HEDLEY_DIAGNOSTIC_POP _Pragma(\"warning(pop)\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_PUSH\n    #define JSON_HEDLEY_DIAGNOSTIC_POP\n#endif\n\n/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for\n   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_\n#endif\n#if defined(__cplusplus)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wc++98-compat\")\n#    if JSON_HEDLEY_HAS_WARNING(\"-Wc++17-extensions\")\n#      if JSON_HEDLEY_HAS_WARNING(\"-Wc++1z-extensions\")\n#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++17-extensions\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++1z-extensions\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#      else\n#        define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++17-extensions\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#      endif\n#    else\n#      define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wc++98-compat\\\"\") \\\n    xpr \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#    endif\n#  endif\n#endif\n#if !defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x\n#endif\n\n#if defined(JSON_HEDLEY_CONST_CAST)\n    #undef JSON_HEDLEY_CONST_CAST\n#endif\n#if defined(__cplusplus)\n#  define JSON_HEDLEY_CONST_CAST(T, expr) (const_cast<T>(expr))\n#elif \\\n  JSON_HEDLEY_HAS_WARNING(\"-Wcast-qual\") || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_CONST_CAST(T, expr) (__extension__ ({ \\\n        JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n        JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL \\\n        ((T) (expr)); \\\n        JSON_HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define JSON_HEDLEY_CONST_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_REINTERPRET_CAST)\n    #undef JSON_HEDLEY_REINTERPRET_CAST\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) (reinterpret_cast<T>(expr))\n#else\n    #define JSON_HEDLEY_REINTERPRET_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_STATIC_CAST)\n    #undef JSON_HEDLEY_STATIC_CAST\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_STATIC_CAST(T, expr) (static_cast<T>(expr))\n#else\n    #define JSON_HEDLEY_STATIC_CAST(T, expr) ((T) (expr))\n#endif\n\n#if defined(JSON_HEDLEY_CPP_CAST)\n    #undef JSON_HEDLEY_CPP_CAST\n#endif\n#if defined(__cplusplus)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wold-style-cast\")\n#    define JSON_HEDLEY_CPP_CAST(T, expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wold-style-cast\\\"\") \\\n    ((T) (expr)) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  elif JSON_HEDLEY_IAR_VERSION_CHECK(8,3,0)\n#    define JSON_HEDLEY_CPP_CAST(T, expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"diag_suppress=Pe137\") \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define JSON_HEDLEY_CPP_CAST(T, expr) ((T) (expr))\n#  endif\n#else\n#  define JSON_HEDLEY_CPP_CAST(T, expr) (expr)\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wdeprecated-declarations\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"clang diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warning(disable:1478 1786)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:1478 1786))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1216,1444,1445\")\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1444\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED __pragma(warning(disable:4996))\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1215,1444\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress 1291,1718\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && !defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,E_DEPRECATED_ATT,E_DEPRECATED_ATT_MESS)\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"error_messages(off,symdeprecated,symdeprecated2)\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"diag_suppress=Pe1444,Pe1215\")\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,90,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED _Pragma(\"warn(disable:2241)\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"clang diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"warning(disable:161)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:161))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 1675\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"GCC diagnostic ignored \\\"-Wunknown-pragmas\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS __pragma(warning(disable:4068))\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(16,9,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 163\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress=Pe161\")\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS _Pragma(\"diag_suppress 161\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-attributes\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"clang diagnostic ignored \\\"-Wunknown-attributes\\\"\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"GCC diagnostic ignored \\\"-Wdeprecated-declarations\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"warning(disable:1292)\")\n#elif JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:1292))\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030))\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(20,7,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097,1098\")\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097\")\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"error_messages(off,attrskipunsup)\")\n#elif \\\n    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1173\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress=Pe1097\")\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma(\"diag_suppress 1097\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wcast-qual\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"clang diagnostic ignored \\\"-Wcast-qual\\\"\")\n#elif JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"warning(disable:2203 2331)\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL _Pragma(\"GCC diagnostic ignored \\\"-Wcast-qual\\\"\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#endif\n\n#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION)\n    #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunused-function\")\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma(\"clang diagnostic ignored \\\"-Wunused-function\\\"\")\n#elif JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma(\"GCC diagnostic ignored \\\"-Wunused-function\\\"\")\n#elif JSON_HEDLEY_MSVC_VERSION_CHECK(1,0,0)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION __pragma(warning(disable:4505))\n#elif JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION _Pragma(\"diag_suppress 3142\")\n#else\n    #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION\n#endif\n\n#if defined(JSON_HEDLEY_DEPRECATED)\n    #undef JSON_HEDLEY_DEPRECATED\n#endif\n#if defined(JSON_HEDLEY_DEPRECATED_FOR)\n    #undef JSON_HEDLEY_DEPRECATED_FOR\n#endif\n#if \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated(\"Since \" # since))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated(\"Since \" #since \"; use \" #replacement))\n#elif \\\n    (JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) && !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,13,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(18,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,3,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,3,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__(\"Since \" #since)))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__(\"Since \" #since \"; use \" #replacement)))\n#elif defined(__cplusplus) && (__cplusplus >= 201402L)\n    #define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated(\"Since \" #since)]])\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated(\"Since \" #since \"; use \" #replacement)]])\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(deprecated) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __attribute__((__deprecated__))\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __attribute__((__deprecated__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated)\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated)\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_DEPRECATED(since) _Pragma(\"deprecated\")\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) _Pragma(\"deprecated\")\n#else\n    #define JSON_HEDLEY_DEPRECATED(since)\n    #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement)\n#endif\n\n#if defined(JSON_HEDLEY_UNAVAILABLE)\n    #undef JSON_HEDLEY_UNAVAILABLE\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(warning) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_UNAVAILABLE(available_since) __attribute__((__warning__(\"Not available until \" #available_since)))\n#else\n    #define JSON_HEDLEY_UNAVAILABLE(available_since)\n#endif\n\n#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT)\n    #undef JSON_HEDLEY_WARN_UNUSED_RESULT\n#endif\n#if defined(JSON_HEDLEY_WARN_UNUSED_RESULT_MSG)\n    #undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) __attribute__((__warn_unused_result__))\n#elif (JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard) >= 201907L)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard(msg)]])\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(nodiscard)\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]])\n#elif defined(_Check_return_) /* SAL */\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT _Check_return_\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg) _Check_return_\n#else\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT\n    #define JSON_HEDLEY_WARN_UNUSED_RESULT_MSG(msg)\n#endif\n\n#if defined(JSON_HEDLEY_SENTINEL)\n    #undef JSON_HEDLEY_SENTINEL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(sentinel) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_SENTINEL(position) __attribute__((__sentinel__(position)))\n#else\n    #define JSON_HEDLEY_SENTINEL(position)\n#endif\n\n#if defined(JSON_HEDLEY_NO_RETURN)\n    #undef JSON_HEDLEY_NO_RETURN\n#endif\n#if JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_NO_RETURN __noreturn\n#elif \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L\n    #define JSON_HEDLEY_NO_RETURN _Noreturn\n#elif defined(__cplusplus) && (__cplusplus >= 201103L)\n    #define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]])\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_NO_RETURN _Pragma(\"does_not_return\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_NO_RETURN _Pragma(\"FUNC_NEVER_RETURNS;\")\n#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n    #define JSON_HEDLEY_NO_RETURN __attribute((noreturn))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n    #define JSON_HEDLEY_NO_RETURN __declspec(noreturn)\n#else\n    #define JSON_HEDLEY_NO_RETURN\n#endif\n\n#if defined(JSON_HEDLEY_NO_ESCAPE)\n    #undef JSON_HEDLEY_NO_ESCAPE\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape)\n    #define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__))\n#else\n    #define JSON_HEDLEY_NO_ESCAPE\n#endif\n\n#if defined(JSON_HEDLEY_UNREACHABLE)\n    #undef JSON_HEDLEY_UNREACHABLE\n#endif\n#if defined(JSON_HEDLEY_UNREACHABLE_RETURN)\n    #undef JSON_HEDLEY_UNREACHABLE_RETURN\n#endif\n#if defined(JSON_HEDLEY_ASSUME)\n    #undef JSON_HEDLEY_ASSUME\n#endif\n#if \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_ASSUME(expr) __assume(expr)\n#elif JSON_HEDLEY_HAS_BUILTIN(__builtin_assume)\n    #define JSON_HEDLEY_ASSUME(expr) __builtin_assume(expr)\n#elif \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)\n    #if defined(__cplusplus)\n        #define JSON_HEDLEY_ASSUME(expr) std::_nassert(expr)\n    #else\n        #define JSON_HEDLEY_ASSUME(expr) _nassert(expr)\n    #endif\n#endif\n#if \\\n    (JSON_HEDLEY_HAS_BUILTIN(__builtin_unreachable) && (!defined(JSON_HEDLEY_ARM_VERSION))) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(18,10,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,5) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(10,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_UNREACHABLE() __builtin_unreachable()\n#elif defined(JSON_HEDLEY_ASSUME)\n    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)\n#endif\n#if !defined(JSON_HEDLEY_ASSUME)\n    #if defined(JSON_HEDLEY_UNREACHABLE)\n        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, ((expr) ? 1 : (JSON_HEDLEY_UNREACHABLE(), 1)))\n    #else\n        #define JSON_HEDLEY_ASSUME(expr) JSON_HEDLEY_STATIC_CAST(void, expr)\n    #endif\n#endif\n#if defined(JSON_HEDLEY_UNREACHABLE)\n    #if  \\\n        JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0)\n        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (JSON_HEDLEY_STATIC_CAST(void, JSON_HEDLEY_ASSUME(0)), (value))\n    #else\n        #define JSON_HEDLEY_UNREACHABLE_RETURN(value) JSON_HEDLEY_UNREACHABLE()\n    #endif\n#else\n    #define JSON_HEDLEY_UNREACHABLE_RETURN(value) return (value)\n#endif\n#if !defined(JSON_HEDLEY_UNREACHABLE)\n    #define JSON_HEDLEY_UNREACHABLE() JSON_HEDLEY_ASSUME(0)\n#endif\n\nJSON_HEDLEY_DIAGNOSTIC_PUSH\n#if JSON_HEDLEY_HAS_WARNING(\"-Wpedantic\")\n    #pragma clang diagnostic ignored \"-Wpedantic\"\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wc++98-compat-pedantic\") && defined(__cplusplus)\n    #pragma clang diagnostic ignored \"-Wc++98-compat-pedantic\"\n#endif\n#if JSON_HEDLEY_GCC_HAS_WARNING(\"-Wvariadic-macros\",4,0,0)\n    #if defined(__clang__)\n        #pragma clang diagnostic ignored \"-Wvariadic-macros\"\n    #elif defined(JSON_HEDLEY_GCC_VERSION)\n        #pragma GCC diagnostic ignored \"-Wvariadic-macros\"\n    #endif\n#endif\n#if defined(JSON_HEDLEY_NON_NULL)\n    #undef JSON_HEDLEY_NON_NULL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(nonnull) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)\n    #define JSON_HEDLEY_NON_NULL(...) __attribute__((__nonnull__(__VA_ARGS__)))\n#else\n    #define JSON_HEDLEY_NON_NULL(...)\n#endif\nJSON_HEDLEY_DIAGNOSTIC_POP\n\n#if defined(JSON_HEDLEY_PRINTF_FORMAT)\n    #undef JSON_HEDLEY_PRINTF_FORMAT\n#endif\n#if defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && !defined(__USE_MINGW_ANSI_STDIO)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(ms_printf, string_idx, first_to_check)))\n#elif defined(__MINGW32__) && JSON_HEDLEY_GCC_HAS_ATTRIBUTE(format,4,4,0) && defined(__USE_MINGW_ANSI_STDIO)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(gnu_printf, string_idx, first_to_check)))\n#elif \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(format) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(5,6,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __attribute__((__format__(__printf__, string_idx, first_to_check)))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(6,0,0)\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check) __declspec(vaformat(printf,string_idx,first_to_check))\n#else\n    #define JSON_HEDLEY_PRINTF_FORMAT(string_idx,first_to_check)\n#endif\n\n#if defined(JSON_HEDLEY_CONSTEXPR)\n    #undef JSON_HEDLEY_CONSTEXPR\n#endif\n#if defined(__cplusplus)\n    #if __cplusplus >= 201103L\n        #define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr)\n    #endif\n#endif\n#if !defined(JSON_HEDLEY_CONSTEXPR)\n    #define JSON_HEDLEY_CONSTEXPR\n#endif\n\n#if defined(JSON_HEDLEY_PREDICT)\n    #undef JSON_HEDLEY_PREDICT\n#endif\n#if defined(JSON_HEDLEY_LIKELY)\n    #undef JSON_HEDLEY_LIKELY\n#endif\n#if defined(JSON_HEDLEY_UNLIKELY)\n    #undef JSON_HEDLEY_UNLIKELY\n#endif\n#if defined(JSON_HEDLEY_UNPREDICTABLE)\n    #undef JSON_HEDLEY_UNPREDICTABLE\n#endif\n#if JSON_HEDLEY_HAS_BUILTIN(__builtin_unpredictable)\n    #define JSON_HEDLEY_UNPREDICTABLE(expr) __builtin_unpredictable((expr))\n#endif\n#if \\\n  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect_with_probability) && !defined(JSON_HEDLEY_PGI_VERSION)) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(9,0,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#  define JSON_HEDLEY_PREDICT(expr, value, probability) __builtin_expect_with_probability(  (expr), (value), (probability))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability)   __builtin_expect_with_probability(!!(expr),    1   , (probability))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability)  __builtin_expect_with_probability(!!(expr),    0   , (probability))\n#  define JSON_HEDLEY_LIKELY(expr)                      __builtin_expect                 (!!(expr),    1                  )\n#  define JSON_HEDLEY_UNLIKELY(expr)                    __builtin_expect                 (!!(expr),    0                  )\n#elif \\\n  (JSON_HEDLEY_HAS_BUILTIN(__builtin_expect) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(3,0,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0) && defined(__cplusplus)) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,7,0) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,1,0) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,27) || \\\n  JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#  define JSON_HEDLEY_PREDICT(expr, expected, probability) \\\n    (((probability) >= 0.9) ? __builtin_expect((expr), (expected)) : (JSON_HEDLEY_STATIC_CAST(void, expected), (expr)))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) \\\n    (__extension__ ({ \\\n        double hedley_probability_ = (probability); \\\n        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 1) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 0) : !!(expr))); \\\n    }))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) \\\n    (__extension__ ({ \\\n        double hedley_probability_ = (probability); \\\n        ((hedley_probability_ >= 0.9) ? __builtin_expect(!!(expr), 0) : ((hedley_probability_ <= 0.1) ? __builtin_expect(!!(expr), 1) : !!(expr))); \\\n    }))\n#  define JSON_HEDLEY_LIKELY(expr)   __builtin_expect(!!(expr), 1)\n#  define JSON_HEDLEY_UNLIKELY(expr) __builtin_expect(!!(expr), 0)\n#else\n#  define JSON_HEDLEY_PREDICT(expr, expected, probability) (JSON_HEDLEY_STATIC_CAST(void, expected), (expr))\n#  define JSON_HEDLEY_PREDICT_TRUE(expr, probability) (!!(expr))\n#  define JSON_HEDLEY_PREDICT_FALSE(expr, probability) (!!(expr))\n#  define JSON_HEDLEY_LIKELY(expr) (!!(expr))\n#  define JSON_HEDLEY_UNLIKELY(expr) (!!(expr))\n#endif\n#if !defined(JSON_HEDLEY_UNPREDICTABLE)\n    #define JSON_HEDLEY_UNPREDICTABLE(expr) JSON_HEDLEY_PREDICT(expr, 1, 0.5)\n#endif\n\n#if defined(JSON_HEDLEY_MALLOC)\n    #undef JSON_HEDLEY_MALLOC\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(malloc) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_MALLOC __attribute__((__malloc__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_MALLOC _Pragma(\"returns_new_memory\")\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_MALLOC __declspec(restrict)\n#else\n    #define JSON_HEDLEY_MALLOC\n#endif\n\n#if defined(JSON_HEDLEY_PURE)\n    #undef JSON_HEDLEY_PURE\n#endif\n#if \\\n  JSON_HEDLEY_HAS_ATTRIBUTE(pure) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(2,96,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#  define JSON_HEDLEY_PURE __attribute__((__pure__))\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n#  define JSON_HEDLEY_PURE _Pragma(\"does_not_write_global_data\")\n#elif defined(__cplusplus) && \\\n    ( \\\n      JSON_HEDLEY_TI_CL430_VERSION_CHECK(2,0,1) || \\\n      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(4,0,0) || \\\n      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) \\\n    )\n#  define JSON_HEDLEY_PURE _Pragma(\"FUNC_IS_PURE;\")\n#else\n#  define JSON_HEDLEY_PURE\n#endif\n\n#if defined(JSON_HEDLEY_CONST)\n    #undef JSON_HEDLEY_CONST\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(const) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(2,5,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_CONST __attribute__((__const__))\n#elif \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0)\n    #define JSON_HEDLEY_CONST _Pragma(\"no_side_effect\")\n#else\n    #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE\n#endif\n\n#if defined(JSON_HEDLEY_RESTRICT)\n    #undef JSON_HEDLEY_RESTRICT\n#endif\n#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)\n    #define JSON_HEDLEY_RESTRICT restrict\n#elif \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(14,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,4) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus)) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) || \\\n    defined(__clang__) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_RESTRICT __restrict\n#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,3,0) && !defined(__cplusplus)\n    #define JSON_HEDLEY_RESTRICT _Restrict\n#else\n    #define JSON_HEDLEY_RESTRICT\n#endif\n\n#if defined(JSON_HEDLEY_INLINE)\n    #undef JSON_HEDLEY_INLINE\n#endif\n#if \\\n    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \\\n    (defined(__cplusplus) && (__cplusplus >= 199711L))\n    #define JSON_HEDLEY_INLINE inline\n#elif \\\n    defined(JSON_HEDLEY_GCC_VERSION) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(6,2,0)\n    #define JSON_HEDLEY_INLINE __inline__\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,1,0) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(3,1,0) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,2,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(8,0,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_INLINE __inline\n#else\n    #define JSON_HEDLEY_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_ALWAYS_INLINE)\n    #undef JSON_HEDLEY_ALWAYS_INLINE\n#endif\n#if \\\n  JSON_HEDLEY_HAS_ATTRIBUTE(always_inline) || \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n  JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n  JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n  JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n  JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n  (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n  (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n  (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n  (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n  JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n  JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n  JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n  JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \\\n  JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE __attribute__((__always_inline__)) JSON_HEDLEY_INLINE\n#elif \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(12,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE __forceinline\n#elif defined(__cplusplus) && \\\n    ( \\\n      JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n      JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n      JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n      JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n      JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n      JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) \\\n    )\n#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma(\"FUNC_ALWAYS_INLINE;\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define JSON_HEDLEY_ALWAYS_INLINE _Pragma(\"inline=forced\")\n#else\n#  define JSON_HEDLEY_ALWAYS_INLINE JSON_HEDLEY_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_NEVER_INLINE)\n    #undef JSON_HEDLEY_NEVER_INLINE\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(noinline) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(10,1,0) || \\\n    JSON_HEDLEY_TI_VERSION_CHECK(15,12,0) || \\\n    (JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(4,8,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_ARMCL_VERSION_CHECK(5,2,0) || \\\n    (JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL2000_VERSION_CHECK(6,4,0) || \\\n    (JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,0,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL430_VERSION_CHECK(4,3,0) || \\\n    (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) || \\\n    JSON_HEDLEY_TI_CL7X_VERSION_CHECK(1,2,0) || \\\n    JSON_HEDLEY_TI_CLPRU_VERSION_CHECK(2,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10) || \\\n    JSON_HEDLEY_IAR_VERSION_CHECK(8,10,0)\n    #define JSON_HEDLEY_NEVER_INLINE __attribute__((__noinline__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)\n#elif JSON_HEDLEY_PGI_VERSION_CHECK(10,2,0)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"noinline\")\n#elif JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,0,0) && defined(__cplusplus)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"FUNC_CANNOT_INLINE;\")\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n    #define JSON_HEDLEY_NEVER_INLINE _Pragma(\"inline=never\")\n#elif JSON_HEDLEY_COMPCERT_VERSION_CHECK(3,2,0)\n    #define JSON_HEDLEY_NEVER_INLINE __attribute((noinline))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(9,0,0)\n    #define JSON_HEDLEY_NEVER_INLINE __declspec(noinline)\n#else\n    #define JSON_HEDLEY_NEVER_INLINE\n#endif\n\n#if defined(JSON_HEDLEY_PRIVATE)\n    #undef JSON_HEDLEY_PRIVATE\n#endif\n#if defined(JSON_HEDLEY_PUBLIC)\n    #undef JSON_HEDLEY_PUBLIC\n#endif\n#if defined(JSON_HEDLEY_IMPORT)\n    #undef JSON_HEDLEY_IMPORT\n#endif\n#if defined(_WIN32) || defined(__CYGWIN__)\n#  define JSON_HEDLEY_PRIVATE\n#  define JSON_HEDLEY_PUBLIC   __declspec(dllexport)\n#  define JSON_HEDLEY_IMPORT   __declspec(dllimport)\n#else\n#  if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(visibility) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,11,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    ( \\\n      defined(__TI_EABI__) && \\\n      ( \\\n        (JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,2,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \\\n        JSON_HEDLEY_TI_CL6X_VERSION_CHECK(7,5,0) \\\n      ) \\\n    ) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n#    define JSON_HEDLEY_PRIVATE __attribute__((__visibility__(\"hidden\")))\n#    define JSON_HEDLEY_PUBLIC  __attribute__((__visibility__(\"default\")))\n#  else\n#    define JSON_HEDLEY_PRIVATE\n#    define JSON_HEDLEY_PUBLIC\n#  endif\n#  define JSON_HEDLEY_IMPORT    extern\n#endif\n\n#if defined(JSON_HEDLEY_NO_THROW)\n    #undef JSON_HEDLEY_NO_THROW\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(nothrow) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,3,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_NO_THROW __attribute__((__nothrow__))\n#elif \\\n    JSON_HEDLEY_MSVC_VERSION_CHECK(13,1,0) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0)\n    #define JSON_HEDLEY_NO_THROW __declspec(nothrow)\n#else\n    #define JSON_HEDLEY_NO_THROW\n#endif\n\n#if defined(JSON_HEDLEY_FALL_THROUGH)\n    #undef JSON_HEDLEY_FALL_THROUGH\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(fallthrough) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__))\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough)\n    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]])\n#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)\n    #define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]])\n#elif defined(__fallthrough) /* SAL */\n    #define JSON_HEDLEY_FALL_THROUGH __fallthrough\n#else\n    #define JSON_HEDLEY_FALL_THROUGH\n#endif\n\n#if defined(JSON_HEDLEY_RETURNS_NON_NULL)\n    #undef JSON_HEDLEY_RETURNS_NON_NULL\n#endif\n#if \\\n    JSON_HEDLEY_HAS_ATTRIBUTE(returns_nonnull) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_RETURNS_NON_NULL __attribute__((__returns_nonnull__))\n#elif defined(_Ret_notnull_) /* SAL */\n    #define JSON_HEDLEY_RETURNS_NON_NULL _Ret_notnull_\n#else\n    #define JSON_HEDLEY_RETURNS_NON_NULL\n#endif\n\n#if defined(JSON_HEDLEY_ARRAY_PARAM)\n    #undef JSON_HEDLEY_ARRAY_PARAM\n#endif\n#if \\\n    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \\\n    !defined(__STDC_NO_VLA__) && \\\n    !defined(__cplusplus) && \\\n    !defined(JSON_HEDLEY_PGI_VERSION) && \\\n    !defined(JSON_HEDLEY_TINYC_VERSION)\n    #define JSON_HEDLEY_ARRAY_PARAM(name) (name)\n#else\n    #define JSON_HEDLEY_ARRAY_PARAM(name)\n#endif\n\n#if defined(JSON_HEDLEY_IS_CONSTANT)\n    #undef JSON_HEDLEY_IS_CONSTANT\n#endif\n#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR)\n    #undef JSON_HEDLEY_REQUIRE_CONSTEXPR\n#endif\n/* JSON_HEDLEY_IS_CONSTEXPR_ is for\n   HEDLEY INTERNAL USE ONLY.  API subject to change without notice. */\n#if defined(JSON_HEDLEY_IS_CONSTEXPR_)\n    #undef JSON_HEDLEY_IS_CONSTEXPR_\n#endif\n#if \\\n    JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \\\n    JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n    JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n    JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,19) || \\\n    JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \\\n    JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n    JSON_HEDLEY_TI_CL6X_VERSION_CHECK(6,1,0) || \\\n    (JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \\\n    JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n    JSON_HEDLEY_MCST_LCC_VERSION_CHECK(1,25,10)\n    #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr)\n#endif\n#if !defined(__cplusplus)\n#  if \\\n       JSON_HEDLEY_HAS_BUILTIN(__builtin_types_compatible_p) || \\\n       JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \\\n       JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n       JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \\\n       JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) || \\\n       JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \\\n       JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24)\n#if defined(__INTPTR_TYPE__)\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*)\n#else\n    #include <stdint.h>\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*)\n#endif\n#  elif \\\n       ( \\\n          defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \\\n          !defined(JSON_HEDLEY_SUNPRO_VERSION) && \\\n          !defined(JSON_HEDLEY_PGI_VERSION) && \\\n          !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n       (JSON_HEDLEY_HAS_EXTENSION(c_generic_selections) && !defined(JSON_HEDLEY_IAR_VERSION)) || \\\n       JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0) || \\\n       JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) || \\\n       JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \\\n       JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0)\n#if defined(__INTPTR_TYPE__)\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0)\n#else\n    #include <stdint.h>\n    #define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0)\n#endif\n#  elif \\\n       defined(JSON_HEDLEY_GCC_VERSION) || \\\n       defined(JSON_HEDLEY_INTEL_VERSION) || \\\n       defined(JSON_HEDLEY_TINYC_VERSION) || \\\n       defined(JSON_HEDLEY_TI_ARMCL_VERSION) || \\\n       JSON_HEDLEY_TI_CL430_VERSION_CHECK(18,12,0) || \\\n       defined(JSON_HEDLEY_TI_CL2000_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CL6X_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CL7X_VERSION) || \\\n       defined(JSON_HEDLEY_TI_CLPRU_VERSION) || \\\n       defined(__clang__)\n#    define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \\\n        sizeof(void) != \\\n        sizeof(*( \\\n                  1 ? \\\n                  ((void*) ((expr) * 0L) ) : \\\n((struct { char v[sizeof(void) * 2]; } *) 1) \\\n                ) \\\n              ) \\\n                                            )\n#  endif\n#endif\n#if defined(JSON_HEDLEY_IS_CONSTEXPR_)\n    #if !defined(JSON_HEDLEY_IS_CONSTANT)\n        #define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr)\n    #endif\n    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1))\n#else\n    #if !defined(JSON_HEDLEY_IS_CONSTANT)\n        #define JSON_HEDLEY_IS_CONSTANT(expr) (0)\n    #endif\n    #define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (expr)\n#endif\n\n#if defined(JSON_HEDLEY_BEGIN_C_DECLS)\n    #undef JSON_HEDLEY_BEGIN_C_DECLS\n#endif\n#if defined(JSON_HEDLEY_END_C_DECLS)\n    #undef JSON_HEDLEY_END_C_DECLS\n#endif\n#if defined(JSON_HEDLEY_C_DECL)\n    #undef JSON_HEDLEY_C_DECL\n#endif\n#if defined(__cplusplus)\n    #define JSON_HEDLEY_BEGIN_C_DECLS extern \"C\" {\n    #define JSON_HEDLEY_END_C_DECLS }\n    #define JSON_HEDLEY_C_DECL extern \"C\"\n#else\n    #define JSON_HEDLEY_BEGIN_C_DECLS\n    #define JSON_HEDLEY_END_C_DECLS\n    #define JSON_HEDLEY_C_DECL\n#endif\n\n#if defined(JSON_HEDLEY_STATIC_ASSERT)\n    #undef JSON_HEDLEY_STATIC_ASSERT\n#endif\n#if \\\n  !defined(__cplusplus) && ( \\\n      (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) || \\\n      (JSON_HEDLEY_HAS_FEATURE(c_static_assert) && !defined(JSON_HEDLEY_INTEL_CL_VERSION)) || \\\n      JSON_HEDLEY_GCC_VERSION_CHECK(6,0,0) || \\\n      JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0) || \\\n      defined(_Static_assert) \\\n    )\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message)\n#elif \\\n  (defined(__cplusplus) && (__cplusplus >= 201103L)) || \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message))\n#else\n#  define JSON_HEDLEY_STATIC_ASSERT(expr, message)\n#endif\n\n#if defined(JSON_HEDLEY_NULL)\n    #undef JSON_HEDLEY_NULL\n#endif\n#if defined(__cplusplus)\n    #if __cplusplus >= 201103L\n        #define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr)\n    #elif defined(NULL)\n        #define JSON_HEDLEY_NULL NULL\n    #else\n        #define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0)\n    #endif\n#elif defined(NULL)\n    #define JSON_HEDLEY_NULL NULL\n#else\n    #define JSON_HEDLEY_NULL ((void*) 0)\n#endif\n\n#if defined(JSON_HEDLEY_MESSAGE)\n    #undef JSON_HEDLEY_MESSAGE\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define JSON_HEDLEY_MESSAGE(msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n    JSON_HEDLEY_PRAGMA(message msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,4,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message msg)\n#elif JSON_HEDLEY_CRAY_VERSION_CHECK(5,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(_CRI message msg)\n#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#elif JSON_HEDLEY_PELLES_VERSION_CHECK(2,0,0)\n#  define JSON_HEDLEY_MESSAGE(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#else\n#  define JSON_HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(JSON_HEDLEY_WARNING)\n    #undef JSON_HEDLEY_WARNING\n#endif\n#if JSON_HEDLEY_HAS_WARNING(\"-Wunknown-pragmas\")\n#  define JSON_HEDLEY_WARNING(msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS \\\n    JSON_HEDLEY_PRAGMA(clang warning msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#elif \\\n  JSON_HEDLEY_GCC_VERSION_CHECK(4,8,0) || \\\n  JSON_HEDLEY_PGI_VERSION_CHECK(18,4,0) || \\\n  JSON_HEDLEY_INTEL_VERSION_CHECK(13,0,0)\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(GCC warning msg)\n#elif \\\n  JSON_HEDLEY_MSVC_VERSION_CHECK(15,0,0) || \\\n  JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_PRAGMA(message(msg))\n#else\n#  define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg)\n#endif\n\n#if defined(JSON_HEDLEY_REQUIRE)\n    #undef JSON_HEDLEY_REQUIRE\n#endif\n#if defined(JSON_HEDLEY_REQUIRE_MSG)\n    #undef JSON_HEDLEY_REQUIRE_MSG\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if)\n#  if JSON_HEDLEY_HAS_WARNING(\"-Wgcc-compat\")\n#    define JSON_HEDLEY_REQUIRE(expr) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n    __attribute__((diagnose_if(!(expr), #expr, \"error\"))) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \\\n    JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n    _Pragma(\"clang diagnostic ignored \\\"-Wgcc-compat\\\"\") \\\n    __attribute__((diagnose_if(!(expr), msg, \"error\"))) \\\n    JSON_HEDLEY_DIAGNOSTIC_POP\n#  else\n#    define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, \"error\")))\n#    define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, \"error\")))\n#  endif\n#else\n#  define JSON_HEDLEY_REQUIRE(expr)\n#  define JSON_HEDLEY_REQUIRE_MSG(expr,msg)\n#endif\n\n#if defined(JSON_HEDLEY_FLAGS)\n    #undef JSON_HEDLEY_FLAGS\n#endif\n#if JSON_HEDLEY_HAS_ATTRIBUTE(flag_enum) && (!defined(__cplusplus) || JSON_HEDLEY_HAS_WARNING(\"-Wbitfield-enum-conversion\"))\n    #define JSON_HEDLEY_FLAGS __attribute__((__flag_enum__))\n#else\n    #define JSON_HEDLEY_FLAGS\n#endif\n\n#if defined(JSON_HEDLEY_FLAGS_CAST)\n    #undef JSON_HEDLEY_FLAGS_CAST\n#endif\n#if JSON_HEDLEY_INTEL_VERSION_CHECK(19,0,0)\n#  define JSON_HEDLEY_FLAGS_CAST(T, expr) (__extension__ ({ \\\n        JSON_HEDLEY_DIAGNOSTIC_PUSH \\\n        _Pragma(\"warning(disable:188)\") \\\n        ((T) (expr)); \\\n        JSON_HEDLEY_DIAGNOSTIC_POP \\\n    }))\n#else\n#  define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr)\n#endif\n\n#if defined(JSON_HEDLEY_EMPTY_BASES)\n    #undef JSON_HEDLEY_EMPTY_BASES\n#endif\n#if \\\n    (JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0)) || \\\n    JSON_HEDLEY_INTEL_CL_VERSION_CHECK(2021,1,0)\n    #define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases)\n#else\n    #define JSON_HEDLEY_EMPTY_BASES\n#endif\n\n/* Remaining macros are deprecated. */\n\n#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK)\n    #undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#endif\n#if defined(__clang__)\n    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) (0)\n#else\n    #define JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK(major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch)\n#endif\n\n#if defined(JSON_HEDLEY_CLANG_HAS_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_BUILTIN)\n    #undef JSON_HEDLEY_CLANG_HAS_BUILTIN\n#endif\n#define JSON_HEDLEY_CLANG_HAS_BUILTIN(builtin) JSON_HEDLEY_HAS_BUILTIN(builtin)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_FEATURE)\n    #undef JSON_HEDLEY_CLANG_HAS_FEATURE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_FEATURE(feature) JSON_HEDLEY_HAS_FEATURE(feature)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_EXTENSION)\n    #undef JSON_HEDLEY_CLANG_HAS_EXTENSION\n#endif\n#define JSON_HEDLEY_CLANG_HAS_EXTENSION(extension) JSON_HEDLEY_HAS_EXTENSION(extension)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE)\n    #undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#endif\n#define JSON_HEDLEY_CLANG_HAS_DECLSPEC_ATTRIBUTE(attribute) JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE(attribute)\n\n#if defined(JSON_HEDLEY_CLANG_HAS_WARNING)\n    #undef JSON_HEDLEY_CLANG_HAS_WARNING\n#endif\n#define JSON_HEDLEY_CLANG_HAS_WARNING(warning) JSON_HEDLEY_HAS_WARNING(warning)\n\n#endif /* !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < X) */\n\n\n// This file contains all internal macro definitions (except those affecting ABI)\n// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\n// exclude unsupported compilers\n#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)\n    #if defined(__clang__)\n        #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400\n            #error \"unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))\n        #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800\n            #error \"unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers\"\n        #endif\n    #endif\n#endif\n\n// C++ language standard detection\n// if the user manually specified the used c++ version this is skipped\n#if !defined(JSON_HAS_CPP_23) && !defined(JSON_HAS_CPP_20) && !defined(JSON_HAS_CPP_17) && !defined(JSON_HAS_CPP_14) && !defined(JSON_HAS_CPP_11)\n    #if (defined(__cplusplus) && __cplusplus > 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG > 202002L)\n        #define JSON_HAS_CPP_23\n        #define JSON_HAS_CPP_20\n        #define JSON_HAS_CPP_17\n        #define JSON_HAS_CPP_14\n    #elif (defined(__cplusplus) && __cplusplus > 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L)\n        #define JSON_HAS_CPP_20\n        #define JSON_HAS_CPP_17\n        #define JSON_HAS_CPP_14\n    #elif (defined(__cplusplus) && __cplusplus > 201402L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464\n        #define JSON_HAS_CPP_17\n        #define JSON_HAS_CPP_14\n    #elif (defined(__cplusplus) && __cplusplus > 201103L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)\n        #define JSON_HAS_CPP_14\n    #endif\n    // the cpp 11 flag is always specified because it is the minimal required version\n    #define JSON_HAS_CPP_11\n#endif\n\n#ifdef __has_include\n    #if __has_include(<version>)\n        #include <version>\n    #endif\n#endif\n\n#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)\n    #ifdef JSON_HAS_CPP_17\n        #if defined(__cpp_lib_filesystem)\n            #define JSON_HAS_FILESYSTEM 1\n        #elif defined(__cpp_lib_experimental_filesystem)\n            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1\n        #elif !defined(__has_include)\n            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1\n        #elif __has_include(<filesystem>)\n            #define JSON_HAS_FILESYSTEM 1\n        #elif __has_include(<experimental/filesystem>)\n            #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 1\n        #endif\n\n        // std::filesystem does not work on MinGW GCC 8: https://sourceforge.net/p/mingw-w64/bugs/737/\n        #if defined(__MINGW32__) && defined(__GNUC__) && __GNUC__ == 8\n            #undef JSON_HAS_FILESYSTEM\n            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n        #endif\n\n        // no filesystem support before GCC 8: https://en.cppreference.com/w/cpp/compiler_support\n        #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 8\n            #undef JSON_HAS_FILESYSTEM\n            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n        #endif\n\n        // no filesystem support before Clang 7: https://en.cppreference.com/w/cpp/compiler_support\n        #if defined(__clang_major__) && __clang_major__ < 7\n            #undef JSON_HAS_FILESYSTEM\n            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n        #endif\n\n        // no filesystem support before MSVC 19.14: https://en.cppreference.com/w/cpp/compiler_support\n        #if defined(_MSC_VER) && _MSC_VER < 1914\n            #undef JSON_HAS_FILESYSTEM\n            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n        #endif\n\n        // no filesystem support before iOS 13\n        #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 130000\n            #undef JSON_HAS_FILESYSTEM\n            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n        #endif\n\n        // no filesystem support before macOS Catalina\n        #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101500\n            #undef JSON_HAS_FILESYSTEM\n            #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n        #endif\n    #endif\n#endif\n\n#ifndef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n    #define JSON_HAS_EXPERIMENTAL_FILESYSTEM 0\n#endif\n\n#ifndef JSON_HAS_FILESYSTEM\n    #define JSON_HAS_FILESYSTEM 0\n#endif\n\n#ifndef JSON_HAS_THREE_WAY_COMPARISON\n    #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \\\n        && defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L\n        #define JSON_HAS_THREE_WAY_COMPARISON 1\n    #else\n        #define JSON_HAS_THREE_WAY_COMPARISON 0\n    #endif\n#endif\n\n#ifndef JSON_HAS_RANGES\n    // ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error\n    #if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427\n        #define JSON_HAS_RANGES 0\n    #elif defined(__cpp_lib_ranges)\n        #define JSON_HAS_RANGES 1\n    #else\n        #define JSON_HAS_RANGES 0\n    #endif\n#endif\n\n#ifndef JSON_HAS_STATIC_RTTI\n    #if !defined(_HAS_STATIC_RTTI) || _HAS_STATIC_RTTI != 0\n        #define JSON_HAS_STATIC_RTTI 1\n    #else\n        #define JSON_HAS_STATIC_RTTI 0\n    #endif\n#endif\n\n#ifdef JSON_HAS_CPP_17\n    #define JSON_INLINE_VARIABLE inline\n#else\n    #define JSON_INLINE_VARIABLE\n#endif\n\n#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)\n    #define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]\n#else\n    #define JSON_NO_UNIQUE_ADDRESS\n#endif\n\n// disable documentation warnings on clang\n#if defined(__clang__)\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wdocumentation\"\n    #pragma clang diagnostic ignored \"-Wdocumentation-unknown-command\"\n#endif\n\n// allow disabling exceptions\n#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)\n    #define JSON_THROW(exception) throw exception\n    #define JSON_TRY try\n    #define JSON_CATCH(exception) catch(exception)\n    #define JSON_INTERNAL_CATCH(exception) catch(exception)\n#else\n    #include <cstdlib>\n    #define JSON_THROW(exception) std::abort()\n    #define JSON_TRY if(true)\n    #define JSON_CATCH(exception) if(false)\n    #define JSON_INTERNAL_CATCH(exception) if(false)\n#endif\n\n// override exception macros\n#if defined(JSON_THROW_USER)\n    #undef JSON_THROW\n    #define JSON_THROW JSON_THROW_USER\n#endif\n#if defined(JSON_TRY_USER)\n    #undef JSON_TRY\n    #define JSON_TRY JSON_TRY_USER\n#endif\n#if defined(JSON_CATCH_USER)\n    #undef JSON_CATCH\n    #define JSON_CATCH JSON_CATCH_USER\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_CATCH_USER\n#endif\n#if defined(JSON_INTERNAL_CATCH_USER)\n    #undef JSON_INTERNAL_CATCH\n    #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER\n#endif\n\n// allow overriding assert\n#if !defined(JSON_ASSERT)\n    #include <cassert> // assert\n    #define JSON_ASSERT(x) assert(x)\n#endif\n\n// allow to access some private functions (needed by the test suite)\n#if defined(JSON_TESTS_PRIVATE)\n    #define JSON_PRIVATE_UNLESS_TESTED public\n#else\n    #define JSON_PRIVATE_UNLESS_TESTED private\n#endif\n\n/*!\n@brief macro to briefly define a mapping between an enum and JSON\n@def NLOHMANN_JSON_SERIALIZE_ENUM\n@since version 3.4.0\n*/\n#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...)                                            \\\n    template<typename BasicJsonType>                                                            \\\n    inline void to_json(BasicJsonType& j, const ENUM_TYPE& e)                                   \\\n    {                                                                                           \\\n        /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */                                \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");          \\\n        /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */       \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                      \\\n                               [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool  \\\n        {                                                                                       \\\n            return ej_pair.first == e;                                                          \\\n        });                                                                                     \\\n        j = ((it != std::end(m)) ? it : std::begin(m))->second;                                 \\\n    }                                                                                           \\\n    template<typename BasicJsonType>                                                            \\\n    inline void from_json(const BasicJsonType& j, ENUM_TYPE& e)                                 \\\n    {                                                                                           \\\n        /* NOLINTNEXTLINE(modernize-type-traits) we use C++11 */                                \\\n        static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE \" must be an enum!\");          \\\n        /* NOLINTNEXTLINE(modernize-avoid-c-arrays) we don't want to depend on <array> */       \\\n        static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__;                     \\\n        auto it = std::find_if(std::begin(m), std::end(m),                                      \\\n                               [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \\\n        {                                                                                       \\\n            return ej_pair.second == j;                                                         \\\n        });                                                                                     \\\n        e = ((it != std::end(m)) ? it : std::begin(m))->first;                                  \\\n    }\n\n// Ugly macros to avoid uglier copy-paste when specializing basic_json. They\n// may be removed in the future once the class is split.\n\n#define NLOHMANN_BASIC_JSON_TPL_DECLARATION                                \\\n    template<template<typename, typename, typename...> class ObjectType,   \\\n             template<typename, typename...> class ArrayType,              \\\n             class StringType, class BooleanType, class NumberIntegerType, \\\n             class NumberUnsignedType, class NumberFloatType,              \\\n             template<typename> class AllocatorType,                       \\\n             template<typename, typename = void> class JSONSerializer,     \\\n             class BinaryType,                                             \\\n             class CustomBaseClass>\n\n#define NLOHMANN_BASIC_JSON_TPL                                            \\\n    basic_json<ObjectType, ArrayType, StringType, BooleanType,             \\\n    NumberIntegerType, NumberUnsignedType, NumberFloatType,                \\\n    AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>\n\n// Macros to simplify conversion from/to types\n\n#define NLOHMANN_JSON_EXPAND( x ) x\n#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME\n#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \\\n        NLOHMANN_JSON_PASTE64, \\\n        NLOHMANN_JSON_PASTE63, \\\n        NLOHMANN_JSON_PASTE62, \\\n        NLOHMANN_JSON_PASTE61, \\\n        NLOHMANN_JSON_PASTE60, \\\n        NLOHMANN_JSON_PASTE59, \\\n        NLOHMANN_JSON_PASTE58, \\\n        NLOHMANN_JSON_PASTE57, \\\n        NLOHMANN_JSON_PASTE56, \\\n        NLOHMANN_JSON_PASTE55, \\\n        NLOHMANN_JSON_PASTE54, \\\n        NLOHMANN_JSON_PASTE53, \\\n        NLOHMANN_JSON_PASTE52, \\\n        NLOHMANN_JSON_PASTE51, \\\n        NLOHMANN_JSON_PASTE50, \\\n        NLOHMANN_JSON_PASTE49, \\\n        NLOHMANN_JSON_PASTE48, \\\n        NLOHMANN_JSON_PASTE47, \\\n        NLOHMANN_JSON_PASTE46, \\\n        NLOHMANN_JSON_PASTE45, \\\n        NLOHMANN_JSON_PASTE44, \\\n        NLOHMANN_JSON_PASTE43, \\\n        NLOHMANN_JSON_PASTE42, \\\n        NLOHMANN_JSON_PASTE41, \\\n        NLOHMANN_JSON_PASTE40, \\\n        NLOHMANN_JSON_PASTE39, \\\n        NLOHMANN_JSON_PASTE38, \\\n        NLOHMANN_JSON_PASTE37, \\\n        NLOHMANN_JSON_PASTE36, \\\n        NLOHMANN_JSON_PASTE35, \\\n        NLOHMANN_JSON_PASTE34, \\\n        NLOHMANN_JSON_PASTE33, \\\n        NLOHMANN_JSON_PASTE32, \\\n        NLOHMANN_JSON_PASTE31, \\\n        NLOHMANN_JSON_PASTE30, \\\n        NLOHMANN_JSON_PASTE29, \\\n        NLOHMANN_JSON_PASTE28, \\\n        NLOHMANN_JSON_PASTE27, \\\n        NLOHMANN_JSON_PASTE26, \\\n        NLOHMANN_JSON_PASTE25, \\\n        NLOHMANN_JSON_PASTE24, \\\n        NLOHMANN_JSON_PASTE23, \\\n        NLOHMANN_JSON_PASTE22, \\\n        NLOHMANN_JSON_PASTE21, \\\n        NLOHMANN_JSON_PASTE20, \\\n        NLOHMANN_JSON_PASTE19, \\\n        NLOHMANN_JSON_PASTE18, \\\n        NLOHMANN_JSON_PASTE17, \\\n        NLOHMANN_JSON_PASTE16, \\\n        NLOHMANN_JSON_PASTE15, \\\n        NLOHMANN_JSON_PASTE14, \\\n        NLOHMANN_JSON_PASTE13, \\\n        NLOHMANN_JSON_PASTE12, \\\n        NLOHMANN_JSON_PASTE11, \\\n        NLOHMANN_JSON_PASTE10, \\\n        NLOHMANN_JSON_PASTE9, \\\n        NLOHMANN_JSON_PASTE8, \\\n        NLOHMANN_JSON_PASTE7, \\\n        NLOHMANN_JSON_PASTE6, \\\n        NLOHMANN_JSON_PASTE5, \\\n        NLOHMANN_JSON_PASTE4, \\\n        NLOHMANN_JSON_PASTE3, \\\n        NLOHMANN_JSON_PASTE2, \\\n        NLOHMANN_JSON_PASTE1)(__VA_ARGS__))\n#define NLOHMANN_JSON_PASTE2(func, v1) func(v1)\n#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)\n#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)\n#define NLOHMANN_JSON_PASTE5(func, v1, v2, v3, v4) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE4(func, v2, v3, v4)\n#define NLOHMANN_JSON_PASTE6(func, v1, v2, v3, v4, v5) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE5(func, v2, v3, v4, v5)\n#define NLOHMANN_JSON_PASTE7(func, v1, v2, v3, v4, v5, v6) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE6(func, v2, v3, v4, v5, v6)\n#define NLOHMANN_JSON_PASTE8(func, v1, v2, v3, v4, v5, v6, v7) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE7(func, v2, v3, v4, v5, v6, v7)\n#define NLOHMANN_JSON_PASTE9(func, v1, v2, v3, v4, v5, v6, v7, v8) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE8(func, v2, v3, v4, v5, v6, v7, v8)\n#define NLOHMANN_JSON_PASTE10(func, v1, v2, v3, v4, v5, v6, v7, v8, v9) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE9(func, v2, v3, v4, v5, v6, v7, v8, v9)\n#define NLOHMANN_JSON_PASTE11(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE10(func, v2, v3, v4, v5, v6, v7, v8, v9, v10)\n#define NLOHMANN_JSON_PASTE12(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE11(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11)\n#define NLOHMANN_JSON_PASTE13(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE12(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12)\n#define NLOHMANN_JSON_PASTE14(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE13(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13)\n#define NLOHMANN_JSON_PASTE15(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE14(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14)\n#define NLOHMANN_JSON_PASTE16(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE15(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15)\n#define NLOHMANN_JSON_PASTE17(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE16(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16)\n#define NLOHMANN_JSON_PASTE18(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE17(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17)\n#define NLOHMANN_JSON_PASTE19(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE18(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18)\n#define NLOHMANN_JSON_PASTE20(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE19(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19)\n#define NLOHMANN_JSON_PASTE21(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE20(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)\n#define NLOHMANN_JSON_PASTE22(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE21(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21)\n#define NLOHMANN_JSON_PASTE23(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE22(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22)\n#define NLOHMANN_JSON_PASTE24(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE23(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23)\n#define NLOHMANN_JSON_PASTE25(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE24(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24)\n#define NLOHMANN_JSON_PASTE26(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE25(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25)\n#define NLOHMANN_JSON_PASTE27(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE26(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26)\n#define NLOHMANN_JSON_PASTE28(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE27(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27)\n#define NLOHMANN_JSON_PASTE29(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE28(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28)\n#define NLOHMANN_JSON_PASTE30(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE29(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29)\n#define NLOHMANN_JSON_PASTE31(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE30(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30)\n#define NLOHMANN_JSON_PASTE32(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE31(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31)\n#define NLOHMANN_JSON_PASTE33(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE32(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32)\n#define NLOHMANN_JSON_PASTE34(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE33(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33)\n#define NLOHMANN_JSON_PASTE35(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE34(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34)\n#define NLOHMANN_JSON_PASTE36(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE35(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35)\n#define NLOHMANN_JSON_PASTE37(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE36(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36)\n#define NLOHMANN_JSON_PASTE38(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE37(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37)\n#define NLOHMANN_JSON_PASTE39(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE38(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38)\n#define NLOHMANN_JSON_PASTE40(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE39(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39)\n#define NLOHMANN_JSON_PASTE41(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE40(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40)\n#define NLOHMANN_JSON_PASTE42(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE41(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41)\n#define NLOHMANN_JSON_PASTE43(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE42(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42)\n#define NLOHMANN_JSON_PASTE44(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE43(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43)\n#define NLOHMANN_JSON_PASTE45(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE44(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44)\n#define NLOHMANN_JSON_PASTE46(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE45(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45)\n#define NLOHMANN_JSON_PASTE47(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE46(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46)\n#define NLOHMANN_JSON_PASTE48(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE47(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47)\n#define NLOHMANN_JSON_PASTE49(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE48(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48)\n#define NLOHMANN_JSON_PASTE50(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE49(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49)\n#define NLOHMANN_JSON_PASTE51(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE50(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50)\n#define NLOHMANN_JSON_PASTE52(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE51(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51)\n#define NLOHMANN_JSON_PASTE53(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE52(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52)\n#define NLOHMANN_JSON_PASTE54(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE53(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53)\n#define NLOHMANN_JSON_PASTE55(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE54(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54)\n#define NLOHMANN_JSON_PASTE56(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE55(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55)\n#define NLOHMANN_JSON_PASTE57(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE56(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56)\n#define NLOHMANN_JSON_PASTE58(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE57(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57)\n#define NLOHMANN_JSON_PASTE59(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE58(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58)\n#define NLOHMANN_JSON_PASTE60(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE59(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59)\n#define NLOHMANN_JSON_PASTE61(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE60(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60)\n#define NLOHMANN_JSON_PASTE62(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE61(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61)\n#define NLOHMANN_JSON_PASTE63(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE62(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62)\n#define NLOHMANN_JSON_PASTE64(func, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE63(func, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49, v50, v51, v52, v53, v54, v55, v56, v57, v58, v59, v60, v61, v62, v63)\n\n#define NLOHMANN_JSON_TO(v1) nlohmann_json_j[#v1] = nlohmann_json_t.v1;\n#define NLOHMANN_JSON_FROM(v1) nlohmann_json_j.at(#v1).get_to(nlohmann_json_t.v1);\n#define NLOHMANN_JSON_FROM_WITH_DEFAULT(v1) nlohmann_json_t.v1 = !nlohmann_json_j.is_null() ? nlohmann_json_j.value(#v1, nlohmann_json_default_obj.v1) : nlohmann_json_default_obj.v1;\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_INTRUSIVE\n@since version 3.9.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/\n*/\n#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT\n@since version 3.11.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/\n*/\n#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE\n@since version 3.11.3\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_intrusive/\n*/\n#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE\n@since version 3.9.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/\n*/\n#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT\n@since version 3.11.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/\n*/\n#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE\n@since version 3.11.3\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_type_non_intrusive/\n*/\n#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE\n@since version 3.12.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/\n*/\n#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE(Type, BaseType, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT\n@since version 3.12.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/\n*/\n#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE\n@since version 3.12.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/\n*/\n#define NLOHMANN_DEFINE_DERIVED_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    friend void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE\n@since version 3.12.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/\n*/\n#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE(Type, BaseType, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT\n@since version 3.12.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/\n*/\n#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, BaseType, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) { nlohmann::from_json(nlohmann_json_j, static_cast<BaseType&>(nlohmann_json_t)); const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) }\n\n/*!\n@brief macro\n@def NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE\n@since version 3.12.0\n@sa https://json.nlohmann.me/api/macros/nlohmann_define_derived_type/\n*/\n#define NLOHMANN_DEFINE_DERIVED_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, BaseType, ...)  \\\n    template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \\\n    void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) { nlohmann::to_json(nlohmann_json_j, static_cast<const BaseType &>(nlohmann_json_t)); NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) }\n\n// inspired from https://stackoverflow.com/a/26745591\n// allows calling any std function as if (e.g., with begin):\n// using std::begin; begin(x);\n//\n// it allows using the detected idiom to retrieve the return type\n// of such an expression\n#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name)                                 \\\n    namespace detail {                                                            \\\n    using std::std_name;                                                          \\\n    \\\n    template<typename... T>                                                       \\\n    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \\\n    }                                                                             \\\n    \\\n    namespace detail2 {                                                           \\\n    struct std_name##_tag                                                         \\\n    {                                                                             \\\n    };                                                                            \\\n    \\\n    template<typename... T>                                                       \\\n    std_name##_tag std_name(T&&...);                                              \\\n    \\\n    template<typename... T>                                                       \\\n    using result_of_##std_name = decltype(std_name(std::declval<T>()...));        \\\n    \\\n    template<typename... T>                                                       \\\n    struct would_call_std_##std_name                                              \\\n    {                                                                             \\\n        static constexpr auto const value = ::nlohmann::detail::                  \\\n                                            is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \\\n    };                                                                            \\\n    } /* namespace detail2 */ \\\n    \\\n    template<typename... T>                                                       \\\n    struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...>   \\\n    {                                                                             \\\n    }\n\n#ifndef JSON_USE_IMPLICIT_CONVERSIONS\n    #define JSON_USE_IMPLICIT_CONVERSIONS 1\n#endif\n\n#if JSON_USE_IMPLICIT_CONVERSIONS\n    #define JSON_EXPLICIT\n#else\n    #define JSON_EXPLICIT explicit\n#endif\n\n#ifndef JSON_DISABLE_ENUM_SERIALIZATION\n    #define JSON_DISABLE_ENUM_SERIALIZATION 0\n#endif\n\n#ifndef JSON_USE_GLOBAL_UDLS\n    #define JSON_USE_GLOBAL_UDLS 1\n#endif\n\n#if JSON_HAS_THREE_WAY_COMPARISON\n    #include <compare> // partial_ordering\n#endif\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n///////////////////////////\n// JSON type enumeration //\n///////////////////////////\n\n/*!\n@brief the JSON type enumeration\n\nThis enumeration collects the different JSON types. It is internally used to\ndistinguish the stored values, and the functions @ref basic_json::is_null(),\n@ref basic_json::is_object(), @ref basic_json::is_array(),\n@ref basic_json::is_string(), @ref basic_json::is_boolean(),\n@ref basic_json::is_number() (with @ref basic_json::is_number_integer(),\n@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()),\n@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and\n@ref basic_json::is_structured() rely on it.\n\n@note There are three enumeration entries (number_integer, number_unsigned, and\nnumber_float), because the library distinguishes these three types for numbers:\n@ref basic_json::number_unsigned_t is used for unsigned integers,\n@ref basic_json::number_integer_t is used for signed integers, and\n@ref basic_json::number_float_t is used for floating-point numbers or to\napproximate integers which do not fit in the limits of their respective type.\n\n@sa see @ref basic_json::basic_json(const value_t value_type) -- create a JSON\nvalue with the default value for a given type\n\n@since version 1.0.0\n*/\nenum class value_t : std::uint8_t\n{\n    null,             ///< null value\n    object,           ///< object (unordered set of name/value pairs)\n    array,            ///< array (ordered collection of values)\n    string,           ///< string value\n    boolean,          ///< boolean value\n    number_integer,   ///< number value (signed integer)\n    number_unsigned,  ///< number value (unsigned integer)\n    number_float,     ///< number value (floating-point)\n    binary,           ///< binary array (ordered collection of bytes)\n    discarded         ///< discarded by the parser callback function\n};\n\n/*!\n@brief comparison operator for JSON types\n\nReturns an ordering that is similar to Python:\n- order: null < boolean < number < object < array < string < binary\n- furthermore, each type is not smaller than itself\n- discarded values are not comparable\n- binary is represented as a b\"\" string in python and directly comparable to a\n  string; however, making a binary array directly comparable with a string would\n  be surprising behavior in a JSON file.\n\n@since version 1.0.0\n*/\n#if JSON_HAS_THREE_WAY_COMPARISON\n    inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*\n#else\n    inline bool operator<(const value_t lhs, const value_t rhs) noexcept\n#endif\n{\n    static constexpr std::array<std::uint8_t, 9> order = {{\n            0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,\n            1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */,\n            6 /* binary */\n        }\n    };\n\n    const auto l_index = static_cast<std::size_t>(lhs);\n    const auto r_index = static_cast<std::size_t>(rhs);\n#if JSON_HAS_THREE_WAY_COMPARISON\n    if (l_index < order.size() && r_index < order.size())\n    {\n        return order[l_index] <=> order[r_index]; // *NOPAD*\n    }\n    return std::partial_ordering::unordered;\n#else\n    return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];\n#endif\n}\n\n// GCC selects the built-in operator< over an operator rewritten from\n// a user-defined spaceship operator\n// Clang, MSVC, and ICC select the rewritten candidate\n// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)\n#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)\ninline bool operator<(const value_t lhs, const value_t rhs) noexcept\n{\n    return std::is_lt(lhs <=> rhs); // *NOPAD*\n}\n#endif\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/string_escape.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/*!\n@brief replace all occurrences of a substring by another string\n\n@param[in,out] s  the string to manipulate; changed so that all\n               occurrences of @a f are replaced with @a t\n@param[in]     f  the substring to replace with @a t\n@param[in]     t  the string to replace @a f\n\n@pre The search string @a f must not be empty. **This precondition is\nenforced with an assertion.**\n\n@since version 2.0.0\n*/\ntemplate<typename StringType>\ninline void replace_substring(StringType& s, const StringType& f,\n                              const StringType& t)\n{\n    JSON_ASSERT(!f.empty());\n    for (auto pos = s.find(f);                // find first occurrence of f\n            pos != StringType::npos;          // make sure f was found\n            s.replace(pos, f.size(), t),      // replace with t, and\n            pos = s.find(f, pos + t.size()))  // find next occurrence of f\n    {}\n}\n\n/*!\n * @brief string escaping as described in RFC 6901 (Sect. 4)\n * @param[in] s string to escape\n * @return    escaped string\n *\n * Note the order of escaping \"~\" to \"~0\" and \"/\" to \"~1\" is important.\n */\ntemplate<typename StringType>\ninline StringType escape(StringType s)\n{\n    replace_substring(s, StringType{\"~\"}, StringType{\"~0\"});\n    replace_substring(s, StringType{\"/\"}, StringType{\"~1\"});\n    return s;\n}\n\n/*!\n * @brief string unescaping as described in RFC 6901 (Sect. 4)\n * @param[in] s string to unescape\n * @return    unescaped string\n *\n * Note the order of escaping \"~1\" to \"/\" and \"~0\" to \"~\" is important.\n */\ntemplate<typename StringType>\nstatic void unescape(StringType& s)\n{\n    replace_substring(s, StringType{\"~1\"}, StringType{\"/\"});\n    replace_substring(s, StringType{\"~0\"}, StringType{\"~\"});\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/input/position_t.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef> // size_t\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/// struct to capture the start position of the current token\nstruct position_t\n{\n    /// the total number of characters read\n    std::size_t chars_read_total = 0;\n    /// the number of characters read in the current line\n    std::size_t chars_read_current_line = 0;\n    /// the number of lines read\n    std::size_t lines_read = 0;\n\n    /// conversion to size_t to preserve SAX interface\n    constexpr operator size_t() const\n    {\n        return chars_read_total;\n    }\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-FileCopyrightText: 2018 The Abseil Authors\n// SPDX-License-Identifier: MIT\n\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type\n#include <utility> // index_sequence, make_index_sequence, index_sequence_for\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename T>\nusing uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;\n\n#ifdef JSON_HAS_CPP_14\n\n// the following utilities are natively available in C++14\nusing std::enable_if_t;\nusing std::index_sequence;\nusing std::make_index_sequence;\nusing std::index_sequence_for;\n\n#else\n\n// alias templates to reduce boilerplate\ntemplate<bool B, typename T = void>\nusing enable_if_t = typename std::enable_if<B, T>::type;\n\n// The following code is taken from https://github.com/abseil/abseil-cpp/blob/10cb35e459f5ecca5b2ff107635da0bfa41011b4/absl/utility/utility.h\n// which is part of Google Abseil (https://github.com/abseil/abseil-cpp), licensed under the Apache License 2.0.\n\n//// START OF CODE FROM GOOGLE ABSEIL\n\n// integer_sequence\n//\n// Class template representing a compile-time integer sequence. An instantiation\n// of `integer_sequence<T, Ints...>` has a sequence of integers encoded in its\n// type through its template arguments (which is a common need when\n// working with C++11 variadic templates). `absl::integer_sequence` is designed\n// to be a drop-in replacement for C++14's `std::integer_sequence`.\n//\n// Example:\n//\n//   template< class T, T... Ints >\n//   void user_function(integer_sequence<T, Ints...>);\n//\n//   int main()\n//   {\n//     // user_function's `T` will be deduced to `int` and `Ints...`\n//     // will be deduced to `0, 1, 2, 3, 4`.\n//     user_function(make_integer_sequence<int, 5>());\n//   }\ntemplate <typename T, T... Ints>\nstruct integer_sequence\n{\n    using value_type = T;\n    static constexpr std::size_t size() noexcept\n    {\n        return sizeof...(Ints);\n    }\n};\n\n// index_sequence\n//\n// A helper template for an `integer_sequence` of `size_t`,\n// `absl::index_sequence` is designed to be a drop-in replacement for C++14's\n// `std::index_sequence`.\ntemplate <size_t... Ints>\nusing index_sequence = integer_sequence<size_t, Ints...>;\n\nnamespace utility_internal\n{\n\ntemplate <typename Seq, size_t SeqSize, size_t Rem>\nstruct Extend;\n\n// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.\ntemplate <typename T, T... Ints, size_t SeqSize>\nstruct Extend<integer_sequence<T, Ints...>, SeqSize, 0>\n{\n    using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >;\n};\n\ntemplate <typename T, T... Ints, size_t SeqSize>\nstruct Extend<integer_sequence<T, Ints...>, SeqSize, 1>\n{\n    using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >;\n};\n\n// Recursion helper for 'make_integer_sequence<T, N>'.\n// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.\ntemplate <typename T, size_t N>\nstruct Gen\n{\n    using type =\n        typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type;\n};\n\ntemplate <typename T>\nstruct Gen<T, 0>\n{\n    using type = integer_sequence<T>;\n};\n\n}  // namespace utility_internal\n\n// Compile-time sequences of integers\n\n// make_integer_sequence\n//\n// This template alias is equivalent to\n// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in\n// replacement for C++14's `std::make_integer_sequence`.\ntemplate <typename T, T N>\nusing make_integer_sequence = typename utility_internal::Gen<T, N>::type;\n\n// make_index_sequence\n//\n// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,\n// and is designed to be a drop-in replacement for C++14's\n// `std::make_index_sequence`.\ntemplate <size_t N>\nusing make_index_sequence = make_integer_sequence<size_t, N>;\n\n// index_sequence_for\n//\n// Converts a typename pack into an index sequence of the same length, and\n// is designed to be a drop-in replacement for C++14's\n// `std::index_sequence_for()`\ntemplate <typename... Ts>\nusing index_sequence_for = make_index_sequence<sizeof...(Ts)>;\n\n//// END OF CODE FROM GOOGLE ABSEIL\n\n#endif\n\n// dispatch utility (taken from ranges-v3)\ntemplate<unsigned N> struct priority_tag : priority_tag < N - 1 > {};\ntemplate<> struct priority_tag<0> {};\n\n// taken from ranges-v3\ntemplate<typename T>\nstruct static_const\n{\n    static JSON_INLINE_VARIABLE constexpr T value{};\n};\n\n#ifndef JSON_HAS_CPP_17\n    template<typename T>\n    constexpr T static_const<T>::value;\n#endif\n\ntemplate<typename T, typename... Args>\nconstexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args)\n{\n    return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}};\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <limits> // numeric_limits\n#include <string> // char_traits\n#include <tuple> // tuple\n#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type\n#include <utility> // declval\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <iterator> // random_access_iterator_tag\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n// #include <nlohmann/detail/meta/void_t.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename It, typename = void>\nstruct iterator_types {};\n\ntemplate<typename It>\nstruct iterator_types <\n    It,\n    void_t<typename It::difference_type, typename It::value_type, typename It::pointer,\n    typename It::reference, typename It::iterator_category >>\n{\n    using difference_type = typename It::difference_type;\n    using value_type = typename It::value_type;\n    using pointer = typename It::pointer;\n    using reference = typename It::reference;\n    using iterator_category = typename It::iterator_category;\n};\n\n// This is required as some compilers implement std::iterator_traits in a way that\n// doesn't work with SFINAE. See https://github.com/nlohmann/json/issues/1341.\ntemplate<typename T, typename = void>\nstruct iterator_traits\n{\n};\n\ntemplate<typename T>\nstruct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >>\n    : iterator_types<T>\n{\n};\n\ntemplate<typename T>\nstruct iterator_traits<T*, enable_if_t<std::is_object<T>::value>>\n{\n    using iterator_category = std::random_access_iterator_tag;\n    using value_type = T;\n    using difference_type = ptrdiff_t;\n    using pointer = T*;\n    using reference = T&;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/call_std/begin.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\nNLOHMANN_CAN_CALL_STD_FUNC_IMPL(begin);\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/meta/call_std/end.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\nNLOHMANN_CAN_CALL_STD_FUNC_IMPL(end);\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/json_fwd.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_\n    #define INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n    #include <cstdint> // int64_t, uint64_t\n    #include <map> // map\n    #include <memory> // allocator\n    #include <string> // string\n    #include <vector> // vector\n\n    // #include <nlohmann/detail/abi_macros.hpp>\n\n\n    /*!\n    @brief namespace for Niels Lohmann\n    @see https://github.com/nlohmann\n    @since version 1.0.0\n    */\n    NLOHMANN_JSON_NAMESPACE_BEGIN\n\n    /*!\n    @brief default JSONSerializer template argument\n\n    This serializer ignores the template arguments and uses ADL\n    ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\n    for serialization.\n    */\n    template<typename T = void, typename SFINAE = void>\n    struct adl_serializer;\n\n    /// a class to store JSON values\n    /// @sa https://json.nlohmann.me/api/basic_json/\n    template<template<typename U, typename V, typename... Args> class ObjectType =\n    std::map,\n    template<typename U, typename... Args> class ArrayType = std::vector,\n    class StringType = std::string, class BooleanType = bool,\n    class NumberIntegerType = std::int64_t,\n    class NumberUnsignedType = std::uint64_t,\n    class NumberFloatType = double,\n    template<typename U> class AllocatorType = std::allocator,\n    template<typename T, typename SFINAE = void> class JSONSerializer =\n    adl_serializer,\n    class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError\n    class CustomBaseClass = void>\n    class basic_json;\n\n    /// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document\n    /// @sa https://json.nlohmann.me/api/json_pointer/\n    template<typename RefStringType>\n    class json_pointer;\n\n    /*!\n    @brief default specialization\n    @sa https://json.nlohmann.me/api/json/\n    */\n    using json = basic_json<>;\n\n    /// @brief a minimal map-like container that preserves insertion order\n    /// @sa https://json.nlohmann.me/api/ordered_map/\n    template<class Key, class T, class IgnoredLess, class Allocator>\n    struct ordered_map;\n\n    /// @brief specialization that maintains the insertion order of object keys\n    /// @sa https://json.nlohmann.me/api/ordered_json/\n    using ordered_json = basic_json<nlohmann::ordered_map>;\n\n    NLOHMANN_JSON_NAMESPACE_END\n\n#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n/*!\n@brief detail namespace with internal helper functions\n\nThis namespace collects functions that should not be exposed,\nimplementations of some @ref basic_json methods, and meta-programming helpers.\n\n@since version 2.1.0\n*/\nnamespace detail\n{\n\n/////////////\n// helpers //\n/////////////\n\n// Note to maintainers:\n//\n// Every trait in this file expects a non CV-qualified type.\n// The only exceptions are in the 'aliases for detected' section\n// (i.e. those of the form: decltype(T::member_function(std::declval<T>())))\n//\n// In this case, T has to be properly CV-qualified to constraint the function arguments\n// (e.g. to_json(BasicJsonType&, const T&))\n\ntemplate<typename> struct is_basic_json : std::false_type {};\n\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstruct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};\n\n// used by exceptions create() member functions\n// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t\n// false_type otherwise\ntemplate<typename BasicJsonContext>\nstruct is_basic_json_context :\n    std::integral_constant < bool,\n    is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value\n    || std::is_same<BasicJsonContext, std::nullptr_t>::value >\n{};\n\n//////////////////////\n// json_ref helpers //\n//////////////////////\n\ntemplate<typename>\nclass json_ref;\n\ntemplate<typename>\nstruct is_json_ref : std::false_type {};\n\ntemplate<typename T>\nstruct is_json_ref<json_ref<T>> : std::true_type {};\n\n//////////////////////////\n// aliases for detected //\n//////////////////////////\n\ntemplate<typename T>\nusing mapped_type_t = typename T::mapped_type;\n\ntemplate<typename T>\nusing key_type_t = typename T::key_type;\n\ntemplate<typename T>\nusing value_type_t = typename T::value_type;\n\ntemplate<typename T>\nusing difference_type_t = typename T::difference_type;\n\ntemplate<typename T>\nusing pointer_t = typename T::pointer;\n\ntemplate<typename T>\nusing reference_t = typename T::reference;\n\ntemplate<typename T>\nusing iterator_category_t = typename T::iterator_category;\n\ntemplate<typename T, typename... Args>\nusing to_json_function = decltype(T::to_json(std::declval<Args>()...));\n\ntemplate<typename T, typename... Args>\nusing from_json_function = decltype(T::from_json(std::declval<Args>()...));\n\ntemplate<typename T, typename U>\nusing get_template_function = decltype(std::declval<T>().template get<U>());\n\n// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_from_json : std::false_type {};\n\n// trait checking if j.get<T> is valid\n// use this trait instead of std::is_constructible or std::is_convertible,\n// both rely on, or make use of implicit conversions, and thus fail when T\n// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)\ntemplate <typename BasicJsonType, typename T>\nstruct is_getable\n{\n    static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;\n};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, from_json_function, serializer,\n        const BasicJsonType&, T&>::value;\n};\n\n// This trait checks if JSONSerializer<T>::from_json(json const&) exists\n// this overload is used for non-default-constructible user-defined-types\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_non_default_from_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<T, from_json_function, serializer,\n        const BasicJsonType&>::value;\n};\n\n// This trait checks if BasicJsonType::json_serializer<T>::to_json exists\n// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.\ntemplate<typename BasicJsonType, typename T, typename = void>\nstruct has_to_json : std::false_type {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >>\n{\n    using serializer = typename BasicJsonType::template json_serializer<T, void>;\n\n    static constexpr bool value =\n        is_detected_exact<void, to_json_function, serializer, BasicJsonType&,\n        T>::value;\n};\n\ntemplate<typename T>\nusing detect_key_compare = typename T::key_compare;\n\ntemplate<typename T>\nstruct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {};\n\n// obtains the actual object key comparator\ntemplate<typename BasicJsonType>\nstruct actual_object_comparator\n{\n    using object_t = typename BasicJsonType::object_t;\n    using object_comparator_t = typename BasicJsonType::default_object_comparator_t;\n    using type = typename std::conditional < has_key_compare<object_t>::value,\n          typename object_t::key_compare, object_comparator_t>::type;\n};\n\ntemplate<typename BasicJsonType>\nusing actual_object_comparator_t = typename actual_object_comparator<BasicJsonType>::type;\n\n/////////////////\n// char_traits //\n/////////////////\n\n// Primary template of char_traits calls std char_traits\ntemplate<typename T>\nstruct char_traits : std::char_traits<T>\n{};\n\n// Explicitly define char traits for unsigned char since it is not standard\ntemplate<>\nstruct char_traits<unsigned char> : std::char_traits<char>\n{\n    using char_type = unsigned char;\n    using int_type = uint64_t;\n\n    // Redefine to_int_type function\n    static int_type to_int_type(char_type c) noexcept\n    {\n        return static_cast<int_type>(c);\n    }\n\n    static char_type to_char_type(int_type i) noexcept\n    {\n        return static_cast<char_type>(i);\n    }\n\n    static constexpr int_type eof() noexcept\n    {\n        return static_cast<int_type>(std::char_traits<char>::eof());\n    }\n};\n\n// Explicitly define char traits for signed char since it is not standard\ntemplate<>\nstruct char_traits<signed char> : std::char_traits<char>\n{\n    using char_type = signed char;\n    using int_type = uint64_t;\n\n    // Redefine to_int_type function\n    static int_type to_int_type(char_type c) noexcept\n    {\n        return static_cast<int_type>(c);\n    }\n\n    static char_type to_char_type(int_type i) noexcept\n    {\n        return static_cast<char_type>(i);\n    }\n\n    static constexpr int_type eof() noexcept\n    {\n        return static_cast<int_type>(std::char_traits<char>::eof());\n    }\n};\n\n///////////////////\n// is_ functions //\n///////////////////\n\n// https://en.cppreference.com/w/cpp/types/conjunction\ntemplate<class...> struct conjunction : std::true_type { };\ntemplate<class B> struct conjunction<B> : B { };\ntemplate<class B, class... Bn>\nstruct conjunction<B, Bn...>\n: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {};\n\n// https://en.cppreference.com/w/cpp/types/negation\ntemplate<class B> struct negation : std::integral_constant < bool, !B::value > { };\n\n// Reimplementation of is_constructible and is_default_constructible, due to them being broken for\n// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).\n// This causes compile errors in e.g. clang 3.5 or gcc 4.9.\ntemplate <typename T>\nstruct is_default_constructible : std::is_default_constructible<T> {};\n\ntemplate <typename T1, typename T2>\nstruct is_default_constructible<std::pair<T1, T2>>\n    : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};\n\ntemplate <typename T1, typename T2>\nstruct is_default_constructible<const std::pair<T1, T2>>\n    : conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {};\n\ntemplate <typename... Ts>\nstruct is_default_constructible<std::tuple<Ts...>>\n    : conjunction<is_default_constructible<Ts>...> {};\n\ntemplate <typename... Ts>\nstruct is_default_constructible<const std::tuple<Ts...>>\n    : conjunction<is_default_constructible<Ts>...> {};\n\ntemplate <typename T, typename... Args>\nstruct is_constructible : std::is_constructible<T, Args...> {};\n\ntemplate <typename T1, typename T2>\nstruct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {};\n\ntemplate <typename T1, typename T2>\nstruct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {};\n\ntemplate <typename... Ts>\nstruct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {};\n\ntemplate <typename... Ts>\nstruct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {};\n\ntemplate<typename T, typename = void>\nstruct is_iterator_traits : std::false_type {};\n\ntemplate<typename T>\nstruct is_iterator_traits<iterator_traits<T>>\n{\n  private:\n    using traits = iterator_traits<T>;\n\n  public:\n    static constexpr auto value =\n        is_detected<value_type_t, traits>::value &&\n        is_detected<difference_type_t, traits>::value &&\n        is_detected<pointer_t, traits>::value &&\n        is_detected<iterator_category_t, traits>::value &&\n        is_detected<reference_t, traits>::value;\n};\n\ntemplate<typename T>\nstruct is_range\n{\n  private:\n    using t_ref = typename std::add_lvalue_reference<T>::type;\n\n    using iterator = detected_t<result_of_begin, t_ref>;\n    using sentinel = detected_t<result_of_end, t_ref>;\n\n    // to be 100% correct, it should use https://en.cppreference.com/w/cpp/iterator/input_or_output_iterator\n    // and https://en.cppreference.com/w/cpp/iterator/sentinel_for\n    // but reimplementing these would be too much work, as a lot of other concepts are used underneath\n    static constexpr auto is_iterator_begin =\n        is_iterator_traits<iterator_traits<iterator>>::value;\n\n  public:\n    static constexpr bool value = !std::is_same<iterator, nonesuch>::value && !std::is_same<sentinel, nonesuch>::value && is_iterator_begin;\n};\n\ntemplate<typename R>\nusing iterator_t = enable_if_t<is_range<R>::value, result_of_begin<decltype(std::declval<R&>())>>;\n\ntemplate<typename T>\nusing range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;\n\n// The following implementation of is_complete_type is taken from\n// https://blogs.msdn.microsoft.com/vcblog/2015/12/02/partial-support-for-expression-sfinae-in-vs-2015-update-1/\n// and is written by Xiang Fan who agreed to using it in this library.\n\ntemplate<typename T, typename = void>\nstruct is_complete_type : std::false_type {};\n\ntemplate<typename T>\nstruct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType,\n         typename = void>\nstruct is_compatible_object_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type_impl <\n    BasicJsonType, CompatibleObjectType,\n    enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&&\n    is_detected<key_type_t, CompatibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    // macOS's is_constructible does not play well with nonesuch...\n    static constexpr bool value =\n        is_constructible<typename object_t::key_type,\n        typename CompatibleObjectType::key_type>::value &&\n        is_constructible<typename object_t::mapped_type,\n        typename CompatibleObjectType::mapped_type>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleObjectType>\nstruct is_compatible_object_type\n    : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         typename = void>\nstruct is_constructible_object_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type_impl <\n    BasicJsonType, ConstructibleObjectType,\n    enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&&\n    is_detected<key_type_t, ConstructibleObjectType>::value >>\n{\n    using object_t = typename BasicJsonType::object_t;\n\n    static constexpr bool value =\n        (is_default_constructible<ConstructibleObjectType>::value &&\n         (std::is_move_assignable<ConstructibleObjectType>::value ||\n          std::is_copy_assignable<ConstructibleObjectType>::value) &&\n         (is_constructible<typename ConstructibleObjectType::key_type,\n          typename object_t::key_type>::value &&\n          std::is_same <\n          typename object_t::mapped_type,\n          typename ConstructibleObjectType::mapped_type >::value)) ||\n        (has_from_json<BasicJsonType,\n         typename ConstructibleObjectType::mapped_type>::value ||\n         has_non_default_from_json <\n         BasicJsonType,\n         typename ConstructibleObjectType::mapped_type >::value);\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType>\nstruct is_constructible_object_type\n    : is_constructible_object_type_impl<BasicJsonType,\n      ConstructibleObjectType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleStringType>\nstruct is_compatible_string_type\n{\n    static constexpr auto value =\n        is_constructible<typename BasicJsonType::string_t, CompatibleStringType>::value;\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleStringType>\nstruct is_constructible_string_type\n{\n    // launder type through decltype() to fix compilation failure on ICPC\n#ifdef __INTEL_COMPILER\n    using laundered_type = decltype(std::declval<ConstructibleStringType>());\n#else\n    using laundered_type = ConstructibleStringType;\n#endif\n\n    static constexpr auto value =\n        conjunction <\n        is_constructible<laundered_type, typename BasicJsonType::string_t>,\n        is_detected_exact<typename BasicJsonType::string_t::value_type,\n        value_type_t, laundered_type >>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType, typename = void>\nstruct is_compatible_array_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type_impl <\n    BasicJsonType, CompatibleArrayType,\n    enable_if_t <\n    is_detected<iterator_t, CompatibleArrayType>::value&&\n    is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&&\n// special case for types like std::filesystem::path whose iterator's value_type are themselves\n// c.f. https://github.com/nlohmann/json/pull/3073\n    !std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >>\n{\n    static constexpr bool value =\n        is_constructible<BasicJsonType,\n        range_value_t<CompatibleArrayType>>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleArrayType>\nstruct is_compatible_array_type\n    : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType, typename = void>\nstruct is_constructible_array_type_impl : std::false_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t<std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value >>\n            : std::true_type {};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type_impl <\n    BasicJsonType, ConstructibleArrayType,\n    enable_if_t < !std::is_same<ConstructibleArrayType,\n    typename BasicJsonType::value_type>::value&&\n    !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&&\n    is_default_constructible<ConstructibleArrayType>::value&&\n(std::is_move_assignable<ConstructibleArrayType>::value ||\n std::is_copy_assignable<ConstructibleArrayType>::value)&&\nis_detected<iterator_t, ConstructibleArrayType>::value&&\nis_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&&\nis_detected<range_value_t, ConstructibleArrayType>::value&&\n// special case for types like std::filesystem::path whose iterator's value_type are themselves\n// c.f. https://github.com/nlohmann/json/pull/3073\n!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&&\nis_complete_type <\ndetected_t<range_value_t, ConstructibleArrayType >>::value >>\n{\n    using value_type = range_value_t<ConstructibleArrayType>;\n\n    static constexpr bool value =\n        std::is_same<value_type,\n        typename BasicJsonType::array_t::value_type>::value ||\n        has_from_json<BasicJsonType,\n        value_type>::value ||\n        has_non_default_from_json <\n        BasicJsonType,\n        value_type >::value;\n};\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType>\nstruct is_constructible_array_type\n    : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType,\n         typename = void>\nstruct is_compatible_integer_type_impl : std::false_type {};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type_impl <\n    RealIntegerType, CompatibleNumberIntegerType,\n    enable_if_t < std::is_integral<RealIntegerType>::value&&\n    std::is_integral<CompatibleNumberIntegerType>::value&&\n    !std::is_same<bool, CompatibleNumberIntegerType>::value >>\n{\n    // is there an assert somewhere on overflows?\n    using RealLimits = std::numeric_limits<RealIntegerType>;\n    using CompatibleLimits = std::numeric_limits<CompatibleNumberIntegerType>;\n\n    static constexpr auto value =\n        is_constructible<RealIntegerType,\n        CompatibleNumberIntegerType>::value &&\n        CompatibleLimits::is_integer &&\n        RealLimits::is_signed == CompatibleLimits::is_signed;\n};\n\ntemplate<typename RealIntegerType, typename CompatibleNumberIntegerType>\nstruct is_compatible_integer_type\n    : is_compatible_integer_type_impl<RealIntegerType,\n      CompatibleNumberIntegerType> {};\n\ntemplate<typename BasicJsonType, typename CompatibleType, typename = void>\nstruct is_compatible_type_impl: std::false_type {};\n\ntemplate<typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type_impl <\n    BasicJsonType, CompatibleType,\n    enable_if_t<is_complete_type<CompatibleType>::value >>\n{\n    static constexpr bool value =\n        has_to_json<BasicJsonType, CompatibleType>::value;\n};\n\ntemplate<typename BasicJsonType, typename CompatibleType>\nstruct is_compatible_type\n    : is_compatible_type_impl<BasicJsonType, CompatibleType> {};\n\ntemplate<typename T1, typename T2>\nstruct is_constructible_tuple : std::false_type {};\n\ntemplate<typename T1, typename... Args>\nstruct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {};\n\ntemplate<typename BasicJsonType, typename T>\nstruct is_json_iterator_of : std::false_type {};\n\ntemplate<typename BasicJsonType>\nstruct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {};\n\ntemplate<typename BasicJsonType>\nstruct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type\n{};\n\n// checks if a given type T is a template specialization of Primary\ntemplate<template <typename...> class Primary, typename T>\nstruct is_specialization_of : std::false_type {};\n\ntemplate<template <typename...> class Primary, typename... Args>\nstruct is_specialization_of<Primary, Primary<Args...>> : std::true_type {};\n\ntemplate<typename T>\nusing is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;\n\n// checks if A and B are comparable using Compare functor\ntemplate<typename Compare, typename A, typename B, typename = void>\nstruct is_comparable : std::false_type {};\n\ntemplate<typename Compare, typename A, typename B>\nstruct is_comparable<Compare, A, B, void_t<\ndecltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())),\ndecltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))\n>> : std::true_type {};\n\ntemplate<typename T>\nusing detect_is_transparent = typename T::is_transparent;\n\n// type trait to check if KeyType can be used as object key (without a BasicJsonType)\n// see is_usable_as_basic_json_key_type below\ntemplate<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,\n         bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>\nusing is_usable_as_key_type = typename std::conditional <\n                              is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value\n                              && !(ExcludeObjectKeyType && std::is_same<KeyType,\n                                   ObjectKeyType>::value)\n                              && (!RequireTransparentComparator\n                                  || is_detected <detect_is_transparent, Comparator>::value)\n                              && !is_json_pointer<KeyType>::value,\n                              std::true_type,\n                              std::false_type >::type;\n\n// type trait to check if KeyType can be used as object key\n// true if:\n//   - KeyType is comparable with BasicJsonType::object_t::key_type\n//   - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type\n//   - the comparator is transparent or RequireTransparentComparator is false\n//   - KeyType is not a JSON iterator or json_pointer\ntemplate<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true,\n         bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>\nusing is_usable_as_basic_json_key_type = typename std::conditional <\n    is_usable_as_key_type<typename BasicJsonType::object_comparator_t,\n    typename BasicJsonType::object_t::key_type, KeyTypeCVRef,\n    RequireTransparentComparator, ExcludeObjectKeyType>::value\n    && !is_json_iterator_of<BasicJsonType, KeyType>::value,\n    std::true_type,\n    std::false_type >::type;\n\ntemplate<typename ObjectType, typename KeyType>\nusing detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));\n\n// type trait to check if object_t has an erase() member functions accepting KeyType\ntemplate<typename BasicJsonType, typename KeyType>\nusing has_erase_with_key_type = typename std::conditional <\n                                is_detected <\n                                detect_erase_with_key_type,\n                                typename BasicJsonType::object_t, KeyType >::value,\n                                std::true_type,\n                                std::false_type >::type;\n\n// a naive helper to check if a type is an ordered_map (exploits the fact that\n// ordered_map inherits capacity() from std::vector)\ntemplate <typename T>\nstruct is_ordered_map\n{\n    using one = char;\n\n    struct two\n    {\n        char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n    };\n\n    template <typename C> static one test( decltype(&C::capacity) ) ;\n    template <typename C> static two test(...);\n\n    enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n};\n\n// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)\ntemplate < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >\nT conditional_static_cast(U value)\n{\n    return static_cast<T>(value);\n}\n\ntemplate<typename T, typename U, enable_if_t<std::is_same<T, U>::value, int> = 0>\nT conditional_static_cast(U value)\n{\n    return value;\n}\n\ntemplate<typename... Types>\nusing all_integral = conjunction<std::is_integral<Types>...>;\n\ntemplate<typename... Types>\nusing all_signed = conjunction<std::is_signed<Types>...>;\n\ntemplate<typename... Types>\nusing all_unsigned = conjunction<std::is_unsigned<Types>...>;\n\n// there's a disjunction trait in another PR; replace when merged\ntemplate<typename... Types>\nusing same_sign = std::integral_constant < bool,\n      all_signed<Types...>::value || all_unsigned<Types...>::value >;\n\ntemplate<typename OfType, typename T>\nusing never_out_of_range = std::integral_constant < bool,\n      (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType)))\n      || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;\n\ntemplate<typename OfType, typename T,\n         bool OfTypeSigned = std::is_signed<OfType>::value,\n         bool TSigned = std::is_signed<T>::value>\nstruct value_in_range_of_impl2;\n\ntemplate<typename OfType, typename T>\nstruct value_in_range_of_impl2<OfType, T, false, false>\n{\n    static constexpr bool test(T val)\n    {\n        using CommonType = typename std::common_type<OfType, T>::type;\n        return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());\n    }\n};\n\ntemplate<typename OfType, typename T>\nstruct value_in_range_of_impl2<OfType, T, true, false>\n{\n    static constexpr bool test(T val)\n    {\n        using CommonType = typename std::common_type<OfType, T>::type;\n        return static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());\n    }\n};\n\ntemplate<typename OfType, typename T>\nstruct value_in_range_of_impl2<OfType, T, false, true>\n{\n    static constexpr bool test(T val)\n    {\n        using CommonType = typename std::common_type<OfType, T>::type;\n        return val >= 0 && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());\n    }\n};\n\ntemplate<typename OfType, typename T>\nstruct value_in_range_of_impl2<OfType, T, true, true>\n{\n    static constexpr bool test(T val)\n    {\n        using CommonType = typename std::common_type<OfType, T>::type;\n        return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)())\n               && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());\n    }\n};\n\ntemplate<typename OfType, typename T,\n         bool NeverOutOfRange = never_out_of_range<OfType, T>::value,\n         typename = detail::enable_if_t<all_integral<OfType, T>::value>>\nstruct value_in_range_of_impl1;\n\ntemplate<typename OfType, typename T>\nstruct value_in_range_of_impl1<OfType, T, false>\n{\n    static constexpr bool test(T val)\n    {\n        return value_in_range_of_impl2<OfType, T>::test(val);\n    }\n};\n\ntemplate<typename OfType, typename T>\nstruct value_in_range_of_impl1<OfType, T, true>\n{\n    static constexpr bool test(T /*val*/)\n    {\n        return true;\n    }\n};\n\ntemplate<typename OfType, typename T>\nconstexpr bool value_in_range_of(T val)\n{\n    return value_in_range_of_impl1<OfType, T>::test(val);\n}\n\ntemplate<bool Value>\nusing bool_constant = std::integral_constant<bool, Value>;\n\n///////////////////////////////////////////////////////////////////////////////\n// is_c_string\n///////////////////////////////////////////////////////////////////////////////\n\nnamespace impl\n{\n\ntemplate<typename T>\nconstexpr bool is_c_string()\n{\n    using TUnExt = typename std::remove_extent<T>::type;\n    using TUnCVExt = typename std::remove_cv<TUnExt>::type;\n    using TUnPtr = typename std::remove_pointer<T>::type;\n    using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;\n    return\n        (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)\n        || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);\n}\n\n}  // namespace impl\n\n// checks whether T is a [cv] char */[cv] char[] C string\ntemplate<typename T>\nstruct is_c_string : bool_constant<impl::is_c_string<T>()> {};\n\ntemplate<typename T>\nusing is_c_string_uncvref = is_c_string<uncvref_t<T>>;\n\n///////////////////////////////////////////////////////////////////////////////\n// is_transparent\n///////////////////////////////////////////////////////////////////////////////\n\nnamespace impl\n{\n\ntemplate<typename T>\nconstexpr bool is_transparent()\n{\n    return is_detected<detect_is_transparent, T>::value;\n}\n\n}  // namespace impl\n\n// checks whether T has a member named is_transparent\ntemplate<typename T>\nstruct is_transparent : bool_constant<impl::is_transparent<T>()> {};\n\n///////////////////////////////////////////////////////////////////////////////\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/string_concat.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstring> // strlen\n#include <string> // string\n#include <utility> // forward\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ninline std::size_t concat_length()\n{\n    return 0;\n}\n\ntemplate<typename... Args>\ninline std::size_t concat_length(const char* cstr, const Args& ... rest);\n\ntemplate<typename StringType, typename... Args>\ninline std::size_t concat_length(const StringType& str, const Args& ... rest);\n\ntemplate<typename... Args>\ninline std::size_t concat_length(const char /*c*/, const Args& ... rest)\n{\n    return 1 + concat_length(rest...);\n}\n\ntemplate<typename... Args>\ninline std::size_t concat_length(const char* cstr, const Args& ... rest)\n{\n    // cppcheck-suppress ignoredReturnValue\n    return ::strlen(cstr) + concat_length(rest...);\n}\n\ntemplate<typename StringType, typename... Args>\ninline std::size_t concat_length(const StringType& str, const Args& ... rest)\n{\n    return str.size() + concat_length(rest...);\n}\n\ntemplate<typename OutStringType>\ninline void concat_into(OutStringType& /*out*/)\n{}\n\ntemplate<typename StringType, typename Arg>\nusing string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ()));\n\ntemplate<typename StringType, typename Arg>\nusing detect_string_can_append = is_detected<string_can_append, StringType, Arg>;\n\ntemplate<typename StringType, typename Arg>\nusing string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ());\n\ntemplate<typename StringType, typename Arg>\nusing detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;\n\ntemplate<typename StringType, typename Arg>\nusing string_can_append_iter = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().begin(), std::declval<const Arg&>().end()));\n\ntemplate<typename StringType, typename Arg>\nusing detect_string_can_append_iter = is_detected<string_can_append_iter, StringType, Arg>;\n\ntemplate<typename StringType, typename Arg>\nusing string_can_append_data = decltype(std::declval<StringType&>().append(std::declval<const Arg&>().data(), std::declval<const Arg&>().size()));\n\ntemplate<typename StringType, typename Arg>\nusing detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;\n\ntemplate < typename OutStringType, typename Arg, typename... Args,\n           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value\n                         && detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >\ninline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);\n\ntemplate < typename OutStringType, typename Arg, typename... Args,\n           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value\n                         && !detect_string_can_append_op<OutStringType, Arg>::value\n                         && detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >\ninline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);\n\ntemplate < typename OutStringType, typename Arg, typename... Args,\n           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value\n                         && !detect_string_can_append_op<OutStringType, Arg>::value\n                         && !detect_string_can_append_iter<OutStringType, Arg>::value\n                         && detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >\ninline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);\n\ntemplate<typename OutStringType, typename Arg, typename... Args,\n         enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>\ninline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)\n{\n    out.append(std::forward<Arg>(arg));\n    concat_into(out, std::forward<Args>(rest)...);\n}\n\ntemplate < typename OutStringType, typename Arg, typename... Args,\n           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value\n                         && detect_string_can_append_op<OutStringType, Arg>::value, int > >\ninline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)\n{\n    out += std::forward<Arg>(arg);\n    concat_into(out, std::forward<Args>(rest)...);\n}\n\ntemplate < typename OutStringType, typename Arg, typename... Args,\n           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value\n                         && !detect_string_can_append_op<OutStringType, Arg>::value\n                         && detect_string_can_append_iter<OutStringType, Arg>::value, int > >\ninline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)\n{\n    out.append(arg.begin(), arg.end());\n    concat_into(out, std::forward<Args>(rest)...);\n}\n\ntemplate < typename OutStringType, typename Arg, typename... Args,\n           enable_if_t < !detect_string_can_append<OutStringType, Arg>::value\n                         && !detect_string_can_append_op<OutStringType, Arg>::value\n                         && !detect_string_can_append_iter<OutStringType, Arg>::value\n                         && detect_string_can_append_data<OutStringType, Arg>::value, int > >\ninline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)\n{\n    out.append(arg.data(), arg.size());\n    concat_into(out, std::forward<Args>(rest)...);\n}\n\ntemplate<typename OutStringType = std::string, typename... Args>\ninline OutStringType concat(Args && ... args)\n{\n    OutStringType str;\n    str.reserve(concat_length(args...));\n    concat_into(str, std::forward<Args>(args)...);\n    return str;\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n\n// With -Wweak-vtables, Clang will complain about the exception classes as they\n// have no out-of-line virtual method definitions and their vtable will be\n// emitted in every translation unit. This issue cannot be fixed with a\n// header-only library as there is no implementation file to move these\n// functions to. As a result, we suppress this warning here to avoid client\n// code to stumble over this. See https://github.com/nlohmann/json/issues/4087\n// for a discussion.\n#if defined(__clang__)\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wweak-vtables\"\n#endif\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n////////////////\n// exceptions //\n////////////////\n\n/// @brief general exception of the @ref basic_json class\n/// @sa https://json.nlohmann.me/api/basic_json/exception/\nclass exception : public std::exception\n{\n  public:\n    /// returns the explanatory string\n    const char* what() const noexcept override\n    {\n        return m.what();\n    }\n\n    /// the id of the exception\n    const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)\n\n  protected:\n    JSON_HEDLEY_NON_NULL(3)\n    exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing)\n\n    static std::string name(const std::string& ename, int id_)\n    {\n        return concat(\"[json.exception.\", ename, '.', std::to_string(id_), \"] \");\n    }\n\n    static std::string diagnostics(std::nullptr_t /*leaf_element*/)\n    {\n        return \"\";\n    }\n\n    template<typename BasicJsonType>\n    static std::string diagnostics(const BasicJsonType* leaf_element)\n    {\n#if JSON_DIAGNOSTICS\n        std::vector<std::string> tokens;\n        for (const auto* current = leaf_element; current != nullptr && current->m_parent != nullptr; current = current->m_parent)\n        {\n            switch (current->m_parent->type())\n            {\n                case value_t::array:\n                {\n                    for (std::size_t i = 0; i < current->m_parent->m_data.m_value.array->size(); ++i)\n                    {\n                        if (&current->m_parent->m_data.m_value.array->operator[](i) == current)\n                        {\n                            tokens.emplace_back(std::to_string(i));\n                            break;\n                        }\n                    }\n                    break;\n                }\n\n                case value_t::object:\n                {\n                    for (const auto& element : *current->m_parent->m_data.m_value.object)\n                    {\n                        if (&element.second == current)\n                        {\n                            tokens.emplace_back(element.first.c_str());\n                            break;\n                        }\n                    }\n                    break;\n                }\n\n                case value_t::null: // LCOV_EXCL_LINE\n                case value_t::string: // LCOV_EXCL_LINE\n                case value_t::boolean: // LCOV_EXCL_LINE\n                case value_t::number_integer: // LCOV_EXCL_LINE\n                case value_t::number_unsigned: // LCOV_EXCL_LINE\n                case value_t::number_float: // LCOV_EXCL_LINE\n                case value_t::binary: // LCOV_EXCL_LINE\n                case value_t::discarded: // LCOV_EXCL_LINE\n                default:   // LCOV_EXCL_LINE\n                    break; // LCOV_EXCL_LINE\n            }\n        }\n\n        if (tokens.empty())\n        {\n            return \"\";\n        }\n\n        auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{},\n                                   [](const std::string & a, const std::string & b)\n        {\n            return concat(a, '/', detail::escape(b));\n        });\n\n        return concat('(', str, \") \", get_byte_positions(leaf_element));\n#else\n        return get_byte_positions(leaf_element);\n#endif\n    }\n\n  private:\n    /// an exception object as storage for error messages\n    std::runtime_error m;\n#if JSON_DIAGNOSTIC_POSITIONS\n    template<typename BasicJsonType>\n    static std::string get_byte_positions(const BasicJsonType* leaf_element)\n    {\n        if ((leaf_element->start_pos() != std::string::npos) && (leaf_element->end_pos() != std::string::npos))\n        {\n            return concat(\"(bytes \", std::to_string(leaf_element->start_pos()), \"-\", std::to_string(leaf_element->end_pos()), \") \");\n        }\n        return \"\";\n    }\n#else\n    template<typename BasicJsonType>\n    static std::string get_byte_positions(const BasicJsonType* leaf_element)\n    {\n        static_cast<void>(leaf_element);\n        return \"\";\n    }\n#endif\n};\n\n/// @brief exception indicating a parse error\n/// @sa https://json.nlohmann.me/api/basic_json/parse_error/\nclass parse_error : public exception\n{\n  public:\n    /*!\n    @brief create a parse error exception\n    @param[in] id_       the id of the exception\n    @param[in] pos       the position where the error occurred (or with\n                         chars_read_total=0 if the position cannot be\n                         determined)\n    @param[in] what_arg  the explanatory string\n    @return parse_error object\n    */\n    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>\n    static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)\n    {\n        const std::string w = concat(exception::name(\"parse_error\", id_), \"parse error\",\n                                     position_string(pos), \": \", exception::diagnostics(context), what_arg);\n        return {id_, pos.chars_read_total, w.c_str()};\n    }\n\n    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>\n    static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)\n    {\n        const std::string w = concat(exception::name(\"parse_error\", id_), \"parse error\",\n                                     (byte_ != 0 ? (concat(\" at byte \", std::to_string(byte_))) : \"\"),\n                                     \": \", exception::diagnostics(context), what_arg);\n        return {id_, byte_, w.c_str()};\n    }\n\n    /*!\n    @brief byte index of the parse error\n\n    The byte index of the last read character in the input file.\n\n    @note For an input with n bytes, 1 is the index of the first character and\n          n+1 is the index of the terminating null byte or the end of file.\n          This also holds true when reading a byte vector (CBOR or MessagePack).\n    */\n    const std::size_t byte;\n\n  private:\n    parse_error(int id_, std::size_t byte_, const char* what_arg)\n        : exception(id_, what_arg), byte(byte_) {}\n\n    static std::string position_string(const position_t& pos)\n    {\n        return concat(\" at line \", std::to_string(pos.lines_read + 1),\n                      \", column \", std::to_string(pos.chars_read_current_line));\n    }\n};\n\n/// @brief exception indicating errors with iterators\n/// @sa https://json.nlohmann.me/api/basic_json/invalid_iterator/\nclass invalid_iterator : public exception\n{\n  public:\n    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>\n    static invalid_iterator create(int id_, const std::string& what_arg, BasicJsonContext context)\n    {\n        const std::string w = concat(exception::name(\"invalid_iterator\", id_), exception::diagnostics(context), what_arg);\n        return {id_, w.c_str()};\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    invalid_iterator(int id_, const char* what_arg)\n        : exception(id_, what_arg) {}\n};\n\n/// @brief exception indicating executing a member function with a wrong type\n/// @sa https://json.nlohmann.me/api/basic_json/type_error/\nclass type_error : public exception\n{\n  public:\n    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>\n    static type_error create(int id_, const std::string& what_arg, BasicJsonContext context)\n    {\n        const std::string w = concat(exception::name(\"type_error\", id_), exception::diagnostics(context), what_arg);\n        return {id_, w.c_str()};\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    type_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/// @brief exception indicating access out of the defined range\n/// @sa https://json.nlohmann.me/api/basic_json/out_of_range/\nclass out_of_range : public exception\n{\n  public:\n    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>\n    static out_of_range create(int id_, const std::string& what_arg, BasicJsonContext context)\n    {\n        const std::string w = concat(exception::name(\"out_of_range\", id_), exception::diagnostics(context), what_arg);\n        return {id_, w.c_str()};\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n/// @brief exception indicating other library errors\n/// @sa https://json.nlohmann.me/api/basic_json/other_error/\nclass other_error : public exception\n{\n  public:\n    template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>\n    static other_error create(int id_, const std::string& what_arg, BasicJsonContext context)\n    {\n        const std::string w = concat(exception::name(\"other_error\", id_), exception::diagnostics(context), what_arg);\n        return {id_, w.c_str()};\n    }\n\n  private:\n    JSON_HEDLEY_NON_NULL(3)\n    other_error(int id_, const char* what_arg) : exception(id_, what_arg) {}\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n#if defined(__clang__)\n    #pragma clang diagnostic pop\n#endif\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/identity_tag.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n// dispatching helper struct\ntemplate <class T> struct identity_tag {};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/meta/std_fs.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\n#if JSON_HAS_EXPERIMENTAL_FILESYSTEM\n#include <experimental/filesystem>\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\nnamespace std_fs = std::experimental::filesystem;\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n#elif JSON_HAS_FILESYSTEM\n#include <filesystem> // NOLINT(build/c++17)\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\nnamespace std_fs = std::filesystem;\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n#endif\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_null()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be null, but is \", j.type_name()), &j));\n    }\n    n = nullptr;\n}\n\n#ifdef JSON_HAS_CPP_17\n#ifndef JSON_USE_IMPLICIT_CONVERSIONS\ntemplate<typename BasicJsonType, typename T>\nvoid from_json(const BasicJsonType& j, std::optional<T>& opt)\n{\n    if (j.is_null())\n    {\n        opt = std::nullopt;\n    }\n    else\n    {\n        opt.emplace(j.template get<T>());\n    }\n}\n\n#endif // JSON_USE_IMPLICIT_CONVERSIONS\n#endif // JSON_HAS_CPP_17\n\n// overloads for basic_json template parameters\ntemplate < typename BasicJsonType, typename ArithmeticType,\n           enable_if_t < std::is_arithmetic<ArithmeticType>::value&&\n                         !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n                         int > = 0 >\nvoid get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n\n        case value_t::null:\n        case value_t::object:\n        case value_t::array:\n        case value_t::string:\n        case value_t::boolean:\n        case value_t::binary:\n        case value_t::discarded:\n        default:\n            JSON_THROW(type_error::create(302, concat(\"type must be number, but is \", j.type_name()), &j));\n    }\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be boolean, but is \", j.type_name()), &j));\n    }\n    b = *j.template get_ptr<const typename BasicJsonType::boolean_t*>();\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be string, but is \", j.type_name()), &j));\n    }\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate <\n    typename BasicJsonType, typename StringType,\n    enable_if_t <\n        std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value\n        && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value\n        && !std::is_same<typename BasicJsonType::string_t, StringType>::value\n        && !is_json_ref<StringType>::value, int > = 0 >\ninline void from_json(const BasicJsonType& j, StringType& s)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be string, but is \", j.type_name()), &j));\n    }\n\n    s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)\n{\n    get_arithmetic_value(j, val);\n}\n\n#if !JSON_DISABLE_ENUM_SERIALIZATION\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\ninline void from_json(const BasicJsonType& j, EnumType& e)\n{\n    typename std::underlying_type<EnumType>::type val;\n    get_arithmetic_value(j, val);\n    e = static_cast<EnumType>(val);\n}\n#endif  // JSON_DISABLE_ENUM_SERIALIZATION\n\n// forward_list doesn't have an insert method\ntemplate<typename BasicJsonType, typename T, typename Allocator,\n         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>\ninline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n    l.clear();\n    std::transform(j.rbegin(), j.rend(),\n                   std::front_inserter(l), [](const BasicJsonType & i)\n    {\n        return i.template get<T>();\n    });\n}\n\n// valarray doesn't have an insert method\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>\ninline void from_json(const BasicJsonType& j, std::valarray<T>& l)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n    l.resize(j.size());\n    std::transform(j.begin(), j.end(), std::begin(l),\n                   [](const BasicJsonType & elem)\n    {\n        return elem.template get<T>();\n    });\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N>\nauto from_json(const BasicJsonType& j, T (&arr)[N])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2>\nauto from_json(const BasicJsonType& j, T (&arr)[N1][N2])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i1 = 0; i1 < N1; ++i1)\n    {\n        for (std::size_t i2 = 0; i2 < N2; ++i2)\n        {\n            arr[i1][i2] = j.at(i1).at(i2).template get<T>();\n        }\n    }\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3>\nauto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i1 = 0; i1 < N1; ++i1)\n    {\n        for (std::size_t i2 = 0; i2 < N2; ++i2)\n        {\n            for (std::size_t i3 = 0; i3 < N3; ++i3)\n            {\n                arr[i1][i2][i3] = j.at(i1).at(i2).at(i3).template get<T>();\n            }\n        }\n    }\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N1, std::size_t N2, std::size_t N3, std::size_t N4>\nauto from_json(const BasicJsonType& j, T (&arr)[N1][N2][N3][N4])  // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i1 = 0; i1 < N1; ++i1)\n    {\n        for (std::size_t i2 = 0; i2 < N2; ++i2)\n        {\n            for (std::size_t i3 = 0; i3 < N3; ++i3)\n            {\n                for (std::size_t i4 = 0; i4 < N4; ++i4)\n                {\n                    arr[i1][i2][i3][i4] = j.at(i1).at(i2).at(i3).at(i4).template get<T>();\n                }\n            }\n        }\n    }\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)\n{\n    arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();\n}\n\ntemplate<typename BasicJsonType, typename T, std::size_t N>\nauto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,\n                          priority_tag<2> /*unused*/)\n-> decltype(j.template get<T>(), void())\n{\n    for (std::size_t i = 0; i < N; ++i)\n    {\n        arr[i] = j.at(i).template get<T>();\n    }\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType,\n         enable_if_t<\n             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,\n             int> = 0>\nauto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)\n-> decltype(\n    arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),\n    j.template get<typename ConstructibleArrayType::value_type>(),\n    void())\n{\n    using std::end;\n\n    ConstructibleArrayType ret;\n    ret.reserve(j.size());\n    std::transform(j.begin(), j.end(),\n                   std::inserter(ret, end(ret)), [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n    arr = std::move(ret);\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleArrayType,\n         enable_if_t<\n             std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,\n             int> = 0>\ninline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,\n                                 priority_tag<0> /*unused*/)\n{\n    using std::end;\n\n    ConstructibleArrayType ret;\n    std::transform(\n        j.begin(), j.end(), std::inserter(ret, end(ret)),\n        [](const BasicJsonType & i)\n    {\n        // get<BasicJsonType>() returns *this, this won't call a from_json\n        // method when value_type is BasicJsonType\n        return i.template get<typename ConstructibleArrayType::value_type>();\n    });\n    arr = std::move(ret);\n}\n\ntemplate < typename BasicJsonType, typename ConstructibleArrayType,\n           enable_if_t <\n               is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&\n               !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&\n               !is_basic_json<ConstructibleArrayType>::value,\n               int > = 0 >\nauto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)\n-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}),\nj.template get<typename ConstructibleArrayType::value_type>(),\nvoid())\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n\n    from_json_array_impl(j, arr, priority_tag<3> {});\n}\n\ntemplate < typename BasicJsonType, typename T, std::size_t... Idx >\nstd::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,\n                     identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/)\n{\n    return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } };\n}\n\ntemplate < typename BasicJsonType, typename T, std::size_t N >\nauto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)\n-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}))\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n\n    return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {});\n}\n\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be binary, but is \", j.type_name()), &j));\n    }\n\n    bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();\n}\n\ntemplate<typename BasicJsonType, typename ConstructibleObjectType,\n         enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>\ninline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_object()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be object, but is \", j.type_name()), &j));\n    }\n\n    ConstructibleObjectType ret;\n    const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();\n    using value_type = typename ConstructibleObjectType::value_type;\n    std::transform(\n        inner_object->begin(), inner_object->end(),\n        std::inserter(ret, ret.begin()),\n        [](typename BasicJsonType::object_t::value_type const & p)\n    {\n        return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());\n    });\n    obj = std::move(ret);\n}\n\n// overload for arithmetic types, not chosen for basic_json template arguments\n// (BooleanType, etc..); note: Is it really necessary to provide explicit\n// overloads for boolean_t etc. in case of a custom BooleanType which is not\n// an arithmetic type?\ntemplate < typename BasicJsonType, typename ArithmeticType,\n           enable_if_t <\n               std::is_arithmetic<ArithmeticType>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&\n               !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,\n               int > = 0 >\ninline void from_json(const BasicJsonType& j, ArithmeticType& val)\n{\n    switch (static_cast<value_t>(j))\n    {\n        case value_t::number_unsigned:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_unsigned_t*>());\n            break;\n        }\n        case value_t::number_integer:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_integer_t*>());\n            break;\n        }\n        case value_t::number_float:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::number_float_t*>());\n            break;\n        }\n        case value_t::boolean:\n        {\n            val = static_cast<ArithmeticType>(*j.template get_ptr<const typename BasicJsonType::boolean_t*>());\n            break;\n        }\n\n        case value_t::null:\n        case value_t::object:\n        case value_t::array:\n        case value_t::string:\n        case value_t::binary:\n        case value_t::discarded:\n        default:\n            JSON_THROW(type_error::create(302, concat(\"type must be number, but is \", j.type_name()), &j));\n    }\n}\n\ntemplate<typename BasicJsonType, typename... Args, std::size_t... Idx>\nstd::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<Idx...> /*unused*/)\n{\n    return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);\n}\n\ntemplate<typename BasicJsonType>\nstd::tuple<> from_json_tuple_impl_base(BasicJsonType& /*unused*/, index_sequence<> /*unused*/)\n{\n    return {};\n}\n\ntemplate < typename BasicJsonType, class A1, class A2 >\nstd::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)\n{\n    return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),\n            std::forward<BasicJsonType>(j).at(1).template get<A2>()};\n}\n\ntemplate<typename BasicJsonType, typename A1, typename A2>\ninline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)\n{\n    p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});\n}\n\ntemplate<typename BasicJsonType, typename... Args>\nstd::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)\n{\n    return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});\n}\n\ntemplate<typename BasicJsonType, typename... Args>\ninline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)\n{\n    t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});\n}\n\ntemplate<typename BasicJsonType, typename TupleRelated>\nauto from_json(BasicJsonType&& j, TupleRelated&& t)\n-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}))\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n\n    return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {});\n}\n\ntemplate < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,\n           typename = enable_if_t < !std::is_constructible <\n                                        typename BasicJsonType::string_t, Key >::value >>\ninline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n    m.clear();\n    for (const auto& p : j)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", p.type_name()), &j));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\ntemplate < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,\n           typename = enable_if_t < !std::is_constructible <\n                                        typename BasicJsonType::string_t, Key >::value >>\ninline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_array()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", j.type_name()), &j));\n    }\n    m.clear();\n    for (const auto& p : j)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!p.is_array()))\n        {\n            JSON_THROW(type_error::create(302, concat(\"type must be array, but is \", p.type_name()), &j));\n        }\n        m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());\n    }\n}\n\n#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM\ntemplate<typename BasicJsonType>\ninline void from_json(const BasicJsonType& j, std_fs::path& p)\n{\n    if (JSON_HEDLEY_UNLIKELY(!j.is_string()))\n    {\n        JSON_THROW(type_error::create(302, concat(\"type must be string, but is \", j.type_name()), &j));\n    }\n    const auto& s = *j.template get_ptr<const typename BasicJsonType::string_t*>();\n#ifdef JSON_HAS_CPP_20\n    p = std_fs::path(std::u8string_view(reinterpret_cast<const char8_t*>(s.data()), s.size()));\n#else\n    p = std_fs::u8path(s); // accepts UTF-8 encoded std::string in C++17, deprecated in C++20\n#endif\n}\n#endif\n\nstruct from_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(const BasicJsonType& j, T&& val) const\n    noexcept(noexcept(from_json(j, std::forward<T>(val))))\n    -> decltype(from_json(j, std::forward<T>(val)))\n    {\n        return from_json(j, std::forward<T>(val));\n    }\n};\n\n}  // namespace detail\n\n#ifndef JSON_HAS_CPP_17\n/// namespace to hold default `from_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)\n{\n#endif\nJSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)\n    detail::static_const<detail::from_json_fn>::value;\n#ifndef JSON_HAS_CPP_17\n}  // namespace\n#endif\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/macro_scope.hpp>\n// JSON_HAS_CPP_17\n#ifdef JSON_HAS_CPP_17\n    #include <optional> // optional\n#endif\n\n#include <algorithm> // copy\n#include <iterator> // begin, end\n#include <string> // string\n#include <tuple> // tuple, get\n#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type\n#include <utility> // move, forward, declval, pair\n#include <valarray> // valarray\n#include <vector> // vector\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef> // size_t\n#include <iterator> // forward_iterator_tag\n#include <tuple> // tuple_size, get, tuple_element\n#include <utility> // move\n\n#if JSON_HAS_RANGES\n    #include <ranges> // enable_borrowed_range\n#endif\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/string_utils.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef> // size_t\n#include <string> // string, to_string\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename StringType>\nvoid int_to_string(StringType& target, std::size_t value)\n{\n    // For ADL\n    using std::to_string;\n    target = to_string(value);\n}\n\ntemplate<typename StringType>\nStringType to_string(std::size_t value)\n{\n    StringType result;\n    int_to_string(result, value);\n    return result;\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename IteratorType> class iteration_proxy_value\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    using value_type = iteration_proxy_value;\n    using pointer = value_type *;\n    using reference = value_type &;\n    using iterator_category = std::forward_iterator_tag;\n    using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;\n\n  private:\n    /// the iterator\n    IteratorType anchor{};\n    /// an index for arrays (used to create key names)\n    std::size_t array_index = 0;\n    /// last stringified array index\n    mutable std::size_t array_index_last = 0;\n    /// a string representation of the array index\n    mutable string_type array_index_str = \"0\";\n    /// an empty string (to return a reference for primitive values)\n    string_type empty_str{};\n\n  public:\n    explicit iteration_proxy_value() = default;\n    explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)\n    noexcept(std::is_nothrow_move_constructible<IteratorType>::value\n             && std::is_nothrow_default_constructible<string_type>::value)\n        : anchor(std::move(it))\n        , array_index(array_index_)\n    {}\n\n    iteration_proxy_value(iteration_proxy_value const&) = default;\n    iteration_proxy_value& operator=(iteration_proxy_value const&) = default;\n    // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions\n    iteration_proxy_value(iteration_proxy_value&&)\n    noexcept(std::is_nothrow_move_constructible<IteratorType>::value\n             && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)\n    iteration_proxy_value& operator=(iteration_proxy_value&&)\n    noexcept(std::is_nothrow_move_assignable<IteratorType>::value\n             && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)\n    ~iteration_proxy_value() = default;\n\n    /// dereference operator (needed for range-based for)\n    const iteration_proxy_value& operator*() const\n    {\n        return *this;\n    }\n\n    /// increment operator (needed for range-based for)\n    iteration_proxy_value& operator++()\n    {\n        ++anchor;\n        ++array_index;\n\n        return *this;\n    }\n\n    iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)\n    {\n        auto tmp = iteration_proxy_value(anchor, array_index);\n        ++anchor;\n        ++array_index;\n        return tmp;\n    }\n\n    /// equality operator (needed for InputIterator)\n    bool operator==(const iteration_proxy_value& o) const\n    {\n        return anchor == o.anchor;\n    }\n\n    /// inequality operator (needed for range-based for)\n    bool operator!=(const iteration_proxy_value& o) const\n    {\n        return anchor != o.anchor;\n    }\n\n    /// return key of the iterator\n    const string_type& key() const\n    {\n        JSON_ASSERT(anchor.m_object != nullptr);\n\n        switch (anchor.m_object->type())\n        {\n            // use integer array index as key\n            case value_t::array:\n            {\n                if (array_index != array_index_last)\n                {\n                    int_to_string( array_index_str, array_index );\n                    array_index_last = array_index;\n                }\n                return array_index_str;\n            }\n\n            // use key from the object\n            case value_t::object:\n                return anchor.key();\n\n            // use an empty key for all primitive types\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return empty_str;\n        }\n    }\n\n    /// return value of the iterator\n    typename IteratorType::reference value() const\n    {\n        return anchor.value();\n    }\n};\n\n/// proxy class for the items() function\ntemplate<typename IteratorType> class iteration_proxy\n{\n  private:\n    /// the container to iterate\n    typename IteratorType::pointer container = nullptr;\n\n  public:\n    explicit iteration_proxy() = default;\n\n    /// construct iteration proxy from a container\n    explicit iteration_proxy(typename IteratorType::reference cont) noexcept\n        : container(&cont) {}\n\n    iteration_proxy(iteration_proxy const&) = default;\n    iteration_proxy& operator=(iteration_proxy const&) = default;\n    iteration_proxy(iteration_proxy&&) noexcept = default;\n    iteration_proxy& operator=(iteration_proxy&&) noexcept = default;\n    ~iteration_proxy() = default;\n\n    /// return iterator begin (needed for range-based for)\n    iteration_proxy_value<IteratorType> begin() const noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container->begin());\n    }\n\n    /// return iterator end (needed for range-based for)\n    iteration_proxy_value<IteratorType> end() const noexcept\n    {\n        return iteration_proxy_value<IteratorType>(container->end());\n    }\n};\n\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate<std::size_t N, typename IteratorType, enable_if_t<N == 0, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.key())\n{\n    return i.key();\n}\n// Structured Bindings Support\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\ntemplate<std::size_t N, typename IteratorType, enable_if_t<N == 1, int> = 0>\nauto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decltype(i.value())\n{\n    return i.value();\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// The Addition to the STD Namespace is required to add\n// Structured Bindings Support to the iteration_proxy_value class\n// For further reference see https://blog.tartanllama.xyz/structured-bindings/\n// And see https://github.com/nlohmann/json/pull/1391\nnamespace std\n{\n\n#if defined(__clang__)\n    // Fix: https://github.com/nlohmann/json/issues/1401\n    #pragma clang diagnostic push\n    #pragma clang diagnostic ignored \"-Wmismatched-tags\"\n#endif\ntemplate<typename IteratorType>\nclass tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)\n    : public std::integral_constant<std::size_t, 2> {};\n\ntemplate<std::size_t N, typename IteratorType>\nclass tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp)\n{\n  public:\n    using type = decltype(\n                     get<N>(std::declval <\n                            ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));\n};\n#if defined(__clang__)\n    #pragma clang diagnostic pop\n#endif\n\n}  // namespace std\n\n#if JSON_HAS_RANGES\n    template <typename IteratorType>\n    inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;\n#endif\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/std_fs.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n//////////////////\n// constructors //\n//////////////////\n\n/*\n * Note all external_constructor<>::construct functions need to call\n * j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an\n * allocated value (e.g., a string). See bug issue\n * https://github.com/nlohmann/json/issues/2865 for more information.\n */\n\ntemplate<value_t> struct external_constructor;\n\ntemplate<>\nstruct external_constructor<value_t::boolean>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::boolean;\n        j.m_data.m_value = b;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::string>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::string;\n        j.m_data.m_value = s;\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::string;\n        j.m_data.m_value = std::move(s);\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleStringType,\n               enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,\n                             int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleStringType& str)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::string;\n        j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::binary>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::binary;\n        j.m_data.m_value = typename BasicJsonType::binary_t(b);\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::binary;\n        j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_float>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::number_float;\n        j.m_data.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_unsigned>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::number_unsigned;\n        j.m_data.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::number_integer>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::number_integer;\n        j.m_data.m_value = val;\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::array>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::array;\n        j.m_data.m_value = arr;\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::array;\n        j.m_data.m_value = std::move(arr);\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleArrayType,\n               enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,\n                             int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleArrayType& arr)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::array;\n        j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const std::vector<bool>& arr)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::array;\n        j.m_data.m_value = value_t::array;\n        j.m_data.m_value.array->reserve(arr.size());\n        for (const bool x : arr)\n        {\n            j.m_data.m_value.array->push_back(x);\n            j.set_parent(j.m_data.m_value.array->back());\n        }\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType, typename T,\n             enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\n    static void construct(BasicJsonType& j, const std::valarray<T>& arr)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::array;\n        j.m_data.m_value = value_t::array;\n        j.m_data.m_value.array->resize(arr.size());\n        if (arr.size() > 0)\n        {\n            std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());\n        }\n        j.set_parents();\n        j.assert_invariant();\n    }\n};\n\ntemplate<>\nstruct external_constructor<value_t::object>\n{\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::object;\n        j.m_data.m_value = obj;\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template<typename BasicJsonType>\n    static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n    {\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::object;\n        j.m_data.m_value = std::move(obj);\n        j.set_parents();\n        j.assert_invariant();\n    }\n\n    template < typename BasicJsonType, typename CompatibleObjectType,\n               enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >\n    static void construct(BasicJsonType& j, const CompatibleObjectType& obj)\n    {\n        using std::begin;\n        using std::end;\n\n        j.m_data.m_value.destroy(j.m_data.m_type);\n        j.m_data.m_type = value_t::object;\n        j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));\n        j.set_parents();\n        j.assert_invariant();\n    }\n};\n\n/////////////\n// to_json //\n/////////////\n\n#ifdef JSON_HAS_CPP_17\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_constructible<BasicJsonType, T>::value, int> = 0>\nvoid to_json(BasicJsonType& j, const std::optional<T>& opt)\n{\n    if (opt.has_value())\n    {\n        j = *opt;\n    }\n    else\n    {\n        j = nullptr;\n    }\n}\n#endif\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>\ninline void to_json(BasicJsonType& j, T b) noexcept\n{\n    external_constructor<value_t::boolean>::construct(j, b);\n}\n\ntemplate < typename BasicJsonType, typename BoolRef,\n           enable_if_t <\n               ((std::is_same<std::vector<bool>::reference, BoolRef>::value\n                 && !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)\n                || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value\n                    && !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,\n                                      typename BasicJsonType::boolean_t >::value))\n               && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >\ninline void to_json(BasicJsonType& j, const BoolRef& b) noexcept\n{\n    external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleString,\n         enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>\ninline void to_json(BasicJsonType& j, const CompatibleString& s)\n{\n    external_constructor<value_t::string>::construct(j, s);\n}\n\ntemplate<typename BasicJsonType>\ninline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)\n{\n    external_constructor<value_t::string>::construct(j, std::move(s));\n}\n\ntemplate<typename BasicJsonType, typename FloatType,\n         enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>\ninline void to_json(BasicJsonType& j, FloatType val) noexcept\n{\n    external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberUnsignedType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>\ninline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept\n{\n    external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));\n}\n\ntemplate<typename BasicJsonType, typename CompatibleNumberIntegerType,\n         enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>\ninline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept\n{\n    external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));\n}\n\n#if !JSON_DISABLE_ENUM_SERIALIZATION\ntemplate<typename BasicJsonType, typename EnumType,\n         enable_if_t<std::is_enum<EnumType>::value, int> = 0>\ninline void to_json(BasicJsonType& j, EnumType e) noexcept\n{\n    using underlying_type = typename std::underlying_type<EnumType>::type;\n    static constexpr value_t integral_value_t = std::is_unsigned<underlying_type>::value ? value_t::number_unsigned : value_t::number_integer;\n    external_constructor<integral_value_t>::construct(j, static_cast<underlying_type>(e));\n}\n#endif  // JSON_DISABLE_ENUM_SERIALIZATION\n\ntemplate<typename BasicJsonType>\ninline void to_json(BasicJsonType& j, const std::vector<bool>& e)\n{\n    external_constructor<value_t::array>::construct(j, e);\n}\n\ntemplate < typename BasicJsonType, typename CompatibleArrayType,\n           enable_if_t < is_compatible_array_type<BasicJsonType,\n                         CompatibleArrayType>::value&&\n                         !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&\n                         !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&\n                         !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&\n                         !is_basic_json<CompatibleArrayType>::value,\n                         int > = 0 >\ninline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate<typename BasicJsonType>\ninline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)\n{\n    external_constructor<value_t::binary>::construct(j, bin);\n}\n\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>\ninline void to_json(BasicJsonType& j, const std::valarray<T>& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate<typename BasicJsonType>\ninline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)\n{\n    external_constructor<value_t::array>::construct(j, std::move(arr));\n}\n\ntemplate < typename BasicJsonType, typename CompatibleObjectType,\n           enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >\ninline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)\n{\n    external_constructor<value_t::object>::construct(j, obj);\n}\n\ntemplate<typename BasicJsonType>\ninline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)\n{\n    external_constructor<value_t::object>::construct(j, std::move(obj));\n}\n\ntemplate <\n    typename BasicJsonType, typename T, std::size_t N,\n    enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,\n                  const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n                  int > = 0 >\ninline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n{\n    external_constructor<value_t::array>::construct(j, arr);\n}\n\ntemplate < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >\ninline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)\n{\n    j = { p.first, p.second };\n}\n\n// for https://github.com/nlohmann/json/pull/1134\ntemplate<typename BasicJsonType, typename T,\n         enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>\ninline void to_json(BasicJsonType& j, const T& b)\n{\n    j = { {b.key(), b.value()} };\n}\n\ntemplate<typename BasicJsonType, typename Tuple, std::size_t... Idx>\ninline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)\n{\n    j = { std::get<Idx>(t)... };\n}\n\ntemplate<typename BasicJsonType, typename Tuple>\ninline void to_json_tuple_impl(BasicJsonType& j, const Tuple& /*unused*/, index_sequence<> /*unused*/)\n{\n    using array_t = typename BasicJsonType::array_t;\n    j = array_t();\n}\n\ntemplate<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>\ninline void to_json(BasicJsonType& j, const T& t)\n{\n    to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});\n}\n\n#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM\ntemplate<typename BasicJsonType>\ninline void to_json(BasicJsonType& j, const std_fs::path& p)\n{\n#ifdef JSON_HAS_CPP_20\n    const std::u8string s = p.u8string();\n    j = std::string(s.begin(), s.end());\n#else\n    j = p.u8string(); // returns std::string in C++17\n#endif\n}\n#endif\n\nstruct to_json_fn\n{\n    template<typename BasicJsonType, typename T>\n    auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))\n    -> decltype(to_json(j, std::forward<T>(val)), void())\n    {\n        return to_json(j, std::forward<T>(val));\n    }\n};\n}  // namespace detail\n\n#ifndef JSON_HAS_CPP_17\n/// namespace to hold default `to_json` function\n/// to see why this is required:\n/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html\nnamespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)\n{\n#endif\nJSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)\n    detail::static_const<detail::to_json_fn>::value;\n#ifndef JSON_HAS_CPP_17\n}  // namespace\n#endif\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/meta/identity_tag.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/// @sa https://json.nlohmann.me/api/adl_serializer/\ntemplate<typename ValueType, typename>\nstruct adl_serializer\n{\n    /// @brief convert a JSON value to any value type\n    /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/\n    template<typename BasicJsonType, typename TargetType = ValueType>\n    static auto from_json(BasicJsonType && j, TargetType& val) noexcept(\n        noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())\n    {\n        ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);\n    }\n\n    /// @brief convert a JSON value to any value type\n    /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/\n    template<typename BasicJsonType, typename TargetType = ValueType>\n    static auto from_json(BasicJsonType && j) noexcept(\n    noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})))\n    -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))\n    {\n        return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {});\n    }\n\n    /// @brief convert any value type to a JSON value\n    /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/\n    template<typename BasicJsonType, typename TargetType = ValueType>\n    static auto to_json(BasicJsonType& j, TargetType && val) noexcept(\n        noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))\n    -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())\n    {\n        ::nlohmann::to_json(j, std::forward<TargetType>(val));\n    }\n};\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/byte_container_with_subtype.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstdint> // uint8_t, uint64_t\n#include <tuple> // tie\n#include <utility> // move\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/// @brief an internal type for a backed binary type\n/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/\ntemplate<typename BinaryType>\nclass byte_container_with_subtype : public BinaryType\n{\n  public:\n    using container_type = BinaryType;\n    using subtype_type = std::uint64_t;\n\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/\n    byte_container_with_subtype() noexcept(noexcept(container_type()))\n        : container_type()\n    {}\n\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/\n    byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))\n        : container_type(b)\n    {}\n\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/\n    byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))\n        : container_type(std::move(b))\n    {}\n\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/\n    byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))\n        : container_type(b)\n        , m_subtype(subtype_)\n        , m_has_subtype(true)\n    {}\n\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/\n    byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))\n        : container_type(std::move(b))\n        , m_subtype(subtype_)\n        , m_has_subtype(true)\n    {}\n\n    bool operator==(const byte_container_with_subtype& rhs) const\n    {\n        return std::tie(static_cast<const BinaryType&>(*this), m_subtype, m_has_subtype) ==\n               std::tie(static_cast<const BinaryType&>(rhs), rhs.m_subtype, rhs.m_has_subtype);\n    }\n\n    bool operator!=(const byte_container_with_subtype& rhs) const\n    {\n        return !(rhs == *this);\n    }\n\n    /// @brief sets the binary subtype\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/set_subtype/\n    void set_subtype(subtype_type subtype_) noexcept\n    {\n        m_subtype = subtype_;\n        m_has_subtype = true;\n    }\n\n    /// @brief return the binary subtype\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/subtype/\n    constexpr subtype_type subtype() const noexcept\n    {\n        return m_has_subtype ? m_subtype : static_cast<subtype_type>(-1);\n    }\n\n    /// @brief return whether the value has a subtype\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/has_subtype/\n    constexpr bool has_subtype() const noexcept\n    {\n        return m_has_subtype;\n    }\n\n    /// @brief clears the binary subtype\n    /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/clear_subtype/\n    void clear_subtype() noexcept\n    {\n        m_subtype = 0;\n        m_has_subtype = false;\n    }\n\n  private:\n    subtype_type m_subtype = 0;\n    bool m_has_subtype = false;\n};\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/conversions/from_json.hpp>\n\n// #include <nlohmann/detail/conversions/to_json.hpp>\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/hash.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstdint> // uint8_t\n#include <cstddef> // size_t\n#include <functional> // hash\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n// boost::hash_combine\ninline std::size_t combine(std::size_t seed, std::size_t h) noexcept\n{\n    seed ^= h + 0x9e3779b9 + (seed << 6U) + (seed >> 2U);\n    return seed;\n}\n\n/*!\n@brief hash a JSON value\n\nThe hash function tries to rely on std::hash where possible. Furthermore, the\ntype of the JSON value is taken into account to have different hash values for\nnull, 0, 0U, and false, etc.\n\n@tparam BasicJsonType basic_json specialization\n@param j JSON value to hash\n@return hash value of j\n*/\ntemplate<typename BasicJsonType>\nstd::size_t hash(const BasicJsonType& j)\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n\n    const auto type = static_cast<std::size_t>(j.type());\n    switch (j.type())\n    {\n        case BasicJsonType::value_t::null:\n        case BasicJsonType::value_t::discarded:\n        {\n            return combine(type, 0);\n        }\n\n        case BasicJsonType::value_t::object:\n        {\n            auto seed = combine(type, j.size());\n            for (const auto& element : j.items())\n            {\n                const auto h = std::hash<string_t> {}(element.key());\n                seed = combine(seed, h);\n                seed = combine(seed, hash(element.value()));\n            }\n            return seed;\n        }\n\n        case BasicJsonType::value_t::array:\n        {\n            auto seed = combine(type, j.size());\n            for (const auto& element : j)\n            {\n                seed = combine(seed, hash(element));\n            }\n            return seed;\n        }\n\n        case BasicJsonType::value_t::string:\n        {\n            const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::boolean:\n        {\n            const auto h = std::hash<bool> {}(j.template get<bool>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_integer:\n        {\n            const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_unsigned:\n        {\n            const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::number_float:\n        {\n            const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>());\n            return combine(type, h);\n        }\n\n        case BasicJsonType::value_t::binary:\n        {\n            auto seed = combine(type, j.get_binary().size());\n            const auto h = std::hash<bool> {}(j.get_binary().has_subtype());\n            seed = combine(seed, h);\n            seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));\n            for (const auto byte : j.get_binary())\n            {\n                seed = combine(seed, std::hash<std::uint8_t> {}(byte));\n            }\n            return seed;\n        }\n\n        default:                   // LCOV_EXCL_LINE\n            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n            return 0;              // LCOV_EXCL_LINE\n    }\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <algorithm> // generate_n\n#include <array> // array\n#include <cmath> // ldexp\n#include <cstddef> // size_t\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstdio> // snprintf\n#include <cstring> // memcpy\n#include <iterator> // back_inserter\n#include <limits> // numeric_limits\n#include <string> // char_traits, string\n#include <utility> // make_pair, move\n#include <vector> // vector\n#ifdef __cpp_lib_byteswap\n    #include <bit>  //byteswap\n#endif\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <array> // array\n#include <cstddef> // size_t\n#include <cstring> // strlen\n#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next\n#include <memory> // shared_ptr, make_shared, addressof\n#include <numeric> // accumulate\n#include <string> // string, char_traits\n#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer\n#include <utility> // pair, declval\n\n#ifndef JSON_NO_IO\n    #include <cstdio>   // FILE *\n    #include <istream>  // istream\n#endif                  // JSON_NO_IO\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/iterators/iterator_traits.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/// the supported input formats\nenum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata };\n\n////////////////////\n// input adapters //\n////////////////////\n\n#ifndef JSON_NO_IO\n/*!\nInput adapter for stdio file access. This adapter read only 1 byte and do not use any\n buffer. This adapter is a very low level adapter.\n*/\nclass file_input_adapter\n{\n  public:\n    using char_type = char;\n\n    JSON_HEDLEY_NON_NULL(2)\n    explicit file_input_adapter(std::FILE* f) noexcept\n        : m_file(f)\n    {\n        JSON_ASSERT(m_file != nullptr);\n    }\n\n    // make class move-only\n    file_input_adapter(const file_input_adapter&) = delete;\n    file_input_adapter(file_input_adapter&&) noexcept = default;\n    file_input_adapter& operator=(const file_input_adapter&) = delete;\n    file_input_adapter& operator=(file_input_adapter&&) = delete;\n    ~file_input_adapter() = default;\n\n    std::char_traits<char>::int_type get_character() noexcept\n    {\n        return std::fgetc(m_file);\n    }\n\n    // returns the number of characters successfully read\n    template<class T>\n    std::size_t get_elements(T* dest, std::size_t count = 1)\n    {\n        return fread(dest, 1, sizeof(T) * count, m_file);\n    }\n\n  private:\n    /// the file pointer to read from\n    std::FILE* m_file;\n};\n\n/*!\nInput adapter for a (caching) istream. Ignores a UFT Byte Order Mark at\nbeginning of input. Does not support changing the underlying std::streambuf\nin mid-input. Maintains underlying std::istream and std::streambuf to support\nsubsequent use of standard std::istream operations to process any input\ncharacters following those used in parsing the JSON input.  Clears the\nstd::istream flags; any input errors (e.g., EOF) will be detected by the first\nsubsequent call for input from the std::istream.\n*/\nclass input_stream_adapter\n{\n  public:\n    using char_type = char;\n\n    ~input_stream_adapter()\n    {\n        // clear stream flags; we use underlying streambuf I/O, do not\n        // maintain ifstream flags, except eof\n        if (is != nullptr)\n        {\n            is->clear(is->rdstate() & std::ios::eofbit);\n        }\n    }\n\n    explicit input_stream_adapter(std::istream& i)\n        : is(&i), sb(i.rdbuf())\n    {}\n\n    // delete because of pointer members\n    input_stream_adapter(const input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&) = delete;\n    input_stream_adapter& operator=(input_stream_adapter&&) = delete;\n\n    input_stream_adapter(input_stream_adapter&& rhs) noexcept\n        : is(rhs.is), sb(rhs.sb)\n    {\n        rhs.is = nullptr;\n        rhs.sb = nullptr;\n    }\n\n    // std::istream/std::streambuf use std::char_traits<char>::to_int_type, to\n    // ensure that std::char_traits<char>::eof() and the character 0xFF do not\n    // end up as the same value, e.g. 0xFFFFFFFF.\n    std::char_traits<char>::int_type get_character()\n    {\n        auto res = sb->sbumpc();\n        // set eof manually, as we don't use the istream interface.\n        if (JSON_HEDLEY_UNLIKELY(res == std::char_traits<char>::eof()))\n        {\n            is->clear(is->rdstate() | std::ios::eofbit);\n        }\n        return res;\n    }\n\n    template<class T>\n    std::size_t get_elements(T* dest, std::size_t count = 1)\n    {\n        auto res = static_cast<std::size_t>(sb->sgetn(reinterpret_cast<char*>(dest), static_cast<std::streamsize>(count * sizeof(T))));\n        if (JSON_HEDLEY_UNLIKELY(res < count * sizeof(T)))\n        {\n            is->clear(is->rdstate() | std::ios::eofbit);\n        }\n        return res;\n    }\n\n  private:\n    /// the associated input stream\n    std::istream* is = nullptr;\n    std::streambuf* sb = nullptr;\n};\n#endif  // JSON_NO_IO\n\n// General-purpose iterator-based adapter. It might not be as fast as\n// theoretically possible for some containers, but it is extremely versatile.\ntemplate<typename IteratorType>\nclass iterator_input_adapter\n{\n  public:\n    using char_type = typename std::iterator_traits<IteratorType>::value_type;\n\n    iterator_input_adapter(IteratorType first, IteratorType last)\n        : current(std::move(first)), end(std::move(last))\n    {}\n\n    typename char_traits<char_type>::int_type get_character()\n    {\n        if (JSON_HEDLEY_LIKELY(current != end))\n        {\n            auto result = char_traits<char_type>::to_int_type(*current);\n            std::advance(current, 1);\n            return result;\n        }\n\n        return char_traits<char_type>::eof();\n    }\n\n    // for general iterators, we cannot really do something better than falling back to processing the range one-by-one\n    template<class T>\n    std::size_t get_elements(T* dest, std::size_t count = 1)\n    {\n        auto* ptr = reinterpret_cast<char*>(dest);\n        for (std::size_t read_index = 0; read_index < count * sizeof(T); ++read_index)\n        {\n            if (JSON_HEDLEY_LIKELY(current != end))\n            {\n                ptr[read_index] = static_cast<char>(*current);\n                std::advance(current, 1);\n            }\n            else\n            {\n                return read_index;\n            }\n        }\n        return count * sizeof(T);\n    }\n\n  private:\n    IteratorType current;\n    IteratorType end;\n\n    template<typename BaseInputAdapter, size_t T>\n    friend struct wide_string_input_helper;\n\n    bool empty() const\n    {\n        return current == end;\n    }\n};\n\ntemplate<typename BaseInputAdapter, size_t T>\nstruct wide_string_input_helper;\n\ntemplate<typename BaseInputAdapter>\nstruct wide_string_input_helper<BaseInputAdapter, 4>\n{\n    // UTF-32\n    static void fill_buffer(BaseInputAdapter& input,\n                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n                            size_t& utf8_bytes_index,\n                            size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (JSON_HEDLEY_UNLIKELY(input.empty()))\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = input.get_character();\n\n            // UTF-32 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u) & 0x1Fu));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 2;\n            }\n            else if (wc <= 0xFFFF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u) & 0x0Fu));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 3;\n            }\n            else if (wc <= 0x10FFFF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((static_cast<unsigned int>(wc) >> 18u) & 0x07u));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 12u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 4;\n            }\n            else\n            {\n                // unknown character\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n        }\n    }\n};\n\ntemplate<typename BaseInputAdapter>\nstruct wide_string_input_helper<BaseInputAdapter, 2>\n{\n    // UTF-16\n    static void fill_buffer(BaseInputAdapter& input,\n                            std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,\n                            size_t& utf8_bytes_index,\n                            size_t& utf8_bytes_filled)\n    {\n        utf8_bytes_index = 0;\n\n        if (JSON_HEDLEY_UNLIKELY(input.empty()))\n        {\n            utf8_bytes[0] = std::char_traits<char>::eof();\n            utf8_bytes_filled = 1;\n        }\n        else\n        {\n            // get the current character\n            const auto wc = input.get_character();\n\n            // UTF-16 to UTF-8 encoding\n            if (wc < 0x80)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                utf8_bytes_filled = 1;\n            }\n            else if (wc <= 0x7FF)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((static_cast<unsigned int>(wc) >> 6u)));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 2;\n            }\n            else if (0xD800 > wc || wc >= 0xE000)\n            {\n                utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((static_cast<unsigned int>(wc) >> 12u)));\n                utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((static_cast<unsigned int>(wc) >> 6u) & 0x3Fu));\n                utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (static_cast<unsigned int>(wc) & 0x3Fu));\n                utf8_bytes_filled = 3;\n            }\n            else\n            {\n                if (JSON_HEDLEY_UNLIKELY(!input.empty()))\n                {\n                    const auto wc2 = static_cast<unsigned int>(input.get_character());\n                    const auto charcode = 0x10000u + (((static_cast<unsigned int>(wc) & 0x3FFu) << 10u) | (wc2 & 0x3FFu));\n                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));\n                    utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));\n                    utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));\n                    utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));\n                    utf8_bytes_filled = 4;\n                }\n                else\n                {\n                    utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);\n                    utf8_bytes_filled = 1;\n                }\n            }\n        }\n    }\n};\n\n// Wraps another input adapter to convert wide character types into individual bytes.\ntemplate<typename BaseInputAdapter, typename WideCharType>\nclass wide_string_input_adapter\n{\n  public:\n    using char_type = char;\n\n    wide_string_input_adapter(BaseInputAdapter base)\n        : base_adapter(base) {}\n\n    typename std::char_traits<char>::int_type get_character() noexcept\n    {\n        // check if buffer needs to be filled\n        if (utf8_bytes_index == utf8_bytes_filled)\n        {\n            fill_buffer<sizeof(WideCharType)>();\n\n            JSON_ASSERT(utf8_bytes_filled > 0);\n            JSON_ASSERT(utf8_bytes_index == 0);\n        }\n\n        // use buffer\n        JSON_ASSERT(utf8_bytes_filled > 0);\n        JSON_ASSERT(utf8_bytes_index < utf8_bytes_filled);\n        return utf8_bytes[utf8_bytes_index++];\n    }\n\n    // parsing binary with wchar doesn't make sense, but since the parsing mode can be runtime, we need something here\n    template<class T>\n    std::size_t get_elements(T* /*dest*/, std::size_t /*count*/ = 1)\n    {\n        JSON_THROW(parse_error::create(112, 1, \"wide string type cannot be interpreted as binary data\", nullptr));\n    }\n\n  private:\n    BaseInputAdapter base_adapter;\n\n    template<size_t T>\n    void fill_buffer()\n    {\n        wide_string_input_helper<BaseInputAdapter, T>::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled);\n    }\n\n    /// a buffer for UTF-8 bytes\n    std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};\n\n    /// index to the utf8_codes array for the next valid byte\n    std::size_t utf8_bytes_index = 0;\n    /// number of valid bytes in the utf8_codes array\n    std::size_t utf8_bytes_filled = 0;\n};\n\ntemplate<typename IteratorType, typename Enable = void>\nstruct iterator_input_adapter_factory\n{\n    using iterator_type = IteratorType;\n    using char_type = typename std::iterator_traits<iterator_type>::value_type;\n    using adapter_type = iterator_input_adapter<iterator_type>;\n\n    static adapter_type create(IteratorType first, IteratorType last)\n    {\n        return adapter_type(std::move(first), std::move(last));\n    }\n};\n\ntemplate<typename T>\nstruct is_iterator_of_multibyte\n{\n    using value_type = typename std::iterator_traits<T>::value_type;\n    enum\n    {\n        value = sizeof(value_type) > 1\n    };\n};\n\ntemplate<typename IteratorType>\nstruct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>::value>>\n{\n    using iterator_type = IteratorType;\n    using char_type = typename std::iterator_traits<iterator_type>::value_type;\n    using base_adapter_type = iterator_input_adapter<iterator_type>;\n    using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>;\n\n    static adapter_type create(IteratorType first, IteratorType last)\n    {\n        return adapter_type(base_adapter_type(std::move(first), std::move(last)));\n    }\n};\n\n// General purpose iterator-based input\ntemplate<typename IteratorType>\ntypename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last)\n{\n    using factory_type = iterator_input_adapter_factory<IteratorType>;\n    return factory_type::create(first, last);\n}\n\n// Convenience shorthand from container to iterator\n// Enables ADL on begin(container) and end(container)\n// Encloses the using declarations in namespace for not to leak them to outside scope\n\nnamespace container_input_adapter_factory_impl\n{\n\nusing std::begin;\nusing std::end;\n\ntemplate<typename ContainerType, typename Enable = void>\nstruct container_input_adapter_factory {};\n\ntemplate<typename ContainerType>\nstruct container_input_adapter_factory< ContainerType,\n       void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>\n       {\n           using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));\n\n           static adapter_type create(const ContainerType& container)\n{\n    return input_adapter(begin(container), end(container));\n}\n       };\n\n}  // namespace container_input_adapter_factory_impl\n\ntemplate<typename ContainerType>\ntypename container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::adapter_type input_adapter(const ContainerType& container)\n{\n    return container_input_adapter_factory_impl::container_input_adapter_factory<ContainerType>::create(container);\n}\n\n// specialization for std::string\nusing string_input_adapter_type = decltype(input_adapter(std::declval<std::string>()));\n\n#ifndef JSON_NO_IO\n// Special cases with fast paths\ninline file_input_adapter input_adapter(std::FILE* file)\n{\n    if (file == nullptr)\n    {\n        JSON_THROW(parse_error::create(101, 0, \"attempting to parse an empty input; check that your input string or stream contains the expected JSON\", nullptr));\n    }\n    return file_input_adapter(file);\n}\n\ninline input_stream_adapter input_adapter(std::istream& stream)\n{\n    return input_stream_adapter(stream);\n}\n\ninline input_stream_adapter input_adapter(std::istream&& stream)\n{\n    return input_stream_adapter(stream);\n}\n#endif  // JSON_NO_IO\n\nusing contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));\n\n// Null-delimited strings, and the like.\ntemplate < typename CharT,\n           typename std::enable_if <\n               std::is_pointer<CharT>::value&&\n               !std::is_array<CharT>::value&&\n               std::is_integral<typename std::remove_pointer<CharT>::type>::value&&\n               sizeof(typename std::remove_pointer<CharT>::type) == 1,\n               int >::type = 0 >\ncontiguous_bytes_input_adapter input_adapter(CharT b)\n{\n    if (b == nullptr)\n    {\n        JSON_THROW(parse_error::create(101, 0, \"attempting to parse an empty input; check that your input string or stream contains the expected JSON\", nullptr));\n    }\n    auto length = std::strlen(reinterpret_cast<const char*>(b));\n    const auto* ptr = reinterpret_cast<const char*>(b);\n    return input_adapter(ptr, ptr + length); // cppcheck-suppress[nullPointerArithmeticRedundantCheck]\n}\n\ntemplate<typename T, std::size_t N>\nauto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n{\n    return input_adapter(array, array + N);\n}\n\n// This class only handles inputs of input_buffer_adapter type.\n// It's required so that expressions like {ptr, len} can be implicitly cast\n// to the correct adapter.\nclass span_input_adapter\n{\n  public:\n    template < typename CharT,\n               typename std::enable_if <\n                   std::is_pointer<CharT>::value&&\n                   std::is_integral<typename std::remove_pointer<CharT>::type>::value&&\n                   sizeof(typename std::remove_pointer<CharT>::type) == 1,\n                   int >::type = 0 >\n    span_input_adapter(CharT b, std::size_t l)\n        : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {}\n\n    template<class IteratorType,\n             typename std::enable_if<\n                 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,\n                 int>::type = 0>\n    span_input_adapter(IteratorType first, IteratorType last)\n        : ia(input_adapter(first, last)) {}\n\n    contiguous_bytes_input_adapter&& get()\n    {\n        return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)\n    }\n\n  private:\n    contiguous_bytes_input_adapter ia;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef>\n#include <string> // string\n#include <type_traits> // enable_if_t\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <array> // array\n#include <clocale> // localeconv\n#include <cstddef> // size_t\n#include <cstdio> // snprintf\n#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull\n#include <initializer_list> // initializer_list\n#include <string> // char_traits, string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/position_t.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n///////////\n// lexer //\n///////////\n\ntemplate<typename BasicJsonType>\nclass lexer_base\n{\n  public:\n    /// token types for the parser\n    enum class token_type\n    {\n        uninitialized,    ///< indicating the scanner is uninitialized\n        literal_true,     ///< the `true` literal\n        literal_false,    ///< the `false` literal\n        literal_null,     ///< the `null` literal\n        value_string,     ///< a string -- use get_string() for actual value\n        value_unsigned,   ///< an unsigned integer -- use get_number_unsigned() for actual value\n        value_integer,    ///< a signed integer -- use get_number_integer() for actual value\n        value_float,      ///< an floating point number -- use get_number_float() for actual value\n        begin_array,      ///< the character for array begin `[`\n        begin_object,     ///< the character for object begin `{`\n        end_array,        ///< the character for array end `]`\n        end_object,       ///< the character for object end `}`\n        name_separator,   ///< the name separator `:`\n        value_separator,  ///< the value separator `,`\n        parse_error,      ///< indicating a parse error\n        end_of_input,     ///< indicating the end of the input buffer\n        literal_or_value  ///< a literal or the begin of a value (only for diagnostics)\n    };\n\n    /// return name of values of type token_type (only used for errors)\n    JSON_HEDLEY_RETURNS_NON_NULL\n    JSON_HEDLEY_CONST\n    static const char* token_type_name(const token_type t) noexcept\n    {\n        switch (t)\n        {\n            case token_type::uninitialized:\n                return \"<uninitialized>\";\n            case token_type::literal_true:\n                return \"true literal\";\n            case token_type::literal_false:\n                return \"false literal\";\n            case token_type::literal_null:\n                return \"null literal\";\n            case token_type::value_string:\n                return \"string literal\";\n            case token_type::value_unsigned:\n            case token_type::value_integer:\n            case token_type::value_float:\n                return \"number literal\";\n            case token_type::begin_array:\n                return \"'['\";\n            case token_type::begin_object:\n                return \"'{'\";\n            case token_type::end_array:\n                return \"']'\";\n            case token_type::end_object:\n                return \"'}'\";\n            case token_type::name_separator:\n                return \"':'\";\n            case token_type::value_separator:\n                return \"','\";\n            case token_type::parse_error:\n                return \"<parse error>\";\n            case token_type::end_of_input:\n                return \"end of input\";\n            case token_type::literal_or_value:\n                return \"'[', '{', or a literal\";\n            // LCOV_EXCL_START\n            default: // catch non-enum values\n                return \"unknown token\";\n                // LCOV_EXCL_STOP\n        }\n    }\n};\n/*!\n@brief lexical analysis\n\nThis class organizes the lexical analysis during JSON deserialization.\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass lexer : public lexer_base<BasicJsonType>\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using char_type = typename InputAdapterType::char_type;\n    using char_int_type = typename char_traits<char_type>::int_type;\n\n  public:\n    using token_type = typename lexer_base<BasicJsonType>::token_type;\n\n    explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept\n        : ia(std::move(adapter))\n        , ignore_comments(ignore_comments_)\n        , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))\n    {}\n\n    // delete because of pointer members\n    lexer(const lexer&) = delete;\n    lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    lexer& operator=(lexer&) = delete;\n    lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~lexer() = default;\n\n  private:\n    /////////////////////\n    // locales\n    /////////////////////\n\n    /// return the locale-dependent decimal point\n    JSON_HEDLEY_PURE\n    static char get_decimal_point() noexcept\n    {\n        const auto* loc = localeconv();\n        JSON_ASSERT(loc != nullptr);\n        return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);\n    }\n\n    /////////////////////\n    // scan functions\n    /////////////////////\n\n    /*!\n    @brief get codepoint from 4 hex characters following `\\u`\n\n    For input \"\\u c1 c2 c3 c4\" the codepoint is:\n      (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4\n    = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0)\n\n    Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f'\n    must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The\n    conversion is done by subtracting the offset (0x30, 0x37, and 0x57)\n    between the ASCII value of the character and the desired integer value.\n\n    @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or\n            non-hex character)\n    */\n    int get_codepoint()\n    {\n        // this function only makes sense after reading `\\u`\n        JSON_ASSERT(current == 'u');\n        int codepoint = 0;\n\n        const auto factors = { 12u, 8u, 4u, 0u };\n        for (const auto factor : factors)\n        {\n            get();\n\n            if (current >= '0' && current <= '9')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);\n            }\n            else if (current >= 'A' && current <= 'F')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);\n            }\n            else if (current >= 'a' && current <= 'f')\n            {\n                codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);\n            }\n            else\n            {\n                return -1;\n            }\n        }\n\n        JSON_ASSERT(0x0000 <= codepoint && codepoint <= 0xFFFF);\n        return codepoint;\n    }\n\n    /*!\n    @brief check if the next byte(s) are inside a given range\n\n    Adds the current byte and, for each passed range, reads a new byte and\n    checks if it is inside the range. If a violation was detected, set up an\n    error message and return false. Otherwise, return true.\n\n    @param[in] ranges  list of integers; interpreted as list of pairs of\n                       inclusive lower and upper bound, respectively\n\n    @pre The passed list @a ranges must have 2, 4, or 6 elements; that is,\n         1, 2, or 3 pairs. This precondition is enforced by an assertion.\n\n    @return true if and only if no range violation was detected\n    */\n    bool next_byte_in_range(std::initializer_list<char_int_type> ranges)\n    {\n        JSON_ASSERT(ranges.size() == 2 || ranges.size() == 4 || ranges.size() == 6);\n        add(current);\n\n        for (auto range = ranges.begin(); range != ranges.end(); ++range)\n        {\n            get();\n            if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions)\n            {\n                add(current);\n            }\n            else\n            {\n                error_message = \"invalid string: ill-formed UTF-8 byte\";\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief scan a string literal\n\n    This function scans a string according to Sect. 7 of RFC 8259. While\n    scanning, bytes are escaped and copied into buffer token_buffer. Then the\n    function returns successfully, token_buffer is *not* null-terminated (as it\n    may contain \\0 bytes), and token_buffer.size() is the number of bytes in the\n    string.\n\n    @return token_type::value_string if string could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note In case of errors, variable error_message contains a textual\n          description.\n    */\n    token_type scan_string()\n    {\n        // reset token_buffer (ignore opening quote)\n        reset();\n\n        // we entered the function by reading an open quote\n        JSON_ASSERT(current == '\\\"');\n\n        while (true)\n        {\n            // get next character\n            switch (get())\n            {\n                // end of file while parsing string\n                case char_traits<char_type>::eof():\n                {\n                    error_message = \"invalid string: missing closing quote\";\n                    return token_type::parse_error;\n                }\n\n                // closing quote\n                case '\\\"':\n                {\n                    return token_type::value_string;\n                }\n\n                // escapes\n                case '\\\\':\n                {\n                    switch (get())\n                    {\n                        // quotation mark\n                        case '\\\"':\n                            add('\\\"');\n                            break;\n                        // reverse solidus\n                        case '\\\\':\n                            add('\\\\');\n                            break;\n                        // solidus\n                        case '/':\n                            add('/');\n                            break;\n                        // backspace\n                        case 'b':\n                            add('\\b');\n                            break;\n                        // form feed\n                        case 'f':\n                            add('\\f');\n                            break;\n                        // line feed\n                        case 'n':\n                            add('\\n');\n                            break;\n                        // carriage return\n                        case 'r':\n                            add('\\r');\n                            break;\n                        // tab\n                        case 't':\n                            add('\\t');\n                            break;\n\n                        // unicode escapes\n                        case 'u':\n                        {\n                            const int codepoint1 = get_codepoint();\n                            int codepoint = codepoint1; // start with codepoint1\n\n                            if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))\n                            {\n                                error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                return token_type::parse_error;\n                            }\n\n                            // check if code point is a high surrogate\n                            if (0xD800 <= codepoint1 && codepoint1 <= 0xDBFF)\n                            {\n                                // expect next \\uxxxx entry\n                                if (JSON_HEDLEY_LIKELY(get() == '\\\\' && get() == 'u'))\n                                {\n                                    const int codepoint2 = get_codepoint();\n\n                                    if (JSON_HEDLEY_UNLIKELY(codepoint2 == -1))\n                                    {\n                                        error_message = \"invalid string: '\\\\u' must be followed by 4 hex digits\";\n                                        return token_type::parse_error;\n                                    }\n\n                                    // check if codepoint2 is a low surrogate\n                                    if (JSON_HEDLEY_LIKELY(0xDC00 <= codepoint2 && codepoint2 <= 0xDFFF))\n                                    {\n                                        // overwrite codepoint\n                                        codepoint = static_cast<int>(\n                                                        // high surrogate occupies the most significant 22 bits\n                                                        (static_cast<unsigned int>(codepoint1) << 10u)\n                                                        // low surrogate occupies the least significant 15 bits\n                                                        + static_cast<unsigned int>(codepoint2)\n                                                        // there is still the 0xD800, 0xDC00 and 0x10000 noise\n                                                        // in the result, so we have to subtract with:\n                                                        // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00\n                                                        - 0x35FDC00u);\n                                    }\n                                    else\n                                    {\n                                        error_message = \"invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF\";\n                                        return token_type::parse_error;\n                                    }\n                                }\n                                else\n                                {\n                                    error_message = \"invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n                            else\n                            {\n                                if (JSON_HEDLEY_UNLIKELY(0xDC00 <= codepoint1 && codepoint1 <= 0xDFFF))\n                                {\n                                    error_message = \"invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF\";\n                                    return token_type::parse_error;\n                                }\n                            }\n\n                            // result of the above calculation yields a proper codepoint\n                            JSON_ASSERT(0x00 <= codepoint && codepoint <= 0x10FFFF);\n\n                            // translate codepoint into bytes\n                            if (codepoint < 0x80)\n                            {\n                                // 1-byte characters: 0xxxxxxx (ASCII)\n                                add(static_cast<char_int_type>(codepoint));\n                            }\n                            else if (codepoint <= 0x7FF)\n                            {\n                                // 2-byte characters: 110xxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n                            else if (codepoint <= 0xFFFF)\n                            {\n                                // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n                            else\n                            {\n                                // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx\n                                add(static_cast<char_int_type>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));\n                                add(static_cast<char_int_type>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));\n                            }\n\n                            break;\n                        }\n\n                        // other characters after escape\n                        default:\n                            error_message = \"invalid string: forbidden character after backslash\";\n                            return token_type::parse_error;\n                    }\n\n                    break;\n                }\n\n                // invalid control characters\n                case 0x00:\n                {\n                    error_message = \"invalid string: control character U+0000 (NUL) must be escaped to \\\\u0000\";\n                    return token_type::parse_error;\n                }\n\n                case 0x01:\n                {\n                    error_message = \"invalid string: control character U+0001 (SOH) must be escaped to \\\\u0001\";\n                    return token_type::parse_error;\n                }\n\n                case 0x02:\n                {\n                    error_message = \"invalid string: control character U+0002 (STX) must be escaped to \\\\u0002\";\n                    return token_type::parse_error;\n                }\n\n                case 0x03:\n                {\n                    error_message = \"invalid string: control character U+0003 (ETX) must be escaped to \\\\u0003\";\n                    return token_type::parse_error;\n                }\n\n                case 0x04:\n                {\n                    error_message = \"invalid string: control character U+0004 (EOT) must be escaped to \\\\u0004\";\n                    return token_type::parse_error;\n                }\n\n                case 0x05:\n                {\n                    error_message = \"invalid string: control character U+0005 (ENQ) must be escaped to \\\\u0005\";\n                    return token_type::parse_error;\n                }\n\n                case 0x06:\n                {\n                    error_message = \"invalid string: control character U+0006 (ACK) must be escaped to \\\\u0006\";\n                    return token_type::parse_error;\n                }\n\n                case 0x07:\n                {\n                    error_message = \"invalid string: control character U+0007 (BEL) must be escaped to \\\\u0007\";\n                    return token_type::parse_error;\n                }\n\n                case 0x08:\n                {\n                    error_message = \"invalid string: control character U+0008 (BS) must be escaped to \\\\u0008 or \\\\b\";\n                    return token_type::parse_error;\n                }\n\n                case 0x09:\n                {\n                    error_message = \"invalid string: control character U+0009 (HT) must be escaped to \\\\u0009 or \\\\t\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0A:\n                {\n                    error_message = \"invalid string: control character U+000A (LF) must be escaped to \\\\u000A or \\\\n\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0B:\n                {\n                    error_message = \"invalid string: control character U+000B (VT) must be escaped to \\\\u000B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0C:\n                {\n                    error_message = \"invalid string: control character U+000C (FF) must be escaped to \\\\u000C or \\\\f\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0D:\n                {\n                    error_message = \"invalid string: control character U+000D (CR) must be escaped to \\\\u000D or \\\\r\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0E:\n                {\n                    error_message = \"invalid string: control character U+000E (SO) must be escaped to \\\\u000E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x0F:\n                {\n                    error_message = \"invalid string: control character U+000F (SI) must be escaped to \\\\u000F\";\n                    return token_type::parse_error;\n                }\n\n                case 0x10:\n                {\n                    error_message = \"invalid string: control character U+0010 (DLE) must be escaped to \\\\u0010\";\n                    return token_type::parse_error;\n                }\n\n                case 0x11:\n                {\n                    error_message = \"invalid string: control character U+0011 (DC1) must be escaped to \\\\u0011\";\n                    return token_type::parse_error;\n                }\n\n                case 0x12:\n                {\n                    error_message = \"invalid string: control character U+0012 (DC2) must be escaped to \\\\u0012\";\n                    return token_type::parse_error;\n                }\n\n                case 0x13:\n                {\n                    error_message = \"invalid string: control character U+0013 (DC3) must be escaped to \\\\u0013\";\n                    return token_type::parse_error;\n                }\n\n                case 0x14:\n                {\n                    error_message = \"invalid string: control character U+0014 (DC4) must be escaped to \\\\u0014\";\n                    return token_type::parse_error;\n                }\n\n                case 0x15:\n                {\n                    error_message = \"invalid string: control character U+0015 (NAK) must be escaped to \\\\u0015\";\n                    return token_type::parse_error;\n                }\n\n                case 0x16:\n                {\n                    error_message = \"invalid string: control character U+0016 (SYN) must be escaped to \\\\u0016\";\n                    return token_type::parse_error;\n                }\n\n                case 0x17:\n                {\n                    error_message = \"invalid string: control character U+0017 (ETB) must be escaped to \\\\u0017\";\n                    return token_type::parse_error;\n                }\n\n                case 0x18:\n                {\n                    error_message = \"invalid string: control character U+0018 (CAN) must be escaped to \\\\u0018\";\n                    return token_type::parse_error;\n                }\n\n                case 0x19:\n                {\n                    error_message = \"invalid string: control character U+0019 (EM) must be escaped to \\\\u0019\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1A:\n                {\n                    error_message = \"invalid string: control character U+001A (SUB) must be escaped to \\\\u001A\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1B:\n                {\n                    error_message = \"invalid string: control character U+001B (ESC) must be escaped to \\\\u001B\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1C:\n                {\n                    error_message = \"invalid string: control character U+001C (FS) must be escaped to \\\\u001C\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1D:\n                {\n                    error_message = \"invalid string: control character U+001D (GS) must be escaped to \\\\u001D\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1E:\n                {\n                    error_message = \"invalid string: control character U+001E (RS) must be escaped to \\\\u001E\";\n                    return token_type::parse_error;\n                }\n\n                case 0x1F:\n                {\n                    error_message = \"invalid string: control character U+001F (US) must be escaped to \\\\u001F\";\n                    return token_type::parse_error;\n                }\n\n                // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace))\n                case 0x20:\n                case 0x21:\n                case 0x23:\n                case 0x24:\n                case 0x25:\n                case 0x26:\n                case 0x27:\n                case 0x28:\n                case 0x29:\n                case 0x2A:\n                case 0x2B:\n                case 0x2C:\n                case 0x2D:\n                case 0x2E:\n                case 0x2F:\n                case 0x30:\n                case 0x31:\n                case 0x32:\n                case 0x33:\n                case 0x34:\n                case 0x35:\n                case 0x36:\n                case 0x37:\n                case 0x38:\n                case 0x39:\n                case 0x3A:\n                case 0x3B:\n                case 0x3C:\n                case 0x3D:\n                case 0x3E:\n                case 0x3F:\n                case 0x40:\n                case 0x41:\n                case 0x42:\n                case 0x43:\n                case 0x44:\n                case 0x45:\n                case 0x46:\n                case 0x47:\n                case 0x48:\n                case 0x49:\n                case 0x4A:\n                case 0x4B:\n                case 0x4C:\n                case 0x4D:\n                case 0x4E:\n                case 0x4F:\n                case 0x50:\n                case 0x51:\n                case 0x52:\n                case 0x53:\n                case 0x54:\n                case 0x55:\n                case 0x56:\n                case 0x57:\n                case 0x58:\n                case 0x59:\n                case 0x5A:\n                case 0x5B:\n                case 0x5D:\n                case 0x5E:\n                case 0x5F:\n                case 0x60:\n                case 0x61:\n                case 0x62:\n                case 0x63:\n                case 0x64:\n                case 0x65:\n                case 0x66:\n                case 0x67:\n                case 0x68:\n                case 0x69:\n                case 0x6A:\n                case 0x6B:\n                case 0x6C:\n                case 0x6D:\n                case 0x6E:\n                case 0x6F:\n                case 0x70:\n                case 0x71:\n                case 0x72:\n                case 0x73:\n                case 0x74:\n                case 0x75:\n                case 0x76:\n                case 0x77:\n                case 0x78:\n                case 0x79:\n                case 0x7A:\n                case 0x7B:\n                case 0x7C:\n                case 0x7D:\n                case 0x7E:\n                case 0x7F:\n                {\n                    add(current);\n                    break;\n                }\n\n                // U+0080..U+07FF: bytes C2..DF 80..BF\n                case 0xC2:\n                case 0xC3:\n                case 0xC4:\n                case 0xC5:\n                case 0xC6:\n                case 0xC7:\n                case 0xC8:\n                case 0xC9:\n                case 0xCA:\n                case 0xCB:\n                case 0xCC:\n                case 0xCD:\n                case 0xCE:\n                case 0xCF:\n                case 0xD0:\n                case 0xD1:\n                case 0xD2:\n                case 0xD3:\n                case 0xD4:\n                case 0xD5:\n                case 0xD6:\n                case 0xD7:\n                case 0xD8:\n                case 0xD9:\n                case 0xDA:\n                case 0xDB:\n                case 0xDC:\n                case 0xDD:\n                case 0xDE:\n                case 0xDF:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!next_byte_in_range({0x80, 0xBF})))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+0800..U+0FFF: bytes E0 A0..BF 80..BF\n                case 0xE0:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF\n                // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF\n                case 0xE1:\n                case 0xE2:\n                case 0xE3:\n                case 0xE4:\n                case 0xE5:\n                case 0xE6:\n                case 0xE7:\n                case 0xE8:\n                case 0xE9:\n                case 0xEA:\n                case 0xEB:\n                case 0xEC:\n                case 0xEE:\n                case 0xEF:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+D000..U+D7FF: bytes ED 80..9F 80..BF\n                case 0xED:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x9F, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF\n                case 0xF0:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF\n                case 0xF1:\n                case 0xF2:\n                case 0xF3:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF\n                case 0xF4:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!(next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF}))))\n                    {\n                        return token_type::parse_error;\n                    }\n                    break;\n                }\n\n                // remaining bytes (80..C1 and F5..FF) are ill-formed\n                default:\n                {\n                    error_message = \"invalid string: ill-formed UTF-8 byte\";\n                    return token_type::parse_error;\n                }\n            }\n        }\n    }\n\n    /*!\n     * @brief scan a comment\n     * @return whether comment could be scanned successfully\n     */\n    bool scan_comment()\n    {\n        switch (get())\n        {\n            // single-line comments skip input until a newline or EOF is read\n            case '/':\n            {\n                while (true)\n                {\n                    switch (get())\n                    {\n                        case '\\n':\n                        case '\\r':\n                        case char_traits<char_type>::eof():\n                        case '\\0':\n                            return true;\n\n                        default:\n                            break;\n                    }\n                }\n            }\n\n            // multi-line comments skip input until */ is read\n            case '*':\n            {\n                while (true)\n                {\n                    switch (get())\n                    {\n                        case char_traits<char_type>::eof():\n                        case '\\0':\n                        {\n                            error_message = \"invalid comment; missing closing '*/'\";\n                            return false;\n                        }\n\n                        case '*':\n                        {\n                            switch (get())\n                            {\n                                case '/':\n                                    return true;\n\n                                default:\n                                {\n                                    unget();\n                                    continue;\n                                }\n                            }\n                        }\n\n                        default:\n                            continue;\n                    }\n                }\n            }\n\n            // unexpected character after reading '/'\n            default:\n            {\n                error_message = \"invalid comment; expecting '/' or '*' after '/'\";\n                return false;\n            }\n        }\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(float& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtof(str, endptr);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtod(str, endptr);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    static void strtof(long double& f, const char* str, char** endptr) noexcept\n    {\n        f = std::strtold(str, endptr);\n    }\n\n    /*!\n    @brief scan a number literal\n\n    This function scans a string according to Sect. 6 of RFC 8259.\n\n    The function is realized with a deterministic finite state machine derived\n    from the grammar described in RFC 8259. Starting in state \"init\", the\n    input is read and used to determined the next state. Only state \"done\"\n    accepts the number. State \"error\" is a trap state to model errors. In the\n    table below, \"anything\" means any character but the ones listed before.\n\n    state    | 0        | 1-9      | e E      | +       | -       | .        | anything\n    ---------|----------|----------|----------|---------|---------|----------|-----------\n    init     | zero     | any1     | [error]  | [error] | minus   | [error]  | [error]\n    minus    | zero     | any1     | [error]  | [error] | [error] | [error]  | [error]\n    zero     | done     | done     | exponent | done    | done    | decimal1 | done\n    any1     | any1     | any1     | exponent | done    | done    | decimal1 | done\n    decimal1 | decimal2 | decimal2 | [error]  | [error] | [error] | [error]  | [error]\n    decimal2 | decimal2 | decimal2 | exponent | done    | done    | done     | done\n    exponent | any2     | any2     | [error]  | sign    | sign    | [error]  | [error]\n    sign     | any2     | any2     | [error]  | [error] | [error] | [error]  | [error]\n    any2     | any2     | any2     | done     | done    | done    | done     | done\n\n    The state machine is realized with one label per state (prefixed with\n    \"scan_number_\") and `goto` statements between them. The state machine\n    contains cycles, but any cycle can be left when EOF is read. Therefore,\n    the function is guaranteed to terminate.\n\n    During scanning, the read bytes are stored in token_buffer. This string is\n    then converted to a signed integer, an unsigned integer, or a\n    floating-point number.\n\n    @return token_type::value_unsigned, token_type::value_integer, or\n            token_type::value_float if number could be successfully scanned,\n            token_type::parse_error otherwise\n\n    @note The scanner is independent of the current locale. Internally, the\n          locale's decimal point is used instead of `.` to work with the\n          locale-dependent converters.\n    */\n    token_type scan_number()  // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the \"done\" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.\n    {\n        // reset token_buffer to store the number's bytes\n        reset();\n\n        // the type of the parsed number; initially set to unsigned; will be\n        // changed if minus sign, decimal point or exponent is read\n        token_type number_type = token_type::value_unsigned;\n\n        // state (init): we just found out we need to scan a number\n        switch (current)\n        {\n            case '-':\n            {\n                add(current);\n                goto scan_number_minus;\n            }\n\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            // all other characters are rejected outside scan_number()\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n\nscan_number_minus:\n        // state: we just parsed a leading minus sign\n        number_type = token_type::value_integer;\n        switch (get())\n        {\n            case '0':\n            {\n                add(current);\n                goto scan_number_zero;\n            }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '-'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_zero:\n        // state: we just parse a zero (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '.':\n            {\n                add(decimal_point_char);\n                decimal_point_position = token_buffer.size() - 1;\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_any1:\n        // state: we just parsed a number 0-9 (maybe with a leading minus sign)\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any1;\n            }\n\n            case '.':\n            {\n                add(decimal_point_char);\n                decimal_point_position = token_buffer.size() - 1;\n                goto scan_number_decimal1;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_decimal1:\n        // state: we just parsed a decimal point\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after '.'\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_decimal2:\n        // we just parsed at least one number after a decimal point\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_decimal2;\n            }\n\n            case 'e':\n            case 'E':\n            {\n                add(current);\n                goto scan_number_exponent;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_exponent:\n        // we just parsed an exponent\n        number_type = token_type::value_float;\n        switch (get())\n        {\n            case '+':\n            case '-':\n            {\n                add(current);\n                goto scan_number_sign;\n            }\n\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message =\n                    \"invalid number; expected '+', '-', or digit after exponent\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_sign:\n        // we just parsed an exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n            {\n                error_message = \"invalid number; expected digit after exponent sign\";\n                return token_type::parse_error;\n            }\n        }\n\nscan_number_any2:\n        // we just parsed a number after the exponent or exponent sign\n        switch (get())\n        {\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n            {\n                add(current);\n                goto scan_number_any2;\n            }\n\n            default:\n                goto scan_number_done;\n        }\n\nscan_number_done:\n        // unget the character after the number (we only read it to know that\n        // we are done scanning a number)\n        unget();\n\n        char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n        errno = 0;\n\n        // try to parse integers first and fall back to floats\n        if (number_type == token_type::value_unsigned)\n        {\n            const auto x = std::strtoull(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno != ERANGE)\n            {\n                value_unsigned = static_cast<number_unsigned_t>(x);\n                if (value_unsigned == x)\n                {\n                    return token_type::value_unsigned;\n                }\n            }\n        }\n        else if (number_type == token_type::value_integer)\n        {\n            const auto x = std::strtoll(token_buffer.data(), &endptr, 10);\n\n            // we checked the number format before\n            JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n            if (errno != ERANGE)\n            {\n                value_integer = static_cast<number_integer_t>(x);\n                if (value_integer == x)\n                {\n                    return token_type::value_integer;\n                }\n            }\n        }\n\n        // this code is reached if we parse a floating-point number or if an\n        // integer conversion above failed\n        strtof(value_float, token_buffer.data(), &endptr);\n\n        // we checked the number format before\n        JSON_ASSERT(endptr == token_buffer.data() + token_buffer.size());\n\n        return token_type::value_float;\n    }\n\n    /*!\n    @param[in] literal_text  the literal text to expect\n    @param[in] length        the length of the passed literal text\n    @param[in] return_type   the token type to return on success\n    */\n    JSON_HEDLEY_NON_NULL(2)\n    token_type scan_literal(const char_type* literal_text, const std::size_t length,\n                            token_type return_type)\n    {\n        JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]);\n        for (std::size_t i = 1; i < length; ++i)\n        {\n            if (JSON_HEDLEY_UNLIKELY(char_traits<char_type>::to_char_type(get()) != literal_text[i]))\n            {\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n            }\n        }\n        return return_type;\n    }\n\n    /////////////////////\n    // input management\n    /////////////////////\n\n    /// reset token_buffer; current character is beginning of token\n    void reset() noexcept\n    {\n        token_buffer.clear();\n        token_string.clear();\n        decimal_point_position = std::string::npos;\n        token_string.push_back(char_traits<char_type>::to_char_type(current));\n    }\n\n    /*\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a\n    `char_traits<char>::eof()` in that case.  Stores the scanned characters\n    for use in error messages.\n\n    @return character read from the input\n    */\n    char_int_type get()\n    {\n        ++position.chars_read_total;\n        ++position.chars_read_current_line;\n\n        if (next_unget)\n        {\n            // just reset the next_unget variable and work with current\n            next_unget = false;\n        }\n        else\n        {\n            current = ia.get_character();\n        }\n\n        if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))\n        {\n            token_string.push_back(char_traits<char_type>::to_char_type(current));\n        }\n\n        if (current == '\\n')\n        {\n            ++position.lines_read;\n            position.chars_read_current_line = 0;\n        }\n\n        return current;\n    }\n\n    /*!\n    @brief unget current character (read it again on next get)\n\n    We implement unget by setting variable next_unget to true. The input is not\n    changed - we just simulate ungetting by modifying chars_read_total,\n    chars_read_current_line, and token_string. The next call to get() will\n    behave as if the unget character is read again.\n    */\n    void unget()\n    {\n        next_unget = true;\n\n        --position.chars_read_total;\n\n        // in case we \"unget\" a newline, we have to also decrement the lines_read\n        if (position.chars_read_current_line == 0)\n        {\n            if (position.lines_read > 0)\n            {\n                --position.lines_read;\n            }\n        }\n        else\n        {\n            --position.chars_read_current_line;\n        }\n\n        if (JSON_HEDLEY_LIKELY(current != char_traits<char_type>::eof()))\n        {\n            JSON_ASSERT(!token_string.empty());\n            token_string.pop_back();\n        }\n    }\n\n    /// add a character to token_buffer\n    void add(char_int_type c)\n    {\n        token_buffer.push_back(static_cast<typename string_t::value_type>(c));\n    }\n\n  public:\n    /////////////////////\n    // value getters\n    /////////////////////\n\n    /// return integer value\n    constexpr number_integer_t get_number_integer() const noexcept\n    {\n        return value_integer;\n    }\n\n    /// return unsigned integer value\n    constexpr number_unsigned_t get_number_unsigned() const noexcept\n    {\n        return value_unsigned;\n    }\n\n    /// return floating-point value\n    constexpr number_float_t get_number_float() const noexcept\n    {\n        return value_float;\n    }\n\n    /// return current string value (implicitly resets the token; useful only once)\n    string_t& get_string()\n    {\n        // translate decimal points from locale back to '.' (#4084)\n        if (decimal_point_char != '.' && decimal_point_position != std::string::npos)\n        {\n            token_buffer[decimal_point_position] = '.';\n        }\n        return token_buffer;\n    }\n\n    /////////////////////\n    // diagnostics\n    /////////////////////\n\n    /// return position of last read token\n    constexpr position_t get_position() const noexcept\n    {\n        return position;\n    }\n\n    /// return the last read token (for errors only).  Will never contain EOF\n    /// (an arbitrary value that is not a valid char value, often -1), because\n    /// 255 may legitimately occur.  May contain NUL, which should be escaped.\n    std::string get_token_string() const\n    {\n        // escape control characters\n        std::string result;\n        for (const auto c : token_string)\n        {\n            if (static_cast<unsigned char>(c) <= '\\x1F')\n            {\n                // escape control characters\n                std::array<char, 9> cs{{}};\n                static_cast<void>((std::snprintf)(cs.data(), cs.size(), \"<U+%.4X>\", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                result += cs.data();\n            }\n            else\n            {\n                // add character as is\n                result.push_back(static_cast<std::string::value_type>(c));\n            }\n        }\n\n        return result;\n    }\n\n    /// return syntax error message\n    JSON_HEDLEY_RETURNS_NON_NULL\n    constexpr const char* get_error_message() const noexcept\n    {\n        return error_message;\n    }\n\n    /////////////////////\n    // actual scanner\n    /////////////////////\n\n    /*!\n    @brief skip the UTF-8 byte order mark\n    @return true iff there is no BOM or the correct BOM has been skipped\n    */\n    bool skip_bom()\n    {\n        if (get() == 0xEF)\n        {\n            // check if we completely parse the BOM\n            return get() == 0xBB && get() == 0xBF;\n        }\n\n        // the first character is not the beginning of the BOM; unget it to\n        // process is later\n        unget();\n        return true;\n    }\n\n    void skip_whitespace()\n    {\n        do\n        {\n            get();\n        }\n        while (current == ' ' || current == '\\t' || current == '\\n' || current == '\\r');\n    }\n\n    token_type scan()\n    {\n        // initially, skip the BOM\n        if (position.chars_read_total == 0 && !skip_bom())\n        {\n            error_message = \"invalid BOM; must be 0xEF 0xBB 0xBF if given\";\n            return token_type::parse_error;\n        }\n\n        // read next character and ignore whitespace\n        skip_whitespace();\n\n        // ignore comments\n        while (ignore_comments && current == '/')\n        {\n            if (!scan_comment())\n            {\n                return token_type::parse_error;\n            }\n\n            // skip following whitespace\n            skip_whitespace();\n        }\n\n        switch (current)\n        {\n            // structural characters\n            case '[':\n                return token_type::begin_array;\n            case ']':\n                return token_type::end_array;\n            case '{':\n                return token_type::begin_object;\n            case '}':\n                return token_type::end_object;\n            case ':':\n                return token_type::name_separator;\n            case ',':\n                return token_type::value_separator;\n\n            // literals\n            case 't':\n            {\n                std::array<char_type, 4> true_literal = {{static_cast<char_type>('t'), static_cast<char_type>('r'), static_cast<char_type>('u'), static_cast<char_type>('e')}};\n                return scan_literal(true_literal.data(), true_literal.size(), token_type::literal_true);\n            }\n            case 'f':\n            {\n                std::array<char_type, 5> false_literal = {{static_cast<char_type>('f'), static_cast<char_type>('a'), static_cast<char_type>('l'), static_cast<char_type>('s'), static_cast<char_type>('e')}};\n                return scan_literal(false_literal.data(), false_literal.size(), token_type::literal_false);\n            }\n            case 'n':\n            {\n                std::array<char_type, 4> null_literal = {{static_cast<char_type>('n'), static_cast<char_type>('u'), static_cast<char_type>('l'), static_cast<char_type>('l')}};\n                return scan_literal(null_literal.data(), null_literal.size(), token_type::literal_null);\n            }\n\n            // string\n            case '\\\"':\n                return scan_string();\n\n            // number\n            case '-':\n            case '0':\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                return scan_number();\n\n            // end of input (the null byte is needed when parsing from\n            // string literals)\n            case '\\0':\n            case char_traits<char_type>::eof():\n                return token_type::end_of_input;\n\n            // error\n            default:\n                error_message = \"invalid literal\";\n                return token_type::parse_error;\n        }\n    }\n\n  private:\n    /// input adapter\n    InputAdapterType ia;\n\n    /// whether comments should be ignored (true) or signaled as errors (false)\n    const bool ignore_comments = false;\n\n    /// the current character\n    char_int_type current = char_traits<char_type>::eof();\n\n    /// whether the next get() call should just return current\n    bool next_unget = false;\n\n    /// the start position of the current token\n    position_t position {};\n\n    /// raw input token string (for error messages)\n    std::vector<char_type> token_string {};\n\n    /// buffer for variable-length tokens (numbers, strings)\n    string_t token_buffer {};\n\n    /// a description of occurred lexer errors\n    const char* error_message = \"\";\n\n    // number values\n    number_integer_t value_integer = 0;\n    number_unsigned_t value_unsigned = 0;\n    number_float_t value_float = 0;\n\n    /// the decimal point\n    const char_int_type decimal_point_char = '.';\n    /// the position of the decimal point in the input\n    std::size_t decimal_point_position = std::string::npos;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/*!\n@brief SAX interface\n\nThis class describes the SAX interface used by @ref nlohmann::json::sax_parse.\nEach function is called in different situations while the input is parsed. The\nboolean return value informs the parser whether to continue processing the\ninput.\n*/\ntemplate<typename BasicJsonType>\nstruct json_sax\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    /*!\n    @brief a null value was read\n    @return whether parsing should proceed\n    */\n    virtual bool null() = 0;\n\n    /*!\n    @brief a boolean value was read\n    @param[in] val  boolean value\n    @return whether parsing should proceed\n    */\n    virtual bool boolean(bool val) = 0;\n\n    /*!\n    @brief an integer number was read\n    @param[in] val  integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_integer(number_integer_t val) = 0;\n\n    /*!\n    @brief an unsigned integer number was read\n    @param[in] val  unsigned integer value\n    @return whether parsing should proceed\n    */\n    virtual bool number_unsigned(number_unsigned_t val) = 0;\n\n    /*!\n    @brief a floating-point number was read\n    @param[in] val  floating-point value\n    @param[in] s    raw token value\n    @return whether parsing should proceed\n    */\n    virtual bool number_float(number_float_t val, const string_t& s) = 0;\n\n    /*!\n    @brief a string value was read\n    @param[in] val  string value\n    @return whether parsing should proceed\n    @note It is safe to move the passed string value.\n    */\n    virtual bool string(string_t& val) = 0;\n\n    /*!\n    @brief a binary value was read\n    @param[in] val  binary value\n    @return whether parsing should proceed\n    @note It is safe to move the passed binary value.\n    */\n    virtual bool binary(binary_t& val) = 0;\n\n    /*!\n    @brief the beginning of an object was read\n    @param[in] elements  number of object elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_object(std::size_t elements) = 0;\n\n    /*!\n    @brief an object key was read\n    @param[in] val  object key\n    @return whether parsing should proceed\n    @note It is safe to move the passed string.\n    */\n    virtual bool key(string_t& val) = 0;\n\n    /*!\n    @brief the end of an object was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_object() = 0;\n\n    /*!\n    @brief the beginning of an array was read\n    @param[in] elements  number of array elements or -1 if unknown\n    @return whether parsing should proceed\n    @note binary formats may report the number of elements\n    */\n    virtual bool start_array(std::size_t elements) = 0;\n\n    /*!\n    @brief the end of an array was read\n    @return whether parsing should proceed\n    */\n    virtual bool end_array() = 0;\n\n    /*!\n    @brief a parse error occurred\n    @param[in] position    the position in the input where the error occurs\n    @param[in] last_token  the last read token\n    @param[in] ex          an exception object describing the error\n    @return whether parsing should proceed (must return false)\n    */\n    virtual bool parse_error(std::size_t position,\n                             const std::string& last_token,\n                             const detail::exception& ex) = 0;\n\n    json_sax() = default;\n    json_sax(const json_sax&) = default;\n    json_sax(json_sax&&) noexcept = default;\n    json_sax& operator=(const json_sax&) = default;\n    json_sax& operator=(json_sax&&) noexcept = default;\n    virtual ~json_sax() = default;\n};\n\nnamespace detail\n{\nconstexpr std::size_t unknown_size()\n{\n    return (std::numeric_limits<std::size_t>::max)();\n}\n\n/*!\n@brief SAX implementation to create a JSON value from SAX events\n\nThis class implements the @ref json_sax interface and processes the SAX events\nto create a JSON value which makes it basically a DOM parser. The structure or\nhierarchy of the JSON value is managed by the stack `ref_stack` which contains\na pointer to the respective array or object for each recursion depth.\n\nAfter successful parsing, the value that is passed by reference to the\nconstructor contains the parsed value.\n\n@tparam BasicJsonType  the JSON type\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass json_sax_dom_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using lexer_t = lexer<BasicJsonType, InputAdapterType>;\n\n    /*!\n    @param[in,out] r  reference to a JSON value that is manipulated while\n                       parsing\n    @param[in] allow_exceptions_  whether parse errors yield exceptions\n    */\n    explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true, lexer_t* lexer_ = nullptr)\n        : root(r), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)\n    {}\n\n    // make class move-only\n    json_sax_dom_parser(const json_sax_dom_parser&) = delete;\n    json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;\n    json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~json_sax_dom_parser() = default;\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool binary(binary_t& val)\n    {\n        handle_value(std::move(val));\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::object));\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        // Manually set the start position of the object here.\n        // Ensure this is after the call to handle_value to ensure correct start position.\n        if (m_lexer_ref)\n        {\n            // Lexer has read the first character of the object, so\n            // subtract 1 from the position to get the correct start position.\n            ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;\n        }\n#endif\n\n        if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, concat(\"excessive object size: \", std::to_string(len)), ref_stack.back()));\n        }\n\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(ref_stack.back()->is_object());\n\n        // add null at given key and store the reference for later\n        object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val));\n        return true;\n    }\n\n    bool end_object()\n    {\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(ref_stack.back()->is_object());\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        if (m_lexer_ref)\n        {\n            // Lexer's position is past the closing brace, so set that as the end position.\n            ref_stack.back()->end_position = m_lexer_ref->get_position();\n        }\n#endif\n\n        ref_stack.back()->set_parents();\n        ref_stack.pop_back();\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        ref_stack.push_back(handle_value(BasicJsonType::value_t::array));\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        // Manually set the start position of the array here.\n        // Ensure this is after the call to handle_value to ensure correct start position.\n        if (m_lexer_ref)\n        {\n            ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;\n        }\n#endif\n\n        if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))\n        {\n            JSON_THROW(out_of_range::create(408, concat(\"excessive array size: \", std::to_string(len)), ref_stack.back()));\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(ref_stack.back()->is_array());\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        if (m_lexer_ref)\n        {\n            // Lexer's position is past the closing bracket, so set that as the end position.\n            ref_stack.back()->end_position = m_lexer_ref->get_position();\n        }\n#endif\n\n        ref_stack.back()->set_parents();\n        ref_stack.pop_back();\n        return true;\n    }\n\n    template<class Exception>\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const Exception& ex)\n    {\n        errored = true;\n        static_cast<void>(ex);\n        if (allow_exceptions)\n        {\n            JSON_THROW(ex);\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n\n#if JSON_DIAGNOSTIC_POSITIONS\n    void handle_diagnostic_positions_for_json_value(BasicJsonType& v)\n    {\n        if (m_lexer_ref)\n        {\n            // Lexer has read past the current field value, so set the end position to the current position.\n            // The start position will be set below based on the length of the string representation\n            // of the value.\n            v.end_position = m_lexer_ref->get_position();\n\n            switch (v.type())\n            {\n                case value_t::boolean:\n                {\n                    // 4 and 5 are the string length of \"true\" and \"false\"\n                    v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    // 4 is the string length of \"null\"\n                    v.start_position = v.end_position - 4;\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    // include the length of the quotes, which is 2\n                    v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;\n                    break;\n                }\n\n                // As we handle the start and end positions for values created during parsing,\n                // we do not expect the following value type to be called. Regardless, set the positions\n                // in case this is created manually or through a different constructor. Exclude from lcov\n                // since the exact condition of this switch is esoteric.\n                // LCOV_EXCL_START\n                case value_t::discarded:\n                {\n                    v.end_position = std::string::npos;\n                    v.start_position = v.end_position;\n                    break;\n                }\n                // LCOV_EXCL_STOP\n                case value_t::binary:\n                case value_t::number_integer:\n                case value_t::number_unsigned:\n                case value_t::number_float:\n                {\n                    v.start_position = v.end_position - m_lexer_ref->get_string().size();\n                    break;\n                }\n                case value_t::object:\n                case value_t::array:\n                {\n                    // object and array are handled in start_object() and start_array() handlers\n                    // skip setting the values here.\n                    break;\n                }\n                default: // LCOV_EXCL_LINE\n                    // Handle all possible types discretely, default handler should never be reached.\n                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE\n            }\n        }\n    }\n#endif\n\n    /*!\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n    */\n    template<typename Value>\n    JSON_HEDLEY_RETURNS_NON_NULL\n    BasicJsonType* handle_value(Value&& v)\n    {\n        if (ref_stack.empty())\n        {\n            root = BasicJsonType(std::forward<Value>(v));\n\n#if JSON_DIAGNOSTIC_POSITIONS\n            handle_diagnostic_positions_for_json_value(root);\n#endif\n\n            return &root;\n        }\n\n        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());\n\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_data.m_value.array->emplace_back(std::forward<Value>(v));\n\n#if JSON_DIAGNOSTIC_POSITIONS\n            handle_diagnostic_positions_for_json_value(ref_stack.back()->m_data.m_value.array->back());\n#endif\n\n            return &(ref_stack.back()->m_data.m_value.array->back());\n        }\n\n        JSON_ASSERT(ref_stack.back()->is_object());\n        JSON_ASSERT(object_element);\n        *object_element = BasicJsonType(std::forward<Value>(v));\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        handle_diagnostic_positions_for_json_value(*object_element);\n#endif\n\n        return object_element;\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack {};\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n    /// the lexer reference to obtain the current position\n    lexer_t* m_lexer_ref = nullptr;\n};\n\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass json_sax_dom_callback_parser\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using parser_callback_t = typename BasicJsonType::parser_callback_t;\n    using parse_event_t = typename BasicJsonType::parse_event_t;\n    using lexer_t = lexer<BasicJsonType, InputAdapterType>;\n\n    json_sax_dom_callback_parser(BasicJsonType& r,\n                                 parser_callback_t cb,\n                                 const bool allow_exceptions_ = true,\n                                 lexer_t* lexer_ = nullptr)\n        : root(r), callback(std::move(cb)), allow_exceptions(allow_exceptions_), m_lexer_ref(lexer_)\n    {\n        keep_stack.push_back(true);\n    }\n\n    // make class move-only\n    json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;\n    json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;\n    json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~json_sax_dom_callback_parser() = default;\n\n    bool null()\n    {\n        handle_value(nullptr);\n        return true;\n    }\n\n    bool boolean(bool val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_integer(number_integer_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool number_float(number_float_t val, const string_t& /*unused*/)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool string(string_t& val)\n    {\n        handle_value(val);\n        return true;\n    }\n\n    bool binary(binary_t& val)\n    {\n        handle_value(std::move(val));\n        return true;\n    }\n\n    bool start_object(std::size_t len)\n    {\n        // check callback for object start\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::object, true);\n        ref_stack.push_back(val.second);\n\n        if (ref_stack.back())\n        {\n\n#if JSON_DIAGNOSTIC_POSITIONS\n            // Manually set the start position of the object here.\n            // Ensure this is after the call to handle_value to ensure correct start position.\n            if (m_lexer_ref)\n            {\n                // Lexer has read the first character of the object, so\n                // subtract 1 from the position to get the correct start position.\n                ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;\n            }\n#endif\n\n            // check object limit\n            if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))\n            {\n                JSON_THROW(out_of_range::create(408, concat(\"excessive object size: \", std::to_string(len)), ref_stack.back()));\n            }\n        }\n        return true;\n    }\n\n    bool key(string_t& val)\n    {\n        BasicJsonType k = BasicJsonType(val);\n\n        // check callback for key\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);\n        key_keep_stack.push_back(keep);\n\n        // add discarded value at given key and store the reference for later\n        if (keep && ref_stack.back())\n        {\n            object_element = &(ref_stack.back()->m_data.m_value.object->operator[](val) = discarded);\n        }\n\n        return true;\n    }\n\n    bool end_object()\n    {\n        if (ref_stack.back())\n        {\n            if (!callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))\n            {\n                // discard object\n                *ref_stack.back() = discarded;\n\n#if JSON_DIAGNOSTIC_POSITIONS\n                // Set start/end positions for discarded object.\n                handle_diagnostic_positions_for_json_value(*ref_stack.back());\n#endif\n            }\n            else\n            {\n\n#if JSON_DIAGNOSTIC_POSITIONS\n                if (m_lexer_ref)\n                {\n                    // Lexer's position is past the closing brace, so set that as the end position.\n                    ref_stack.back()->end_position = m_lexer_ref->get_position();\n                }\n#endif\n\n                ref_stack.back()->set_parents();\n            }\n        }\n\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(!keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())\n        {\n            // remove discarded value\n            for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)\n            {\n                if (it->is_discarded())\n                {\n                    ref_stack.back()->erase(it);\n                    break;\n                }\n            }\n        }\n\n        return true;\n    }\n\n    bool start_array(std::size_t len)\n    {\n        const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);\n        keep_stack.push_back(keep);\n\n        auto val = handle_value(BasicJsonType::value_t::array, true);\n        ref_stack.push_back(val.second);\n\n        if (ref_stack.back())\n        {\n\n#if JSON_DIAGNOSTIC_POSITIONS\n            // Manually set the start position of the array here.\n            // Ensure this is after the call to handle_value to ensure correct start position.\n            if (m_lexer_ref)\n            {\n                // Lexer has read the first character of the array, so\n                // subtract 1 from the position to get the correct start position.\n                ref_stack.back()->start_position = m_lexer_ref->get_position() - 1;\n            }\n#endif\n\n            // check array limit\n            if (JSON_HEDLEY_UNLIKELY(len != detail::unknown_size() && len > ref_stack.back()->max_size()))\n            {\n                JSON_THROW(out_of_range::create(408, concat(\"excessive array size: \", std::to_string(len)), ref_stack.back()));\n            }\n        }\n\n        return true;\n    }\n\n    bool end_array()\n    {\n        bool keep = true;\n\n        if (ref_stack.back())\n        {\n            keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());\n            if (keep)\n            {\n\n#if JSON_DIAGNOSTIC_POSITIONS\n                if (m_lexer_ref)\n                {\n                    // Lexer's position is past the closing bracket, so set that as the end position.\n                    ref_stack.back()->end_position = m_lexer_ref->get_position();\n                }\n#endif\n\n                ref_stack.back()->set_parents();\n            }\n            else\n            {\n                // discard array\n                *ref_stack.back() = discarded;\n\n#if JSON_DIAGNOSTIC_POSITIONS\n                // Set start/end positions for discarded array.\n                handle_diagnostic_positions_for_json_value(*ref_stack.back());\n#endif\n            }\n        }\n\n        JSON_ASSERT(!ref_stack.empty());\n        JSON_ASSERT(!keep_stack.empty());\n        ref_stack.pop_back();\n        keep_stack.pop_back();\n\n        // remove discarded value\n        if (!keep && !ref_stack.empty() && ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_data.m_value.array->pop_back();\n        }\n\n        return true;\n    }\n\n    template<class Exception>\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/,\n                     const Exception& ex)\n    {\n        errored = true;\n        static_cast<void>(ex);\n        if (allow_exceptions)\n        {\n            JSON_THROW(ex);\n        }\n        return false;\n    }\n\n    constexpr bool is_errored() const\n    {\n        return errored;\n    }\n\n  private:\n\n#if JSON_DIAGNOSTIC_POSITIONS\n    void handle_diagnostic_positions_for_json_value(BasicJsonType& v)\n    {\n        if (m_lexer_ref)\n        {\n            // Lexer has read past the current field value, so set the end position to the current position.\n            // The start position will be set below based on the length of the string representation\n            // of the value.\n            v.end_position = m_lexer_ref->get_position();\n\n            switch (v.type())\n            {\n                case value_t::boolean:\n                {\n                    // 4 and 5 are the string length of \"true\" and \"false\"\n                    v.start_position = v.end_position - (v.m_data.m_value.boolean ? 4 : 5);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    // 4 is the string length of \"null\"\n                    v.start_position = v.end_position - 4;\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    // include the length of the quotes, which is 2\n                    v.start_position = v.end_position - v.m_data.m_value.string->size() - 2;\n                    break;\n                }\n\n                case value_t::discarded:\n                {\n                    v.end_position = std::string::npos;\n                    v.start_position = v.end_position;\n                    break;\n                }\n\n                case value_t::binary:\n                case value_t::number_integer:\n                case value_t::number_unsigned:\n                case value_t::number_float:\n                {\n                    v.start_position = v.end_position - m_lexer_ref->get_string().size();\n                    break;\n                }\n\n                case value_t::object:\n                case value_t::array:\n                {\n                    // object and array are handled in start_object() and start_array() handlers\n                    // skip setting the values here.\n                    break;\n                }\n                default: // LCOV_EXCL_LINE\n                    // Handle all possible types discretely, default handler should never be reached.\n                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert,-warnings-as-errors) LCOV_EXCL_LINE\n            }\n        }\n    }\n#endif\n\n    /*!\n    @param[in] v  value to add to the JSON value we build during parsing\n    @param[in] skip_callback  whether we should skip calling the callback\n               function; this is required after start_array() and\n               start_object() SAX events, because otherwise we would call the\n               callback function with an empty array or object, respectively.\n\n    @invariant If the ref stack is empty, then the passed value will be the new\n               root.\n    @invariant If the ref stack contains a value, then it is an array or an\n               object to which we can add elements\n\n    @return pair of boolean (whether value should be kept) and pointer (to the\n            passed value in the ref_stack hierarchy; nullptr if not kept)\n    */\n    template<typename Value>\n    std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)\n    {\n        JSON_ASSERT(!keep_stack.empty());\n\n        // do not handle this value if we know it would be added to a discarded\n        // container\n        if (!keep_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // create value\n        auto value = BasicJsonType(std::forward<Value>(v));\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        handle_diagnostic_positions_for_json_value(value);\n#endif\n\n        // check callback\n        const bool keep = skip_callback || callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);\n\n        // do not handle this value if we just learnt it shall be discarded\n        if (!keep)\n        {\n            return {false, nullptr};\n        }\n\n        if (ref_stack.empty())\n        {\n            root = std::move(value);\n            return {true, & root};\n        }\n\n        // skip this value if we already decided to skip the parent\n        // (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)\n        if (!ref_stack.back())\n        {\n            return {false, nullptr};\n        }\n\n        // we now only expect arrays and objects\n        JSON_ASSERT(ref_stack.back()->is_array() || ref_stack.back()->is_object());\n\n        // array\n        if (ref_stack.back()->is_array())\n        {\n            ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));\n            return {true, & (ref_stack.back()->m_data.m_value.array->back())};\n        }\n\n        // object\n        JSON_ASSERT(ref_stack.back()->is_object());\n        // check if we should store an element for the current key\n        JSON_ASSERT(!key_keep_stack.empty());\n        const bool store_element = key_keep_stack.back();\n        key_keep_stack.pop_back();\n\n        if (!store_element)\n        {\n            return {false, nullptr};\n        }\n\n        JSON_ASSERT(object_element);\n        *object_element = std::move(value);\n        return {true, object_element};\n    }\n\n    /// the parsed JSON value\n    BasicJsonType& root;\n    /// stack to model hierarchy of values\n    std::vector<BasicJsonType*> ref_stack {};\n    /// stack to manage which values to keep\n    std::vector<bool> keep_stack {}; // NOLINT(readability-redundant-member-init)\n    /// stack to manage which object keys to keep\n    std::vector<bool> key_keep_stack {}; // NOLINT(readability-redundant-member-init)\n    /// helper to hold the reference for the next object element\n    BasicJsonType* object_element = nullptr;\n    /// whether a syntax error occurred\n    bool errored = false;\n    /// callback function\n    const parser_callback_t callback = nullptr;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n    /// a discarded value for the callback\n    BasicJsonType discarded = BasicJsonType::value_t::discarded;\n    /// the lexer reference to obtain the current position\n    lexer_t* m_lexer_ref = nullptr;\n};\n\ntemplate<typename BasicJsonType>\nclass json_sax_acceptor\n{\n  public:\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n\n    bool null()\n    {\n        return true;\n    }\n\n    bool boolean(bool /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_integer(number_integer_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_unsigned(number_unsigned_t /*unused*/)\n    {\n        return true;\n    }\n\n    bool number_float(number_float_t /*unused*/, const string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool string(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool binary(binary_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool start_object(std::size_t /*unused*/ = detail::unknown_size())\n    {\n        return true;\n    }\n\n    bool key(string_t& /*unused*/)\n    {\n        return true;\n    }\n\n    bool end_object()\n    {\n        return true;\n    }\n\n    bool start_array(std::size_t /*unused*/ = detail::unknown_size())\n    {\n        return true;\n    }\n\n    bool end_array()\n    {\n        return true;\n    }\n\n    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const detail::exception& /*unused*/)\n    {\n        return false;\n    }\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstdint> // size_t\n#include <utility> // declval\n#include <string> // string\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n// #include <nlohmann/detail/meta/detected.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename T>\nusing null_function_t = decltype(std::declval<T&>().null());\n\ntemplate<typename T>\nusing boolean_function_t =\n    decltype(std::declval<T&>().boolean(std::declval<bool>()));\n\ntemplate<typename T, typename Integer>\nusing number_integer_function_t =\n    decltype(std::declval<T&>().number_integer(std::declval<Integer>()));\n\ntemplate<typename T, typename Unsigned>\nusing number_unsigned_function_t =\n    decltype(std::declval<T&>().number_unsigned(std::declval<Unsigned>()));\n\ntemplate<typename T, typename Float, typename String>\nusing number_float_function_t = decltype(std::declval<T&>().number_float(\n                                    std::declval<Float>(), std::declval<const String&>()));\n\ntemplate<typename T, typename String>\nusing string_function_t =\n    decltype(std::declval<T&>().string(std::declval<String&>()));\n\ntemplate<typename T, typename Binary>\nusing binary_function_t =\n    decltype(std::declval<T&>().binary(std::declval<Binary&>()));\n\ntemplate<typename T>\nusing start_object_function_t =\n    decltype(std::declval<T&>().start_object(std::declval<std::size_t>()));\n\ntemplate<typename T, typename String>\nusing key_function_t =\n    decltype(std::declval<T&>().key(std::declval<String&>()));\n\ntemplate<typename T>\nusing end_object_function_t = decltype(std::declval<T&>().end_object());\n\ntemplate<typename T>\nusing start_array_function_t =\n    decltype(std::declval<T&>().start_array(std::declval<std::size_t>()));\n\ntemplate<typename T>\nusing end_array_function_t = decltype(std::declval<T&>().end_array());\n\ntemplate<typename T, typename Exception>\nusing parse_error_function_t = decltype(std::declval<T&>().parse_error(\n        std::declval<std::size_t>(), std::declval<const std::string&>(),\n        std::declval<const Exception&>()));\n\ntemplate<typename SAX, typename BasicJsonType>\nstruct is_sax\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static constexpr bool value =\n        is_detected_exact<bool, null_function_t, SAX>::value &&\n        is_detected_exact<bool, boolean_function_t, SAX>::value &&\n        is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value &&\n        is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value &&\n        is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value &&\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value &&\n        is_detected_exact<bool, start_object_function_t, SAX>::value &&\n        is_detected_exact<bool, key_function_t, SAX, string_t>::value &&\n        is_detected_exact<bool, end_object_function_t, SAX>::value &&\n        is_detected_exact<bool, start_array_function_t, SAX>::value &&\n        is_detected_exact<bool, end_array_function_t, SAX>::value &&\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;\n};\n\ntemplate<typename SAX, typename BasicJsonType>\nstruct is_sax_static_asserts\n{\n  private:\n    static_assert(is_basic_json<BasicJsonType>::value,\n                  \"BasicJsonType must be of type basic_json<...>\");\n\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using exception_t = typename BasicJsonType::exception;\n\n  public:\n    static_assert(is_detected_exact<bool, null_function_t, SAX>::value,\n                  \"Missing/invalid function: bool null()\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,\n                  \"Missing/invalid function: bool boolean(bool)\");\n    static_assert(\n        is_detected_exact<bool, number_integer_function_t, SAX,\n        number_integer_t>::value,\n        \"Missing/invalid function: bool number_integer(number_integer_t)\");\n    static_assert(\n        is_detected_exact<bool, number_unsigned_function_t, SAX,\n        number_unsigned_t>::value,\n        \"Missing/invalid function: bool number_unsigned(number_unsigned_t)\");\n    static_assert(is_detected_exact<bool, number_float_function_t, SAX,\n                  number_float_t, string_t>::value,\n                  \"Missing/invalid function: bool number_float(number_float_t, const string_t&)\");\n    static_assert(\n        is_detected_exact<bool, string_function_t, SAX, string_t>::value,\n        \"Missing/invalid function: bool string(string_t&)\");\n    static_assert(\n        is_detected_exact<bool, binary_function_t, SAX, binary_t>::value,\n        \"Missing/invalid function: bool binary(binary_t&)\");\n    static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_object(std::size_t)\");\n    static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,\n                  \"Missing/invalid function: bool key(string_t&)\");\n    static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_object()\");\n    static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool start_array(std::size_t)\");\n    static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,\n                  \"Missing/invalid function: bool end_array()\");\n    static_assert(\n        is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,\n        \"Missing/invalid function: bool parse_error(std::size_t, const \"\n        \"std::string&, const exception&)\");\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/// how to treat CBOR tags\nenum class cbor_tag_handler_t\n{\n    error,   ///< throw a parse_error exception in case of a tag\n    ignore,  ///< ignore tags\n    store    ///< store tags as binary type\n};\n\n/*!\n@brief determine system byte order\n\n@return true if and only if system's byte order is little endian\n\n@note from https://stackoverflow.com/a/1001328/266378\n*/\nstatic inline bool little_endianness(int num = 1) noexcept\n{\n    return *reinterpret_cast<char*>(&num) == 1;\n}\n\n///////////////////\n// binary reader //\n///////////////////\n\n/*!\n@brief deserialization of CBOR, MessagePack, and UBJSON values\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType, typename SAX = json_sax_dom_parser<BasicJsonType, InputAdapterType>>\nclass binary_reader\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using json_sax_t = SAX;\n    using char_type = typename InputAdapterType::char_type;\n    using char_int_type = typename char_traits<char_type>::int_type;\n\n  public:\n    /*!\n    @brief create a binary reader\n\n    @param[in] adapter  input adapter to read from\n    */\n    explicit binary_reader(InputAdapterType&& adapter, const input_format_t format = input_format_t::json) noexcept : ia(std::move(adapter)), input_format(format)\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n    }\n\n    // make class move-only\n    binary_reader(const binary_reader&) = delete;\n    binary_reader(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    binary_reader& operator=(const binary_reader&) = delete;\n    binary_reader& operator=(binary_reader&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)\n    ~binary_reader() = default;\n\n    /*!\n    @param[in] format  the binary format to parse\n    @param[in] sax_    a SAX event processor\n    @param[in] strict  whether to expect the input to be consumed completed\n    @param[in] tag_handler  how to treat CBOR tags\n\n    @return whether parsing was successful\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    bool sax_parse(const input_format_t format,\n                   json_sax_t* sax_,\n                   const bool strict = true,\n                   const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        sax = sax_;\n        bool result = false;\n\n        switch (format)\n        {\n            case input_format_t::bson:\n                result = parse_bson_internal();\n                break;\n\n            case input_format_t::cbor:\n                result = parse_cbor_internal(true, tag_handler);\n                break;\n\n            case input_format_t::msgpack:\n                result = parse_msgpack_internal();\n                break;\n\n            case input_format_t::ubjson:\n            case input_format_t::bjdata:\n                result = parse_ubjson_internal();\n                break;\n\n            case input_format_t::json: // LCOV_EXCL_LINE\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n\n        // strict mode: next byte must be EOF\n        if (result && strict)\n        {\n            if (input_format == input_format_t::ubjson || input_format == input_format_t::bjdata)\n            {\n                get_ignore_noop();\n            }\n            else\n            {\n                get();\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(current != char_traits<char_type>::eof()))\n            {\n                return sax->parse_error(chars_read, get_token_string(), parse_error::create(110, chars_read,\n                                        exception_message(input_format, concat(\"expected end of input; last byte: 0x\", get_token_string()), \"value\"), nullptr));\n            }\n        }\n\n        return result;\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @brief Reads in a BSON-object and passes it to the SAX-parser.\n    @return whether a valid BSON-value was passed to the SAX parser\n    */\n    bool parse_bson_internal()\n    {\n        std::int32_t document_size{};\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))\n        {\n            return false;\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))\n        {\n            return false;\n        }\n\n        return sax->end_object();\n    }\n\n    /*!\n    @brief Parses a C-style string from the BSON input.\n    @param[in,out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @return `true` if the \\x00-byte indicating the end of the string was\n             encountered before the EOF; false` indicates an unexpected EOF.\n    */\n    bool get_bson_cstr(string_t& result)\n    {\n        auto out = std::back_inserter(result);\n        while (true)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, \"cstring\")))\n            {\n                return false;\n            }\n            if (current == 0x00)\n            {\n                return true;\n            }\n            *out++ = static_cast<typename string_t::value_type>(current);\n        }\n    }\n\n    /*!\n    @brief Parses a zero-terminated string of length @a len from the BSON\n           input.\n    @param[in] len  The length (including the zero-byte at the end) of the\n                    string to be read.\n    @param[in,out] result  A reference to the string variable where the read\n                            string is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 1\n    @return `true` if the string was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_string(const NumberType len, string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(len < 1))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                    exception_message(input_format_t::bson, concat(\"string length must be at least 1, is \", std::to_string(len)), \"string\"), nullptr));\n        }\n\n        return get_string(input_format_t::bson, len - static_cast<NumberType>(1), result) && get() != char_traits<char_type>::eof();\n    }\n\n    /*!\n    @brief Parses a byte array input of length @a len from the BSON input.\n    @param[in] len  The length of the byte array to be read.\n    @param[in,out] result  A reference to the binary variable where the read\n                            array is to be stored.\n    @tparam NumberType The type of the length @a len\n    @pre len >= 0\n    @return `true` if the byte array was successfully parsed\n    */\n    template<typename NumberType>\n    bool get_bson_binary(const NumberType len, binary_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(len < 0))\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                    exception_message(input_format_t::bson, concat(\"byte array length cannot be negative, is \", std::to_string(len)), \"binary\"), nullptr));\n        }\n\n        // All BSON binary values have a subtype\n        std::uint8_t subtype{};\n        get_number<std::uint8_t>(input_format_t::bson, subtype);\n        result.set_subtype(subtype);\n\n        return get_binary(input_format_t::bson, len, result);\n    }\n\n    /*!\n    @brief Read a BSON document element of the given @a element_type.\n    @param[in] element_type The BSON element type, c.f. http://bsonspec.org/spec.html\n    @param[in] element_type_parse_position The position in the input stream,\n               where the `element_type` was read.\n    @warning Not all BSON element types are supported yet. An unsupported\n             @a element_type will give rise to a parse_error.114:\n             Unsupported BSON record type 0x...\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_internal(const char_int_type element_type,\n                                     const std::size_t element_type_parse_position)\n    {\n        switch (element_type)\n        {\n            case 0x01: // double\n            {\n                double number{};\n                return get_number<double, true>(input_format_t::bson, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0x02: // string\n            {\n                std::int32_t len{};\n                string_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_string(len, value) && sax->string(value);\n            }\n\n            case 0x03: // object\n            {\n                return parse_bson_internal();\n            }\n\n            case 0x04: // array\n            {\n                return parse_bson_array();\n            }\n\n            case 0x05: // binary\n            {\n                std::int32_t len{};\n                binary_t value;\n                return get_number<std::int32_t, true>(input_format_t::bson, len) && get_bson_binary(len, value) && sax->binary(value);\n            }\n\n            case 0x08: // boolean\n            {\n                return sax->boolean(get() != 0);\n            }\n\n            case 0x0A: // null\n            {\n                return sax->null();\n            }\n\n            case 0x10: // int32\n            {\n                std::int32_t value{};\n                return get_number<std::int32_t, true>(input_format_t::bson, value) && sax->number_integer(value);\n            }\n\n            case 0x12: // int64\n            {\n                std::int64_t value{};\n                return get_number<std::int64_t, true>(input_format_t::bson, value) && sax->number_integer(value);\n            }\n\n            case 0x11: // uint64\n            {\n                std::uint64_t value{};\n                return get_number<std::uint64_t, true>(input_format_t::bson, value) && sax->number_unsigned(value);\n            }\n\n            default: // anything else not supported (yet)\n            {\n                std::array<char, 3> cr{{}};\n                static_cast<void>((std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(element_type))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                const std::string cr_str{cr.data()};\n                return sax->parse_error(element_type_parse_position, cr_str,\n                                        parse_error::create(114, element_type_parse_position, concat(\"Unsupported BSON record type 0x\", cr_str), nullptr));\n            }\n        }\n    }\n\n    /*!\n    @brief Read a BSON element list (as specified in the BSON-spec)\n\n    The same binary layout is used for objects and arrays, hence it must be\n    indicated with the argument @a is_array which one is expected\n    (true --> array, false --> object).\n\n    @param[in] is_array Determines if the element list being read is to be\n                        treated as an object (@a is_array == false), or as an\n                        array (@a is_array == true).\n    @return whether a valid BSON-object/array was passed to the SAX parser\n    */\n    bool parse_bson_element_list(const bool is_array)\n    {\n        string_t key;\n\n        while (auto element_type = get())\n        {\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::bson, \"element list\")))\n            {\n                return false;\n            }\n\n            const std::size_t element_type_parse_position = chars_read;\n            if (JSON_HEDLEY_UNLIKELY(!get_bson_cstr(key)))\n            {\n                return false;\n            }\n\n            if (!is_array && !sax->key(key))\n            {\n                return false;\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_internal(element_type, element_type_parse_position)))\n            {\n                return false;\n            }\n\n            // get_bson_cstr only appends\n            key.clear();\n        }\n\n        return true;\n    }\n\n    /*!\n    @brief Reads an array from the BSON input and passes it to the SAX-parser.\n    @return whether a valid BSON-array was passed to the SAX parser\n    */\n    bool parse_bson_array()\n    {\n        std::int32_t document_size{};\n        get_number<std::int32_t, true>(input_format_t::bson, document_size);\n\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))\n        {\n            return false;\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/true)))\n        {\n            return false;\n        }\n\n        return sax->end_array();\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true) or whether the last read character should\n                         be considered instead (false)\n    @param[in] tag_handler how CBOR tags should be treated\n\n    @return whether a valid CBOR value was passed to the SAX parser\n    */\n    bool parse_cbor_internal(const bool get_char,\n                             const cbor_tag_handler_t tag_handler)\n    {\n        switch (get_char ? get() : current)\n        {\n            // EOF\n            case char_traits<char_type>::eof():\n                return unexpect_eof(input_format_t::cbor, \"value\");\n\n            // Integer 0x00..0x17 (0..23)\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            case 0x18: // Unsigned integer (one-byte uint8_t follows)\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x19: // Unsigned integer (two-byte uint16_t follows)\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x1A: // Unsigned integer (four-byte uint32_t follows)\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            case 0x1B: // Unsigned integer (eight-byte uint64_t follows)\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_unsigned(number);\n            }\n\n            // Negative integer -1-0x00..-1-0x17 (-1..-24)\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n                return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));\n\n            case 0x38: // Negative integer (one-byte uint8_t follows)\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x39: // Negative integer -1-n (two-byte uint16_t follows)\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1) - number);\n            }\n\n            case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::cbor, number) && sax->number_integer(static_cast<number_integer_t>(-1)\n                        - static_cast<number_integer_t>(number));\n            }\n\n            // Binary data (0x00..0x17 bytes follow)\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58: // Binary data (one-byte uint8_t for n follows)\n            case 0x59: // Binary data (two-byte uint16_t for n follow)\n            case 0x5A: // Binary data (four-byte uint32_t for n follow)\n            case 0x5B: // Binary data (eight-byte uint64_t for n follow)\n            case 0x5F: // Binary data (indefinite length)\n            {\n                binary_t b;\n                return get_cbor_binary(b) && sax->binary(b);\n            }\n\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                string_t s;\n                return get_cbor_string(s) && sax->string(s);\n            }\n\n            // array (0x00..0x17 data items follow)\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n                return get_cbor_array(\n                           conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);\n\n            case 0x98: // array (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x99: // array (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9A: // array (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9B: // array (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_array(conditional_static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0x9F: // array (indefinite length)\n                return get_cbor_array(detail::unknown_size(), tag_handler);\n\n            // map (0x00..0x17 pairs of data items follow)\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n                return get_cbor_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu), tag_handler);\n\n            case 0xB8: // map (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xB9: // map (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBA: // map (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBB: // map (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_cbor_object(conditional_static_cast<std::size_t>(len), tag_handler);\n            }\n\n            case 0xBF: // map (indefinite length)\n                return get_cbor_object(detail::unknown_size(), tag_handler);\n\n            case 0xC6: // tagged item\n            case 0xC7:\n            case 0xC8:\n            case 0xC9:\n            case 0xCA:\n            case 0xCB:\n            case 0xCC:\n            case 0xCD:\n            case 0xCE:\n            case 0xCF:\n            case 0xD0:\n            case 0xD1:\n            case 0xD2:\n            case 0xD3:\n            case 0xD4:\n            case 0xD8: // tagged item (1 bytes follow)\n            case 0xD9: // tagged item (2 bytes follow)\n            case 0xDA: // tagged item (4 bytes follow)\n            case 0xDB: // tagged item (8 bytes follow)\n            {\n                switch (tag_handler)\n                {\n                    case cbor_tag_handler_t::error:\n                    {\n                        auto last_token = get_token_string();\n                        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                                exception_message(input_format_t::cbor, concat(\"invalid byte: 0x\", last_token), \"value\"), nullptr));\n                    }\n\n                    case cbor_tag_handler_t::ignore:\n                    {\n                        // ignore binary subtype\n                        switch (current)\n                        {\n                            case 0xD8:\n                            {\n                                std::uint8_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            case 0xD9:\n                            {\n                                std::uint16_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            case 0xDA:\n                            {\n                                std::uint32_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            case 0xDB:\n                            {\n                                std::uint64_t subtype_to_ignore{};\n                                get_number(input_format_t::cbor, subtype_to_ignore);\n                                break;\n                            }\n                            default:\n                                break;\n                        }\n                        return parse_cbor_internal(true, tag_handler);\n                    }\n\n                    case cbor_tag_handler_t::store:\n                    {\n                        binary_t b;\n                        // use binary subtype and store in binary container\n                        switch (current)\n                        {\n                            case 0xD8:\n                            {\n                                std::uint8_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            case 0xD9:\n                            {\n                                std::uint16_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            case 0xDA:\n                            {\n                                std::uint32_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            case 0xDB:\n                            {\n                                std::uint64_t subtype{};\n                                get_number(input_format_t::cbor, subtype);\n                                b.set_subtype(detail::conditional_static_cast<typename binary_t::subtype_type>(subtype));\n                                break;\n                            }\n                            default:\n                                return parse_cbor_internal(true, tag_handler);\n                        }\n                        get();\n                        return get_cbor_binary(b) && sax->binary(b);\n                    }\n\n                    default:                 // LCOV_EXCL_LINE\n                        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n                        return false;        // LCOV_EXCL_LINE\n                }\n            }\n\n            case 0xF4: // false\n                return sax->boolean(false);\n\n            case 0xF5: // true\n                return sax->boolean(true);\n\n            case 0xF6: // null\n                return sax->null();\n\n            case 0xF9: // Half-Precision Float (two-byte IEEE 754)\n            {\n                const auto byte1_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n                const auto byte2_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"number\")))\n                {\n                    return false;\n                }\n\n                const auto byte1 = static_cast<unsigned char>(byte1_raw);\n                const auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n                // code from RFC 7049, Appendix D, Figure 3:\n                // As half-precision floating-point numbers were only added\n                // to IEEE 754 in 2008, today's programming platforms often\n                // still only have limited support for them. It is very\n                // easy to include at least decoding support for them even\n                // without such support. An example of a small decoder for\n                // half-precision floating-point numbers in the C language\n                // is shown in Fig. 3.\n                const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);\n                const double val = [&half]\n                {\n                    const int exp = (half >> 10u) & 0x1Fu;\n                    const unsigned int mant = half & 0x3FFu;\n                    JSON_ASSERT(0 <= exp&& exp <= 32);\n                    JSON_ASSERT(mant <= 1024);\n                    switch (exp)\n                    {\n                        case 0:\n                            return std::ldexp(mant, -24);\n                        case 31:\n                            return (mant == 0)\n                            ? std::numeric_limits<double>::infinity()\n                            : std::numeric_limits<double>::quiet_NaN();\n                        default:\n                            return std::ldexp(mant + 1024, exp - 25);\n                    }\n                }();\n                return sax->number_float((half & 0x8000u) != 0\n                                         ? static_cast<number_float_t>(-val)\n                                         : static_cast<number_float_t>(val), \"\");\n            }\n\n            case 0xFA: // Single-Precision Float (four-byte IEEE 754)\n            {\n                float number{};\n                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xFB: // Double-Precision Float (eight-byte IEEE 754)\n            {\n                double number{};\n                return get_number(input_format_t::cbor, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            default: // anything else (0xFF is handled inside the other types)\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                        exception_message(input_format_t::cbor, concat(\"invalid byte: 0x\", last_token), \"value\"), nullptr));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n    Additionally, CBOR's strings with indefinite lengths are supported.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_cbor_string(string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // UTF-8 string (0x00..0x17 bytes follow)\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            {\n                return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0x78: // UTF-8 string (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x79: // UTF-8 string (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) && get_string(input_format_t::cbor, len, result);\n            }\n\n            case 0x7F: // UTF-8 string (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    string_t chunk;\n                    if (!get_cbor_string(chunk))\n                    {\n                        return false;\n                    }\n                    result.append(chunk);\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,\n                                        exception_message(input_format_t::cbor, concat(\"expected length specification (0x60-0x7B) or indefinite string type (0x7F); last byte: 0x\", last_token), \"string\"), nullptr));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a CBOR byte array\n\n    This function first reads starting bytes to determine the expected\n    byte array length and then copies this number of bytes into the byte array.\n    Additionally, CBOR's byte arrays with indefinite lengths are supported.\n\n    @param[out] result  created byte array\n\n    @return whether byte array creation completed\n    */\n    bool get_cbor_binary(binary_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::cbor, \"binary\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // Binary data (0x00..0x17 bytes follow)\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            {\n                return get_binary(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0x58: // Binary data (one-byte uint8_t for n follows)\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x59: // Binary data (two-byte uint16_t for n follow)\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5A: // Binary data (four-byte uint32_t for n follow)\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5B: // Binary data (eight-byte uint64_t for n follow)\n            {\n                std::uint64_t len{};\n                return get_number(input_format_t::cbor, len) &&\n                       get_binary(input_format_t::cbor, len, result);\n            }\n\n            case 0x5F: // Binary data (indefinite length)\n            {\n                while (get() != 0xFF)\n                {\n                    binary_t chunk;\n                    if (!get_cbor_binary(chunk))\n                    {\n                        return false;\n                    }\n                    result.insert(result.end(), chunk.begin(), chunk.end());\n                }\n                return true;\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,\n                                        exception_message(input_format_t::cbor, concat(\"expected length specification (0x40-0x5B) or indefinite binary array type (0x5F); last byte: 0x\", last_token), \"binary\"), nullptr));\n            }\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array or detail::unknown_size() for an\n                    array of indefinite size\n    @param[in] tag_handler how CBOR tags should be treated\n    @return whether array creation completed\n    */\n    bool get_cbor_array(const std::size_t len,\n                        const cbor_tag_handler_t tag_handler)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))\n        {\n            return false;\n        }\n\n        if (len != detail::unknown_size())\n        {\n            for (std::size_t i = 0; i < len; ++i)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                {\n                    return false;\n                }\n            }\n        }\n        else\n        {\n            while (get() != 0xFF)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(false, tag_handler)))\n                {\n                    return false;\n                }\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object or detail::unknown_size() for an\n                    object of indefinite size\n    @param[in] tag_handler how CBOR tags should be treated\n    @return whether object creation completed\n    */\n    bool get_cbor_object(const std::size_t len,\n                         const cbor_tag_handler_t tag_handler)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))\n        {\n            return false;\n        }\n\n        if (len != 0)\n        {\n            string_t key;\n            if (len != detail::unknown_size())\n            {\n                for (std::size_t i = 0; i < len; ++i)\n                {\n                    get();\n                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n\n                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                while (get() != 0xFF)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_cbor_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n\n                    if (JSON_HEDLEY_UNLIKELY(!parse_cbor_internal(true, tag_handler)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    /*!\n    @return whether a valid MessagePack value was passed to the SAX parser\n    */\n    bool parse_msgpack_internal()\n    {\n        switch (get())\n        {\n            // EOF\n            case char_traits<char_type>::eof():\n                return unexpect_eof(input_format_t::msgpack, \"value\");\n\n            // positive fixint\n            case 0x00:\n            case 0x01:\n            case 0x02:\n            case 0x03:\n            case 0x04:\n            case 0x05:\n            case 0x06:\n            case 0x07:\n            case 0x08:\n            case 0x09:\n            case 0x0A:\n            case 0x0B:\n            case 0x0C:\n            case 0x0D:\n            case 0x0E:\n            case 0x0F:\n            case 0x10:\n            case 0x11:\n            case 0x12:\n            case 0x13:\n            case 0x14:\n            case 0x15:\n            case 0x16:\n            case 0x17:\n            case 0x18:\n            case 0x19:\n            case 0x1A:\n            case 0x1B:\n            case 0x1C:\n            case 0x1D:\n            case 0x1E:\n            case 0x1F:\n            case 0x20:\n            case 0x21:\n            case 0x22:\n            case 0x23:\n            case 0x24:\n            case 0x25:\n            case 0x26:\n            case 0x27:\n            case 0x28:\n            case 0x29:\n            case 0x2A:\n            case 0x2B:\n            case 0x2C:\n            case 0x2D:\n            case 0x2E:\n            case 0x2F:\n            case 0x30:\n            case 0x31:\n            case 0x32:\n            case 0x33:\n            case 0x34:\n            case 0x35:\n            case 0x36:\n            case 0x37:\n            case 0x38:\n            case 0x39:\n            case 0x3A:\n            case 0x3B:\n            case 0x3C:\n            case 0x3D:\n            case 0x3E:\n            case 0x3F:\n            case 0x40:\n            case 0x41:\n            case 0x42:\n            case 0x43:\n            case 0x44:\n            case 0x45:\n            case 0x46:\n            case 0x47:\n            case 0x48:\n            case 0x49:\n            case 0x4A:\n            case 0x4B:\n            case 0x4C:\n            case 0x4D:\n            case 0x4E:\n            case 0x4F:\n            case 0x50:\n            case 0x51:\n            case 0x52:\n            case 0x53:\n            case 0x54:\n            case 0x55:\n            case 0x56:\n            case 0x57:\n            case 0x58:\n            case 0x59:\n            case 0x5A:\n            case 0x5B:\n            case 0x5C:\n            case 0x5D:\n            case 0x5E:\n            case 0x5F:\n            case 0x60:\n            case 0x61:\n            case 0x62:\n            case 0x63:\n            case 0x64:\n            case 0x65:\n            case 0x66:\n            case 0x67:\n            case 0x68:\n            case 0x69:\n            case 0x6A:\n            case 0x6B:\n            case 0x6C:\n            case 0x6D:\n            case 0x6E:\n            case 0x6F:\n            case 0x70:\n            case 0x71:\n            case 0x72:\n            case 0x73:\n            case 0x74:\n            case 0x75:\n            case 0x76:\n            case 0x77:\n            case 0x78:\n            case 0x79:\n            case 0x7A:\n            case 0x7B:\n            case 0x7C:\n            case 0x7D:\n            case 0x7E:\n            case 0x7F:\n                return sax->number_unsigned(static_cast<number_unsigned_t>(current));\n\n            // fixmap\n            case 0x80:\n            case 0x81:\n            case 0x82:\n            case 0x83:\n            case 0x84:\n            case 0x85:\n            case 0x86:\n            case 0x87:\n            case 0x88:\n            case 0x89:\n            case 0x8A:\n            case 0x8B:\n            case 0x8C:\n            case 0x8D:\n            case 0x8E:\n            case 0x8F:\n                return get_msgpack_object(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n            // fixarray\n            case 0x90:\n            case 0x91:\n            case 0x92:\n            case 0x93:\n            case 0x94:\n            case 0x95:\n            case 0x96:\n            case 0x97:\n            case 0x98:\n            case 0x99:\n            case 0x9A:\n            case 0x9B:\n            case 0x9C:\n            case 0x9D:\n            case 0x9E:\n            case 0x9F:\n                return get_msgpack_array(conditional_static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));\n\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            case 0xD9: // str 8\n            case 0xDA: // str 16\n            case 0xDB: // str 32\n            {\n                string_t s;\n                return get_msgpack_string(s) && sax->string(s);\n            }\n\n            case 0xC0: // nil\n                return sax->null();\n\n            case 0xC2: // false\n                return sax->boolean(false);\n\n            case 0xC3: // true\n                return sax->boolean(true);\n\n            case 0xC4: // bin 8\n            case 0xC5: // bin 16\n            case 0xC6: // bin 32\n            case 0xC7: // ext 8\n            case 0xC8: // ext 16\n            case 0xC9: // ext 32\n            case 0xD4: // fixext 1\n            case 0xD5: // fixext 2\n            case 0xD6: // fixext 4\n            case 0xD7: // fixext 8\n            case 0xD8: // fixext 16\n            {\n                binary_t b;\n                return get_msgpack_binary(b) && sax->binary(b);\n            }\n\n            case 0xCA: // float 32\n            {\n                float number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCB: // float 64\n            {\n                double number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 0xCC: // uint 8\n            {\n                std::uint8_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCD: // uint 16\n            {\n                std::uint16_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCE: // uint 32\n            {\n                std::uint32_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xCF: // uint 64\n            {\n                std::uint64_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_unsigned(number);\n            }\n\n            case 0xD0: // int 8\n            {\n                std::int8_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD1: // int 16\n            {\n                std::int16_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD2: // int 32\n            {\n                std::int32_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xD3: // int 64\n            {\n                std::int64_t number{};\n                return get_number(input_format_t::msgpack, number) && sax->number_integer(number);\n            }\n\n            case 0xDC: // array 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_array(static_cast<std::size_t>(len));\n            }\n\n            case 0xDD: // array 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_array(conditional_static_cast<std::size_t>(len));\n            }\n\n            case 0xDE: // map 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_object(static_cast<std::size_t>(len));\n            }\n\n            case 0xDF: // map 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_msgpack_object(conditional_static_cast<std::size_t>(len));\n            }\n\n            // negative fixint\n            case 0xE0:\n            case 0xE1:\n            case 0xE2:\n            case 0xE3:\n            case 0xE4:\n            case 0xE5:\n            case 0xE6:\n            case 0xE7:\n            case 0xE8:\n            case 0xE9:\n            case 0xEA:\n            case 0xEB:\n            case 0xEC:\n            case 0xED:\n            case 0xEE:\n            case 0xEF:\n            case 0xF0:\n            case 0xF1:\n            case 0xF2:\n            case 0xF3:\n            case 0xF4:\n            case 0xF5:\n            case 0xF6:\n            case 0xF7:\n            case 0xF8:\n            case 0xF9:\n            case 0xFA:\n            case 0xFB:\n            case 0xFC:\n            case 0xFD:\n            case 0xFE:\n            case 0xFF:\n                return sax->number_integer(static_cast<std::int8_t>(current));\n\n            default: // anything else\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                        exception_message(input_format_t::msgpack, concat(\"invalid byte: 0x\", last_token), \"value\"), nullptr));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack string\n\n    This function first reads starting bytes to determine the expected\n    string length and then copies this number of bytes into a string.\n\n    @param[out] result  created string\n\n    @return whether string creation completed\n    */\n    bool get_msgpack_string(string_t& result)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format_t::msgpack, \"string\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            // fixstr\n            case 0xA0:\n            case 0xA1:\n            case 0xA2:\n            case 0xA3:\n            case 0xA4:\n            case 0xA5:\n            case 0xA6:\n            case 0xA7:\n            case 0xA8:\n            case 0xA9:\n            case 0xAA:\n            case 0xAB:\n            case 0xAC:\n            case 0xAD:\n            case 0xAE:\n            case 0xAF:\n            case 0xB0:\n            case 0xB1:\n            case 0xB2:\n            case 0xB3:\n            case 0xB4:\n            case 0xB5:\n            case 0xB6:\n            case 0xB7:\n            case 0xB8:\n            case 0xB9:\n            case 0xBA:\n            case 0xBB:\n            case 0xBC:\n            case 0xBD:\n            case 0xBE:\n            case 0xBF:\n            {\n                return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);\n            }\n\n            case 0xD9: // str 8\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDA: // str 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            case 0xDB: // str 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) && get_string(input_format_t::msgpack, len, result);\n            }\n\n            default:\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,\n                                        exception_message(input_format_t::msgpack, concat(\"expected length specification (0xA0-0xBF, 0xD9-0xDB); last byte: 0x\", last_token), \"string\"), nullptr));\n            }\n        }\n    }\n\n    /*!\n    @brief reads a MessagePack byte array\n\n    This function first reads starting bytes to determine the expected\n    byte array length and then copies this number of bytes into a byte array.\n\n    @param[out] result  created byte array\n\n    @return whether byte array creation completed\n    */\n    bool get_msgpack_binary(binary_t& result)\n    {\n        // helper function to set the subtype\n        auto assign_and_return_true = [&result](std::int8_t subtype)\n        {\n            result.set_subtype(static_cast<std::uint8_t>(subtype));\n            return true;\n        };\n\n        switch (current)\n        {\n            case 0xC4: // bin 8\n            {\n                std::uint8_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC5: // bin 16\n            {\n                std::uint16_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC6: // bin 32\n            {\n                std::uint32_t len{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_binary(input_format_t::msgpack, len, result);\n            }\n\n            case 0xC7: // ext 8\n            {\n                std::uint8_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xC8: // ext 16\n            {\n                std::uint16_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xC9: // ext 32\n            {\n                std::uint32_t len{};\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, len) &&\n                       get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, len, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD4: // fixext 1\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 1, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD5: // fixext 2\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 2, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD6: // fixext 4\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 4, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD7: // fixext 8\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 8, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            case 0xD8: // fixext 16\n            {\n                std::int8_t subtype{};\n                return get_number(input_format_t::msgpack, subtype) &&\n                       get_binary(input_format_t::msgpack, 16, result) &&\n                       assign_and_return_true(subtype);\n            }\n\n            default:           // LCOV_EXCL_LINE\n                return false;  // LCOV_EXCL_LINE\n        }\n    }\n\n    /*!\n    @param[in] len  the length of the array\n    @return whether array creation completed\n    */\n    bool get_msgpack_array(const std::size_t len)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(len)))\n        {\n            return false;\n        }\n\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))\n            {\n                return false;\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @param[in] len  the length of the object\n    @return whether object creation completed\n    */\n    bool get_msgpack_object(const std::size_t len)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(len)))\n        {\n            return false;\n        }\n\n        string_t key;\n        for (std::size_t i = 0; i < len; ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!get_msgpack_string(key) || !sax->key(key)))\n            {\n                return false;\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!parse_msgpack_internal()))\n            {\n                return false;\n            }\n            key.clear();\n        }\n\n        return sax->end_object();\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    /*!\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether a valid UBJSON value was passed to the SAX parser\n    */\n    bool parse_ubjson_internal(const bool get_char = true)\n    {\n        return get_ubjson_value(get_char ? get_ignore_noop() : current);\n    }\n\n    /*!\n    @brief reads a UBJSON string\n\n    This function is either called after reading the 'S' byte explicitly\n    indicating a string, or in case of an object key where the 'S' byte can be\n    left out.\n\n    @param[out] result   created string\n    @param[in] get_char  whether a new character should be retrieved from the\n                         input (true, default) or whether the last read\n                         character should be considered instead\n\n    @return whether string creation completed\n    */\n    bool get_ubjson_string(string_t& result, const bool get_char = true)\n    {\n        if (get_char)\n        {\n            get();  // TODO(niels): may we ignore N here?\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"value\")))\n        {\n            return false;\n        }\n\n        switch (current)\n        {\n            case 'U':\n            {\n                std::uint8_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'i':\n            {\n                std::int8_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'I':\n            {\n                std::int16_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'l':\n            {\n                std::int32_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'L':\n            {\n                std::int64_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'u':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint16_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'm':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint32_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            case 'M':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint64_t len{};\n                return get_number(input_format, len) && get_string(input_format, len, result);\n            }\n\n            default:\n                break;\n        }\n        auto last_token = get_token_string();\n        std::string message;\n\n        if (input_format != input_format_t::bjdata)\n        {\n            message = \"expected length type specification (U, i, I, l, L); last byte: 0x\" + last_token;\n        }\n        else\n        {\n            message = \"expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x\" + last_token;\n        }\n        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, \"string\"), nullptr));\n    }\n\n    /*!\n    @param[out] dim  an integer vector storing the ND array dimensions\n    @return whether reading ND array size vector is successful\n    */\n    bool get_ubjson_ndarray_size(std::vector<size_t>& dim)\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        size_t dimlen = 0;\n        bool no_ndarray = true;\n\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type, no_ndarray)))\n        {\n            return false;\n        }\n\n        if (size_and_type.first != npos)\n        {\n            if (size_and_type.second != 0)\n            {\n                if (size_and_type.second != 'N')\n                {\n                    for (std::size_t i = 0; i < size_and_type.first; ++i)\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, size_and_type.second)))\n                        {\n                            return false;\n                        }\n                        dim.push_back(dimlen);\n                    }\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray)))\n                    {\n                        return false;\n                    }\n                    dim.push_back(dimlen);\n                }\n            }\n        }\n        else\n        {\n            while (current != ']')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_value(dimlen, no_ndarray, current)))\n                {\n                    return false;\n                }\n                dim.push_back(dimlen);\n                get_ignore_noop();\n            }\n        }\n        return true;\n    }\n\n    /*!\n    @param[out] result  determined size\n    @param[in,out] is_ndarray  for input, `true` means already inside an ndarray vector\n                               or ndarray dimension is not allowed; `false` means ndarray\n                               is allowed; for output, `true` means an ndarray is found;\n                               is_ndarray can only return `true` when its initial value\n                               is `false`\n    @param[in] prefix  type marker if already read, otherwise set to 0\n\n    @return whether size determination completed\n    */\n    bool get_ubjson_size_value(std::size_t& result, bool& is_ndarray, char_int_type prefix = 0)\n    {\n        if (prefix == 0)\n        {\n            prefix = get_ignore_noop();\n        }\n\n        switch (prefix)\n        {\n            case 'U':\n            {\n                std::uint8_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'i':\n            {\n                std::int8_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                if (number < 0)\n                {\n                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,\n                                            exception_message(input_format, \"count in an optimized container must be positive\", \"size\"), nullptr));\n                }\n                result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char\n                return true;\n            }\n\n            case 'I':\n            {\n                std::int16_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                if (number < 0)\n                {\n                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,\n                                            exception_message(input_format, \"count in an optimized container must be positive\", \"size\"), nullptr));\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'l':\n            {\n                std::int32_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                if (number < 0)\n                {\n                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,\n                                            exception_message(input_format, \"count in an optimized container must be positive\", \"size\"), nullptr));\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'L':\n            {\n                std::int64_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                if (number < 0)\n                {\n                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,\n                                            exception_message(input_format, \"count in an optimized container must be positive\", \"size\"), nullptr));\n                }\n                if (!value_in_range_of<std::size_t>(number))\n                {\n                    return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,\n                                            exception_message(input_format, \"integer value overflow\", \"size\"), nullptr));\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'u':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint16_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                result = static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'm':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint32_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                result = conditional_static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case 'M':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint64_t number{};\n                if (JSON_HEDLEY_UNLIKELY(!get_number(input_format, number)))\n                {\n                    return false;\n                }\n                if (!value_in_range_of<std::size_t>(number))\n                {\n                    return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408,\n                                            exception_message(input_format, \"integer value overflow\", \"size\"), nullptr));\n                }\n                result = detail::conditional_static_cast<std::size_t>(number);\n                return true;\n            }\n\n            case '[':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                if (is_ndarray) // ndarray dimensional vector can only contain integers, and can not embed another array\n                {\n                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read, exception_message(input_format, \"ndarray dimensional vector is not allowed\", \"size\"), nullptr));\n                }\n                std::vector<size_t> dim;\n                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_ndarray_size(dim)))\n                {\n                    return false;\n                }\n                if (dim.size() == 1 || (dim.size() == 2 && dim.at(0) == 1)) // return normal array size if 1D row vector\n                {\n                    result = dim.at(dim.size() - 1);\n                    return true;\n                }\n                if (!dim.empty())  // if ndarray, convert to an object in JData annotated array format\n                {\n                    for (auto i : dim) // test if any dimension in an ndarray is 0, if so, return a 1D empty container\n                    {\n                        if ( i == 0 )\n                        {\n                            result = 0;\n                            return true;\n                        }\n                    }\n\n                    string_t key = \"_ArraySize_\";\n                    if (JSON_HEDLEY_UNLIKELY(!sax->start_object(3) || !sax->key(key) || !sax->start_array(dim.size())))\n                    {\n                        return false;\n                    }\n                    result = 1;\n                    for (auto i : dim)\n                    {\n                        result *= i;\n                        if (result == 0 || result == npos) // because dim elements shall not have zeros, result = 0 means overflow happened; it also can't be npos as it is used to initialize size in get_ubjson_size_type()\n                        {\n                            return sax->parse_error(chars_read, get_token_string(), out_of_range::create(408, exception_message(input_format, \"excessive ndarray size caused overflow\", \"size\"), nullptr));\n                        }\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(static_cast<number_unsigned_t>(i))))\n                        {\n                            return false;\n                        }\n                    }\n                    is_ndarray = true;\n                    return sax->end_array();\n                }\n                result = 0;\n                return true;\n            }\n\n            default:\n                break;\n        }\n        auto last_token = get_token_string();\n        std::string message;\n\n        if (input_format != input_format_t::bjdata)\n        {\n            message = \"expected length type specification (U, i, I, l, L) after '#'; last byte: 0x\" + last_token;\n        }\n        else\n        {\n            message = \"expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x\" + last_token;\n        }\n        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, \"size\"), nullptr));\n    }\n\n    /*!\n    @brief determine the type and size for a container\n\n    In the optimized UBJSON format, a type and a size can be provided to allow\n    for a more compact representation.\n\n    @param[out] result  pair of the size and the type\n    @param[in] inside_ndarray  whether the parser is parsing an ND array dimensional vector\n\n    @return whether pair creation completed\n    */\n    bool get_ubjson_size_type(std::pair<std::size_t, char_int_type>& result, bool inside_ndarray = false)\n    {\n        result.first = npos; // size\n        result.second = 0; // type\n        bool is_ndarray = false;\n\n        get_ignore_noop();\n\n        if (current == '$')\n        {\n            result.second = get();  // must not ignore 'N', because 'N' maybe the type\n            if (input_format == input_format_t::bjdata\n                    && JSON_HEDLEY_UNLIKELY(std::binary_search(bjd_optimized_type_markers.begin(), bjd_optimized_type_markers.end(), result.second)))\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                        exception_message(input_format, concat(\"marker 0x\", last_token, \" is not a permitted optimized array type\"), \"type\"), nullptr));\n            }\n\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"type\")))\n            {\n                return false;\n            }\n\n            get_ignore_noop();\n            if (JSON_HEDLEY_UNLIKELY(current != '#'))\n            {\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"value\")))\n                {\n                    return false;\n                }\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                        exception_message(input_format, concat(\"expected '#' after type information; last byte: 0x\", last_token), \"size\"), nullptr));\n            }\n\n            const bool is_error = get_ubjson_size_value(result.first, is_ndarray);\n            if (input_format == input_format_t::bjdata && is_ndarray)\n            {\n                if (inside_ndarray)\n                {\n                    return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,\n                                            exception_message(input_format, \"ndarray can not be recursive\", \"size\"), nullptr));\n                }\n                result.second |= (1 << 8); // use bit 8 to indicate ndarray, all UBJSON and BJData markers should be ASCII letters\n            }\n            return is_error;\n        }\n\n        if (current == '#')\n        {\n            const bool is_error = get_ubjson_size_value(result.first, is_ndarray);\n            if (input_format == input_format_t::bjdata && is_ndarray)\n            {\n                return sax->parse_error(chars_read, get_token_string(), parse_error::create(112, chars_read,\n                                        exception_message(input_format, \"ndarray requires both type and size\", \"size\"), nullptr));\n            }\n            return is_error;\n        }\n\n        return true;\n    }\n\n    /*!\n    @param prefix  the previously read or set type prefix\n    @return whether value creation completed\n    */\n    bool get_ubjson_value(const char_int_type prefix)\n    {\n        switch (prefix)\n        {\n            case char_traits<char_type>::eof():  // EOF\n                return unexpect_eof(input_format, \"value\");\n\n            case 'T':  // true\n                return sax->boolean(true);\n            case 'F':  // false\n                return sax->boolean(false);\n\n            case 'Z':  // null\n                return sax->null();\n\n            case 'B':  // byte\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint8_t number{};\n                return get_number(input_format, number) && sax->number_unsigned(number);\n            }\n\n            case 'U':\n            {\n                std::uint8_t number{};\n                return get_number(input_format, number) && sax->number_unsigned(number);\n            }\n\n            case 'i':\n            {\n                std::int8_t number{};\n                return get_number(input_format, number) && sax->number_integer(number);\n            }\n\n            case 'I':\n            {\n                std::int16_t number{};\n                return get_number(input_format, number) && sax->number_integer(number);\n            }\n\n            case 'l':\n            {\n                std::int32_t number{};\n                return get_number(input_format, number) && sax->number_integer(number);\n            }\n\n            case 'L':\n            {\n                std::int64_t number{};\n                return get_number(input_format, number) && sax->number_integer(number);\n            }\n\n            case 'u':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint16_t number{};\n                return get_number(input_format, number) && sax->number_unsigned(number);\n            }\n\n            case 'm':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint32_t number{};\n                return get_number(input_format, number) && sax->number_unsigned(number);\n            }\n\n            case 'M':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                std::uint64_t number{};\n                return get_number(input_format, number) && sax->number_unsigned(number);\n            }\n\n            case 'h':\n            {\n                if (input_format != input_format_t::bjdata)\n                {\n                    break;\n                }\n                const auto byte1_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"number\")))\n                {\n                    return false;\n                }\n                const auto byte2_raw = get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"number\")))\n                {\n                    return false;\n                }\n\n                const auto byte1 = static_cast<unsigned char>(byte1_raw);\n                const auto byte2 = static_cast<unsigned char>(byte2_raw);\n\n                // code from RFC 7049, Appendix D, Figure 3:\n                // As half-precision floating-point numbers were only added\n                // to IEEE 754 in 2008, today's programming platforms often\n                // still only have limited support for them. It is very\n                // easy to include at least decoding support for them even\n                // without such support. An example of a small decoder for\n                // half-precision floating-point numbers in the C language\n                // is shown in Fig. 3.\n                const auto half = static_cast<unsigned int>((byte2 << 8u) + byte1);\n                const double val = [&half]\n                {\n                    const int exp = (half >> 10u) & 0x1Fu;\n                    const unsigned int mant = half & 0x3FFu;\n                    JSON_ASSERT(0 <= exp&& exp <= 32);\n                    JSON_ASSERT(mant <= 1024);\n                    switch (exp)\n                    {\n                        case 0:\n                            return std::ldexp(mant, -24);\n                        case 31:\n                            return (mant == 0)\n                            ? std::numeric_limits<double>::infinity()\n                            : std::numeric_limits<double>::quiet_NaN();\n                        default:\n                            return std::ldexp(mant + 1024, exp - 25);\n                    }\n                }();\n                return sax->number_float((half & 0x8000u) != 0\n                                         ? static_cast<number_float_t>(-val)\n                                         : static_cast<number_float_t>(val), \"\");\n            }\n\n            case 'd':\n            {\n                float number{};\n                return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'D':\n            {\n                double number{};\n                return get_number(input_format, number) && sax->number_float(static_cast<number_float_t>(number), \"\");\n            }\n\n            case 'H':\n            {\n                return get_ubjson_high_precision_number();\n            }\n\n            case 'C':  // char\n            {\n                get();\n                if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"char\")))\n                {\n                    return false;\n                }\n                if (JSON_HEDLEY_UNLIKELY(current > 127))\n                {\n                    auto last_token = get_token_string();\n                    return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,\n                                            exception_message(input_format, concat(\"byte after 'C' must be in range 0x00..0x7F; last byte: 0x\", last_token), \"char\"), nullptr));\n                }\n                string_t s(1, static_cast<typename string_t::value_type>(current));\n                return sax->string(s);\n            }\n\n            case 'S':  // string\n            {\n                string_t s;\n                return get_ubjson_string(s) && sax->string(s);\n            }\n\n            case '[':  // array\n                return get_ubjson_array();\n\n            case '{':  // object\n                return get_ubjson_object();\n\n            default: // anything else\n                break;\n        }\n        auto last_token = get_token_string();\n        return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read, exception_message(input_format, \"invalid byte: 0x\" + last_token, \"value\"), nullptr));\n    }\n\n    /*!\n    @return whether array creation completed\n    */\n    bool get_ubjson_array()\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        // if bit-8 of size_and_type.second is set to 1, encode bjdata ndarray as an object in JData annotated array format (https://github.com/NeuroJSON/jdata):\n        // {\"_ArrayType_\" : \"typeid\", \"_ArraySize_\" : [n1, n2, ...], \"_ArrayData_\" : [v1, v2, ...]}\n\n        if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)\n        {\n            size_and_type.second &= ~(static_cast<char_int_type>(1) << 8);  // use bit 8 to indicate ndarray, here we remove the bit to restore the type marker\n            auto it = std::lower_bound(bjd_types_map.begin(), bjd_types_map.end(), size_and_type.second, [](const bjd_type & p, char_int_type t)\n            {\n                return p.first < t;\n            });\n            string_t key = \"_ArrayType_\";\n            if (JSON_HEDLEY_UNLIKELY(it == bjd_types_map.end() || it->first != size_and_type.second))\n            {\n                auto last_token = get_token_string();\n                return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                        exception_message(input_format, \"invalid byte: 0x\" + last_token, \"type\"), nullptr));\n            }\n\n            string_t type = it->second; // sax->string() takes a reference\n            if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->string(type)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second == 'C' || size_and_type.second == 'B')\n            {\n                size_and_type.second = 'U';\n            }\n\n            key = \"_ArrayData_\";\n            if (JSON_HEDLEY_UNLIKELY(!sax->key(key) || !sax->start_array(size_and_type.first) ))\n            {\n                return false;\n            }\n\n            for (std::size_t i = 0; i < size_and_type.first; ++i)\n            {\n                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                {\n                    return false;\n                }\n            }\n\n            return (sax->end_array() && sax->end_object());\n        }\n\n        // If BJData type marker is 'B' decode as binary\n        if (input_format == input_format_t::bjdata && size_and_type.first != npos && size_and_type.second == 'B')\n        {\n            binary_t result;\n            return get_binary(input_format, size_and_type.first, result) && sax->binary(result);\n        }\n\n        if (size_and_type.first != npos)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                if (size_and_type.second != 'N')\n                {\n                    for (std::size_t i = 0; i < size_and_type.first; ++i)\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                        {\n                            return false;\n                        }\n                    }\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                }\n            }\n        }\n        else\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))\n            {\n                return false;\n            }\n\n            while (current != ']')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal(false)))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n            }\n        }\n\n        return sax->end_array();\n    }\n\n    /*!\n    @return whether object creation completed\n    */\n    bool get_ubjson_object()\n    {\n        std::pair<std::size_t, char_int_type> size_and_type;\n        if (JSON_HEDLEY_UNLIKELY(!get_ubjson_size_type(size_and_type)))\n        {\n            return false;\n        }\n\n        // do not accept ND-array size in objects in BJData\n        if (input_format == input_format_t::bjdata && size_and_type.first != npos && (size_and_type.second & (1 << 8)) != 0)\n        {\n            auto last_token = get_token_string();\n            return sax->parse_error(chars_read, last_token, parse_error::create(112, chars_read,\n                                    exception_message(input_format, \"BJData object does not support ND-array size in optimized format\", \"object\"), nullptr));\n        }\n\n        string_t key;\n        if (size_and_type.first != npos)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(size_and_type.first)))\n            {\n                return false;\n            }\n\n            if (size_and_type.second != 0)\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_value(size_and_type.second)))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n            else\n            {\n                for (std::size_t i = 0; i < size_and_type.first; ++i)\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key) || !sax->key(key)))\n                    {\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                    {\n                        return false;\n                    }\n                    key.clear();\n                }\n            }\n        }\n        else\n        {\n            if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))\n            {\n                return false;\n            }\n\n            while (current != '}')\n            {\n                if (JSON_HEDLEY_UNLIKELY(!get_ubjson_string(key, false) || !sax->key(key)))\n                {\n                    return false;\n                }\n                if (JSON_HEDLEY_UNLIKELY(!parse_ubjson_internal()))\n                {\n                    return false;\n                }\n                get_ignore_noop();\n                key.clear();\n            }\n        }\n\n        return sax->end_object();\n    }\n\n    // Note, no reader for UBJSON binary types is implemented because they do\n    // not exist\n\n    bool get_ubjson_high_precision_number()\n    {\n        // get size of following number string\n        std::size_t size{};\n        bool no_ndarray = true;\n        auto res = get_ubjson_size_value(size, no_ndarray);\n        if (JSON_HEDLEY_UNLIKELY(!res))\n        {\n            return res;\n        }\n\n        // get number string\n        std::vector<char> number_vector;\n        for (std::size_t i = 0; i < size; ++i)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(input_format, \"number\")))\n            {\n                return false;\n            }\n            number_vector.push_back(static_cast<char>(current));\n        }\n\n        // parse number string\n        using ia_type = decltype(detail::input_adapter(number_vector));\n        auto number_lexer = detail::lexer<BasicJsonType, ia_type>(detail::input_adapter(number_vector), false);\n        const auto result_number = number_lexer.scan();\n        const auto number_string = number_lexer.get_token_string();\n        const auto result_remainder = number_lexer.scan();\n\n        using token_type = typename detail::lexer_base<BasicJsonType>::token_type;\n\n        if (JSON_HEDLEY_UNLIKELY(result_remainder != token_type::end_of_input))\n        {\n            return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,\n                                    exception_message(input_format, concat(\"invalid number text: \", number_lexer.get_token_string()), \"high-precision number\"), nullptr));\n        }\n\n        switch (result_number)\n        {\n            case token_type::value_integer:\n                return sax->number_integer(number_lexer.get_number_integer());\n            case token_type::value_unsigned:\n                return sax->number_unsigned(number_lexer.get_number_unsigned());\n            case token_type::value_float:\n                return sax->number_float(number_lexer.get_number_float(), std::move(number_string));\n            case token_type::uninitialized:\n            case token_type::literal_true:\n            case token_type::literal_false:\n            case token_type::literal_null:\n            case token_type::value_string:\n            case token_type::begin_array:\n            case token_type::begin_object:\n            case token_type::end_array:\n            case token_type::end_object:\n            case token_type::name_separator:\n            case token_type::value_separator:\n            case token_type::parse_error:\n            case token_type::end_of_input:\n            case token_type::literal_or_value:\n            default:\n                return sax->parse_error(chars_read, number_string, parse_error::create(115, chars_read,\n                                        exception_message(input_format, concat(\"invalid number text: \", number_lexer.get_token_string()), \"high-precision number\"), nullptr));\n        }\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*!\n    @brief get next character from the input\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns a -'ve valued\n    `char_traits<char_type>::eof()` in that case.\n\n    @return character read from the input\n    */\n    char_int_type get()\n    {\n        ++chars_read;\n        return current = ia.get_character();\n    }\n\n    /*!\n    @brief get_to read into a primitive type\n\n    This function provides the interface to the used input adapter. It does\n    not throw in case the input reached EOF, but returns false instead\n\n    @return bool, whether the read was successful\n    */\n    template<class T>\n    bool get_to(T& dest, const input_format_t format, const char* context)\n    {\n        auto new_chars_read = ia.get_elements(&dest);\n        chars_read += new_chars_read;\n        if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T)))\n        {\n            // in case of failure, advance position by 1 to report failing location\n            ++chars_read;\n            sax->parse_error(chars_read, \"<end of file>\", parse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context), nullptr));\n            return false;\n        }\n        return true;\n    }\n\n    /*!\n    @return character read from the input after ignoring all 'N' entries\n    */\n    char_int_type get_ignore_noop()\n    {\n        do\n        {\n            get();\n        }\n        while (current == 'N');\n\n        return current;\n    }\n\n    template<class NumberType>\n    static void byte_swap(NumberType& number)\n    {\n        constexpr std::size_t sz = sizeof(number);\n#ifdef __cpp_lib_byteswap\n        if constexpr (sz == 1)\n        {\n            return;\n        }\n        if constexpr(std::is_integral_v<NumberType>)\n        {\n            number = std::byteswap(number);\n            return;\n        }\n#endif\n        auto* ptr = reinterpret_cast<std::uint8_t*>(&number);\n        for (std::size_t i = 0; i < sz / 2; ++i)\n        {\n            std::swap(ptr[i], ptr[sz - i - 1]);\n        }\n    }\n\n    /*\n    @brief read a number from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format   the current format (for diagnostics)\n    @param[out] result  number of type @a NumberType\n\n    @return whether conversion completed\n\n    @note This function needs to respect the system's endianness, because\n          bytes in CBOR, MessagePack, and UBJSON are stored in network order\n          (big endian) and therefore need reordering on little endian systems.\n          On the other hand, BSON and BJData use little endian and should reorder\n          on big endian systems.\n    */\n    template<typename NumberType, bool InputIsLittleEndian = false>\n    bool get_number(const input_format_t format, NumberType& result)\n    {\n        // read in the original format\n\n        if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, \"number\")))\n        {\n            return false;\n        }\n        if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))\n        {\n            byte_swap(result);\n        }\n        return true;\n    }\n\n    /*!\n    @brief create a string by reading characters from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of characters to read\n    @param[out] result string created by reading @a len bytes\n\n    @return whether string creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of string memory.\n    */\n    template<typename NumberType>\n    bool get_string(const input_format_t format,\n                    const NumberType len,\n                    string_t& result)\n    {\n        bool success = true;\n        for (NumberType i = 0; i < len; i++)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"string\")))\n            {\n                success = false;\n                break;\n            }\n            result.push_back(static_cast<typename string_t::value_type>(current));\n        }\n        return success;\n    }\n\n    /*!\n    @brief create a byte array by reading bytes from the input\n\n    @tparam NumberType the type of the number\n    @param[in] format the current format (for diagnostics)\n    @param[in] len number of bytes to read\n    @param[out] result byte array created by reading @a len bytes\n\n    @return whether byte array creation completed\n\n    @note We can not reserve @a len bytes for the result, because @a len\n          may be too large. Usually, @ref unexpect_eof() detects the end of\n          the input before we run out of memory.\n    */\n    template<typename NumberType>\n    bool get_binary(const input_format_t format,\n                    const NumberType len,\n                    binary_t& result)\n    {\n        bool success = true;\n        for (NumberType i = 0; i < len; i++)\n        {\n            get();\n            if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, \"binary\")))\n            {\n                success = false;\n                break;\n            }\n            result.push_back(static_cast<std::uint8_t>(current));\n        }\n        return success;\n    }\n\n    /*!\n    @param[in] format   the current format (for diagnostics)\n    @param[in] context  further context information (for diagnostics)\n    @return whether the last read character is not EOF\n    */\n    JSON_HEDLEY_NON_NULL(3)\n    bool unexpect_eof(const input_format_t format, const char* context) const\n    {\n        if (JSON_HEDLEY_UNLIKELY(current == char_traits<char_type>::eof()))\n        {\n            return sax->parse_error(chars_read, \"<end of file>\",\n                                    parse_error::create(110, chars_read, exception_message(format, \"unexpected end of input\", context), nullptr));\n        }\n        return true;\n    }\n\n    /*!\n    @return a string representation of the last read byte\n    */\n    std::string get_token_string() const\n    {\n        std::array<char, 3> cr{{}};\n        static_cast<void>((std::snprintf)(cr.data(), cr.size(), \"%.2hhX\", static_cast<unsigned char>(current))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n        return std::string{cr.data()};\n    }\n\n    /*!\n    @param[in] format   the current format\n    @param[in] detail   a detailed error message\n    @param[in] context  further context information\n    @return a message string to use in the parse_error exceptions\n    */\n    std::string exception_message(const input_format_t format,\n                                  const std::string& detail,\n                                  const std::string& context) const\n    {\n        std::string error_msg = \"syntax error while parsing \";\n\n        switch (format)\n        {\n            case input_format_t::cbor:\n                error_msg += \"CBOR\";\n                break;\n\n            case input_format_t::msgpack:\n                error_msg += \"MessagePack\";\n                break;\n\n            case input_format_t::ubjson:\n                error_msg += \"UBJSON\";\n                break;\n\n            case input_format_t::bson:\n                error_msg += \"BSON\";\n                break;\n\n            case input_format_t::bjdata:\n                error_msg += \"BJData\";\n                break;\n\n            case input_format_t::json: // LCOV_EXCL_LINE\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n\n        return concat(error_msg, ' ', context, \": \", detail);\n    }\n\n  private:\n    static JSON_INLINE_VARIABLE constexpr std::size_t npos = detail::unknown_size();\n\n    /// input adapter\n    InputAdapterType ia;\n\n    /// the current character\n    char_int_type current = char_traits<char_type>::eof();\n\n    /// the number of characters read\n    std::size_t chars_read = 0;\n\n    /// whether we can assume little endianness\n    const bool is_little_endian = little_endianness();\n\n    /// input format\n    const input_format_t input_format = input_format_t::json;\n\n    /// the SAX parser\n    json_sax_t* sax = nullptr;\n\n    // excluded markers in bjdata optimized type\n#define JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_ \\\n    make_array<char_int_type>('F', 'H', 'N', 'S', 'T', 'Z', '[', '{')\n\n#define JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_ \\\n    make_array<bjd_type>(                      \\\n    bjd_type{'B', \"byte\"},                     \\\n    bjd_type{'C', \"char\"},                     \\\n    bjd_type{'D', \"double\"},                   \\\n    bjd_type{'I', \"int16\"},                    \\\n    bjd_type{'L', \"int64\"},                    \\\n    bjd_type{'M', \"uint64\"},                   \\\n    bjd_type{'U', \"uint8\"},                    \\\n    bjd_type{'d', \"single\"},                   \\\n    bjd_type{'i', \"int8\"},                     \\\n    bjd_type{'l', \"int32\"},                    \\\n    bjd_type{'m', \"uint32\"},                   \\\n    bjd_type{'u', \"uint16\"})\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    // lookup tables\n    // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)\n    const decltype(JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_) bjd_optimized_type_markers =\n        JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_;\n\n    using bjd_type = std::pair<char_int_type, string_t>;\n    // NOLINTNEXTLINE(cppcoreguidelines-non-private-member-variables-in-classes)\n    const decltype(JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_) bjd_types_map =\n        JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_;\n\n#undef JSON_BINARY_READER_MAKE_BJD_OPTIMIZED_TYPE_MARKERS_\n#undef JSON_BINARY_READER_MAKE_BJD_TYPES_MAP_\n};\n\n#ifndef JSON_HAS_CPP_17\n    template<typename BasicJsonType, typename InputAdapterType, typename SAX>\n    constexpr std::size_t binary_reader<BasicJsonType, InputAdapterType, SAX>::npos;\n#endif\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/input/parser.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cmath> // isfinite\n#include <cstdint> // uint8_t\n#include <functional> // function\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/input/input_adapters.hpp>\n\n// #include <nlohmann/detail/input/json_sax.hpp>\n\n// #include <nlohmann/detail/input/lexer.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/is_sax.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n////////////\n// parser //\n////////////\n\nenum class parse_event_t : std::uint8_t\n{\n    /// the parser read `{` and started to process a JSON object\n    object_start,\n    /// the parser read `}` and finished processing a JSON object\n    object_end,\n    /// the parser read `[` and started to process a JSON array\n    array_start,\n    /// the parser read `]` and finished processing a JSON array\n    array_end,\n    /// the parser read a key of a value in an object\n    key,\n    /// the parser finished reading a JSON value\n    value\n};\n\ntemplate<typename BasicJsonType>\nusing parser_callback_t =\n    std::function<bool(int /*depth*/, parse_event_t /*event*/, BasicJsonType& /*parsed*/)>;\n\n/*!\n@brief syntax analysis\n\nThis class implements a recursive descent parser.\n*/\ntemplate<typename BasicJsonType, typename InputAdapterType>\nclass parser\n{\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using string_t = typename BasicJsonType::string_t;\n    using lexer_t = lexer<BasicJsonType, InputAdapterType>;\n    using token_type = typename lexer_t::token_type;\n\n  public:\n    /// a parser reading from an input adapter\n    explicit parser(InputAdapterType&& adapter,\n                    parser_callback_t<BasicJsonType> cb = nullptr,\n                    const bool allow_exceptions_ = true,\n                    const bool skip_comments = false)\n        : callback(std::move(cb))\n        , m_lexer(std::move(adapter), skip_comments)\n        , allow_exceptions(allow_exceptions_)\n    {\n        // read first token\n        get_token();\n    }\n\n    /*!\n    @brief public parser interface\n\n    @param[in] strict      whether to expect the last token to be EOF\n    @param[in,out] result  parsed JSON value\n\n    @throw parse_error.101 in case of an unexpected token\n    @throw parse_error.102 if to_unicode fails or surrogate error\n    @throw parse_error.103 if to_unicode fails\n    */\n    void parse(const bool strict, BasicJsonType& result)\n    {\n        if (callback)\n        {\n            json_sax_dom_callback_parser<BasicJsonType, InputAdapterType> sdp(result, callback, allow_exceptions, &m_lexer);\n            sax_parse_internal(&sdp);\n\n            // in strict mode, input must be completely read\n            if (strict && (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(),\n                                                    exception_message(token_type::end_of_input, \"value\"), nullptr));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n\n            // set top-level value to null if it was discarded by the callback\n            // function\n            if (result.is_discarded())\n            {\n                result = nullptr;\n            }\n        }\n        else\n        {\n            json_sax_dom_parser<BasicJsonType, InputAdapterType> sdp(result, allow_exceptions, &m_lexer);\n            sax_parse_internal(&sdp);\n\n            // in strict mode, input must be completely read\n            if (strict && (get_token() != token_type::end_of_input))\n            {\n                sdp.parse_error(m_lexer.get_position(),\n                                m_lexer.get_token_string(),\n                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, \"value\"), nullptr));\n            }\n\n            // in case of an error, return discarded value\n            if (sdp.is_errored())\n            {\n                result = value_t::discarded;\n                return;\n            }\n        }\n\n        result.assert_invariant();\n    }\n\n    /*!\n    @brief public accept interface\n\n    @param[in] strict  whether to expect the last token to be EOF\n    @return whether the input is a proper JSON text\n    */\n    bool accept(const bool strict = true)\n    {\n        json_sax_acceptor<BasicJsonType> sax_acceptor;\n        return sax_parse(&sax_acceptor, strict);\n    }\n\n    template<typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    bool sax_parse(SAX* sax, const bool strict = true)\n    {\n        (void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};\n        const bool result = sax_parse_internal(sax);\n\n        // strict mode: next byte must be EOF\n        if (result && strict && (get_token() != token_type::end_of_input))\n        {\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, \"value\"), nullptr));\n        }\n\n        return result;\n    }\n\n  private:\n    template<typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    bool sax_parse_internal(SAX* sax)\n    {\n        // stack to remember the hierarchy of structured values we are parsing\n        // true = array; false = object\n        std::vector<bool> states;\n        // value to avoid a goto (see comment where set to true)\n        bool skip_to_state_evaluation = false;\n\n        while (true)\n        {\n            if (!skip_to_state_evaluation)\n            {\n                // invariant: get_token() was called before each iteration\n                switch (last_token)\n                {\n                    case token_type::begin_object:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))\n                        {\n                            return false;\n                        }\n\n                        // closing } -> we are done\n                        if (get_token() == token_type::end_object)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // parse key\n                        if (JSON_HEDLEY_UNLIKELY(last_token != token_type::value_string))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, \"object key\"), nullptr));\n                        }\n                        if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        // parse separator (:)\n                        if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, \"object separator\"), nullptr));\n                        }\n\n                        // remember we are now inside an object\n                        states.push_back(false);\n\n                        // parse values\n                        get_token();\n                        continue;\n                    }\n\n                    case token_type::begin_array:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))\n                        {\n                            return false;\n                        }\n\n                        // closing ] -> we are done\n                        if (get_token() == token_type::end_array)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))\n                            {\n                                return false;\n                            }\n                            break;\n                        }\n\n                        // remember we are now inside an array\n                        states.push_back(true);\n\n                        // parse values (no need to call get_token)\n                        continue;\n                    }\n\n                    case token_type::value_float:\n                    {\n                        const auto res = m_lexer.get_number_float();\n\n                        if (JSON_HEDLEY_UNLIKELY(!std::isfinite(res)))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    out_of_range::create(406, concat(\"number overflow parsing '\", m_lexer.get_token_string(), '\\''), nullptr));\n                        }\n\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_float(res, m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n\n                        break;\n                    }\n\n                    case token_type::literal_false:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(false)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_null:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->null()))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::literal_true:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->boolean(true)))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_integer:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_integer(m_lexer.get_number_integer())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_string:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->string(m_lexer.get_string())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::value_unsigned:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!sax->number_unsigned(m_lexer.get_number_unsigned())))\n                        {\n                            return false;\n                        }\n                        break;\n                    }\n\n                    case token_type::parse_error:\n                    {\n                        // using \"uninitialized\" to avoid \"expected\" message\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized, \"value\"), nullptr));\n                    }\n                    case token_type::end_of_input:\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(m_lexer.get_position().chars_read_total == 1))\n                        {\n                            return sax->parse_error(m_lexer.get_position(),\n                                                    m_lexer.get_token_string(),\n                                                    parse_error::create(101, m_lexer.get_position(),\n                                                            \"attempting to parse an empty input; check that your input string or stream contains the expected JSON\", nullptr));\n                        }\n\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, \"value\"), nullptr));\n                    }\n                    case token_type::uninitialized:\n                    case token_type::end_array:\n                    case token_type::end_object:\n                    case token_type::name_separator:\n                    case token_type::value_separator:\n                    case token_type::literal_or_value:\n                    default: // the last token was unexpected\n                    {\n                        return sax->parse_error(m_lexer.get_position(),\n                                                m_lexer.get_token_string(),\n                                                parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value, \"value\"), nullptr));\n                    }\n                }\n            }\n            else\n            {\n                skip_to_state_evaluation = false;\n            }\n\n            // we reached this line after we successfully parsed a value\n            if (states.empty())\n            {\n                // empty stack: we reached the end of the hierarchy: done\n                return true;\n            }\n\n            if (states.back())  // array\n            {\n                // comma -> next value\n                if (get_token() == token_type::value_separator)\n                {\n                    // parse a new value\n                    get_token();\n                    continue;\n                }\n\n                // closing ]\n                if (JSON_HEDLEY_LIKELY(last_token == token_type::end_array))\n                {\n                    if (JSON_HEDLEY_UNLIKELY(!sax->end_array()))\n                    {\n                        return false;\n                    }\n\n                    // We are done with this array. Before we can parse a\n                    // new value, we need to evaluate the new state first.\n                    // By setting skip_to_state_evaluation to false, we\n                    // are effectively jumping to the beginning of this if.\n                    JSON_ASSERT(!states.empty());\n                    states.pop_back();\n                    skip_to_state_evaluation = true;\n                    continue;\n                }\n\n                return sax->parse_error(m_lexer.get_position(),\n                                        m_lexer.get_token_string(),\n                                        parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array, \"array\"), nullptr));\n            }\n\n            // states.back() is false -> object\n\n            // comma -> next value\n            if (get_token() == token_type::value_separator)\n            {\n                // parse key\n                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::value_string))\n                {\n                    return sax->parse_error(m_lexer.get_position(),\n                                            m_lexer.get_token_string(),\n                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string, \"object key\"), nullptr));\n                }\n\n                if (JSON_HEDLEY_UNLIKELY(!sax->key(m_lexer.get_string())))\n                {\n                    return false;\n                }\n\n                // parse separator (:)\n                if (JSON_HEDLEY_UNLIKELY(get_token() != token_type::name_separator))\n                {\n                    return sax->parse_error(m_lexer.get_position(),\n                                            m_lexer.get_token_string(),\n                                            parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator, \"object separator\"), nullptr));\n                }\n\n                // parse values\n                get_token();\n                continue;\n            }\n\n            // closing }\n            if (JSON_HEDLEY_LIKELY(last_token == token_type::end_object))\n            {\n                if (JSON_HEDLEY_UNLIKELY(!sax->end_object()))\n                {\n                    return false;\n                }\n\n                // We are done with this object. Before we can parse a\n                // new value, we need to evaluate the new state first.\n                // By setting skip_to_state_evaluation to false, we\n                // are effectively jumping to the beginning of this if.\n                JSON_ASSERT(!states.empty());\n                states.pop_back();\n                skip_to_state_evaluation = true;\n                continue;\n            }\n\n            return sax->parse_error(m_lexer.get_position(),\n                                    m_lexer.get_token_string(),\n                                    parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object, \"object\"), nullptr));\n        }\n    }\n\n    /// get next token from lexer\n    token_type get_token()\n    {\n        return last_token = m_lexer.scan();\n    }\n\n    std::string exception_message(const token_type expected, const std::string& context)\n    {\n        std::string error_msg = \"syntax error \";\n\n        if (!context.empty())\n        {\n            error_msg += concat(\"while parsing \", context, ' ');\n        }\n\n        error_msg += \"- \";\n\n        if (last_token == token_type::parse_error)\n        {\n            error_msg += concat(m_lexer.get_error_message(), \"; last read: '\",\n                                m_lexer.get_token_string(), '\\'');\n        }\n        else\n        {\n            error_msg += concat(\"unexpected \", lexer_t::token_type_name(last_token));\n        }\n\n        if (expected != token_type::uninitialized)\n        {\n            error_msg += concat(\"; expected \", lexer_t::token_type_name(expected));\n        }\n\n        return error_msg;\n    }\n\n  private:\n    /// callback function\n    const parser_callback_t<BasicJsonType> callback = nullptr;\n    /// the type of the last read token\n    token_type last_token = token_type::uninitialized;\n    /// the lexer\n    lexer_t m_lexer;\n    /// whether to throw exceptions in case of errors\n    const bool allow_exceptions = true;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef> // ptrdiff_t\n#include <limits>  // numeric_limits\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/*\n@brief an iterator for primitive JSON types\n\nThis class models an iterator for primitive JSON types (boolean, number,\nstring). It's only purpose is to allow the iterator/const_iterator classes\nto \"iterate\" over primitive values. Internally, the iterator is modeled by\na `difference_type` variable. Value begin_value (`0`) models the begin,\nend_value (`1`) models past the end.\n*/\nclass primitive_iterator_t\n{\n  private:\n    using difference_type = std::ptrdiff_t;\n    static constexpr difference_type begin_value = 0;\n    static constexpr difference_type end_value = begin_value + 1;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// iterator as signed integer type\n    difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();\n\n  public:\n    constexpr difference_type get_value() const noexcept\n    {\n        return m_it;\n    }\n\n    /// set iterator to a defined beginning\n    void set_begin() noexcept\n    {\n        m_it = begin_value;\n    }\n\n    /// set iterator to a defined past the end\n    void set_end() noexcept\n    {\n        m_it = end_value;\n    }\n\n    /// return whether the iterator can be dereferenced\n    constexpr bool is_begin() const noexcept\n    {\n        return m_it == begin_value;\n    }\n\n    /// return whether the iterator is at end\n    constexpr bool is_end() const noexcept\n    {\n        return m_it == end_value;\n    }\n\n    friend constexpr bool operator==(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it == rhs.m_it;\n    }\n\n    friend constexpr bool operator<(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it < rhs.m_it;\n    }\n\n    primitive_iterator_t operator+(difference_type n) noexcept\n    {\n        auto result = *this;\n        result += n;\n        return result;\n    }\n\n    friend constexpr difference_type operator-(primitive_iterator_t lhs, primitive_iterator_t rhs) noexcept\n    {\n        return lhs.m_it - rhs.m_it;\n    }\n\n    primitive_iterator_t& operator++() noexcept\n    {\n        ++m_it;\n        return *this;\n    }\n\n    primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp)\n    {\n        auto result = *this;\n        ++m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator--() noexcept\n    {\n        --m_it;\n        return *this;\n    }\n\n    primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp)\n    {\n        auto result = *this;\n        --m_it;\n        return result;\n    }\n\n    primitive_iterator_t& operator+=(difference_type n) noexcept\n    {\n        m_it += n;\n        return *this;\n    }\n\n    primitive_iterator_t& operator-=(difference_type n) noexcept\n    {\n        m_it -= n;\n        return *this;\n    }\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/*!\n@brief an iterator value\n\n@note This structure could easily be a union, but MSVC currently does not allow\nunions members with complex constructors, see https://github.com/nlohmann/json/pull/105.\n*/\ntemplate<typename BasicJsonType> struct internal_iterator\n{\n    /// iterator for JSON objects\n    typename BasicJsonType::object_t::iterator object_iterator {};\n    /// iterator for JSON arrays\n    typename BasicJsonType::array_t::iterator array_iterator {};\n    /// generic iterator for all other types\n    primitive_iterator_t primitive_iterator {};\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/iterators/iter_impl.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next\n#include <type_traits> // conditional, is_const, remove_const\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/iterators/internal_iterator.hpp>\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n// forward declare, to be able to friend it later on\ntemplate<typename IteratorType> class iteration_proxy;\ntemplate<typename IteratorType> class iteration_proxy_value;\n\n/*!\n@brief a template for a bidirectional iterator for the @ref basic_json class\nThis class implements a both iterators (iterator and const_iterator) for the\n@ref basic_json class.\n@note An iterator is called *initialized* when a pointer to a JSON value has\n      been set (e.g., by a constructor or a copy assignment). If the iterator is\n      default-constructed, it is *uninitialized* and most methods are undefined.\n      **The library uses assertions to detect calls on uninitialized iterators.**\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n@since version 1.0.0, simplified in version 2.0.9, change to bidirectional\n       iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)\n*/\ntemplate<typename BasicJsonType>\nclass iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)\n{\n    /// the iterator with BasicJsonType of different const-ness\n    using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;\n    /// allow basic_json to access private members\n    friend other_iter_impl;\n    friend BasicJsonType;\n    friend iteration_proxy<iter_impl>;\n    friend iteration_proxy_value<iter_impl>;\n\n    using object_t = typename BasicJsonType::object_t;\n    using array_t = typename BasicJsonType::array_t;\n    // make sure BasicJsonType is basic_json or const basic_json\n    static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,\n                  \"iter_impl only accepts (const) basic_json\");\n    // superficial check for the LegacyBidirectionalIterator named requirement\n    static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value\n                  &&  std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,\n                  \"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.\");\n\n  public:\n    /// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.\n    /// The C++ Standard has never required user-defined iterators to derive from std::iterator.\n    /// A user-defined iterator should provide publicly accessible typedefs named\n    /// iterator_category, value_type, difference_type, pointer, and reference.\n    /// Note that value_type is required to be non-const, even for constant iterators.\n    using iterator_category = std::bidirectional_iterator_tag;\n\n    /// the type of the values when the iterator is dereferenced\n    using value_type = typename BasicJsonType::value_type;\n    /// a type to represent differences between iterators\n    using difference_type = typename BasicJsonType::difference_type;\n    /// defines a pointer to the type iterated over (value_type)\n    using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,\n          typename BasicJsonType::const_pointer,\n          typename BasicJsonType::pointer>::type;\n    /// defines a reference to the type iterated over (value_type)\n    using reference =\n        typename std::conditional<std::is_const<BasicJsonType>::value,\n        typename BasicJsonType::const_reference,\n        typename BasicJsonType::reference>::type;\n\n    iter_impl() = default;\n    ~iter_impl() = default;\n    iter_impl(iter_impl&&) noexcept = default;\n    iter_impl& operator=(iter_impl&&) noexcept = default;\n\n    /*!\n    @brief constructor for a given JSON instance\n    @param[in] object  pointer to a JSON object for this iterator\n    @pre object != nullptr\n    @post The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    explicit iter_impl(pointer object) noexcept : m_object(object)\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = typename object_t::iterator();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = typename array_t::iterator();\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator = primitive_iterator_t();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @note The conventional copy constructor and copy assignment are implicitly\n          defined. Combined with the following converting constructor and\n          assignment, they support: (1) copy from iterator to iterator, (2)\n          copy from const iterator to const iterator, and (3) conversion from\n          iterator to const iterator. However conversion from const iterator\n          to iterator is not defined.\n    */\n\n    /*!\n    @brief const copy constructor\n    @param[in] other const iterator to copy from\n    @note This copy constructor had to be defined explicitly to circumvent a bug\n          occurring on msvc v19.0 compiler (VS 2015) debug build. For more\n          information refer to: https://github.com/nlohmann/json/issues/1608\n    */\n    iter_impl(const iter_impl<const BasicJsonType>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it)\n    {}\n\n    /*!\n    @brief converting assignment\n    @param[in] other const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<const BasicJsonType>& other) noexcept\n    {\n        if (&other != this)\n        {\n            m_object = other.m_object;\n            m_it = other.m_it;\n        }\n        return *this;\n    }\n\n    /*!\n    @brief converting constructor\n    @param[in] other  non-const iterator to copy from\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept\n        : m_object(other.m_object), m_it(other.m_it)\n    {}\n\n    /*!\n    @brief converting assignment\n    @param[in] other  non-const iterator to copy from\n    @return const/non-const iterator\n    @note It is not checked whether @a other is initialized.\n    */\n    iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)\n    {\n        m_object = other.m_object;\n        m_it = other.m_it;\n        return *this;\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief set the iterator to the first value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_begin() noexcept\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_data.m_value.object->begin();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_data.m_value.array->begin();\n                break;\n            }\n\n            case value_t::null:\n            {\n                // set to end so begin()==end() is true: null is empty\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator.set_begin();\n                break;\n            }\n        }\n    }\n\n    /*!\n    @brief set the iterator past the last value\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    void set_end() noexcept\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                m_it.object_iterator = m_object->m_data.m_value.object->end();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_it.array_iterator = m_object->m_data.m_value.array->end();\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator.set_end();\n                break;\n            }\n        }\n    }\n\n  public:\n    /*!\n    @brief return a reference to the value pointed to by the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator*() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());\n                return m_it.object_iterator->second;\n            }\n\n            case value_t::array:\n            {\n                JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());\n                return *m_it.array_iterator;\n            }\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", m_object));\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", m_object));\n            }\n        }\n    }\n\n    /*!\n    @brief dereference the iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    pointer operator->() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                JSON_ASSERT(m_it.object_iterator != m_object->m_data.m_value.object->end());\n                return &(m_it.object_iterator->second);\n            }\n\n            case value_t::array:\n            {\n                JSON_ASSERT(m_it.array_iterator != m_object->m_data.m_value.array->end());\n                return &*m_it.array_iterator;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.is_begin()))\n                {\n                    return m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", m_object));\n            }\n        }\n    }\n\n    /*!\n    @brief post-increment (it++)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp)\n    {\n        auto result = *this;\n        ++(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-increment (++it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator++()\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, 1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, 1);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                ++m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief post-decrement (it--)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp)\n    {\n        auto result = *this;\n        --(*this);\n        return result;\n    }\n\n    /*!\n    @brief pre-decrement (--it)\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator--()\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n            {\n                std::advance(m_it.object_iterator, -1);\n                break;\n            }\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, -1);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                --m_it.primitive_iterator;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief comparison: equal\n    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.\n    */\n    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >\n    bool operator==(const IterImpl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\", m_object));\n        }\n\n        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493\n        if (m_object == nullptr)\n        {\n            return true;\n        }\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n                return (m_it.object_iterator == other.m_it.object_iterator);\n\n            case value_t::array:\n                return (m_it.array_iterator == other.m_it.array_iterator);\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return (m_it.primitive_iterator == other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief comparison: not equal\n    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.\n    */\n    template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr >\n    bool operator!=(const IterImpl& other) const\n    {\n        return !operator==(other);\n    }\n\n    /*!\n    @brief comparison: smaller\n    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.\n    */\n    bool operator<(const iter_impl& other) const\n    {\n        // if objects are not the same, the comparison is undefined\n        if (JSON_HEDLEY_UNLIKELY(m_object != other.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(212, \"cannot compare iterators of different containers\", m_object));\n        }\n\n        // value-initialized forward iterators can be compared, and must compare equal to other value-initialized iterators of the same type #4493\n        if (m_object == nullptr)\n        {\n            // the iterators are both value-initialized and are to be considered equal, but this function checks for smaller, so we return false\n            return false;\n        }\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(213, \"cannot compare order of object iterators\", m_object));\n\n            case value_t::array:\n                return (m_it.array_iterator < other.m_it.array_iterator);\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return (m_it.primitive_iterator < other.m_it.primitive_iterator);\n        }\n    }\n\n    /*!\n    @brief comparison: less than or equal\n    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.\n    */\n    bool operator<=(const iter_impl& other) const\n    {\n        return !other.operator < (*this);\n    }\n\n    /*!\n    @brief comparison: greater than\n    @pre (1) Both iterators are initialized to point to the same object, or (2) both iterators are value-initialized.\n    */\n    bool operator>(const iter_impl& other) const\n    {\n        return !operator<=(other);\n    }\n\n    /*!\n    @brief comparison: greater than or equal\n    @pre (1) The iterator is initialized; i.e. `m_object != nullptr`, or (2) both iterators are value-initialized.\n    */\n    bool operator>=(const iter_impl& other) const\n    {\n        return !operator<(other);\n    }\n\n    /*!\n    @brief add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator+=(difference_type i)\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\", m_object));\n\n            case value_t::array:\n            {\n                std::advance(m_it.array_iterator, i);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                m_it.primitive_iterator += i;\n                break;\n            }\n        }\n\n        return *this;\n    }\n\n    /*!\n    @brief subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl& operator-=(difference_type i)\n    {\n        return operator+=(-i);\n    }\n\n    /*!\n    @brief add to iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator+(difference_type i) const\n    {\n        auto result = *this;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief addition of distance and iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    friend iter_impl operator+(difference_type i, const iter_impl& it)\n    {\n        auto result = it;\n        result += i;\n        return result;\n    }\n\n    /*!\n    @brief subtract from iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    iter_impl operator-(difference_type i) const\n    {\n        auto result = *this;\n        result -= i;\n        return result;\n    }\n\n    /*!\n    @brief return difference\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    difference_type operator-(const iter_impl& other) const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(209, \"cannot use offsets with object iterators\", m_object));\n\n            case value_t::array:\n                return m_it.array_iterator - other.m_it.array_iterator;\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                return m_it.primitive_iterator - other.m_it.primitive_iterator;\n        }\n    }\n\n    /*!\n    @brief access to successor\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference operator[](difference_type n) const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        switch (m_object->m_data.m_type)\n        {\n            case value_t::object:\n                JSON_THROW(invalid_iterator::create(208, \"cannot use operator[] for object iterators\", m_object));\n\n            case value_t::array:\n                return *std::next(m_it.array_iterator, n);\n\n            case value_t::null:\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", m_object));\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                if (JSON_HEDLEY_LIKELY(m_it.primitive_iterator.get_value() == -n))\n                {\n                    return *m_object;\n                }\n\n                JSON_THROW(invalid_iterator::create(214, \"cannot get value\", m_object));\n            }\n        }\n    }\n\n    /*!\n    @brief return the key of an object iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    const typename object_t::key_type& key() const\n    {\n        JSON_ASSERT(m_object != nullptr);\n\n        if (JSON_HEDLEY_LIKELY(m_object->is_object()))\n        {\n            return m_it.object_iterator->first;\n        }\n\n        JSON_THROW(invalid_iterator::create(207, \"cannot use key() for non-object iterators\", m_object));\n    }\n\n    /*!\n    @brief return the value of an iterator\n    @pre The iterator is initialized; i.e. `m_object != nullptr`.\n    */\n    reference value() const\n    {\n        return operator*();\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /// associated JSON instance\n    pointer m_object = nullptr;\n    /// the actual iterator of the associated instance\n    internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {};\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/iterators/iteration_proxy.hpp>\n\n// #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <cstddef> // ptrdiff_t\n#include <iterator> // reverse_iterator\n#include <utility> // declval\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n//////////////////////\n// reverse_iterator //\n//////////////////////\n\n/*!\n@brief a template for a reverse iterator class\n\n@tparam Base the base iterator type to reverse. Valid types are @ref\niterator (to create @ref reverse_iterator) and @ref const_iterator (to\ncreate @ref const_reverse_iterator).\n\n@requirement The class satisfies the following concept requirements:\n-\n[BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):\n  The iterator that can be moved can be moved in both directions (i.e.\n  incremented and decremented).\n- [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):\n  It is possible to write to the pointed-to element (only if @a Base is\n  @ref iterator).\n\n@since version 1.0.0\n*/\ntemplate<typename Base>\nclass json_reverse_iterator : public std::reverse_iterator<Base>\n{\n  public:\n    using difference_type = std::ptrdiff_t;\n    /// shortcut to the reverse iterator adapter\n    using base_iterator = std::reverse_iterator<Base>;\n    /// the reference type for the pointed-to element\n    using reference = typename Base::reference;\n\n    /// create reverse iterator from iterator\n    explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept\n        : base_iterator(it) {}\n\n    /// create reverse iterator from base class\n    explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}\n\n    /// post-increment (it++)\n    json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator++(1));\n    }\n\n    /// pre-increment (++it)\n    json_reverse_iterator& operator++()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator++());\n    }\n\n    /// post-decrement (it--)\n    json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp)\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator--(1));\n    }\n\n    /// pre-decrement (--it)\n    json_reverse_iterator& operator--()\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator--());\n    }\n\n    /// add to iterator\n    json_reverse_iterator& operator+=(difference_type i)\n    {\n        return static_cast<json_reverse_iterator&>(base_iterator::operator+=(i));\n    }\n\n    /// add to iterator\n    json_reverse_iterator operator+(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator+(i));\n    }\n\n    /// subtract from iterator\n    json_reverse_iterator operator-(difference_type i) const\n    {\n        return static_cast<json_reverse_iterator>(base_iterator::operator-(i));\n    }\n\n    /// return difference\n    difference_type operator-(const json_reverse_iterator& other) const\n    {\n        return base_iterator(*this) - base_iterator(other);\n    }\n\n    /// access to successor\n    reference operator[](difference_type n) const\n    {\n        return *(this->operator+(n));\n    }\n\n    /// return the key of an object iterator\n    auto key() const -> decltype(std::declval<Base>().key())\n    {\n        auto it = --this->base();\n        return it.key();\n    }\n\n    /// return the value of an iterator\n    reference value() const\n    {\n        auto it = --this->base();\n        return it.operator * ();\n    }\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/iterators/primitive_iterator.hpp>\n\n// #include <nlohmann/detail/json_custom_base_class.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <type_traits> // conditional, is_same\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/*!\n@brief Default base class of the @ref basic_json class.\n\nSo that the correct implementations of the copy / move ctors / assign operators\nof @ref basic_json do not require complex case distinctions\n(no base class / custom base class used as customization point),\n@ref basic_json always has a base class.\nBy default, this class is used because it is empty and thus has no effect\non the behavior of @ref basic_json.\n*/\nstruct json_default_base {};\n\ntemplate<class T>\nusing json_base_class = typename std::conditional <\n                        std::is_same<T, void>::value,\n                        json_default_base,\n                        T\n                        >::type;\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/json_pointer.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <algorithm> // all_of\n#include <cctype> // isdigit\n#include <cerrno> // errno, ERANGE\n#include <cstdlib> // strtoull\n#ifndef JSON_NO_IO\n    #include <iosfwd> // ostream\n#endif  // JSON_NO_IO\n#include <limits> // max\n#include <numeric> // accumulate\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n// #include <nlohmann/detail/string_escape.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document\n/// @sa https://json.nlohmann.me/api/json_pointer/\ntemplate<typename RefStringType>\nclass json_pointer\n{\n    // allow basic_json to access private members\n    NLOHMANN_BASIC_JSON_TPL_DECLARATION\n    friend class basic_json;\n\n    template<typename>\n    friend class json_pointer;\n\n    template<typename T>\n    struct string_t_helper\n    {\n        using type = T;\n    };\n\n    NLOHMANN_BASIC_JSON_TPL_DECLARATION\n    struct string_t_helper<NLOHMANN_BASIC_JSON_TPL>\n    {\n        using type = StringType;\n    };\n\n  public:\n    // for backwards compatibility accept BasicJsonType\n    using string_t = typename string_t_helper<RefStringType>::type;\n\n    /// @brief create JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/\n    explicit json_pointer(const string_t& s = \"\")\n        : reference_tokens(split(s))\n    {}\n\n    /// @brief return a string representation of the JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/to_string/\n    string_t to_string() const\n    {\n        return std::accumulate(reference_tokens.begin(), reference_tokens.end(),\n                               string_t{},\n                               [](const string_t& a, const string_t& b)\n        {\n            return detail::concat(a, '/', detail::escape(b));\n        });\n    }\n\n    /// @brief return a string representation of the JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_string/\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, to_string())\n    operator string_t() const\n    {\n        return to_string();\n    }\n\n#ifndef JSON_NO_IO\n    /// @brief write string representation of the JSON pointer to stream\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/\n    friend std::ostream& operator<<(std::ostream& o, const json_pointer& ptr)\n    {\n        o << ptr.to_string();\n        return o;\n    }\n#endif\n\n    /// @brief append another JSON pointer at the end of this JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/\n    json_pointer& operator/=(const json_pointer& ptr)\n    {\n        reference_tokens.insert(reference_tokens.end(),\n                                ptr.reference_tokens.begin(),\n                                ptr.reference_tokens.end());\n        return *this;\n    }\n\n    /// @brief append an unescaped reference token at the end of this JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/\n    json_pointer& operator/=(string_t token)\n    {\n        push_back(std::move(token));\n        return *this;\n    }\n\n    /// @brief append an array index at the end of this JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slasheq/\n    json_pointer& operator/=(std::size_t array_idx)\n    {\n        return *this /= std::to_string(array_idx);\n    }\n\n    /// @brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/\n    friend json_pointer operator/(const json_pointer& lhs,\n                                  const json_pointer& rhs)\n    {\n        return json_pointer(lhs) /= rhs;\n    }\n\n    /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/\n    friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)\n    {\n        return json_pointer(lhs) /= std::move(token);\n    }\n\n    /// @brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/\n    friend json_pointer operator/(const json_pointer& lhs, std::size_t array_idx)\n    {\n        return json_pointer(lhs) /= array_idx;\n    }\n\n    /// @brief returns the parent of this JSON pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/parent_pointer/\n    json_pointer parent_pointer() const\n    {\n        if (empty())\n        {\n            return *this;\n        }\n\n        json_pointer res = *this;\n        res.pop_back();\n        return res;\n    }\n\n    /// @brief remove last reference token\n    /// @sa https://json.nlohmann.me/api/json_pointer/pop_back/\n    void pop_back()\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\", nullptr));\n        }\n\n        reference_tokens.pop_back();\n    }\n\n    /// @brief return last reference token\n    /// @sa https://json.nlohmann.me/api/json_pointer/back/\n    const string_t& back() const\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\", nullptr));\n        }\n\n        return reference_tokens.back();\n    }\n\n    /// @brief append an unescaped token at the end of the reference pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/push_back/\n    void push_back(const string_t& token)\n    {\n        reference_tokens.push_back(token);\n    }\n\n    /// @brief append an unescaped token at the end of the reference pointer\n    /// @sa https://json.nlohmann.me/api/json_pointer/push_back/\n    void push_back(string_t&& token)\n    {\n        reference_tokens.push_back(std::move(token));\n    }\n\n    /// @brief return whether pointer points to the root document\n    /// @sa https://json.nlohmann.me/api/json_pointer/empty/\n    bool empty() const noexcept\n    {\n        return reference_tokens.empty();\n    }\n\n  private:\n    /*!\n    @param[in] s  reference token to be converted into an array index\n\n    @return integer representation of @a s\n\n    @throw parse_error.106  if an array index begins with '0'\n    @throw parse_error.109  if an array index begins not with a digit\n    @throw out_of_range.404 if string @a s could not be converted to an integer\n    @throw out_of_range.410 if an array index exceeds size_type\n    */\n    template<typename BasicJsonType>\n    static typename BasicJsonType::size_type array_index(const string_t& s)\n    {\n        using size_type = typename BasicJsonType::size_type;\n\n        // error condition (cf. RFC 6901, Sect. 4)\n        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && s[0] == '0'))\n        {\n            JSON_THROW(detail::parse_error::create(106, 0, detail::concat(\"array index '\", s, \"' must not begin with '0'\"), nullptr));\n        }\n\n        // error condition (cf. RFC 6901, Sect. 4)\n        if (JSON_HEDLEY_UNLIKELY(s.size() > 1 && !(s[0] >= '1' && s[0] <= '9')))\n        {\n            JSON_THROW(detail::parse_error::create(109, 0, detail::concat(\"array index '\", s, \"' is not a number\"), nullptr));\n        }\n\n        const char* p = s.c_str();\n        char* p_end = nullptr; // NOLINT(misc-const-correctness)\n        errno = 0; // strtoull doesn't reset errno\n        const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)\n        if (p == p_end // invalid input or empty string\n                || errno == ERANGE // out of range\n                || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read\n        {\n            JSON_THROW(detail::out_of_range::create(404, detail::concat(\"unresolved reference token '\", s, \"'\"), nullptr));\n        }\n\n        // only triggered on special platforms (like 32bit), see also\n        // https://github.com/nlohmann/json/pull/2203\n        if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)()))  // NOLINT(runtime/int)\n        {\n            JSON_THROW(detail::out_of_range::create(410, detail::concat(\"array index \", s, \" exceeds size_type\"), nullptr));   // LCOV_EXCL_LINE\n        }\n\n        return static_cast<size_type>(res);\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    json_pointer top() const\n    {\n        if (JSON_HEDLEY_UNLIKELY(empty()))\n        {\n            JSON_THROW(detail::out_of_range::create(405, \"JSON pointer has no parent\", nullptr));\n        }\n\n        json_pointer result = *this;\n        result.reference_tokens = {reference_tokens[0]};\n        return result;\n    }\n\n  private:\n    /*!\n    @brief create and return a reference to the pointed to value\n\n    @complexity Linear in the number of reference tokens.\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.313 if value cannot be unflattened\n    */\n    template<typename BasicJsonType>\n    BasicJsonType& get_and_create(BasicJsonType& j) const\n    {\n        auto* result = &j;\n\n        // in case no reference tokens exist, return a reference to the JSON value\n        // j which will be overwritten by a primitive value\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (result->type())\n            {\n                case detail::value_t::null:\n                {\n                    if (reference_token == \"0\")\n                    {\n                        // start a new array if reference token is 0\n                        result = &result->operator[](0);\n                    }\n                    else\n                    {\n                        // start a new object otherwise\n                        result = &result->operator[](reference_token);\n                    }\n                    break;\n                }\n\n                case detail::value_t::object:\n                {\n                    // create an entry in the object\n                    result = &result->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    // create an entry in the array\n                    result = &result->operator[](array_index<BasicJsonType>(reference_token));\n                    break;\n                }\n\n                /*\n                The following code is only reached if there exists a reference\n                token _and_ the current value is primitive. In this case, we have\n                an error situation, because primitive values may only occur as\n                single value; that is, with an empty list of reference tokens.\n                */\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::type_error::create(313, \"invalid value to unflatten\", &j));\n            }\n        }\n\n        return *result;\n    }\n\n    /*!\n    @brief return a reference to the pointed to value\n\n    @note This version does not throw if a value is not present, but tries to\n          create nested values instead. For instance, calling this function\n          with pointer `\"/this/that\"` on a null value is equivalent to calling\n          `operator[](\"this\").operator[](\"that\")` on that value, effectively\n          changing the null value to an object.\n\n    @param[in] ptr  a JSON value\n\n    @return reference to the JSON value pointed to by the JSON pointer\n\n    @complexity Linear in the length of the JSON pointer.\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    template<typename BasicJsonType>\n    BasicJsonType& get_unchecked(BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            // convert null values to arrays or objects before continuing\n            if (ptr->is_null())\n            {\n                // check if reference token is a number\n                const bool nums =\n                    std::all_of(reference_token.begin(), reference_token.end(),\n                                [](const unsigned char x)\n                {\n                    return std::isdigit(x);\n                });\n\n                // change value to array for numbers or \"-\" or to object otherwise\n                *ptr = (nums || reference_token == \"-\")\n                       ? detail::value_t::array\n                       : detail::value_t::object;\n            }\n\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (reference_token == \"-\")\n                    {\n                        // explicitly treat \"-\" as index beyond the end\n                        ptr = &ptr->operator[](ptr->m_data.m_value.array->size());\n                    }\n                    else\n                    {\n                        // convert array index to number; unchecked access\n                        ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));\n                    }\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, detail::concat(\"unresolved reference token '\", reference_token, \"'\"), ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    template<typename BasicJsonType>\n    BasicJsonType& get_checked(BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402, detail::concat(\n                                \"array index '-' (\", std::to_string(ptr->m_data.m_value.array->size()),\n                                \") is out of range\"), ptr));\n                    }\n\n                    // note: at performs range check\n                    ptr = &ptr->at(array_index<BasicJsonType>(reference_token));\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, detail::concat(\"unresolved reference token '\", reference_token, \"'\"), ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @brief return a const reference to the pointed to value\n\n    @param[in] ptr  a JSON value\n\n    @return const reference to the JSON value pointed to by the JSON\n    pointer\n\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    template<typename BasicJsonType>\n    const BasicJsonType& get_unchecked(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // use unchecked object access\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" cannot be used for const access\n                        JSON_THROW(detail::out_of_range::create(402, detail::concat(\"array index '-' (\", std::to_string(ptr->m_data.m_value.array->size()), \") is out of range\"), ptr));\n                    }\n\n                    // use unchecked array access\n                    ptr = &ptr->operator[](array_index<BasicJsonType>(reference_token));\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, detail::concat(\"unresolved reference token '\", reference_token, \"'\"), ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    @throw out_of_range.402  if the array index '-' is used\n    @throw out_of_range.404  if the JSON pointer can not be resolved\n    */\n    template<typename BasicJsonType>\n    const BasicJsonType& get_checked(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    // note: at performs range check\n                    ptr = &ptr->at(reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        JSON_THROW(detail::out_of_range::create(402, detail::concat(\n                                \"array index '-' (\", std::to_string(ptr->m_data.m_value.array->size()),\n                                \") is out of range\"), ptr));\n                    }\n\n                    // note: at performs range check\n                    ptr = &ptr->at(array_index<BasicJsonType>(reference_token));\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                    JSON_THROW(detail::out_of_range::create(404, detail::concat(\"unresolved reference token '\", reference_token, \"'\"), ptr));\n            }\n        }\n\n        return *ptr;\n    }\n\n    /*!\n    @throw parse_error.106   if an array index begins with '0'\n    @throw parse_error.109   if an array index was not a number\n    */\n    template<typename BasicJsonType>\n    bool contains(const BasicJsonType* ptr) const\n    {\n        for (const auto& reference_token : reference_tokens)\n        {\n            switch (ptr->type())\n            {\n                case detail::value_t::object:\n                {\n                    if (!ptr->contains(reference_token))\n                    {\n                        // we did not find the key in the object\n                        return false;\n                    }\n\n                    ptr = &ptr->operator[](reference_token);\n                    break;\n                }\n\n                case detail::value_t::array:\n                {\n                    if (JSON_HEDLEY_UNLIKELY(reference_token == \"-\"))\n                    {\n                        // \"-\" always fails the range check\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() == 1 && !(\"0\" <= reference_token && reference_token <= \"9\")))\n                    {\n                        // invalid char\n                        return false;\n                    }\n                    if (JSON_HEDLEY_UNLIKELY(reference_token.size() > 1))\n                    {\n                        if (JSON_HEDLEY_UNLIKELY(!('1' <= reference_token[0] && reference_token[0] <= '9')))\n                        {\n                            // first char should be between '1' and '9'\n                            return false;\n                        }\n                        for (std::size_t i = 1; i < reference_token.size(); i++)\n                        {\n                            if (JSON_HEDLEY_UNLIKELY(!('0' <= reference_token[i] && reference_token[i] <= '9')))\n                            {\n                                // other char should be between '0' and '9'\n                                return false;\n                            }\n                        }\n                    }\n\n                    const auto idx = array_index<BasicJsonType>(reference_token);\n                    if (idx >= ptr->size())\n                    {\n                        // index out of range\n                        return false;\n                    }\n\n                    ptr = &ptr->operator[](idx);\n                    break;\n                }\n\n                case detail::value_t::null:\n                case detail::value_t::string:\n                case detail::value_t::boolean:\n                case detail::value_t::number_integer:\n                case detail::value_t::number_unsigned:\n                case detail::value_t::number_float:\n                case detail::value_t::binary:\n                case detail::value_t::discarded:\n                default:\n                {\n                    // we do not expect primitive values if there is still a\n                    // reference token to process\n                    return false;\n                }\n            }\n        }\n\n        // no reference token left means we found a primitive value\n        return true;\n    }\n\n    /*!\n    @brief split the string input to reference tokens\n\n    @note This function is only called by the json_pointer constructor.\n          All exceptions below are documented there.\n\n    @throw parse_error.107  if the pointer is not empty or begins with '/'\n    @throw parse_error.108  if character '~' is not followed by '0' or '1'\n    */\n    static std::vector<string_t> split(const string_t& reference_string)\n    {\n        std::vector<string_t> result;\n\n        // special case: empty reference string -> no reference tokens\n        if (reference_string.empty())\n        {\n            return result;\n        }\n\n        // check if nonempty reference string begins with slash\n        if (JSON_HEDLEY_UNLIKELY(reference_string[0] != '/'))\n        {\n            JSON_THROW(detail::parse_error::create(107, 1, detail::concat(\"JSON pointer must be empty or begin with '/' - was: '\", reference_string, \"'\"), nullptr));\n        }\n\n        // extract the reference tokens:\n        // - slash: position of the last read slash (or end of string)\n        // - start: position after the previous slash\n        for (\n            // search for the first slash after the first character\n            std::size_t slash = reference_string.find_first_of('/', 1),\n            // set the beginning of the first reference token\n            start = 1;\n            // we can stop if start == 0 (if slash == string_t::npos)\n            start != 0;\n            // set the beginning of the next reference token\n            // (will eventually be 0 if slash == string_t::npos)\n            start = (slash == string_t::npos) ? 0 : slash + 1,\n            // find next slash\n            slash = reference_string.find_first_of('/', start))\n        {\n            // use the text between the beginning of the reference token\n            // (start) and the last slash (slash).\n            auto reference_token = reference_string.substr(start, slash - start);\n\n            // check reference tokens are properly escaped\n            for (std::size_t pos = reference_token.find_first_of('~');\n                    pos != string_t::npos;\n                    pos = reference_token.find_first_of('~', pos + 1))\n            {\n                JSON_ASSERT(reference_token[pos] == '~');\n\n                // ~ must be followed by 0 or 1\n                if (JSON_HEDLEY_UNLIKELY(pos == reference_token.size() - 1 ||\n                                         (reference_token[pos + 1] != '0' &&\n                                          reference_token[pos + 1] != '1')))\n                {\n                    JSON_THROW(detail::parse_error::create(108, 0, \"escape character '~' must be followed with '0' or '1'\", nullptr));\n                }\n            }\n\n            // finally, store the reference token\n            detail::unescape(reference_token);\n            result.push_back(reference_token);\n        }\n\n        return result;\n    }\n\n  private:\n    /*!\n    @param[in] reference_string  the reference string to the current value\n    @param[in] value             the value to consider\n    @param[in,out] result        the result object to insert values to\n\n    @note Empty objects or arrays are flattened to `null`.\n    */\n    template<typename BasicJsonType>\n    static void flatten(const string_t& reference_string,\n                        const BasicJsonType& value,\n                        BasicJsonType& result)\n    {\n        switch (value.type())\n        {\n            case detail::value_t::array:\n            {\n                if (value.m_data.m_value.array->empty())\n                {\n                    // flatten empty array as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate array and use index as reference string\n                    for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)\n                    {\n                        flatten(detail::concat<string_t>(reference_string, '/', std::to_string(i)),\n                                value.m_data.m_value.array->operator[](i), result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::object:\n            {\n                if (value.m_data.m_value.object->empty())\n                {\n                    // flatten empty object as null\n                    result[reference_string] = nullptr;\n                }\n                else\n                {\n                    // iterate object and use keys as reference string\n                    for (const auto& element : *value.m_data.m_value.object)\n                    {\n                        flatten(detail::concat<string_t>(reference_string, '/', detail::escape(element.first)), element.second, result);\n                    }\n                }\n                break;\n            }\n\n            case detail::value_t::null:\n            case detail::value_t::string:\n            case detail::value_t::boolean:\n            case detail::value_t::number_integer:\n            case detail::value_t::number_unsigned:\n            case detail::value_t::number_float:\n            case detail::value_t::binary:\n            case detail::value_t::discarded:\n            default:\n            {\n                // add primitive value with its reference string\n                result[reference_string] = value;\n                break;\n            }\n        }\n    }\n\n    /*!\n    @param[in] value  flattened JSON\n\n    @return unflattened JSON\n\n    @throw parse_error.109 if array index is not a number\n    @throw type_error.314  if value is not an object\n    @throw type_error.315  if object values are not primitive\n    @throw type_error.313  if value cannot be unflattened\n    */\n    template<typename BasicJsonType>\n    static BasicJsonType\n    unflatten(const BasicJsonType& value)\n    {\n        if (JSON_HEDLEY_UNLIKELY(!value.is_object()))\n        {\n            JSON_THROW(detail::type_error::create(314, \"only objects can be unflattened\", &value));\n        }\n\n        BasicJsonType result;\n\n        // iterate the JSON object values\n        for (const auto& element : *value.m_data.m_value.object)\n        {\n            if (JSON_HEDLEY_UNLIKELY(!element.second.is_primitive()))\n            {\n                JSON_THROW(detail::type_error::create(315, \"values in object must be primitive\", &element.second));\n            }\n\n            // assign value to reference pointed to by JSON pointer; Note that if\n            // the JSON pointer is \"\" (i.e., points to the whole value), function\n            // get_and_create returns a reference to result itself. An assignment\n            // will then create a primitive value.\n            json_pointer(element.first).get_and_create(result) = element.second;\n        }\n\n        return result;\n    }\n\n    // can't use conversion operator because of ambiguity\n    json_pointer<string_t> convert() const&\n    {\n        json_pointer<string_t> result;\n        result.reference_tokens = reference_tokens;\n        return result;\n    }\n\n    json_pointer<string_t> convert()&&\n    {\n        json_pointer<string_t> result;\n        result.reference_tokens = std::move(reference_tokens);\n        return result;\n    }\n\n  public:\n#if JSON_HAS_THREE_WAY_COMPARISON\n    /// @brief compares two JSON pointers for equality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/\n    template<typename RefStringTypeRhs>\n    bool operator==(const json_pointer<RefStringTypeRhs>& rhs) const noexcept\n    {\n        return reference_tokens == rhs.reference_tokens;\n    }\n\n    /// @brief compares JSON pointer and string for equality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer))\n    bool operator==(const string_t& rhs) const\n    {\n        return *this == json_pointer(rhs);\n    }\n\n    /// @brief 3-way compares two JSON pointers\n    template<typename RefStringTypeRhs>\n    std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*\n    {\n        return  reference_tokens <=> rhs.reference_tokens; // *NOPAD*\n    }\n#else\n    /// @brief compares two JSON pointers for equality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/\n    template<typename RefStringTypeLhs, typename RefStringTypeRhs>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,\n                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;\n\n    /// @brief compares JSON pointer and string for equality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/\n    template<typename RefStringTypeLhs, typename StringType>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator==(const json_pointer<RefStringTypeLhs>& lhs,\n                           const StringType& rhs);\n\n    /// @brief compares string and JSON pointer for equality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_eq/\n    template<typename RefStringTypeRhs, typename StringType>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator==(const StringType& lhs,\n                           const json_pointer<RefStringTypeRhs>& rhs);\n\n    /// @brief compares two JSON pointers for inequality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/\n    template<typename RefStringTypeLhs, typename RefStringTypeRhs>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,\n                           const json_pointer<RefStringTypeRhs>& rhs) noexcept;\n\n    /// @brief compares JSON pointer and string for inequality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/\n    template<typename RefStringTypeLhs, typename StringType>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,\n                           const StringType& rhs);\n\n    /// @brief compares string and JSON pointer for inequality\n    /// @sa https://json.nlohmann.me/api/json_pointer/operator_ne/\n    template<typename RefStringTypeRhs, typename StringType>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator!=(const StringType& lhs,\n                           const json_pointer<RefStringTypeRhs>& rhs);\n\n    /// @brief compares two JSON pointer for less-than\n    template<typename RefStringTypeLhs, typename RefStringTypeRhs>\n    // NOLINTNEXTLINE(readability-redundant-declaration)\n    friend bool operator<(const json_pointer<RefStringTypeLhs>& lhs,\n                          const json_pointer<RefStringTypeRhs>& rhs) noexcept;\n#endif\n\n  private:\n    /// the reference tokens\n    std::vector<string_t> reference_tokens;\n};\n\n#if !JSON_HAS_THREE_WAY_COMPARISON\n// functions cannot be defined inside class due to ODR violations\ntemplate<typename RefStringTypeLhs, typename RefStringTypeRhs>\ninline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,\n                       const json_pointer<RefStringTypeRhs>& rhs) noexcept\n{\n    return lhs.reference_tokens == rhs.reference_tokens;\n}\n\ntemplate<typename RefStringTypeLhs,\n         typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>\nJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))\ninline bool operator==(const json_pointer<RefStringTypeLhs>& lhs,\n                       const StringType& rhs)\n{\n    return lhs == json_pointer<RefStringTypeLhs>(rhs);\n}\n\ntemplate<typename RefStringTypeRhs,\n         typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>\nJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator==(json_pointer, json_pointer))\ninline bool operator==(const StringType& lhs,\n                       const json_pointer<RefStringTypeRhs>& rhs)\n{\n    return json_pointer<RefStringTypeRhs>(lhs) == rhs;\n}\n\ntemplate<typename RefStringTypeLhs, typename RefStringTypeRhs>\ninline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,\n                       const json_pointer<RefStringTypeRhs>& rhs) noexcept\n{\n    return !(lhs == rhs);\n}\n\ntemplate<typename RefStringTypeLhs,\n         typename StringType = typename json_pointer<RefStringTypeLhs>::string_t>\nJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))\ninline bool operator!=(const json_pointer<RefStringTypeLhs>& lhs,\n                       const StringType& rhs)\n{\n    return !(lhs == rhs);\n}\n\ntemplate<typename RefStringTypeRhs,\n         typename StringType = typename json_pointer<RefStringTypeRhs>::string_t>\nJSON_HEDLEY_DEPRECATED_FOR(3.11.2, operator!=(json_pointer, json_pointer))\ninline bool operator!=(const StringType& lhs,\n                       const json_pointer<RefStringTypeRhs>& rhs)\n{\n    return !(lhs == rhs);\n}\n\ntemplate<typename RefStringTypeLhs, typename RefStringTypeRhs>\ninline bool operator<(const json_pointer<RefStringTypeLhs>& lhs,\n                      const json_pointer<RefStringTypeRhs>& rhs) noexcept\n{\n    return lhs.reference_tokens < rhs.reference_tokens;\n}\n#endif\n\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/json_ref.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <initializer_list>\n#include <utility>\n\n// #include <nlohmann/detail/abi_macros.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\ntemplate<typename BasicJsonType>\nclass json_ref\n{\n  public:\n    using value_type = BasicJsonType;\n\n    json_ref(value_type&& value)\n        : owned_value(std::move(value))\n    {}\n\n    json_ref(const value_type& value)\n        : value_ref(&value)\n    {}\n\n    json_ref(std::initializer_list<json_ref> init)\n        : owned_value(init)\n    {}\n\n    template <\n        class... Args,\n        enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 >\n    json_ref(Args && ... args)\n        : owned_value(std::forward<Args>(args)...)\n    {}\n\n    // class should be movable only\n    json_ref(json_ref&&) noexcept = default;\n    json_ref(const json_ref&) = delete;\n    json_ref& operator=(const json_ref&) = delete;\n    json_ref& operator=(json_ref&&) = delete;\n    ~json_ref() = default;\n\n    value_type moved_or_copied() const\n    {\n        if (value_ref == nullptr)\n        {\n            return std::move(owned_value);\n        }\n        return *value_ref;\n    }\n\n    value_type const& operator*() const\n    {\n        return value_ref ? *value_ref : owned_value;\n    }\n\n    value_type const* operator->() const\n    {\n        return &** this;\n    }\n\n  private:\n    mutable value_type owned_value = nullptr;\n    value_type const* value_ref = nullptr;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n// #include <nlohmann/detail/string_escape.hpp>\n\n// #include <nlohmann/detail/string_utils.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <algorithm> // reverse\n#include <array> // array\n#include <map> // map\n#include <cmath> // isnan, isinf\n#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t\n#include <cstring> // memcpy\n#include <limits> // numeric_limits\n#include <string> // string\n#include <utility> // move\n#include <vector> // vector\n\n// #include <nlohmann/detail/input/binary_reader.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <algorithm> // copy\n#include <cstddef> // size_t\n#include <iterator> // back_inserter\n#include <memory> // shared_ptr, make_shared\n#include <string> // basic_string\n#include <vector> // vector\n\n#ifndef JSON_NO_IO\n    #include <ios>      // streamsize\n    #include <ostream>  // basic_ostream\n#endif  // JSON_NO_IO\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/// abstract output adapter interface\ntemplate<typename CharType> struct output_adapter_protocol\n{\n    virtual void write_character(CharType c) = 0;\n    virtual void write_characters(const CharType* s, std::size_t length) = 0;\n    virtual ~output_adapter_protocol() = default;\n\n    output_adapter_protocol() = default;\n    output_adapter_protocol(const output_adapter_protocol&) = default;\n    output_adapter_protocol(output_adapter_protocol&&) noexcept = default;\n    output_adapter_protocol& operator=(const output_adapter_protocol&) = default;\n    output_adapter_protocol& operator=(output_adapter_protocol&&) noexcept = default;\n};\n\n/// a type to simplify interfaces\ntemplate<typename CharType>\nusing output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;\n\n/// output adapter for byte vectors\ntemplate<typename CharType, typename AllocatorType = std::allocator<CharType>>\nclass output_vector_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept\n        : v(vec)\n    {}\n\n    void write_character(CharType c) override\n    {\n        v.push_back(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        v.insert(v.end(), s, s + length);\n    }\n\n  private:\n    std::vector<CharType, AllocatorType>& v;\n};\n\n#ifndef JSON_NO_IO\n/// output adapter for output streams\ntemplate<typename CharType>\nclass output_stream_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept\n        : stream(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        stream.put(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        stream.write(s, static_cast<std::streamsize>(length));\n    }\n\n  private:\n    std::basic_ostream<CharType>& stream;\n};\n#endif  // JSON_NO_IO\n\n/// output adapter for basic_string\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_string_adapter : public output_adapter_protocol<CharType>\n{\n  public:\n    explicit output_string_adapter(StringType& s) noexcept\n        : str(s)\n    {}\n\n    void write_character(CharType c) override\n    {\n        str.push_back(c);\n    }\n\n    JSON_HEDLEY_NON_NULL(2)\n    void write_characters(const CharType* s, std::size_t length) override\n    {\n        str.append(s, length);\n    }\n\n  private:\n    StringType& str;\n};\n\ntemplate<typename CharType, typename StringType = std::basic_string<CharType>>\nclass output_adapter\n{\n  public:\n    template<typename AllocatorType = std::allocator<CharType>>\n    output_adapter(std::vector<CharType, AllocatorType>& vec)\n        : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {}\n\n#ifndef JSON_NO_IO\n    output_adapter(std::basic_ostream<CharType>& s)\n        : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}\n#endif  // JSON_NO_IO\n\n    output_adapter(StringType& s)\n        : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}\n\n    operator output_adapter_t<CharType>()\n    {\n        return oa;\n    }\n\n  private:\n    output_adapter_t<CharType> oa = nullptr;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/// how to encode BJData\nenum class bjdata_version_t\n{\n    draft2,\n    draft3,\n};\n\n///////////////////\n// binary writer //\n///////////////////\n\n/*!\n@brief serialization to CBOR and MessagePack values\n*/\ntemplate<typename BasicJsonType, typename CharType>\nclass binary_writer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using binary_t = typename BasicJsonType::binary_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n\n  public:\n    /*!\n    @brief create a binary writer\n\n    @param[in] adapter  output adapter to write to\n    */\n    explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter))\n    {\n        JSON_ASSERT(oa);\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @pre       j.type() == value_t::object\n    */\n    void write_bson(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n            {\n                write_bson_object(*j.m_data.m_value.object);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::array:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                JSON_THROW(type_error::create(317, concat(\"to serialize to BSON, top-level type must be object, but is \", j.type_name()), &j));\n            }\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_cbor(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                oa->write_character(to_char_type(0xF6));\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                oa->write_character(j.m_data.m_value.boolean\n                                    ? to_char_type(0xF5)\n                                    : to_char_type(0xF4));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_data.m_value.number_integer >= 0)\n                {\n                    // CBOR does not differentiate between positive signed\n                    // integers and unsigned integers. Therefore, we used the\n                    // code from the value_t::number_unsigned case here.\n                    if (j.m_data.m_value.number_integer <= 0x17)\n                    {\n                        write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x18));\n                        write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x19));\n                        write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x1A));\n                        write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x1B));\n                        write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    // The conversions below encode the sign in the first\n                    // byte, and the value is converted to a positive number.\n                    const auto positive_number = -1 - j.m_data.m_value.number_integer;\n                    if (j.m_data.m_value.number_integer >= -24)\n                    {\n                        write_number(static_cast<std::uint8_t>(0x20 + positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x38));\n                        write_number(static_cast<std::uint8_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x39));\n                        write_number(static_cast<std::uint16_t>(positive_number));\n                    }\n                    else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        oa->write_character(to_char_type(0x3A));\n                        write_number(static_cast<std::uint32_t>(positive_number));\n                    }\n                    else\n                    {\n                        oa->write_character(to_char_type(0x3B));\n                        write_number(static_cast<std::uint64_t>(positive_number));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_data.m_value.number_unsigned <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x18));\n                    write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_unsigned));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x19));\n                    write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_unsigned));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x1A));\n                    write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_unsigned));\n                }\n                else\n                {\n                    oa->write_character(to_char_type(0x1B));\n                    write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                if (std::isnan(j.m_data.m_value.number_float))\n                {\n                    // NaN is 0xf97e00 in CBOR\n                    oa->write_character(to_char_type(0xF9));\n                    oa->write_character(to_char_type(0x7E));\n                    oa->write_character(to_char_type(0x00));\n                }\n                else if (std::isinf(j.m_data.m_value.number_float))\n                {\n                    // Infinity is 0xf97c00, -Infinity is 0xf9fc00\n                    oa->write_character(to_char_type(0xf9));\n                    oa->write_character(j.m_data.m_value.number_float > 0 ? to_char_type(0x7C) : to_char_type(0xFC));\n                    oa->write_character(to_char_type(0x00));\n                }\n                else\n                {\n                    write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::cbor);\n                }\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_data.m_value.string->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x60 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x78));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x79));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x7B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),\n                    j.m_data.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_data.m_value.array->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x80 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x98));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x99));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x9B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_data.m_value.array)\n                {\n                    write_cbor(el);\n                }\n                break;\n            }\n\n            case value_t::binary:\n            {\n                if (j.m_data.m_value.binary->has_subtype())\n                {\n                    if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xd8));\n                        write_number(static_cast<std::uint8_t>(j.m_data.m_value.binary->subtype()));\n                    }\n                    else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xd9));\n                        write_number(static_cast<std::uint16_t>(j.m_data.m_value.binary->subtype()));\n                    }\n                    else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xda));\n                        write_number(static_cast<std::uint32_t>(j.m_data.m_value.binary->subtype()));\n                    }\n                    else if (j.m_data.m_value.binary->subtype() <= (std::numeric_limits<std::uint64_t>::max)())\n                    {\n                        write_number(static_cast<std::uint8_t>(0xdb));\n                        write_number(static_cast<std::uint64_t>(j.m_data.m_value.binary->subtype()));\n                    }\n                }\n\n                // step 1: write control byte and the binary array size\n                const auto N = j.m_data.m_value.binary->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0x40 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x58));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x59));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x5A));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0x5B));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),\n                    N);\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_data.m_value.object->size();\n                if (N <= 0x17)\n                {\n                    write_number(static_cast<std::uint8_t>(0xA0 + N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB8));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xB9));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBA));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n                // LCOV_EXCL_START\n                else if (N <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    oa->write_character(to_char_type(0xBB));\n                    write_number(static_cast<std::uint64_t>(N));\n                }\n                // LCOV_EXCL_STOP\n\n                // step 2: write each element\n                for (const auto& el : *j.m_data.m_value.object)\n                {\n                    write_cbor(el.first);\n                    write_cbor(el.second);\n                }\n                break;\n            }\n\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    */\n    void write_msgpack(const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::null: // nil\n            {\n                oa->write_character(to_char_type(0xC0));\n                break;\n            }\n\n            case value_t::boolean: // true and false\n            {\n                oa->write_character(j.m_data.m_value.boolean\n                                    ? to_char_type(0xC3)\n                                    : to_char_type(0xC2));\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                if (j.m_data.m_value.number_integer >= 0)\n                {\n                    // MessagePack does not differentiate between positive\n                    // signed integers and unsigned integers. Therefore, we used\n                    // the code from the value_t::number_unsigned case here.\n                    if (j.m_data.m_value.number_unsigned < 128)\n                    {\n                        // positive fixnum\n                        write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                    {\n                        // uint 8\n                        oa->write_character(to_char_type(0xCC));\n                        write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                    {\n                        // uint 16\n                        oa->write_character(to_char_type(0xCD));\n                        write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                    {\n                        // uint 32\n                        oa->write_character(to_char_type(0xCE));\n                        write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                    {\n                        // uint 64\n                        oa->write_character(to_char_type(0xCF));\n                        write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));\n                    }\n                }\n                else\n                {\n                    if (j.m_data.m_value.number_integer >= -32)\n                    {\n                        // negative fixnum\n                        write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() &&\n                             j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n                    {\n                        // int 8\n                        oa->write_character(to_char_type(0xD0));\n                        write_number(static_cast<std::int8_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() &&\n                             j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n                    {\n                        // int 16\n                        oa->write_character(to_char_type(0xD1));\n                        write_number(static_cast<std::int16_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() &&\n                             j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n                    {\n                        // int 32\n                        oa->write_character(to_char_type(0xD2));\n                        write_number(static_cast<std::int32_t>(j.m_data.m_value.number_integer));\n                    }\n                    else if (j.m_data.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() &&\n                             j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n                    {\n                        // int 64\n                        oa->write_character(to_char_type(0xD3));\n                        write_number(static_cast<std::int64_t>(j.m_data.m_value.number_integer));\n                    }\n                }\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_data.m_value.number_unsigned < 128)\n                {\n                    // positive fixnum\n                    write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    // uint 8\n                    oa->write_character(to_char_type(0xCC));\n                    write_number(static_cast<std::uint8_t>(j.m_data.m_value.number_integer));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // uint 16\n                    oa->write_character(to_char_type(0xCD));\n                    write_number(static_cast<std::uint16_t>(j.m_data.m_value.number_integer));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // uint 32\n                    oa->write_character(to_char_type(0xCE));\n                    write_number(static_cast<std::uint32_t>(j.m_data.m_value.number_integer));\n                }\n                else if (j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    // uint 64\n                    oa->write_character(to_char_type(0xCF));\n                    write_number(static_cast<std::uint64_t>(j.m_data.m_value.number_integer));\n                }\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_compact_float(j.m_data.m_value.number_float, detail::input_format_t::msgpack);\n                break;\n            }\n\n            case value_t::string:\n            {\n                // step 1: write control byte and the string length\n                const auto N = j.m_data.m_value.string->size();\n                if (N <= 31)\n                {\n                    // fixstr\n                    write_number(static_cast<std::uint8_t>(0xA0 | N));\n                }\n                else if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    // str 8\n                    oa->write_character(to_char_type(0xD9));\n                    write_number(static_cast<std::uint8_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // str 16\n                    oa->write_character(to_char_type(0xDA));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // str 32\n                    oa->write_character(to_char_type(0xDB));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write the string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),\n                    j.m_data.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                // step 1: write control byte and the array size\n                const auto N = j.m_data.m_value.array->size();\n                if (N <= 15)\n                {\n                    // fixarray\n                    write_number(static_cast<std::uint8_t>(0x90 | N));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // array 16\n                    oa->write_character(to_char_type(0xDC));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // array 32\n                    oa->write_character(to_char_type(0xDD));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_data.m_value.array)\n                {\n                    write_msgpack(el);\n                }\n                break;\n            }\n\n            case value_t::binary:\n            {\n                // step 0: determine if the binary type has a set subtype to\n                // determine whether to use the ext or fixext types\n                const bool use_ext = j.m_data.m_value.binary->has_subtype();\n\n                // step 1: write control byte and the byte string length\n                const auto N = j.m_data.m_value.binary->size();\n                if (N <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    std::uint8_t output_type{};\n                    bool fixed = true;\n                    if (use_ext)\n                    {\n                        switch (N)\n                        {\n                            case 1:\n                                output_type = 0xD4; // fixext 1\n                                break;\n                            case 2:\n                                output_type = 0xD5; // fixext 2\n                                break;\n                            case 4:\n                                output_type = 0xD6; // fixext 4\n                                break;\n                            case 8:\n                                output_type = 0xD7; // fixext 8\n                                break;\n                            case 16:\n                                output_type = 0xD8; // fixext 16\n                                break;\n                            default:\n                                output_type = 0xC7; // ext 8\n                                fixed = false;\n                                break;\n                        }\n\n                    }\n                    else\n                    {\n                        output_type = 0xC4; // bin 8\n                        fixed = false;\n                    }\n\n                    oa->write_character(to_char_type(output_type));\n                    if (!fixed)\n                    {\n                        write_number(static_cast<std::uint8_t>(N));\n                    }\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    const std::uint8_t output_type = use_ext\n                                                     ? 0xC8 // ext 16\n                                                     : 0xC5; // bin 16\n\n                    oa->write_character(to_char_type(output_type));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    const std::uint8_t output_type = use_ext\n                                                     ? 0xC9 // ext 32\n                                                     : 0xC6; // bin 32\n\n                    oa->write_character(to_char_type(output_type));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 1.5: if this is an ext type, write the subtype\n                if (use_ext)\n                {\n                    write_number(static_cast<std::int8_t>(j.m_data.m_value.binary->subtype()));\n                }\n\n                // step 2: write the byte string\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),\n                    N);\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // step 1: write control byte and the object size\n                const auto N = j.m_data.m_value.object->size();\n                if (N <= 15)\n                {\n                    // fixmap\n                    write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));\n                }\n                else if (N <= (std::numeric_limits<std::uint16_t>::max)())\n                {\n                    // map 16\n                    oa->write_character(to_char_type(0xDE));\n                    write_number(static_cast<std::uint16_t>(N));\n                }\n                else if (N <= (std::numeric_limits<std::uint32_t>::max)())\n                {\n                    // map 32\n                    oa->write_character(to_char_type(0xDF));\n                    write_number(static_cast<std::uint32_t>(N));\n                }\n\n                // step 2: write each element\n                for (const auto& el : *j.m_data.m_value.object)\n                {\n                    write_msgpack(el.first);\n                    write_msgpack(el.second);\n                }\n                break;\n            }\n\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n    /*!\n    @param[in] j  JSON value to serialize\n    @param[in] use_count   whether to use '#' prefixes (optimized format)\n    @param[in] use_type    whether to use '$' prefixes (optimized format)\n    @param[in] add_prefix  whether prefixes need to be used for this value\n    @param[in] use_bjdata  whether write in BJData format, default is false\n    @param[in] bjdata_version  which BJData version to use, default is draft2\n    */\n    void write_ubjson(const BasicJsonType& j, const bool use_count,\n                      const bool use_type, const bool add_prefix = true,\n                      const bool use_bjdata = false, const bjdata_version_t bjdata_version = bjdata_version_t::draft2)\n    {\n        const bool bjdata_draft3 = use_bjdata && bjdata_version == bjdata_version_t::draft3;\n\n        switch (j.type())\n        {\n            case value_t::null:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('Z'));\n                }\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(j.m_data.m_value.boolean\n                                        ? to_char_type('T')\n                                        : to_char_type('F'));\n                }\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                write_number_with_ubjson_prefix(j.m_data.m_value.number_integer, add_prefix, use_bjdata);\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                write_number_with_ubjson_prefix(j.m_data.m_value.number_unsigned, add_prefix, use_bjdata);\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                write_number_with_ubjson_prefix(j.m_data.m_value.number_float, add_prefix, use_bjdata);\n                break;\n            }\n\n            case value_t::string:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('S'));\n                }\n                write_number_with_ubjson_prefix(j.m_data.m_value.string->size(), true, use_bjdata);\n                oa->write_characters(\n                    reinterpret_cast<const CharType*>(j.m_data.m_value.string->c_str()),\n                    j.m_data.m_value.string->size());\n                break;\n            }\n\n            case value_t::array:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                bool prefix_required = true;\n                if (use_type && !j.m_data.m_value.array->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);\n                    const bool same_prefix = std::all_of(j.begin() + 1, j.end(),\n                                                         [this, first_prefix, use_bjdata](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v, use_bjdata) == first_prefix;\n                    });\n\n                    std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type\n\n                    if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_data.m_value.array->size(), true, use_bjdata);\n                }\n\n                for (const auto& el : *j.m_data.m_value.array)\n                {\n                    write_ubjson(el, use_count, use_type, prefix_required, use_bjdata, bjdata_version);\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::binary:\n            {\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('['));\n                }\n\n                if (use_type && (bjdata_draft3 || !j.m_data.m_value.binary->empty()))\n                {\n                    JSON_ASSERT(use_count);\n                    oa->write_character(to_char_type('$'));\n                    oa->write_character(bjdata_draft3 ? 'B' : 'U');\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_data.m_value.binary->size(), true, use_bjdata);\n                }\n\n                if (use_type)\n                {\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(j.m_data.m_value.binary->data()),\n                        j.m_data.m_value.binary->size());\n                }\n                else\n                {\n                    for (size_t i = 0; i < j.m_data.m_value.binary->size(); ++i)\n                    {\n                        oa->write_character(to_char_type(bjdata_draft3 ? 'B' : 'U'));\n                        oa->write_character(j.m_data.m_value.binary->data()[i]);\n                    }\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type(']'));\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                if (use_bjdata && j.m_data.m_value.object->size() == 3 && j.m_data.m_value.object->find(\"_ArrayType_\") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find(\"_ArraySize_\") != j.m_data.m_value.object->end() && j.m_data.m_value.object->find(\"_ArrayData_\") != j.m_data.m_value.object->end())\n                {\n                    if (!write_bjdata_ndarray(*j.m_data.m_value.object, use_count, use_type, bjdata_version))  // decode bjdata ndarray in the JData format (https://github.com/NeuroJSON/jdata)\n                    {\n                        break;\n                    }\n                }\n\n                if (add_prefix)\n                {\n                    oa->write_character(to_char_type('{'));\n                }\n\n                bool prefix_required = true;\n                if (use_type && !j.m_data.m_value.object->empty())\n                {\n                    JSON_ASSERT(use_count);\n                    const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);\n                    const bool same_prefix = std::all_of(j.begin(), j.end(),\n                                                         [this, first_prefix, use_bjdata](const BasicJsonType & v)\n                    {\n                        return ubjson_prefix(v, use_bjdata) == first_prefix;\n                    });\n\n                    std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type\n\n                    if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))\n                    {\n                        prefix_required = false;\n                        oa->write_character(to_char_type('$'));\n                        oa->write_character(first_prefix);\n                    }\n                }\n\n                if (use_count)\n                {\n                    oa->write_character(to_char_type('#'));\n                    write_number_with_ubjson_prefix(j.m_data.m_value.object->size(), true, use_bjdata);\n                }\n\n                for (const auto& el : *j.m_data.m_value.object)\n                {\n                    write_number_with_ubjson_prefix(el.first.size(), true, use_bjdata);\n                    oa->write_characters(\n                        reinterpret_cast<const CharType*>(el.first.c_str()),\n                        el.first.size());\n                    write_ubjson(el.second, use_count, use_type, prefix_required, use_bjdata, bjdata_version);\n                }\n\n                if (!use_count)\n                {\n                    oa->write_character(to_char_type('}'));\n                }\n\n                break;\n            }\n\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n  private:\n    //////////\n    // BSON //\n    //////////\n\n    /*!\n    @return The size of a BSON document entry header, including the id marker\n            and the entry name size (and its null-terminator).\n    */\n    static std::size_t calc_bson_entry_header_size(const string_t& name, const BasicJsonType& j)\n    {\n        const auto it = name.find(static_cast<typename string_t::value_type>(0));\n        if (JSON_HEDLEY_UNLIKELY(it != BasicJsonType::string_t::npos))\n        {\n            JSON_THROW(out_of_range::create(409, concat(\"BSON key cannot contain code point U+0000 (at byte \", std::to_string(it), \")\"), &j));\n            static_cast<void>(j);\n        }\n\n        return /*id*/ 1ul + name.size() + /*zero-terminator*/1u;\n    }\n\n    /*!\n    @brief Writes the given @a element_type and @a name to the output adapter\n    */\n    void write_bson_entry_header(const string_t& name,\n                                 const std::uint8_t element_type)\n    {\n        oa->write_character(to_char_type(element_type)); // boolean\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(name.c_str()),\n            name.size() + 1u);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and boolean value @a value\n    */\n    void write_bson_boolean(const string_t& name,\n                            const bool value)\n    {\n        write_bson_entry_header(name, 0x08);\n        oa->write_character(value ? to_char_type(0x01) : to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and double value @a value\n    */\n    void write_bson_double(const string_t& name,\n                           const double value)\n    {\n        write_bson_entry_header(name, 0x01);\n        write_number<double>(value, true);\n    }\n\n    /*!\n    @return The size of the BSON-encoded string in @a value\n    */\n    static std::size_t calc_bson_string_size(const string_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and string value @a value\n    */\n    void write_bson_string(const string_t& name,\n                           const string_t& value)\n    {\n        write_bson_entry_header(name, 0x02);\n\n        write_number<std::int32_t>(static_cast<std::int32_t>(value.size() + 1ul), true);\n        oa->write_characters(\n            reinterpret_cast<const CharType*>(value.c_str()),\n            value.size() + 1);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and null value\n    */\n    void write_bson_null(const string_t& name)\n    {\n        write_bson_entry_header(name, 0x0A);\n    }\n\n    /*!\n    @return The size of the BSON-encoded integer @a value\n    */\n    static std::size_t calc_bson_integer_size(const std::int64_t value)\n    {\n        return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and integer @a value\n    */\n    void write_bson_integer(const string_t& name,\n                            const std::int64_t value)\n    {\n        if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            write_bson_entry_header(name, 0x10); // int32\n            write_number<std::int32_t>(static_cast<std::int32_t>(value), true);\n        }\n        else\n        {\n            write_bson_entry_header(name, 0x12); // int64\n            write_number<std::int64_t>(static_cast<std::int64_t>(value), true);\n        }\n    }\n\n    /*!\n    @return The size of the BSON-encoded unsigned integer in @a j\n    */\n    static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept\n    {\n        return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n               ? sizeof(std::int32_t)\n               : sizeof(std::int64_t);\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and unsigned @a value\n    */\n    void write_bson_unsigned(const string_t& name,\n                             const BasicJsonType& j)\n    {\n        if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x10 /* int32 */);\n            write_number<std::int32_t>(static_cast<std::int32_t>(j.m_data.m_value.number_unsigned), true);\n        }\n        else if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            write_bson_entry_header(name, 0x12 /* int64 */);\n            write_number<std::int64_t>(static_cast<std::int64_t>(j.m_data.m_value.number_unsigned), true);\n        }\n        else\n        {\n            write_bson_entry_header(name, 0x11 /* uint64 */);\n            write_number<std::uint64_t>(static_cast<std::uint64_t>(j.m_data.m_value.number_unsigned), true);\n        }\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and object @a value\n    */\n    void write_bson_object_entry(const string_t& name,\n                                 const typename BasicJsonType::object_t& value)\n    {\n        write_bson_entry_header(name, 0x03); // object\n        write_bson_object(value);\n    }\n\n    /*!\n    @return The size of the BSON-encoded array @a value\n    */\n    static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value)\n    {\n        std::size_t array_index = 0ul;\n\n        const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el)\n        {\n            return result + calc_bson_element_size(std::to_string(array_index++), el);\n        });\n\n        return sizeof(std::int32_t) + embedded_document_size + 1ul;\n    }\n\n    /*!\n    @return The size of the BSON-encoded binary array @a value\n    */\n    static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)\n    {\n        return sizeof(std::int32_t) + value.size() + 1ul;\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and array @a value\n    */\n    void write_bson_array(const string_t& name,\n                          const typename BasicJsonType::array_t& value)\n    {\n        write_bson_entry_header(name, 0x04); // array\n        write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);\n\n        std::size_t array_index = 0ul;\n\n        for (const auto& el : value)\n        {\n            write_bson_element(std::to_string(array_index++), el);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    /*!\n    @brief Writes a BSON element with key @a name and binary value @a value\n    */\n    void write_bson_binary(const string_t& name,\n                           const binary_t& value)\n    {\n        write_bson_entry_header(name, 0x05);\n\n        write_number<std::int32_t>(static_cast<std::int32_t>(value.size()), true);\n        write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));\n\n        oa->write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());\n    }\n\n    /*!\n    @brief Calculates the size necessary to serialize the JSON value @a j with its @a name\n    @return The calculated size for the BSON document entry for @a j with the given @a name.\n    */\n    static std::size_t calc_bson_element_size(const string_t& name,\n            const BasicJsonType& j)\n    {\n        const auto header_size = calc_bson_entry_header_size(name, j);\n        switch (j.type())\n        {\n            case value_t::object:\n                return header_size + calc_bson_object_size(*j.m_data.m_value.object);\n\n            case value_t::array:\n                return header_size + calc_bson_array_size(*j.m_data.m_value.array);\n\n            case value_t::binary:\n                return header_size + calc_bson_binary_size(*j.m_data.m_value.binary);\n\n            case value_t::boolean:\n                return header_size + 1ul;\n\n            case value_t::number_float:\n                return header_size + 8ul;\n\n            case value_t::number_integer:\n                return header_size + calc_bson_integer_size(j.m_data.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return header_size + calc_bson_unsigned_size(j.m_data.m_value.number_unsigned);\n\n            case value_t::string:\n                return header_size + calc_bson_string_size(*j.m_data.m_value.string);\n\n            case value_t::null:\n                return header_size + 0ul;\n\n            // LCOV_EXCL_START\n            case value_t::discarded:\n            default:\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)\n                return 0ul;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Serializes the JSON value @a j to BSON and associates it with the\n           key @a name.\n    @param name The name to associate with the JSON entity @a j within the\n                current BSON document\n    */\n    void write_bson_element(const string_t& name,\n                            const BasicJsonType& j)\n    {\n        switch (j.type())\n        {\n            case value_t::object:\n                return write_bson_object_entry(name, *j.m_data.m_value.object);\n\n            case value_t::array:\n                return write_bson_array(name, *j.m_data.m_value.array);\n\n            case value_t::binary:\n                return write_bson_binary(name, *j.m_data.m_value.binary);\n\n            case value_t::boolean:\n                return write_bson_boolean(name, j.m_data.m_value.boolean);\n\n            case value_t::number_float:\n                return write_bson_double(name, j.m_data.m_value.number_float);\n\n            case value_t::number_integer:\n                return write_bson_integer(name, j.m_data.m_value.number_integer);\n\n            case value_t::number_unsigned:\n                return write_bson_unsigned(name, j);\n\n            case value_t::string:\n                return write_bson_string(name, *j.m_data.m_value.string);\n\n            case value_t::null:\n                return write_bson_null(name);\n\n            // LCOV_EXCL_START\n            case value_t::discarded:\n            default:\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)\n                return;\n                // LCOV_EXCL_STOP\n        }\n    }\n\n    /*!\n    @brief Calculates the size of the BSON serialization of the given\n           JSON-object @a j.\n    @param[in] value  JSON value to serialize\n    @pre       value.type() == value_t::object\n    */\n    static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)\n    {\n        const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0),\n                                          [](size_t result, const typename BasicJsonType::object_t::value_type & el)\n        {\n            return result += calc_bson_element_size(el.first, el.second);\n        });\n\n        return sizeof(std::int32_t) + document_size + 1ul;\n    }\n\n    /*!\n    @param[in] value  JSON value to serialize\n    @pre       value.type() == value_t::object\n    */\n    void write_bson_object(const typename BasicJsonType::object_t& value)\n    {\n        write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_object_size(value)), true);\n\n        for (const auto& el : value)\n        {\n            write_bson_element(el.first, el.second);\n        }\n\n        oa->write_character(to_char_type(0x00));\n    }\n\n    //////////\n    // CBOR //\n    //////////\n\n    static constexpr CharType get_cbor_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xFA);  // Single-Precision Float\n    }\n\n    static constexpr CharType get_cbor_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xFB);  // Double-Precision Float\n    }\n\n    /////////////\n    // MsgPack //\n    /////////////\n\n    static constexpr CharType get_msgpack_float_prefix(float /*unused*/)\n    {\n        return to_char_type(0xCA);  // float 32\n    }\n\n    static constexpr CharType get_msgpack_float_prefix(double /*unused*/)\n    {\n        return to_char_type(0xCB);  // float 64\n    }\n\n    ////////////\n    // UBJSON //\n    ////////////\n\n    // UBJSON: write number (floating point)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_floating_point<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix,\n                                         const bool use_bjdata)\n    {\n        if (add_prefix)\n        {\n            oa->write_character(get_ubjson_float_prefix(n));\n        }\n        write_number(n, use_bjdata);\n    }\n\n    // UBJSON: write number (unsigned integer)\n    template<typename NumberType, typename std::enable_if<\n                 std::is_unsigned<NumberType>::value, int>::type = 0>\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix,\n                                         const bool use_bjdata)\n    {\n        if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<std::uint8_t>(n), use_bjdata);\n        }\n        else if (n <= (std::numeric_limits<std::uint8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<std::uint8_t>(n), use_bjdata);\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<std::int16_t>(n), use_bjdata);\n        }\n        else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint16_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('u'));  // uint16 - bjdata only\n            }\n            write_number(static_cast<std::uint16_t>(n), use_bjdata);\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<std::int32_t>(n), use_bjdata);\n        }\n        else if (use_bjdata && n <= static_cast<uint64_t>((std::numeric_limits<uint32_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('m'));  // uint32 - bjdata only\n            }\n            write_number(static_cast<std::uint32_t>(n), use_bjdata);\n        }\n        else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<std::int64_t>(n), use_bjdata);\n        }\n        else if (use_bjdata && n <= (std::numeric_limits<uint64_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('M'));  // uint64 - bjdata only\n            }\n            write_number(static_cast<std::uint64_t>(n), use_bjdata);\n        }\n        else\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('H'));  // high-precision number\n            }\n\n            const auto number = BasicJsonType(n).dump();\n            write_number_with_ubjson_prefix(number.size(), true, use_bjdata);\n            for (std::size_t i = 0; i < number.size(); ++i)\n            {\n                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));\n            }\n        }\n    }\n\n    // UBJSON: write number (signed integer)\n    template < typename NumberType, typename std::enable_if <\n                   std::is_signed<NumberType>::value&&\n                   !std::is_floating_point<NumberType>::value, int >::type = 0 >\n    void write_number_with_ubjson_prefix(const NumberType n,\n                                         const bool add_prefix,\n                                         const bool use_bjdata)\n    {\n        if ((std::numeric_limits<std::int8_t>::min)() <= n && n <= (std::numeric_limits<std::int8_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('i'));  // int8\n            }\n            write_number(static_cast<std::int8_t>(n), use_bjdata);\n        }\n        else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('U'));  // uint8\n            }\n            write_number(static_cast<std::uint8_t>(n), use_bjdata);\n        }\n        else if ((std::numeric_limits<std::int16_t>::min)() <= n && n <= (std::numeric_limits<std::int16_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('I'));  // int16\n            }\n            write_number(static_cast<std::int16_t>(n), use_bjdata);\n        }\n        else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint16_t>::max)())))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('u'));  // uint16 - bjdata only\n            }\n            write_number(static_cast<uint16_t>(n), use_bjdata);\n        }\n        else if ((std::numeric_limits<std::int32_t>::min)() <= n && n <= (std::numeric_limits<std::int32_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('l'));  // int32\n            }\n            write_number(static_cast<std::int32_t>(n), use_bjdata);\n        }\n        else if (use_bjdata && (static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::min)()) <= n && n <= static_cast<std::int64_t>((std::numeric_limits<std::uint32_t>::max)())))\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('m'));  // uint32 - bjdata only\n            }\n            write_number(static_cast<uint32_t>(n), use_bjdata);\n        }\n        else if ((std::numeric_limits<std::int64_t>::min)() <= n && n <= (std::numeric_limits<std::int64_t>::max)())\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('L'));  // int64\n            }\n            write_number(static_cast<std::int64_t>(n), use_bjdata);\n        }\n        // LCOV_EXCL_START\n        else\n        {\n            if (add_prefix)\n            {\n                oa->write_character(to_char_type('H'));  // high-precision number\n            }\n\n            const auto number = BasicJsonType(n).dump();\n            write_number_with_ubjson_prefix(number.size(), true, use_bjdata);\n            for (std::size_t i = 0; i < number.size(); ++i)\n            {\n                oa->write_character(to_char_type(static_cast<std::uint8_t>(number[i])));\n            }\n        }\n        // LCOV_EXCL_STOP\n    }\n\n    /*!\n    @brief determine the type prefix of container values\n    */\n    CharType ubjson_prefix(const BasicJsonType& j, const bool use_bjdata) const noexcept\n    {\n        switch (j.type())\n        {\n            case value_t::null:\n                return 'Z';\n\n            case value_t::boolean:\n                return j.m_data.m_value.boolean ? 'T' : 'F';\n\n            case value_t::number_integer:\n            {\n                if ((std::numeric_limits<std::int8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())\n                {\n                    return 'i';\n                }\n                if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())\n                {\n                    return 'U';\n                }\n                if ((std::numeric_limits<std::int16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())\n                {\n                    return 'I';\n                }\n                if (use_bjdata && ((std::numeric_limits<std::uint16_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)()))\n                {\n                    return 'u';\n                }\n                if ((std::numeric_limits<std::int32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())\n                {\n                    return 'l';\n                }\n                if (use_bjdata && ((std::numeric_limits<std::uint32_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)()))\n                {\n                    return 'm';\n                }\n                if ((std::numeric_limits<std::int64_t>::min)() <= j.m_data.m_value.number_integer && j.m_data.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())\n                {\n                    return 'L';\n                }\n                // anything else is treated as high-precision number\n                return 'H'; // LCOV_EXCL_LINE\n            }\n\n            case value_t::number_unsigned:\n            {\n                if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))\n                {\n                    return 'i';\n                }\n                if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint8_t>::max)()))\n                {\n                    return 'U';\n                }\n                if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))\n                {\n                    return 'I';\n                }\n                if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint16_t>::max)()))\n                {\n                    return 'u';\n                }\n                if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))\n                {\n                    return 'l';\n                }\n                if (use_bjdata && j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::uint32_t>::max)()))\n                {\n                    return 'm';\n                }\n                if (j.m_data.m_value.number_unsigned <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))\n                {\n                    return 'L';\n                }\n                if (use_bjdata && j.m_data.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())\n                {\n                    return 'M';\n                }\n                // anything else is treated as high-precision number\n                return 'H'; // LCOV_EXCL_LINE\n            }\n\n            case value_t::number_float:\n                return get_ubjson_float_prefix(j.m_data.m_value.number_float);\n\n            case value_t::string:\n                return 'S';\n\n            case value_t::array: // fallthrough\n            case value_t::binary:\n                return '[';\n\n            case value_t::object:\n                return '{';\n\n            case value_t::discarded:\n            default:  // discarded values\n                return 'N';\n        }\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(float /*unused*/)\n    {\n        return 'd';  // float 32\n    }\n\n    static constexpr CharType get_ubjson_float_prefix(double /*unused*/)\n    {\n        return 'D';  // float 64\n    }\n\n    /*!\n    @return false if the object is successfully converted to a bjdata ndarray, true if the type or size is invalid\n    */\n    bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type, const bjdata_version_t bjdata_version)\n    {\n        std::map<string_t, CharType> bjdtype = {{\"uint8\", 'U'},  {\"int8\", 'i'},  {\"uint16\", 'u'}, {\"int16\", 'I'},\n            {\"uint32\", 'm'}, {\"int32\", 'l'}, {\"uint64\", 'M'}, {\"int64\", 'L'}, {\"single\", 'd'}, {\"double\", 'D'},\n            {\"char\", 'C'}, {\"byte\", 'B'}\n        };\n\n        string_t key = \"_ArrayType_\";\n        auto it = bjdtype.find(static_cast<string_t>(value.at(key)));\n        if (it == bjdtype.end())\n        {\n            return true;\n        }\n        CharType dtype = it->second;\n\n        key = \"_ArraySize_\";\n        std::size_t len = (value.at(key).empty() ? 0 : 1);\n        for (const auto& el : value.at(key))\n        {\n            len *= static_cast<std::size_t>(el.m_data.m_value.number_unsigned);\n        }\n\n        key = \"_ArrayData_\";\n        if (value.at(key).size() != len)\n        {\n            return true;\n        }\n\n        oa->write_character('[');\n        oa->write_character('$');\n        oa->write_character(dtype);\n        oa->write_character('#');\n\n        key = \"_ArraySize_\";\n        write_ubjson(value.at(key), use_count, use_type, true,  true, bjdata_version);\n\n        key = \"_ArrayData_\";\n        if (dtype == 'U' || dtype == 'C' || dtype == 'B')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::uint8_t>(el.m_data.m_value.number_unsigned), true);\n            }\n        }\n        else if (dtype == 'i')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::int8_t>(el.m_data.m_value.number_integer), true);\n            }\n        }\n        else if (dtype == 'u')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::uint16_t>(el.m_data.m_value.number_unsigned), true);\n            }\n        }\n        else if (dtype == 'I')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::int16_t>(el.m_data.m_value.number_integer), true);\n            }\n        }\n        else if (dtype == 'm')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::uint32_t>(el.m_data.m_value.number_unsigned), true);\n            }\n        }\n        else if (dtype == 'l')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::int32_t>(el.m_data.m_value.number_integer), true);\n            }\n        }\n        else if (dtype == 'M')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::uint64_t>(el.m_data.m_value.number_unsigned), true);\n            }\n        }\n        else if (dtype == 'L')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<std::int64_t>(el.m_data.m_value.number_integer), true);\n            }\n        }\n        else if (dtype == 'd')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<float>(el.m_data.m_value.number_float), true);\n            }\n        }\n        else if (dtype == 'D')\n        {\n            for (const auto& el : value.at(key))\n            {\n                write_number(static_cast<double>(el.m_data.m_value.number_float), true);\n            }\n        }\n        return false;\n    }\n\n    ///////////////////////\n    // Utility functions //\n    ///////////////////////\n\n    /*\n    @brief write a number to output input\n    @param[in] n number of type @a NumberType\n    @param[in] OutputIsLittleEndian Set to true if output data is\n                                 required to be little endian\n    @tparam NumberType the type of the number\n\n    @note This function needs to respect the system's endianness, because bytes\n          in CBOR, MessagePack, and UBJSON are stored in network order (big\n          endian) and therefore need reordering on little endian systems.\n          On the other hand, BSON and BJData use little endian and should reorder\n          on big endian systems.\n    */\n    template<typename NumberType>\n    void write_number(const NumberType n, const bool OutputIsLittleEndian = false)\n    {\n        // step 1: write number to array of length NumberType\n        std::array<CharType, sizeof(NumberType)> vec{};\n        std::memcpy(vec.data(), &n, sizeof(NumberType));\n\n        // step 2: write array to output (with possible reordering)\n        if (is_little_endian != OutputIsLittleEndian)\n        {\n            // reverse byte order prior to conversion if necessary\n            std::reverse(vec.begin(), vec.end());\n        }\n\n        oa->write_characters(vec.data(), sizeof(NumberType));\n    }\n\n    void write_compact_float(const number_float_t n, detail::input_format_t format)\n    {\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n        if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&\n                static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&\n                static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))\n        {\n            oa->write_character(format == detail::input_format_t::cbor\n                                ? get_cbor_float_prefix(static_cast<float>(n))\n                                : get_msgpack_float_prefix(static_cast<float>(n)));\n            write_number(static_cast<float>(n));\n        }\n        else\n        {\n            oa->write_character(format == detail::input_format_t::cbor\n                                ? get_cbor_float_prefix(n)\n                                : get_msgpack_float_prefix(n));\n            write_number(n);\n        }\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n    }\n\n  public:\n    // The following to_char_type functions are implement the conversion\n    // between uint8_t and CharType. In case CharType is not unsigned,\n    // such a conversion is required to allow values greater than 128.\n    // See <https://github.com/nlohmann/json/issues/1286> for a discussion.\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr >\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return *reinterpret_cast<char*>(&x);\n    }\n\n    template < typename C = CharType,\n               enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr >\n    static CharType to_char_type(std::uint8_t x) noexcept\n    {\n        static_assert(sizeof(std::uint8_t) == sizeof(CharType), \"size of CharType must be equal to std::uint8_t\");\n        static_assert(std::is_trivial<CharType>::value, \"CharType must be trivial\");\n        CharType result;\n        std::memcpy(&result, &x, sizeof(x));\n        return result;\n    }\n\n    template<typename C = CharType,\n             enable_if_t<std::is_unsigned<C>::value>* = nullptr>\n    static constexpr CharType to_char_type(std::uint8_t x) noexcept\n    {\n        return x;\n    }\n\n    template < typename InputCharType, typename C = CharType,\n               enable_if_t <\n                   std::is_signed<C>::value &&\n                   std::is_signed<char>::value &&\n                   std::is_same<char, typename std::remove_cv<InputCharType>::type>::value\n                   > * = nullptr >\n    static constexpr CharType to_char_type(InputCharType x) noexcept\n    {\n        return x;\n    }\n\n  private:\n    /// whether we can assume little endianness\n    const bool is_little_endian = little_endianness();\n\n    /// the output\n    output_adapter_t<CharType> oa = nullptr;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/output/serializer.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2008 - 2009 Björn Hoehrmann <bjoern@hoehrmann.de>\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <algorithm> // reverse, remove, fill, find, none_of\n#include <array> // array\n#include <clocale> // localeconv, lconv\n#include <cmath> // labs, isfinite, isnan, signbit\n#include <cstddef> // size_t, ptrdiff_t\n#include <cstdint> // uint8_t\n#include <cstdio> // snprintf\n#include <limits> // numeric_limits\n#include <string> // string, char_traits\n#include <iomanip> // setfill, setw\n#include <type_traits> // is_same\n#include <utility> // move\n\n// #include <nlohmann/detail/conversions/to_chars.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2009 Florian Loitsch <https://florian.loitsch.com/>\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <array> // array\n#include <cmath>   // signbit, isfinite\n#include <cstdint> // intN_t, uintN_t\n#include <cstring> // memcpy, memmove\n#include <limits> // numeric_limits\n#include <type_traits> // conditional\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n/*!\n@brief implements the Grisu2 algorithm for binary to decimal floating-point\nconversion.\n\nThis implementation is a slightly modified version of the reference\nimplementation which may be obtained from\nhttp://florian.loitsch.com/publications (bench.tar.gz).\n\nThe code is distributed under the MIT license, Copyright (c) 2009 Florian Loitsch.\n\nFor a detailed description of the algorithm see:\n\n[1] Loitsch, \"Printing Floating-Point Numbers Quickly and Accurately with\n    Integers\", Proceedings of the ACM SIGPLAN 2010 Conference on Programming\n    Language Design and Implementation, PLDI 2010\n[2] Burger, Dybvig, \"Printing Floating-Point Numbers Quickly and Accurately\",\n    Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language\n    Design and Implementation, PLDI 1996\n*/\nnamespace dtoa_impl\n{\n\ntemplate<typename Target, typename Source>\nTarget reinterpret_bits(const Source source)\n{\n    static_assert(sizeof(Target) == sizeof(Source), \"size mismatch\");\n\n    Target target;\n    std::memcpy(&target, &source, sizeof(Source));\n    return target;\n}\n\nstruct diyfp // f * 2^e\n{\n    static constexpr int kPrecision = 64; // = q\n\n    std::uint64_t f = 0;\n    int e = 0;\n\n    constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {}\n\n    /*!\n    @brief returns x - y\n    @pre x.e == y.e and x.f >= y.f\n    */\n    static diyfp sub(const diyfp& x, const diyfp& y) noexcept\n    {\n        JSON_ASSERT(x.e == y.e);\n        JSON_ASSERT(x.f >= y.f);\n\n        return {x.f - y.f, x.e};\n    }\n\n    /*!\n    @brief returns x * y\n    @note The result is rounded. (Only the upper q bits are returned.)\n    */\n    static diyfp mul(const diyfp& x, const diyfp& y) noexcept\n    {\n        static_assert(kPrecision == 64, \"internal error\");\n\n        // Computes:\n        //  f = round((x.f * y.f) / 2^q)\n        //  e = x.e + y.e + q\n\n        // Emulate the 64-bit * 64-bit multiplication:\n        //\n        // p = u * v\n        //   = (u_lo + 2^32 u_hi) (v_lo + 2^32 v_hi)\n        //   = (u_lo v_lo         ) + 2^32 ((u_lo v_hi         ) + (u_hi v_lo         )) + 2^64 (u_hi v_hi         )\n        //   = (p0                ) + 2^32 ((p1                ) + (p2                )) + 2^64 (p3                )\n        //   = (p0_lo + 2^32 p0_hi) + 2^32 ((p1_lo + 2^32 p1_hi) + (p2_lo + 2^32 p2_hi)) + 2^64 (p3                )\n        //   = (p0_lo             ) + 2^32 (p0_hi + p1_lo + p2_lo                      ) + 2^64 (p1_hi + p2_hi + p3)\n        //   = (p0_lo             ) + 2^32 (Q                                          ) + 2^64 (H                 )\n        //   = (p0_lo             ) + 2^32 (Q_lo + 2^32 Q_hi                           ) + 2^64 (H                 )\n        //\n        // (Since Q might be larger than 2^32 - 1)\n        //\n        //   = (p0_lo + 2^32 Q_lo) + 2^64 (Q_hi + H)\n        //\n        // (Q_hi + H does not overflow a 64-bit int)\n        //\n        //   = p_lo + 2^64 p_hi\n\n        const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;\n        const std::uint64_t u_hi = x.f >> 32u;\n        const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;\n        const std::uint64_t v_hi = y.f >> 32u;\n\n        const std::uint64_t p0 = u_lo * v_lo;\n        const std::uint64_t p1 = u_lo * v_hi;\n        const std::uint64_t p2 = u_hi * v_lo;\n        const std::uint64_t p3 = u_hi * v_hi;\n\n        const std::uint64_t p0_hi = p0 >> 32u;\n        const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;\n        const std::uint64_t p1_hi = p1 >> 32u;\n        const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;\n        const std::uint64_t p2_hi = p2 >> 32u;\n\n        std::uint64_t Q = p0_hi + p1_lo + p2_lo;\n\n        // The full product might now be computed as\n        //\n        // p_hi = p3 + p2_hi + p1_hi + (Q >> 32)\n        // p_lo = p0_lo + (Q << 32)\n        //\n        // But in this particular case here, the full p_lo is not required.\n        // Effectively we only need to add the highest bit in p_lo to p_hi (and\n        // Q_hi + 1 does not overflow).\n\n        Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up\n\n        const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);\n\n        return {h, x.e + y.e + 64};\n    }\n\n    /*!\n    @brief normalize x such that the significand is >= 2^(q-1)\n    @pre x.f != 0\n    */\n    static diyfp normalize(diyfp x) noexcept\n    {\n        JSON_ASSERT(x.f != 0);\n\n        while ((x.f >> 63u) == 0)\n        {\n            x.f <<= 1u;\n            x.e--;\n        }\n\n        return x;\n    }\n\n    /*!\n    @brief normalize x such that the result has the exponent E\n    @pre e >= x.e and the upper e - x.e bits of x.f must be zero.\n    */\n    static diyfp normalize_to(const diyfp& x, const int target_exponent) noexcept\n    {\n        const int delta = x.e - target_exponent;\n\n        JSON_ASSERT(delta >= 0);\n        JSON_ASSERT(((x.f << delta) >> delta) == x.f);\n\n        return {x.f << delta, target_exponent};\n    }\n};\n\nstruct boundaries\n{\n    diyfp w;\n    diyfp minus;\n    diyfp plus;\n};\n\n/*!\nCompute the (normalized) diyfp representing the input number 'value' and its\nboundaries.\n\n@pre value must be finite and positive\n*/\ntemplate<typename FloatType>\nboundaries compute_boundaries(FloatType value)\n{\n    JSON_ASSERT(std::isfinite(value));\n    JSON_ASSERT(value > 0);\n\n    // Convert the IEEE representation into a diyfp.\n    //\n    // If v is denormal:\n    //      value = 0.F * 2^(1 - bias) = (          F) * 2^(1 - bias - (p-1))\n    // If v is normalized:\n    //      value = 1.F * 2^(E - bias) = (2^(p-1) + F) * 2^(E - bias - (p-1))\n\n    static_assert(std::numeric_limits<FloatType>::is_iec559,\n                  \"internal error: dtoa_short requires an IEEE-754 floating-point implementation\");\n\n    constexpr int      kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)\n    constexpr int      kBias      = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);\n    constexpr int      kMinExp    = 1 - kBias;\n    constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)\n\n    using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;\n\n    const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));\n    const std::uint64_t E = bits >> (kPrecision - 1);\n    const std::uint64_t F = bits & (kHiddenBit - 1);\n\n    const bool is_denormal = E == 0;\n    const diyfp v = is_denormal\n                    ? diyfp(F, kMinExp)\n                    : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);\n\n    // Compute the boundaries m- and m+ of the floating-point value\n    // v = f * 2^e.\n    //\n    // Determine v- and v+, the floating-point predecessor and successor if v,\n    // respectively.\n    //\n    //      v- = v - 2^e        if f != 2^(p-1) or e == e_min                (A)\n    //         = v - 2^(e-1)    if f == 2^(p-1) and e > e_min                (B)\n    //\n    //      v+ = v + 2^e\n    //\n    // Let m- = (v- + v) / 2 and m+ = (v + v+) / 2. All real numbers _strictly_\n    // between m- and m+ round to v, regardless of how the input rounding\n    // algorithm breaks ties.\n    //\n    //      ---+-------------+-------------+-------------+-------------+---  (A)\n    //         v-            m-            v             m+            v+\n    //\n    //      -----------------+------+------+-------------+-------------+---  (B)\n    //                       v-     m-     v             m+            v+\n\n    const bool lower_boundary_is_closer = F == 0 && E > 1;\n    const diyfp m_plus = diyfp((2 * v.f) + 1, v.e - 1);\n    const diyfp m_minus = lower_boundary_is_closer\n                          ? diyfp((4 * v.f) - 1, v.e - 2)  // (B)\n                          : diyfp((2 * v.f) - 1, v.e - 1); // (A)\n\n    // Determine the normalized w+ = m+.\n    const diyfp w_plus = diyfp::normalize(m_plus);\n\n    // Determine w- = m- such that e_(w-) = e_(w+).\n    const diyfp w_minus = diyfp::normalize_to(m_minus, w_plus.e);\n\n    return {diyfp::normalize(v), w_minus, w_plus};\n}\n\n// Given normalized diyfp w, Grisu needs to find a (normalized) cached\n// power-of-ten c, such that the exponent of the product c * w = f * 2^e lies\n// within a certain range [alpha, gamma] (Definition 3.2 from [1])\n//\n//      alpha <= e = e_c + e_w + q <= gamma\n//\n// or\n//\n//      f_c * f_w * 2^alpha <= f_c 2^(e_c) * f_w 2^(e_w) * 2^q\n//                          <= f_c * f_w * 2^gamma\n//\n// Since c and w are normalized, i.e. 2^(q-1) <= f < 2^q, this implies\n//\n//      2^(q-1) * 2^(q-1) * 2^alpha <= c * w * 2^q < 2^q * 2^q * 2^gamma\n//\n// or\n//\n//      2^(q - 2 + alpha) <= c * w < 2^(q + gamma)\n//\n// The choice of (alpha,gamma) determines the size of the table and the form of\n// the digit generation procedure. Using (alpha,gamma)=(-60,-32) works out well\n// in practice:\n//\n// The idea is to cut the number c * w = f * 2^e into two parts, which can be\n// processed independently: An integral part p1, and a fractional part p2:\n//\n//      f * 2^e = ( (f div 2^-e) * 2^-e + (f mod 2^-e) ) * 2^e\n//              = (f div 2^-e) + (f mod 2^-e) * 2^e\n//              = p1 + p2 * 2^e\n//\n// The conversion of p1 into decimal form requires a series of divisions and\n// modulos by (a power of) 10. These operations are faster for 32-bit than for\n// 64-bit integers, so p1 should ideally fit into a 32-bit integer. This can be\n// achieved by choosing\n//\n//      -e >= 32   or   e <= -32 := gamma\n//\n// In order to convert the fractional part\n//\n//      p2 * 2^e = p2 / 2^-e = d[-1] / 10^1 + d[-2] / 10^2 + ...\n//\n// into decimal form, the fraction is repeatedly multiplied by 10 and the digits\n// d[-i] are extracted in order:\n//\n//      (10 * p2) div 2^-e = d[-1]\n//      (10 * p2) mod 2^-e = d[-2] / 10^1 + ...\n//\n// The multiplication by 10 must not overflow. It is sufficient to choose\n//\n//      10 * p2 < 16 * p2 = 2^4 * p2 <= 2^64.\n//\n// Since p2 = f mod 2^-e < 2^-e,\n//\n//      -e <= 60   or   e >= -60 := alpha\n\nconstexpr int kAlpha = -60;\nconstexpr int kGamma = -32;\n\nstruct cached_power // c = f * 2^e ~= 10^k\n{\n    std::uint64_t f;\n    int e;\n    int k;\n};\n\n/*!\nFor a normalized diyfp w = f * 2^e, this function returns a (normalized) cached\npower-of-ten c = f_c * 2^e_c, such that the exponent of the product w * c\nsatisfies (Definition 3.2 from [1])\n\n     alpha <= e_c + e + q <= gamma.\n*/\ninline cached_power get_cached_power_for_binary_exponent(int e)\n{\n    // Now\n    //\n    //      alpha <= e_c + e + q <= gamma                                    (1)\n    //      ==> f_c * 2^alpha <= c * 2^e * 2^q\n    //\n    // and since the c's are normalized, 2^(q-1) <= f_c,\n    //\n    //      ==> 2^(q - 1 + alpha) <= c * 2^(e + q)\n    //      ==> 2^(alpha - e - 1) <= c\n    //\n    // If c were an exact power of ten, i.e. c = 10^k, one may determine k as\n    //\n    //      k = ceil( log_10( 2^(alpha - e - 1) ) )\n    //        = ceil( (alpha - e - 1) * log_10(2) )\n    //\n    // From the paper:\n    // \"In theory the result of the procedure could be wrong since c is rounded,\n    //  and the computation itself is approximated [...]. In practice, however,\n    //  this simple function is sufficient.\"\n    //\n    // For IEEE double precision floating-point numbers converted into\n    // normalized diyfp's w = f * 2^e, with q = 64,\n    //\n    //      e >= -1022      (min IEEE exponent)\n    //           -52        (p - 1)\n    //           -52        (p - 1, possibly normalize denormal IEEE numbers)\n    //           -11        (normalize the diyfp)\n    //         = -1137\n    //\n    // and\n    //\n    //      e <= +1023      (max IEEE exponent)\n    //           -52        (p - 1)\n    //           -11        (normalize the diyfp)\n    //         = 960\n    //\n    // This binary exponent range [-1137,960] results in a decimal exponent\n    // range [-307,324]. One does not need to store a cached power for each\n    // k in this range. For each such k it suffices to find a cached power\n    // such that the exponent of the product lies in [alpha,gamma].\n    // This implies that the difference of the decimal exponents of adjacent\n    // table entries must be less than or equal to\n    //\n    //      floor( (gamma - alpha) * log_10(2) ) = 8.\n    //\n    // (A smaller distance gamma-alpha would require a larger table.)\n\n    // NB:\n    // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.\n\n    constexpr int kCachedPowersMinDecExp = -300;\n    constexpr int kCachedPowersDecStep = 8;\n\n    static constexpr std::array<cached_power, 79> kCachedPowers =\n    {\n        {\n            { 0xAB70FE17C79AC6CA, -1060, -300 },\n            { 0xFF77B1FCBEBCDC4F, -1034, -292 },\n            { 0xBE5691EF416BD60C, -1007, -284 },\n            { 0x8DD01FAD907FFC3C,  -980, -276 },\n            { 0xD3515C2831559A83,  -954, -268 },\n            { 0x9D71AC8FADA6C9B5,  -927, -260 },\n            { 0xEA9C227723EE8BCB,  -901, -252 },\n            { 0xAECC49914078536D,  -874, -244 },\n            { 0x823C12795DB6CE57,  -847, -236 },\n            { 0xC21094364DFB5637,  -821, -228 },\n            { 0x9096EA6F3848984F,  -794, -220 },\n            { 0xD77485CB25823AC7,  -768, -212 },\n            { 0xA086CFCD97BF97F4,  -741, -204 },\n            { 0xEF340A98172AACE5,  -715, -196 },\n            { 0xB23867FB2A35B28E,  -688, -188 },\n            { 0x84C8D4DFD2C63F3B,  -661, -180 },\n            { 0xC5DD44271AD3CDBA,  -635, -172 },\n            { 0x936B9FCEBB25C996,  -608, -164 },\n            { 0xDBAC6C247D62A584,  -582, -156 },\n            { 0xA3AB66580D5FDAF6,  -555, -148 },\n            { 0xF3E2F893DEC3F126,  -529, -140 },\n            { 0xB5B5ADA8AAFF80B8,  -502, -132 },\n            { 0x87625F056C7C4A8B,  -475, -124 },\n            { 0xC9BCFF6034C13053,  -449, -116 },\n            { 0x964E858C91BA2655,  -422, -108 },\n            { 0xDFF9772470297EBD,  -396, -100 },\n            { 0xA6DFBD9FB8E5B88F,  -369,  -92 },\n            { 0xF8A95FCF88747D94,  -343,  -84 },\n            { 0xB94470938FA89BCF,  -316,  -76 },\n            { 0x8A08F0F8BF0F156B,  -289,  -68 },\n            { 0xCDB02555653131B6,  -263,  -60 },\n            { 0x993FE2C6D07B7FAC,  -236,  -52 },\n            { 0xE45C10C42A2B3B06,  -210,  -44 },\n            { 0xAA242499697392D3,  -183,  -36 },\n            { 0xFD87B5F28300CA0E,  -157,  -28 },\n            { 0xBCE5086492111AEB,  -130,  -20 },\n            { 0x8CBCCC096F5088CC,  -103,  -12 },\n            { 0xD1B71758E219652C,   -77,   -4 },\n            { 0x9C40000000000000,   -50,    4 },\n            { 0xE8D4A51000000000,   -24,   12 },\n            { 0xAD78EBC5AC620000,     3,   20 },\n            { 0x813F3978F8940984,    30,   28 },\n            { 0xC097CE7BC90715B3,    56,   36 },\n            { 0x8F7E32CE7BEA5C70,    83,   44 },\n            { 0xD5D238A4ABE98068,   109,   52 },\n            { 0x9F4F2726179A2245,   136,   60 },\n            { 0xED63A231D4C4FB27,   162,   68 },\n            { 0xB0DE65388CC8ADA8,   189,   76 },\n            { 0x83C7088E1AAB65DB,   216,   84 },\n            { 0xC45D1DF942711D9A,   242,   92 },\n            { 0x924D692CA61BE758,   269,  100 },\n            { 0xDA01EE641A708DEA,   295,  108 },\n            { 0xA26DA3999AEF774A,   322,  116 },\n            { 0xF209787BB47D6B85,   348,  124 },\n            { 0xB454E4A179DD1877,   375,  132 },\n            { 0x865B86925B9BC5C2,   402,  140 },\n            { 0xC83553C5C8965D3D,   428,  148 },\n            { 0x952AB45CFA97A0B3,   455,  156 },\n            { 0xDE469FBD99A05FE3,   481,  164 },\n            { 0xA59BC234DB398C25,   508,  172 },\n            { 0xF6C69A72A3989F5C,   534,  180 },\n            { 0xB7DCBF5354E9BECE,   561,  188 },\n            { 0x88FCF317F22241E2,   588,  196 },\n            { 0xCC20CE9BD35C78A5,   614,  204 },\n            { 0x98165AF37B2153DF,   641,  212 },\n            { 0xE2A0B5DC971F303A,   667,  220 },\n            { 0xA8D9D1535CE3B396,   694,  228 },\n            { 0xFB9B7CD9A4A7443C,   720,  236 },\n            { 0xBB764C4CA7A44410,   747,  244 },\n            { 0x8BAB8EEFB6409C1A,   774,  252 },\n            { 0xD01FEF10A657842C,   800,  260 },\n            { 0x9B10A4E5E9913129,   827,  268 },\n            { 0xE7109BFBA19C0C9D,   853,  276 },\n            { 0xAC2820D9623BF429,   880,  284 },\n            { 0x80444B5E7AA7CF85,   907,  292 },\n            { 0xBF21E44003ACDD2D,   933,  300 },\n            { 0x8E679C2F5E44FF8F,   960,  308 },\n            { 0xD433179D9C8CB841,   986,  316 },\n            { 0x9E19DB92B4E31BA9,  1013,  324 },\n        }\n    };\n\n    // This computation gives exactly the same results for k as\n    //      k = ceil((kAlpha - e - 1) * 0.30102999566398114)\n    // for |e| <= 1500, but doesn't require floating-point operations.\n    // NB: log_10(2) ~= 78913 / 2^18\n    JSON_ASSERT(e >= -1500);\n    JSON_ASSERT(e <=  1500);\n    const int f = kAlpha - e - 1;\n    const int k = ((f * 78913) / (1 << 18)) + static_cast<int>(f > 0);\n\n    const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;\n    JSON_ASSERT(index >= 0);\n    JSON_ASSERT(static_cast<std::size_t>(index) < kCachedPowers.size());\n\n    const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];\n    JSON_ASSERT(kAlpha <= cached.e + e + 64);\n    JSON_ASSERT(kGamma >= cached.e + e + 64);\n\n    return cached;\n}\n\n/*!\nFor n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.\nFor n == 0, returns 1 and sets pow10 := 1.\n*/\ninline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)\n{\n    // LCOV_EXCL_START\n    if (n >= 1000000000)\n    {\n        pow10 = 1000000000;\n        return 10;\n    }\n    // LCOV_EXCL_STOP\n    if (n >= 100000000)\n    {\n        pow10 = 100000000;\n        return  9;\n    }\n    if (n >= 10000000)\n    {\n        pow10 = 10000000;\n        return  8;\n    }\n    if (n >= 1000000)\n    {\n        pow10 = 1000000;\n        return  7;\n    }\n    if (n >= 100000)\n    {\n        pow10 = 100000;\n        return  6;\n    }\n    if (n >= 10000)\n    {\n        pow10 = 10000;\n        return  5;\n    }\n    if (n >= 1000)\n    {\n        pow10 = 1000;\n        return  4;\n    }\n    if (n >= 100)\n    {\n        pow10 = 100;\n        return  3;\n    }\n    if (n >= 10)\n    {\n        pow10 = 10;\n        return  2;\n    }\n\n    pow10 = 1;\n    return 1;\n}\n\ninline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,\n                         std::uint64_t rest, std::uint64_t ten_k)\n{\n    JSON_ASSERT(len >= 1);\n    JSON_ASSERT(dist <= delta);\n    JSON_ASSERT(rest <= delta);\n    JSON_ASSERT(ten_k > 0);\n\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    //                                  ten_k\n    //                                <------>\n    //                                       <---- rest ---->\n    // --------------[------------------+----+--------------]--------------\n    //                                  w    V\n    //                                       = buf * 10^k\n    //\n    // ten_k represents a unit-in-the-last-place in the decimal representation\n    // stored in buf.\n    // Decrement buf by ten_k while this takes buf closer to w.\n\n    // The tests are written in this order to avoid overflow in unsigned\n    // integer arithmetic.\n\n    while (rest < dist\n            && delta - rest >= ten_k\n            && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))\n    {\n        JSON_ASSERT(buf[len - 1] != '0');\n        buf[len - 1]--;\n        rest += ten_k;\n    }\n}\n\n/*!\nGenerates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.\nM- and M+ must be normalized and share the same exponent -60 <= e <= -32.\n*/\ninline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,\n                             diyfp M_minus, diyfp w, diyfp M_plus)\n{\n    static_assert(kAlpha >= -60, \"internal error\");\n    static_assert(kGamma <= -32, \"internal error\");\n\n    // Generates the digits (and the exponent) of a decimal floating-point\n    // number V = buffer * 10^decimal_exponent in the range [M-, M+]. The diyfp's\n    // w, M- and M+ share the same exponent e, which satisfies alpha <= e <= gamma.\n    //\n    //               <--------------------------- delta ---->\n    //                                  <---- dist --------->\n    // --------------[------------------+-------------------]--------------\n    //               M-                 w                   M+\n    //\n    // Grisu2 generates the digits of M+ from left to right and stops as soon as\n    // V is in [M-,M+].\n\n    JSON_ASSERT(M_plus.e >= kAlpha);\n    JSON_ASSERT(M_plus.e <= kGamma);\n\n    std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)\n    std::uint64_t dist  = diyfp::sub(M_plus, w      ).f; // (significand of (M+ - w ), implicit exponent is e)\n\n    // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):\n    //\n    //      M+ = f * 2^e\n    //         = ((f div 2^-e) * 2^-e + (f mod 2^-e)) * 2^e\n    //         = ((p1        ) * 2^-e + (p2        )) * 2^e\n    //         = p1 + p2 * 2^e\n\n    const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);\n\n    auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)\n    std::uint64_t p2 = M_plus.f & (one.f - 1);                    // p2 = f mod 2^-e\n\n    // 1)\n    //\n    // Generate the digits of the integral part p1 = d[n-1]...d[1]d[0]\n\n    JSON_ASSERT(p1 > 0);\n\n    std::uint32_t pow10{};\n    const int k = find_largest_pow10(p1, pow10);\n\n    //      10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)\n    //\n    //      p1 = (p1 div 10^(k-1)) * 10^(k-1) + (p1 mod 10^(k-1))\n    //         = (d[k-1]         ) * 10^(k-1) + (p1 mod 10^(k-1))\n    //\n    //      M+ = p1                                             + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + (p1 mod 10^(k-1))          + p2 * 2^e\n    //         = d[k-1] * 10^(k-1) + ((p1 mod 10^(k-1)) * 2^-e + p2) * 2^e\n    //         = d[k-1] * 10^(k-1) + (                         rest) * 2^e\n    //\n    // Now generate the digits d[n] of p1 from left to right (n = k-1,...,0)\n    //\n    //      p1 = d[k-1]...d[n] * 10^n + d[n-1]...d[0]\n    //\n    // but stop as soon as\n    //\n    //      rest * 2^e = (d[n-1]...d[0] * 2^-e + p2) * 2^e <= delta * 2^e\n\n    int n = k;\n    while (n > 0)\n    {\n        // Invariants:\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)    (buffer = 0 for n = k)\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        //\n        const std::uint32_t d = p1 / pow10;  // d = p1 div 10^(n-1)\n        const std::uint32_t r = p1 % pow10;  // r = p1 mod 10^(n-1)\n        //\n        //      M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e\n        //         = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)\n        //\n        JSON_ASSERT(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(n-1) + (r + p2 * 2^e)\n        //\n        p1 = r;\n        n--;\n        //\n        //      M+ = buffer * 10^n + (p1 + p2 * 2^e)\n        //      pow10 = 10^n\n        //\n\n        // Now check if enough digits have been generated.\n        // Compute\n        //\n        //      p1 + p2 * 2^e = (p1 * 2^-e + p2) * 2^e = rest * 2^e\n        //\n        // Note:\n        // Since rest and delta share the same exponent e, it suffices to\n        // compare the significands.\n        const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;\n        if (rest <= delta)\n        {\n            // V = buffer * 10^n, with M- <= V <= M+.\n\n            decimal_exponent += n;\n\n            // We may now just stop. But instead look if the buffer could be\n            // decremented to bring V closer to w.\n            //\n            // pow10 = 10^n is now 1 ulp in the decimal representation V.\n            // The rounding procedure works with diyfp's with an implicit\n            // exponent of e.\n            //\n            //      10^n = (10^n * 2^-e) * 2^e = ulp * 2^e\n            //\n            const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;\n            grisu2_round(buffer, length, dist, delta, rest, ten_n);\n\n            return;\n        }\n\n        pow10 /= 10;\n        //\n        //      pow10 = 10^(n-1) <= p1 < 10^n\n        // Invariants restored.\n    }\n\n    // 2)\n    //\n    // The digits of the integral part have been generated:\n    //\n    //      M+ = d[k-1]...d[1]d[0] + p2 * 2^e\n    //         = buffer            + p2 * 2^e\n    //\n    // Now generate the digits of the fractional part p2 * 2^e.\n    //\n    // Note:\n    // No decimal point is generated: the exponent is adjusted instead.\n    //\n    // p2 actually represents the fraction\n    //\n    //      p2 * 2^e\n    //          = p2 / 2^-e\n    //          = d[-1] / 10^1 + d[-2] / 10^2 + ...\n    //\n    // Now generate the digits d[-m] of p1 from left to right (m = 1,2,...)\n    //\n    //      p2 * 2^e = d[-1]d[-2]...d[-m] * 10^-m\n    //                      + 10^-m * (d[-m-1] / 10^1 + d[-m-2] / 10^2 + ...)\n    //\n    // using\n    //\n    //      10^m * p2 = ((10^m * p2) div 2^-e) * 2^-e + ((10^m * p2) mod 2^-e)\n    //                = (                   d) * 2^-e + (                   r)\n    //\n    // or\n    //      10^m * p2 * 2^e = d + r * 2^e\n    //\n    // i.e.\n    //\n    //      M+ = buffer + p2 * 2^e\n    //         = buffer + 10^-m * (d + r * 2^e)\n    //         = (buffer * 10^m + d) * 10^-m + 10^-m * r * 2^e\n    //\n    // and stop as soon as 10^-m * r * 2^e <= delta * 2^e\n\n    JSON_ASSERT(p2 > delta);\n\n    int m = 0;\n    for (;;)\n    {\n        // Invariant:\n        //      M+ = buffer * 10^-m + 10^-m * (d[-m-1] / 10 + d[-m-2] / 10^2 + ...) * 2^e\n        //         = buffer * 10^-m + 10^-m * (p2                                 ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (10 * p2)                   ) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e\n        //\n        JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);\n        p2 *= 10;\n        const std::uint64_t d = p2 >> -one.e;     // d = (10 * p2) div 2^-e\n        const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e\n        //\n        //      M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e\n        //         = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))\n        //         = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        JSON_ASSERT(d <= 9);\n        buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d\n        //\n        //      M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e\n        //\n        p2 = r;\n        m++;\n        //\n        //      M+ = buffer * 10^-m + 10^-m * p2 * 2^e\n        // Invariant restored.\n\n        // Check if enough digits have been generated.\n        //\n        //      10^-m * p2 * 2^e <= delta * 2^e\n        //              p2 * 2^e <= 10^m * delta * 2^e\n        //                    p2 <= 10^m * delta\n        delta *= 10;\n        dist  *= 10;\n        if (p2 <= delta)\n        {\n            break;\n        }\n    }\n\n    // V = buffer * 10^-m, with M- <= V <= M+.\n\n    decimal_exponent -= m;\n\n    // 1 ulp in the decimal representation is now 10^-m.\n    // Since delta and dist are now scaled by 10^m, we need to do the\n    // same with ulp in order to keep the units in sync.\n    //\n    //      10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e\n    //\n    const std::uint64_t ten_m = one.f;\n    grisu2_round(buffer, length, dist, delta, p2, ten_m);\n\n    // By construction this algorithm generates the shortest possible decimal\n    // number (Loitsch, Theorem 6.2) which rounds back to w.\n    // For an input number of precision p, at least\n    //\n    //      N = 1 + ceil(p * log_10(2))\n    //\n    // decimal digits are sufficient to identify all binary floating-point\n    // numbers (Matula, \"In-and-Out conversions\").\n    // This implies that the algorithm does not produce more than N decimal\n    // digits.\n    //\n    //      N = 17 for p = 53 (IEEE double precision)\n    //      N = 9  for p = 24 (IEEE single precision)\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\nJSON_HEDLEY_NON_NULL(1)\ninline void grisu2(char* buf, int& len, int& decimal_exponent,\n                   diyfp m_minus, diyfp v, diyfp m_plus)\n{\n    JSON_ASSERT(m_plus.e == m_minus.e);\n    JSON_ASSERT(m_plus.e == v.e);\n\n    //  --------(-----------------------+-----------------------)--------    (A)\n    //          m-                      v                       m+\n    //\n    //  --------------------(-----------+-----------------------)--------    (B)\n    //                      m-          v                       m+\n    //\n    // First scale v (and m- and m+) such that the exponent is in the range\n    // [alpha, gamma].\n\n    const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);\n\n    const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k\n\n    // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]\n    const diyfp w       = diyfp::mul(v,       c_minus_k);\n    const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);\n    const diyfp w_plus  = diyfp::mul(m_plus,  c_minus_k);\n\n    //  ----(---+---)---------------(---+---)---------------(---+---)----\n    //          w-                      w                       w+\n    //          = c*m-                  = c*v                   = c*m+\n    //\n    // diyfp::mul rounds its result and c_minus_k is approximated too. w, w- and\n    // w+ are now off by a small amount.\n    // In fact:\n    //\n    //      w - v * 10^k < 1 ulp\n    //\n    // To account for this inaccuracy, add resp. subtract 1 ulp.\n    //\n    //  --------+---[---------------(---+---)---------------]---+--------\n    //          w-  M-                  w                   M+  w+\n    //\n    // Now any number in [M-, M+] (bounds included) will round to w when input,\n    // regardless of how the input rounding algorithm breaks ties.\n    //\n    // And digit_gen generates the shortest possible such number in [M-, M+].\n    // Note that this does not mean that Grisu2 always generates the shortest\n    // possible number in the interval (m-, m+).\n    const diyfp M_minus(w_minus.f + 1, w_minus.e);\n    const diyfp M_plus (w_plus.f  - 1, w_plus.e );\n\n    decimal_exponent = -cached.k; // = -(-k) = k\n\n    grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);\n}\n\n/*!\nv = buf * 10^decimal_exponent\nlen is the length of the buffer (number of decimal digits)\nThe buffer must be large enough, i.e. >= max_digits10.\n*/\ntemplate<typename FloatType>\nJSON_HEDLEY_NON_NULL(1)\nvoid grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)\n{\n    static_assert(diyfp::kPrecision >= std::numeric_limits<FloatType>::digits + 3,\n                  \"internal error: not enough precision\");\n\n    JSON_ASSERT(std::isfinite(value));\n    JSON_ASSERT(value > 0);\n\n    // If the neighbors (and boundaries) of 'value' are always computed for double-precision\n    // numbers, all float's can be recovered using strtod (and strtof). However, the resulting\n    // decimal representations are not exactly \"short\".\n    //\n    // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)\n    // says \"value is converted to a string as if by std::sprintf in the default (\"C\") locale\"\n    // and since sprintf promotes floats to doubles, I think this is exactly what 'std::to_chars'\n    // does.\n    // On the other hand, the documentation for 'std::to_chars' requires that \"parsing the\n    // representation using the corresponding std::from_chars function recovers value exactly\". That\n    // indicates that single precision floating-point numbers should be recovered using\n    // 'std::strtof'.\n    //\n    // NB: If the neighbors are computed for single-precision numbers, there is a single float\n    //     (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision\n    //     value is off by 1 ulp.\n#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if)\n    const boundaries w = compute_boundaries(static_cast<double>(value));\n#else\n    const boundaries w = compute_boundaries(value);\n#endif\n\n    grisu2(buf, len, decimal_exponent, w.minus, w.w, w.plus);\n}\n\n/*!\n@brief appends a decimal representation of e to buf\n@return a pointer to the element following the exponent.\n@pre -1000 < e < 1000\n*/\nJSON_HEDLEY_NON_NULL(1)\nJSON_HEDLEY_RETURNS_NON_NULL\ninline char* append_exponent(char* buf, int e)\n{\n    JSON_ASSERT(e > -1000);\n    JSON_ASSERT(e <  1000);\n\n    if (e < 0)\n    {\n        e = -e;\n        *buf++ = '-';\n    }\n    else\n    {\n        *buf++ = '+';\n    }\n\n    auto k = static_cast<std::uint32_t>(e);\n    if (k < 10)\n    {\n        // Always print at least two digits in the exponent.\n        // This is for compatibility with printf(\"%g\").\n        *buf++ = '0';\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else if (k < 100)\n    {\n        *buf++ = static_cast<char>('0' + (k / 10));\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n    else\n    {\n        *buf++ = static_cast<char>('0' + (k / 100));\n        k %= 100;\n        *buf++ = static_cast<char>('0' + (k / 10));\n        k %= 10;\n        *buf++ = static_cast<char>('0' + k);\n    }\n\n    return buf;\n}\n\n/*!\n@brief prettify v = buf * 10^decimal_exponent\n\nIf v is in the range [10^min_exp, 10^max_exp) it will be printed in fixed-point\nnotation. Otherwise it will be printed in exponential notation.\n\n@pre min_exp < 0\n@pre max_exp > 0\n*/\nJSON_HEDLEY_NON_NULL(1)\nJSON_HEDLEY_RETURNS_NON_NULL\ninline char* format_buffer(char* buf, int len, int decimal_exponent,\n                           int min_exp, int max_exp)\n{\n    JSON_ASSERT(min_exp < 0);\n    JSON_ASSERT(max_exp > 0);\n\n    const int k = len;\n    const int n = len + decimal_exponent;\n\n    // v = buf * 10^(n-k)\n    // k is the length of the buffer (number of decimal digits)\n    // n is the position of the decimal point relative to the start of the buffer.\n\n    if (k <= n && n <= max_exp)\n    {\n        // digits[000]\n        // len <= max_exp + 2\n\n        std::memset(buf + k, '0', static_cast<size_t>(n) - static_cast<size_t>(k));\n        // Make it look like a floating-point number (#362, #378)\n        buf[n + 0] = '.';\n        buf[n + 1] = '0';\n        return buf + (static_cast<size_t>(n) + 2);\n    }\n\n    if (0 < n && n <= max_exp)\n    {\n        // dig.its\n        // len <= max_digits10 + 1\n\n        JSON_ASSERT(k > n);\n\n        std::memmove(buf + (static_cast<size_t>(n) + 1), buf + n, static_cast<size_t>(k) - static_cast<size_t>(n));\n        buf[n] = '.';\n        return buf + (static_cast<size_t>(k) + 1U);\n    }\n\n    if (min_exp < n && n <= 0)\n    {\n        // 0.[000]digits\n        // len <= 2 + (-min_exp - 1) + max_digits10\n\n        std::memmove(buf + (2 + static_cast<size_t>(-n)), buf, static_cast<size_t>(k));\n        buf[0] = '0';\n        buf[1] = '.';\n        std::memset(buf + 2, '0', static_cast<size_t>(-n));\n        return buf + (2U + static_cast<size_t>(-n) + static_cast<size_t>(k));\n    }\n\n    if (k == 1)\n    {\n        // dE+123\n        // len <= 1 + 5\n\n        buf += 1;\n    }\n    else\n    {\n        // d.igitsE+123\n        // len <= max_digits10 + 1 + 5\n\n        std::memmove(buf + 2, buf + 1, static_cast<size_t>(k) - 1);\n        buf[1] = '.';\n        buf += 1 + static_cast<size_t>(k);\n    }\n\n    *buf++ = 'e';\n    return append_exponent(buf, n - 1);\n}\n\n}  // namespace dtoa_impl\n\n/*!\n@brief generates a decimal representation of the floating-point number value in [first, last).\n\nThe format of the resulting decimal representation is similar to printf's %g\nformat. Returns an iterator pointing past-the-end of the decimal representation.\n\n@note The input number must be finite, i.e. NaN's and Inf's are not supported.\n@note The buffer must be large enough.\n@note The result is NOT null-terminated.\n*/\ntemplate<typename FloatType>\nJSON_HEDLEY_NON_NULL(1, 2)\nJSON_HEDLEY_RETURNS_NON_NULL\nchar* to_chars(char* first, const char* last, FloatType value)\n{\n    static_cast<void>(last); // maybe unused - fix warning\n    JSON_ASSERT(std::isfinite(value));\n\n    // Use signbit(value) instead of (value < 0) since signbit works for -0.\n    if (std::signbit(value))\n    {\n        value = -value;\n        *first++ = '-';\n    }\n\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n    if (value == 0) // +-0\n    {\n        *first++ = '0';\n        // Make it look like a floating-point number (#362, #378)\n        *first++ = '.';\n        *first++ = '0';\n        return first;\n    }\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n\n    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);\n\n    // Compute v = buffer * 10^decimal_exponent.\n    // The decimal digits are stored in the buffer, which needs to be interpreted\n    // as an unsigned decimal integer.\n    // len is the length of the buffer, i.e. the number of decimal digits.\n    int len = 0;\n    int decimal_exponent = 0;\n    dtoa_impl::grisu2(first, len, decimal_exponent, value);\n\n    JSON_ASSERT(len <= std::numeric_limits<FloatType>::max_digits10);\n\n    // Format the buffer like printf(\"%.*g\", prec, value)\n    constexpr int kMinExp = -4;\n    // Use digits10 here to increase compatibility with version 2.\n    constexpr int kMaxExp = std::numeric_limits<FloatType>::digits10;\n\n    JSON_ASSERT(last - first >= kMaxExp + 2);\n    JSON_ASSERT(last - first >= 2 + (-kMinExp - 1) + std::numeric_limits<FloatType>::max_digits10);\n    JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10 + 6);\n\n    return dtoa_impl::format_buffer(first, len, decimal_exponent, kMinExp, kMaxExp);\n}\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/exceptions.hpp>\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/cpp_future.hpp>\n\n// #include <nlohmann/detail/output/binary_writer.hpp>\n\n// #include <nlohmann/detail/output/output_adapters.hpp>\n\n// #include <nlohmann/detail/string_concat.hpp>\n\n// #include <nlohmann/detail/value_t.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\nnamespace detail\n{\n\n///////////////////\n// serialization //\n///////////////////\n\n/// how to treat decoding errors\nenum class error_handler_t\n{\n    strict,  ///< throw a type_error exception in case of invalid UTF-8\n    replace, ///< replace invalid UTF-8 sequences with U+FFFD\n    ignore   ///< ignore invalid UTF-8 sequences\n};\n\ntemplate<typename BasicJsonType>\nclass serializer\n{\n    using string_t = typename BasicJsonType::string_t;\n    using number_float_t = typename BasicJsonType::number_float_t;\n    using number_integer_t = typename BasicJsonType::number_integer_t;\n    using number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n    using binary_char_t = typename BasicJsonType::binary_t::value_type;\n    static constexpr std::uint8_t UTF8_ACCEPT = 0;\n    static constexpr std::uint8_t UTF8_REJECT = 1;\n\n  public:\n    /*!\n    @param[in] s  output stream to serialize to\n    @param[in] ichar  indentation character to use\n    @param[in] error_handler_  how to react on decoding errors\n    */\n    serializer(output_adapter_t<char> s, const char ichar,\n               error_handler_t error_handler_ = error_handler_t::strict)\n        : o(std::move(s))\n        , loc(std::localeconv())\n        , thousands_sep(loc->thousands_sep == nullptr ? '\\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep)))\n        , decimal_point(loc->decimal_point == nullptr ? '\\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point)))\n        , indent_char(ichar)\n        , indent_string(512, indent_char)\n        , error_handler(error_handler_)\n    {}\n\n    // delete because of pointer members\n    serializer(const serializer&) = delete;\n    serializer& operator=(const serializer&) = delete;\n    serializer(serializer&&) = delete;\n    serializer& operator=(serializer&&) = delete;\n    ~serializer() = default;\n\n    /*!\n    @brief internal implementation of the serialization function\n\n    This function is called by the public member function dump and organizes\n    the serialization internally. The indentation level is propagated as\n    additional parameter. In case of arrays and objects, the function is\n    called recursively.\n\n    - strings and object keys are escaped using `escape_string()`\n    - integer numbers are converted implicitly via `operator<<`\n    - floating-point numbers are converted to a string using `\"%g\"` format\n    - binary values are serialized as objects containing the subtype and the\n      byte array\n\n    @param[in] val               value to serialize\n    @param[in] pretty_print      whether the output shall be pretty-printed\n    @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters\n    in the output are escaped with `\\uXXXX` sequences, and the result consists\n    of ASCII characters only.\n    @param[in] indent_step       the indent level\n    @param[in] current_indent    the current indent level (only used internally)\n    */\n    void dump(const BasicJsonType& val,\n              const bool pretty_print,\n              const bool ensure_ascii,\n              const unsigned int indent_step,\n              const unsigned int current_indent = 0)\n    {\n        switch (val.m_data.m_type)\n        {\n            case value_t::object:\n            {\n                if (val.m_data.m_value.object->empty())\n                {\n                    o->write_characters(\"{}\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    auto i = val.m_data.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\": \", 3);\n                        dump(i->second, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    JSON_ASSERT(i != val.m_data.m_value.object->cend());\n                    JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\": \", 3);\n                    dump(i->second, true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_character('{');\n\n                    // first n-1 elements\n                    auto i = val.m_data.m_value.object->cbegin();\n                    for (std::size_t cnt = 0; cnt < val.m_data.m_value.object->size() - 1; ++cnt, ++i)\n                    {\n                        o->write_character('\\\"');\n                        dump_escaped(i->first, ensure_ascii);\n                        o->write_characters(\"\\\":\", 2);\n                        dump(i->second, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    JSON_ASSERT(i != val.m_data.m_value.object->cend());\n                    JSON_ASSERT(std::next(i) == val.m_data.m_value.object->cend());\n                    o->write_character('\\\"');\n                    dump_escaped(i->first, ensure_ascii);\n                    o->write_characters(\"\\\":\", 2);\n                    dump(i->second, false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character('}');\n                }\n\n                return;\n            }\n\n            case value_t::array:\n            {\n                if (val.m_data.m_value.array->empty())\n                {\n                    o->write_characters(\"[]\", 2);\n                    return;\n                }\n\n                if (pretty_print)\n                {\n                    o->write_characters(\"[\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    // first n-1 elements\n                    for (auto i = val.m_data.m_value.array->cbegin();\n                            i != val.m_data.m_value.array->cend() - 1; ++i)\n                    {\n                        o->write_characters(indent_string.c_str(), new_indent);\n                        dump(*i, true, ensure_ascii, indent_step, new_indent);\n                        o->write_characters(\",\\n\", 2);\n                    }\n\n                    // last element\n                    JSON_ASSERT(!val.m_data.m_value.array->empty());\n                    o->write_characters(indent_string.c_str(), new_indent);\n                    dump(val.m_data.m_value.array->back(), true, ensure_ascii, indent_step, new_indent);\n\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character(']');\n                }\n                else\n                {\n                    o->write_character('[');\n\n                    // first n-1 elements\n                    for (auto i = val.m_data.m_value.array->cbegin();\n                            i != val.m_data.m_value.array->cend() - 1; ++i)\n                    {\n                        dump(*i, false, ensure_ascii, indent_step, current_indent);\n                        o->write_character(',');\n                    }\n\n                    // last element\n                    JSON_ASSERT(!val.m_data.m_value.array->empty());\n                    dump(val.m_data.m_value.array->back(), false, ensure_ascii, indent_step, current_indent);\n\n                    o->write_character(']');\n                }\n\n                return;\n            }\n\n            case value_t::string:\n            {\n                o->write_character('\\\"');\n                dump_escaped(*val.m_data.m_value.string, ensure_ascii);\n                o->write_character('\\\"');\n                return;\n            }\n\n            case value_t::binary:\n            {\n                if (pretty_print)\n                {\n                    o->write_characters(\"{\\n\", 2);\n\n                    // variable to hold indentation for recursive calls\n                    const auto new_indent = current_indent + indent_step;\n                    if (JSON_HEDLEY_UNLIKELY(indent_string.size() < new_indent))\n                    {\n                        indent_string.resize(indent_string.size() * 2, ' ');\n                    }\n\n                    o->write_characters(indent_string.c_str(), new_indent);\n\n                    o->write_characters(\"\\\"bytes\\\": [\", 10);\n\n                    if (!val.m_data.m_value.binary->empty())\n                    {\n                        for (auto i = val.m_data.m_value.binary->cbegin();\n                                i != val.m_data.m_value.binary->cend() - 1; ++i)\n                        {\n                            dump_integer(*i);\n                            o->write_characters(\", \", 2);\n                        }\n                        dump_integer(val.m_data.m_value.binary->back());\n                    }\n\n                    o->write_characters(\"],\\n\", 3);\n                    o->write_characters(indent_string.c_str(), new_indent);\n\n                    o->write_characters(\"\\\"subtype\\\": \", 11);\n                    if (val.m_data.m_value.binary->has_subtype())\n                    {\n                        dump_integer(val.m_data.m_value.binary->subtype());\n                    }\n                    else\n                    {\n                        o->write_characters(\"null\", 4);\n                    }\n                    o->write_character('\\n');\n                    o->write_characters(indent_string.c_str(), current_indent);\n                    o->write_character('}');\n                }\n                else\n                {\n                    o->write_characters(\"{\\\"bytes\\\":[\", 10);\n\n                    if (!val.m_data.m_value.binary->empty())\n                    {\n                        for (auto i = val.m_data.m_value.binary->cbegin();\n                                i != val.m_data.m_value.binary->cend() - 1; ++i)\n                        {\n                            dump_integer(*i);\n                            o->write_character(',');\n                        }\n                        dump_integer(val.m_data.m_value.binary->back());\n                    }\n\n                    o->write_characters(\"],\\\"subtype\\\":\", 12);\n                    if (val.m_data.m_value.binary->has_subtype())\n                    {\n                        dump_integer(val.m_data.m_value.binary->subtype());\n                        o->write_character('}');\n                    }\n                    else\n                    {\n                        o->write_characters(\"null}\", 5);\n                    }\n                }\n                return;\n            }\n\n            case value_t::boolean:\n            {\n                if (val.m_data.m_value.boolean)\n                {\n                    o->write_characters(\"true\", 4);\n                }\n                else\n                {\n                    o->write_characters(\"false\", 5);\n                }\n                return;\n            }\n\n            case value_t::number_integer:\n            {\n                dump_integer(val.m_data.m_value.number_integer);\n                return;\n            }\n\n            case value_t::number_unsigned:\n            {\n                dump_integer(val.m_data.m_value.number_unsigned);\n                return;\n            }\n\n            case value_t::number_float:\n            {\n                dump_float(val.m_data.m_value.number_float);\n                return;\n            }\n\n            case value_t::discarded:\n            {\n                o->write_characters(\"<discarded>\", 11);\n                return;\n            }\n\n            case value_t::null:\n            {\n                o->write_characters(\"null\", 4);\n                return;\n            }\n\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief dump escaped string\n\n    Escape a string by replacing certain special characters by a sequence of an\n    escape character (backslash) and another character and other control\n    characters by a sequence of \"\\u\" followed by a four-digit hex\n    representation. The escaped string is written to output stream @a o.\n\n    @param[in] s  the string to escape\n    @param[in] ensure_ascii  whether to escape non-ASCII characters with\n                             \\uXXXX sequences\n\n    @complexity Linear in the length of string @a s.\n    */\n    void dump_escaped(const string_t& s, const bool ensure_ascii)\n    {\n        std::uint32_t codepoint{};\n        std::uint8_t state = UTF8_ACCEPT;\n        std::size_t bytes = 0;  // number of bytes written to string_buffer\n\n        // number of bytes written at the point of the last valid byte\n        std::size_t bytes_after_last_accept = 0;\n        std::size_t undumped_chars = 0;\n\n        for (std::size_t i = 0; i < s.size(); ++i)\n        {\n            const auto byte = static_cast<std::uint8_t>(s[i]);\n\n            switch (decode(state, codepoint, byte))\n            {\n                case UTF8_ACCEPT:  // decode found a new code point\n                {\n                    switch (codepoint)\n                    {\n                        case 0x08: // backspace\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'b';\n                            break;\n                        }\n\n                        case 0x09: // horizontal tab\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 't';\n                            break;\n                        }\n\n                        case 0x0A: // newline\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'n';\n                            break;\n                        }\n\n                        case 0x0C: // formfeed\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'f';\n                            break;\n                        }\n\n                        case 0x0D: // carriage return\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = 'r';\n                            break;\n                        }\n\n                        case 0x22: // quotation mark\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\"';\n                            break;\n                        }\n\n                        case 0x5C: // reverse solidus\n                        {\n                            string_buffer[bytes++] = '\\\\';\n                            string_buffer[bytes++] = '\\\\';\n                            break;\n                        }\n\n                        default:\n                        {\n                            // escape control characters (0x00..0x1F) or, if\n                            // ensure_ascii parameter is used, non-ASCII characters\n                            if ((codepoint <= 0x1F) || (ensure_ascii && (codepoint >= 0x7F)))\n                            {\n                                if (codepoint <= 0xFFFF)\n                                {\n                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                                    static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, \"\\\\u%04x\",\n                                                                      static_cast<std::uint16_t>(codepoint)));\n                                    bytes += 6;\n                                }\n                                else\n                                {\n                                    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n                                    static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, \"\\\\u%04x\\\\u%04x\",\n                                                                      static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),\n                                                                      static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));\n                                    bytes += 12;\n                                }\n                            }\n                            else\n                            {\n                                // copy byte to buffer (all previous bytes\n                                // been copied have in default case above)\n                                string_buffer[bytes++] = s[i];\n                            }\n                            break;\n                        }\n                    }\n\n                    // write buffer and reset index; there must be 13 bytes\n                    // left, as this is the maximal number of bytes to be\n                    // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                    if (string_buffer.size() - bytes < 13)\n                    {\n                        o->write_characters(string_buffer.data(), bytes);\n                        bytes = 0;\n                    }\n\n                    // remember the byte position of this accept\n                    bytes_after_last_accept = bytes;\n                    undumped_chars = 0;\n                    break;\n                }\n\n                case UTF8_REJECT:  // decode found invalid UTF-8 byte\n                {\n                    switch (error_handler)\n                    {\n                        case error_handler_t::strict:\n                        {\n                            JSON_THROW(type_error::create(316, concat(\"invalid UTF-8 byte at index \", std::to_string(i), \": 0x\", hex_bytes(byte | 0)), nullptr));\n                        }\n\n                        case error_handler_t::ignore:\n                        case error_handler_t::replace:\n                        {\n                            // in case we saw this character the first time, we\n                            // would like to read it again, because the byte\n                            // may be OK for itself, but just not OK for the\n                            // previous sequence\n                            if (undumped_chars > 0)\n                            {\n                                --i;\n                            }\n\n                            // reset length buffer to the last accepted index;\n                            // thus removing/ignoring the invalid characters\n                            bytes = bytes_after_last_accept;\n\n                            if (error_handler == error_handler_t::replace)\n                            {\n                                // add a replacement character\n                                if (ensure_ascii)\n                                {\n                                    string_buffer[bytes++] = '\\\\';\n                                    string_buffer[bytes++] = 'u';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'f';\n                                    string_buffer[bytes++] = 'd';\n                                }\n                                else\n                                {\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xEF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBF');\n                                    string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\\xBD');\n                                }\n\n                                // write buffer and reset index; there must be 13 bytes\n                                // left, as this is the maximal number of bytes to be\n                                // written (\"\\uxxxx\\uxxxx\\0\") for one code point\n                                if (string_buffer.size() - bytes < 13)\n                                {\n                                    o->write_characters(string_buffer.data(), bytes);\n                                    bytes = 0;\n                                }\n\n                                bytes_after_last_accept = bytes;\n                            }\n\n                            undumped_chars = 0;\n\n                            // continue processing the string\n                            state = UTF8_ACCEPT;\n                            break;\n                        }\n\n                        default:            // LCOV_EXCL_LINE\n                            JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n\n                default:  // decode found yet incomplete multi-byte code point\n                {\n                    if (!ensure_ascii)\n                    {\n                        // code point will not be escaped - copy byte to buffer\n                        string_buffer[bytes++] = s[i];\n                    }\n                    ++undumped_chars;\n                    break;\n                }\n            }\n        }\n\n        // we finished processing the string\n        if (JSON_HEDLEY_LIKELY(state == UTF8_ACCEPT))\n        {\n            // write buffer\n            if (bytes > 0)\n            {\n                o->write_characters(string_buffer.data(), bytes);\n            }\n        }\n        else\n        {\n            // we finish reading, but do not accept: string was incomplete\n            switch (error_handler)\n            {\n                case error_handler_t::strict:\n                {\n                    JSON_THROW(type_error::create(316, concat(\"incomplete UTF-8 string; last byte: 0x\", hex_bytes(static_cast<std::uint8_t>(s.back() | 0))), nullptr));\n                }\n\n                case error_handler_t::ignore:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    break;\n                }\n\n                case error_handler_t::replace:\n                {\n                    // write all accepted bytes\n                    o->write_characters(string_buffer.data(), bytes_after_last_accept);\n                    // add a replacement character\n                    if (ensure_ascii)\n                    {\n                        o->write_characters(\"\\\\ufffd\", 6);\n                    }\n                    else\n                    {\n                        o->write_characters(\"\\xEF\\xBF\\xBD\", 3);\n                    }\n                    break;\n                }\n\n                default:            // LCOV_EXCL_LINE\n                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n            }\n        }\n    }\n\n  private:\n    /*!\n    @brief count digits\n\n    Count the number of decimal (base 10) digits for an input unsigned integer.\n\n    @param[in] x  unsigned integer number to count its digits\n    @return    number of decimal digits\n    */\n    unsigned int count_digits(number_unsigned_t x) noexcept\n    {\n        unsigned int n_digits = 1;\n        for (;;)\n        {\n            if (x < 10)\n            {\n                return n_digits;\n            }\n            if (x < 100)\n            {\n                return n_digits + 1;\n            }\n            if (x < 1000)\n            {\n                return n_digits + 2;\n            }\n            if (x < 10000)\n            {\n                return n_digits + 3;\n            }\n            x = x / 10000u;\n            n_digits += 4;\n        }\n    }\n\n    /*!\n     * @brief convert a byte to a uppercase hex representation\n     * @param[in] byte byte to represent\n     * @return representation (\"00\"..\"FF\")\n     */\n    static std::string hex_bytes(std::uint8_t byte)\n    {\n        std::string result = \"FF\";\n        constexpr const char* nibble_to_hex = \"0123456789ABCDEF\";\n        result[0] = nibble_to_hex[byte / 16];\n        result[1] = nibble_to_hex[byte % 16];\n        return result;\n    }\n\n    // templates to avoid warnings about useless casts\n    template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>\n    bool is_negative_number(NumberType x)\n    {\n        return x < 0;\n    }\n\n    template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 >\n    bool is_negative_number(NumberType /*unused*/)\n    {\n        return false;\n    }\n\n    /*!\n    @brief dump an integer\n\n    Dump a given integer to output stream @a o. Works internally with\n    @a number_buffer.\n\n    @param[in] x  integer number (signed or unsigned) to dump\n    @tparam NumberType either @a number_integer_t or @a number_unsigned_t\n    */\n    template < typename NumberType, detail::enable_if_t <\n                   std::is_integral<NumberType>::value ||\n                   std::is_same<NumberType, number_unsigned_t>::value ||\n                   std::is_same<NumberType, number_integer_t>::value ||\n                   std::is_same<NumberType, binary_char_t>::value,\n                   int > = 0 >\n    void dump_integer(NumberType x)\n    {\n        static constexpr std::array<std::array<char, 2>, 100> digits_to_99\n        {\n            {\n                {{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},\n                {{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}},\n                {{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}},\n                {{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}},\n                {{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}},\n                {{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}},\n                {{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}},\n                {{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}},\n                {{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}},\n                {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},\n            }\n        };\n\n        // special case for \"0\"\n        if (x == 0)\n        {\n            o->write_character('0');\n            return;\n        }\n\n        // use a pointer to fill the buffer\n        auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n\n        number_unsigned_t abs_value;\n\n        unsigned int n_chars{};\n\n        if (is_negative_number(x))\n        {\n            *buffer_ptr = '-';\n            abs_value = remove_sign(static_cast<number_integer_t>(x));\n\n            // account one more byte for the minus sign\n            n_chars = 1 + count_digits(abs_value);\n        }\n        else\n        {\n            abs_value = static_cast<number_unsigned_t>(x);\n            n_chars = count_digits(abs_value);\n        }\n\n        // spare 1 byte for '\\0'\n        JSON_ASSERT(n_chars < number_buffer.size() - 1);\n\n        // jump to the end to generate the string from backward,\n        // so we later avoid reversing the result\n        buffer_ptr += n_chars;\n\n        // Fast int2ascii implementation inspired by \"Fastware\" talk by Andrei Alexandrescu\n        // See: https://www.youtube.com/watch?v=o4-CwDo2zpg\n        while (abs_value >= 100)\n        {\n            const auto digits_index = static_cast<unsigned>((abs_value % 100));\n            abs_value /= 100;\n            *(--buffer_ptr) = digits_to_99[digits_index][1];\n            *(--buffer_ptr) = digits_to_99[digits_index][0];\n        }\n\n        if (abs_value >= 10)\n        {\n            const auto digits_index = static_cast<unsigned>(abs_value);\n            *(--buffer_ptr) = digits_to_99[digits_index][1];\n            *(--buffer_ptr) = digits_to_99[digits_index][0];\n        }\n        else\n        {\n            *(--buffer_ptr) = static_cast<char>('0' + abs_value);\n        }\n\n        o->write_characters(number_buffer.data(), n_chars);\n    }\n\n    /*!\n    @brief dump a floating-point number\n\n    Dump a given floating-point number to output stream @a o. Works internally\n    with @a number_buffer.\n\n    @param[in] x  floating-point number to dump\n    */\n    void dump_float(number_float_t x)\n    {\n        // NaN / inf\n        if (!std::isfinite(x))\n        {\n            o->write_characters(\"null\", 4);\n            return;\n        }\n\n        // If number_float_t is an IEEE-754 single or double precision number,\n        // use the Grisu2 algorithm to produce short numbers which are\n        // guaranteed to round-trip, using strtof and strtod, resp.\n        //\n        // NB: The test below works if <long double> == <double>.\n        static constexpr bool is_ieee_single_or_double\n            = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||\n              (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);\n\n        dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());\n    }\n\n    void dump_float(number_float_t x, std::true_type /*is_ieee_single_or_double*/)\n    {\n        auto* begin = number_buffer.data();\n        auto* end = ::nlohmann::detail::to_chars(begin, begin + number_buffer.size(), x);\n\n        o->write_characters(begin, static_cast<size_t>(end - begin));\n    }\n\n    void dump_float(number_float_t x, std::false_type /*is_ieee_single_or_double*/)\n    {\n        // get number of digits for a float -> text -> float round-trip\n        static constexpr auto d = std::numeric_limits<number_float_t>::max_digits10;\n\n        // the actual conversion\n        // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)\n        std::ptrdiff_t len = (std::snprintf)(number_buffer.data(), number_buffer.size(), \"%.*g\", d, x);\n\n        // negative value indicates an error\n        JSON_ASSERT(len > 0);\n        // check if buffer was large enough\n        JSON_ASSERT(static_cast<std::size_t>(len) < number_buffer.size());\n\n        // erase thousands separator\n        if (thousands_sep != '\\0')\n        {\n            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::remove returns an iterator, see https://github.com/nlohmann/json/issues/3081\n            const auto end = std::remove(number_buffer.begin(), number_buffer.begin() + len, thousands_sep);\n            std::fill(end, number_buffer.end(), '\\0');\n            JSON_ASSERT((end - number_buffer.begin()) <= len);\n            len = (end - number_buffer.begin());\n        }\n\n        // convert decimal point to '.'\n        if (decimal_point != '\\0' && decimal_point != '.')\n        {\n            // NOLINTNEXTLINE(readability-qualified-auto,llvm-qualified-auto): std::find returns an iterator, see https://github.com/nlohmann/json/issues/3081\n            const auto dec_pos = std::find(number_buffer.begin(), number_buffer.end(), decimal_point);\n            if (dec_pos != number_buffer.end())\n            {\n                *dec_pos = '.';\n            }\n        }\n\n        o->write_characters(number_buffer.data(), static_cast<std::size_t>(len));\n\n        // determine if we need to append \".0\"\n        const bool value_is_int_like =\n            std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1,\n                         [](char c)\n        {\n            return c == '.' || c == 'e';\n        });\n\n        if (value_is_int_like)\n        {\n            o->write_characters(\".0\", 2);\n        }\n    }\n\n    /*!\n    @brief check whether a string is UTF-8 encoded\n\n    The function checks each byte of a string whether it is UTF-8 encoded. The\n    result of the check is stored in the @a state parameter. The function must\n    be called initially with state 0 (accept). State 1 means the string must\n    be rejected, because the current byte is not allowed. If the string is\n    completely processed, but the state is non-zero, the string ended\n    prematurely; that is, the last byte indicated more bytes should have\n    followed.\n\n    @param[in,out] state  the state of the decoding\n    @param[in,out] codep  codepoint (valid only if resulting state is UTF8_ACCEPT)\n    @param[in] byte       next byte to decode\n    @return               new state\n\n    @note The function has been edited: a std::array is used.\n\n    @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>\n    @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n    */\n    static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept\n    {\n        static const std::array<std::uint8_t, 400> utf8d =\n        {\n            {\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F\n                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F\n                7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF\n                8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF\n                0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF\n                0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF\n                0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0\n                1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2\n                1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4\n                1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6\n                1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8\n            }\n        };\n\n        JSON_ASSERT(byte < utf8d.size());\n        const std::uint8_t type = utf8d[byte];\n\n        codep = (state != UTF8_ACCEPT)\n                ? (byte & 0x3fu) | (codep << 6u)\n                : (0xFFu >> type) & (byte);\n\n        const std::size_t index = 256u + (static_cast<size_t>(state) * 16u) + static_cast<size_t>(type);\n        JSON_ASSERT(index < utf8d.size());\n        state = utf8d[index];\n        return state;\n    }\n\n    /*\n     * Overload to make the compiler happy while it is instantiating\n     * dump_integer for number_unsigned_t.\n     * Must never be called.\n     */\n    number_unsigned_t remove_sign(number_unsigned_t x)\n    {\n        JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        return x; // LCOV_EXCL_LINE\n    }\n\n    /*\n     * Helper function for dump_integer\n     *\n     * This function takes a negative signed integer and returns its absolute\n     * value as unsigned integer. The plus/minus shuffling is necessary as we can\n     * not directly remove the sign of an arbitrary signed integer as the\n     * absolute values of INT_MIN and INT_MAX are usually not the same. See\n     * #1708 for details.\n     */\n    number_unsigned_t remove_sign(number_integer_t x) noexcept\n    {\n        JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)\n        return static_cast<number_unsigned_t>(-(x + 1)) + 1;\n    }\n\n  private:\n    /// the output of the serializer\n    output_adapter_t<char> o = nullptr;\n\n    /// a (hopefully) large enough character buffer\n    std::array<char, 64> number_buffer{{}};\n\n    /// the locale\n    const std::lconv* loc = nullptr;\n    /// the locale's thousand separator character\n    const char thousands_sep = '\\0';\n    /// the locale's decimal point character\n    const char decimal_point = '\\0';\n\n    /// string buffer\n    std::array<char, 512> string_buffer{{}};\n\n    /// the indentation character\n    const char indent_char;\n    /// the indentation string\n    string_t indent_string;\n\n    /// error_handler how to react on decoding errors\n    const error_handler_t error_handler;\n};\n\n}  // namespace detail\nNLOHMANN_JSON_NAMESPACE_END\n\n// #include <nlohmann/detail/value_t.hpp>\n\n// #include <nlohmann/json_fwd.hpp>\n\n// #include <nlohmann/ordered_map.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#include <functional> // equal_to, less\n#include <initializer_list> // initializer_list\n#include <iterator> // input_iterator_tag, iterator_traits\n#include <memory> // allocator\n#include <stdexcept> // for out_of_range\n#include <type_traits> // enable_if, is_convertible\n#include <utility> // pair\n#include <vector> // vector\n\n// #include <nlohmann/detail/macro_scope.hpp>\n\n// #include <nlohmann/detail/meta/type_traits.hpp>\n\n\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/// ordered_map: a minimal map-like container that preserves insertion order\n/// for use within nlohmann::basic_json<ordered_map>\ntemplate <class Key, class T, class IgnoredLess = std::less<Key>,\n          class Allocator = std::allocator<std::pair<const Key, T>>>\n              struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>\n{\n    using key_type = Key;\n    using mapped_type = T;\n    using Container = std::vector<std::pair<const Key, T>, Allocator>;\n    using iterator = typename Container::iterator;\n    using const_iterator = typename Container::const_iterator;\n    using size_type = typename Container::size_type;\n    using value_type = typename Container::value_type;\n#ifdef JSON_HAS_CPP_14\n    using key_compare = std::equal_to<>;\n#else\n    using key_compare = std::equal_to<Key>;\n#endif\n\n    // Explicit constructors instead of `using Container::Container`\n    // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)\n    ordered_map() noexcept(noexcept(Container())) : Container{} {}\n    explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {}\n    template <class It>\n    ordered_map(It first, It last, const Allocator& alloc = Allocator())\n        : Container{first, last, alloc} {}\n    ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() )\n        : Container{init, alloc} {}\n\n    std::pair<iterator, bool> emplace(const key_type& key, T&& t)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return {it, false};\n            }\n        }\n        Container::emplace_back(key, std::forward<T>(t));\n        return {std::prev(this->end()), true};\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    std::pair<iterator, bool> emplace(KeyType && key, T && t)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return {it, false};\n            }\n        }\n        Container::emplace_back(std::forward<KeyType>(key), std::forward<T>(t));\n        return {std::prev(this->end()), true};\n    }\n\n    T& operator[](const key_type& key)\n    {\n        return emplace(key, T{}).first->second;\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    T & operator[](KeyType && key)\n    {\n        return emplace(std::forward<KeyType>(key), T{}).first->second;\n    }\n\n    const T& operator[](const key_type& key) const\n    {\n        return at(key);\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    const T & operator[](KeyType && key) const\n    {\n        return at(std::forward<KeyType>(key));\n    }\n\n    T& at(const key_type& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    const T& at(const key_type& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it->second;\n            }\n        }\n\n        JSON_THROW(std::out_of_range(\"key not found\"));\n    }\n\n    size_type erase(const key_type& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                // Since we cannot move const Keys, re-construct them in place\n                for (auto next = it; ++next != this->end(); ++it)\n                {\n                    it->~value_type(); // Destroy but keep allocation\n                    new (&*it) value_type{std::move(*next)};\n                }\n                Container::pop_back();\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                // Since we cannot move const Keys, re-construct them in place\n                for (auto next = it; ++next != this->end(); ++it)\n                {\n                    it->~value_type(); // Destroy but keep allocation\n                    new (&*it) value_type{std::move(*next)};\n                }\n                Container::pop_back();\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    iterator erase(iterator pos)\n    {\n        return erase(pos, std::next(pos));\n    }\n\n    iterator erase(iterator first, iterator last)\n    {\n        if (first == last)\n        {\n            return first;\n        }\n\n        const auto elements_affected = std::distance(first, last);\n        const auto offset = std::distance(Container::begin(), first);\n\n        // This is the start situation. We need to delete elements_affected\n        // elements (3 in this example: e, f, g), and need to return an\n        // iterator past the last deleted element (h in this example).\n        // Note that offset is the distance from the start of the vector\n        // to first. We will need this later.\n\n        // [ a, b, c, d, e, f, g, h, i, j ]\n        //               ^        ^\n        //             first    last\n\n        // Since we cannot move const Keys, we re-construct them in place.\n        // We start at first and re-construct (viz. copy) the elements from\n        // the back of the vector. Example for first iteration:\n\n        //               ,--------.\n        //               v        |   destroy e and re-construct with h\n        // [ a, b, c, d, e, f, g, h, i, j ]\n        //               ^        ^\n        //               it       it + elements_affected\n\n        for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)\n        {\n            it->~value_type(); // destroy but keep allocation\n            new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // \"move\" next element to it\n        }\n\n        // [ a, b, c, d, h, i, j, h, i, j ]\n        //               ^        ^\n        //             first    last\n\n        // remove the unneeded elements at the end of the vector\n        Container::resize(this->size() - static_cast<size_type>(elements_affected));\n\n        // [ a, b, c, d, h, i, j ]\n        //               ^        ^\n        //             first    last\n\n        // first is now pointing past the last deleted element, but we cannot\n        // use this iterator, because it may have been invalidated by the\n        // resize call. Instead, we can return begin() + offset.\n        return Container::begin() + offset;\n    }\n\n    size_type count(const key_type& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return 1;\n            }\n        }\n        return 0;\n    }\n\n    iterator find(const key_type& key)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>\n    iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    const_iterator find(const key_type& key) const\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, key))\n            {\n                return it;\n            }\n        }\n        return Container::end();\n    }\n\n    std::pair<iterator, bool> insert( value_type&& value )\n    {\n        return emplace(value.first, std::move(value.second));\n    }\n\n    std::pair<iterator, bool> insert( const value_type& value )\n    {\n        for (auto it = this->begin(); it != this->end(); ++it)\n        {\n            if (m_compare(it->first, value.first))\n            {\n                return {it, false};\n            }\n        }\n        Container::push_back(value);\n        return {--this->end(), true};\n    }\n\n    template<typename InputIt>\n    using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,\n        std::input_iterator_tag>::value>::type;\n\n    template<typename InputIt, typename = require_input_iter<InputIt>>\n    void insert(InputIt first, InputIt last)\n    {\n        for (auto it = first; it != last; ++it)\n        {\n            insert(*it);\n        }\n    }\n\nprivate:\n    JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();\n};\n\nNLOHMANN_JSON_NAMESPACE_END\n\n\n#if defined(JSON_HAS_CPP_17)\n    #if JSON_HAS_STATIC_RTTI\n        #include <any>\n    #endif\n    #include <string_view>\n#endif\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/*!\n@brief a class to store JSON values\n\n@internal\n@invariant The member variables @a m_value and @a m_type have the following\nrelationship:\n- If `m_type == value_t::object`, then `m_value.object != nullptr`.\n- If `m_type == value_t::array`, then `m_value.array != nullptr`.\n- If `m_type == value_t::string`, then `m_value.string != nullptr`.\nThe invariants are checked by member function assert_invariant().\n\n@note ObjectType trick from https://stackoverflow.com/a/9860911\n@endinternal\n\n@since version 1.0.0\n\n@nosubgrouping\n*/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nclass basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)\n    : public ::nlohmann::detail::json_base_class<CustomBaseClass>\n{\n  private:\n    template<detail::value_t> friend struct detail::external_constructor;\n\n    template<typename>\n    friend class ::nlohmann::json_pointer;\n    // can be restored when json_pointer backwards compatibility is removed\n    // friend ::nlohmann::json_pointer<StringType>;\n\n    template<typename BasicJsonType, typename InputType>\n    friend class ::nlohmann::detail::parser;\n    friend ::nlohmann::detail::serializer<basic_json>;\n    template<typename BasicJsonType>\n    friend class ::nlohmann::detail::iter_impl;\n    template<typename BasicJsonType, typename CharType>\n    friend class ::nlohmann::detail::binary_writer;\n    template<typename BasicJsonType, typename InputType, typename SAX>\n    friend class ::nlohmann::detail::binary_reader;\n    template<typename BasicJsonType, typename InputAdapterType>\n    friend class ::nlohmann::detail::json_sax_dom_parser;\n    template<typename BasicJsonType, typename InputAdapterType>\n    friend class ::nlohmann::detail::json_sax_dom_callback_parser;\n    friend class ::nlohmann::detail::exception;\n\n    /// workaround type for MSVC\n    using basic_json_t = NLOHMANN_BASIC_JSON_TPL;\n    using json_base_class_t = ::nlohmann::detail::json_base_class<CustomBaseClass>;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    // convenience aliases for types residing in namespace detail;\n    using lexer = ::nlohmann::detail::lexer_base<basic_json>;\n\n    template<typename InputAdapterType>\n    static ::nlohmann::detail::parser<basic_json, InputAdapterType> parser(\n        InputAdapterType adapter,\n        detail::parser_callback_t<basic_json>cb = nullptr,\n        const bool allow_exceptions = true,\n        const bool ignore_comments = false\n                                 )\n    {\n        return ::nlohmann::detail::parser<basic_json, InputAdapterType>(std::move(adapter),\n            std::move(cb), allow_exceptions, ignore_comments);\n    }\n\n  private:\n    using primitive_iterator_t = ::nlohmann::detail::primitive_iterator_t;\n    template<typename BasicJsonType>\n    using internal_iterator = ::nlohmann::detail::internal_iterator<BasicJsonType>;\n    template<typename BasicJsonType>\n    using iter_impl = ::nlohmann::detail::iter_impl<BasicJsonType>;\n    template<typename Iterator>\n    using iteration_proxy = ::nlohmann::detail::iteration_proxy<Iterator>;\n    template<typename Base> using json_reverse_iterator = ::nlohmann::detail::json_reverse_iterator<Base>;\n\n    template<typename CharType>\n    using output_adapter_t = ::nlohmann::detail::output_adapter_t<CharType>;\n\n    template<typename InputType>\n    using binary_reader = ::nlohmann::detail::binary_reader<basic_json, InputType>;\n    template<typename CharType> using binary_writer = ::nlohmann::detail::binary_writer<basic_json, CharType>;\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    using serializer = ::nlohmann::detail::serializer<basic_json>;\n\n  public:\n    using value_t = detail::value_t;\n    /// JSON Pointer, see @ref nlohmann::json_pointer\n    using json_pointer = ::nlohmann::json_pointer<StringType>;\n    template<typename T, typename SFINAE>\n    using json_serializer = JSONSerializer<T, SFINAE>;\n    /// how to treat decoding errors\n    using error_handler_t = detail::error_handler_t;\n    /// how to treat CBOR tags\n    using cbor_tag_handler_t = detail::cbor_tag_handler_t;\n    /// how to encode BJData\n    using bjdata_version_t = detail::bjdata_version_t;\n    /// helper type for initializer lists of basic_json values\n    using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;\n\n    using input_format_t = detail::input_format_t;\n    /// SAX interface type, see @ref nlohmann::json_sax\n    using json_sax_t = json_sax<basic_json>;\n\n    ////////////////\n    // exceptions //\n    ////////////////\n\n    /// @name exceptions\n    /// Classes to implement user-defined exceptions.\n    /// @{\n\n    using exception = detail::exception;\n    using parse_error = detail::parse_error;\n    using invalid_iterator = detail::invalid_iterator;\n    using type_error = detail::type_error;\n    using out_of_range = detail::out_of_range;\n    using other_error = detail::other_error;\n\n    /// @}\n\n    /////////////////////\n    // container types //\n    /////////////////////\n\n    /// @name container types\n    /// The canonic container types to use @ref basic_json like any other STL\n    /// container.\n    /// @{\n\n    /// the type of elements in a basic_json container\n    using value_type = basic_json;\n\n    /// the type of an element reference\n    using reference = value_type&;\n    /// the type of an element const reference\n    using const_reference = const value_type&;\n\n    /// a type to represent differences between iterators\n    using difference_type = std::ptrdiff_t;\n    /// a type to represent container sizes\n    using size_type = std::size_t;\n\n    /// the allocator type\n    using allocator_type = AllocatorType<basic_json>;\n\n    /// the type of an element pointer\n    using pointer = typename std::allocator_traits<allocator_type>::pointer;\n    /// the type of an element const pointer\n    using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;\n\n    /// an iterator for a basic_json container\n    using iterator = iter_impl<basic_json>;\n    /// a const iterator for a basic_json container\n    using const_iterator = iter_impl<const basic_json>;\n    /// a reverse iterator for a basic_json container\n    using reverse_iterator = json_reverse_iterator<typename basic_json::iterator>;\n    /// a const reverse iterator for a basic_json container\n    using const_reverse_iterator = json_reverse_iterator<typename basic_json::const_iterator>;\n\n    /// @}\n\n    /// @brief returns the allocator associated with the container\n    /// @sa https://json.nlohmann.me/api/basic_json/get_allocator/\n    static allocator_type get_allocator()\n    {\n        return allocator_type();\n    }\n\n    /// @brief returns version information on the library\n    /// @sa https://json.nlohmann.me/api/basic_json/meta/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json meta()\n    {\n        basic_json result;\n\n        result[\"copyright\"] = \"(C) 2013-2025 Niels Lohmann\";\n        result[\"name\"] = \"JSON for Modern C++\";\n        result[\"url\"] = \"https://github.com/nlohmann/json\";\n        result[\"version\"][\"string\"] =\n            detail::concat(std::to_string(NLOHMANN_JSON_VERSION_MAJOR), '.',\n                           std::to_string(NLOHMANN_JSON_VERSION_MINOR), '.',\n                           std::to_string(NLOHMANN_JSON_VERSION_PATCH));\n        result[\"version\"][\"major\"] = NLOHMANN_JSON_VERSION_MAJOR;\n        result[\"version\"][\"minor\"] = NLOHMANN_JSON_VERSION_MINOR;\n        result[\"version\"][\"patch\"] = NLOHMANN_JSON_VERSION_PATCH;\n\n#ifdef _WIN32\n        result[\"platform\"] = \"win32\";\n#elif defined __linux__\n        result[\"platform\"] = \"linux\";\n#elif defined __APPLE__\n        result[\"platform\"] = \"apple\";\n#elif defined __unix__\n        result[\"platform\"] = \"unix\";\n#else\n        result[\"platform\"] = \"unknown\";\n#endif\n\n#if defined(__ICC) || defined(__INTEL_COMPILER)\n        result[\"compiler\"] = {{\"family\", \"icc\"}, {\"version\", __INTEL_COMPILER}};\n#elif defined(__clang__)\n        result[\"compiler\"] = {{\"family\", \"clang\"}, {\"version\", __clang_version__}};\n#elif defined(__GNUC__) || defined(__GNUG__)\n        result[\"compiler\"] = {{\"family\", \"gcc\"}, {\"version\", detail::concat(\n                    std::to_string(__GNUC__), '.',\n                    std::to_string(__GNUC_MINOR__), '.',\n                    std::to_string(__GNUC_PATCHLEVEL__))\n            }\n        };\n#elif defined(__HP_cc) || defined(__HP_aCC)\n        result[\"compiler\"] = \"hp\"\n#elif defined(__IBMCPP__)\n        result[\"compiler\"] = {{\"family\", \"ilecpp\"}, {\"version\", __IBMCPP__}};\n#elif defined(_MSC_VER)\n        result[\"compiler\"] = {{\"family\", \"msvc\"}, {\"version\", _MSC_VER}};\n#elif defined(__PGI)\n        result[\"compiler\"] = {{\"family\", \"pgcpp\"}, {\"version\", __PGI}};\n#elif defined(__SUNPRO_CC)\n        result[\"compiler\"] = {{\"family\", \"sunpro\"}, {\"version\", __SUNPRO_CC}};\n#else\n        result[\"compiler\"] = {{\"family\", \"unknown\"}, {\"version\", \"unknown\"}};\n#endif\n\n#if defined(_MSVC_LANG)\n        result[\"compiler\"][\"c++\"] = std::to_string(_MSVC_LANG);\n#elif defined(__cplusplus)\n        result[\"compiler\"][\"c++\"] = std::to_string(__cplusplus);\n#else\n        result[\"compiler\"][\"c++\"] = \"unknown\";\n#endif\n        return result;\n    }\n\n    ///////////////////////////\n    // JSON value data types //\n    ///////////////////////////\n\n    /// @name JSON value data types\n    /// The data types to store a JSON value. These types are derived from\n    /// the template arguments passed to class @ref basic_json.\n    /// @{\n\n    /// @brief default object key comparator type\n    /// The actual object key comparator type (@ref object_comparator_t) may be\n    /// different.\n    /// @sa https://json.nlohmann.me/api/basic_json/default_object_comparator_t/\n#if defined(JSON_HAS_CPP_14)\n    // use of transparent comparator avoids unnecessary repeated construction of temporaries\n    // in functions involving lookup by key with types other than object_t::key_type (aka. StringType)\n    using default_object_comparator_t = std::less<>;\n#else\n    using default_object_comparator_t = std::less<StringType>;\n#endif\n\n    /// @brief a type for an object\n    /// @sa https://json.nlohmann.me/api/basic_json/object_t/\n    using object_t = ObjectType<StringType,\n          basic_json,\n          default_object_comparator_t,\n          AllocatorType<std::pair<const StringType,\n          basic_json>>>;\n\n    /// @brief a type for an array\n    /// @sa https://json.nlohmann.me/api/basic_json/array_t/\n    using array_t = ArrayType<basic_json, AllocatorType<basic_json>>;\n\n    /// @brief a type for a string\n    /// @sa https://json.nlohmann.me/api/basic_json/string_t/\n    using string_t = StringType;\n\n    /// @brief a type for a boolean\n    /// @sa https://json.nlohmann.me/api/basic_json/boolean_t/\n    using boolean_t = BooleanType;\n\n    /// @brief a type for a number (integer)\n    /// @sa https://json.nlohmann.me/api/basic_json/number_integer_t/\n    using number_integer_t = NumberIntegerType;\n\n    /// @brief a type for a number (unsigned)\n    /// @sa https://json.nlohmann.me/api/basic_json/number_unsigned_t/\n    using number_unsigned_t = NumberUnsignedType;\n\n    /// @brief a type for a number (floating-point)\n    /// @sa https://json.nlohmann.me/api/basic_json/number_float_t/\n    using number_float_t = NumberFloatType;\n\n    /// @brief a type for a packed binary type\n    /// @sa https://json.nlohmann.me/api/basic_json/binary_t/\n    using binary_t = nlohmann::byte_container_with_subtype<BinaryType>;\n\n    /// @brief object key comparator type\n    /// @sa https://json.nlohmann.me/api/basic_json/object_comparator_t/\n    using object_comparator_t = detail::actual_object_comparator_t<basic_json>;\n\n    /// @}\n\n  private:\n\n    /// helper for exception-safe object creation\n    template<typename T, typename... Args>\n    JSON_HEDLEY_RETURNS_NON_NULL\n    static T* create(Args&& ... args)\n    {\n        AllocatorType<T> alloc;\n        using AllocatorTraits = std::allocator_traits<AllocatorType<T>>;\n\n        auto deleter = [&](T * obj)\n        {\n            AllocatorTraits::deallocate(alloc, obj, 1);\n        };\n        std::unique_ptr<T, decltype(deleter)> obj(AllocatorTraits::allocate(alloc, 1), deleter);\n        AllocatorTraits::construct(alloc, obj.get(), std::forward<Args>(args)...);\n        JSON_ASSERT(obj != nullptr);\n        return obj.release();\n    }\n\n    ////////////////////////\n    // JSON value storage //\n    ////////////////////////\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    /*!\n    @brief a JSON value\n\n    The actual storage for a JSON value of the @ref basic_json class. This\n    union combines the different storage types for the JSON value types\n    defined in @ref value_t.\n\n    JSON type | value_t type    | used type\n    --------- | --------------- | ------------------------\n    object    | object          | pointer to @ref object_t\n    array     | array           | pointer to @ref array_t\n    string    | string          | pointer to @ref string_t\n    boolean   | boolean         | @ref boolean_t\n    number    | number_integer  | @ref number_integer_t\n    number    | number_unsigned | @ref number_unsigned_t\n    number    | number_float    | @ref number_float_t\n    binary    | binary          | pointer to @ref binary_t\n    null      | null            | *no value is stored*\n\n    @note Variable-length types (objects, arrays, and strings) are stored as\n    pointers. The size of the union should not exceed 64 bits if the default\n    value types are used.\n\n    @since version 1.0.0\n    */\n    union json_value\n    {\n        /// object (stored with pointer to save storage)\n        object_t* object;\n        /// array (stored with pointer to save storage)\n        array_t* array;\n        /// string (stored with pointer to save storage)\n        string_t* string;\n        /// binary (stored with pointer to save storage)\n        binary_t* binary;\n        /// boolean\n        boolean_t boolean;\n        /// number (integer)\n        number_integer_t number_integer;\n        /// number (unsigned integer)\n        number_unsigned_t number_unsigned;\n        /// number (floating-point)\n        number_float_t number_float;\n\n        /// default constructor (for null values)\n        json_value() = default;\n        /// constructor for booleans\n        json_value(boolean_t v) noexcept : boolean(v) {}\n        /// constructor for numbers (integer)\n        json_value(number_integer_t v) noexcept : number_integer(v) {}\n        /// constructor for numbers (unsigned)\n        json_value(number_unsigned_t v) noexcept : number_unsigned(v) {}\n        /// constructor for numbers (floating-point)\n        json_value(number_float_t v) noexcept : number_float(v) {}\n        /// constructor for empty values of a given type\n        json_value(value_t t)\n        {\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    object = create<object_t>();\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    array = create<array_t>();\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    string = create<string_t>(\"\");\n                    break;\n                }\n\n                case value_t::binary:\n                {\n                    binary = create<binary_t>();\n                    break;\n                }\n\n                case value_t::boolean:\n                {\n                    boolean = static_cast<boolean_t>(false);\n                    break;\n                }\n\n                case value_t::number_integer:\n                {\n                    number_integer = static_cast<number_integer_t>(0);\n                    break;\n                }\n\n                case value_t::number_unsigned:\n                {\n                    number_unsigned = static_cast<number_unsigned_t>(0);\n                    break;\n                }\n\n                case value_t::number_float:\n                {\n                    number_float = static_cast<number_float_t>(0.0);\n                    break;\n                }\n\n                case value_t::null:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    break;\n                }\n\n                case value_t::discarded:\n                default:\n                {\n                    object = nullptr;  // silence warning, see #821\n                    if (JSON_HEDLEY_UNLIKELY(t == value_t::null))\n                    {\n                        JSON_THROW(other_error::create(500, \"961c151d2e87f2686a955a9be24d316f1362bf21 3.12.0\", nullptr)); // LCOV_EXCL_LINE\n                    }\n                    break;\n                }\n            }\n        }\n\n        /// constructor for strings\n        json_value(const string_t& value) : string(create<string_t>(value)) {}\n\n        /// constructor for rvalue strings\n        json_value(string_t&& value) : string(create<string_t>(std::move(value))) {}\n\n        /// constructor for objects\n        json_value(const object_t& value) : object(create<object_t>(value)) {}\n\n        /// constructor for rvalue objects\n        json_value(object_t&& value) : object(create<object_t>(std::move(value))) {}\n\n        /// constructor for arrays\n        json_value(const array_t& value) : array(create<array_t>(value)) {}\n\n        /// constructor for rvalue arrays\n        json_value(array_t&& value) : array(create<array_t>(std::move(value))) {}\n\n        /// constructor for binary arrays\n        json_value(const typename binary_t::container_type& value) : binary(create<binary_t>(value)) {}\n\n        /// constructor for rvalue binary arrays\n        json_value(typename binary_t::container_type&& value) : binary(create<binary_t>(std::move(value))) {}\n\n        /// constructor for binary arrays (internal type)\n        json_value(const binary_t& value) : binary(create<binary_t>(value)) {}\n\n        /// constructor for rvalue binary arrays (internal type)\n        json_value(binary_t&& value) : binary(create<binary_t>(std::move(value))) {}\n\n        void destroy(value_t t)\n        {\n            if (\n                (t == value_t::object && object == nullptr) ||\n                (t == value_t::array && array == nullptr) ||\n                (t == value_t::string && string == nullptr) ||\n                (t == value_t::binary && binary == nullptr)\n            )\n            {\n                //not initialized (e.g. due to exception in the ctor)\n                return;\n            }\n            if (t == value_t::array || t == value_t::object)\n            {\n                // flatten the current json_value to a heap-allocated stack\n                std::vector<basic_json> stack;\n\n                // move the top-level items to stack\n                if (t == value_t::array)\n                {\n                    stack.reserve(array->size());\n                    std::move(array->begin(), array->end(), std::back_inserter(stack));\n                }\n                else\n                {\n                    stack.reserve(object->size());\n                    for (auto&& it : *object)\n                    {\n                        stack.push_back(std::move(it.second));\n                    }\n                }\n\n                while (!stack.empty())\n                {\n                    // move the last item to local variable to be processed\n                    basic_json current_item(std::move(stack.back()));\n                    stack.pop_back();\n\n                    // if current_item is array/object, move\n                    // its children to the stack to be processed later\n                    if (current_item.is_array())\n                    {\n                        std::move(current_item.m_data.m_value.array->begin(), current_item.m_data.m_value.array->end(), std::back_inserter(stack));\n\n                        current_item.m_data.m_value.array->clear();\n                    }\n                    else if (current_item.is_object())\n                    {\n                        for (auto&& it : *current_item.m_data.m_value.object)\n                        {\n                            stack.push_back(std::move(it.second));\n                        }\n\n                        current_item.m_data.m_value.object->clear();\n                    }\n\n                    // it's now safe that current_item get destructed\n                    // since it doesn't have any children\n                }\n            }\n\n            switch (t)\n            {\n                case value_t::object:\n                {\n                    AllocatorType<object_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, object);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, object, 1);\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    AllocatorType<array_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, array);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, array, 1);\n                    break;\n                }\n\n                case value_t::string:\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, string, 1);\n                    break;\n                }\n\n                case value_t::binary:\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, binary, 1);\n                    break;\n                }\n\n                case value_t::null:\n                case value_t::boolean:\n                case value_t::number_integer:\n                case value_t::number_unsigned:\n                case value_t::number_float:\n                case value_t::discarded:\n                default:\n                {\n                    break;\n                }\n            }\n        }\n    };\n\n  private:\n    /*!\n    @brief checks the class invariants\n\n    This function asserts the class invariants. It needs to be called at the\n    end of every constructor to make sure that created objects respect the\n    invariant. Furthermore, it has to be called each time the type of a JSON\n    value is changed, because the invariant expresses a relationship between\n    @a m_type and @a m_value.\n\n    Furthermore, the parent relation is checked for arrays and objects: If\n    @a check_parents true and the value is an array or object, then the\n    container's elements must have the current value as parent.\n\n    @param[in] check_parents  whether the parent relation should be checked.\n               The value is true by default and should only be set to false\n               during destruction of objects when the invariant does not\n               need to hold.\n    */\n    void assert_invariant(bool check_parents = true) const noexcept\n    {\n        JSON_ASSERT(m_data.m_type != value_t::object || m_data.m_value.object != nullptr);\n        JSON_ASSERT(m_data.m_type != value_t::array || m_data.m_value.array != nullptr);\n        JSON_ASSERT(m_data.m_type != value_t::string || m_data.m_value.string != nullptr);\n        JSON_ASSERT(m_data.m_type != value_t::binary || m_data.m_value.binary != nullptr);\n\n#if JSON_DIAGNOSTICS\n        JSON_TRY\n        {\n            // cppcheck-suppress assertWithSideEffect\n            JSON_ASSERT(!check_parents || !is_structured() || std::all_of(begin(), end(), [this](const basic_json & j)\n            {\n                return j.m_parent == this;\n            }));\n        }\n        JSON_CATCH(...) {} // LCOV_EXCL_LINE\n#endif\n        static_cast<void>(check_parents);\n    }\n\n    void set_parents()\n    {\n#if JSON_DIAGNOSTICS\n        switch (m_data.m_type)\n        {\n            case value_t::array:\n            {\n                for (auto& element : *m_data.m_value.array)\n                {\n                    element.m_parent = this;\n                }\n                break;\n            }\n\n            case value_t::object:\n            {\n                for (auto& element : *m_data.m_value.object)\n                {\n                    element.second.m_parent = this;\n                }\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                break;\n        }\n#endif\n    }\n\n    iterator set_parents(iterator it, typename iterator::difference_type count_set_parents)\n    {\n#if JSON_DIAGNOSTICS\n        for (typename iterator::difference_type i = 0; i < count_set_parents; ++i)\n        {\n            (it + i)->m_parent = this;\n        }\n#else\n        static_cast<void>(count_set_parents);\n#endif\n        return it;\n    }\n\n    reference set_parent(reference j, std::size_t old_capacity = detail::unknown_size())\n    {\n#if JSON_DIAGNOSTICS\n        if (old_capacity != detail::unknown_size())\n        {\n            // see https://github.com/nlohmann/json/issues/2838\n            JSON_ASSERT(type() == value_t::array);\n            if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))\n            {\n                // capacity has changed: update all parents\n                set_parents();\n                return j;\n            }\n        }\n\n        // ordered_json uses a vector internally, so pointers could have\n        // been invalidated; see https://github.com/nlohmann/json/issues/2962\n#ifdef JSON_HEDLEY_MSVC_VERSION\n#pragma warning(push )\n#pragma warning(disable : 4127) // ignore warning to replace if with if constexpr\n#endif\n        if (detail::is_ordered_map<object_t>::value)\n        {\n            set_parents();\n            return j;\n        }\n#ifdef JSON_HEDLEY_MSVC_VERSION\n#pragma warning( pop )\n#endif\n\n        j.m_parent = this;\n#else\n        static_cast<void>(j);\n        static_cast<void>(old_capacity);\n#endif\n        return j;\n    }\n\n  public:\n    //////////////////////////\n    // JSON parser callback //\n    //////////////////////////\n\n    /// @brief parser event types\n    /// @sa https://json.nlohmann.me/api/basic_json/parse_event_t/\n    using parse_event_t = detail::parse_event_t;\n\n    /// @brief per-element parser callback type\n    /// @sa https://json.nlohmann.me/api/basic_json/parser_callback_t/\n    using parser_callback_t = detail::parser_callback_t<basic_json>;\n\n    //////////////////\n    // constructors //\n    //////////////////\n\n    /// @name constructors and destructors\n    /// Constructors of class @ref basic_json, copy/move constructor, copy\n    /// assignment, static functions creating objects, and the destructor.\n    /// @{\n\n    /// @brief create an empty value with a given type\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    basic_json(const value_t v)\n        : m_data(v)\n    {\n        assert_invariant();\n    }\n\n    /// @brief create a null object\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    basic_json(std::nullptr_t = nullptr) noexcept // NOLINT(bugprone-exception-escape)\n        : basic_json(value_t::null)\n    {\n        assert_invariant();\n    }\n\n    /// @brief create a JSON value from compatible types\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    template < typename CompatibleType,\n               typename U = detail::uncvref_t<CompatibleType>,\n               detail::enable_if_t <\n                   !detail::is_basic_json<U>::value && detail::is_compatible_type<basic_json_t, U>::value, int > = 0 >\n    basic_json(CompatibleType && val) noexcept(noexcept( // NOLINT(bugprone-forwarding-reference-overload,bugprone-exception-escape)\n            JSONSerializer<U>::to_json(std::declval<basic_json_t&>(),\n                                       std::forward<CompatibleType>(val))))\n    {\n        JSONSerializer<U>::to_json(*this, std::forward<CompatibleType>(val));\n        set_parents();\n        assert_invariant();\n    }\n\n    /// @brief create a JSON value from an existing one\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    template < typename BasicJsonType,\n               detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value&& !std::is_same<basic_json, BasicJsonType>::value, int > = 0 >\n    basic_json(const BasicJsonType& val)\n#if JSON_DIAGNOSTIC_POSITIONS\n        : start_position(val.start_pos()),\n          end_position(val.end_pos())\n#endif\n    {\n        using other_boolean_t = typename BasicJsonType::boolean_t;\n        using other_number_float_t = typename BasicJsonType::number_float_t;\n        using other_number_integer_t = typename BasicJsonType::number_integer_t;\n        using other_number_unsigned_t = typename BasicJsonType::number_unsigned_t;\n        using other_string_t = typename BasicJsonType::string_t;\n        using other_object_t = typename BasicJsonType::object_t;\n        using other_array_t = typename BasicJsonType::array_t;\n        using other_binary_t = typename BasicJsonType::binary_t;\n\n        switch (val.type())\n        {\n            case value_t::boolean:\n                JSONSerializer<other_boolean_t>::to_json(*this, val.template get<other_boolean_t>());\n                break;\n            case value_t::number_float:\n                JSONSerializer<other_number_float_t>::to_json(*this, val.template get<other_number_float_t>());\n                break;\n            case value_t::number_integer:\n                JSONSerializer<other_number_integer_t>::to_json(*this, val.template get<other_number_integer_t>());\n                break;\n            case value_t::number_unsigned:\n                JSONSerializer<other_number_unsigned_t>::to_json(*this, val.template get<other_number_unsigned_t>());\n                break;\n            case value_t::string:\n                JSONSerializer<other_string_t>::to_json(*this, val.template get_ref<const other_string_t&>());\n                break;\n            case value_t::object:\n                JSONSerializer<other_object_t>::to_json(*this, val.template get_ref<const other_object_t&>());\n                break;\n            case value_t::array:\n                JSONSerializer<other_array_t>::to_json(*this, val.template get_ref<const other_array_t&>());\n                break;\n            case value_t::binary:\n                JSONSerializer<other_binary_t>::to_json(*this, val.template get_ref<const other_binary_t&>());\n                break;\n            case value_t::null:\n                *this = nullptr;\n                break;\n            case value_t::discarded:\n                m_data.m_type = value_t::discarded;\n                break;\n            default:            // LCOV_EXCL_LINE\n                JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n        }\n        JSON_ASSERT(m_data.m_type == val.type());\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /// @brief create a container (array or object) from an initializer list\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    basic_json(initializer_list_t init,\n               bool type_deduction = true,\n               value_t manual_type = value_t::array)\n    {\n        // check if each element is an array with two elements whose first\n        // element is a string\n        bool is_an_object = std::all_of(init.begin(), init.end(),\n                                        [](const detail::json_ref<basic_json>& element_ref)\n        {\n            // The cast is to ensure op[size_type] is called, bearing in mind size_type may not be int;\n            // (many string types can be constructed from 0 via its null-pointer guise, so we get a\n            // broken call to op[key_type], the wrong semantics and a 4804 warning on Windows)\n            return element_ref->is_array() && element_ref->size() == 2 && (*element_ref)[static_cast<size_type>(0)].is_string();\n        });\n\n        // adjust type if type deduction is not wanted\n        if (!type_deduction)\n        {\n            // if array is wanted, do not create an object though possible\n            if (manual_type == value_t::array)\n            {\n                is_an_object = false;\n            }\n\n            // if object is wanted but impossible, throw an exception\n            if (JSON_HEDLEY_UNLIKELY(manual_type == value_t::object && !is_an_object))\n            {\n                JSON_THROW(type_error::create(301, \"cannot create object from initializer list\", nullptr));\n            }\n        }\n\n        if (is_an_object)\n        {\n            // the initializer list is a list of pairs -> create object\n            m_data.m_type = value_t::object;\n            m_data.m_value = value_t::object;\n\n            for (auto& element_ref : init)\n            {\n                auto element = element_ref.moved_or_copied();\n                m_data.m_value.object->emplace(\n                    std::move(*((*element.m_data.m_value.array)[0].m_data.m_value.string)),\n                    std::move((*element.m_data.m_value.array)[1]));\n            }\n        }\n        else\n        {\n            // the initializer list describes an array -> create array\n            m_data.m_type = value_t::array;\n            m_data.m_value.array = create<array_t>(init.begin(), init.end());\n        }\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /// @brief explicitly create a binary array (without subtype)\n    /// @sa https://json.nlohmann.me/api/basic_json/binary/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(const typename binary_t::container_type& init)\n    {\n        auto res = basic_json();\n        res.m_data.m_type = value_t::binary;\n        res.m_data.m_value = init;\n        return res;\n    }\n\n    /// @brief explicitly create a binary array (with subtype)\n    /// @sa https://json.nlohmann.me/api/basic_json/binary/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)\n    {\n        auto res = basic_json();\n        res.m_data.m_type = value_t::binary;\n        res.m_data.m_value = binary_t(init, subtype);\n        return res;\n    }\n\n    /// @brief explicitly create a binary array\n    /// @sa https://json.nlohmann.me/api/basic_json/binary/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(typename binary_t::container_type&& init)\n    {\n        auto res = basic_json();\n        res.m_data.m_type = value_t::binary;\n        res.m_data.m_value = std::move(init);\n        return res;\n    }\n\n    /// @brief explicitly create a binary array (with subtype)\n    /// @sa https://json.nlohmann.me/api/basic_json/binary/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)\n    {\n        auto res = basic_json();\n        res.m_data.m_type = value_t::binary;\n        res.m_data.m_value = binary_t(std::move(init), subtype);\n        return res;\n    }\n\n    /// @brief explicitly create an array from an initializer list\n    /// @sa https://json.nlohmann.me/api/basic_json/array/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json array(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::array);\n    }\n\n    /// @brief explicitly create an object from an initializer list\n    /// @sa https://json.nlohmann.me/api/basic_json/object/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json object(initializer_list_t init = {})\n    {\n        return basic_json(init, false, value_t::object);\n    }\n\n    /// @brief construct an array with count copies of given value\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    basic_json(size_type cnt, const basic_json& val):\n        m_data{cnt, val}\n    {\n        set_parents();\n        assert_invariant();\n    }\n\n    /// @brief construct a JSON container given an iterator range\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    template < class InputIT, typename std::enable_if <\n                   std::is_same<InputIT, typename basic_json_t::iterator>::value ||\n                   std::is_same<InputIT, typename basic_json_t::const_iterator>::value, int >::type = 0 >\n    basic_json(InputIT first, InputIT last) // NOLINT(performance-unnecessary-value-param)\n    {\n        JSON_ASSERT(first.m_object != nullptr);\n        JSON_ASSERT(last.m_object != nullptr);\n\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(201, \"iterators are not compatible\", nullptr));\n        }\n\n        // copy type from first iterator\n        m_data.m_type = first.m_object->m_data.m_type;\n\n        // check if iterator range is complete for primitive values\n        switch (m_data.m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            {\n                if (JSON_HEDLEY_UNLIKELY(!first.m_it.primitive_iterator.is_begin()\n                                         || !last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\", first.m_object));\n                }\n                break;\n            }\n\n            case value_t::null:\n            case value_t::object:\n            case value_t::array:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n                break;\n        }\n\n        switch (m_data.m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_data.m_value.number_integer = first.m_object->m_data.m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_data.m_value.number_unsigned = first.m_object->m_data.m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_data.m_value.number_float = first.m_object->m_data.m_value.number_float;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_data.m_value.boolean = first.m_object->m_data.m_value.boolean;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_data.m_value = *first.m_object->m_data.m_value.string;\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_data.m_value.object = create<object_t>(first.m_it.object_iterator,\n                                        last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_data.m_value.array = create<array_t>(first.m_it.array_iterator,\n                                                       last.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_data.m_value = *first.m_object->m_data.m_value.binary;\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                JSON_THROW(invalid_iterator::create(206, detail::concat(\"cannot construct with iterators from \", first.m_object->type_name()), first.m_object));\n        }\n\n        set_parents();\n        assert_invariant();\n    }\n\n    ///////////////////////////////////////\n    // other constructors and destructor //\n    ///////////////////////////////////////\n\n    template<typename JsonRef,\n             detail::enable_if_t<detail::conjunction<detail::is_json_ref<JsonRef>,\n                                 std::is_same<typename JsonRef::value_type, basic_json>>::value, int> = 0 >\n    basic_json(const JsonRef& ref) : basic_json(ref.moved_or_copied()) {}\n\n    /// @brief copy constructor\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    basic_json(const basic_json& other)\n        : json_base_class_t(other)\n#if JSON_DIAGNOSTIC_POSITIONS\n        , start_position(other.start_position)\n        , end_position(other.end_position)\n#endif\n    {\n        m_data.m_type = other.m_data.m_type;\n        // check of passed value is valid\n        other.assert_invariant();\n\n        switch (m_data.m_type)\n        {\n            case value_t::object:\n            {\n                m_data.m_value = *other.m_data.m_value.object;\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_data.m_value = *other.m_data.m_value.array;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_data.m_value = *other.m_data.m_value.string;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_data.m_value = other.m_data.m_value.boolean;\n                break;\n            }\n\n            case value_t::number_integer:\n            {\n                m_data.m_value = other.m_data.m_value.number_integer;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_data.m_value = other.m_data.m_value.number_unsigned;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_data.m_value = other.m_data.m_value.number_float;\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_data.m_value = *other.m_data.m_value.binary;\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                break;\n        }\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /// @brief move constructor\n    /// @sa https://json.nlohmann.me/api/basic_json/basic_json/\n    basic_json(basic_json&& other) noexcept\n        : json_base_class_t(std::forward<json_base_class_t>(other)),\n          m_data(std::move(other.m_data)) // cppcheck-suppress[accessForwarded] TODO check\n#if JSON_DIAGNOSTIC_POSITIONS\n        , start_position(other.start_position) // cppcheck-suppress[accessForwarded] TODO check\n        , end_position(other.end_position) // cppcheck-suppress[accessForwarded] TODO check\n#endif\n    {\n        // check that passed value is valid\n        other.assert_invariant(false); // cppcheck-suppress[accessForwarded]\n\n        // invalidate payload\n        other.m_data.m_type = value_t::null;\n        other.m_data.m_value = {};\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        other.start_position = std::string::npos;\n        other.end_position = std::string::npos;\n#endif\n\n        set_parents();\n        assert_invariant();\n    }\n\n    /// @brief copy assignment\n    /// @sa https://json.nlohmann.me/api/basic_json/operator=/\n    basic_json& operator=(basic_json other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&&\n        std::is_nothrow_move_assignable<json_value>::value&&\n        std::is_nothrow_move_assignable<json_base_class_t>::value\n    )\n    {\n        // check that passed value is valid\n        other.assert_invariant();\n\n        using std::swap;\n        swap(m_data.m_type, other.m_data.m_type);\n        swap(m_data.m_value, other.m_data.m_value);\n\n#if JSON_DIAGNOSTIC_POSITIONS\n        swap(start_position, other.start_position);\n        swap(end_position, other.end_position);\n#endif\n\n        json_base_class_t::operator=(std::move(other));\n\n        set_parents();\n        assert_invariant();\n        return *this;\n    }\n\n    /// @brief destructor\n    /// @sa https://json.nlohmann.me/api/basic_json/~basic_json/\n    ~basic_json() noexcept\n    {\n        assert_invariant(false);\n    }\n\n    /// @}\n\n  public:\n    ///////////////////////\n    // object inspection //\n    ///////////////////////\n\n    /// @name object inspection\n    /// Functions to inspect the type of a JSON value.\n    /// @{\n\n    /// @brief serialization\n    /// @sa https://json.nlohmann.me/api/basic_json/dump/\n    string_t dump(const int indent = -1,\n                  const char indent_char = ' ',\n                  const bool ensure_ascii = false,\n                  const error_handler_t error_handler = error_handler_t::strict) const\n    {\n        string_t result;\n        serializer s(detail::output_adapter<char, string_t>(result), indent_char, error_handler);\n\n        if (indent >= 0)\n        {\n            s.dump(*this, true, ensure_ascii, static_cast<unsigned int>(indent));\n        }\n        else\n        {\n            s.dump(*this, false, ensure_ascii, 0);\n        }\n\n        return result;\n    }\n\n    /// @brief return the type of the JSON value (explicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/type/\n    constexpr value_t type() const noexcept\n    {\n        return m_data.m_type;\n    }\n\n    /// @brief return whether type is primitive\n    /// @sa https://json.nlohmann.me/api/basic_json/is_primitive/\n    constexpr bool is_primitive() const noexcept\n    {\n        return is_null() || is_string() || is_boolean() || is_number() || is_binary();\n    }\n\n    /// @brief return whether type is structured\n    /// @sa https://json.nlohmann.me/api/basic_json/is_structured/\n    constexpr bool is_structured() const noexcept\n    {\n        return is_array() || is_object();\n    }\n\n    /// @brief return whether value is null\n    /// @sa https://json.nlohmann.me/api/basic_json/is_null/\n    constexpr bool is_null() const noexcept\n    {\n        return m_data.m_type == value_t::null;\n    }\n\n    /// @brief return whether value is a boolean\n    /// @sa https://json.nlohmann.me/api/basic_json/is_boolean/\n    constexpr bool is_boolean() const noexcept\n    {\n        return m_data.m_type == value_t::boolean;\n    }\n\n    /// @brief return whether value is a number\n    /// @sa https://json.nlohmann.me/api/basic_json/is_number/\n    constexpr bool is_number() const noexcept\n    {\n        return is_number_integer() || is_number_float();\n    }\n\n    /// @brief return whether value is an integer number\n    /// @sa https://json.nlohmann.me/api/basic_json/is_number_integer/\n    constexpr bool is_number_integer() const noexcept\n    {\n        return m_data.m_type == value_t::number_integer || m_data.m_type == value_t::number_unsigned;\n    }\n\n    /// @brief return whether value is an unsigned integer number\n    /// @sa https://json.nlohmann.me/api/basic_json/is_number_unsigned/\n    constexpr bool is_number_unsigned() const noexcept\n    {\n        return m_data.m_type == value_t::number_unsigned;\n    }\n\n    /// @brief return whether value is a floating-point number\n    /// @sa https://json.nlohmann.me/api/basic_json/is_number_float/\n    constexpr bool is_number_float() const noexcept\n    {\n        return m_data.m_type == value_t::number_float;\n    }\n\n    /// @brief return whether value is an object\n    /// @sa https://json.nlohmann.me/api/basic_json/is_object/\n    constexpr bool is_object() const noexcept\n    {\n        return m_data.m_type == value_t::object;\n    }\n\n    /// @brief return whether value is an array\n    /// @sa https://json.nlohmann.me/api/basic_json/is_array/\n    constexpr bool is_array() const noexcept\n    {\n        return m_data.m_type == value_t::array;\n    }\n\n    /// @brief return whether value is a string\n    /// @sa https://json.nlohmann.me/api/basic_json/is_string/\n    constexpr bool is_string() const noexcept\n    {\n        return m_data.m_type == value_t::string;\n    }\n\n    /// @brief return whether value is a binary array\n    /// @sa https://json.nlohmann.me/api/basic_json/is_binary/\n    constexpr bool is_binary() const noexcept\n    {\n        return m_data.m_type == value_t::binary;\n    }\n\n    /// @brief return whether value is discarded\n    /// @sa https://json.nlohmann.me/api/basic_json/is_discarded/\n    constexpr bool is_discarded() const noexcept\n    {\n        return m_data.m_type == value_t::discarded;\n    }\n\n    /// @brief return the type of the JSON value (implicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_value_t/\n    constexpr operator value_t() const noexcept\n    {\n        return m_data.m_type;\n    }\n\n    /// @}\n\n  private:\n    //////////////////\n    // value access //\n    //////////////////\n\n    /// get a boolean (explicit)\n    boolean_t get_impl(boolean_t* /*unused*/) const\n    {\n        if (JSON_HEDLEY_LIKELY(is_boolean()))\n        {\n            return m_data.m_value.boolean;\n        }\n\n        JSON_THROW(type_error::create(302, detail::concat(\"type must be boolean, but is \", type_name()), this));\n    }\n\n    /// get a pointer to the value (object)\n    object_t* get_impl_ptr(object_t* /*unused*/) noexcept\n    {\n        return is_object() ? m_data.m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (object)\n    constexpr const object_t* get_impl_ptr(const object_t* /*unused*/) const noexcept\n    {\n        return is_object() ? m_data.m_value.object : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    array_t* get_impl_ptr(array_t* /*unused*/) noexcept\n    {\n        return is_array() ? m_data.m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (array)\n    constexpr const array_t* get_impl_ptr(const array_t* /*unused*/) const noexcept\n    {\n        return is_array() ? m_data.m_value.array : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    string_t* get_impl_ptr(string_t* /*unused*/) noexcept\n    {\n        return is_string() ? m_data.m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (string)\n    constexpr const string_t* get_impl_ptr(const string_t* /*unused*/) const noexcept\n    {\n        return is_string() ? m_data.m_value.string : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    boolean_t* get_impl_ptr(boolean_t* /*unused*/) noexcept\n    {\n        return is_boolean() ? &m_data.m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (boolean)\n    constexpr const boolean_t* get_impl_ptr(const boolean_t* /*unused*/) const noexcept\n    {\n        return is_boolean() ? &m_data.m_value.boolean : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    number_integer_t* get_impl_ptr(number_integer_t* /*unused*/) noexcept\n    {\n        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (integer number)\n    constexpr const number_integer_t* get_impl_ptr(const number_integer_t* /*unused*/) const noexcept\n    {\n        return m_data.m_type == value_t::number_integer ? &m_data.m_value.number_integer : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    number_unsigned_t* get_impl_ptr(number_unsigned_t* /*unused*/) noexcept\n    {\n        return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (unsigned number)\n    constexpr const number_unsigned_t* get_impl_ptr(const number_unsigned_t* /*unused*/) const noexcept\n    {\n        return is_number_unsigned() ? &m_data.m_value.number_unsigned : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    number_float_t* get_impl_ptr(number_float_t* /*unused*/) noexcept\n    {\n        return is_number_float() ? &m_data.m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (floating-point number)\n    constexpr const number_float_t* get_impl_ptr(const number_float_t* /*unused*/) const noexcept\n    {\n        return is_number_float() ? &m_data.m_value.number_float : nullptr;\n    }\n\n    /// get a pointer to the value (binary)\n    binary_t* get_impl_ptr(binary_t* /*unused*/) noexcept\n    {\n        return is_binary() ? m_data.m_value.binary : nullptr;\n    }\n\n    /// get a pointer to the value (binary)\n    constexpr const binary_t* get_impl_ptr(const binary_t* /*unused*/) const noexcept\n    {\n        return is_binary() ? m_data.m_value.binary : nullptr;\n    }\n\n    /*!\n    @brief helper function to implement get_ref()\n\n    This function helps to implement get_ref() without code duplication for\n    const and non-const overloads\n\n    @tparam ThisType will be deduced as `basic_json` or `const basic_json`\n\n    @throw type_error.303 if ReferenceType does not match underlying value\n    type of the current JSON\n    */\n    template<typename ReferenceType, typename ThisType>\n    static ReferenceType get_ref_impl(ThisType& obj)\n    {\n        // delegate the call to get_ptr<>()\n        auto* ptr = obj.template get_ptr<typename std::add_pointer<ReferenceType>::type>();\n\n        if (JSON_HEDLEY_LIKELY(ptr != nullptr))\n        {\n            return *ptr;\n        }\n\n        JSON_THROW(type_error::create(303, detail::concat(\"incompatible ReferenceType for get_ref, actual type is \", obj.type_name()), &obj));\n    }\n\n  public:\n    /// @name value access\n    /// Direct access to the stored value of a JSON value.\n    /// @{\n\n    /// @brief get a pointer value (implicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get_ptr() noexcept -> decltype(std::declval<basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>()\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n    /// @brief get a pointer value (implicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/get_ptr/\n    template < typename PointerType, typename std::enable_if <\n                   std::is_pointer<PointerType>::value&&\n                   std::is_const<typename std::remove_pointer<PointerType>::type>::value, int >::type = 0 >\n    constexpr auto get_ptr() const noexcept -> decltype(std::declval<const basic_json_t&>().get_impl_ptr(std::declval<PointerType>()))\n    {\n        // delegate the call to get_impl_ptr<>() const\n        return get_impl_ptr(static_cast<PointerType>(nullptr));\n    }\n\n  private:\n    /*!\n    @brief get a value (explicit)\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    ValueType ret;\n    JSONSerializer<ValueType>::from_json(*this, ret);\n    return ret;\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json,\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `void from_json(const basic_json&, ValueType&)`, and\n    - @ref json_serializer<ValueType> does not have a `from_json()` method of\n      the form `ValueType from_json(const basic_json&)`\n\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,get__ValueType_const}\n\n    @since version 2.1.0\n    */\n    template < typename ValueType,\n               detail::enable_if_t <\n                   detail::is_default_constructible<ValueType>::value&&\n                   detail::has_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType get_impl(detail::priority_tag<0> /*unused*/) const noexcept(noexcept(\n            JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), std::declval<ValueType&>())))\n    {\n        auto ret = ValueType();\n        JSONSerializer<ValueType>::from_json(*this, ret);\n        return ret;\n    }\n\n    /*!\n    @brief get a value (explicit); special case\n\n    Explicit type conversion between the JSON value and a compatible value\n    which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)\n    and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).\n    The value is converted by calling the @ref json_serializer<ValueType>\n    `from_json()` method.\n\n    The function is equivalent to executing\n    @code {.cpp}\n    return JSONSerializer<ValueType>::from_json(*this);\n    @endcode\n\n    This overloads is chosen if:\n    - @a ValueType is not @ref basic_json and\n    - @ref json_serializer<ValueType> has a `from_json()` method of the form\n      `ValueType from_json(const basic_json&)`\n\n    @note If @ref json_serializer<ValueType> has both overloads of\n    `from_json()`, this one is chosen.\n\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @a ValueType\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws\n\n    @since version 2.1.0\n    */\n    template < typename ValueType,\n               detail::enable_if_t <\n                   detail::has_non_default_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType get_impl(detail::priority_tag<1> /*unused*/) const noexcept(noexcept(\n            JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>())))\n    {\n        return JSONSerializer<ValueType>::from_json(*this);\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads converts the current @ref basic_json in a different\n    @ref basic_json type\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this, converted into @a BasicJsonType\n\n    @complexity Depending on the implementation of the called `from_json()`\n                method.\n\n    @since version 3.2.0\n    */\n    template < typename BasicJsonType,\n               detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value,\n                   int > = 0 >\n    BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get special-case overload\n\n    This overloads avoids a lot of template boilerplate, it can be seen as the\n    identity method\n\n    @tparam BasicJsonType == @ref basic_json\n\n    @return a copy of *this\n\n    @complexity Constant.\n\n    @since version 2.1.0\n    */\n    template<typename BasicJsonType,\n             detail::enable_if_t<\n                 std::is_same<BasicJsonType, basic_json_t>::value,\n                 int> = 0>\n    basic_json get_impl(detail::priority_tag<3> /*unused*/) const\n    {\n        return *this;\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n    @copydoc get()\n    */\n    template<typename PointerType,\n             detail::enable_if_t<\n                 std::is_pointer<PointerType>::value,\n                 int> = 0>\n    constexpr auto get_impl(detail::priority_tag<4> /*unused*/) const noexcept\n    -> decltype(std::declval<const basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n  public:\n    /*!\n    @brief get a (pointer) value (explicit)\n\n    Performs explicit type conversion between the JSON value and a compatible value if required.\n\n    - If the requested type is a pointer to the internally stored JSON value that pointer is returned.\n    No copies are made.\n\n    - If the requested type is the current @ref basic_json, or a different @ref basic_json convertible\n    from the current @ref basic_json.\n\n    - Otherwise the value is converted by calling the @ref json_serializer<ValueType> `from_json()`\n    method.\n\n    @tparam ValueTypeCV the provided value type\n    @tparam ValueType the returned value type\n\n    @return copy of the JSON value, converted to @tparam ValueType if necessary\n\n    @throw what @ref json_serializer<ValueType> `from_json()` method throws if conversion is required\n\n    @since version 2.1.0\n    */\n    template < typename ValueTypeCV, typename ValueType = detail::uncvref_t<ValueTypeCV>>\n#if defined(JSON_HAS_CPP_14)\n    constexpr\n#endif\n    auto get() const noexcept(\n    noexcept(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {})))\n    -> decltype(std::declval<const basic_json_t&>().template get_impl<ValueType>(detail::priority_tag<4> {}))\n    {\n        // we cannot static_assert on ValueTypeCV being non-const, because\n        // there is support for get<const basic_json_t>(), which is why we\n        // still need the uncvref\n        static_assert(!std::is_reference<ValueTypeCV>::value,\n                      \"get() cannot be used with reference types, you might want to use get_ref()\");\n        return get_impl<ValueType>(detail::priority_tag<4> {});\n    }\n\n    /*!\n    @brief get a pointer value (explicit)\n\n    Explicit pointer access to the internally stored JSON value. No copies are\n    made.\n\n    @warning The pointer becomes invalid if the underlying JSON object\n    changes.\n\n    @tparam PointerType pointer type; must be a pointer to @ref array_t, @ref\n    object_t, @ref string_t, @ref boolean_t, @ref number_integer_t,\n    @ref number_unsigned_t, or @ref number_float_t.\n\n    @return pointer to the internally stored JSON value if the requested\n    pointer type @a PointerType fits to the JSON value; `nullptr` otherwise\n\n    @complexity Constant.\n\n    @liveexample{The example below shows how pointers to internal values of a\n    JSON value can be requested. Note that no type conversions are made and a\n    `nullptr` is returned if the value and the requested pointer type does not\n    match.,get__PointerType}\n\n    @sa see @ref get_ptr() for explicit pointer-member access\n\n    @since version 1.0.0\n    */\n    template<typename PointerType, typename std::enable_if<\n                 std::is_pointer<PointerType>::value, int>::type = 0>\n    auto get() noexcept -> decltype(std::declval<basic_json_t&>().template get_ptr<PointerType>())\n    {\n        // delegate the call to get_ptr\n        return get_ptr<PointerType>();\n    }\n\n    /// @brief get a value (explicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/get_to/\n    template < typename ValueType,\n               detail::enable_if_t <\n                   !detail::is_basic_json<ValueType>::value&&\n                   detail::has_from_json<basic_json_t, ValueType>::value,\n                   int > = 0 >\n    ValueType & get_to(ValueType& v) const noexcept(noexcept(\n            JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<ValueType>::from_json(*this, v);\n        return v;\n    }\n\n    // specialization to allow calling get_to with a basic_json value\n    // see https://github.com/nlohmann/json/issues/2175\n    template<typename ValueType,\n             detail::enable_if_t <\n                 detail::is_basic_json<ValueType>::value,\n                 int> = 0>\n    ValueType & get_to(ValueType& v) const\n    {\n        v = *this;\n        return v;\n    }\n\n    template <\n        typename T, std::size_t N,\n        typename Array = T (&)[N], // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n        detail::enable_if_t <\n            detail::has_from_json<basic_json_t, Array>::value, int > = 0 >\n    Array get_to(T (&v)[N]) const // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)\n    noexcept(noexcept(JSONSerializer<Array>::from_json(\n                          std::declval<const basic_json_t&>(), v)))\n    {\n        JSONSerializer<Array>::from_json(*this, v);\n        return v;\n    }\n\n    /// @brief get a reference value (implicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/\n    template<typename ReferenceType, typename std::enable_if<\n                 std::is_reference<ReferenceType>::value, int>::type = 0>\n    ReferenceType get_ref()\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /// @brief get a reference value (implicit)\n    /// @sa https://json.nlohmann.me/api/basic_json/get_ref/\n    template < typename ReferenceType, typename std::enable_if <\n                   std::is_reference<ReferenceType>::value&&\n                   std::is_const<typename std::remove_reference<ReferenceType>::type>::value, int >::type = 0 >\n    ReferenceType get_ref() const\n    {\n        // delegate call to get_ref_impl\n        return get_ref_impl<ReferenceType>(*this);\n    }\n\n    /*!\n    @brief get a value (implicit)\n\n    Implicit type conversion between the JSON value and a compatible value.\n    The call is realized by calling @ref get() const.\n\n    @tparam ValueType non-pointer type compatible to the JSON value, for\n    instance `int` for JSON integer numbers, `bool` for JSON booleans, or\n    `std::vector` types for JSON arrays. The character type of @ref string_t\n    as well as an initializer list of this type is excluded to avoid\n    ambiguities as these types implicitly convert to `std::string`.\n\n    @return copy of the JSON value, converted to type @a ValueType\n\n    @throw type_error.302 in case passed type @a ValueType is incompatible\n    to the JSON value type (e.g., the JSON value is of type boolean, but a\n    string is requested); see example below\n\n    @complexity Linear in the size of the JSON value.\n\n    @liveexample{The example below shows several conversions from JSON values\n    to other types. There a few things to note: (1) Floating-point numbers can\n    be converted to integers\\, (2) A JSON array can be converted to a standard\n    `std::vector<short>`\\, (3) A JSON object can be converted to C++\n    associative containers such as `std::unordered_map<std::string\\,\n    json>`.,operator__ValueType}\n\n    @since version 1.0.0\n    */\n    template < typename ValueType, typename std::enable_if <\n                   detail::conjunction <\n                       detail::negation<std::is_pointer<ValueType>>,\n                       detail::negation<std::is_same<ValueType, std::nullptr_t>>,\n                       detail::negation<std::is_same<ValueType, detail::json_ref<basic_json>>>,\n                                        detail::negation<std::is_same<ValueType, typename string_t::value_type>>,\n                                        detail::negation<detail::is_basic_json<ValueType>>,\n                                        detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,\n#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))\n                                                detail::negation<std::is_same<ValueType, std::string_view>>,\n#endif\n#if defined(JSON_HAS_CPP_17) && JSON_HAS_STATIC_RTTI\n                                                detail::negation<std::is_same<ValueType, std::any>>,\n#endif\n                                                detail::is_detected_lazy<detail::get_template_function, const basic_json_t&, ValueType>\n                                                >::value, int >::type = 0 >\n                                        JSON_EXPLICIT operator ValueType() const\n    {\n        // delegate the call to get<>() const\n        return get<ValueType>();\n    }\n\n    /// @brief get a binary value\n    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/\n    binary_t& get_binary()\n    {\n        if (!is_binary())\n        {\n            JSON_THROW(type_error::create(302, detail::concat(\"type must be binary, but is \", type_name()), this));\n        }\n\n        return *get_ptr<binary_t*>();\n    }\n\n    /// @brief get a binary value\n    /// @sa https://json.nlohmann.me/api/basic_json/get_binary/\n    const binary_t& get_binary() const\n    {\n        if (!is_binary())\n        {\n            JSON_THROW(type_error::create(302, detail::concat(\"type must be binary, but is \", type_name()), this));\n        }\n\n        return *get_ptr<const binary_t*>();\n    }\n\n    /// @}\n\n    ////////////////////\n    // element access //\n    ////////////////////\n\n    /// @name element access\n    /// Access to the JSON value.\n    /// @{\n\n    /// @brief access specified array element with bounds checking\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    reference at(size_type idx)\n    {\n        // at only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return set_parent(m_data.m_value.array->at(idx));\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, detail::concat(\"array index \", std::to_string(idx), \" is out of range\"), this));\n            } // cppcheck-suppress[missingReturn]\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, detail::concat(\"cannot use at() with \", type_name()), this));\n        }\n    }\n\n    /// @brief access specified array element with bounds checking\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    const_reference at(size_type idx) const\n    {\n        // at only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            JSON_TRY\n            {\n                return m_data.m_value.array->at(idx);\n            }\n            JSON_CATCH (std::out_of_range&)\n            {\n                // create better exception explanation\n                JSON_THROW(out_of_range::create(401, detail::concat(\"array index \", std::to_string(idx), \" is out of range\"), this));\n            } // cppcheck-suppress[missingReturn]\n        }\n        else\n        {\n            JSON_THROW(type_error::create(304, detail::concat(\"cannot use at() with \", type_name()), this));\n        }\n    }\n\n    /// @brief access specified object element with bounds checking\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    reference at(const typename object_t::key_type& key)\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(304, detail::concat(\"cannot use at() with \", type_name()), this));\n        }\n\n        auto it = m_data.m_value.object->find(key);\n        if (it == m_data.m_value.object->end())\n        {\n            JSON_THROW(out_of_range::create(403, detail::concat(\"key '\", key, \"' not found\"), this));\n        }\n        return set_parent(it->second);\n    }\n\n    /// @brief access specified object element with bounds checking\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    reference at(KeyType && key)\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(304, detail::concat(\"cannot use at() with \", type_name()), this));\n        }\n\n        auto it = m_data.m_value.object->find(std::forward<KeyType>(key));\n        if (it == m_data.m_value.object->end())\n        {\n            JSON_THROW(out_of_range::create(403, detail::concat(\"key '\", string_t(std::forward<KeyType>(key)), \"' not found\"), this));\n        }\n        return set_parent(it->second);\n    }\n\n    /// @brief access specified object element with bounds checking\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    const_reference at(const typename object_t::key_type& key) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(304, detail::concat(\"cannot use at() with \", type_name()), this));\n        }\n\n        auto it = m_data.m_value.object->find(key);\n        if (it == m_data.m_value.object->end())\n        {\n            JSON_THROW(out_of_range::create(403, detail::concat(\"key '\", key, \"' not found\"), this));\n        }\n        return it->second;\n    }\n\n    /// @brief access specified object element with bounds checking\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    const_reference at(KeyType && key) const\n    {\n        // at only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(304, detail::concat(\"cannot use at() with \", type_name()), this));\n        }\n\n        auto it = m_data.m_value.object->find(std::forward<KeyType>(key));\n        if (it == m_data.m_value.object->end())\n        {\n            JSON_THROW(out_of_range::create(403, detail::concat(\"key '\", string_t(std::forward<KeyType>(key)), \"' not found\"), this));\n        }\n        return it->second;\n    }\n\n    /// @brief access specified array element\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    reference operator[](size_type idx)\n    {\n        // implicitly convert null value to an empty array\n        if (is_null())\n        {\n            m_data.m_type = value_t::array;\n            m_data.m_value.array = create<array_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // fill up array with null values if given idx is outside range\n            if (idx >= m_data.m_value.array->size())\n            {\n#if JSON_DIAGNOSTICS\n                // remember array size & capacity before resizing\n                const auto old_size = m_data.m_value.array->size();\n                const auto old_capacity = m_data.m_value.array->capacity();\n#endif\n                m_data.m_value.array->resize(idx + 1);\n\n#if JSON_DIAGNOSTICS\n                if (JSON_HEDLEY_UNLIKELY(m_data.m_value.array->capacity() != old_capacity))\n                {\n                    // capacity has changed: update all parents\n                    set_parents();\n                }\n                else\n                {\n                    // set parent for values added above\n                    set_parents(begin() + static_cast<typename iterator::difference_type>(old_size), static_cast<typename iterator::difference_type>(idx + 1 - old_size));\n                }\n#endif\n                assert_invariant();\n            }\n\n            return m_data.m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, detail::concat(\"cannot use operator[] with a numeric argument with \", type_name()), this));\n    }\n\n    /// @brief access specified array element\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    const_reference operator[](size_type idx) const\n    {\n        // const operator[] only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            return m_data.m_value.array->operator[](idx);\n        }\n\n        JSON_THROW(type_error::create(305, detail::concat(\"cannot use operator[] with a numeric argument with \", type_name()), this));\n    }\n\n    /// @brief access specified object element\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    reference operator[](typename object_t::key_type key) // NOLINT(performance-unnecessary-value-param)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_data.m_type = value_t::object;\n            m_data.m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            auto result = m_data.m_value.object->emplace(std::move(key), nullptr);\n            return set_parent(result.first->second);\n        }\n\n        JSON_THROW(type_error::create(305, detail::concat(\"cannot use operator[] with a string argument with \", type_name()), this));\n    }\n\n    /// @brief access specified object element\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    const_reference operator[](const typename object_t::key_type& key) const\n    {\n        // const operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            auto it = m_data.m_value.object->find(key);\n            JSON_ASSERT(it != m_data.m_value.object->end());\n            return it->second;\n        }\n\n        JSON_THROW(type_error::create(305, detail::concat(\"cannot use operator[] with a string argument with \", type_name()), this));\n    }\n\n    // these two functions resolve a (const) char * ambiguity affecting Clang and MSVC\n    // (they seemingly cannot be constrained to resolve the ambiguity)\n    template<typename T>\n    reference operator[](T* key)\n    {\n        return operator[](typename object_t::key_type(key));\n    }\n\n    template<typename T>\n    const_reference operator[](T* key) const\n    {\n        return operator[](typename object_t::key_type(key));\n    }\n\n    /// @brief access specified object element\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >\n    reference operator[](KeyType && key)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_data.m_type = value_t::object;\n            m_data.m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        // operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            auto result = m_data.m_value.object->emplace(std::forward<KeyType>(key), nullptr);\n            return set_parent(result.first->second);\n        }\n\n        JSON_THROW(type_error::create(305, detail::concat(\"cannot use operator[] with a string argument with \", type_name()), this));\n    }\n\n    /// @brief access specified object element\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int > = 0 >\n    const_reference operator[](KeyType && key) const\n    {\n        // const operator[] only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            auto it = m_data.m_value.object->find(std::forward<KeyType>(key));\n            JSON_ASSERT(it != m_data.m_value.object->end());\n            return it->second;\n        }\n\n        JSON_THROW(type_error::create(305, detail::concat(\"cannot use operator[] with a string argument with \", type_name()), this));\n    }\n\n  private:\n    template<typename KeyType>\n    using is_comparable_with_object_key = detail::is_comparable <\n        object_comparator_t, const typename object_t::key_type&, KeyType >;\n\n    template<typename ValueType>\n    using value_return_type = std::conditional <\n        detail::is_c_string_uncvref<ValueType>::value,\n        string_t, typename std::decay<ValueType>::type >;\n\n  public:\n    /// @brief access specified object element with default value\n    /// @sa https://json.nlohmann.me/api/basic_json/value/\n    template < class ValueType, detail::enable_if_t <\n                   !detail::is_transparent<object_comparator_t>::value\n                   && detail::is_getable<basic_json_t, ValueType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    ValueType value(const typename object_t::key_type& key, const ValueType& default_value) const\n    {\n        // value only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(key);\n            if (it != end())\n            {\n                return it->template get<ValueType>();\n            }\n\n            return default_value;\n        }\n\n        JSON_THROW(type_error::create(306, detail::concat(\"cannot use value() with \", type_name()), this));\n    }\n\n    /// @brief access specified object element with default value\n    /// @sa https://json.nlohmann.me/api/basic_json/value/\n    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,\n               detail::enable_if_t <\n                   !detail::is_transparent<object_comparator_t>::value\n                   && detail::is_getable<basic_json_t, ReturnType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    ReturnType value(const typename object_t::key_type& key, ValueType && default_value) const\n    {\n        // value only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(key);\n            if (it != end())\n            {\n                return it->template get<ReturnType>();\n            }\n\n            return std::forward<ValueType>(default_value);\n        }\n\n        JSON_THROW(type_error::create(306, detail::concat(\"cannot use value() with \", type_name()), this));\n    }\n\n    /// @brief access specified object element with default value\n    /// @sa https://json.nlohmann.me/api/basic_json/value/\n    template < class ValueType, class KeyType, detail::enable_if_t <\n                   detail::is_transparent<object_comparator_t>::value\n                   && !detail::is_json_pointer<KeyType>::value\n                   && is_comparable_with_object_key<KeyType>::value\n                   && detail::is_getable<basic_json_t, ValueType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    ValueType value(KeyType && key, const ValueType& default_value) const\n    {\n        // value only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(std::forward<KeyType>(key));\n            if (it != end())\n            {\n                return it->template get<ValueType>();\n            }\n\n            return default_value;\n        }\n\n        JSON_THROW(type_error::create(306, detail::concat(\"cannot use value() with \", type_name()), this));\n    }\n\n    /// @brief access specified object element via JSON Pointer with default value\n    /// @sa https://json.nlohmann.me/api/basic_json/value/\n    template < class ValueType, class KeyType, class ReturnType = typename value_return_type<ValueType>::type,\n               detail::enable_if_t <\n                   detail::is_transparent<object_comparator_t>::value\n                   && !detail::is_json_pointer<KeyType>::value\n                   && is_comparable_with_object_key<KeyType>::value\n                   && detail::is_getable<basic_json_t, ReturnType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    ReturnType value(KeyType && key, ValueType && default_value) const\n    {\n        // value only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if key is found, return value and given default value otherwise\n            const auto it = find(std::forward<KeyType>(key));\n            if (it != end())\n            {\n                return it->template get<ReturnType>();\n            }\n\n            return std::forward<ValueType>(default_value);\n        }\n\n        JSON_THROW(type_error::create(306, detail::concat(\"cannot use value() with \", type_name()), this));\n    }\n\n    /// @brief access specified object element via JSON Pointer with default value\n    /// @sa https://json.nlohmann.me/api/basic_json/value/\n    template < class ValueType, detail::enable_if_t <\n                   detail::is_getable<basic_json_t, ValueType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    ValueType value(const json_pointer& ptr, const ValueType& default_value) const\n    {\n        // value only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if pointer resolves a value, return it or use default value\n            JSON_TRY\n            {\n                return ptr.get_checked(this).template get<ValueType>();\n            }\n            JSON_INTERNAL_CATCH (out_of_range&)\n            {\n                return default_value;\n            }\n        }\n\n        JSON_THROW(type_error::create(306, detail::concat(\"cannot use value() with \", type_name()), this));\n    }\n\n    /// @brief access specified object element via JSON Pointer with default value\n    /// @sa https://json.nlohmann.me/api/basic_json/value/\n    template < class ValueType, class ReturnType = typename value_return_type<ValueType>::type,\n               detail::enable_if_t <\n                   detail::is_getable<basic_json_t, ReturnType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    ReturnType value(const json_pointer& ptr, ValueType && default_value) const\n    {\n        // value only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            // if pointer resolves a value, return it or use default value\n            JSON_TRY\n            {\n                return ptr.get_checked(this).template get<ReturnType>();\n            }\n            JSON_INTERNAL_CATCH (out_of_range&)\n            {\n                return std::forward<ValueType>(default_value);\n            }\n        }\n\n        JSON_THROW(type_error::create(306, detail::concat(\"cannot use value() with \", type_name()), this));\n    }\n\n    template < class ValueType, class BasicJsonType, detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value\n                   && detail::is_getable<basic_json_t, ValueType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    ValueType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, const ValueType& default_value) const\n    {\n        return value(ptr.convert(), default_value);\n    }\n\n    template < class ValueType, class BasicJsonType, class ReturnType = typename value_return_type<ValueType>::type,\n               detail::enable_if_t <\n                   detail::is_basic_json<BasicJsonType>::value\n                   && detail::is_getable<basic_json_t, ReturnType>::value\n                   && !std::is_same<value_t, detail::uncvref_t<ValueType>>::value, int > = 0 >\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    ReturnType value(const ::nlohmann::json_pointer<BasicJsonType>& ptr, ValueType && default_value) const\n    {\n        return value(ptr.convert(), std::forward<ValueType>(default_value));\n    }\n\n    /// @brief access the first element\n    /// @sa https://json.nlohmann.me/api/basic_json/front/\n    reference front()\n    {\n        return *begin();\n    }\n\n    /// @brief access the first element\n    /// @sa https://json.nlohmann.me/api/basic_json/front/\n    const_reference front() const\n    {\n        return *cbegin();\n    }\n\n    /// @brief access the last element\n    /// @sa https://json.nlohmann.me/api/basic_json/back/\n    reference back()\n    {\n        auto tmp = end();\n        --tmp;\n        return *tmp;\n    }\n\n    /// @brief access the last element\n    /// @sa https://json.nlohmann.me/api/basic_json/back/\n    const_reference back() const\n    {\n        auto tmp = cend();\n        --tmp;\n        return *tmp;\n    }\n\n    /// @brief remove element given an iterator\n    /// @sa https://json.nlohmann.me/api/basic_json/erase/\n    template < class IteratorType, detail::enable_if_t <\n                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||\n                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >\n    IteratorType erase(IteratorType pos) // NOLINT(performance-unnecessary-value-param)\n    {\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(this != pos.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", this));\n        }\n\n        IteratorType result = end();\n\n        switch (m_data.m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            case value_t::binary:\n            {\n                if (JSON_HEDLEY_UNLIKELY(!pos.m_it.primitive_iterator.is_begin()))\n                {\n                    JSON_THROW(invalid_iterator::create(205, \"iterator out of range\", this));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);\n                    m_data.m_value.string = nullptr;\n                }\n                else if (is_binary())\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);\n                    m_data.m_value.binary = nullptr;\n                }\n\n                m_data.m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_data.m_value.object->erase(pos.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_data.m_value.array->erase(pos.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                JSON_THROW(type_error::create(307, detail::concat(\"cannot use erase() with \", type_name()), this));\n        }\n\n        return result;\n    }\n\n    /// @brief remove elements given an iterator range\n    /// @sa https://json.nlohmann.me/api/basic_json/erase/\n    template < class IteratorType, detail::enable_if_t <\n                   std::is_same<IteratorType, typename basic_json_t::iterator>::value ||\n                   std::is_same<IteratorType, typename basic_json_t::const_iterator>::value, int > = 0 >\n    IteratorType erase(IteratorType first, IteratorType last) // NOLINT(performance-unnecessary-value-param)\n    {\n        // make sure iterator fits the current value\n        if (JSON_HEDLEY_UNLIKELY(this != first.m_object || this != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(203, \"iterators do not fit current value\", this));\n        }\n\n        IteratorType result = end();\n\n        switch (m_data.m_type)\n        {\n            case value_t::boolean:\n            case value_t::number_float:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::string:\n            case value_t::binary:\n            {\n                if (JSON_HEDLEY_LIKELY(!first.m_it.primitive_iterator.is_begin()\n                                       || !last.m_it.primitive_iterator.is_end()))\n                {\n                    JSON_THROW(invalid_iterator::create(204, \"iterators out of range\", this));\n                }\n\n                if (is_string())\n                {\n                    AllocatorType<string_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.string);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.string, 1);\n                    m_data.m_value.string = nullptr;\n                }\n                else if (is_binary())\n                {\n                    AllocatorType<binary_t> alloc;\n                    std::allocator_traits<decltype(alloc)>::destroy(alloc, m_data.m_value.binary);\n                    std::allocator_traits<decltype(alloc)>::deallocate(alloc, m_data.m_value.binary, 1);\n                    m_data.m_value.binary = nullptr;\n                }\n\n                m_data.m_type = value_t::null;\n                assert_invariant();\n                break;\n            }\n\n            case value_t::object:\n            {\n                result.m_it.object_iterator = m_data.m_value.object->erase(first.m_it.object_iterator,\n                                              last.m_it.object_iterator);\n                break;\n            }\n\n            case value_t::array:\n            {\n                result.m_it.array_iterator = m_data.m_value.array->erase(first.m_it.array_iterator,\n                                             last.m_it.array_iterator);\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                JSON_THROW(type_error::create(307, detail::concat(\"cannot use erase() with \", type_name()), this));\n        }\n\n        return result;\n    }\n\n  private:\n    template < typename KeyType, detail::enable_if_t <\n                   detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >\n    size_type erase_internal(KeyType && key)\n    {\n        // this erase only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(307, detail::concat(\"cannot use erase() with \", type_name()), this));\n        }\n\n        return m_data.m_value.object->erase(std::forward<KeyType>(key));\n    }\n\n    template < typename KeyType, detail::enable_if_t <\n                   !detail::has_erase_with_key_type<basic_json_t, KeyType>::value, int > = 0 >\n    size_type erase_internal(KeyType && key)\n    {\n        // this erase only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(307, detail::concat(\"cannot use erase() with \", type_name()), this));\n        }\n\n        const auto it = m_data.m_value.object->find(std::forward<KeyType>(key));\n        if (it != m_data.m_value.object->end())\n        {\n            m_data.m_value.object->erase(it);\n            return 1;\n        }\n        return 0;\n    }\n\n  public:\n\n    /// @brief remove element from a JSON object given a key\n    /// @sa https://json.nlohmann.me/api/basic_json/erase/\n    size_type erase(const typename object_t::key_type& key)\n    {\n        // the indirection via erase_internal() is added to avoid making this\n        // function a template and thus de-rank it during overload resolution\n        return erase_internal(key);\n    }\n\n    /// @brief remove element from a JSON object given a key\n    /// @sa https://json.nlohmann.me/api/basic_json/erase/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    size_type erase(KeyType && key)\n    {\n        return erase_internal(std::forward<KeyType>(key));\n    }\n\n    /// @brief remove element from a JSON array given an index\n    /// @sa https://json.nlohmann.me/api/basic_json/erase/\n    void erase(const size_type idx)\n    {\n        // this erase only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            if (JSON_HEDLEY_UNLIKELY(idx >= size()))\n            {\n                JSON_THROW(out_of_range::create(401, detail::concat(\"array index \", std::to_string(idx), \" is out of range\"), this));\n            }\n\n            m_data.m_value.array->erase(m_data.m_value.array->begin() + static_cast<difference_type>(idx));\n        }\n        else\n        {\n            JSON_THROW(type_error::create(307, detail::concat(\"cannot use erase() with \", type_name()), this));\n        }\n    }\n\n    /// @}\n\n    ////////////\n    // lookup //\n    ////////////\n\n    /// @name lookup\n    /// @{\n\n    /// @brief find an element in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/find/\n    iterator find(const typename object_t::key_type& key)\n    {\n        auto result = end();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_data.m_value.object->find(key);\n        }\n\n        return result;\n    }\n\n    /// @brief find an element in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/find/\n    const_iterator find(const typename object_t::key_type& key) const\n    {\n        auto result = cend();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_data.m_value.object->find(key);\n        }\n\n        return result;\n    }\n\n    /// @brief find an element in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/find/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    iterator find(KeyType && key)\n    {\n        auto result = end();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));\n        }\n\n        return result;\n    }\n\n    /// @brief find an element in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/find/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    const_iterator find(KeyType && key) const\n    {\n        auto result = cend();\n\n        if (is_object())\n        {\n            result.m_it.object_iterator = m_data.m_value.object->find(std::forward<KeyType>(key));\n        }\n\n        return result;\n    }\n\n    /// @brief returns the number of occurrences of a key in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/count/\n    size_type count(const typename object_t::key_type& key) const\n    {\n        // return 0 for all nonobject types\n        return is_object() ? m_data.m_value.object->count(key) : 0;\n    }\n\n    /// @brief returns the number of occurrences of a key in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/count/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    size_type count(KeyType && key) const\n    {\n        // return 0 for all nonobject types\n        return is_object() ? m_data.m_value.object->count(std::forward<KeyType>(key)) : 0;\n    }\n\n    /// @brief check the existence of an element in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/contains/\n    bool contains(const typename object_t::key_type& key) const\n    {\n        return is_object() && m_data.m_value.object->find(key) != m_data.m_value.object->end();\n    }\n\n    /// @brief check the existence of an element in a JSON object\n    /// @sa https://json.nlohmann.me/api/basic_json/contains/\n    template<class KeyType, detail::enable_if_t<\n                 detail::is_usable_as_basic_json_key_type<basic_json_t, KeyType>::value, int> = 0>\n    bool contains(KeyType && key) const\n    {\n        return is_object() && m_data.m_value.object->find(std::forward<KeyType>(key)) != m_data.m_value.object->end();\n    }\n\n    /// @brief check the existence of an element in a JSON object given a JSON pointer\n    /// @sa https://json.nlohmann.me/api/basic_json/contains/\n    bool contains(const json_pointer& ptr) const\n    {\n        return ptr.contains(this);\n    }\n\n    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    bool contains(const typename ::nlohmann::json_pointer<BasicJsonType>& ptr) const\n    {\n        return ptr.contains(this);\n    }\n\n    /// @}\n\n    ///////////////\n    // iterators //\n    ///////////////\n\n    /// @name iterators\n    /// @{\n\n    /// @brief returns an iterator to the first element\n    /// @sa https://json.nlohmann.me/api/basic_json/begin/\n    iterator begin() noexcept\n    {\n        iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /// @brief returns an iterator to the first element\n    /// @sa https://json.nlohmann.me/api/basic_json/begin/\n    const_iterator begin() const noexcept\n    {\n        return cbegin();\n    }\n\n    /// @brief returns a const iterator to the first element\n    /// @sa https://json.nlohmann.me/api/basic_json/cbegin/\n    const_iterator cbegin() const noexcept\n    {\n        const_iterator result(this);\n        result.set_begin();\n        return result;\n    }\n\n    /// @brief returns an iterator to one past the last element\n    /// @sa https://json.nlohmann.me/api/basic_json/end/\n    iterator end() noexcept\n    {\n        iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /// @brief returns an iterator to one past the last element\n    /// @sa https://json.nlohmann.me/api/basic_json/end/\n    const_iterator end() const noexcept\n    {\n        return cend();\n    }\n\n    /// @brief returns an iterator to one past the last element\n    /// @sa https://json.nlohmann.me/api/basic_json/cend/\n    const_iterator cend() const noexcept\n    {\n        const_iterator result(this);\n        result.set_end();\n        return result;\n    }\n\n    /// @brief returns an iterator to the reverse-beginning\n    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/\n    reverse_iterator rbegin() noexcept\n    {\n        return reverse_iterator(end());\n    }\n\n    /// @brief returns an iterator to the reverse-beginning\n    /// @sa https://json.nlohmann.me/api/basic_json/rbegin/\n    const_reverse_iterator rbegin() const noexcept\n    {\n        return crbegin();\n    }\n\n    /// @brief returns an iterator to the reverse-end\n    /// @sa https://json.nlohmann.me/api/basic_json/rend/\n    reverse_iterator rend() noexcept\n    {\n        return reverse_iterator(begin());\n    }\n\n    /// @brief returns an iterator to the reverse-end\n    /// @sa https://json.nlohmann.me/api/basic_json/rend/\n    const_reverse_iterator rend() const noexcept\n    {\n        return crend();\n    }\n\n    /// @brief returns a const reverse iterator to the last element\n    /// @sa https://json.nlohmann.me/api/basic_json/crbegin/\n    const_reverse_iterator crbegin() const noexcept\n    {\n        return const_reverse_iterator(cend());\n    }\n\n    /// @brief returns a const reverse iterator to one before the first\n    /// @sa https://json.nlohmann.me/api/basic_json/crend/\n    const_reverse_iterator crend() const noexcept\n    {\n        return const_reverse_iterator(cbegin());\n    }\n\n  public:\n    /// @brief wrapper to access iterator member functions in range-based for\n    /// @sa https://json.nlohmann.me/api/basic_json/items/\n    /// @deprecated This function is deprecated since 3.1.0 and will be removed in\n    ///             version 4.0.0 of the library. Please use @ref items() instead;\n    ///             that is, replace `json::iterator_wrapper(j)` with `j.items()`.\n    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())\n    static iteration_proxy<iterator> iterator_wrapper(reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /// @brief wrapper to access iterator member functions in range-based for\n    /// @sa https://json.nlohmann.me/api/basic_json/items/\n    /// @deprecated This function is deprecated since 3.1.0 and will be removed in\n    ///         version 4.0.0 of the library. Please use @ref items() instead;\n    ///         that is, replace `json::iterator_wrapper(j)` with `j.items()`.\n    JSON_HEDLEY_DEPRECATED_FOR(3.1.0, items())\n    static iteration_proxy<const_iterator> iterator_wrapper(const_reference ref) noexcept\n    {\n        return ref.items();\n    }\n\n    /// @brief helper to access iterator member functions in range-based for\n    /// @sa https://json.nlohmann.me/api/basic_json/items/\n    iteration_proxy<iterator> items() noexcept\n    {\n        return iteration_proxy<iterator>(*this);\n    }\n\n    /// @brief helper to access iterator member functions in range-based for\n    /// @sa https://json.nlohmann.me/api/basic_json/items/\n    iteration_proxy<const_iterator> items() const noexcept\n    {\n        return iteration_proxy<const_iterator>(*this);\n    }\n\n    /// @}\n\n    //////////////\n    // capacity //\n    //////////////\n\n    /// @name capacity\n    /// @{\n\n    /// @brief checks whether the container is empty.\n    /// @sa https://json.nlohmann.me/api/basic_json/empty/\n    bool empty() const noexcept\n    {\n        switch (m_data.m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return true;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::empty()\n                return m_data.m_value.array->empty();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::empty()\n                return m_data.m_value.object->empty();\n            }\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // all other types are nonempty\n                return false;\n            }\n        }\n    }\n\n    /// @brief returns the number of elements\n    /// @sa https://json.nlohmann.me/api/basic_json/size/\n    size_type size() const noexcept\n    {\n        switch (m_data.m_type)\n        {\n            case value_t::null:\n            {\n                // null values are empty\n                return 0;\n            }\n\n            case value_t::array:\n            {\n                // delegate call to array_t::size()\n                return m_data.m_value.array->size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::size()\n                return m_data.m_value.object->size();\n            }\n\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // all other types have size 1\n                return 1;\n            }\n        }\n    }\n\n    /// @brief returns the maximum possible number of elements\n    /// @sa https://json.nlohmann.me/api/basic_json/max_size/\n    size_type max_size() const noexcept\n    {\n        switch (m_data.m_type)\n        {\n            case value_t::array:\n            {\n                // delegate call to array_t::max_size()\n                return m_data.m_value.array->max_size();\n            }\n\n            case value_t::object:\n            {\n                // delegate call to object_t::max_size()\n                return m_data.m_value.object->max_size();\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // all other types have max_size() == size()\n                return size();\n            }\n        }\n    }\n\n    /// @}\n\n    ///////////////\n    // modifiers //\n    ///////////////\n\n    /// @name modifiers\n    /// @{\n\n    /// @brief clears the contents\n    /// @sa https://json.nlohmann.me/api/basic_json/clear/\n    void clear() noexcept\n    {\n        switch (m_data.m_type)\n        {\n            case value_t::number_integer:\n            {\n                m_data.m_value.number_integer = 0;\n                break;\n            }\n\n            case value_t::number_unsigned:\n            {\n                m_data.m_value.number_unsigned = 0;\n                break;\n            }\n\n            case value_t::number_float:\n            {\n                m_data.m_value.number_float = 0.0;\n                break;\n            }\n\n            case value_t::boolean:\n            {\n                m_data.m_value.boolean = false;\n                break;\n            }\n\n            case value_t::string:\n            {\n                m_data.m_value.string->clear();\n                break;\n            }\n\n            case value_t::binary:\n            {\n                m_data.m_value.binary->clear();\n                break;\n            }\n\n            case value_t::array:\n            {\n                m_data.m_value.array->clear();\n                break;\n            }\n\n            case value_t::object:\n            {\n                m_data.m_value.object->clear();\n                break;\n            }\n\n            case value_t::null:\n            case value_t::discarded:\n            default:\n                break;\n        }\n    }\n\n    /// @brief add an object to an array\n    /// @sa https://json.nlohmann.me/api/basic_json/push_back/\n    void push_back(basic_json&& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(308, detail::concat(\"cannot use push_back() with \", type_name()), this));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_data.m_type = value_t::array;\n            m_data.m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (move semantics)\n        const auto old_capacity = m_data.m_value.array->capacity();\n        m_data.m_value.array->push_back(std::move(val));\n        set_parent(m_data.m_value.array->back(), old_capacity);\n        // if val is moved from, basic_json move constructor marks it null, so we do not call the destructor\n    }\n\n    /// @brief add an object to an array\n    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/\n    reference operator+=(basic_json&& val)\n    {\n        push_back(std::move(val));\n        return *this;\n    }\n\n    /// @brief add an object to an array\n    /// @sa https://json.nlohmann.me/api/basic_json/push_back/\n    void push_back(const basic_json& val)\n    {\n        // push_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(308, detail::concat(\"cannot use push_back() with \", type_name()), this));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_data.m_type = value_t::array;\n            m_data.m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array\n        const auto old_capacity = m_data.m_value.array->capacity();\n        m_data.m_value.array->push_back(val);\n        set_parent(m_data.m_value.array->back(), old_capacity);\n    }\n\n    /// @brief add an object to an array\n    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/\n    reference operator+=(const basic_json& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /// @brief add an object to an object\n    /// @sa https://json.nlohmann.me/api/basic_json/push_back/\n    void push_back(const typename object_t::value_type& val)\n    {\n        // push_back only works for null objects or objects\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))\n        {\n            JSON_THROW(type_error::create(308, detail::concat(\"cannot use push_back() with \", type_name()), this));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_data.m_type = value_t::object;\n            m_data.m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to object\n        auto res = m_data.m_value.object->insert(val);\n        set_parent(res.first->second);\n    }\n\n    /// @brief add an object to an object\n    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/\n    reference operator+=(const typename object_t::value_type& val)\n    {\n        push_back(val);\n        return *this;\n    }\n\n    /// @brief add an object to an object\n    /// @sa https://json.nlohmann.me/api/basic_json/push_back/\n    void push_back(initializer_list_t init)\n    {\n        if (is_object() && init.size() == 2 && (*init.begin())->is_string())\n        {\n            basic_json&& key = init.begin()->moved_or_copied();\n            push_back(typename object_t::value_type(\n                          std::move(key.get_ref<string_t&>()), (init.begin() + 1)->moved_or_copied()));\n        }\n        else\n        {\n            push_back(basic_json(init));\n        }\n    }\n\n    /// @brief add an object to an object\n    /// @sa https://json.nlohmann.me/api/basic_json/operator+=/\n    reference operator+=(initializer_list_t init)\n    {\n        push_back(init);\n        return *this;\n    }\n\n    /// @brief add an object to an array\n    /// @sa https://json.nlohmann.me/api/basic_json/emplace_back/\n    template<class... Args>\n    reference emplace_back(Args&& ... args)\n    {\n        // emplace_back only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_array())))\n        {\n            JSON_THROW(type_error::create(311, detail::concat(\"cannot use emplace_back() with \", type_name()), this));\n        }\n\n        // transform null object into an array\n        if (is_null())\n        {\n            m_data.m_type = value_t::array;\n            m_data.m_value = value_t::array;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        const auto old_capacity = m_data.m_value.array->capacity();\n        m_data.m_value.array->emplace_back(std::forward<Args>(args)...);\n        return set_parent(m_data.m_value.array->back(), old_capacity);\n    }\n\n    /// @brief add an object to an object if key does not exist\n    /// @sa https://json.nlohmann.me/api/basic_json/emplace/\n    template<class... Args>\n    std::pair<iterator, bool> emplace(Args&& ... args)\n    {\n        // emplace only works for null objects or arrays\n        if (JSON_HEDLEY_UNLIKELY(!(is_null() || is_object())))\n        {\n            JSON_THROW(type_error::create(311, detail::concat(\"cannot use emplace() with \", type_name()), this));\n        }\n\n        // transform null object into an object\n        if (is_null())\n        {\n            m_data.m_type = value_t::object;\n            m_data.m_value = value_t::object;\n            assert_invariant();\n        }\n\n        // add element to array (perfect forwarding)\n        auto res = m_data.m_value.object->emplace(std::forward<Args>(args)...);\n        set_parent(res.first->second);\n\n        // create result iterator and set iterator to the result of emplace\n        auto it = begin();\n        it.m_it.object_iterator = res.first;\n\n        // return pair of iterator and boolean\n        return {it, res.second};\n    }\n\n    /// Helper for insertion of an iterator\n    /// @note: This uses std::distance to support GCC 4.8,\n    ///        see https://github.com/nlohmann/json/pull/1257\n    template<typename... Args>\n    iterator insert_iterator(const_iterator pos, Args&& ... args) // NOLINT(performance-unnecessary-value-param)\n    {\n        iterator result(this);\n        JSON_ASSERT(m_data.m_value.array != nullptr);\n\n        auto insert_pos = std::distance(m_data.m_value.array->begin(), pos.m_it.array_iterator);\n        m_data.m_value.array->insert(pos.m_it.array_iterator, std::forward<Args>(args)...);\n        result.m_it.array_iterator = m_data.m_value.array->begin() + insert_pos;\n\n        // This could have been written as:\n        // result.m_it.array_iterator = m_data.m_value.array->insert(pos.m_it.array_iterator, cnt, val);\n        // but the return value of insert is missing in GCC 4.8, so it is written this way instead.\n\n        set_parents();\n        return result;\n    }\n\n    /// @brief inserts element into array\n    /// @sa https://json.nlohmann.me/api/basic_json/insert/\n    iterator insert(const_iterator pos, const basic_json& val) // NOLINT(performance-unnecessary-value-param)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", this));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, val);\n        }\n\n        JSON_THROW(type_error::create(309, detail::concat(\"cannot use insert() with \", type_name()), this));\n    }\n\n    /// @brief inserts element into array\n    /// @sa https://json.nlohmann.me/api/basic_json/insert/\n    iterator insert(const_iterator pos, basic_json&& val) // NOLINT(performance-unnecessary-value-param)\n    {\n        return insert(pos, val);\n    }\n\n    /// @brief inserts copies of element into array\n    /// @sa https://json.nlohmann.me/api/basic_json/insert/\n    iterator insert(const_iterator pos, size_type cnt, const basic_json& val) // NOLINT(performance-unnecessary-value-param)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            // check if iterator pos fits to this JSON value\n            if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n            {\n                JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", this));\n            }\n\n            // insert to array and return iterator\n            return insert_iterator(pos, cnt, val);\n        }\n\n        JSON_THROW(type_error::create(309, detail::concat(\"cannot use insert() with \", type_name()), this));\n    }\n\n    /// @brief inserts range of elements into array\n    /// @sa https://json.nlohmann.me/api/basic_json/insert/\n    iterator insert(const_iterator pos, const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_UNLIKELY(!is_array()))\n        {\n            JSON_THROW(type_error::create(309, detail::concat(\"cannot use insert() with \", type_name()), this));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", this));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\", this));\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(first.m_object == this))\n        {\n            JSON_THROW(invalid_iterator::create(211, \"passed iterators may not belong to container\", this));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, first.m_it.array_iterator, last.m_it.array_iterator);\n    }\n\n    /// @brief inserts elements from initializer list into array\n    /// @sa https://json.nlohmann.me/api/basic_json/insert/\n    iterator insert(const_iterator pos, initializer_list_t ilist) // NOLINT(performance-unnecessary-value-param)\n    {\n        // insert only works for arrays\n        if (JSON_HEDLEY_UNLIKELY(!is_array()))\n        {\n            JSON_THROW(type_error::create(309, detail::concat(\"cannot use insert() with \", type_name()), this));\n        }\n\n        // check if iterator pos fits to this JSON value\n        if (JSON_HEDLEY_UNLIKELY(pos.m_object != this))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterator does not fit current value\", this));\n        }\n\n        // insert to array and return iterator\n        return insert_iterator(pos, ilist.begin(), ilist.end());\n    }\n\n    /// @brief inserts range of elements into object\n    /// @sa https://json.nlohmann.me/api/basic_json/insert/\n    void insert(const_iterator first, const_iterator last) // NOLINT(performance-unnecessary-value-param)\n    {\n        // insert only works for objects\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(309, detail::concat(\"cannot use insert() with \", type_name()), this));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\", this));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))\n        {\n            JSON_THROW(invalid_iterator::create(202, \"iterators first and last must point to objects\", this));\n        }\n\n        m_data.m_value.object->insert(first.m_it.object_iterator, last.m_it.object_iterator);\n        set_parents();\n    }\n\n    /// @brief updates a JSON object from another object, overwriting existing keys\n    /// @sa https://json.nlohmann.me/api/basic_json/update/\n    void update(const_reference j, bool merge_objects = false)\n    {\n        update(j.begin(), j.end(), merge_objects);\n    }\n\n    /// @brief updates a JSON object from another object, overwriting existing keys\n    /// @sa https://json.nlohmann.me/api/basic_json/update/\n    void update(const_iterator first, const_iterator last, bool merge_objects = false) // NOLINT(performance-unnecessary-value-param)\n    {\n        // implicitly convert null value to an empty object\n        if (is_null())\n        {\n            m_data.m_type = value_t::object;\n            m_data.m_value.object = create<object_t>();\n            assert_invariant();\n        }\n\n        if (JSON_HEDLEY_UNLIKELY(!is_object()))\n        {\n            JSON_THROW(type_error::create(312, detail::concat(\"cannot use update() with \", type_name()), this));\n        }\n\n        // check if range iterators belong to the same JSON object\n        if (JSON_HEDLEY_UNLIKELY(first.m_object != last.m_object))\n        {\n            JSON_THROW(invalid_iterator::create(210, \"iterators do not fit\", this));\n        }\n\n        // passed iterators must belong to objects\n        if (JSON_HEDLEY_UNLIKELY(!first.m_object->is_object()))\n        {\n            JSON_THROW(type_error::create(312, detail::concat(\"cannot use update() with \", first.m_object->type_name()), first.m_object));\n        }\n\n        for (auto it = first; it != last; ++it)\n        {\n            if (merge_objects && it.value().is_object())\n            {\n                auto it2 = m_data.m_value.object->find(it.key());\n                if (it2 != m_data.m_value.object->end())\n                {\n                    it2->second.update(it.value(), true);\n                    continue;\n                }\n            }\n            m_data.m_value.object->operator[](it.key()) = it.value();\n#if JSON_DIAGNOSTICS\n            m_data.m_value.object->operator[](it.key()).m_parent = this;\n#endif\n        }\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    void swap(reference other) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        std::swap(m_data.m_type, other.m_data.m_type);\n        std::swap(m_data.m_value, other.m_data.m_value);\n\n        set_parents();\n        other.set_parents();\n        assert_invariant();\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    friend void swap(reference left, reference right) noexcept (\n        std::is_nothrow_move_constructible<value_t>::value&&\n        std::is_nothrow_move_assignable<value_t>::value&&\n        std::is_nothrow_move_constructible<json_value>::value&& // NOLINT(cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n        std::is_nothrow_move_assignable<json_value>::value\n    )\n    {\n        left.swap(right);\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    void swap(array_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n    {\n        // swap only works for arrays\n        if (JSON_HEDLEY_LIKELY(is_array()))\n        {\n            using std::swap;\n            swap(*(m_data.m_value.array), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, detail::concat(\"cannot use swap(array_t&) with \", type_name()), this));\n        }\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    void swap(object_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n    {\n        // swap only works for objects\n        if (JSON_HEDLEY_LIKELY(is_object()))\n        {\n            using std::swap;\n            swap(*(m_data.m_value.object), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, detail::concat(\"cannot use swap(object_t&) with \", type_name()), this));\n        }\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    void swap(string_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_string()))\n        {\n            using std::swap;\n            swap(*(m_data.m_value.string), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, detail::concat(\"cannot use swap(string_t&) with \", type_name()), this));\n        }\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    void swap(binary_t& other) // NOLINT(bugprone-exception-escape,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_binary()))\n        {\n            using std::swap;\n            swap(*(m_data.m_value.binary), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, detail::concat(\"cannot use swap(binary_t&) with \", type_name()), this));\n        }\n    }\n\n    /// @brief exchanges the values\n    /// @sa https://json.nlohmann.me/api/basic_json/swap/\n    void swap(typename binary_t::container_type& other) // NOLINT(bugprone-exception-escape)\n    {\n        // swap only works for strings\n        if (JSON_HEDLEY_LIKELY(is_binary()))\n        {\n            using std::swap;\n            swap(*(m_data.m_value.binary), other);\n        }\n        else\n        {\n            JSON_THROW(type_error::create(310, detail::concat(\"cannot use swap(binary_t::container_type&) with \", type_name()), this));\n        }\n    }\n\n    /// @}\n\n    //////////////////////////////////////////\n    // lexicographical comparison operators //\n    //////////////////////////////////////////\n\n    /// @name lexicographical comparison operators\n    /// @{\n\n    // note parentheses around operands are necessary; see\n    // https://github.com/nlohmann/json/issues/1530\n#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result)                       \\\n    const auto lhs_type = lhs.type();                                                                    \\\n    const auto rhs_type = rhs.type();                                                                    \\\n    \\\n    if (lhs_type == rhs_type) /* NOLINT(readability/braces) */                                           \\\n    {                                                                                                    \\\n        switch (lhs_type)                                                                                \\\n        {                                                                                                \\\n            case value_t::array:                                                                         \\\n                return (*lhs.m_data.m_value.array) op (*rhs.m_data.m_value.array);                                     \\\n                \\\n            case value_t::object:                                                                        \\\n                return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object);                                   \\\n                \\\n            case value_t::null:                                                                          \\\n                return (null_result);                                                                    \\\n                \\\n            case value_t::string:                                                                        \\\n                return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string);                                   \\\n                \\\n            case value_t::boolean:                                                                       \\\n                return (lhs.m_data.m_value.boolean) op (rhs.m_data.m_value.boolean);                                   \\\n                \\\n            case value_t::number_integer:                                                                \\\n                return (lhs.m_data.m_value.number_integer) op (rhs.m_data.m_value.number_integer);                     \\\n                \\\n            case value_t::number_unsigned:                                                               \\\n                return (lhs.m_data.m_value.number_unsigned) op (rhs.m_data.m_value.number_unsigned);                   \\\n                \\\n            case value_t::number_float:                                                                  \\\n                return (lhs.m_data.m_value.number_float) op (rhs.m_data.m_value.number_float);                         \\\n                \\\n            case value_t::binary:                                                                        \\\n                return (*lhs.m_data.m_value.binary) op (*rhs.m_data.m_value.binary);                                   \\\n                \\\n            case value_t::discarded:                                                                     \\\n            default:                                                                                     \\\n                return (unordered_result);                                                               \\\n        }                                                                                                \\\n    }                                                                                                    \\\n    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)                   \\\n    {                                                                                                    \\\n        return static_cast<number_float_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_float;      \\\n    }                                                                                                    \\\n    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)                   \\\n    {                                                                                                    \\\n        return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_integer);      \\\n    }                                                                                                    \\\n    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)                  \\\n    {                                                                                                    \\\n        return static_cast<number_float_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_float;     \\\n    }                                                                                                    \\\n    else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)                  \\\n    {                                                                                                    \\\n        return lhs.m_data.m_value.number_float op static_cast<number_float_t>(rhs.m_data.m_value.number_unsigned);     \\\n    }                                                                                                    \\\n    else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)                \\\n    {                                                                                                    \\\n        return static_cast<number_integer_t>(lhs.m_data.m_value.number_unsigned) op rhs.m_data.m_value.number_integer; \\\n    }                                                                                                    \\\n    else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)                \\\n    {                                                                                                    \\\n        return lhs.m_data.m_value.number_integer op static_cast<number_integer_t>(rhs.m_data.m_value.number_unsigned); \\\n    }                                                                                                    \\\n    else if(compares_unordered(lhs, rhs))\\\n    {\\\n        return (unordered_result);\\\n    }\\\n    \\\n    return (default_result);\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    // returns true if:\n    // - any operand is NaN and the other operand is of number type\n    // - any operand is discarded\n    // in legacy mode, discarded values are considered ordered if\n    // an operation is computed as an odd number of inverses of others\n    static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept\n    {\n        if ((lhs.is_number_float() && std::isnan(lhs.m_data.m_value.number_float) && rhs.is_number())\n                || (rhs.is_number_float() && std::isnan(rhs.m_data.m_value.number_float) && lhs.is_number()))\n        {\n            return true;\n        }\n#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n        return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;\n#else\n        static_cast<void>(inverse);\n        return lhs.is_discarded() || rhs.is_discarded();\n#endif\n    }\n\n  private:\n    bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept\n    {\n        return compares_unordered(*this, rhs, inverse);\n    }\n\n  public:\n#if JSON_HAS_THREE_WAY_COMPARISON\n    /// @brief comparison: equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/\n    bool operator==(const_reference rhs) const noexcept\n    {\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n        const_reference lhs = *this;\n        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n    }\n\n    /// @brief comparison: equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/\n    template<typename ScalarType>\n    requires std::is_scalar_v<ScalarType>\n    bool operator==(ScalarType rhs) const noexcept\n    {\n        return *this == basic_json(rhs);\n    }\n\n    /// @brief comparison: not equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/\n    bool operator!=(const_reference rhs) const noexcept\n    {\n        if (compares_unordered(rhs, true))\n        {\n            return false;\n        }\n        return !operator==(rhs);\n    }\n\n    /// @brief comparison: 3-way\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/\n    std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*\n    {\n        const_reference lhs = *this;\n        // default_result is used if we cannot compare values. In that case,\n        // we compare types.\n        JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*\n                                std::partial_ordering::equivalent,\n                                std::partial_ordering::unordered,\n                                lhs_type <=> rhs_type) // *NOPAD*\n    }\n\n    /// @brief comparison: 3-way\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/\n    template<typename ScalarType>\n    requires std::is_scalar_v<ScalarType>\n    std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*\n    {\n        return *this <=> basic_json(rhs); // *NOPAD*\n    }\n\n#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n    // all operators that are computed as an odd number of inverses of others\n    // need to be overloaded to emulate the legacy comparison behavior\n\n    /// @brief comparison: less than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)\n    bool operator<=(const_reference rhs) const noexcept\n    {\n        if (compares_unordered(rhs, true))\n        {\n            return false;\n        }\n        return !(rhs < *this);\n    }\n\n    /// @brief comparison: less than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/\n    template<typename ScalarType>\n    requires std::is_scalar_v<ScalarType>\n    bool operator<=(ScalarType rhs) const noexcept\n    {\n        return *this <= basic_json(rhs);\n    }\n\n    /// @brief comparison: greater than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)\n    bool operator>=(const_reference rhs) const noexcept\n    {\n        if (compares_unordered(rhs, true))\n        {\n            return false;\n        }\n        return !(*this < rhs);\n    }\n\n    /// @brief comparison: greater than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/\n    template<typename ScalarType>\n    requires std::is_scalar_v<ScalarType>\n    bool operator>=(ScalarType rhs) const noexcept\n    {\n        return *this >= basic_json(rhs);\n    }\n#endif\n#else\n    /// @brief comparison: equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/\n    friend bool operator==(const_reference lhs, const_reference rhs) noexcept\n    {\n#ifdef __GNUC__\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wfloat-equal\"\n#endif\n        JSON_IMPLEMENT_OPERATOR( ==, true, false, false)\n#ifdef __GNUC__\n#pragma GCC diagnostic pop\n#endif\n    }\n\n    /// @brief comparison: equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs == basic_json(rhs);\n    }\n\n    /// @brief comparison: equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_eq/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator==(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) == rhs;\n    }\n\n    /// @brief comparison: not equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/\n    friend bool operator!=(const_reference lhs, const_reference rhs) noexcept\n    {\n        if (compares_unordered(lhs, rhs, true))\n        {\n            return false;\n        }\n        return !(lhs == rhs);\n    }\n\n    /// @brief comparison: not equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs != basic_json(rhs);\n    }\n\n    /// @brief comparison: not equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ne/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator!=(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) != rhs;\n    }\n\n    /// @brief comparison: less than\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/\n    friend bool operator<(const_reference lhs, const_reference rhs) noexcept\n    {\n        // default_result is used if we cannot compare values. In that case,\n        // we compare types. Note we have to call the operator explicitly,\n        // because MSVC has problems otherwise.\n        JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))\n    }\n\n    /// @brief comparison: less than\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs < basic_json(rhs);\n    }\n\n    /// @brief comparison: less than\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_lt/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) < rhs;\n    }\n\n    /// @brief comparison: less than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/\n    friend bool operator<=(const_reference lhs, const_reference rhs) noexcept\n    {\n        if (compares_unordered(lhs, rhs, true))\n        {\n            return false;\n        }\n        return !(rhs < lhs);\n    }\n\n    /// @brief comparison: less than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs <= basic_json(rhs);\n    }\n\n    /// @brief comparison: less than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_le/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator<=(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) <= rhs;\n    }\n\n    /// @brief comparison: greater than\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/\n    friend bool operator>(const_reference lhs, const_reference rhs) noexcept\n    {\n        // double inverse\n        if (compares_unordered(lhs, rhs))\n        {\n            return false;\n        }\n        return !(lhs <= rhs);\n    }\n\n    /// @brief comparison: greater than\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs > basic_json(rhs);\n    }\n\n    /// @brief comparison: greater than\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_gt/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) > rhs;\n    }\n\n    /// @brief comparison: greater than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/\n    friend bool operator>=(const_reference lhs, const_reference rhs) noexcept\n    {\n        if (compares_unordered(lhs, rhs, true))\n        {\n            return false;\n        }\n        return !(lhs < rhs);\n    }\n\n    /// @brief comparison: greater than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(const_reference lhs, ScalarType rhs) noexcept\n    {\n        return lhs >= basic_json(rhs);\n    }\n\n    /// @brief comparison: greater than or equal\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ge/\n    template<typename ScalarType, typename std::enable_if<\n                 std::is_scalar<ScalarType>::value, int>::type = 0>\n    friend bool operator>=(ScalarType lhs, const_reference rhs) noexcept\n    {\n        return basic_json(lhs) >= rhs;\n    }\n#endif\n\n#undef JSON_IMPLEMENT_OPERATOR\n\n    /// @}\n\n    ///////////////////\n    // serialization //\n    ///////////////////\n\n    /// @name serialization\n    /// @{\n#ifndef JSON_NO_IO\n    /// @brief serialize to stream\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/\n    friend std::ostream& operator<<(std::ostream& o, const basic_json& j)\n    {\n        // read width member and use it as indentation parameter if nonzero\n        const bool pretty_print = o.width() > 0;\n        const auto indentation = pretty_print ? o.width() : 0;\n\n        // reset width to 0 for subsequent calls to this stream\n        o.width(0);\n\n        // do the actual serialization\n        serializer s(detail::output_adapter<char>(o), o.fill());\n        s.dump(j, pretty_print, false, static_cast<unsigned int>(indentation));\n        return o;\n    }\n\n    /// @brief serialize to stream\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_ltlt/\n    /// @deprecated This function is deprecated since 3.0.0 and will be removed in\n    ///             version 4.0.0 of the library. Please use\n    ///             operator<<(std::ostream&, const basic_json&) instead; that is,\n    ///             replace calls like `j >> o;` with `o << j;`.\n    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator<<(std::ostream&, const basic_json&))\n    friend std::ostream& operator>>(const basic_json& j, std::ostream& o)\n    {\n        return o << j;\n    }\n#endif  // JSON_NO_IO\n    /// @}\n\n    /////////////////////\n    // deserialization //\n    /////////////////////\n\n    /// @name deserialization\n    /// @{\n\n    /// @brief deserialize from a compatible input\n    /// @sa https://json.nlohmann.me/api/basic_json/parse/\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json parse(InputType&& i,\n                            parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(detail::input_adapter(std::forward<InputType>(i)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved,accessForwarded]\n        return result;\n    }\n\n    /// @brief deserialize from a pair of character iterators\n    /// @sa https://json.nlohmann.me/api/basic_json/parse/\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json parse(IteratorType first,\n                            IteratorType last,\n                            parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(detail::input_adapter(std::move(first), std::move(last)), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]\n        return result;\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len))\n    static basic_json parse(detail::span_input_adapter&& i,\n                            parser_callback_t cb = nullptr,\n                            const bool allow_exceptions = true,\n                            const bool ignore_comments = false)\n    {\n        basic_json result;\n        parser(i.get(), std::move(cb), allow_exceptions, ignore_comments).parse(true, result); // cppcheck-suppress[accessMoved]\n        return result;\n    }\n\n    /// @brief check if the input is valid JSON\n    /// @sa https://json.nlohmann.me/api/basic_json/accept/\n    template<typename InputType>\n    static bool accept(InputType&& i,\n                       const bool ignore_comments = false)\n    {\n        return parser(detail::input_adapter(std::forward<InputType>(i)), nullptr, false, ignore_comments).accept(true);\n    }\n\n    /// @brief check if the input is valid JSON\n    /// @sa https://json.nlohmann.me/api/basic_json/accept/\n    template<typename IteratorType>\n    static bool accept(IteratorType first, IteratorType last,\n                       const bool ignore_comments = false)\n    {\n        return parser(detail::input_adapter(std::move(first), std::move(last)), nullptr, false, ignore_comments).accept(true);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len))\n    static bool accept(detail::span_input_adapter&& i,\n                       const bool ignore_comments = false)\n    {\n        return parser(i.get(), nullptr, false, ignore_comments).accept(true);\n    }\n\n    /// @brief generate SAX events\n    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/\n    template <typename InputType, typename SAX>\n    JSON_HEDLEY_NON_NULL(2)\n    static bool sax_parse(InputType&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);\n    }\n\n    /// @brief generate SAX events\n    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/\n    template<class IteratorType, class SAX>\n    JSON_HEDLEY_NON_NULL(3)\n    static bool sax_parse(IteratorType first, IteratorType last, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        return format == input_format_t::json\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);\n    }\n\n    /// @brief generate SAX events\n    /// @sa https://json.nlohmann.me/api/basic_json/sax_parse/\n    /// @deprecated This function is deprecated since 3.8.0 and will be removed in\n    ///             version 4.0.0 of the library. Please use\n    ///             sax_parse(ptr, ptr + len) instead.\n    template <typename SAX>\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...))\n    JSON_HEDLEY_NON_NULL(2)\n    static bool sax_parse(detail::span_input_adapter&& i, SAX* sax,\n                          input_format_t format = input_format_t::json,\n                          const bool strict = true,\n                          const bool ignore_comments = false)\n    {\n        auto ia = i.get();\n        return format == input_format_t::json\n               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n               ? parser(std::move(ia), nullptr, true, ignore_comments).sax_parse(sax, strict)\n               // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n               : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia), format).sax_parse(format, sax, strict);\n    }\n#ifndef JSON_NO_IO\n    /// @brief deserialize from stream\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/\n    /// @deprecated This stream operator is deprecated since 3.0.0 and will be removed in\n    ///             version 4.0.0 of the library. Please use\n    ///             operator>>(std::istream&, basic_json&) instead; that is,\n    ///             replace calls like `j << i;` with `i >> j;`.\n    JSON_HEDLEY_DEPRECATED_FOR(3.0.0, operator>>(std::istream&, basic_json&))\n    friend std::istream& operator<<(basic_json& j, std::istream& i)\n    {\n        return operator>>(i, j);\n    }\n\n    /// @brief deserialize from stream\n    /// @sa https://json.nlohmann.me/api/basic_json/operator_gtgt/\n    friend std::istream& operator>>(std::istream& i, basic_json& j)\n    {\n        parser(detail::input_adapter(i)).parse(false, j);\n        return i;\n    }\n#endif  // JSON_NO_IO\n    /// @}\n\n    ///////////////////////////\n    // convenience functions //\n    ///////////////////////////\n\n    /// @brief return the type as string\n    /// @sa https://json.nlohmann.me/api/basic_json/type_name/\n    JSON_HEDLEY_RETURNS_NON_NULL\n    const char* type_name() const noexcept\n    {\n        switch (m_data.m_type)\n        {\n            case value_t::null:\n                return \"null\";\n            case value_t::object:\n                return \"object\";\n            case value_t::array:\n                return \"array\";\n            case value_t::string:\n                return \"string\";\n            case value_t::boolean:\n                return \"boolean\";\n            case value_t::binary:\n                return \"binary\";\n            case value_t::discarded:\n                return \"discarded\";\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            default:\n                return \"number\";\n        }\n    }\n\n  JSON_PRIVATE_UNLESS_TESTED:\n    //////////////////////\n    // member variables //\n    //////////////////////\n\n    struct data\n    {\n        /// the type of the current element\n        value_t m_type = value_t::null;\n\n        /// the value of the current element\n        json_value m_value = {};\n\n        data(const value_t v)\n            : m_type(v), m_value(v)\n        {\n        }\n\n        data(size_type cnt, const basic_json& val)\n            : m_type(value_t::array)\n        {\n            m_value.array = create<array_t>(cnt, val);\n        }\n\n        data() noexcept = default;\n        data(data&&) noexcept = default;\n        data(const data&) noexcept = delete;\n        data& operator=(data&&) noexcept = delete;\n        data& operator=(const data&) noexcept = delete;\n\n        ~data() noexcept\n        {\n            m_value.destroy(m_type);\n        }\n    };\n\n    data m_data = {};\n\n#if JSON_DIAGNOSTICS\n    /// a pointer to a parent value (for debugging purposes)\n    basic_json* m_parent = nullptr;\n#endif\n\n#if JSON_DIAGNOSTIC_POSITIONS\n    /// the start position of the value\n    std::size_t start_position = std::string::npos;\n    /// the end position of the value\n    std::size_t end_position = std::string::npos;\n  public:\n    constexpr std::size_t start_pos() const noexcept\n    {\n        return start_position;\n    }\n\n    constexpr std::size_t end_pos() const noexcept\n    {\n        return end_position;\n    }\n#endif\n\n    //////////////////////////////////////////\n    // binary serialization/deserialization //\n    //////////////////////////////////////////\n\n    /// @name binary serialization/deserialization support\n    /// @{\n\n  public:\n    /// @brief create a CBOR serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/\n    static std::vector<std::uint8_t> to_cbor(const basic_json& j)\n    {\n        std::vector<std::uint8_t> result;\n        to_cbor(j, result);\n        return result;\n    }\n\n    /// @brief create a CBOR serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/\n    static void to_cbor(const basic_json& j, detail::output_adapter<std::uint8_t> o)\n    {\n        binary_writer<std::uint8_t>(o).write_cbor(j);\n    }\n\n    /// @brief create a CBOR serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_cbor/\n    static void to_cbor(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_cbor(j);\n    }\n\n    /// @brief create a MessagePack serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/\n    static std::vector<std::uint8_t> to_msgpack(const basic_json& j)\n    {\n        std::vector<std::uint8_t> result;\n        to_msgpack(j, result);\n        return result;\n    }\n\n    /// @brief create a MessagePack serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/\n    static void to_msgpack(const basic_json& j, detail::output_adapter<std::uint8_t> o)\n    {\n        binary_writer<std::uint8_t>(o).write_msgpack(j);\n    }\n\n    /// @brief create a MessagePack serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_msgpack/\n    static void to_msgpack(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_msgpack(j);\n    }\n\n    /// @brief create a UBJSON serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/\n    static std::vector<std::uint8_t> to_ubjson(const basic_json& j,\n            const bool use_size = false,\n            const bool use_type = false)\n    {\n        std::vector<std::uint8_t> result;\n        to_ubjson(j, result, use_size, use_type);\n        return result;\n    }\n\n    /// @brief create a UBJSON serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/\n    static void to_ubjson(const basic_json& j, detail::output_adapter<std::uint8_t> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type);\n    }\n\n    /// @brief create a UBJSON serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_ubjson/\n    static void to_ubjson(const basic_json& j, detail::output_adapter<char> o,\n                          const bool use_size = false, const bool use_type = false)\n    {\n        binary_writer<char>(o).write_ubjson(j, use_size, use_type);\n    }\n\n    /// @brief create a BJData serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/\n    static std::vector<std::uint8_t> to_bjdata(const basic_json& j,\n            const bool use_size = false,\n            const bool use_type = false,\n            const bjdata_version_t version = bjdata_version_t::draft2)\n    {\n        std::vector<std::uint8_t> result;\n        to_bjdata(j, result, use_size, use_type, version);\n        return result;\n    }\n\n    /// @brief create a BJData serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/\n    static void to_bjdata(const basic_json& j, detail::output_adapter<std::uint8_t> o,\n                          const bool use_size = false, const bool use_type = false,\n                          const bjdata_version_t version = bjdata_version_t::draft2)\n    {\n        binary_writer<std::uint8_t>(o).write_ubjson(j, use_size, use_type, true, true, version);\n    }\n\n    /// @brief create a BJData serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_bjdata/\n    static void to_bjdata(const basic_json& j, detail::output_adapter<char> o,\n                          const bool use_size = false, const bool use_type = false,\n                          const bjdata_version_t version = bjdata_version_t::draft2)\n    {\n        binary_writer<char>(o).write_ubjson(j, use_size, use_type, true, true, version);\n    }\n\n    /// @brief create a BSON serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/\n    static std::vector<std::uint8_t> to_bson(const basic_json& j)\n    {\n        std::vector<std::uint8_t> result;\n        to_bson(j, result);\n        return result;\n    }\n\n    /// @brief create a BSON serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/\n    static void to_bson(const basic_json& j, detail::output_adapter<std::uint8_t> o)\n    {\n        binary_writer<std::uint8_t>(o).write_bson(j);\n    }\n\n    /// @brief create a BSON serialization of a given JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/to_bson/\n    static void to_bson(const basic_json& j, detail::output_adapter<char> o)\n    {\n        binary_writer<char>(o).write_bson(j);\n    }\n\n    /// @brief create a JSON value from an input in CBOR format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_cbor(InputType&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in CBOR format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_cbor/\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_cbor(IteratorType first, IteratorType last,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))\n    static basic_json from_cbor(const T* ptr, std::size_t len,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        return from_cbor(ptr, ptr + len, strict, allow_exceptions, tag_handler);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len))\n    static basic_json from_cbor(detail::span_input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true,\n                                const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)\n    {\n        basic_json result;\n        auto ia = i.get();\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::cbor).sax_parse(input_format_t::cbor, &sdp, strict, tag_handler); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in MessagePack format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_msgpack(InputType&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in MessagePack format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_msgpack/\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_msgpack(IteratorType first, IteratorType last,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))\n    static basic_json from_msgpack(const T* ptr, std::size_t len,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        return from_msgpack(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len))\n    static basic_json from_msgpack(detail::span_input_adapter&& i,\n                                   const bool strict = true,\n                                   const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = i.get();\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::msgpack).sax_parse(input_format_t::msgpack, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in UBJSON format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_ubjson(InputType&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in UBJSON format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_ubjson/\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_ubjson(IteratorType first, IteratorType last,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))\n    static basic_json from_ubjson(const T* ptr, std::size_t len,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        return from_ubjson(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len))\n    static basic_json from_ubjson(detail::span_input_adapter&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = i.get();\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::ubjson).sax_parse(input_format_t::ubjson, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in BJData format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bjdata(InputType&& i,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in BJData format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_bjdata/\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bjdata(IteratorType first, IteratorType last,\n                                  const bool strict = true,\n                                  const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bjdata).sax_parse(input_format_t::bjdata, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in BSON format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/\n    template<typename InputType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bson(InputType&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::forward<InputType>(i));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    /// @brief create a JSON value from an input in BSON format\n    /// @sa https://json.nlohmann.me/api/basic_json/from_bson/\n    template<typename IteratorType>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json from_bson(IteratorType first, IteratorType last,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = detail::input_adapter(std::move(first), std::move(last));\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n\n    template<typename T>\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))\n    static basic_json from_bson(const T* ptr, std::size_t len,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        return from_bson(ptr, ptr + len, strict, allow_exceptions);\n    }\n\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len))\n    static basic_json from_bson(detail::span_input_adapter&& i,\n                                const bool strict = true,\n                                const bool allow_exceptions = true)\n    {\n        basic_json result;\n        auto ia = i.get();\n        detail::json_sax_dom_parser<basic_json, decltype(ia)> sdp(result, allow_exceptions);\n        // NOLINTNEXTLINE(hicpp-move-const-arg,performance-move-const-arg)\n        const bool res = binary_reader<decltype(ia)>(std::move(ia), input_format_t::bson).sax_parse(input_format_t::bson, &sdp, strict); // cppcheck-suppress[accessMoved]\n        return res ? result : basic_json(value_t::discarded);\n    }\n    /// @}\n\n    //////////////////////////\n    // JSON Pointer support //\n    //////////////////////////\n\n    /// @name JSON Pointer functions\n    /// @{\n\n    /// @brief access specified element via JSON Pointer\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    reference operator[](const json_pointer& ptr)\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr)\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /// @brief access specified element via JSON Pointer\n    /// @sa https://json.nlohmann.me/api/basic_json/operator%5B%5D/\n    const_reference operator[](const json_pointer& ptr) const\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    const_reference operator[](const ::nlohmann::json_pointer<BasicJsonType>& ptr) const\n    {\n        return ptr.get_unchecked(this);\n    }\n\n    /// @brief access specified element via JSON Pointer\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    reference at(const json_pointer& ptr)\n    {\n        return ptr.get_checked(this);\n    }\n\n    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr)\n    {\n        return ptr.get_checked(this);\n    }\n\n    /// @brief access specified element via JSON Pointer\n    /// @sa https://json.nlohmann.me/api/basic_json/at/\n    const_reference at(const json_pointer& ptr) const\n    {\n        return ptr.get_checked(this);\n    }\n\n    template<typename BasicJsonType, detail::enable_if_t<detail::is_basic_json<BasicJsonType>::value, int> = 0>\n    JSON_HEDLEY_DEPRECATED_FOR(3.11.0, basic_json::json_pointer or nlohmann::json_pointer<basic_json::string_t>) // NOLINT(readability/alt_tokens)\n    const_reference at(const ::nlohmann::json_pointer<BasicJsonType>& ptr) const\n    {\n        return ptr.get_checked(this);\n    }\n\n    /// @brief return flattened JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/flatten/\n    basic_json flatten() const\n    {\n        basic_json result(value_t::object);\n        json_pointer::flatten(\"\", *this, result);\n        return result;\n    }\n\n    /// @brief unflatten a previously flattened JSON value\n    /// @sa https://json.nlohmann.me/api/basic_json/unflatten/\n    basic_json unflatten() const\n    {\n        return json_pointer::unflatten(*this);\n    }\n\n    /// @}\n\n    //////////////////////////\n    // JSON Patch functions //\n    //////////////////////////\n\n    /// @name JSON Patch functions\n    /// @{\n\n    /// @brief applies a JSON patch in-place without copying the object\n    /// @sa https://json.nlohmann.me/api/basic_json/patch/\n    void patch_inplace(const basic_json& json_patch)\n    {\n        basic_json& result = *this;\n        // the valid JSON Patch operations\n        enum class patch_operations {add, remove, replace, move, copy, test, invalid};\n\n        const auto get_op = [](const string_t& op)\n        {\n            if (op == \"add\")\n            {\n                return patch_operations::add;\n            }\n            if (op == \"remove\")\n            {\n                return patch_operations::remove;\n            }\n            if (op == \"replace\")\n            {\n                return patch_operations::replace;\n            }\n            if (op == \"move\")\n            {\n                return patch_operations::move;\n            }\n            if (op == \"copy\")\n            {\n                return patch_operations::copy;\n            }\n            if (op == \"test\")\n            {\n                return patch_operations::test;\n            }\n\n            return patch_operations::invalid;\n        };\n\n        // wrapper for \"add\" operation; add value at ptr\n        const auto operation_add = [&result](json_pointer & ptr, const basic_json & val)\n        {\n            // adding to the root of the target document means replacing it\n            if (ptr.empty())\n            {\n                result = val;\n                return;\n            }\n\n            // make sure the top element of the pointer exists\n            json_pointer const top_pointer = ptr.top();\n            if (top_pointer != ptr)\n            {\n                result.at(top_pointer);\n            }\n\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.back();\n            ptr.pop_back();\n            // parent must exist when performing patch add per RFC6902 specs\n            basic_json& parent = result.at(ptr);\n\n            switch (parent.m_data.m_type)\n            {\n                case value_t::null:\n                case value_t::object:\n                {\n                    // use operator[] to add value\n                    parent[last_path] = val;\n                    break;\n                }\n\n                case value_t::array:\n                {\n                    if (last_path == \"-\")\n                    {\n                        // special case: append to back\n                        parent.push_back(val);\n                    }\n                    else\n                    {\n                        const auto idx = json_pointer::template array_index<basic_json_t>(last_path);\n                        if (JSON_HEDLEY_UNLIKELY(idx > parent.size()))\n                        {\n                            // avoid undefined behavior\n                            JSON_THROW(out_of_range::create(401, detail::concat(\"array index \", std::to_string(idx), \" is out of range\"), &parent));\n                        }\n\n                        // default case: insert add offset\n                        parent.insert(parent.begin() + static_cast<difference_type>(idx), val);\n                    }\n                    break;\n                }\n\n                // if there exists a parent it cannot be primitive\n                case value_t::string: // LCOV_EXCL_LINE\n                case value_t::boolean: // LCOV_EXCL_LINE\n                case value_t::number_integer: // LCOV_EXCL_LINE\n                case value_t::number_unsigned: // LCOV_EXCL_LINE\n                case value_t::number_float: // LCOV_EXCL_LINE\n                case value_t::binary: // LCOV_EXCL_LINE\n                case value_t::discarded: // LCOV_EXCL_LINE\n                default:            // LCOV_EXCL_LINE\n                    JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE\n            }\n        };\n\n        // wrapper for \"remove\" operation; remove value at ptr\n        const auto operation_remove = [this, & result](json_pointer & ptr)\n        {\n            // get reference to parent of JSON pointer ptr\n            const auto last_path = ptr.back();\n            ptr.pop_back();\n            basic_json& parent = result.at(ptr);\n\n            // remove child\n            if (parent.is_object())\n            {\n                // perform range check\n                auto it = parent.find(last_path);\n                if (JSON_HEDLEY_LIKELY(it != parent.end()))\n                {\n                    parent.erase(it);\n                }\n                else\n                {\n                    JSON_THROW(out_of_range::create(403, detail::concat(\"key '\", last_path, \"' not found\"), this));\n                }\n            }\n            else if (parent.is_array())\n            {\n                // note erase performs range check\n                parent.erase(json_pointer::template array_index<basic_json_t>(last_path));\n            }\n        };\n\n        // type check: top level value must be an array\n        if (JSON_HEDLEY_UNLIKELY(!json_patch.is_array()))\n        {\n            JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\", &json_patch));\n        }\n\n        // iterate and apply the operations\n        for (const auto& val : json_patch)\n        {\n            // wrapper to get a value for an operation\n            const auto get_value = [&val](const string_t& op,\n                                          const string_t& member,\n                                          bool string_type) -> basic_json &\n            {\n                // find value\n                auto it = val.m_data.m_value.object->find(member);\n\n                // context-sensitive error message\n                const auto error_msg = (op == \"op\") ? \"operation\" : detail::concat(\"operation '\", op, '\\''); // NOLINT(bugprone-unused-local-non-trivial-variable)\n\n                // check if desired value is present\n                if (JSON_HEDLEY_UNLIKELY(it == val.m_data.m_value.object->end()))\n                {\n                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)\n                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, \" must have member '\", member, \"'\"), &val));\n                }\n\n                // check if result is of type string\n                if (JSON_HEDLEY_UNLIKELY(string_type && !it->second.is_string()))\n                {\n                    // NOLINTNEXTLINE(performance-inefficient-string-concatenation)\n                    JSON_THROW(parse_error::create(105, 0, detail::concat(error_msg, \" must have string member '\", member, \"'\"), &val));\n                }\n\n                // no error: return value\n                return it->second;\n            };\n\n            // type check: every element of the array must be an object\n            if (JSON_HEDLEY_UNLIKELY(!val.is_object()))\n            {\n                JSON_THROW(parse_error::create(104, 0, \"JSON patch must be an array of objects\", &val));\n            }\n\n            // collect mandatory members\n            const auto op = get_value(\"op\", \"op\", true).template get<string_t>();\n            const auto path = get_value(op, \"path\", true).template get<string_t>();\n            json_pointer ptr(path);\n\n            switch (get_op(op))\n            {\n                case patch_operations::add:\n                {\n                    operation_add(ptr, get_value(\"add\", \"value\", false));\n                    break;\n                }\n\n                case patch_operations::remove:\n                {\n                    operation_remove(ptr);\n                    break;\n                }\n\n                case patch_operations::replace:\n                {\n                    // the \"path\" location must exist - use at()\n                    result.at(ptr) = get_value(\"replace\", \"value\", false);\n                    break;\n                }\n\n                case patch_operations::move:\n                {\n                    const auto from_path = get_value(\"move\", \"from\", true).template get<string_t>();\n                    json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json const v = result.at(from_ptr);\n\n                    // The move operation is functionally identical to a\n                    // \"remove\" operation on the \"from\" location, followed\n                    // immediately by an \"add\" operation at the target\n                    // location with the value that was just removed.\n                    operation_remove(from_ptr);\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::copy:\n                {\n                    const auto from_path = get_value(\"copy\", \"from\", true).template get<string_t>();\n                    const json_pointer from_ptr(from_path);\n\n                    // the \"from\" location must exist - use at()\n                    basic_json const v = result.at(from_ptr);\n\n                    // The copy is functionally identical to an \"add\"\n                    // operation at the target location using the value\n                    // specified in the \"from\" member.\n                    operation_add(ptr, v);\n                    break;\n                }\n\n                case patch_operations::test:\n                {\n                    bool success = false;\n                    JSON_TRY\n                    {\n                        // check if \"value\" matches the one at \"path\"\n                        // the \"path\" location must exist - use at()\n                        success = (result.at(ptr) == get_value(\"test\", \"value\", false));\n                    }\n                    JSON_INTERNAL_CATCH (out_of_range&)\n                    {\n                        // ignore out of range errors: success remains false\n                    }\n\n                    // throw an exception if test fails\n                    if (JSON_HEDLEY_UNLIKELY(!success))\n                    {\n                        JSON_THROW(other_error::create(501, detail::concat(\"unsuccessful: \", val.dump()), &val));\n                    }\n\n                    break;\n                }\n\n                case patch_operations::invalid:\n                default:\n                {\n                    // op must be \"add\", \"remove\", \"replace\", \"move\", \"copy\", or\n                    // \"test\"\n                    JSON_THROW(parse_error::create(105, 0, detail::concat(\"operation value '\", op, \"' is invalid\"), &val));\n                }\n            }\n        }\n    }\n\n    /// @brief applies a JSON patch to a copy of the current object\n    /// @sa https://json.nlohmann.me/api/basic_json/patch/\n    basic_json patch(const basic_json& json_patch) const\n    {\n        basic_json result = *this;\n        result.patch_inplace(json_patch);\n        return result;\n    }\n\n    /// @brief creates a diff as a JSON patch\n    /// @sa https://json.nlohmann.me/api/basic_json/diff/\n    JSON_HEDLEY_WARN_UNUSED_RESULT\n    static basic_json diff(const basic_json& source, const basic_json& target,\n                           const string_t& path = \"\")\n    {\n        // the patch\n        basic_json result(value_t::array);\n\n        // if the values are the same, return empty patch\n        if (source == target)\n        {\n            return result;\n        }\n\n        if (source.type() != target.type())\n        {\n            // different types: replace value\n            result.push_back(\n            {\n                {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n            });\n            return result;\n        }\n\n        switch (source.type())\n        {\n            case value_t::array:\n            {\n                // first pass: traverse common elements\n                std::size_t i = 0;\n                while (i < source.size() && i < target.size())\n                {\n                    // recursive call to compare array values at index i\n                    auto temp_diff = diff(source[i], target[i], detail::concat<string_t>(path, '/', detail::to_string<string_t>(i)));\n                    result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                    ++i;\n                }\n\n                // We now reached the end of at least one array\n                // in a second pass, traverse the remaining elements\n\n                // remove my remaining elements\n                const auto end_index = static_cast<difference_type>(result.size());\n                while (i < source.size())\n                {\n                    // add operations in reverse order to avoid invalid\n                    // indices\n                    result.insert(result.begin() + end_index, object(\n                    {\n                        {\"op\", \"remove\"},\n                        {\"path\", detail::concat<string_t>(path, '/', detail::to_string<string_t>(i))}\n                    }));\n                    ++i;\n                }\n\n                // add other remaining elements\n                while (i < target.size())\n                {\n                    result.push_back(\n                    {\n                        {\"op\", \"add\"},\n                        {\"path\", detail::concat<string_t>(path, \"/-\")},\n                        {\"value\", target[i]}\n                    });\n                    ++i;\n                }\n\n                break;\n            }\n\n            case value_t::object:\n            {\n                // first pass: traverse this object's elements\n                for (auto it = source.cbegin(); it != source.cend(); ++it)\n                {\n                    // escape the key name to be used in a JSON patch\n                    const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));\n\n                    if (target.find(it.key()) != target.end())\n                    {\n                        // recursive call to compare object values at key it\n                        auto temp_diff = diff(it.value(), target[it.key()], path_key);\n                        result.insert(result.end(), temp_diff.begin(), temp_diff.end());\n                    }\n                    else\n                    {\n                        // found a key that is not in o -> remove it\n                        result.push_back(object(\n                        {\n                            {\"op\", \"remove\"}, {\"path\", path_key}\n                        }));\n                    }\n                }\n\n                // second pass: traverse other object's elements\n                for (auto it = target.cbegin(); it != target.cend(); ++it)\n                {\n                    if (source.find(it.key()) == source.end())\n                    {\n                        // found a key that is not in this -> add it\n                        const auto path_key = detail::concat<string_t>(path, '/', detail::escape(it.key()));\n                        result.push_back(\n                        {\n                            {\"op\", \"add\"}, {\"path\", path_key},\n                            {\"value\", it.value()}\n                        });\n                    }\n                }\n\n                break;\n            }\n\n            case value_t::null:\n            case value_t::string:\n            case value_t::boolean:\n            case value_t::number_integer:\n            case value_t::number_unsigned:\n            case value_t::number_float:\n            case value_t::binary:\n            case value_t::discarded:\n            default:\n            {\n                // both primitive type: replace value\n                result.push_back(\n                {\n                    {\"op\", \"replace\"}, {\"path\", path}, {\"value\", target}\n                });\n                break;\n            }\n        }\n\n        return result;\n    }\n    /// @}\n\n    ////////////////////////////////\n    // JSON Merge Patch functions //\n    ////////////////////////////////\n\n    /// @name JSON Merge Patch functions\n    /// @{\n\n    /// @brief applies a JSON Merge Patch\n    /// @sa https://json.nlohmann.me/api/basic_json/merge_patch/\n    void merge_patch(const basic_json& apply_patch)\n    {\n        if (apply_patch.is_object())\n        {\n            if (!is_object())\n            {\n                *this = object();\n            }\n            for (auto it = apply_patch.begin(); it != apply_patch.end(); ++it)\n            {\n                if (it.value().is_null())\n                {\n                    erase(it.key());\n                }\n                else\n                {\n                    operator[](it.key()).merge_patch(it.value());\n                }\n            }\n        }\n        else\n        {\n            *this = apply_patch;\n        }\n    }\n\n    /// @}\n};\n\n/// @brief user-defined to_string function for JSON values\n/// @sa https://json.nlohmann.me/api/basic_json/to_string/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstd::string to_string(const NLOHMANN_BASIC_JSON_TPL& j)\n{\n    return j.dump();\n}\n\ninline namespace literals\n{\ninline namespace json_literals\n{\n\n/// @brief user-defined string literal for JSON values\n/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json/\nJSON_HEDLEY_NON_NULL(1)\n#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)\n    inline nlohmann::json operator \"\"_json(const char* s, std::size_t n)\n#else\n    inline nlohmann::json operator \"\" _json(const char* s, std::size_t n)\n#endif\n{\n    return nlohmann::json::parse(s, s + n);\n}\n\n/// @brief user-defined string literal for JSON pointer\n/// @sa https://json.nlohmann.me/api/basic_json/operator_literal_json_pointer/\nJSON_HEDLEY_NON_NULL(1)\n#if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)\n    inline nlohmann::json::json_pointer operator \"\"_json_pointer(const char* s, std::size_t n)\n#else\n    inline nlohmann::json::json_pointer operator \"\" _json_pointer(const char* s, std::size_t n)\n#endif\n{\n    return nlohmann::json::json_pointer(std::string(s, n));\n}\n\n}  // namespace json_literals\n}  // namespace literals\nNLOHMANN_JSON_NAMESPACE_END\n\n///////////////////////\n// nonmember support //\n///////////////////////\n\nnamespace std // NOLINT(cert-dcl58-cpp)\n{\n\n/// @brief hash value for JSON objects\n/// @sa https://json.nlohmann.me/api/basic_json/std_hash/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\nstruct hash<nlohmann::NLOHMANN_BASIC_JSON_TPL> // NOLINT(cert-dcl58-cpp)\n{\n    std::size_t operator()(const nlohmann::NLOHMANN_BASIC_JSON_TPL& j) const\n    {\n        return nlohmann::detail::hash(j);\n    }\n};\n\n// specialization for std::less<value_t>\ntemplate<>\nstruct less< ::nlohmann::detail::value_t> // do not remove the space after '<', see https://github.com/nlohmann/json/pull/679\n{\n    /*!\n    @brief compare two value_t enum values\n    @since version 3.0.0\n    */\n    bool operator()(::nlohmann::detail::value_t lhs,\n                    ::nlohmann::detail::value_t rhs) const noexcept\n    {\n#if JSON_HAS_THREE_WAY_COMPARISON\n        return std::is_lt(lhs <=> rhs); // *NOPAD*\n#else\n        return ::nlohmann::detail::operator<(lhs, rhs);\n#endif\n    }\n};\n\n// C++20 prohibit function specialization in the std namespace.\n#ifndef JSON_HAS_CPP_20\n\n/// @brief exchanges the values of two JSON objects\n/// @sa https://json.nlohmann.me/api/basic_json/std_swap/\nNLOHMANN_BASIC_JSON_TPL_DECLARATION\ninline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC_JSON_TPL& j2) noexcept(  // NOLINT(readability-inconsistent-declaration-parameter-name, cert-dcl58-cpp)\n    is_nothrow_move_constructible<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value&&                          // NOLINT(misc-redundant-expression,cppcoreguidelines-noexcept-swap,performance-noexcept-swap)\n    is_nothrow_move_assignable<nlohmann::NLOHMANN_BASIC_JSON_TPL>::value)\n{\n    j1.swap(j2);\n}\n\n#endif\n\n}  // namespace std\n\n#if JSON_USE_GLOBAL_UDLS\n    #if !defined(JSON_HEDLEY_GCC_VERSION) || JSON_HEDLEY_GCC_VERSION_CHECK(4,9,0)\n        using nlohmann::literals::json_literals::operator \"\"_json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)\n        using nlohmann::literals::json_literals::operator \"\"_json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)\n    #else\n        using nlohmann::literals::json_literals::operator \"\" _json; // NOLINT(misc-unused-using-decls,google-global-names-in-headers)\n        using nlohmann::literals::json_literals::operator \"\" _json_pointer; //NOLINT(misc-unused-using-decls,google-global-names-in-headers)\n    #endif\n#endif\n\n// #include <nlohmann/detail/macro_unscope.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// restore clang diagnostic settings\n#if defined(__clang__)\n    #pragma clang diagnostic pop\n#endif\n\n// clean up\n#undef JSON_ASSERT\n#undef JSON_INTERNAL_CATCH\n#undef JSON_THROW\n#undef JSON_PRIVATE_UNLESS_TESTED\n#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION\n#undef NLOHMANN_BASIC_JSON_TPL\n#undef JSON_EXPLICIT\n#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL\n#undef JSON_INLINE_VARIABLE\n#undef JSON_NO_UNIQUE_ADDRESS\n#undef JSON_DISABLE_ENUM_SERIALIZATION\n#undef JSON_USE_GLOBAL_UDLS\n\n#ifndef JSON_TEST_KEEP_MACROS\n    #undef JSON_CATCH\n    #undef JSON_TRY\n    #undef JSON_HAS_CPP_11\n    #undef JSON_HAS_CPP_14\n    #undef JSON_HAS_CPP_17\n    #undef JSON_HAS_CPP_20\n    #undef JSON_HAS_CPP_23\n    #undef JSON_HAS_FILESYSTEM\n    #undef JSON_HAS_EXPERIMENTAL_FILESYSTEM\n    #undef JSON_HAS_THREE_WAY_COMPARISON\n    #undef JSON_HAS_RANGES\n    #undef JSON_HAS_STATIC_RTTI\n    #undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n#endif\n\n// #include <nlohmann/thirdparty/hedley/hedley_undef.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n#undef JSON_HEDLEY_ALWAYS_INLINE\n#undef JSON_HEDLEY_ARM_VERSION\n#undef JSON_HEDLEY_ARM_VERSION_CHECK\n#undef JSON_HEDLEY_ARRAY_PARAM\n#undef JSON_HEDLEY_ASSUME\n#undef JSON_HEDLEY_BEGIN_C_DECLS\n#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_BUILTIN\n#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_DECLSPEC_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_CLANG_HAS_EXTENSION\n#undef JSON_HEDLEY_CLANG_HAS_FEATURE\n#undef JSON_HEDLEY_CLANG_HAS_WARNING\n#undef JSON_HEDLEY_COMPCERT_VERSION\n#undef JSON_HEDLEY_COMPCERT_VERSION_CHECK\n#undef JSON_HEDLEY_CONCAT\n#undef JSON_HEDLEY_CONCAT3\n#undef JSON_HEDLEY_CONCAT3_EX\n#undef JSON_HEDLEY_CONCAT_EX\n#undef JSON_HEDLEY_CONST\n#undef JSON_HEDLEY_CONSTEXPR\n#undef JSON_HEDLEY_CONST_CAST\n#undef JSON_HEDLEY_CPP_CAST\n#undef JSON_HEDLEY_CRAY_VERSION\n#undef JSON_HEDLEY_CRAY_VERSION_CHECK\n#undef JSON_HEDLEY_C_DECL\n#undef JSON_HEDLEY_DEPRECATED\n#undef JSON_HEDLEY_DEPRECATED_FOR\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS\n#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNUSED_FUNCTION\n#undef JSON_HEDLEY_DIAGNOSTIC_POP\n#undef JSON_HEDLEY_DIAGNOSTIC_PUSH\n#undef JSON_HEDLEY_DMC_VERSION\n#undef JSON_HEDLEY_DMC_VERSION_CHECK\n#undef JSON_HEDLEY_EMPTY_BASES\n#undef JSON_HEDLEY_EMSCRIPTEN_VERSION\n#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK\n#undef JSON_HEDLEY_END_C_DECLS\n#undef JSON_HEDLEY_FLAGS\n#undef JSON_HEDLEY_FLAGS_CAST\n#undef JSON_HEDLEY_GCC_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_BUILTIN\n#undef JSON_HEDLEY_GCC_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_GCC_HAS_EXTENSION\n#undef JSON_HEDLEY_GCC_HAS_FEATURE\n#undef JSON_HEDLEY_GCC_HAS_WARNING\n#undef JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK\n#undef JSON_HEDLEY_GCC_VERSION\n#undef JSON_HEDLEY_GCC_VERSION_CHECK\n#undef JSON_HEDLEY_GNUC_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_BUILTIN\n#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_GNUC_HAS_EXTENSION\n#undef JSON_HEDLEY_GNUC_HAS_FEATURE\n#undef JSON_HEDLEY_GNUC_HAS_WARNING\n#undef JSON_HEDLEY_GNUC_VERSION\n#undef JSON_HEDLEY_GNUC_VERSION_CHECK\n#undef JSON_HEDLEY_HAS_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_BUILTIN\n#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS\n#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE\n#undef JSON_HEDLEY_HAS_EXTENSION\n#undef JSON_HEDLEY_HAS_FEATURE\n#undef JSON_HEDLEY_HAS_WARNING\n#undef JSON_HEDLEY_IAR_VERSION\n#undef JSON_HEDLEY_IAR_VERSION_CHECK\n#undef JSON_HEDLEY_IBM_VERSION\n#undef JSON_HEDLEY_IBM_VERSION_CHECK\n#undef JSON_HEDLEY_IMPORT\n#undef JSON_HEDLEY_INLINE\n#undef JSON_HEDLEY_INTEL_CL_VERSION\n#undef JSON_HEDLEY_INTEL_CL_VERSION_CHECK\n#undef JSON_HEDLEY_INTEL_VERSION\n#undef JSON_HEDLEY_INTEL_VERSION_CHECK\n#undef JSON_HEDLEY_IS_CONSTANT\n#undef JSON_HEDLEY_IS_CONSTEXPR_\n#undef JSON_HEDLEY_LIKELY\n#undef JSON_HEDLEY_MALLOC\n#undef JSON_HEDLEY_MCST_LCC_VERSION\n#undef JSON_HEDLEY_MCST_LCC_VERSION_CHECK\n#undef JSON_HEDLEY_MESSAGE\n#undef JSON_HEDLEY_MSVC_VERSION\n#undef JSON_HEDLEY_MSVC_VERSION_CHECK\n#undef JSON_HEDLEY_NEVER_INLINE\n#undef JSON_HEDLEY_NON_NULL\n#undef JSON_HEDLEY_NO_ESCAPE\n#undef JSON_HEDLEY_NO_RETURN\n#undef JSON_HEDLEY_NO_THROW\n#undef JSON_HEDLEY_NULL\n#undef JSON_HEDLEY_PELLES_VERSION\n#undef JSON_HEDLEY_PELLES_VERSION_CHECK\n#undef JSON_HEDLEY_PGI_VERSION\n#undef JSON_HEDLEY_PGI_VERSION_CHECK\n#undef JSON_HEDLEY_PREDICT\n#undef JSON_HEDLEY_PRINTF_FORMAT\n#undef JSON_HEDLEY_PRIVATE\n#undef JSON_HEDLEY_PUBLIC\n#undef JSON_HEDLEY_PURE\n#undef JSON_HEDLEY_REINTERPRET_CAST\n#undef JSON_HEDLEY_REQUIRE\n#undef JSON_HEDLEY_REQUIRE_CONSTEXPR\n#undef JSON_HEDLEY_REQUIRE_MSG\n#undef JSON_HEDLEY_RESTRICT\n#undef JSON_HEDLEY_RETURNS_NON_NULL\n#undef JSON_HEDLEY_SENTINEL\n#undef JSON_HEDLEY_STATIC_ASSERT\n#undef JSON_HEDLEY_STATIC_CAST\n#undef JSON_HEDLEY_STRINGIFY\n#undef JSON_HEDLEY_STRINGIFY_EX\n#undef JSON_HEDLEY_SUNPRO_VERSION\n#undef JSON_HEDLEY_SUNPRO_VERSION_CHECK\n#undef JSON_HEDLEY_TINYC_VERSION\n#undef JSON_HEDLEY_TINYC_VERSION_CHECK\n#undef JSON_HEDLEY_TI_ARMCL_VERSION\n#undef JSON_HEDLEY_TI_ARMCL_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL2000_VERSION\n#undef JSON_HEDLEY_TI_CL2000_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL430_VERSION\n#undef JSON_HEDLEY_TI_CL430_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL6X_VERSION\n#undef JSON_HEDLEY_TI_CL6X_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CL7X_VERSION\n#undef JSON_HEDLEY_TI_CL7X_VERSION_CHECK\n#undef JSON_HEDLEY_TI_CLPRU_VERSION\n#undef JSON_HEDLEY_TI_CLPRU_VERSION_CHECK\n#undef JSON_HEDLEY_TI_VERSION\n#undef JSON_HEDLEY_TI_VERSION_CHECK\n#undef JSON_HEDLEY_UNAVAILABLE\n#undef JSON_HEDLEY_UNLIKELY\n#undef JSON_HEDLEY_UNPREDICTABLE\n#undef JSON_HEDLEY_UNREACHABLE\n#undef JSON_HEDLEY_UNREACHABLE_RETURN\n#undef JSON_HEDLEY_VERSION\n#undef JSON_HEDLEY_VERSION_DECODE_MAJOR\n#undef JSON_HEDLEY_VERSION_DECODE_MINOR\n#undef JSON_HEDLEY_VERSION_DECODE_REVISION\n#undef JSON_HEDLEY_VERSION_ENCODE\n#undef JSON_HEDLEY_WARNING\n#undef JSON_HEDLEY_WARN_UNUSED_RESULT\n#undef JSON_HEDLEY_WARN_UNUSED_RESULT_MSG\n#undef JSON_HEDLEY_FALL_THROUGH\n\n\n\n#endif  // INCLUDE_NLOHMANN_JSON_HPP_\n"
  },
  {
    "path": "lib/nlohmannjson/include/nlohmann/json_fwd.hpp",
    "content": "//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_\n#define INCLUDE_NLOHMANN_JSON_FWD_HPP_\n\n#include <cstdint> // int64_t, uint64_t\n#include <map> // map\n#include <memory> // allocator\n#include <string> // string\n#include <vector> // vector\n\n// #include <nlohmann/detail/abi_macros.hpp>\n//     __ _____ _____ _____\n//  __|  |   __|     |   | |  JSON for Modern C++\n// |  |  |__   |  |  | | | |  version 3.12.0\n// |_____|_____|_____|_|___|  https://github.com/nlohmann/json\n//\n// SPDX-FileCopyrightText: 2013 - 2025 Niels Lohmann <https://nlohmann.me>\n// SPDX-License-Identifier: MIT\n\n\n\n// This file contains all macro definitions affecting or depending on the ABI\n\n#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK\n    #if defined(NLOHMANN_JSON_VERSION_MAJOR) && defined(NLOHMANN_JSON_VERSION_MINOR) && defined(NLOHMANN_JSON_VERSION_PATCH)\n        #if NLOHMANN_JSON_VERSION_MAJOR != 3 || NLOHMANN_JSON_VERSION_MINOR != 12 || NLOHMANN_JSON_VERSION_PATCH != 0\n            #warning \"Already included a different version of the library!\"\n        #endif\n    #endif\n#endif\n\n#define NLOHMANN_JSON_VERSION_MAJOR 3   // NOLINT(modernize-macro-to-enum)\n#define NLOHMANN_JSON_VERSION_MINOR 12  // NOLINT(modernize-macro-to-enum)\n#define NLOHMANN_JSON_VERSION_PATCH 0   // NOLINT(modernize-macro-to-enum)\n\n#ifndef JSON_DIAGNOSTICS\n    #define JSON_DIAGNOSTICS 0\n#endif\n\n#ifndef JSON_DIAGNOSTIC_POSITIONS\n    #define JSON_DIAGNOSTIC_POSITIONS 0\n#endif\n\n#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n    #define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0\n#endif\n\n#if JSON_DIAGNOSTICS\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS _diag\n#else\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS\n#endif\n\n#if JSON_DIAGNOSTIC_POSITIONS\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS _dp\n#else\n    #define NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS\n#endif\n\n#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON\n    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON _ldvcmp\n#else\n    #define NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON\n#endif\n\n#ifndef NLOHMANN_JSON_NAMESPACE_NO_VERSION\n    #define NLOHMANN_JSON_NAMESPACE_NO_VERSION 0\n#endif\n\n// Construct the namespace ABI tags component\n#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c) json_abi ## a ## b ## c\n#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b, c) \\\n    NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b, c)\n\n#define NLOHMANN_JSON_ABI_TAGS                                       \\\n    NLOHMANN_JSON_ABI_TAGS_CONCAT(                                   \\\n            NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS,                       \\\n            NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON, \\\n            NLOHMANN_JSON_ABI_TAG_DIAGNOSTIC_POSITIONS)\n\n// Construct the namespace version component\n#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \\\n    _v ## major ## _ ## minor ## _ ## patch\n#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \\\n    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)\n\n#if NLOHMANN_JSON_NAMESPACE_NO_VERSION\n#define NLOHMANN_JSON_NAMESPACE_VERSION\n#else\n#define NLOHMANN_JSON_NAMESPACE_VERSION                                 \\\n    NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \\\n                                           NLOHMANN_JSON_VERSION_MINOR, \\\n                                           NLOHMANN_JSON_VERSION_PATCH)\n#endif\n\n// Combine namespace components\n#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b\n#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \\\n    NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)\n\n#ifndef NLOHMANN_JSON_NAMESPACE\n#define NLOHMANN_JSON_NAMESPACE               \\\n    nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \\\n            NLOHMANN_JSON_ABI_TAGS,           \\\n            NLOHMANN_JSON_NAMESPACE_VERSION)\n#endif\n\n#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN\n#define NLOHMANN_JSON_NAMESPACE_BEGIN                \\\n    namespace nlohmann                               \\\n    {                                                \\\n    inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \\\n                NLOHMANN_JSON_ABI_TAGS,              \\\n                NLOHMANN_JSON_NAMESPACE_VERSION)     \\\n    {\n#endif\n\n#ifndef NLOHMANN_JSON_NAMESPACE_END\n#define NLOHMANN_JSON_NAMESPACE_END                                     \\\n    }  /* namespace (inline namespace) NOLINT(readability/namespace) */ \\\n    }  // namespace nlohmann\n#endif\n\n\n/*!\n@brief namespace for Niels Lohmann\n@see https://github.com/nlohmann\n@since version 1.0.0\n*/\nNLOHMANN_JSON_NAMESPACE_BEGIN\n\n/*!\n@brief default JSONSerializer template argument\n\nThis serializer ignores the template arguments and uses ADL\n([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))\nfor serialization.\n*/\ntemplate<typename T = void, typename SFINAE = void>\nstruct adl_serializer;\n\n/// a class to store JSON values\n/// @sa https://json.nlohmann.me/api/basic_json/\ntemplate<template<typename U, typename V, typename... Args> class ObjectType =\n         std::map,\n         template<typename U, typename... Args> class ArrayType = std::vector,\n         class StringType = std::string, class BooleanType = bool,\n         class NumberIntegerType = std::int64_t,\n         class NumberUnsignedType = std::uint64_t,\n         class NumberFloatType = double,\n         template<typename U> class AllocatorType = std::allocator,\n         template<typename T, typename SFINAE = void> class JSONSerializer =\n         adl_serializer,\n         class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError\n         class CustomBaseClass = void>\nclass basic_json;\n\n/// @brief JSON Pointer defines a string syntax for identifying a specific value within a JSON document\n/// @sa https://json.nlohmann.me/api/json_pointer/\ntemplate<typename RefStringType>\nclass json_pointer;\n\n/*!\n@brief default specialization\n@sa https://json.nlohmann.me/api/json/\n*/\nusing json = basic_json<>;\n\n/// @brief a minimal map-like container that preserves insertion order\n/// @sa https://json.nlohmann.me/api/ordered_map/\ntemplate<class Key, class T, class IgnoredLess, class Allocator>\nstruct ordered_map;\n\n/// @brief specialization that maintains the insertion order of object keys\n/// @sa https://json.nlohmann.me/api/ordered_json/\nusing ordered_json = basic_json<nlohmann::ordered_map>;\n\nNLOHMANN_JSON_NAMESPACE_END\n\n#endif  // INCLUDE_NLOHMANN_JSON_FWD_HPP_\n"
  },
  {
    "path": "res/Maya FBX FO4 Fix.txt",
    "content": "//Title: Fallout 4 BoneFix MEL Script for Maya/Outfit Studio\n//Author: Nightasy\n{ \nstring $selected[] = `ls -type joint`; \nfor ($item in $selected) \n{ \n  string $temp = $item + \".rotateOrder\"; \n  setAttr $temp 5; \n};\nselect -r COM; \nrotate -r -os 0 0 90;\n\nselect `listRelatives -c`;\nselect -d Pelvis;\nselect -d SPINE1;\n$clothBones = `ls -sl`;\nfor ($item in $clothBones)\n{\n    float $Xpos = getAttr($item + \".translateX\");\n    float $Ypos = getAttr($item + \".translateY\");\n    float $Zpos = getAttr($item + \".translateZ\");\n    parent -w $item;\n    setAttr ($item+\".translateX\") $Xpos;\n    setAttr ($item+\".translateY\") $Zpos;\n    setAttr ($item+\".translateZ\") ($Ypos * -1);\n    parent $item COM ;\n}\n\nselect -r bindPose1;\ndoDelete;\nselect -r NifSkeleton;\ndagPose -bp -s;\n\n//list all transform nodes\nstring $transforms[] = `ls -tr`;\n//filter out non-polymesh nodes\nstring $polyMeshes[] = `filterExpand -sm 12 $transforms`;\n\nfor ($item in $polyMeshes)\n{\n\tselect -r $item;\n\tdoDetachSkin \"2\" { \"2\",\"1\" };\n\tselect -r $item;\n\tselect -add NifSkeleton;\n\tSmoothBindSkin;\n\tselect -r $item;\n\tremoveUnusedInfluences;\n};\n}"
  },
  {
    "path": "res/Maya FBX Skyrim Fix.txt",
    "content": "//Title: Skyrim BoneFix MEL Script for Maya/Outfit Studio\n//Author: Nightasy\n{ \nstring $selected[] = `ls -type joint`; \nfor ($item in $selected) \n{ \n  string $temp = $item + \".rotateOrder\"; \n  setAttr $temp 5; \n};\nselect -r NPCFBXASC032COMFBXASC032FBXASC091COMFBXASC032FBXASC093; \nrotate -r -os -90 0 0;\n\n\nselect -r NifSkeleton;\nselect -r bindPose1;\ndoDelete;\nselect -r NifSkeleton;\ndagPose -bp -s;\n\n//list all transform nodes\nstring $transforms[] = `ls -tr`;\n//filter out non-polymesh nodes\nstring $polyMeshes[] = `filterExpand -sm 12 $transforms`;\n\nfor ($item in $polyMeshes)\n{\n\tselect -r $item;\n\tdoDetachSkin \"2\" { \"2\",\"1\" };\n\tsetAttr ($item+\".translateY\") -120;\n\tselect -r $item;\n\tselect -add NifSkeleton;\n\tSmoothBindSkin;\n\tselect -r $item;\n\tremoveUnusedInfluences;\n};\n}"
  },
  {
    "path": "res/shaders/default.frag",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform sampler2D texDiffuse;\nuniform sampler2D texNormal;\nuniform samplerCube texCubemap;\nuniform sampler2D texEnvMask;\nuniform sampler2D texSpecular;\nuniform sampler2D texBacklight;\nuniform sampler2D texLightmask;\nuniform sampler2D texGlowmap;\n\nuniform bool bLightEnabled;\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\nuniform bool bWireframe;\n\nuniform bool bNormalMap;\nuniform bool bModelSpace;\nuniform bool bCubemap;\nuniform bool bEnvMask;\nuniform bool bSpecular;\nuniform bool bEmissive;\nuniform bool bBacklight;\nuniform bool bRimlight;\nuniform bool bSoftlight;\nuniform bool bGlowmap;\n\nuniform mat4 matModel;\nuniform mat4 matView;\nuniform mat4 matModelViewInverse;\nuniform mat3 mv_normalMatrix;\n\nstruct Properties\n{\n\tvec2 uvOffset;\n\tvec2 uvScale;\n\tvec3 specularColor;\n\tfloat specularStrength;\n\tfloat shininess;\n\tfloat envReflection;\n\tvec3 emissiveColor;\n\tfloat emissiveMultiple;\n\tfloat alpha;\n\tfloat rimlightPower;\n\tfloat softlighting;\n};\nuniform Properties prop;\nuniform float alphaThreshold;\n\nuniform float ambient;\n\nstruct DirectionalLight\n{\n\tvec3 diffuse;\n\tvec3 direction;\n};\n\nuniform DirectionalLight frontal;\nuniform DirectionalLight directional0;\nuniform DirectionalLight directional1;\nuniform DirectionalLight directional2;\n\nin vec3 lightFrontal;\nin vec3 lightDirectional0;\nin vec3 lightDirectional1;\nin vec3 lightDirectional2;\n\nin vec3 viewDir;\nin vec3 n;\nin mat3 mv_tbn;\n\nin float maskFactor;\nin vec3 weightColor;\n\nin vec4 vColor;\nin vec2 vUV;\n\nout vec4 fragColor;\n\nvec3 normal = vec3(0.0);\nfloat specFactor = 0.0;\n\nvec2 uv = vec2(0.0);\nvec3 albedo = vec3(0.0);\nvec3 emissive = vec3(0.0);\n\nvec4 baseMap = vec4(0.0);\nvec4 normalMap = vec4(0.0);\nvec4 specMap = vec4(0.0);\nvec4 envMask = vec4(0.0);\nvec4 backlightMap = vec4(0.0);\n\nvec3 tonemap(in vec3 x)\n{\n\tconst float A = 0.15;\n\tconst float B = 0.50;\n\tconst float C = 0.10;\n\tconst float D = 0.20;\n\tconst float E = 0.02;\n\tconst float F = 0.30;\n\n\treturn ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;\n}\n\nvoid directionalLight(in DirectionalLight light, in vec3 lightDir, inout vec3 outDiffuse, inout vec3 outSpec)\n{\n\tvec3 halfDir = normalize(lightDir + viewDir);\n\tfloat NdotL = max(dot(normal, lightDir), 0.0);\n\tfloat NdotH = max(dot(normal, halfDir), 0.0);\n\tfloat NdotV = max(dot(normal, viewDir), 0.0);\n\n\toutDiffuse += ambient + NdotL * light.diffuse;\n\toutSpec += clamp(prop.specularColor * prop.specularStrength * specFactor * pow(NdotH, prop.shininess), 0.0, 1.0) * light.diffuse;\n\n\t// Back lighting not really useful for the current light setup of multiple directional lights\n\t//if (bBacklight && bShowTexture)\n\t//{\n\t//\tfloat NdotNegL = max(dot(normal, -lightDir), 0.0);\n\t//\tvec3 backlight = backlightMap.rgb * NdotNegL * light.diffuse;\n\t//\temissive += backlight;\n\t//}\n\n\tvec3 lightMask = normalize(vec3(0.0, 0.0, 0.5));\n\tif (bRimlight || bSoftlight)\n\t{\n\t\tlightMask = texture(texLightmask, uv).rgb;\n\t}\n\n\t// Rim lighting not really useful for the current light setup of multiple directional lights\n\t//if (bRimlight)\n\t//{\n\t//\tvec3 rim = lightMask * pow(vec3(1.0 - NdotV), vec3(prop.rimlightPower));\n\t//\trim *= smoothstep(-0.2, 1.0, dot(-lightDir, viewDir));\n\t//\temissive += rim * light.diffuse;\n\t//}\n\n\t// Soft Lighting\n\tif (bSoftlight)\n\t{\n\t\tfloat wrap = (dot(normal, lightDir) + prop.softlighting) / (1.0 + prop.softlighting);\n\t\tvec3 soft = max(wrap, 0.0) * lightMask * smoothstep(1.0, 0.0, NdotL);\n\t\tsoft *= sqrt(clamp(prop.softlighting, 0.0, 1.0));\n\t\temissive += soft * light.diffuse;\n\t}\n}\n\nvoid main(void)\n{\n\tuv = vUV * prop.uvScale + prop.uvOffset;\n\tvec4 color = vColor;\n\talbedo = vColor.rgb;\n\n\tif (!bWireframe)\n\t{\n\t\tif (bShowTexture)\n\t\t{\n\t\t\t// Diffuse Texture\n\t\t\tbaseMap = texture(texDiffuse, uv);\n\t\t\talbedo *= baseMap.rgb;\n\t\t\tcolor.a *= baseMap.a;\n\n\t\t\t// Diffuse texture without lighting\n\t\t\tcolor.rgb = albedo;\n\n\t\t\tif (bLightEnabled)\n\t\t\t{\n\t\t\t\tif (bNormalMap)\n\t\t\t\t{\n\t\t\t\t\tnormalMap = texture(texNormal, uv);\n\n\t\t\t\t\tif (bModelSpace && bSpecular)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Dedicated Specular Map\n\t\t\t\t\t\tspecMap = texture(texSpecular, uv);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (bCubemap)\n\t\t\t\t{\n\t\t\t\t\tif (bEnvMask)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Environment Mask\n\t\t\t\t\t\tenvMask = texture(texEnvMask, uv);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (bBacklight)\n\t\t\t\t{\n\t\t\t\t\tbacklightMap = texture(texBacklight, uv);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (bLightEnabled)\n\t\t{\n\t\t\t// Lighting with or without textures\n\t\t\tvec3 outDiffuse = vec3(0.0);\n\t\t\tvec3 outSpecular = vec3(0.0);\n\n\t\t\tspecFactor = 0.0;\n\n\t\t\tif (bShowTexture && bNormalMap)\n\t\t\t{\n\t\t\t\tif (bModelSpace)\n\t\t\t\t{\n\t\t\t\t\t// Model Space Normal Map\n\t\t\t\t\tnormal = normalize(normalMap.rgb * 2.0 - 1.0);\n\t\t\t\t\tnormal.r = -normal.r;\n\t\t\t\t\tnormal = mat3(matView) * normal;\n\t\t\t\t\tnormal = normalize(normal);\n\n\t\t\t\t\tif (bSpecular)\n\t\t\t\t\t{\n\t\t\t\t\t\tspecFactor = specMap.r;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// Tangent Space Normal Map\n\t\t\t\t\tnormal = normalize(mv_tbn * (normalMap.rgb * 2.0 - 1.0));\n\n\t\t\t\t\tif (bSpecular)\n\t\t\t\t\t{\n\t\t\t\t\t\tspecFactor = normalMap.a;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\t// Vertex normal for shading with disabled maps\n\t\t\t\tnormal = mv_normalMatrix * n;\n\t\t\t\tnormal = normalize(normal);\n\t\t\t}\n\n\t\t\tdirectionalLight(frontal, lightFrontal, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional0, lightDirectional0, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional1, lightDirectional1, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional2, lightDirectional2, outDiffuse, outSpecular);\n\n\t\t\tif (bCubemap && bShowTexture)\n\t\t\t{\n\t\t\t\tvec3 reflected = reflect(-viewDir, normal);\n\t\t\t\tvec3 reflectedWS = vec3(matModel * (matModelViewInverse * vec4(reflected, 0.0)));\n\n\t\t\t\tvec4 cubeMap = texture(texCubemap, reflectedWS);\n\t\t\t\tcubeMap.rgb *= prop.envReflection;\n\n\t\t\t\tif (bEnvMask)\n\t\t\t\t{\n\t\t\t\t\tcubeMap.rgb *= envMask.r;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\t// No env mask, use specular factor (0.0 if no normal map either)\n\t\t\t\t\tcubeMap.rgb *= specFactor;\n\t\t\t\t}\n\n\t\t\t\talbedo += cubeMap.rgb;\n\t\t\t}\n\n\t\t\t// Emissive\n\t\t\tif (bEmissive)\n\t\t\t{\n\t\t\t\temissive += prop.emissiveColor * prop.emissiveMultiple;\n\n\t\t\t\t// Glowmap\n\t\t\t\tif (bGlowmap)\n\t\t\t\t{\n\t\t\t\t\tvec4 glowMap = texture(texGlowmap, uv);\n\t\t\t\t\temissive *= glowMap.rgb;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcolor.rgb = albedo * (outDiffuse + emissive) + outSpecular;\n\t\t}\n\n\t\tif (bShowMask)\n\t\t{\n\t\t\tcolor.rgb *= maskFactor;\n\t\t}\n\n\t\tif (bShowWeight)\n\t\t{\n\t\t\tcolor.rgb *= weightColor;\n\t\t}\n\n\t\tcolor.rgb = tonemap(color.rgb) / tonemap(vec3(1.0));\n\t}\n\telse\n\t{\n\t\tcolor = vec4(color.rgb, 0.5);\n\t}\n\n\tcolor = clamp(color, 0.0, 1.0);\n\n\tfragColor = color;\n\n\tif (!bWireframe)\n\t{\n\t\tif (alphaThreshold != -1.0f)\n\t\t\tif (fragColor.a <= alphaThreshold) // GL_GREATER\n\t\t\t\tdiscard;\n\n\t\tfragColor.a *= prop.alpha;\n\t\tgl_FragDepth = gl_FragCoord.z;\n\t}\n\telse\n\t{\n\t\t// Minimal depth offset for wireframe to prevent z-fighting with its own mesh\n\t\tgl_FragDepth = gl_FragCoord.z - 0.00001f;\n\t}\n}\n"
  },
  {
    "path": "res/shaders/default.vert",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform mat4 matProjection;\nuniform mat4 matView;\nuniform mat4 matModelView;\nuniform mat3 mv_normalMatrix;\nuniform vec3 color;\nuniform vec3 subColor;\n\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\nuniform bool bShowVertexColor;\nuniform bool bShowVertexAlpha;\n\nuniform bool bWireframe;\nuniform bool bModelSpace;\n\nlayout(location = 0) in vec3 vertexPosition;\nlayout(location = 1) in vec3 vertexNormal;\nlayout(location = 2) in vec3 vertexTangent;\nlayout(location = 3) in vec3 vertexBitangent;\nlayout(location = 4) in vec3 vertexColors;\nlayout(location = 5) in float vertexAlpha;\nlayout(location = 6) in vec2 vertexUV;\nlayout(location = 7) in float vertexMask;\nlayout(location = 8) in float vertexWeight;\n\nstruct DirectionalLight\n{\n\tvec3 diffuse;\n\tvec3 direction;\n};\n\nuniform DirectionalLight frontal;\nuniform DirectionalLight directional0;\nuniform DirectionalLight directional1;\nuniform DirectionalLight directional2;\n\nout vec3 lightFrontal;\nout vec3 lightDirectional0;\nout vec3 lightDirectional1;\nout vec3 lightDirectional2;\n\nout vec3 viewDir;\nout vec3 n;\nout mat3 mv_tbn;\n\nout float maskFactor;\nout vec3 weightColor;\n\nout vec4 vColor;\nout vec2 vUV;\n\nvec3 colorRamp(in float value)\n{\n\tfloat r;\n\tfloat g;\n\tfloat b;\n\n\tif (value <= 0.0f)\n\t{\n\t\tr = g = b = 1.0;\n\t}\n\telse if (value <= 0.25)\n\t{\n\t\tr = 0.0;\n\t\tb = 1.0;\n\t\tg = value / 0.25;\n\t}\n\telse if (value <= 0.5)\n\t{\n\t\tr = 0.0;\n\t\tg = 1.0;\n\t\tb = 1.0 + (-1.0) * (value - 0.25) / 0.25;\n\t}\n\telse if (value <= 0.75)\n\t{\n\t\tr = (value - 0.5) / 0.25;\n\t\tg = 1.0;\n\t\tb = 0.0;\n\t}\n\telse\n\t{\n\t\tr = 1.0;\n\t\tg = 1.0 + (-1.0) * (value - 0.75) / 0.25;\n\t\tb = 0.0;\n\t}\n\n\treturn vec3(r, g, b);\n}\n\nvoid main(void)\n{\n\t// Initialization\n\tmaskFactor = 1.0;\n\tweightColor = vec3(1.0, 1.0, 1.0);\n\tvColor = vec4(1.0, 1.0, 1.0, 1.0);\n\tvUV = vertexUV;\n\n\tif (bShowVertexColor)\n\t{\n\t\tvColor.rgb = vertexColors;\n\t}\n\n\tif (bShowVertexAlpha)\n\t{\n\t\tvColor.a = vertexAlpha;\n\t}\n\n\t// Eye-coordinate position of vertex\n\tvec3 vPos = vec3(matModelView * vec4(vertexPosition, 1.0));\n\tgl_Position = matProjection * vec4(vPos, 1.0);\n\n\tn = vertexNormal;\n\n\tif (!bModelSpace)\n\t{\n\t\tvec3 mv_normal = mv_normalMatrix * n;\n\t\tvec3 mv_tangent = mv_normalMatrix * vertexTangent;\n\t\tvec3 mv_bitangent = mv_normalMatrix * vertexBitangent;\n\n\t\tmv_tbn = mat3(mv_bitangent.x, mv_bitangent.y, mv_bitangent.z,\n                           mv_tangent.x, mv_tangent.y, mv_tangent.z,\n                           mv_normal.x, mv_normal.y, mv_normal.z);\n\t}\n\tviewDir = normalize(-vPos);\n\tlightFrontal = normalize(frontal.direction);\n\tlightDirectional0 = normalize(mat3(matView) * directional0.direction);\n\tlightDirectional1 = normalize(mat3(matView) * directional1.direction);\n\tlightDirectional2 = normalize(mat3(matView) * directional2.direction);\n\n\tif (!bShowTexture || bWireframe)\n\t{\n\t\tvColor *= clamp(vec4(color, 1.0), 0.0, 1.0);\n\t}\n\n\tif (!bWireframe)\n\t{\n\t\tvColor.rgb *= subColor;\n\n\t\tif (bShowMask)\n\t\t{\n\t\t\tmaskFactor = 1.0 - vertexMask / 1.5;\n\t\t}\n\n\t\tif (bShowWeight)\n\t\t{\n\t\t\tweightColor = colorRamp(vertexWeight);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "res/shaders/fo4_default.frag",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform sampler2D texDiffuse;\nuniform sampler2D texNormal;\nuniform samplerCube texCubemap;\nuniform sampler2D texEnvMask;\nuniform sampler2D texSpecular;\nuniform sampler2D texGreyscale;\nuniform sampler2D texGlowmap;\n\nuniform bool bLightEnabled;\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\nuniform bool bWireframe;\n\nuniform bool bNormalMap;\nuniform bool bModelSpace;\nuniform bool bCubemap;\nuniform bool bEnvMask;\nuniform bool bSpecular;\nuniform bool bEmissive;\nuniform bool bBacklight;\nuniform bool bRimlight;\nuniform bool bSoftlight;\nuniform bool bGlowmap;\nuniform bool bGreyscaleColor;\n\nuniform mat4 matModel;\nuniform mat4 matModelViewInverse;\n\nstruct Properties\n{\n\tvec2 uvOffset;\n\tvec2 uvScale;\n\tvec3 specularColor;\n\tfloat specularStrength;\n\tfloat shininess;\n\tfloat envReflection;\n\tvec3 emissiveColor;\n\tfloat emissiveMultiple;\n\tfloat alpha;\n\tfloat backlightPower;\n\tfloat rimlightPower;\n\tfloat subsurfaceRolloff;\n\tfloat fresnelPower;\n\tfloat paletteScale;\n};\nuniform Properties prop;\nuniform float alphaThreshold;\n\nuniform float ambient;\n\nstruct DirectionalLight\n{\n\tvec3 diffuse;\n\tvec3 direction;\n};\n\nuniform DirectionalLight frontal;\nuniform DirectionalLight directional0;\nuniform DirectionalLight directional1;\nuniform DirectionalLight directional2;\n\nin vec3 lightFrontal;\nin vec3 lightDirectional0;\nin vec3 lightDirectional1;\nin vec3 lightDirectional2;\n\nin vec3 viewDir;\nin mat3 mv_tbn;\n\nin float maskFactor;\nin vec3 weightColor;\n\nin vec4 vColor;\nin vec2 vUV;\n\nout vec4 fragColor;\n\nvec3 normal = vec3(0.0);\nfloat specGloss = 1.0;\nfloat specFactor = 1.0;\n\nvec2 uv = vec2(0.0);\nvec3 albedo = vec3(0.0);\nvec3 emissive = vec3(0.0);\n\nvec4 baseMap = vec4(0.0);\nvec4 normalMap = vec4(0.0);\nvec4 specMap = vec4(0.0);\nvec4 envMask = vec4(0.0);\n\n#ifndef M_PI\n\t#define M_PI 3.1415926535897932384626433832795\n#endif\n\n#define FLT_EPSILON 1.192092896e-07F // smallest such that 1.0 + FLT_EPSILON != 1.0\n\nfloat OrenNayarFull(vec3 L, vec3 V, vec3 N, float roughness, float NdotL)\n{\n\t//float NdotL = dot(N, L);\n\tfloat NdotV = dot(N, V);\n\tfloat LdotV = dot(L, V);\n\n\tfloat angleVN = acos(max(NdotV, FLT_EPSILON));\n\tfloat angleLN = acos(max(NdotL, FLT_EPSILON));\n\n\tfloat alpha = max(angleVN, angleLN);\n\tfloat beta = min(angleVN, angleLN);\n\tfloat gamma = LdotV - NdotL * NdotV;\n\n\tfloat roughnessSquared = roughness * roughness;\n\tfloat roughnessSquared9 = (roughnessSquared / (roughnessSquared + 0.09));\n\n\t// C1, C2, and C3\n\tfloat C1 = 1.0 - 0.5 * (roughnessSquared / (roughnessSquared + 0.33));\n\tfloat C2 = 0.45 * roughnessSquared9;\n\n\tif( gamma >= 0.0 )\n\t\tC2 *= sin(alpha);\n\telse\n\t\tC2 *= (sin(alpha) - pow((2.0 * beta) / M_PI, 3.0));\n\n\tfloat powValue = (4.0 * alpha * beta) / (M_PI * M_PI);\n\tfloat C3 = 0.125 * roughnessSquared9 * powValue * powValue;\n\n\t// Avoid asymptote at pi/2\n\tfloat asym = M_PI / 2.0;\n\tfloat lim1 = asym + 0.01;\n\tfloat lim2 = asym - 0.01;\n\n\tfloat ab2 = (alpha + beta) / 2.0;\n\n\tif (beta >= asym && beta < lim1)\n\t\tbeta = lim1;\n\telse if (beta < asym && beta >= lim2)\n\t\tbeta = lim2;\n\n\tif (ab2 >= asym && ab2 < lim1)\n\t\tab2 = lim1;\n\telse if (ab2 < asym && ab2 >= lim2)\n\t\tab2 = lim2;\n\n\t// Reflection\n\tfloat A = gamma * C2 * tan(beta);\n\tfloat B = (1.0 - abs(gamma)) * C3 * tan(ab2);\n\n\tfloat L1 = max(FLT_EPSILON, NdotL) * (C1 + A + B);\n\n\t// Interreflection\n\tfloat twoBetaPi = 2.0 * beta / M_PI;\n\tfloat L2 = 0.17 * max(FLT_EPSILON, NdotL) * (roughnessSquared / (roughnessSquared + 0.13)) * (1.0 - gamma * twoBetaPi * twoBetaPi);\n\n\treturn L1 + L2;\n}\n\n// Schlick's Fresnel approximation\nfloat fresnelSchlick(float VdotH, float F0)\n{\n\tfloat base = 1.0 - VdotH;\n\tfloat exp = pow(base, prop.fresnelPower);\n\treturn clamp(exp + F0 * (1.0 - exp), 0.0, 1.0);\n}\n\n// The Torrance-Sparrow visibility factor, G\nfloat VisibDiv(float NdotL, float NdotV, float VdotH, float NdotH)\n{\n\tfloat denom = max(VdotH, FLT_EPSILON);\n\tfloat numL = min(NdotV, NdotL);\n\tfloat numR = 2.0 * NdotH;\n\tif (denom >= (numL * numR))\n\t{\n\t\tnumL = (numL == NdotV) ? 1.0 : (NdotL / NdotV);\n\t\treturn (numL * numR) / denom;\n\t}\n\treturn 1.0 / NdotV;\n}\n\n// this is a normalized Phong model used in the Torrance-Sparrow model\nvec3 TorranceSparrow(float NdotL, float NdotH, float NdotV, float VdotH, vec3 color, float power, float F0)\n{\n\t// D: Normalized phong model\n\tfloat D = ((power + 2.0) / (2.0 * M_PI)) * pow(NdotH, power);\n\n\t// G: Torrance-Sparrow visibility term divided by NdotV\n\tfloat G_NdotV = VisibDiv(NdotL, NdotV, VdotH, NdotH);\n\n\t// F: Schlick's approximation\n\tfloat F = fresnelSchlick(VdotH, F0);\n\n\t// Torrance-Sparrow:\n\t// (F * G * D) / (4 * NdotL * NdotV)\n\t// Division by NdotV is done in VisibDiv()\n\t// and division by NdotL is removed since\n\t// outgoing radiance is determined by:\n\t// BRDF * NdotL * L()\n\tfloat spec = (F * G_NdotV * D) / 4.0;\n\n\treturn color * spec * M_PI;\n}\n\nvec3 tonemap(in vec3 x)\n{\n\tconst float A = 0.15;\n\tconst float B = 0.50;\n\tconst float C = 0.10;\n\tconst float D = 0.20;\n\tconst float E = 0.02;\n\tconst float F = 0.30;\n\n\treturn ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;\n}\n\nvoid directionalLight(in DirectionalLight light, in vec3 lightDir, inout vec3 outDiffuse, inout vec3 outSpec)\n{\n\tvec3 halfDir = normalize(lightDir + viewDir);\n\tfloat NdotL = dot(normal, lightDir);\n\tfloat NdotL0 = max(NdotL, FLT_EPSILON);\n\tfloat NdotH = max(dot(normal, halfDir), FLT_EPSILON);\n\tfloat NdotV = max(dot(normal, viewDir), FLT_EPSILON);\n\tfloat VdotH = max(dot(viewDir, halfDir), FLT_EPSILON);\n\n\t// Temporary diffuse\n\tvec3 diff = ambient + NdotL0 * light.diffuse;\n\n\t// Specularity\n\tfloat smoothness = 1.0;\n\tfloat roughness = 0.0;\n\tfloat specMask = 1.0;\n\tif (bSpecular && bShowTexture)\n\t{\n\t\tsmoothness = specGloss * prop.shininess;\n\t\troughness = 1.0 - smoothness;\n\t\tfloat fSpecularPower = exp2(smoothness * 10.0 + 1.0);\n\t\tspecMask = specFactor * prop.specularStrength;\n\n\t\toutSpec += TorranceSparrow(NdotL0, NdotH, NdotV, VdotH, vec3(specMask), fSpecularPower, 0.2) * NdotL0 * light.diffuse * prop.specularColor;\n\t\toutSpec += ambient * specMask * fresnelSchlick(VdotH, 0.2) * (1.0 - NdotV) * light.diffuse;\n\t}\n\n\t// Environment\n\tif (bCubemap && bShowTexture)\n\t{\n\t\tvec3 reflected = reflect(viewDir, normal);\n\t\tvec3 reflectedWS = vec3(matModel * (matModelViewInverse * vec4(reflected, 0.0)));\n\n\t\tvec4 cube = textureLod(texCubemap, reflectedWS, 8.0 - smoothness * 8.0);\n\t\tcube.rgb *= prop.envReflection * prop.specularStrength;\n\t\tif (bEnvMask)\n\t\t{\n\t\t\tcube.rgb *= envMask.r;\n\t\t}\n\t\telse\n\t\t{\n\t\t\t// No env mask, use specular factor\n\t\t\tcube.rgb *= specFactor;\n\t\t}\n\n\t\toutSpec += cube.rgb * diff;\n\t}\n\n\t// Back lighting not really useful for the current light setup of multiple directional lights\n\t//if (bBacklight)\n\t//{\n\t//\tfloat NdotNegL = max(dot(normal, -lightDir), FLT_EPSILON);\n\t//\tvec3 backlight = albedo * NdotNegL * clamp(prop.backlightPower, 0.0, 1.0);\n\t//\temissive += backlight * light.diffuse;\n\t//}\n\n\t// Rim lighting not really useful for the current light setup of multiple directional lights\n\t//if (bRimlight)\n\t//{\n\t//\tvec3 rim = vec3(pow((1.0 - NdotV), prop.rimlightPower));\n\t//\trim *= smoothstep(-0.2, 1.0, dot(-lightDir, viewDir));\n\t//\temissive += rim * light.diffuse * specMask;\n\t//}\n\n\t// Diffuse\n\tdiff = vec3(OrenNayarFull(lightDir, viewDir, normal, roughness, NdotL0));\n\toutDiffuse += diff * light.diffuse;\n\n\t// Soft Lighting\n\tif (bSoftlight)\n\t{\n\t\tfloat wrap = (NdotL + prop.subsurfaceRolloff) / (1.0 + prop.subsurfaceRolloff);\n\t\tvec3 soft = albedo * max(0.0, wrap) * smoothstep(1.0, 0.0, sqrt(diff));\n\t\toutDiffuse += soft;\n\t}\n}\n\nvec4 colorLookup(in float x, in float y)\n{\n\treturn texture(texGreyscale, vec2(clamp(x, 0.0, 1.0), clamp(y, 0.0, 1.0)));\n}\n\nvoid main(void)\n{\n\tuv = vUV * prop.uvScale + prop.uvOffset;\n\tvec4 color = vColor;\n\talbedo = vColor.rgb;\n\n\tif (!bWireframe)\n\t{\n\t\tif (bShowTexture)\n\t\t{\n\t\t\t// Diffuse Texture\n\t\t\tbaseMap = texture(texDiffuse, uv);\n\t\t\talbedo *= baseMap.rgb;\n\t\t\tcolor.a *= baseMap.a;\n\n\t\t\t// Diffuse texture without lighting\n\t\t\tcolor.rgb = albedo;\n\n\t\t\tif (bLightEnabled)\n\t\t\t{\n\t\t\t\tif (bNormalMap)\n\t\t\t\t{\n\t\t\t\t\tnormalMap = texture(texNormal, uv);\n\n\t\t\t\t\tif (bSpecular)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Specular Map\n\t\t\t\t\t\tspecMap = texture(texSpecular, uv);\n\t\t\t\t\t\tspecGloss = specMap.g;\n\t\t\t\t\t\tspecFactor = specMap.r;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (bCubemap)\n\t\t\t\t{\n\t\t\t\t\tif (bEnvMask)\n\t\t\t\t\t{\n\t\t\t\t\t\t// Environment Mask\n\t\t\t\t\t\tenvMask = texture(texEnvMask, uv);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (bLightEnabled)\n\t\t{\n\t\t\t// Lighting with or without textures\n\t\t\tvec3 outDiffuse = vec3(0.0);\n\t\t\tvec3 outSpecular = vec3(0.0);\n\n\t\t\t// Start off neutral\n\t\t\tnormal = normalize(mv_tbn * vec3(0.0, 0.0, 0.5));\n\n\t\t\tif (bShowTexture)\n\t\t\t{\n\t\t\t\tif (bNormalMap)\n\t\t\t\t{\n\t\t\t\t\tif (bModelSpace)\n\t\t\t\t\t{\n\t\t\t\t\t\t// No proper FO4 model space map rendering yet\n\t\t\t\t\t\t//normal = normalize(normalMap.rgb * 2.0 - 1.0);\n\t\t\t\t\t\t//normal.r = -normal.r;\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{\n\t\t\t\t\t\tnormal = (normalMap.rgb * 2.0 - 1.0);\n\n\t\t\t\t\t\t// Calculate missing blue channel\n\t\t\t\t\t\tnormal.b = sqrt(1.0 - dot(normal.rg, normal.rg));\n\n\t\t\t\t\t\t// Tangent space map\n\t\t\t\t\t\tnormal = normalize(mv_tbn * normal);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (bGreyscaleColor)\n\t\t\t\t{\n\t\t\t\t\tvec4 luG = colorLookup(baseMap.g, prop.paletteScale - (1.0 - vColor.r));\n\t\t\t\t\talbedo = luG.rgb;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdirectionalLight(frontal, lightFrontal, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional0, lightDirectional0, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional1, lightDirectional1, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional2, lightDirectional2, outDiffuse, outSpecular);\n\n\t\t\t// Emissive\n\t\t\tif (bEmissive)\n\t\t\t{\n\t\t\t\temissive += prop.emissiveColor * prop.emissiveMultiple;\n\n\t\t\t\t// Glowmap\n\t\t\t\tif (bGlowmap)\n\t\t\t\t{\n\t\t\t\t\tvec4 glowMap = texture(texGlowmap, uv);\n\t\t\t\t\temissive *= glowMap.rgb;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcolor.rgb = outDiffuse * albedo;\n\t\t\tcolor.rgb += outSpecular;\n\t\t\tcolor.rgb += emissive;\n\t\t\tcolor.rgb += ambient * albedo;\n\t\t}\n\n\t\tif (bShowMask)\n\t\t{\n\t\t\tcolor.rgb *= maskFactor;\n\t\t}\n\n\t\tif (bShowWeight)\n\t\t{\n\t\t\tcolor.rgb *= weightColor;\n\t\t}\n\n\t\tcolor.rgb = tonemap(color.rgb) / tonemap(vec3(1.0));\n\t}\n\telse\n\t{\n\t\tcolor = vec4(color.rgb, 0.5);\n\t}\n\n\tcolor = clamp(color, 0.0, 1.0);\n\n\tfragColor = color;\n\n\tif (!bWireframe)\n\t{\n\t\tfragColor.a *= prop.alpha;\n\n\t\tif (alphaThreshold != -1.0f)\n\t\t\tif (fragColor.a <= alphaThreshold) // GL_GREATER\n\t\t\t\tdiscard;\n\n\t\tgl_FragDepth = gl_FragCoord.z;\n\t}\n\telse\n\t{\n\t\t// Minimal depth offset for wireframe to prevent z-fighting with its own mesh\n\t\tgl_FragDepth = gl_FragCoord.z - 0.00001f;\n\t}\n}\n"
  },
  {
    "path": "res/shaders/fo4_default.vert",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform mat4 matProjection;\nuniform mat4 matView;\nuniform mat4 matModel;\nuniform mat4 matModelView;\nuniform mat3 mv_normalMatrix;\nuniform vec3 color;\nuniform vec3 subColor;\n\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\nuniform bool bShowVertexColor;\nuniform bool bShowVertexAlpha;\n\nuniform bool bWireframe;\n\nlayout(location = 0) in vec3 vertexPosition;\nlayout(location = 1) in vec3 vertexNormal;\nlayout(location = 2) in vec3 vertexTangent;\nlayout(location = 3) in vec3 vertexBitangent;\nlayout(location = 4) in vec3 vertexColors;\nlayout(location = 5) in float vertexAlpha;\nlayout(location = 6) in vec2 vertexUV;\nlayout(location = 7) in float vertexMask;\nlayout(location = 8) in float vertexWeight;\n\nstruct DirectionalLight\n{\n\tvec3 diffuse;\n\tvec3 direction;\n};\n\nuniform DirectionalLight frontal;\nuniform DirectionalLight directional0;\nuniform DirectionalLight directional1;\nuniform DirectionalLight directional2;\n\nout vec3 lightFrontal;\nout vec3 lightDirectional0;\nout vec3 lightDirectional1;\nout vec3 lightDirectional2;\n\nout vec3 viewDir;\nout mat3 mv_tbn;\n\nout float maskFactor;\nout vec3 weightColor;\n\nout vec4 vColor;\nout vec2 vUV;\n\nvec3 colorRamp(in float value)\n{\n\tfloat r;\n\tfloat g;\n\tfloat b;\n\n\tif (value <= 0.0f)\n\t{\n\t\tr = g = b = 1.0;\n\t}\n\telse if (value <= 0.25)\n\t{\n\t\tr = 0.0;\n\t\tb = 1.0;\n\t\tg = value / 0.25;\n\t}\n\telse if (value <= 0.5)\n\t{\n\t\tr = 0.0;\n\t\tg = 1.0;\n\t\tb = 1.0 + (-1.0) * (value - 0.25) / 0.25;\n\t}\n\telse if (value <= 0.75)\n\t{\n\t\tr = (value - 0.5) / 0.25;\n\t\tg = 1.0;\n\t\tb = 0.0;\n\t}\n\telse\n\t{\n\t\tr = 1.0;\n\t\tg = 1.0 + (-1.0) * (value - 0.75) / 0.25;\n\t\tb = 0.0;\n\t}\n\n\treturn vec3(r, g, b);\n}\n\nvoid main(void)\n{\n\t// Initialization\n\tmaskFactor = 1.0;\n\tweightColor = vec3(1.0, 1.0, 1.0);\n\tvColor = vec4(1.0, 1.0, 1.0, 1.0);\n\tvUV = vertexUV;\n\n\tif (bShowVertexColor)\n\t{\n\t\tvColor.rgb = vertexColors;\n\t}\n\n\tif (bShowVertexAlpha)\n\t{\n\t\tvColor.a = vertexAlpha;\n\t}\n\n\t// Eye-coordinate position of vertex\n\tvec3 vPos = vec3(matModelView * vec4(vertexPosition, 1.0));\n\tgl_Position = matProjection * vec4(vPos, 1.0);\n\n\tvec3 mv_normal = mv_normalMatrix * vertexNormal;\n\tvec3 mv_tangent = mv_normalMatrix * vertexTangent;\n\tvec3 mv_bitangent = mv_normalMatrix * vertexBitangent;\n\n\tmv_tbn = mat3(mv_bitangent.x, mv_bitangent.y, mv_bitangent.z,\n\t\t\t\t  mv_tangent.x, mv_tangent.y, mv_tangent.z,\n\t\t\t\t  mv_normal.x, mv_normal.y, mv_normal.z);\n\n\tviewDir = normalize(-vPos);\n\tlightFrontal = normalize(frontal.direction);\n\tlightDirectional0 = normalize(mat3(matView) * directional0.direction);\n\tlightDirectional1 = normalize(mat3(matView) * directional1.direction);\n\tlightDirectional2 = normalize(mat3(matView) * directional2.direction);\n\n\tif (!bShowTexture || bWireframe)\n\t{\n\t\tvColor *= clamp(vec4(color, 1.0), 0.0, 1.0);\n\t}\n\n\tif (!bWireframe)\n\t{\n\t\tvColor.rgb *= subColor;\n\n\t\tif (bShowMask)\n\t\t{\n\t\t\tmaskFactor = 1.0 - vertexMask / 1.5;\n\t\t}\n\n\t\tif (bShowWeight)\n\t\t{\n\t\t\tweightColor = colorRamp(vertexWeight);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "res/shaders/fullscreentri.frag",
    "content": "#version 330\n\nuniform sampler2D texDiffuse;\nin vec2 uv;\nout vec4 color;\n\nvec4 blur(in float texel) {\n\tvec2 offs[9] = vec2[]( \n\t\tvec2(-texel, -texel), vec2(0.0, -texel), vec2(texel,-texel),\t\t\n\t\tvec2(-texel, 0.0),\t  vec2(0.0, 0.0),    vec2(texel,0.0),\t\t\n\t\tvec2(-texel, texel),  vec2(0.0, texel),  vec2(texel,texel)\n\t);\n\t\n\tvec4[9] sample;\n\tfor(int i=0;i<9;i++) {\n\t\tsample[i] = texture(texDiffuse, uv + offs[i]);\n\t}\n\treturn (sample[0] + (2.0*sample[1]) + sample[2] + \n              (2.0*sample[3]) + sample[4] + (2.0*sample[5]) + \n              sample[6] + (2.0*sample[7]) + sample[8]) / 13.0;\n\n} \n\nvec4 maxSample(in float texel) {\n\tvec2 offs[9] = vec2[]( \n\t\tvec2(-texel, -texel), vec2(0.0, -texel), vec2(texel,-texel),\t\t\n\t\tvec2(-texel, 0.0),\t  vec2(0.0, 0.0),    vec2(texel,0.0),\t\t\n\t\tvec2(-texel, texel),  vec2(0.0, texel),  vec2(texel,texel)\n\t);\n\tvec4[9] sample;\n\tvec4 maxValue = vec4(0.0);\n\tfor(int i=0;i<9;i++) {\n\t\tsample[i] = texture(texDiffuse, uv + offs[i]);\n\t\tmaxValue = max(sample[i], maxValue);\n\t}\n\n\treturn maxValue;\n}\n\nvec4 minDistSample(in float texel, in int range) {\n\n\tvec2 offs[8] = vec2[] ( vec2(-1.0,0.0), vec2(1.0,0.0), vec2(0.0,1.0), vec2(0.0,-1.0), vec2(-1.0,1.0), vec2(1.0,1.0), vec2(1.0,-1.0), vec2(-1.0,-1.0));\n\tvec4 sample = texture(texDiffuse, uv);\n\tif(sample.a != 0.0) {\n\t\treturn sample;\n\t}\n\n\tfor(int i=0;i<range;i++) {\n\t\tfor(int j=0;j<8;j++) {\n\t\t\tvec4 remoteSample = texture(texDiffuse, uv + offs[j]*(texel*i));\n\t\t\tif(remoteSample.a !=0.0) {\n\t\t\t\treturn remoteSample;\n\t\t\t}\n\t\t}\n\t}\n\treturn sample;\n}\n\nvoid main(void)\n{\t\n\tfloat texel = 1.0 / 1024.0;\n\n\t// blur filter\n\t// color = blur(texel);\n\n\t// simple maximum -- greyscale dilation (Does not work for color)\n\t// color = maxSample(texel);\n\n\t// nearest non-alpha sample, works as a basic color dilation filter\n\tcolor = minDistSample (texel, 10);\n\t\n\t// passthrough\n\t// color = texture(texDiffuse,uv);\n\n\t// uvramp\n\t// color=vec4(uv.x, uv.y,0.0,1.0);\n\t\n}"
  },
  {
    "path": "res/shaders/fullscreentri.vert",
    "content": "#version 330\nout vec2 uv;\n\nvoid main()\n{\n\tuv = vec2((gl_VertexID << 1) & 2, gl_VertexID & 2);\t\t\t\t\t\t\t//  0.0, 0.0     2.0, 0.0   0.0, 2.0\n\tgl_Position = vec4(uv * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0);\t\t//  -1.0, -1.0   3.0, -1.0  -1.0, 3.0\n}\n"
  },
  {
    "path": "res/shaders/normalshade.frag",
    "content": "#version 330\nuniform sampler2D texNormal;\nuniform sampler2D texAlphaMask;\nuniform mat4 matView;\nuniform bool bModelSpace;\nuniform bool bAlphaMask;\n\nin vec3 N;\nin vec3 v;\nin vec3 vPos;\nin vec2 uv;\n\nvec4 normalMap;\n\nout vec4 fragColor;\n\n// simple vertex shading to produce smoothed model space normals.\nvec3 NormalColor(vec3 inNormal) {\n\tfloat r = 1.0 - ( (inNormal.r + 1.0) / 2.0 );\n\tfloat g = (inNormal.g + 1.0) / 2.0;\n    float b = (inNormal.b + 1.0) / 2.0;\n\treturn vec3(r,g,b);\n}\n\n// http://www.thetenthplanet.de/archives/1180\nmat3 cotangent_frame(in vec3 N, in vec3 p)\n{\n    // Get edge vectors of the pixel triangle\n    vec3 dp1 = dFdx(p);\n    vec3 dp2 = dFdy(p);\n    vec2 duv1 = dFdx(uv);\n    vec2 duv2 = dFdy(uv);\n\t\n    // Solve the linear system\n    vec3 dp2perp = cross(dp2, N);\n    vec3 dp1perp = cross(N, dp1);\n    vec3 T = dp2perp * duv1.x + dp1perp * duv2.x;\n    vec3 B = dp2perp * duv1.y + dp1perp * duv2.y;\n\t\n    // Construct a scale-invariant frame\n    float invmax = inversesqrt(max(dot(T, T), dot(B, B)));\n    return mat3(T * invmax, B * invmax, N);\n}\n\nvec3 perturb_normal(in vec3 N, in vec3 V)\n{\n\t// Assume N, the interpolated vertex normal and V, the view vector (vertex to eye)\n\tvec3 map = normalMap.rgb;\n\t//map.r = 1.0-map.r;\n\t//map.g = 1.0-map.g;\n\tmap = map * 255.0 / 127.0 - 128.0 / 127.0;\n\tmat3 TBN = cotangent_frame(N, -V);\n\treturn normalize(TBN * map);\n}\n\n\nvec4 Light(vec3 lightPos, vec4 lightColor, float lightPower, vec3 fragNorm) {\n\n\t//vec3 xformLightPos = inverse(gl_ModelViewMatrix) * lightPos;\n\n\tvec3 lightDir = lightPos - v;\n\tfloat dist = length(lightDir);\n\tlightDir = normalize(lightDir);\n\tfloat NdotL = max(0.0, dot(fragNorm,lightDir));\n\t\t\t\n\tfloat attenuation = 1.0 / ( 1.0 +\t\t\t\t//\t constant attenuation\n\t\t\t\t\t\t\t\t0.002 * dist +\t\t//   linearAttenuation \n\t\t\t\t\t\t\t\t0.0002 * dist * dist   //   quadraticAttenuation\n\t\t\t\t\t\t\t\t);\n\treturn lightColor * lightPower * NdotL * attenuation;\n\n}\n\nvoid main(void)\n{\t\n\tvec3 norm = normalize(N);\t\n\tif(bAlphaMask) {\n\t\tvec4 maskMap = texture(texAlphaMask,uv);\n\t\t\n\t\tif(maskMap.r == 0.0) {\n\t\t\tdiscard;\n\t\t}\n\t}\n\t\n\t//vec4 spec = vec4(0.0);\n\t//vec4 ambient =  vec4(vec3(0.1),1.0);\n\t//vec4 albedo = vec4(0.6, 0.6,0.6,1.0);\n\n\t//vec4 LightDiffuse1 = vec4(1.0, 1.0, 1.0, 1.0);\n\t//vec3 LightPos1 = vec3 (40.0, 40.0, 40.0);\n\n\t//vec4 LightDiffuse2 = vec4(1.0, 1.0, 1.0, 1.0);\n\t//vec3 LightPos2 = vec3 (-80.0, 10.0, 10.0);\n\n\t//vec4 LightDiffuse3 = vec4(0.0, 0.9, 0.9, 1.0);\n\t//vec3 LightPos3 = vec3 (00.0, 00.0, -120.0);\n\n\t//vec4 Light1 = Light (LightPos1, LightDiffuse1, 3, norm);\n\t//vec4 Light2 = Light (LightPos2, LightDiffuse2, 2, norm);\n\t//vec4 Light3 = Light (LightPos3, LightDiffuse3, 3, norm);\n\n\t//fragColor = ambient + Light1 * albedo + Light2 * albedo + Light3 * albedo;\n\t//fragColor = vec4(0.8, 0.0, 0.0, 1.0);\n\t\n\tnormalMap = texture(texNormal,uv);\n\t\n\tmat3 normalMatrix = transpose(inverse(mat3(matView)));\n\tif(bModelSpace) {\n\t\tnorm = normalize(normalMap.rgb * 2.0 - 1.0);\n\t\tnorm.r = -norm.r;\n\t} \n\telse {\n\t\tnorm = normalMatrix * perturb_normal(inverse(normalMatrix) * norm, vPos);\n\t}\n\t//fragColor = normalMap;\n\tfragColor = vec4(NormalColor(norm) ,1.0);\n}"
  },
  {
    "path": "res/shaders/normalshade.vert",
    "content": "#version 330\nuniform mat4 matProjection;\nuniform mat4 matView;\nuniform vec3 color;\n\nuniform bool bLightEnabled;\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\n\nuniform bool bWireframe;\nuniform bool bLighting;\n\nlayout(location = 0) in vec3 vertexPosition;\nlayout(location = 1) in vec3 vertexNormal;\nlayout(location = 6) in vec2 vertexUV;\n\nout vec3 N;\nout vec3 v;\nout vec3 vPos;\nout vec2 uv;\n\nvoid main(void)\n{\n\tN = vertexNormal;\n\tvPos =  vec3(matView * vec4(vertexPosition, 1.0));\n\tv = vec3(matView * vec4(vertexUV, 0.0, 1.0));\n\t\n\tuv = vertexUV;\n\tgl_Position = matProjection * vec4(v, 1.0);\n}\n"
  },
  {
    "path": "res/shaders/ob_default.frag",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform sampler2D texDiffuse;\nuniform sampler2D texGlowmap;\n\nuniform bool bLightEnabled;\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\nuniform bool bWireframe;\n\nuniform bool bGlowmap;\n\nuniform mat4 matModelView;\n\nstruct Properties\n{\n\tvec2 uvOffset;\n\tvec2 uvScale;\n\tvec3 specularColor;\n\tfloat specularStrength;\n\tfloat shininess;\n\tfloat envReflection;\n\tvec3 emissiveColor;\n\tfloat emissiveMultiple;\n\tfloat alpha;\n\tfloat rimlightPower;\n\tfloat softlighting;\n};\nuniform Properties prop;\nuniform float alphaThreshold;\n\nuniform float ambient;\n\nstruct DirectionalLight\n{\n\tvec3 diffuse;\n\tvec3 direction;\n};\n\nuniform DirectionalLight frontal;\nuniform DirectionalLight directional0;\nuniform DirectionalLight directional1;\nuniform DirectionalLight directional2;\n\nin vec3 lightFrontal;\nin vec3 lightDirectional0;\nin vec3 lightDirectional1;\nin vec3 lightDirectional2;\n\nin vec3 viewDir;\nin mat3 mv_tbn;\n\nin float maskFactor;\nin vec3 weightColor;\n\nin vec4 vColor;\nin vec2 vUV;\n\nout vec4 fragColor;\n\nvec3 normal = vec3(0.0);\nfloat specFactor = 0.0;\n\nvec2 uv = vec2(0.0);\nvec3 albedo = vec3(0.0);\nvec3 emissive = vec3(0.0);\n\nvec4 baseMap = vec4(0.0);\n\nvec3 tonemap(in vec3 x)\n{\n\tconst float A = 0.15;\n\tconst float B = 0.50;\n\tconst float C = 0.10;\n\tconst float D = 0.20;\n\tconst float E = 0.02;\n\tconst float F = 0.30;\n\n\treturn ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;\n}\n\nvoid directionalLight(in DirectionalLight light, in vec3 lightDir, inout vec3 outDiffuse, inout vec3 outSpec)\n{\n\tvec3 halfDir = normalize(lightDir + viewDir);\n\tfloat NdotL = max(dot(normal, lightDir), 0.0);\n\tfloat NdotH = max(dot(normal, halfDir), 0.0);\n\tfloat NdotV = max(dot(normal, viewDir), 0.0);\n\n\toutDiffuse += ambient + NdotL * light.diffuse;\n\toutSpec += clamp(prop.specularColor * prop.specularStrength * specFactor * pow(NdotH, prop.shininess), 0.0, 1.0) * light.diffuse;\n}\n\nvoid main(void)\n{\n\tuv = vUV * prop.uvScale + prop.uvOffset;\n\tvec4 color = vColor;\n\talbedo = vColor.rgb;\n\n\tif (!bWireframe)\n\t{\n\t\tif (bShowTexture)\n\t\t{\n\t\t\t// Diffuse Texture\n\t\t\tbaseMap = texture(texDiffuse, uv);\n\t\t\talbedo *= baseMap.rgb;\n\t\t\tcolor.a *= baseMap.a;\n\n\t\t\t// Diffuse texture without lighting\n\t\t\tcolor.rgb = albedo;\n\t\t}\n\n\t\tif (bLightEnabled)\n\t\t{\n\t\t\t// Lighting with or without textures\n\t\t\tvec3 outDiffuse = vec3(0.0);\n\t\t\tvec3 outSpecular = vec3(0.0);\n\n\t\t\t// Start off neutral\n\t\t\tnormal = normalize(mv_tbn * vec3(0.0, 0.0, 0.5));\n\t\t\tspecFactor = 0.0;\n\n\t\t\tdirectionalLight(frontal, lightFrontal, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional0, lightDirectional0, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional1, lightDirectional1, outDiffuse, outSpecular);\n\t\t\tdirectionalLight(directional2, lightDirectional2, outDiffuse, outSpecular);\n\n\t\t\t// Emissive\n\t\t\temissive += prop.emissiveColor * prop.emissiveMultiple;\n\n\t\t\t// Glowmap\n\t\t\tif (bGlowmap)\n\t\t\t{\n\t\t\t\tvec4 glowMap = texture(texGlowmap, uv);\n\t\t\t\temissive *= glowMap.rgb;\n\t\t\t}\n\n\t\t\tcolor.rgb = albedo * (outDiffuse + emissive) + outSpecular;\n\t\t}\n\n\t\tif (bShowMask)\n\t\t{\n\t\t\tcolor.rgb *= maskFactor;\n\t\t}\n\n\t\tif (bShowWeight)\n\t\t{\n\t\t\tcolor.rgb *= weightColor;\n\t\t}\n\n\t\tcolor.rgb = tonemap(color.rgb) / tonemap(vec3(1.0));\n\t}\n\telse\n\t{\n\t\tcolor = vec4(color.rgb, 0.5);\n\t}\n\n\tcolor = clamp(color, 0.0, 1.0);\n\n\tfragColor = color;\n\n\tif (!bWireframe)\n\t{\n\t\tif (alphaThreshold != -1.0f)\n\t\t\tif (fragColor.a <= alphaThreshold) // GL_GREATER\n\t\t\t\tdiscard;\n\n\t\tfragColor.a *= prop.alpha;\n\t\tgl_FragDepth = gl_FragCoord.z;\n\t}\n\telse\n\t{\n\t\t// Minimal depth offset for wireframe to prevent z-fighting with its own mesh\n\t\tgl_FragDepth = gl_FragCoord.z - 0.00001f;\n\t}\n}\n"
  },
  {
    "path": "res/shaders/ob_default.vert",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform mat4 matProjection;\nuniform mat4 matView;\nuniform mat4 matModel;\nuniform mat4 matModelView;\nuniform mat3 mv_normalMatrix;\nuniform vec3 color;\nuniform vec3 subColor;\n\nuniform bool bShowTexture;\nuniform bool bShowMask;\nuniform bool bShowWeight;\nuniform bool bShowVertexColor;\nuniform bool bShowVertexAlpha;\n\nuniform bool bWireframe;\n\nlayout(location = 0) in vec3 vertexPosition;\nlayout(location = 1) in vec3 vertexNormal;\nlayout(location = 2) in vec3 vertexTangent;\nlayout(location = 3) in vec3 vertexBitangent;\nlayout(location = 4) in vec3 vertexColors;\nlayout(location = 5) in float vertexAlpha;\nlayout(location = 6) in vec2 vertexUV;\nlayout(location = 7) in float vertexMask;\nlayout(location = 8) in float vertexWeight;\n\nstruct DirectionalLight\n{\n\tvec3 diffuse;\n\tvec3 direction;\n};\n\nuniform DirectionalLight frontal;\nuniform DirectionalLight directional0;\nuniform DirectionalLight directional1;\nuniform DirectionalLight directional2;\n\nout vec3 lightFrontal;\nout vec3 lightDirectional0;\nout vec3 lightDirectional1;\nout vec3 lightDirectional2;\n\nout vec3 viewDir;\nout mat3 mv_tbn;\n\nout float maskFactor;\nout vec3 weightColor;\n\nout vec4 vColor;\nout vec2 vUV;\n\nvec3 colorRamp(in float value)\n{\n\tfloat r;\n\tfloat g;\n\tfloat b;\n\n\tif (value <= 0.0f)\n\t{\n\t\tr = g = b = 1.0;\n\t}\n\telse if (value <= 0.25)\n\t{\n\t\tr = 0.0;\n\t\tb = 1.0;\n\t\tg = value / 0.25;\n\t}\n\telse if (value <= 0.5)\n\t{\n\t\tr = 0.0;\n\t\tg = 1.0;\n\t\tb = 1.0 + (-1.0) * (value - 0.25) / 0.25;\n\t}\n\telse if (value <= 0.75)\n\t{\n\t\tr = (value - 0.5) / 0.25;\n\t\tg = 1.0;\n\t\tb = 0.0;\n\t}\n\telse\n\t{\n\t\tr = 1.0;\n\t\tg = 1.0 + (-1.0) * (value - 0.75) / 0.25;\n\t\tb = 0.0;\n\t}\n\n\treturn vec3(r, g, b);\n}\n\nvoid main(void)\n{\n\t// Initialization\n\tmaskFactor = 1.0;\n\tweightColor = vec3(1.0, 1.0, 1.0);\n\tvColor = vec4(1.0, 1.0, 1.0, 1.0);\n\tvUV = vertexUV;\n\n\tif (bShowVertexColor)\n\t{\n\t\tvColor.rgb = vertexColors;\n\t}\n\n\tif (bShowVertexAlpha)\n\t{\n\t\tvColor.a = vertexAlpha;\n\t}\n\n\t// Eye-coordinate position of vertex\n\tvec3 vPos = vec3(matModelView * vec4(vertexPosition, 1.0));\n\tgl_Position = matProjection * vec4(vPos, 1.0);\n\n\tvec3 mv_normal = mv_normalMatrix * vertexNormal;\n\tvec3 mv_tangent = mv_normalMatrix * vertexTangent;\n\tvec3 mv_bitangent = mv_normalMatrix * vertexBitangent;\n\n\tmv_tbn = mat3(mv_bitangent.x, mv_bitangent.y, mv_bitangent.z,\n\t\t\t\t  mv_tangent.x, mv_tangent.y, mv_tangent.z,\n\t\t\t\t  mv_normal.x, mv_normal.y, mv_normal.z);\n\n\tviewDir = normalize(-vPos);\n\tlightFrontal = normalize(frontal.direction);\n\tlightDirectional0 = normalize(mat3(matView) * directional0.direction);\n\tlightDirectional1 = normalize(mat3(matView) * directional1.direction);\n\tlightDirectional2 = normalize(mat3(matView) * directional2.direction);\n\n\tif (!bShowTexture || bWireframe)\n\t{\n\t\tvColor *= clamp(vec4(color, 1.0), 0.0, 1.0);\n\t}\n\n\tif (!bWireframe)\n\t{\n\t\tvColor.rgb *= subColor;\n\n\t\tif (bShowMask)\n\t\t{\n\t\t\tmaskFactor = 1.0 - vertexMask / 1.5;\n\t\t}\n\n\t\tif (bShowWeight)\n\t\t{\n\t\t\tweightColor = colorRamp(vertexWeight);\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "res/shaders/points.frag",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform mat4 matModel;\nuniform mat4 matView;\nuniform mat4 matModelViewInverse;\nuniform mat3 mv_normalMatrix;\n\nin vec3 viewDir;\nin vec3 n;\nin mat3 mv_tbn;\n\nin float maskFactor;\n\nin float vViewDepth;\nin vec4 vColor;\nin float pointVisible;\n\nout vec4 fragColor;\n\nvec3 normal = vec3(0.0);\n\nvoid main(void)\n{\n\tif (pointVisible < 0.5)\n\t\tdiscard;\n\n\t// Make round point\n\tif (dot(gl_PointCoord - 0.5, gl_PointCoord - 0.5) > 0.25)\n\t\tdiscard;\n\n\t// Only apply full bias when very close to the camera\n\tfloat depthBiasMax = 1e-3;\n\tfloat fadeStart = 0.1;   // where fading starts (same as znear)\n\tfloat fadeEnd = 15.0;    // where bias fully fades (15 world units away)\n\n\tfloat fadeFactor = clamp(1.0 - (vViewDepth - fadeStart) / (fadeEnd - fadeStart), 0.0, 1.0);\n\tfloat scaledBias = depthBiasMax * fadeFactor;\n\n\tgl_FragDepth = gl_FragCoord.z - scaledBias;\n\n\tvec4 color = vColor;\n\tcolor = clamp(color, 0.0, 1.0);\n\n\tfragColor = color;\n\n\t// Visualize scaled depth bias\n\t//fragColor = vec4(vec3(scaledBias * 1000.0), 1.0);\n}\n"
  },
  {
    "path": "res/shaders/points.vert",
    "content": "#version 330\n\n/*\n * BodySlide and Outfit Studio\n * Shaders by jonwd7 and ousnius\n * https://github.com/ousnius/BodySlide-and-Outfit-Studio\n * http://www.niftools.org/\n */\n\nuniform mat4 matProjection;\nuniform mat4 matView;\nuniform mat4 matModelView;\nuniform mat3 mv_normalMatrix;\nuniform vec3 color;\nuniform vec3 subColor;\nuniform bool bAdjustPointSize;\n\nlayout(location = 0) in vec3 vertexPosition;\nlayout(location = 1) in vec3 vertexNormal;\nlayout(location = 2) in vec3 vertexTangent;\nlayout(location = 3) in vec3 vertexBitangent;\nlayout(location = 4) in vec3 vertexColors;\nlayout(location = 5) in float vertexAlpha;\nlayout(location = 6) in vec2 vertexUV;\nlayout(location = 7) in float vertexMask;\nlayout(location = 8) in float vertexWeight;\n\nout vec3 viewDir;\nout vec3 n;\nout mat3 mv_tbn;\n\nout float maskFactor;\n\nout vec4 vColor;\nout vec2 vUV;\nout float pointVisible;\nout float vViewDepth;\n\n\nvoid main(void)\n{\n\t// Initialization\n\tmaskFactor = 1.0;\n\tvColor = vec4(1.0, 1.0, 1.0, 1.0);\n\tvUV = vertexUV;\n\n\t// Eye-coordinate position of vertex\n\tvec3 vPos = vec3(matModelView * vec4(vertexPosition, 1.0));\n\tvViewDepth = -vPos.z; // positive depth (camera looks down -Z)\n\n\tgl_Position = matProjection * vec4(vPos, 1.0);\n\n\tif (bAdjustPointSize)\n\t\tgl_PointSize = clamp(30.0 / vViewDepth, 2.0, 12.0); // Shrinks with distance\n\n\tn = vertexNormal;\n\n\tvec3 mv_normal = mv_normalMatrix * n;\n\tvec3 mv_tangent = mv_normalMatrix * vertexTangent;\n\tvec3 mv_bitangent = mv_normalMatrix * vertexBitangent;\n\n\tmv_tbn = mat3(mv_bitangent.x, mv_bitangent.y, mv_bitangent.z,\n\t\t\t\t\t   mv_tangent.x, mv_tangent.y, mv_tangent.z,\n\t\t\t\t\t   mv_normal.x, mv_normal.y, mv_normal.z);\n\n\tviewDir = normalize(-vPos);\n\tpointVisible = step(0.0, dot(mv_normal, viewDir)); // 1 if front-facing, 0 if back\n\n\tif (vertexMask > 0.0)\n\t{\n\t\tvColor = vec4(subColor.rgb, 0.5);\n\t}\n\telse\n\t{\n\t\tvColor = vec4(color.rgb, 0.5);\n\t}\n}\n"
  },
  {
    "path": "res/shaders/primitive.frag",
    "content": "#version 330\n\nstruct Properties\n{\n\tfloat alpha;\n};\nuniform Properties prop;\n\nin vec4 vertexColor;\nout vec4 fragColor;\n\nvoid main(void)\n{\n\tvec4 color = vertexColor;\n\n\tcolor.a *= prop.alpha;\n\tcolor = clamp(color, 0.0, 1.0);\n\n\tfragColor = color;\n}\n"
  },
  {
    "path": "res/shaders/primitive.vert",
    "content": "#version 330\nuniform mat4 matProjection;\nuniform mat4 matModelView;\nuniform vec3 color = vec3(1.0);\n\nuniform bool bShowVertexColor;\n\nlayout(location = 0) in vec3 vertexPosition;\nlayout(location = 4) in vec3 vertexColors;\n\nout vec4 vertexColor;\n\nvoid main(void)\n{\n\t// Eye-coordinate position of vertex\n\tvec3 pos = vec3(matModelView * vec4(vertexPosition, 1.0));\n\tgl_Position = matProjection * vec4(pos, 1.0);\n\n\tif (bShowVertexColor)\n\t{\n\t\tvertexColor = vec4(vertexColors, 1.0);\n\t}\n\telse\n\t{\n\t\tvertexColor = vec4(color, 1.0);\n\t}\n\n\tvertexColor = clamp(vertexColor, 0.0, 1.0);\n}\n"
  },
  {
    "path": "res/xrc/About.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgAbout\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX</style>\n\t\t<title>About</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxHtmlWindow\" name=\"htmlAbout\">\n\t\t\t\t\t<style>wxHW_SCROLLBAR_AUTO</style>\n\t\t\t\t\t<htmlcode translate=\"0\">\n<![CDATA[<center>\n<b>BodySlide and Outfit Studio</b><br>\n<font size=\"2\">Copyright(C) 2026  Caliente & ousnius<br><br>\n\n<i>This program is free software: you can redistribute it and/or modify<br>\nit under the terms of the GNU General Public License as published by<br>\nthe Free Software Foundation, either version 3 of the License, or<br>\n(at your option) any later version.<br><br>\n\nThis program is distributed in the hope that it will be useful,<br>\nbut WITHOUT ANY WARRANTY; without even the implied warranty of<br>\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the<br>\nGNU General Public License for more details.<br><br>\n\nYou should have received a copy of the GNU General Public License<br>\nalong with this program.  If not, see <a href=\"http://www.gnu.org/licenses/\">http://www.gnu.org/licenses/</a>.<br><br></i></font>\n\n<b>wxWidgets</b><br><br><font size=\"2\">wxWindows License<br><a href=\"http://www.wxwidgets.org/\">http://www.wxwidgets.org/</a></font><br><br><br>\n\n<b>OpenGL</b><br><font size=\"2\"><a href=\"http://www.opengl.org/\">http://www.opengl.org/</a></font><br><br><br>\n\n<b>OpenGL Image (GLI)</b><br><font size=\"2\">MIT License<br><a href=\"http://gli.g-truc.net/\">http://gli.g-truc.net/</a></font><br><br><br>\n\n<b>Simple OpenGL Image Libary 2 (SOIL2)</b><br><font size=\"2\">Public Domain<br><a href=\"https://bitbucket.org/SpartanJ/soil2\">https://bitbucket.org/SpartanJ/soil2</a><br><a href=\"http://lonesock.net/soil.html\">http://lonesock.net/soil.html</a></font><br><br><br>\n\n<b>Autodesk® FBX®</b><br><font size=\"2\">This software contains Autodesk® FBX® code developed by Autodesk, Inc.<br>\nCopyright 2014 Autodesk, Inc. All rights, reserved.<br><br>\n<i>Such code is provided “as is” and Autodesk, Inc. disclaims<br>\nany and all warranties, whether express or implied, including<br>\nwithout limitation the implied warranties of merchantability,<br>\nfitness for a particular purpose or non-infringement<br>\nof third party rights. In no event shall Autodesk, Inc.<br>\nbe liable for any direct, indirect, incidental, special,<br>\nexemplary, or consequential damages (including,<br>\nbut not limited to, procurement of substitute goods or services;<br>\nloss of use, data, or profits; or business interruption)<br>\nhowever caused and on any theory of liability, whether in contract,<br>\nstrict liability, or tort (including negligence or otherwise)<br>\narising in any way out of such code.</i></font><br><br><br>\n\n<b>TinyXML-2</b><br><br><font size=\"2\">zlib License<br>Original code by Lee Thomason (<a href=\"http://www.grinninglizard.com\">http://www.grinninglizard.com/</a>)<br><br>\n<i>This software is provided 'as-is', without any express or implied<br>\nwarranty. In no event will the authors be held liable for any<br>\ndamages arising from the use of this software.<br><br>\nPermission is granted to anyone to use this software for any<br>\npurpose, including commercial applications, and to alter it and<br>\nredistribute it freely, subject to the following restrictions:<br><br>\n1. The origin of this software must not be misrepresented; you must<br>\nnot claim that you wrote the original software. If you use this<br>\nsoftware in a product, an acknowledgment in the product documentation<br>\nwould be appreciated but is not required.<br><br>\n2. Altered source versions must be plainly marked as such, and<br>\nmust not be misrepresented as being the original software.<br><br>\n3. This notice may not be removed or altered from any source<br>\ndistribution.</i></font><br><br><br>\n\n<b>half - IEEE 754-based half-precision floating point library</b><br><font size=\"2\">Copyright (c) 2012-2017 Christian Rau (rauy@users.sourceforge.net)<br><br>\n<i>Permission is hereby granted, free of charge, to any person<br>\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"),<br>\n to deal in the Software without restriction,<br>\n including without limitation the rights to use, copy,<br>\nmodify, merge, publish, distribute, sublicense,<br>\nand/or sell copies of the Software, and to permit persons to whom the<br>\nSoftware is furnished to do so, subject to the following conditions:<br><br>\nThe above copyright notice and this permission notice shall be included<br>\nin all copies or substantial portions of the Software.<br><br>\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,<br>\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE<br>\nWARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE<br>\nAND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR<br>\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,<br>\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE<br>\nOR THE USE OR OTHER DEALINGS IN THE SOFTWARE.</i></font><br><br><br>\n\n<b>Miniball - Smallest Enclosing Balls of Points</b><br><br><font size=\"2\">GPLv3 License<br>Copyright (C) 1999-2013, Bernd Gärtner, ETH Zürich (<a href=\"http://www.inf.ethz.ch/personal/gaertner\">Contact</a>)</font><br><br><br>\n\n<b>fsengine (BSA Library)</b><br><br><font size=\"2\">BSD License<br>Copyright (c) 2005-2012, <a href=\"http://niftools.sourceforge.net/\">NIF File Format Library and Tools</a><br>Modified by ousnius.<br>All rights reserved.<br><br>\n<i>Redistribution and use in source and binary forms, with or without<br>\nmodification, are permitted provided that the following conditions are met:<br>\n1. Redistributions of source code must retain the above copyright<br>\nnotice, this list of conditions and the following disclaimer.<br>\n2. Redistributions in binary form must reproduce the above copyright<br>\nnotice, this list of conditions and the following disclaimer in the<br>\ndocumentation and/or other materials provided with the distribution.<br>\n3. The name of the NIF File Format Library and Tools project may not be<br>\nused to endorse or promote products derived from this software<br>\nwithout specific prior written permission.<br><br>\nTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR<br>\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES<br>\nOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.<br>\nIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,<br>\nINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT<br>\nNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,<br>\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF<br>\nTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</i></font><br><br><br>\n\n<b>LZ4 auto-framing library</b><br><br><font size=\"2\">BSD License<br>Copyright (c) 2011-2016 (<a href=\"http://www.lz4.org/\">http://www.lz4.org/</a>)<br><br>\n<i>Redistribution and use in source and binary forms, with or without<br>\nmodification, are permitted provided that the following conditions are met:<br><br>\n* Redistributions of source code must retain the above copyright<br>\nnotice, this list of conditions and the following disclaimer.<br>\n* Redistributions in binary form must reproduce the above<br>\ncopyright notice, this list of conditions and the following disclaimer<br>\nin the documentation and/or other materials provided with the distribution.<br><br>\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS<br>\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT<br>\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR<br>\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT<br>\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,<br>\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT<br>\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,<br>\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY<br>\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE<br>\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</i></font><br><br><br>\n\n<b>nlohmann json</b><br><br><font size=\"2\">MIT License<br>Copyright (c) 2013-2026 Niels Lohmann (<a href=\"https://github.com/nlohmann/json\">https://github.com/nlohmann/json</a>)<br><br>\n<i>Permission is hereby granted, free of charge, to any person obtaining a copy<br>\nof this software and associated documentation files (the \"Software\"), to deal<br>\nin the Software without restriction, including without limitation the rights<br>\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell<br>\ncopies of the Software, and to permit persons to whom the Software is<br>\nfurnished to do so, subject to the following conditions:<br><br>\nThe above copyright notice and this permission notice shall be included in all<br>\ncopies or substantial portions of the Software.<br><br>\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE<br>\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,<br>\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br>\nSOFTWARE.</i></font><br><br><br>\n\n<b>fkYAML</b><br><br><font size=\"2\">MIT License<br>Copyright (c) 2023-2025 Kensuke Fukutani (<a href=\"https://github.com/fktn-k/fkYAML\">https://github.com/fktn-k/fkYAML</a>)<br><br>\n<i>Permission is hereby granted, free of charge, to any person obtaining a copy<br>\nof this software and associated documentation files (the \"Software\"), to deal<br>\nin the Software without restriction, including without limitation the rights<br>\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell<br>\ncopies of the Software, and to permit persons to whom the Software is<br>\nfurnished to do so, subject to the following conditions:<br><br>\nThe above copyright notice and this permission notice shall be included in all<br>\ncopies or substantial portions of the Software.<br><br>\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR<br>\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,<br>\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE<br>\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,<br>\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE<br>\nSOFTWARE.</i></font><br><br><br>\n</center>]]>\n\t\t\t\t\t</htmlcode>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t<size>-1,30</size>\n\t\t\t\t\t<label>Close</label>\n\t\t\t\t\t<default>0</default>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/Actions.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgMoveVertex\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>423,155</size>\n\t\t<title>Apply a vertex position</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText32\">\n\t\t\t\t\t<label>This permanently moves a single vertex straight to the given location.</label>\n\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText3\">\n\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"posX\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText4\">\n\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"posY\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText5\">\n\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"posZ\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgMoveShape\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>414,169</size>\n\t\t<title>Move Shape</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"msLabelX\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"msSliderX\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-25000</min>\n\t\t\t\t\t\t\t\t\t<max>25000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"msTextX\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"msLabelY\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"msSliderY\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-25000</min>\n\t\t\t\t\t\t\t\t\t<max>25000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"msTextY\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"msLabelZ\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"msSliderZ\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-25000</min>\n\t\t\t\t\t\t\t\t\t<max>25000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"msTextZ\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"mirrorAxisLabel\">\n\t\t\t\t\t<label>Mirror Axis</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"mirrorAxisX\">\n\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"mirrorAxisY\">\n\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"mirrorAxisZ\">\n\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t\n\t<object class=\"wxDialog\" name=\"dlgScaleShape\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>423,250</size>\n\t\t<title>Scale Shape</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"ssDescription\">\n\t\t\t\t\t<label>Scaling will adjust the size of a mesh. This permanently affects vertices.</label>\n\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"ssLabelX\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"ssSliderX\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1000</value>\n\t\t\t\t\t\t\t\t\t<min>10</min>\n\t\t\t\t\t\t\t\t\t<max>3000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"ssTextX\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"ssLabelY\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"ssSliderY\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1000</value>\n\t\t\t\t\t\t\t\t\t<min>10</min>\n\t\t\t\t\t\t\t\t\t<max>3000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"ssTextY\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"ssLabelZ\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"ssSliderZ\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1000</value>\n\t\t\t\t\t\t\t\t\t<min>10</min>\n\t\t\t\t\t\t\t\t\t<max>3000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"ssTextZ\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"originLabel\">\n\t\t\t\t\t\t\t\t\t<label>Origin</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"origin\">\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t<item>Zero (0, 0, 0)</item>\n\t\t\t\t\t\t\t\t\t\t<item>Center of selected shapes(s)</item>\n\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"ssUniform\">\n\t\t\t\t\t\t\t<label>Uniform (XYZ)</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"button\">\n\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t\n\t<object class=\"wxDialog\" name=\"dlgRotateShape\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>423,155</size>\n\t\t<title>Rotate Shape</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rsLabelX\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"rsSliderX\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-18000</min>\n\t\t\t\t\t\t\t\t\t<max>18000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"rsTextX\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rsLabelY\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"rsSliderY\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-18000</min>\n\t\t\t\t\t\t\t\t\t<max>18000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"rsTextY\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rsLabelZ\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"rsSliderZ\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-18000</min>\n\t\t\t\t\t\t\t\t\t<max>18000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"rsTextZ\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"originLabel\">\n\t\t\t\t\t\t\t<label>Origin</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"origin\">\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t<item>Zero (0, 0, 0)</item>\n\t\t\t\t\t\t\t\t<item>Center of selected shapes(s)</item>\n\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t\n\t<object class=\"wxDialog\" name=\"dlgInflateShape\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>423,250</size>\n\t\t<title>Inflate Shape</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"ssDescription\">\n\t\t\t\t\t<label>Inflate/deflate a mesh along its normals. This permanently affects vertices.</label>\n\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"isLabelX\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"isSliderX\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-10000</min>\n\t\t\t\t\t\t\t\t\t<max>10000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"isTextX\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"isLabelY\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"isSliderY\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-10000</min>\n\t\t\t\t\t\t\t\t\t<max>10000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"isTextY\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"isLabelZ\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"isSliderZ\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-10000</min>\n\t\t\t\t\t\t\t\t\t<max>10000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"isTextZ\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"isUniform\">\n\t\t\t\t\t\t\t<label>Uniform (XYZ)</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"button\">\n\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\n\t<object class=\"wxDialog\" name=\"dlgMirrorShape\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>414,169</size>\n\t\t<title>Mirror Shape</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"mirrorAxisX\">\n\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"mirrorAxisY\">\n\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"mirrorAxisZ\">\n\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCheckBox\" name=\"swapBonesX\">\n\t\t\t\t\t<label>Swap bones on X axis (L/R)</label>\n\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t<checked>0</checked>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\n\t<object class=\"wxDialog\" name=\"dlgSmoothSeams\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>414,169</size>\n\t\t<title>Smooth Seams</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"angleLabel\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Angle Threshold (degrees)</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"angleSlider\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">6000</value>\n\t\t\t\t\t\t\t\t\t<min>10</min>\n\t\t\t\t\t\t\t\t\t<max>17900</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"angleText\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">60.00</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\n\t<object class=\"wxDialog\" name=\"dlgShapeTextures\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>457,308</size>\n\t\t<title>Set Shape Textures</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxGrid\" name=\"stTexGrid\">\n\t\t\t\t\t<style>wxALWAYS_SHOW_SB</style>\n\t\t\t\t\t<size>800,260</size>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND | wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticLine\" name=\"m_staticline2\">\n\t\t\t\t\t<style>wxLI_HORIZONTAL</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgConforming\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>414,169</size>\n\t\t<title>Conforming...</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"conformingDescription\">\n\t\t\t\t\t<label>Each vertex of the reference will copy its slider data to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become conformed and work well. Often, the default values are sufficient.</label>\n\t\t\t\t\t<wrap>550</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols></growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"proximityRadiusLabel\">\n\t\t\t\t\t\t\t<label>Search Radius</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxSlider\" name=\"proximityRadiusSlider\">\n\t\t\t\t\t\t\t<value translate=\"0\">10000</value>\n\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t<max>20000</max>\n\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"proximityRadiusText\">\n\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t<value translate=\"0\">10.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"maxResultsLabel\">\n\t\t\t\t\t\t\t<label>Max Vertex Targets</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxSlider\" name=\"maxResultsSlider\">\n\t\t\t\t\t\t\t<value translate=\"0\">10</value>\n\t\t\t\t\t\t\t<min>1</min>\n\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"maxResultsText\">\n\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t<value translate=\"0\">10</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"noTargetLimitLabel\">\n\t\t\t\t\t\t\t<label>No Target Limit</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"noTargetLimit\">\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"noSqueezeLabel\">\n\t\t\t\t\t\t\t<label>No Squeeze</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"noSqueeze\">\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"solidModeLabel\">\n\t\t\t\t\t\t\t<label>Solid Mode</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"solidMode\">\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"axisLabel\">\n\t\t\t\t\t\t\t<label>Axis</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"axisX\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"axisY\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"axisZ\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"preset\">\n\t\t\t\t\t\t\t<label>Preset</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"presetDefault\">\n\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t<label>Default</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"presetEvenMovement\">\n\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t<label>Even Movement</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"presetSolidObject\">\n\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t<label>Solid Object</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgCopyGeometry\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>414,169</size>\n\t\t<title>Merge Geometry</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"copyGeometryDescription\">\n\t\t\t\t\t<label>This function copies vertices and triangles from one shape to another.  Partitions/segments of source and target shapes must match.  It is the user's responsibility to check that all other shape and shader properties are compatible, or merging will likely have side effects.</label>\n\t\t\t\t\t<wrap>550</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"sourceLabel\">\n\t\t\t\t\t\t\t<label>Source</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"sourceChoice\">\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"targetLabel\">\n\t\t\t\t\t\t\t<label>Target</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"targetChoice\">\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"copyGeometryErrors\">\n\t\t\t\t\t<label></label>\n\t\t\t\t\t<wrap>550</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCheckBox\" name=\"checkDeleteSource\">\n\t\t\t\t\t<label>Delete source shape</label>\n\t\t\t\t\t<checked>1</checked>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgVertexAsym\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>423,155</size>\n\t\t<title>Mask symmetric vertices</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"maskSymmetricVerticesDescription\">\n\t\t\t\t\t<label>Masks all vertices that do not have any of the selected asymmetries.</label>\n\t\t\t\t\t<wrap>600</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"currentUnmaskedLabel\">\n\t\t\t\t\t\t\t<label>Vertices currently unmasked:</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"currentUnmaskedText\">\n\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"checkUnmatched\">\n\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"unmatchedVerticesLabel\">\n\t\t\t\t\t\t\t<label>Unmatched Vertices:</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"unmatchedVerticesText\">\n\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Vertex Data Asymmetries</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<minsize>600,400</minsize>\n\t\t\t\t\t\t<object class=\"wxScrolledWindow\" name=\"asymScroll\">\n\t\t\t\t\t\t\t<style>wxVSCROLL</style>\n\t\t\t\t\t\t\t<scrollrate>5,5</scrollrate>\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t<cols>4</cols>\n\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"typeHeading\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Type</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>20</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"avgHeading\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Average</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"countHeading\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Count</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"checkPosition\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"positionLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Position</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>20</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"posAvgText\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"positionText\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"checkAnySlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCHK_3STATE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"anySliderLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">x Sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"anySliderText\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"slidersCollapse\">\n\t\t\t\t\t\t\t\t\t\t<style>wxCP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t<label>Sliders</label>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"checkAnyBone\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCHK_3STATE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"anyBoneLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">x Bones</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"anyBoneText\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"bonesCollapse\">\n\t\t\t\t\t\t\t\t\t\t<style>wxCP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t<label>Bones</label>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"stillUnmaskedLabel\">\n\t\t\t\t\t\t\t<label>Vertices that will still be unmasked:</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_RIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<minsize>100,20</minsize>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"stillUnmaskedText\">\n\t\t\t\t\t\t\t<label translate=\"0\">0</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t<style>wxALIGN_RIGHT</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;Mask</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/Automation.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgAutomation\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX</style>\n\t\t<title>Automation Script</title>\n\t\t<centered>1</centered>\n\t\t<size>900,650</size>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\n\t\t\t<!-- Toolbar -->\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Automation:</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxComboBox\" name=\"cmbAutomation\">\n\t\t\t\t\t\t\t<tooltip>Select an automation to load, or type a name for a new one</tooltip>\n\t\t\t\t\t\t\t<hint>Automation name...</hint>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnSaveScript\">\n\t\t\t\t\t\t\t<label>Save</label>\n\t\t\t\t\t\t\t<tooltip>Save the automation script</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnDeleteScript\">\n\t\t\t\t\t\t\t<label>Delete</label>\n\t\t\t\t\t\t\t<tooltip>Delete the current automation script</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnOpenFolder\">\n\t\t\t\t\t\t\t<label>Open Folder</label>\n\t\t\t\t\t\t\t<tooltip>Open the Automations folder in file explorer</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\n\t\t\t<!-- Main splitter area -->\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\n\t\t\t\t\t<!-- Left: Step list -->\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxListCtrl\" name=\"listSteps\">\n\t\t\t\t\t\t\t<style>wxLC_REPORT|wxLC_SINGLE_SEL</style>\n\t\t\t\t\t\t\t<size>350,-1</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\n\t\t\t\t\t<!-- Right: Step details -->\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxPanel\" name=\"panelStepSettings\">\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\n\t\t\t\t\t\t\t\t<!-- Common fields -->\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t<label>Step Settings</label>\n\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Type:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceStepType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Bones: Add Custom Bone</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Bones: Copy Bone Weights</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Bones: Delete Bones</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Bones: Edit Custom Bone</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Bones: Remove Skinning</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Export: File</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Export: Save Project</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Import: File</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Import: Slider Data</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Project: Add Project</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Project: Clear Project</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Project: Clear Reference</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Project: Load Reference</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Project: Set Base Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Project: Set Reference Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Apply Pose</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Delete Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Duplicate Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Fix Bad Bones</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Fix Clipping</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Invert UVs</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Mirror Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Refine Mesh</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Rename Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Reset Transforms</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes: Transform Shape</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Sliders: Conform Sliders</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Sliders: Delete Slider</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Sliders: Set Slider Values</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Sliders: Set Slider Properties</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Masks: Clear Mask</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Masks: Load Mask</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Nodes: Remove Unused Nodes</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Active:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkActive\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Execute this step</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Target Shapes:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtTargetMeshes\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of shape names. Leave empty to target all shapes.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated shape list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddTargetMesh\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>+</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>24,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Add shapes from list</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkTargetRegex\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Regex</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Use regex matching for target shape names</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Note:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtNote\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_MULTILINE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,50</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>A note to describe what this step does and how to configure it.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Description of this step...</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t<!-- Type-specific panels in a simplebook -->\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxSimplebook\" name=\"bookStepPages\">\n\n\t\t\t\t\t\t\t\t\t\t<!-- AddCustomBone -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<selected>1</selected>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageAddCustomBone\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Add Custom Bone</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Bone Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Bone name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Parent Bone:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneParent\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the parent bone (leave empty for no parent)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Parent bone name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Translation:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneTransX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">X</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneTransY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Y</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneTransZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Z</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotation:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneRotX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">X</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneRotY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Y</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtAddBoneRotZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Z</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- CopyBoneWeights -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageCopyBoneWeights\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Copy Bone Weights</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Proximity Radius:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtWeightRadius\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">10.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">10.0</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Max Results:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtWeightMaxResults\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">10</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">10</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Bone List:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtWeightBoneList\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of bone names. Leave empty to copy all bones.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated bone list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- DeleteBones -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageDeleteBones\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Delete Bones</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Bone Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtDeleteBoneNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of bone names to delete</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated bone list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mode:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkDeleteBoneFromProject\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Delete bone entirely from project</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>If checked, deletes the bone from all shapes and the NIF. If unchecked, only removes bone weights from target shapes.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- EditBone -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageEditBone\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Edit Bone</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Bone Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the custom bone to edit</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Bone name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Parent Bone:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneParent\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the parent bone (leave empty for no parent)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Parent bone name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Translation:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneTransX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">X</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneTransY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Y</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneTransZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Z</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotation:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneRotX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">X</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneRotY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Y</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtEditBoneRotZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip translate=\"0\">Z</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- RemoveSkinning -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageRemoveSkinning\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Remove Skinning</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Removes skinning from target shapes (or all shapes if Target Meshes is empty).\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tThis deletes all bone weights and skinning data from the shapes.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ExportFile -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageExportFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Export File</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblExportPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Export File Path:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpExportFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select export file path</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wildcard>NIF Files (*.nif)|*.nif|OBJ Files (*.obj)|*.obj|FBX Files (*.fbx)|*.fbx|OSD Files (*.osd)|*.osd|TRI Files (*.tri)|*.tri|All Files (*.*)|*.*</wildcard>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxFLP_SAVE|wxFLP_USE_TEXTCTRL|wxFLP_OVERWRITE_PROMPT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpExportFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select export folder</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxDIRP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkExportUseOriginalPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Use original file path from batch operation</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkExportWithRef\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Export with reference shape (.nif only)</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Filename Prefix:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtExportPrefix\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Prefix to add before the filename. Supports {{PLACEHOLDER}} variables.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>e.g. prefix_</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Filename Suffix:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtExportSuffix\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Suffix to add after the filename before the extension. Supports {{PLACEHOLDER}} variables.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>e.g. _suffix</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- SaveProject -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageSaveProject\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Save Project</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSaveUseOriginal\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Use original project from batch</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"panelSaveOriginalFields\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Display Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveDisplayName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name shown in BodySlide (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Display name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Output File Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveOutputFileName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Base filename for the output NIF (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Output filename</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Output Data Path:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveOutputDataPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Game data path for output (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">meshes\\...</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Set File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveSliderSetFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Slider set project file (.osp) (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">SliderSets\\file.osp</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shape Data Folder:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveShapeDataFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Folder for slider data files (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">ShapeData\\folder</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shape Data File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveShapeDataFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Base NIF filename (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">filename.nif</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSaveGenWeights\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Generate low/high weight outputs</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSaveAutoCopyRef\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Copy reference to output</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"panelSaveBatchFields\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Replace (from):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveReplaceFrom\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Text to find and replace in original project fields (batch only)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Find text</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Replace (to):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveReplaceTo\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Replacement text for matching text in original project fields (batch only)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Replace with</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Suffix:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveSuffix\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Suffix to append to Display Name, Shape Data Folder, and Shape Data File name (batch only)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>e.g. _modified</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSaveCopyRefFromProject\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Copy reference based on loaded project</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>If the loaded project had a reference shape, include it in the output. Otherwise, exclude it. Overrides the option above. (batch only)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSaveCopyRefShapeName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Only treat these shape names as the reference (comma-separated). Leave empty to use any reference shape.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated shape list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ImportFile -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageImportFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Import File</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mode:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkImportFromFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Import all files from folder</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblImportFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpImportFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select file to import</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wildcard>NIF Files (*.nif)|*.nif|OBJ Files (*.obj)|*.obj|FBX Files (*.fbx)|*.fbx|All Files (*.*)|*.*</wildcard>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblImportFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Folder:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpImportFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select folder to import from</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ImportSliderData -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageImportSliderData\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Import Slider Data</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mode:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSliderDataFromFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Import all files from folder (ShapeName#SliderName.ext)</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblSliderDataFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Data File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpSliderDataFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select slider data file</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wildcard>Slider Data Files (*.osd;*.bsd)|*.osd;*.bsd|All Files (*.*)|*.*</wildcard>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblSliderDataFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Folder:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpSliderDataFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select folder with slider data files</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSliderMerge\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Merge into existing sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSliderNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of slider names. Leave empty to import all sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated slider list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- AddProject -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageAddProject\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Add Project</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Source File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpAddProjSourceFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select project file</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wildcard>Slider Set Files (*.osp;*.xml)|*.osp;*.xml|All Files (*.*)|*.*</wildcard>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Set:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceAddProjSet\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the slider set to add</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkAddProjAppendSliders\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Append new sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ClearProject -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageClearProject\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Clear Project</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Clears the current project (removes all shapes, sliders, and references).\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo additional parameters needed.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ClearReference -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageClearReference\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Clear Reference</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Removes the current reference/base shape from the project. Slider data for the reference is moved to the morpher.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNo additional parameters needed.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- LoadReference -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageLoadReference\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Load Reference</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Template:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceRefTemplate\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Select a reference template to auto-fill the fields below</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Source File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpRefSourceFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select reference file</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wildcard>Slider Set Files (*.osp;*.xml)|*.osp;*.xml|NIF Files (*.nif)|*.nif|All Files (*.*)|*.*</wildcard>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Set:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceRefSet\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the slider set within the source file</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shape:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceRefShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the reference shape</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkRefLoadAll\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Load all shapes</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkRefMergeSliders\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Merge sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkRefMergeZaps\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Merge zaps</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkRefAppendNewSliders\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Append new sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- SetBaseShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageSetBaseShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Set Base Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Bakes the current slider values into the base geometry of all shapes and zeros all sliders.\n\nEquivalent to \"Slider -> Set Base Shape\" in the menu.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- SetReferenceShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageSetReferenceShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Set Reference Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shape Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSetRefShapeName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the shape to set as reference (highlighted green).</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Shape name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSetRefUnset\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Unset Reference</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Unset the reference shape instead of setting one. Morph data will be moved.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ApplyPose -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageApplyPose\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Apply Pose</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Pose Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtPoseName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name of the pose from PoseData to apply to meshes</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Pose name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- DeleteShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageDeleteShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Delete Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Deletes the shapes specified in the Target Meshes field above.\n\nIf Target Meshes is empty, all non-reference shapes are deleted. Use Regex mode for pattern matching.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- DuplicateShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageDuplicateShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Duplicate Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>New Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtDupNewName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Name for the duplicated shape. Supports {{PLACEHOLDER}} variables.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>New shape name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- FixBadBones -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageFixBadBones\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Fix Bad Bones</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Fixes bones with inconsistent NIF transforms by applying recommended corrections automatically.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- FixClipping -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageFixClipping\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Fix Clipping</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mode:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceFixClipMode\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Shapes</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Sliders</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Shapes: fix base geometry of target shapes. Sliders: fix clipping for each slider individually.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Strength (0 - 100):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtFixClipStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">50</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Clipping fix strength between 0 and 100.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">0-100</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblFixClipSliderNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtFixClipSliderNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of slider names to fix clipping for (Sliders mode only). Leave empty to process all non-zap/non-UV sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated slider list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddFixClipSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>+</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>24,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Add sliders from list</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- InvertUVs -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageInvertUVs\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Invert UVs</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkInvertU\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Invert U</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkInvertV\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Invert V</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- MirrorShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageMirrorShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mirror Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkMirrorX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mirror X</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkMirrorY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mirror Y</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkMirrorZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mirror Z</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkMirrorSwapBonesX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Swap bones left/right (X axis)</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- RefineMesh -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageRefineMesh\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Refine Mesh</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Subdivides/refines meshes by splitting edges.\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tAll unmasked vertices are refined. Use the Target Meshes field above to select which shapes to refine.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- RenameShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageRenameShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rename Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Old Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtRenameOldName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Current name of the shape (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Current shape name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>New Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtRenameNewName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>New name for the shape (supports {{PLACEHOLDER}} variables)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>New shape name</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ResetTransforms -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageResetTransforms\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Reset Transforms</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Resets global-to-skin transforms for all skinned meshes. No additional parameters needed.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>400</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- TransformShape -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageTransformShape\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Transform Shape</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>4</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>5</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1,2,3</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Move:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtMoveX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Move X</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtMoveY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Move Y</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtMoveZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Move Z</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotate (Ã‚Â°):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtRotateX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Rotate X (degrees)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtRotateY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Rotate Y (degrees)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtRotateZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Rotate Z (degrees)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Scale:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtScaleX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Scale X</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtScaleY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Scale Y</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtScaleZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Scale Z</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Inflate:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtInflateX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Inflate X (along normals)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">X</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtInflateY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Inflate Y (along normals)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Y</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtInflateZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Inflate Z (along normals)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">Z</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ConformSliders -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageConformSliders\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Conform Sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Proximity Radius:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtConformRadius\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">10.0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">10.0</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Max Results:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtConformMaxResults\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">10</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">10</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConformNoSqueeze\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>No squeeze</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConformSolidMode\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Solid mode</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Axes:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>10</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConformAxisX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>X</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>10</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConformAxisY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Y</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConformAxisZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Z</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtConformSliderNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of slider names to conform. Leave empty to conform all visible sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated slider list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddConformSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>+</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>24,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Add sliders from list</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- DeleteSlider -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageDeleteSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Delete Slider</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtDeleteSliderName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of slider names to delete. If regex is checked, the text is used as a single regex pattern.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated slider list or pattern</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddDeleteSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>+</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>24,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Add sliders from list</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Regex:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkDeleteSliderRegex\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Match slider names by regex pattern</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- SetSliderValues -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageSetSliderValues\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Set Slider Values</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSetSliderNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of slider names. Leave empty to set all visible sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated slider list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddSetSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>+</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>24,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Add sliders from list</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Value (0 - 100):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSetSliderValue\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">100</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Slider value between 0 and 100 (percentage)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">0-100</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- SetSliderProperties -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageSetSliderProperties\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Set Slider Properties</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_TOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Names:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSliderPropNames\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Comma-separated list of slider names. Leave empty to apply to all sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Comma-separated slider list</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddSliderProp\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>+</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>24,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Add sliders from list</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Zap:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceSliderPropZap\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>No change</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>No</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Yes</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Set the zap flag on matching sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Hidden:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceSliderPropHidden\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>No change</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>No</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Yes</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Set the hidden flag on matching sliders.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblSliderPropZapped\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Default Zapped:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceSliderPropZapped\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>No change</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Not zapped</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Zapped</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Whether matching zap sliders are zapped by default.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblSliderPropDefaultLo\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Default (Small):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSliderPropDefaultLo\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Default small value (0-100). Leave empty for no change.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">0-100</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblSliderPropDefaultHi\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Default (Big):</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtSliderPropDefaultHi\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Default big value (0-100). Leave empty for no change.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">0-100</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- ClearMask -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageClearMask\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Clear Mask</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Clears the mask for the target shape(s).</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- LoadMask -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageLoadMask\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Load Mask</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mask File:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpLoadMaskFile\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select a mask XML file</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wildcard>XML Files (*.xml)|*.xml</wildcard>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxFLP_OPEN|wxFLP_FILE_MUST_EXIST|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mask Name:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceLoadMaskName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Select a mask entry from the loaded mask file.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- RemoveUnusedNodes -->\n\t\t\t\t\t\t\t\t\t\t<object class=\"simplebookpage\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pageRemoveUnusedNodes\">\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Remove Unused Nodes</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Removes all unreferenced nodes from the NIF.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\n\t\t\t<!-- Variables section -->\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"paneVariables\">\n\t\t\t\t\t<label>Placeholder Variables</label>\n\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxBOTTOM</flag>\n\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t<label>Define {{KEY}} = Value pairs. These are substituted in all text fields before execution.</label>\n\t\t\t\t\t\t\t\t\t<wrap>500</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t<vgap>3</vgap>\n\t\t\t\t\t\t\t\t\t<hgap>5</hgap>\n\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Key:</label>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Value:</label>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtVarKey1\">\n\t\t\t\t\t\t\t\t\t\t\t<hint>KEY</hint>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtVarVal1\">\n\t\t\t\t\t\t\t\t\t\t\t<hint>Value</hint>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxTOP</flag>\n\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddVariable\">\n\t\t\t\t\t\t\t\t\t\t\t<label>+ Add</label>\n\t\t\t\t\t\t\t\t\t\t\t<size>80,-1</size>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnRemoveVariable\">\n\t\t\t\t\t\t\t\t\t\t\t<label>- Remove</label>\n\t\t\t\t\t\t\t\t\t\t\t<size>80,-1</size>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\n\t\t\t<!-- Bottom buttons -->\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"paneBatch\">\n\t\t\t\t\t<label>Batch Operation</label>\n\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxRadioBox\" name=\"radioBatchMode\">\n\t\t\t\t\t\t\t\t\t<label>Mode</label>\n\t\t\t\t\t\t\t\t\t<dimension>1</dimension>\n\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t<item>None (run on current project)</item>\n\t\t\t\t\t\t\t\t\t\t<item>Folder scan (repeat on files in folder)</item>\n\t\t\t\t\t\t\t\t\t\t<item>Slider sets (repeat on installed slider sets)</item>\n\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t<!-- Folder scan options -->\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxBOTTOM</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"panelBatchFolder\">\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\" name=\"boxBatchFolder\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t<label>Folder Scan Settings</label>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Folder:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpBatchFolder\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select folder to scan</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Extension:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtBatchExtension\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">.nif</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>File extension to scan for (e.g. .nif, .obj)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint translate=\"0\">.nif</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Options:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkBatchSubdirs\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Include subdirectories</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>File Filter:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtBatchFileFilter\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Filter file/folder names (substring or regex)</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Filter pattern...</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkBatchFileFilterRegex\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Regex</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t<!-- Slider set batch options -->\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"panelBatchSliderSets\">\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\" name=\"boxBatchSliderSets\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t<label>Slider Set Settings</label>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Filter:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txtBatchSliderSetFilter\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Filter slider set names (substring or regex). Leave empty for all.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hint>Filter pattern...</hint>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkBatchSliderSetFilterRegex\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Regex</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\n\t\t\t\t\t\t\t\t\t\t<!-- RefineMesh -->\n\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\n\t\t\t<!-- Output log -->\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"paneOutput\">\n\t\t\t\t\t<label>Output Log</label>\n\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t</object>\n\t\t\t</object>\n\n\t\t\t<!-- Execute buttons -->\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnExecuteAll\">\n\t\t\t\t\t\t\t<label>Execute</label>\n\t\t\t\t\t\t\t<tooltip>Execute all active steps in order</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CLOSE\">\n\t\t\t\t\t\t\t<label>Close</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/BatchBuild.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgBatchBuild\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN</style>\n\t\t<size>650,300</size>\n\t\t<title>Batch Build</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbDescription\">\n\t\t\t\t\t\t\t<label>Select the slider sets for the batch build process. Use the group and outfit filters to show the outfits you want!</label>\n\t\t\t\t\t\t\t<wrap>625</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCheckListBox\" name=\"batchBuildList\">\n\t\t\t\t\t<style>wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_EXTENDED</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxTOP</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTRE_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;Build</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTRE_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgBuildOverride\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN</style>\n\t\t<size>800,400</size>\n\t\t<title>Choose output set</title>\n\t\t<centered>1</centered>\n\t\t<bg>wxSYS_COLOUR_WINDOW</bg>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxALIGN_CENTRE_HORIZONTAL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbBuildOverride\">\n\t\t\t\t\t<style>wxALIGN_CENTRE_HORIZONTAL</style>\n\t\t\t\t\t<label>The following sets will override the same files.\\nPlease decide which one to use and select it in the list below.</label>\n\t\t\t\t\t<wrap>625</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxTextCtrl\" name=\"chooseText\">\n\t\t\t\t\t<style>wxTE_PROCESS_ENTER</style>\n\t\t\t\t\t<hint>Type and hit enter to choose output...</hint>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxScrolledWindow\" name=\"scrollOverrides\">\n\t\t\t\t\t<style>wxVSCROLL</style>\n\t\t\t\t\t<scrollrate>5,10</scrollrate>\n\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnPreviewConflicts\">\n\t\t\t\t\t\t\t<label>&amp;Preview</label>\n\t\t\t\t\t\t\t<tooltip>Open a preview window showing the conflicting outfits for the selected group</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/BodySlide.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxFrame\" name=\"bodySlideFrame\">\n\t\t<style>wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU|wxTAB_TRAVERSAL|wxCLIP_CHILDREN</style>\n\t\t<size>800,750</size>\n\t\t<bg>#404040</bg>\n\t\t<title>BodySlide</title>\n\t\t<centered>0</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>3</rows>\n\t\t\t\t\t<cols>5</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols>1,3,4</growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblOutfits\">\n\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t<label>Outfit/Body</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"outfitChoice\">\n\t\t\t\t\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t\t\t\t\t<tooltip>Select an outfit to modify</tooltip>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxTOP|wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnDeleteProject\">\n\t\t\t\t\t\t\t<size>24,24</size>\n\t\t\t\t\t\t\t<bitmap stock_id=\"wxART_DELETE\"/>\n\t\t\t\t\t\t\t<tooltip>Deletes a project from its project file</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxTOP|wxBOTTOM|wxLEFT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnEditProject\">\n\t\t\t\t\t\t\t\t\t<size>24,24</size>\n\t\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\LoadProj_sm.png</bitmap>\n\t\t\t\t\t\t\t\t\t<tooltip>Opens the current project in Outfit Studio</tooltip>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"searchHolder\" />\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT|wxTOP|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"unknown\" name=\"outfitsearchHolder\" />\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblPresets\">\n\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t<label>Preset</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"presetChoice\">\n\t\t\t\t\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t\t\t\t\t<tooltip>Choose from a list of slider settings presets</tooltip>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag></flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnDeletePreset\">\n\t\t\t\t\t\t\t<size>24,24</size>\n\t\t\t\t\t\t\t<bitmap stock_id=\"wxART_DELETE\"/>\n\t\t\t\t\t\t\t<tooltip>Deletes a preset from its preset file</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnSavePreset\">\n\t\t\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Saves the new slider values to the currently selected preset</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Save</label>\n\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnSavePresetAs\">\n\t\t\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Save the current slider settings as a new preset</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Save As...</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnGroupManager\">\n\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t<tooltip>Opens the group manager where you can edit existing or create new groups</tooltip>\n\t\t\t\t\t\t\t<label>Group Manager</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>-1,24</size>\n\t\t\t\t\t\t<object class=\"unknown\" name=\"dummy\" />\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"sliderFilter\" />\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"presetFilter\" />\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"unknown\" name=\"dummy\" />\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"unknown\" name=\"dummy\" />\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"unknown\" name=\"dummy\" />\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\" name=\"categoryTabSizer\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>0</border>\n\t\t\t\t<object class=\"wxWrapSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblSingleWt\">\n\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t<font>\n\t\t\t\t\t\t\t\t<size>12</size>\n\t\t\t\t\t\t\t\t<style>normal</style>\n\t\t\t\t\t\t\t\t<weight>normal</weight>\n\t\t\t\t\t\t\t\t<underlined>0</underlined>\n\t\t\t\t\t\t\t\t<face>Andalus</face>\n\t\t\t\t\t\t\t</font>\n\t\t\t\t\t\t\t<label>Single Weight</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxGridSizer\">\n\t\t\t\t\t\t\t<rows>1</rows>\n\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblLowWt\">\n\t\t\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t\t\t<font>\n\t\t\t\t\t\t\t\t\t\t<size>12</size>\n\t\t\t\t\t\t\t\t\t\t<style>normal</style>\n\t\t\t\t\t\t\t\t\t\t<weight>normal</weight>\n\t\t\t\t\t\t\t\t\t\t<underlined>0</underlined>\n\t\t\t\t\t\t\t\t\t\t<face>Andalus</face>\n\t\t\t\t\t\t\t\t\t</font>\n\t\t\t\t\t\t\t\t\t<label>Low Weight</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lblHighWt\">\n\t\t\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t\t\t<font>\n\t\t\t\t\t\t\t\t\t\t<size>12</size>\n\t\t\t\t\t\t\t\t\t\t<style>normal</style>\n\t\t\t\t\t\t\t\t\t\t<weight>normal</weight>\n\t\t\t\t\t\t\t\t\t\t<underlined>0</underlined>\n\t\t\t\t\t\t\t\t\t\t<face>Andalus</face>\n\t\t\t\t\t\t\t\t\t</font>\n\t\t\t\t\t\t\t\t\t<label>High Weight</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>10</border>\n\t\t\t\t\t\t<object class=\"wxScrolledWindow\" name=\"SliderScrollWindow\">\n\t\t\t\t\t\t\t<style>wxNO_BORDER|wxTAB_TRAVERSAL|wxVSCROLL</style>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<cols>6</cols>\n\t\t\t\t\t\t\t\t<minsize>-1,90</minsize>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1,4</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<object class=\"wxGridBagSizer\">\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<hgap>5</hgap>\n\t\t\t\t\t<vgap>5</vgap>\n\t\t\t\t\t<growablecols>0,1,2</growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>0,0</cellpos>\n\t\t\t\t\t\t<cellspan>1,1</cellspan>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnLowToHigh\">\n\t\t\t\t\t\t\t<size>26,-1</size>\n\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t<tooltip>Copy the low weight slider values to the high weight section.</tooltip>\n\t\t\t\t\t\t\t<label translate=\"0\">&#8594;</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>1,0</cellpos>\n\t\t\t\t\t\t<cellspan>1,3</cellspan>\n\t\t\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbIsOutfitChoice\">\n\t\t\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Default outfit choice in Batch Build</tooltip>\n\t\t\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"conflictLabel\">\n\t\t\t\t\t\t\t\t\t<fg>#c8c8d8</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Output Path (which the game would use for this outfit)</tooltip>\n\t\t\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"conflictInfo\">\n\t\t\t\t\t\t\t\t\t<fg>#c8c8d8</fg>\n\t\t\t\t\t\t\t\t\t<label>(right-click to view alternatives)</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>2,0</cellpos>\n\t\t\t\t\t\t<cellspan>1,1</cellspan>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnBuildBatch\">\n\t\t\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Build multiple outfits using the currently active slider values.\\n\\nHold CTRL = Build to custom directory\\nHold ALT = Delete from output directory</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Batch Build...</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbMorphs\">\n\t\t\t\t\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t\t\t\t\t<label>Build Morphs</label>\n\t\t\t\t\t\t\t\t\t\t\t<tooltip>Builds a morphs (.tri) file alongside the meshes for accessing the sliders in-game. Requires other mods to make use of the morph data.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbForceBodyNormals\">\n\t\t\t\t\t\t\t\t\t\t\t<fg>#c8c8c8</fg>\n\t\t\t\t\t\t\t\t\t\t\t<label>Force Body Normals</label>\n\t\t\t\t\t\t\t\t\t\t\t<tooltip>Adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"panelClippingSliders\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<rows>1</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>2</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>4</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#a0a0a0</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Fix Clipping</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"sliderClippingStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value>0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Controls how far outfit vertices are pushed away from the body surface.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>0,1</cellpos>\n\t\t\t\t\t\t<cellspan>1,1</cellspan>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnPreview\">\n\t\t\t\t\t\t\t<size>128,-1</size>\n\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t<tooltip>Show a preview window for this outfit.</tooltip>\n\t\t\t\t\t\t\t<label>Preview</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>2,1</cellpos>\n\t\t\t\t\t\t<cellspan>1,1</cellspan>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnBuild\">\n\t\t\t\t\t\t\t<size>128,45</size>\n\t\t\t\t\t\t\t<font>\n\t\t\t\t\t\t\t\t<size>12</size>\n\t\t\t\t\t\t\t\t<style>normal</style>\n\t\t\t\t\t\t\t\t<weight>normal</weight>\n\t\t\t\t\t\t\t\t<underlined>0</underlined>\n\t\t\t\t\t\t\t\t<face>Andalus</face>\n\t\t\t\t\t\t\t</font>\n\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t<tooltip>Creates the currently selected outfit/body.\\n\\nHold CTRL = Build to working directory\\nHold ALT = Delete from output directory</tooltip>\n\t\t\t\t\t\t\t<label>Build</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>0,2</cellpos>\n\t\t\t\t\t\t<cellspan>1,1</cellspan>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnHighToLow\">\n\t\t\t\t\t\t\t<size>26,-1</size>\n\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t<tooltip>Copy the high weight slider values to the low weight section.</tooltip>\n\t\t\t\t\t\t\t<label translate=\"0\">&#8592;</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<cellpos>2,2</cellpos>\n\t\t\t\t\t\t<cellspan>1,1</cellspan>\n\t\t\t\t\t\t<flag>wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAbout\">\n\t\t\t\t\t\t\t\t\t<size>24,24</size>\n\t\t\t\t\t\t\t\t\t<bitmap stock_id=\"wxART_INFORMATION\"/>\n\t\t\t\t\t\t\t\t\t<tooltip>About</tooltip>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnSettings\">\n\t\t\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Open settings dialog.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Settings</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnOutfitStudio\">\n\t\t\t\t\t\t\t\t\t<fg>wxSYS_COLOUR_BTNTEXT</fg>\n\t\t\t\t\t\t\t\t\t<tooltip>Open Outfit Studio, a full-featured tool for creating and converting outfits.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Outfit Studio</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuGroupContext\">\n\t\t<label>Filter Options</label>\n\t\t<object class=\"wxMenuItem\" name=\"menuChooseGroups\">\n\t\t\t<label>Choose groups...</label>\n\t\t\t<help>Choose groups to display in the Outfit menu</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"menuRefreshGroups\">\n\t\t\t<label>Refresh Groups</label>\n\t\t\t<help>Refresh group information</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuOutfitSrchContext\">\n\t\t<label>Filter Options</label>\n\t\t<object class=\"wxMenuItem\" name=\"menuRefreshOutfits\">\n\t\t\t<label>Refresh Outfits</label>\n\t\t\t<help>Reloads outfit list</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"menuRegexOutfits\">\n\t\t\t<label>Regular Expressions</label>\n\t\t\t<help>Allow the use of regular expressions (regex) for filtering.</help>\n\t\t\t<checkable>1</checkable>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"menuFilterHasZaps\">\n\t\t\t<label>Has Zap Options</label>\n\t\t\t<help>Show only outfits that have zap options.</help>\n\t\t\t<checkable>1</checkable>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"menuBrowseOutfitFolder\">\n\t\t\t<label>Browse outfit folder...</label>\n\t\t\t<help>Browses to the shape data folder of the current outfit in the file explorer.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"menuSaveGroups\">\n\t\t\t<label>Save Outfit list as group...</label>\n\t\t\t<help>Save the current filtered outfit list as a group</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"batchBuildContext\">\n\t\t<object class=\"wxMenuItem\" name=\"batchBuildNone\">\n\t\t\t<label>Select None</label>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"batchBuildAll\">\n\t\t\t<label>Select All</label>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"batchBuildInvert\">\n\t\t\t<label>Invert Selection</label>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuFileCollision\">\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/ConvertBodyReference.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxWizard\" name=\"wizConvertBodyRef\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE</style>\n\t\t<pos>0,0</pos>\n\t\t<title>Convert / Replace Body Reference</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxWizardPageSimple\" name=\"wizpgConvertBodyRef1\">\n\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t<label>This wizard aids in the conversion to another body/reference..</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>10</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Reference Bodies</label>\n\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<size>0,5</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>Select a conversion reference (or 'None' to skip converting):</label>\n\t\t\t\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>170,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"npConvRef\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>Conversion Body Reference</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>300,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npConvRefChoice\">\n\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>Select a body reference to convert to:</label>\n\t\t\t\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>170,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"npNewRef\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>New Body Reference</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>300,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npNewRefChoice\">\n\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>10</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Options</label>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConvertMergeSliders\">\n\t\t\t\t\t\t\t\t<label>Merge Sliders</label>\n\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConvertMergeZaps\">\n\t\t\t\t\t\t\t\t<label>Merge Zaps</label>\n\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>2</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols></growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkConformSliders\">\n\t\t\t\t\t\t\t\t\t\t<label>Conform Sliders</label>\n\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSkipConformPopup\">\n\t\t\t\t\t\t\t\t\t\t<label>Skip conform popup (use default settings)</label>\n\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkCopyBoneWeights\">\n\t\t\t\t\t\t\t\t\t\t<label>Copy Bone Weights</label>\n\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkSkipCopyBonesPopup\">\n\t\t\t\t\t\t\t\t\t\t<label>Skip bone weights popup (use default settings)</label>\n\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkDeleteReferenceOnComplete\">\n\t\t\t\t\t\t\t\t<label>Delete reference after completion</label>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxWizardPageSimple\" name=\"wizpgConvertBodyRef2\">\n\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t<label>This wizard aids in the conversion to another body/reference..</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>10</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Rename Project (optional)</label>\n\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<size>0,5</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>Specify text to be removed from the project name (comma-delimited):</label>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>170,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>Remove from project name</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>200,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"npRemoveText\"></object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>Specify any text to be prepended to project name:</label>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>170,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>Prepend to project name</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>200,25</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"npAppendText\"></object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>NOTE: Game file output path is unaffected by this</label>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>10</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Extras (optional)</label>\n\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<size>0,5</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>Remove the following shapes before conversion (comma-delimited):</label>\n\t\t\t\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>170,20</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>Shapes to delete</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<minsize>200,-1</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"npDeleteShapesText\"></object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t\t\t\t<label>Add the following bones after conversion (comma-delimited):</label>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<minsize>170,20</minsize>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>Bones to add</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"npAddBonesText\"></object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/EditUV.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxFrame\" name=\"dlgEditUV\">\n\t\t<style>wxFRAME_FLOAT_ON_PARENT|wxCAPTION|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxCLOSE_BOX</style>\n\t\t<title>Edit UV</title>\n\t\t<bg>#707070</bg>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<minsize>600,600</minsize>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>0</border>\n\t\t\t\t<object class=\"unknown\" name=\"uvGLView\" />\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<size>0,5</size>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxToolBar\" name=\"uvToolBar\">\n\t\t<style>wxTB_HORIZONTAL|wxTB_FLAT</style>\n\t\t<bg>#707070</bg>\n\t\t<fg>#ffffff</fg>\n\t\t<separation>5</separation>\n\t\t<object class=\"tool\" name=\"btnBoxSelection\">\n\t\t\t<label>Box Selection</label>\n\t\t\t<tooltip>Box Selection\\nShortcut: 1</tooltip>\n\t\t\t<bitmap>$(AppDir)\\res\\images\\MaskBrush.png</bitmap>\n\t\t\t<bitmap2>$(AppDir)\\res\\images\\MaskBrush_d.png</bitmap2>\n\t\t\t<radio>1</radio>\n\t\t\t<checked>1</checked>\n\t\t</object>\n\t\t<object class=\"tool\" name=\"btnVertexSelection\">\n\t\t\t<label>Vertex Selection</label>\n\t\t\t<tooltip>Vertex Selection\\nShortcut: 2</tooltip>\n\t\t\t<bitmap>$(AppDir)\\res\\images\\SelectBrush.png</bitmap>\n\t\t\t<bitmap2>$(AppDir)\\res\\images\\SelectBrush_d.png</bitmap2>\n\t\t\t<radio>1</radio>\n\t\t</object>\n\t\t<object class=\"tool\" name=\"btnMove\">\n\t\t\t<label>Move</label>\n\t\t\t<tooltip>Move\\nShortcut: 3</tooltip>\n\t\t\t<bitmap>$(AppDir)\\res\\images\\MoveBrush.png</bitmap>\n\t\t\t<bitmap2>$(AppDir)\\res\\images\\MoveBrush_d.png</bitmap2>\n\t\t\t<radio>1</radio>\n\t\t</object>\n\t\t<object class=\"tool\" name=\"btnScale\">\n\t\t\t<label>Scale</label>\n\t\t\t<tooltip>Scale\\nShortcut: 4</tooltip>\n\t\t\t<bitmap>$(AppDir)\\res\\images\\TransformTool.png</bitmap>\n\t\t\t<bitmap2>$(AppDir)\\res\\images\\TransformTool_d.png</bitmap2>\n\t\t\t<radio>1</radio>\n\t\t</object>\n\t\t<object class=\"tool\" name=\"btnRotate\">\n\t\t\t<label>Rotate</label>\n\t\t\t<tooltip>Rotate\\nShortcut: 5</tooltip>\n\t\t\t<bitmap>$(AppDir)\\res\\images\\RotateTool.png</bitmap>\n\t\t\t<bitmap2>$(AppDir)\\res\\images\\RotateTool_d.png</bitmap2>\n\t\t\t<radio>1</radio>\n\t\t</object>\n\t\t<object class=\"tool\" name=\"btnSeamEdges\">\n\t\t\t<label>Show Seam Edges</label>\n\t\t\t<tooltip>Show Seam Edges</tooltip>\n\t\t\t<bitmap>$(AppDir)\\res\\images\\SeamEdges.png</bitmap>\n\t\t\t<bitmap2>$(AppDir)\\res\\images\\SeamEdges_d.png</bitmap2>\n\t\t\t<toggle>1</toggle>\n\t\t\t<checked>1</checked>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenuBar\" name=\"uvMenuBar\">\n\t\t<label>Menu</label>\n\t\t<object class=\"wxMenu\" name=\"menuFile\">\n\t\t\t<label>File</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"fileExportUVTemplate\">\n\t\t\t\t<label>Export UV Template...\\tCtrl+E</label>\n\t\t\t\t<help>Export the UV layout as an image file.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuEdit\">\n\t\t\t<label>Edit</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"editUndo\">\n\t\t\t\t<label>Undo\\tCtrl+Z</label>\n\t\t\t\t<help>Undo the previous action.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editRedo\">\n\t\t\t\t<label>Redo\\tCtrl+Y</label>\n\t\t\t\t<help>Redo the next undone action.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"editSelectAll\">\n\t\t\t\t<label>Select All\\tCtrl+A</label>\n\t\t\t\t<help>Select All</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editSelectInvert\">\n\t\t\t\t<label>Invert Selection\\tCtrl+I</label>\n\t\t\t\t<help>Invert Selection</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editSelectLess\">\n\t\t\t\t<label>Select Less\\tA</label>\n\t\t\t\t<help>Select less adjacent points in the selected islands.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editSelectMore\">\n\t\t\t\t<label>Select More\\tD</label>\n\t\t\t\t<help>Select more adjacent points in the selected islands.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"maskSelection\">\n\t\t\t\t<label>Mask Selection</label>\n\t\t\t\t<help>Create a mask from the current UV selection for the mesh in the main viewport.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"editTranslate\">\n\t\t\t\t<label>Translate...\\tT</label>\n\t\t\t\t<help>Show a dialog to translate the current selection.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editRotate\">\n\t\t\t\t<label>Rotate...\\tR</label>\n\t\t\t\t<help>Show a dialog to rotate the current selection.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editScale\">\n\t\t\t\t<label>Scale...\\tS</label>\n\t\t\t\t<help>Show a dialog to scale the current selection.</help>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgTranslate\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>414,169</size>\n\t\t<title>Translate</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelU\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">U</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"sliderU\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-2000</min>\n\t\t\t\t\t\t\t\t\t<max>2000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textU\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelV\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">V</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"sliderV\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-2000</min>\n\t\t\t\t\t\t\t\t\t<max>2000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textV\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgRotate\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>423,155</size>\n\t\t<title>Rotate</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"label\">\n\t\t\t\t\t\t\t\t\t<label>Angle</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"slider\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t<min>-18000</min>\n\t\t\t\t\t\t\t\t\t<max>18000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"text\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgScale\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>423,250</size>\n\t\t<title>Scale</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelU\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">U</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"sliderU\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1000</value>\n\t\t\t\t\t\t\t\t\t<min>10</min>\n\t\t\t\t\t\t\t\t\t<max>3000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textU\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelV\">\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">V</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"sliderV\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1000</value>\n\t\t\t\t\t\t\t\t\t<min>10</min>\n\t\t\t\t\t\t\t\t\t<max>3000</max>\n\t\t\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textV\">\n\t\t\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbUniform\">\n\t\t\t\t\t\t\t<label>Uniform (UV)</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"button\">\n\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgExportUV\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<title>Export UV Template</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t<vgap>8</vgap>\n\t\t\t\t\t<hgap>10</hgap>\n\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Resolution</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceResolution\">\n\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t<item translate=\"0\">512 x 512</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">1024 x 1024</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">2048 x 2048</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">4096 x 4096</item>\n\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t<selection>2</selection>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Wire Color</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpWireColor\">\n\t\t\t\t\t\t\t<colour>#FFFFFF</colour>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Background Color</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpBackgroundColor\">\n\t\t\t\t\t\t\t<colour>#000000</colour>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbTransparentBG\">\n\t\t\t\t\t\t\t<label>Transparent Background</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbIncludeTexture\">\n\t\t\t\t\t\t\t<label>Include Texture</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Wrap Mode</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceWrapMode\">\n\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t<item>Wrap</item>\n\t\t\t\t\t\t\t\t<item>Clamp</item>\n\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbAntiAliasing\">\n\t\t\t\t\t\t\t<label>Anti-Aliasing</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/GroupManager.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgGroupManager\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER</style>\n\t\t<size>800,500</size>\n\t\t<bg>#f0f0f0</bg>\n\t\t<title>Group Manager</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbHeader\">\n\t\t\t\t\t<style>wxALIGN_CENTRE</style>\n\t\t\t\t\t<label>Choose a group and add or remove members by selecting them in the lists.</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpGroupXML\">\n\t\t\t\t\t\t\t<value translate=\"0\"></value>\n\t\t\t\t\t\t\t<message>Select a group XML file</message>\n\t\t\t\t\t\t\t<wildcard>Group Files (*.xml)|*.xml</wildcard>\n\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btSave\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Save</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btSaveAs\">\n\t\t\t\t\t\t\t<label>Save As...</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t<label>Groups</label>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxListBox\" name=\"listGroups\">\n\t\t\t\t\t\t\t\t\t<style>wxLB_ALWAYS_SB|wxLB_SORT</style>\n\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"groupName\">\n\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\"></value>\n\t\t\t\t\t\t\t\t\t\t\t<maxlength>75</maxlength>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btAddGroup\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Add Group</label>\n\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btRemoveGroup\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Remove Group</label>\n\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t<label>Members</label>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxListBox\" name=\"listMembers\">\n\t\t\t\t\t\t\t\t\t\t\t<style>wxLB_ALWAYS_SB|wxLB_EXTENDED|wxLB_SORT</style>\n\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btRemoveMember\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Remove &gt;&gt;</label>\n\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t<label>Outfits</label>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"outfitFilter\" />\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxListBox\" name=\"listOutfits\">\n\t\t\t\t\t\t\t\t\t<style>wxLB_ALWAYS_SB|wxLB_EXTENDED|wxLB_SORT</style>\n\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btAddMember\">\n\t\t\t\t\t\t\t\t\t<label>&lt;&lt; Add</label>\n\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>Close</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/ImportDialog.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"importDialog\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>Import Options...</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbWarning\">\n\t\t\t\t\t<bg>#ffff00</bg>\n\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxListCtrl\" name=\"meshesList\">\n\t\t\t\t\t<style>wxLC_REPORT</style>\n\t\t\t\t\t<object class=\"listcol\">\n\t\t\t\t\t\t<text>Name</text>\n\t\t\t\t\t\t<width>100</width>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"listcol\">\n\t\t\t\t\t\t<text>Vertices #</text>\n\t\t\t\t\t\t<width>75</width>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"listcol\">\n\t\t\t\t\t\t<text>Triangles #</text>\n\t\t\t\t\t\t<width>75</width>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"listcol\">\n\t\t\t\t\t\t<text>Info</text>\n\t\t\t\t\t\t<width>425</width>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbInvertU\">\n\t\t\t\t\t\t\t<label>Invert U</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbInvertV\">\n\t\t\t\t\t\t\t<label>Invert V</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"scaleLabel\">\n\t\t\t\t\t\t\t<label>Scale</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"scale\">\n\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rotateXLabel\">\n\t\t\t\t\t\t\t<label>Rotate (X)</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"rotateX\">\n\t\t\t\t\t\t\t<tooltip>Choose X rotation.</tooltip>\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t<item translate=\"0\">0&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">90&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">180&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">270&#176;</item>\n\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rotateYLabel\">\n\t\t\t\t\t\t\t<label>Rotate (Y)</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"rotateY\">\n\t\t\t\t\t\t\t<tooltip>Choose Y rotation.</tooltip>\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t<item translate=\"0\">0&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">90&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">180&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">270&#176;</item>\n\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rotateZLabel\">\n\t\t\t\t\t\t\t<label>Rotate (Z)</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"rotateZ\">\n\t\t\t\t\t\t\t<tooltip>Choose Z rotation.</tooltip>\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t<item translate=\"0\">0&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">90&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">180&#176;</item>\n\t\t\t\t\t\t\t\t<item translate=\"0\">270&#176;</item>\n\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>0</border>\n\t\t\t\t<minsize>700,600</minsize>\n\t\t\t\t<object class=\"unknown\" name=\"glView\" />\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/NormalsGenDlg.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"wxNormalsGenDlg\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxSTAY_ON_TOP</style>\n\t\t<size>323,473</size>\n\t\t<title>Normal Map Generator</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxTOP</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLayers\">\n\t\t\t\t\t\t\t<label>Layers</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_BOTTOM|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBitmapButton\" name=\"bpPreset\">\n\t\t\t\t\t\t\t<style>wxBU_AUTODRAW|wxNO_BORDER</style>\n\t\t\t\t\t\t\t<tooltip>Load or save preset layer settings.</tooltip>\n\t\t\t\t\t\t\t<bitmap>res/images/save.png</bitmap>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"unknown\" name=\"pgLayers\" />\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddLayer\">\n\t\t\t\t\t\t\t<tooltip>Add a new layer after the current one in the layer list.</tooltip>\n\t\t\t\t\t\t\t<label>Add Layer</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxBOTTOM</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnMoveUp\">\n\t\t\t\t\t\t\t<tooltip>Move selected layer up one position.</tooltip>\n\t\t\t\t\t\t\t<label>Move Up</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnDeleteLayer\">\n\t\t\t\t\t\t\t<tooltip>Delete the selected layer.</tooltip>\n\t\t\t\t\t\t\t<label>Delete Layer</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND | wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticLine\" name=\"line1\">\n\t\t\t\t\t<style>wxLI_HORIZONTAL</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Options</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbBackup\">\n\t\t\t\t\t\t\t<tooltip>Save a copy of an existing normal map if one already exists. File is saved in the original directory.</tooltip>\n\t\t\t\t\t\t\t<label>Backup destination file</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbCompress\">\n\t\t\t\t\t\t\t<tooltip>Compress output file using BC7 compression. This can make saving the file take a VERY long time!</tooltip>\n\t\t\t\t\t\t\t<label>Compress output </label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbSaveToBGLayerFile\">\n\t\t\t\t\t\t\t<tooltip>Use the file name specified in the background layer to save the normal map.</tooltip>\n\t\t\t\t\t\t\t<label>Save to background layer file</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT</flag>\n\t\t\t\t\t\t<border>20</border>\n\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpOutputFile\">\n\t\t\t\t\t\t\t<value translate=\"0\"></value>\n\t\t\t\t\t\t\t<message>Choose an output file...</message>\n\t\t\t\t\t\t\t<wildcard>Texture Files (*.dds)|*.dds</wildcard>\n\t\t\t\t\t\t\t<style>wxFLP_SAVE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<tooltip>Location to save normal map to.</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnPreview\">\n\t\t\t\t\t\t\t<tooltip>Display current settings on mesh in preview window.</tooltip>\n\t\t\t\t\t\t\t<label>Preview</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnGenerate\">\n\t\t\t\t\t\t\t<tooltip>Generate and save the normal map file.</tooltip>\n\t\t\t\t\t\t\t<label>Generate</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"presetContext\">\n\t\t<label>Preset</label>\n\t\t<object class=\"wxMenuItem\" name=\"ctxLoadPreset\">\n\t\t\t<label>Load Preset...</label>\n\t\t\t<help></help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"ctxSavePreset\">\n\t\t\t<label>Save Preset...</label>\n\t\t\t<help></help>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/OutfitStudio.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxFrame\" name=\"outfitStudio\">\n\t\t<style>wxCAPTION|wxCLOSE_BOX|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxRESIZE_BORDER|wxSYSTEM_MENU|wxTAB_TRAVERSAL</style>\n\t\t<size>990,757</size>\n\t\t<bg>#707070</bg>\n\t\t<title>Outfit Studio</title>\n\t\t<centered>1</centered>\n\t\t<aui_managed>0</aui_managed>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>0</border>\n\t\t\t\t<object class=\"wxToolBar\" name=\"toolBarH\">\n\t\t\t\t\t<style>wxTB_HORIZONTAL|wxTB_FLAT</style>\n\t\t\t\t\t<bg>#707070</bg>\n\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t<dontattachtoframe>1</dontattachtoframe>\n\t\t\t\t\t<object class=\"tool\" name=\"btnNewProject\">\n\t\t\t\t\t\t<label>New Project</label>\n\t\t\t\t\t\t<tooltip>Create a new project by selecting a reference body slider set, and outfit model files.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\NewProj.png</bitmap>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t<object class=\"tool\" name=\"btnLoadProject\">\n\t\t\t\t\t\t<label>Load Project</label>\n\t\t\t\t\t\t<tooltip>Load a previously created slider set for editing.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\LoadProj.png</bitmap>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t<object class=\"tool\" name=\"editUndo\">\n\t\t\t\t\t\t<label>Undo</label>\n\t\t\t\t\t\t<tooltip>Undo a previous action.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Undo.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\Undo_d.png</bitmap2>\n\t\t\t\t\t\t<disabled>1</disabled>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"editRedo\">\n\t\t\t\t\t\t<label>Redo</label>\n\t\t\t\t\t\t<tooltip>Redo the next undone action.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Redo.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\Redo_d.png</bitmap2>\n\t\t\t\t\t\t<disabled>1</disabled>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t<object class=\"tool\" name=\"btnSelect\">\n\t\t\t\t\t\t<label>Select</label>\n\t\t\t\t\t\t<tooltip>Navigate and select meshes (or vertices in vertex mode).</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\SelectBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\SelectBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnMaskBrush\">\n\t\t\t\t\t\t<label>Mask</label>\n\t\t\t\t\t\t<tooltip>Mask vertices to prevent them from being transformed.\\nHold down the ALT key to remove masking.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\MaskBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\MaskBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnInflateBrush\">\n\t\t\t\t\t\t<label>Inflate</label>\n\t\t\t\t\t\t<tooltip>Increase mesh volume in an area.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\InflateBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\InflateBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnDeflateBrush\">\n\t\t\t\t\t\t<label>Deflate</label>\n\t\t\t\t\t\t<tooltip>Decrease mesh volume in an area.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\DeflateBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\DeflateBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnMoveBrush\">\n\t\t\t\t\t\t<label>Move</label>\n\t\t\t\t\t\t<tooltip>Move vertices over a plane parallel to the view.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\MoveBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\MoveBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnSmoothBrush\">\n\t\t\t\t\t\t<label>Smooth</label>\n\t\t\t\t\t\t<tooltip>Smooth an area of a mesh.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\SmoothBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\SmoothBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnUndiffBrush\">\n\t\t\t\t\t\t<label>Undiff</label>\n\t\t\t\t\t\t<tooltip>Undiff an area of a slider.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\UndiffBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\UndiffBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnWeightBrush\">\n\t\t\t\t\t\t<label>Weight Paint</label>\n\t\t\t\t\t\t<tooltip>Apply animation weight values for currently selected bone.\\nHold down the ALT key to weaken the weighting.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\WeightBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\WeightBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t\t<disabled>1</disabled>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnColorBrush\">\n\t\t\t\t\t\t<label>Color Paint</label>\n\t\t\t\t\t\t<tooltip>Apply vertex colors.\\nHold down the ALT key to remove colors.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\ColorBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\ColorBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t\t<disabled>1</disabled>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnAlphaBrush\">\n\t\t\t\t\t\t<label>Alpha Paint</label>\n\t\t\t\t\t\t<tooltip>Apply vertex alpha.\\nHold down the ALT key to remove alpha.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\AlphaBrush.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\AlphaBrush_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t\t<disabled>1</disabled>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnCollapseVertex\">\n\t\t\t\t\t\t<label>Collapse Vertex</label>\n\t\t\t\t\t\t<tooltip>Deletes vertices with no more than three connections, without creating a hole.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\CollapseVertex.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\CollapseVertex_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnFlipEdgeTool\">\n\t\t\t\t\t\t<label>Flip Edge</label>\n\t\t\t\t\t\t<tooltip>Flips mesh edges so that the opposite pair of vertices is connected.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\FlipEdge.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\FlipEdge_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnSplitEdgeTool\">\n\t\t\t\t\t\t<label>Split Edge</label>\n\t\t\t\t\t\t<tooltip>Splits a mesh edge in two with a new vertex.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\SplitEdge.png</bitmap>\n\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\SplitEdge_d.png</bitmap2>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnMoveVertexTool\">\n\t\t\t\t\t\t<label>Move Vertex</label>\n\t\t\t\t\t\t<tooltip>Moves a vertex.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\MoveVertex.png</bitmap>\n\t\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbDepthClip\">\n\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t<label>Depth Clip</label>\n\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t<tooltip>Simulates lower depth buffer precision to help with depth-related clipping</tooltip>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxSlider\" name=\"fovSlider\">\n\t\t\t\t\t\t<size>100,25</size>\n\t\t\t\t\t\t<value translate=\"0\">65</value>\n\t\t\t\t\t\t<min>20</min>\n\t\t\t\t\t\t<max>120</max>\n\t\t\t\t\t\t<tooltip>Field of View</tooltip>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxStaticText\" name=\"fovLabel\">\n\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t<label>Field of View: 65</label>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t<object class=\"wxButton\" name=\"brushSettings\">\n\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t<label>Brush Settings</label>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"space\" />\n\t\t\t\t\t<object class=\"tool\" name=\"btnDiscord\">\n\t\t\t\t\t\t<label translate=\"0\">Discord</label>\n\t\t\t\t\t\t<tooltip>Open Discord invite link.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Discord.png</bitmap>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnGitHub\">\n\t\t\t\t\t\t<label translate=\"0\">GitHub</label>\n\t\t\t\t\t\t<tooltip>Open GitHub link.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\GitHub.png</bitmap>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"tool\" name=\"btnPayPal\">\n\t\t\t\t\t\t<label translate=\"0\">PayPal</label>\n\t\t\t\t\t\t<tooltip>Open PayPal link.</tooltip>\n\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\PayPal.png</bitmap>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>0</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxToolBar\" name=\"toolBarV\">\n\t\t\t\t\t\t\t<style>wxTB_VERTICAL|wxTB_FLAT</style>\n\t\t\t\t\t\t\t<bg>#707070</bg>\n\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t<dontattachtoframe>1</dontattachtoframe>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnTransform\">\n\t\t\t\t\t\t\t\t<label>Transform</label>\n\t\t\t\t\t\t\t\t<tooltip>Shows a transform tool to manipulate shapes and vertices with.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\TransformTool.png</bitmap>\n\t\t\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\TransformTool_d.png</bitmap2>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnPivot\">\n\t\t\t\t\t\t\t\t<label>Pivot</label>\n\t\t\t\t\t\t\t\t<tooltip>Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Pivot.png</bitmap>\n\t\t\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\Pivot_d.png</bitmap2>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnVertexEdit\">\n\t\t\t\t\t\t\t\t<label>Vertex Edit</label>\n\t\t\t\t\t\t\t\t<tooltip>Lets you select vertices to add to or remove from the mask.\\nClick on a vertex to select/unmask it.\\nHold down CTRL to unselect/mask it.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\VertexEdit.png</bitmap>\n\t\t\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\VertexEdit_d.png</bitmap2>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnViewFront\">\n\t\t\t\t\t\t\t\t<label>View Front</label>\n\t\t\t\t\t\t\t\t<tooltip>Change camera view to the front.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\ViewFront.png</bitmap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnViewBack\">\n\t\t\t\t\t\t\t\t<label>View Back</label>\n\t\t\t\t\t\t\t\t<tooltip>Change camera view to the back.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\ViewBack.png</bitmap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnViewLeft\">\n\t\t\t\t\t\t\t\t<label>View Left</label>\n\t\t\t\t\t\t\t\t<tooltip>Change camera view to the left.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\ViewLeft.png</bitmap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnViewRight\">\n\t\t\t\t\t\t\t\t<label>View Right</label>\n\t\t\t\t\t\t\t\t<tooltip>Change camera view to the right.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\ViewRight.png</bitmap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnViewPerspective\">\n\t\t\t\t\t\t\t\t<label>Perspective View</label>\n\t\t\t\t\t\t\t\t<tooltip>Toggle perspective view.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\ViewPerspective.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnShowNodes\">\n\t\t\t\t\t\t\t\t<label>Show Nodes</label>\n\t\t\t\t\t\t\t\t<tooltip>Toggle rendering of nodes.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Nodes.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnShowBones\">\n\t\t\t\t\t\t\t\t<label>Show Bones</label>\n\t\t\t\t\t\t\t\t<tooltip>Toggle rendering of bones.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Bones.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnShowFloor\">\n\t\t\t\t\t\t\t\t<label>Show Floor</label>\n\t\t\t\t\t\t\t\t<tooltip>Toggle rendering of the floor grid.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Floor.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"separator\" />\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnXMirror\">\n\t\t\t\t\t\t\t\t<label>X Mirror</label>\n\t\t\t\t\t\t\t\t<tooltip>Mirror edits across the X axis.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\XMirror.png</bitmap>\n\t\t\t\t\t\t\t\t<bitmap2>$(AppDir)\\res\\images\\XMirror_d.png</bitmap2>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnConnected\">\n\t\t\t\t\t\t\t\t<label>Edit Connected Only\\tC</label>\n\t\t\t\t\t\t\t\t<tooltip>Edit only vertices that are connected to the ones under the brush within the brush radius.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\EditConnected.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnMerge\">\n\t\t\t\t\t\t\t\t<label>Merge Vertex</label>\n\t\t\t\t\t\t\t\t<tooltip>Merges two vertices and fills any gaps.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Merge.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnWeld\">\n\t\t\t\t\t\t\t\t<label>Weld Vertex</label>\n\t\t\t\t\t\t\t\t<tooltip>Welds two vertices while keeping the texture coordinates (UV) distinct.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\Weld.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnRestrictSurface\">\n\t\t\t\t\t\t\t\t<label>Restrict To Surface</label>\n\t\t\t\t\t\t\t\t<tooltip>Restricts motion to a mesh surface.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\RestrictSurface.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnRestrictPlane\">\n\t\t\t\t\t\t\t\t<label>Restrict To Plane</label>\n\t\t\t\t\t\t\t\t<tooltip>Restricts motion to parallel to the surface.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\RestrictPlane.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"tool\" name=\"btnRestrictNormal\">\n\t\t\t\t\t\t\t\t<label>Restrict To Normal</label>\n\t\t\t\t\t\t\t\t<tooltip>Restricts motion to perpendicular to the surface.</tooltip>\n\t\t\t\t\t\t\t\t<bitmap>$(AppDir)\\res\\images\\RestrictNormal.png</bitmap>\n\t\t\t\t\t\t\t\t<toggle>1</toggle>\n\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t<object class=\"wxSplitterWindow\" name=\"splitter\">\n\t\t\t\t\t\t\t<style>wxSP_3D|wxSP_LIVE_UPDATE</style>\n\t\t\t\t\t\t\t<sashpos>850</sashpos>\n\t\t\t\t\t\t\t<gravity>1</gravity>\n\t\t\t\t\t\t\t<minsize>250</minsize>\n\t\t\t\t\t\t\t<orientation>vertical</orientation>\n\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"leftSplitPanel\">\n\t\t\t\t\t\t\t\t<style>wxTAB_TRAVERSAL</style>\n\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"mGLView\" />\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"rightSplitPanel\">\n\t\t\t\t\t\t\t\t<style>wxTAB_TRAVERSAL|wxTRANSPARENT_WINDOW</style>\n\t\t\t\t\t\t\t\t<bg>#707070</bg>\n\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxSplitterWindow\" name=\"splitterRight\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<style>wxSP_3D|wxSP_LIVE_UPDATE</style>\n\t\t\t\t\t\t\t\t\t\t\t<sashpos>200</sashpos>\n\t\t\t\t\t\t\t\t\t\t\t<gravity>0</gravity>\n\t\t\t\t\t\t\t\t\t\t\t<minsize>100</minsize>\n\t\t\t\t\t\t\t\t\t\t\t<orientation>horizontal</orientation>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"topSplitPanel\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTAB_TRAVERSAL|wxTRANSPARENT_WINDOW</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<bg>#707070</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxWrapSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"meshTabButton\" subclass=\"wxStateButton\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,20</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxNO_BORDER|wxBU_EXACTFIT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Meshes</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#646464</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"boneTabButton\" subclass=\"wxStateButton\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,20</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxNO_BORDER|wxBU_EXACTFIT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Bones</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#646464</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"segmentTabButton\" subclass=\"wxStateButton\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,20</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxNO_BORDER|wxBU_EXACTFIT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Segments</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#646464</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"partitionTabButton\" subclass=\"wxStateButton\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,20</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxNO_BORDER|wxBU_EXACTFIT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Partitions</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#646464</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"colorsTabButton\" subclass=\"wxStateButton\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,20</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxNO_BORDER|wxBU_EXACTFIT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Colors</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#646464</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"lightsTabButton\" subclass=\"wxStateButton\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,20</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxNO_BORDER|wxBU_EXACTFIT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Lights</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#646464</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTreeCtrl\" name=\"outfitShapes\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTR_LINES_AT_ROOT|wxTR_HIDE_ROOT|wxTR_NO_LINES|wxTR_HAS_BUTTONS|wxTR_MULTIPLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"bonesFilter\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTreeCtrl\" name=\"outfitBones\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTR_LINES_AT_ROOT|wxTR_HIDE_ROOT|wxTR_NO_LINES|wxTR_HAS_BUTTONS|wxTR_MULTIPLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"totalBoneCountLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Total Bones: 0</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"selectedBoneCountLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shape Selection Bones: 0</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxScrolledWindow\" name=\"colorSettings\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxVSCROLL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<scrollrate>5,5</scrollrate>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"colorPalette\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbBrushColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Brush Color</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpBrushColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Color of the brush.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">rgb(0,0,0)</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"clampMaxValue\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Clamp Max Value</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"cpClampMaxValueSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_INVERSE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>255</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"cpClampMaxValueTxt\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>50,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>25</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnSwapBrush\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Edit Alpha</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxTOP</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnMaskVertexColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Mask matching color</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTreeCtrl\" name=\"segmentTree\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTR_LINES_AT_ROOT|wxTR_HIDE_ROOT|wxTR_NO_LINES|wxTR_HAS_BUTTONS</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTreeCtrl\" name=\"partitionTree\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTR_LINES_AT_ROOT|wxTR_HIDE_ROOT|wxTR_NO_LINES|wxTR_HAS_BUTTONS</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxScrolledWindow\" name=\"lightSettings\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxVSCROLL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<scrollrate>5,5</scrollrate>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"lightReset\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Reset</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lightAmbientLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>75,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Ambient</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"lightAmbientSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lightFrontalLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>75,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Frontal</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"lightFrontalSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lightDirectional0Label\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>75,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Directional 1</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"lightDirectional0Slider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lightDirectional1Label\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>75,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Directional 2</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"lightDirectional1Slider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lightDirectional2Label\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>75,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Directional 3</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"lightDirectional2Slider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"bottomSplitPanel\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTAB_TRAVERSAL|wxTRANSPARENT_WINDOW</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<bg>#707070</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxLEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxPanel\" name=\"editPanel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTAB_TRAVERSAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"segmentTypeLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Type</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"segmentType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Default</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">1 | Head/Hair | 0x86b72980</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">1 | Neck | 0x0155094f</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 2 | R-Up Arm | 0xb2e2764f</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 2 | R-Lo Arm | 0x6fc3fbb2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 4 | L-Up Arm | 0xfc03dc25</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 4 | L-Lo Arm | 0x212251d8</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 5 | R-Up Thi | 0xbf3a3cc5</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 5 | R-Kne-Clf | 0x22324321</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 5 | R-Lo Ft.-Ank | 0xc7e6bc92</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 6 | L-Up Leg | 0x865d8d9e</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 6 | L-Kne-Clf | 0x4630dac2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Human 6 | L-Lo Ft.-Ank | 0xa3e42571</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Feral Ghoul 2 | R-Up Arm | 0x2a549ee1</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Feral Ghoul 2 | R-Lo Arm | 0xf775131c</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Feral Ghoul 2 | R-Hand | 0x85342e3c</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Feral Ghoul 4 | L-Up Arm | 0x4e560702</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Feral Ghoul 4 | L-Lo Arm | 0x93778aff</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Feral Ghoul 4 | L-Hand | 0x5ae407df</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 1 | Neck | 0xc0f43cc3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 2 | R-Up-Arm | 0xf2ba1077</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 2 | R-Elbow-4Arm | 0xf4e10d0d</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 2 | R-Hand | 0xe2da5319</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 4 | L-Up-Arm | 0x17932e95</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 4 | L-Elbow-4Arm | 0x0861e2c0</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw 4 | L-Hand | 0x8beb7000</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw, Feral Ghoul 5 | R-Up Thi | 0x9af9d18c</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw, Feral Ghoul 5 | R-Lo Leg | 0x8e0daa93</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw, Feral Ghoul 5 | R-Lo Ft | 0x6bd95520</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw, Feral Ghoul 6 | L-Lo Thi | 0xa325b267</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw, Feral Ghoul 6 | L-Lo Leg | 0x51dd8370</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Death Claw, Feral Ghoul 6 | L-Lo Ft | 0xb4097cc3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 3 | Fr-Lf Up Leg | 0x99338c09</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 3 | Fr-Lf Lo Leg | 0x7491a630</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 3 | Fr-Lf Foot | 0x8a99ba3f</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 4 | Bk-Lf Thigh | 0xa7860026</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 4 | Bk-Lf Knee | 0xaf6a52d7</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 4 | Bk-Lf Ankle | 0xb42c3610</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 4 | Bk-Lf Foot | 0x6e284ec0</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 5 | Bk-Ri Thigh | 0x0e97871c</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 5 | Bk-Ri Knee | 0x02433b3b</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 5 | Bk-Ri Ankle | 0x1d3db12a</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 5 | Bk-Ri Foot | 0x20c9e4aa</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 6 | Fr-Ri Up Leg | 0x5f96443c</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 6 | Fr-Ri Lo Leg | 0xdd80210a</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Super Mutant Hound 6 | Fr-Ri Foot | 0x4c3c720a</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 2 | Fr-Ri-Up Arm | 0xa5f4be71</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 2 | Fr-Ri-Lo Arm | 0x99eb64eb</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 2 | R Claw | 0x3c9df64f</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 4 | L Shoulder | 0x40f66ca4</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 4 | L-Up Arm | 0xc1f62792</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 4 | L Elbow | 0xf0da47f2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 4 | L Claw | 0x55acd556</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 5 | Fr-Ri Hip | 0x064f59cd</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 5 | Fr-Ri Thigh | 0x5b033df6</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 5 | Fr-Ri Calf | 0x15fc7bad</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 5 | Fr-Ri Foot | 0xf028841e</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 6 | Fr-Lf Hip-Thigh | 0xf62a541a</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 6 | Fr-Lf Kne-Clf | 0x5b1dd1c7</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 6 | Fr-Lf Foot | 0xbec92e74</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 8 | Bk-Ri Hip-Thigh | 0xfc5546b8</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 8 | Bk-Ri Kne-Clf | 0x24a15449</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 8 | Bk-Ri Foot | 0xc175abfa</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 9 | Bk-Lf Hip-Thigh | 0xb2b4ecd2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 9 | Bk-Lf Kne-Clf | 0xc1886aab</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Mirelurk 9 | Bk-Lf Foot | 0x245c9518</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 3 | Fr-Lf Knee | 0x5530c47b</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 3 | Fr-Lf Calf | 0xcc3995c1</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 3 | Fr-Lf Heel+Arch | 0xbd2750cf</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 3 | Fr-Lf Paw | 0x77fe1ec8</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 4 | Bk-Lf Knee | 0x52f7244b</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 4 | Bk-Lf Calf | 0xcbfe75f1</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 4 | Bk-Lf Heel+Arch | 0xfe31ace4</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 4 | Bk-Lf Paw | 0x08eb5fa0</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 5 | Bk-Ri Knee | 0x8d270da8</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 5 | Bk-Ri Calf+Heel | 0x142e5c12</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 5 | Bk-Ri Arch | 0x9a333507</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 5 | Bk-Ri Paw | 0x61da7cb9</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 6 | Fr-Ri Knee | 0x8ae0ed98</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 6 | Fr-Ri Calf | 0x13e9bc22</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 6 | Fr-Ri Heel+Arch | 0xd925c92c</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Dog 6 | Fr-Ri Paw | 0x1ecf3dd1</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 2 | R-Arm+Elbow | 0x8c5ae189</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 2 | R-4 Arm | 0x071dfd97</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 2 | R-Hand | 0xded0fadf</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 4 | L-Arm+Elbow | 0xc2bb4be3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 4 | L-4 Arm | 0x3e7a4ccc</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 4 | L-Hand | 0xe7b74b84</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 5 | R-Calf | 0xa411c600</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 5 | R-Foot | 0xac900af3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 6 | L-Calf | 0xc0135fe3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Behemoth 6 | R-Foot | 0x95f7bba8</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Robot 3 | Torso | 0x3d6644aa</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"segmentSlotLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Slot</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"segmentSlot\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">None</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">30 - Hair Top</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">31 - Hair Long</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">32 - Head</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">33 - Body</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">34 - L Hand</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">35 - R Hand</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">36 - [U] Torso</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">37 - [U] L Arm</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">38 - [U] R Arm</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">39 - [U] L Leg</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">40 - [U] R Leg</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">41 - [A] Torso</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">42 - [A] L Arm</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">43 - [A] R Arm</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">44 - [A] L Leg</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">45 - [A] R Leg</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">46 - Headband</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">47 - Eyes</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">48 - Beard</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">49 - Mouth</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">50 - Neck</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">51 - Ring</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">52 - Scalp</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">53 - Decapitation</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">54 - Unnamed</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">55 - Unnamed</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">56 - Unnamed</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">57 - Unnamed</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">58 - Unnamed</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">59 - Shield</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">60 - Pipboy</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">61 - FX</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">65 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">70 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">75 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">80 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">85 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">90 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">95 - Robot</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">100 - Gore</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">101 - Gore</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">102 - Gore</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">103 - Gore</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">160 - Pipboy Cap</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"segmentSSFLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>SSF File</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"segmentSSF\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>255</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"segmentSSFEdit\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Set</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"segmentApply\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Apply</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"segmentReset\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Reset</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"partitionTypeLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Type</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"partitionType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">0 BP_TORSO</item><item translate=\"0\">1 BP_HEAD</item><item translate=\"0\">2 BP_HEAD2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">3 BP_LEFTARM</item><item translate=\"0\">4 BP_LEFTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">5 BP_RIGHTARM</item><item translate=\"0\">6 BP_RIGHTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">7 BP_LEFTLEG</item><item translate=\"0\">8 BP_LEFTLEG2</item><item translate=\"0\">9 BP_LEFTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">10 BP_RIGHTLEG</item><item translate=\"0\">11 BP_RIGHTLEG2</item><item translate=\"0\">12 BP_RIGHTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">13 BP_BRAIN</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">30 SBP_30_HEAD</item><item translate=\"0\">31 SBP_31_HAIR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">32 SBP_32_BODY</item><item translate=\"0\">33 SBP_33_HANDS</item><item translate=\"0\">34 SBP_34_FOREARMS</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">35 SBP_35_AMULET</item><item translate=\"0\">36 SBP_36_RING</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">37 SBP_37_FEET</item><item translate=\"0\">38 SBP_38_CALVES</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">39 SBP_39_SHIELD</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">40 SBP_40_TAIL</item><item translate=\"0\">41 SBP_41_LONGHAIR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">42 SBP_42_CIRCLET</item><item translate=\"0\">43 SBP_43_EARS</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">44 SBP_44_DRAGON_BLOODHEAD_OR_MOD_MOUTH</item><item translate=\"0\">45 SBP_45_DRAGON_BLOODWINGL_OR_MOD_NECK</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">46 SBP_46_DRAGON_BLOODWINGR_OR_MOD_CHEST_PRIMARY</item><item translate=\"0\">47 SBP_47_DRAGON_BLOODTAIL_OR_MOD_BACK</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">48 SBP_48_MOD_MISC1</item><item translate=\"0\">49 SBP_49_MOD_PELVIS_PRIMARY</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">50 SBP_50_DECAPITATEDHEAD</item><item translate=\"0\">51 SBP_51_DECAPITATE</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">52 SBP_52_MOD_PELVIS_SECONDARY</item><item translate=\"0\">53 SBP_53_MOD_LEG_RIGHT</item><item translate=\"0\">54 SBP_54_MOD_LEG_LEFT</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">55 SBP_55_MOD_FACE_JEWELRY</item><item translate=\"0\">56 SBP_56_MOD_CHEST_SECONDARY</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">57 SBP_57_MOD_SHOULDER</item><item translate=\"0\">58 SBP_58_MOD_ARM_LEFT</item><item translate=\"0\">59 SBP_59_MOD_ARM_RIGHT</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">60 SBP_60_MOD_MISC2</item><item translate=\"0\">61 SBP_61_FX01</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">101 BP_SECTIONCAP_HEAD</item><item translate=\"0\">102 BP_SECTIONCAP_HEAD2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">103 BP_SECTIONCAP_LEFTARM</item><item translate=\"0\">104 BP_SECTIONCAP_LEFTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">105 BP_SECTIONCAP_RIGHTARM</item><item translate=\"0\">106 BP_SECTIONCAP_RIGHTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">107 BP_SECTIONCAP_LEFTLEG</item><item translate=\"0\">108 BP_SECTIONCAP_LEFTLEG2</item><item translate=\"0\">109 BP_SECTIONCAP_LEFTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">110 BP_SECTIONCAP_RIGHTLEG</item><item translate=\"0\">111 BP_SECTIONCAP_RIGHTLEG2</item><item translate=\"0\">112 BP_SECTIONCAP_RIGHTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">113 BP_SECTIONCAP_BRAIN</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">130 SBP_130_HEAD</item><item translate=\"0\">131 SBP_131_HAIR</item><item translate=\"0\">141 SBP_141_LONGHAIR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">142 SBP_142_CIRCLET</item><item translate=\"0\">143 SBP_143_EARS</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">150 SBP_150_DECAPITATEDHEAD</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">201 BP_TORSOCAP_HEAD</item><item translate=\"0\">202 BP_TORSOCAP_HEAD2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">203 BP_TORSOCAP_LEFTARM</item><item translate=\"0\">204 BP_TORSOCAP_LEFTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">205 BP_TORSOCAP_RIGHTARM</item><item translate=\"0\">206 BP_TORSOCAP_RIGHTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">207 BP_TORSOCAP_LEFTLEG</item><item translate=\"0\">208 BP_TORSOCAP_LEFTLEG2</item><item translate=\"0\">209 BP_TORSOCAP_LEFTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">210 BP_TORSOCAP_RIGHTLEG</item><item translate=\"0\">211 BP_TORSOCAP_RIGHTLEG2</item><item translate=\"0\">212 BP_TORSOCAP_RIGHTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">213 BP_TORSOCAP_BRAIN</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">230 SBP_230_HEAD</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">1000 BP_TORSOSECTION_HEAD</item><item translate=\"0\">2000 BP_TORSOSECTION_HEAD2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">3000 BP_TORSOSECTION_LEFTARM</item><item translate=\"0\">4000 BP_TORSOSECTION_LEFTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">5000 BP_TORSOSECTION_RIGHTARM</item><item translate=\"0\">6000 BP_TORSOSECTION_RIGHTARM2</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">7000 BP_TORSOSECTION_LEFTLEG</item><item translate=\"0\">8000 BP_TORSOSECTION_LEFTLEG2</item><item translate=\"0\">9000 BP_TORSOSECTION_LEFTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">10000 BP_TORSOSECTION_RIGHTLEG</item><item translate=\"0\">11000 BP_TORSOSECTION_RIGHTLEG2</item><item translate=\"0\">12000 BP_TORSOSECTION_RIGHTLEG3</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">13000 BP_TORSOSECTION_BRAIN</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"partitionApply\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Apply</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"partitionReset\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Reset</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"selectSliders\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>De-/Select Sliders</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>1</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"unknown\" name=\"sliderFilter\" />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbFixedWeight\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Fixed Weight Brush</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbNormalizeWeights\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Normalize Weights</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>15</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"xMirrorBoneLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<fg>#ffffff</fg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>X-Mirror Bone</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"cXMirrorBone\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxLEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"masksPane\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCP_DEFAULT_STYLE|wxCP_NO_TLW_RESIZE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Masks</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>wxSYS_COLOUR_MENU</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>0</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxComboBox\" name=\"cMaskName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"saveMask\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Save</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"deleteMask\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Delete</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"exportMask\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Export...</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"importMask\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Import...</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxLEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"posePane\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCP_DEFAULT_STYLE|wxCP_NO_TLW_RESIZE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Posing</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>wxSYS_COLOUR_MENU</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxComboBox\" name=\"cPoseName\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"savePose\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Save</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"deletePose\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Delete</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"loadHkxPose\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Load HKX...</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbPose\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Show Pose</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"cPoseBone\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"resetBonePose\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Reset Bone</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rxLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotation X</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"rxPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-300</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>300</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"rxPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"ryLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotation Y</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"ryPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-300</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>300</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"ryPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"rzLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotation Z</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"rzPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-300</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>300</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"rzPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"txLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Offset X</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"txPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-1000</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>1000</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"txPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"tyLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Offset Y</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"tyPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-1000</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>1000</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"tyPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"tzLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Offset Z</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"tzPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-1000</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>1000</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"tzPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxALIGN_LEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"scLabel\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxSlider\" name=\"scPoseSlider\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxSL_HORIZONTAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,10</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<min>-1000</min>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<max>1000</max>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxBOTTOM|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"scPoseText\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_RIGHT|wxSIMPLE_BORDER</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>40,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>0</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"resetAllPose\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Reset All</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"poseToMesh\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,25</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Apply to Mesh</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxScrolledWindow\" name=\"sliderScroll\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxHSCROLL|wxVSCROLL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>#404040</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<scrollrate>18,18</scrollrate>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxLEFT</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"notesPane\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCP_DEFAULT_STYLE|wxCP_NO_TLW_RESIZE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Notes</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<bg>wxSYS_COLOUR_MENU</bg>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"projectNotes\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_MULTILINE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,120</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxStatusBar\" name=\"statusBar\">\n\t\t\t<style>wxST_SIZEGRIP</style>\n\t\t\t<bg>#404040</bg>\n\t\t\t<fields>1</fields>\n\t\t</object>\n\t</object>\n\n\t<object class=\"wxMenuBar\" name=\"menuBar\">\n\t\t<label>Menu</label>\n\t\t<object class=\"wxMenu\" name=\"menuFile\">\n\t\t\t<label>File</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnNewProject\">\n\t\t\t\t<label>New Project...\\tCtrl+N</label>\n\t\t\t\t<help>Create a new outfit project.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnLoadProject\">\n\t\t\t\t<label>Load Project..\\tCtrl+O</label>\n\t\t\t\t<help>Load a project.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnAddProject\">\n\t\t\t\t<label>Add Project..\\tCtrl+Shift+O</label>\n\t\t\t\t<help>Add a project without replacing the current one.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"fileUnload\">\n\t\t\t\t<label>Unload Project...\\tCtrl+W</label>\n\t\t\t\t<help>Unloads the project and creates an empty new one.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenu\" name=\"menuRecentProjects\">\n\t\t\t\t<label>Recent Projects...</label>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"fileLoadRef\">\n\t\t\t\t<label>Load Reference...</label>\n\t\t\t\t<help>Load a new reference slider set, replacing any current reference objects.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"fileLoadOutfit\">\n\t\t\t\t<label>Load Outfit...</label>\n\t\t\t\t<help>Load a NIF file as the working outfit, replacing any current outfit objects.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"fileConvBodyRef\">\n\t\t\t\t<label>Convert / Replace Reference...\\tCtrl+Shift+R</label>\n\t\t\t\t<help>Convert to or replace an outfit's body/reference</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"menuRunAutomation\">\n\t\t\t\t<label>Open Automation...\\tCtrl+Shift+A</label>\n\t\t\t\t<help>Open the automation dialog to create, load and execute automation scripts.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"fileSave\">\n\t\t\t\t<label>Save Project\\tCtrl+S</label>\n\t\t\t\t<help>Save the project.</help>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"fileSaveAs\">\n\t\t\t\t<label>Save Project As...\\tCtrl+Shift+S</label>\n\t\t\t\t<help>Save the project under a new name.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenu\" name=\"menuImport\">\n\t\t\t\t<label>Import</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"importNIF\">\n\t\t\t\t\t<label>From NIF...</label>\n\t\t\t\t\t<help>Choose a NIF file to import into the project.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"importOBJ\">\n\t\t\t\t\t<label>From OBJ...</label>\n\t\t\t\t\t<help>Import an OBJ file as a new shape in the outfit.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"importFBX\">\n\t\t\t\t\t<label>From FBX...</label>\n\t\t\t\t\t<help>Import an FBX file as a new shape in the outfit.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"importTRIHead\">\n\t\t\t\t\t<label>From TRI (Head)...</label>\n\t\t\t\t\t<help>Import shape and morphs from a head TRI file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenu\" name=\"menuImportData\">\n\t\t\t\t\t<label>Import Data</label>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"importPhysicsData\">\n\t\t\t\t\t\t<label>Import BSClothExtraData From HKX</label>\n\t\t\t\t\t\t<help>Choose an HKX file to import as a BSClothExtraData block into the project.</help>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenu\" name=\"menuExport\">\n\t\t\t\t<label>Export</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportNIF\">\n\t\t\t\t\t<label>To NIF...\\tCtrl+E</label>\n\t\t\t\t\t<help>Save the current project as a NIF file (without reference)</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportNIFWithRef\">\n\t\t\t\t\t<label>To NIF With Reference...\\tCtrl+Alt+E</label>\n\t\t\t\t\t<help>Save the current project as a NIF file (including reference)</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportOBJ\">\n\t\t\t\t\t<label>To OBJ...</label>\n\t\t\t\t\t<help>Export the current project as an OBJ file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportFBX\">\n\t\t\t\t\t<label>To FBX...</label>\n\t\t\t\t\t<help>Export the current project as an FBX file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportTRIHead\">\n\t\t\t\t\t<label>To TRI (Head)...</label>\n\t\t\t\t\t<help>Export head morphs to a TRI file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenu\" name=\"menuExportData\">\n\t\t\t\t\t<label>Export Data</label>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"exportPhysicsData\">\n\t\t\t\t\t\t<label>Export BSClothExtraData As HKX</label>\n\t\t\t\t\t\t<help>Save one of the currently loaded BSClothExtraData blocks to an HKX file.</help>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"makeConvRef\">\n\t\t\t\t<label>Make Conversion Reference</label>\n\t\t\t\t<help>Using the current slider settings for the reference shape, create a new reference that will morph from the current shape back to the base shape.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"packProjects\">\n\t\t\t\t<label>Pack Projects...</label>\n\t\t\t\t<help>Pack one or more projects into a folder or archive for sharing.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"fileSettings\">\n\t\t\t\t<label>Settings</label>\n\t\t\t\t<help>Open settings dialog.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"fileExit\">\n\t\t\t\t<label>Exit\\tAlt+F4</label>\n\t\t\t\t<help>Exit Outfit Studio.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuEdit\">\n\t\t\t<label>Edit</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"editUndo\">\n\t\t\t\t<label>Undo\\tCtrl+Z</label>\n\t\t\t\t<help>Undo the previous action.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"editRedo\">\n\t\t\t\t<label>Redo\\tCtrl+Y</label>\n\t\t\t\t<help>Redo the next undone action.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"btnXMirror\">\n\t\t\t\t<label>X Mirror\\tX</label>\n\t\t\t\t<help>Mirror edits across the X axis.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnConnected\">\n\t\t\t\t<label>Edit Connected Only\\tC</label>\n\t\t\t\t<help>Edit only vertices that are connected to the ones under the brush within the brush radius</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnMerge\">\n\t\t\t\t<label>Merge Vertex</label>\n\t\t\t\t<help>Merges two vertices and fills any gaps.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnWeld\">\n\t\t\t\t<label>Weld Vertex</label>\n\t\t\t\t<help>Welds two vertices while keeping the texture coordinates (UV) distinct.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnRestrictSurface\">\n\t\t\t\t<label>Restrict To Surface</label>\n\t\t\t\t<help>Restricts motion to a mesh surface.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnRestrictPlane\">\n\t\t\t\t<label>Restrict To Plane</label>\n\t\t\t\t<help>Restricts motion to parallel to the surface.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnRestrictNormal\">\n\t\t\t\t<label>Restrict To Normal</label>\n\t\t\t\t<help>Restricts motion to perpendicular to the surface.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"btnRecalcNormals\">\n\t\t\t\t<label>Recalculate Normals</label>\n\t\t\t\t<help>Recalculate normals on active mesh</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"disableNormalsCalc\">\n\t\t\t\t<label>Disable Normals Calculation</label>\n\t\t\t\t<help>Turn off all automatic recalculation of normals on all meshes. Only applies to Outfit Studio.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>0</checked>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"resetTransforms\">\n\t\t\t\t<label>Reset Transforms</label>\n\t\t\t\t<help>Resets the shape and skin transforms.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"deleteUnreferencedNodes\">\n\t\t\t\t<label>Delete Unreferenced Nodes</label>\n\t\t\t\t<help>Deletes all nodes from the project that aren't used in any other block.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"removeSkinning\">\n\t\t\t\t<label>Remove Skinning</label>\n\t\t\t\t<help>Removes skinning of all shapes and all unused nodes.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuMesh\">\n\t\t\t<label>Shape</label>\n\t\t\t<object class=\"wxMenu\" name=\"menuExportMesh\">\n\t\t\t\t<label>Export</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeNIF\">\n\t\t\t\t\t<label>To NIF...</label>\n\t\t\t\t\t<help>Export only the selected shapes to a NIF file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeOBJ\">\n\t\t\t\t\t<label>To OBJ...</label>\n\t\t\t\t\t<help>Export only the selected shapes to an OBJ file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeFBX\">\n\t\t\t\t\t<label>To FBX...</label>\n\t\t\t\t\t<help>Export only the selected shapes to an FBX file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeTRIHead\">\n\t\t\t\t\t<label>To TRI (Head)...</label>\n\t\t\t\t\t<help>Export head morphs to a TRI file.</help>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenu\" name=\"menuUV\">\n\t\t\t\t<label>UV</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"uvEdit\">\n\t\t\t\t\t<label>Edit...</label>\n\t\t\t\t\t<help>Edit the texture coordinates.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"uvInvertX\">\n\t\t\t\t\t<label>Invert X (Mirror)</label>\n\t\t\t\t\t<help>Inverts the X-axis to mirror the texture coordinates.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"uvInvertY\">\n\t\t\t\t\t<label>Invert Y (Flip)</label>\n\t\t\t\t\t<help>Inverts the Y-axis to flip the texture coordinates.</help>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"deleteVerts\">\n\t\t\t\t<label>Delete Vertices...\\tShift+Del</label>\n\t\t\t\t<help>Deletes all unmasked vertices of the currently selected shapes.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"separateVerts\">\n\t\t\t\t<label>Separate Vertices...\\tShift+S</label>\n\t\t\t\t<help>Separate the current shape into two by using the mask.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"mirrorShape\">\n\t\t\t\t<label>Mirror Shape...</label>\n\t\t\t\t<help>Mirror the selected shapes on any axis.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"copyGeo\">\n\t\t\t\t<label>Merge Geometry...</label>\n\t\t\t\t<help>Copies vertices and triangles from one shape to another.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"copyShape\">\n\t\t\t\t<label>Duplicate...</label>\n\t\t\t\t<help>Duplicate the current shape.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"refineMesh\">\n\t\t\t\t<label>Refine Mesh</label>\n\t\t\t\t<help>Splits all edges between unmasked vertices</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"renameShape\">\n\t\t\t\t<label>Rename...\\tF2</label>\n\t\t\t\t<help>Change the name of the current shape.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"setReference\">\n\t\t\t\t<label>Set Reference</label>\n\t\t\t\t<help>Turn the shape into the reference shape of the project.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"moveShape\">\n\t\t\t\t<label>Move...</label>\n\t\t\t\t<help>Apply an offset adjustment to the mesh vertices. This permanently moves vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"scaleShape\">\n\t\t\t\t<label>Scale...</label>\n\t\t\t\t<help>Apply a scale adjustment to the shape. This permanently moves vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"rotateShape\">\n\t\t\t\t<label>Rotate...</label>\n\t\t\t\t<help>Apply a rotation to the mesh vertices. This permanently moves vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"inflateShape\">\n\t\t\t\t<label>Inflate...</label>\n\t\t\t\t<help>Inflates/deflates a shape along its normals. This permanently moves vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"fixClippingShape\">\n\t\t\t\t<label>Fix Clipping...</label>\n\t\t\t\t<help>Fixes clipping of outfit vertices that penetrate the reference shape.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenu\" name=\"menuNormals\">\n\t\t\t\t<label>Normals</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnSmoothSeams\">\n\t\t\t\t\t<label>Smooth Seam Normals</label>\n\t\t\t\t\t<help>Smooths edges of seams (usually found at texture borders), disable if this causes odd normals on the shape.</help>\n\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t<checkable>1</checkable>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnSmoothSeamsAngle\">\n\t\t\t\t\t<label>Edit Smoothing Angle...</label>\n\t\t\t\t\t<help>Angle, in degrees, that controls the threshold at which normal seams are smoothed.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnLockNormals\">\n\t\t\t\t\t<label>Lock Normals</label>\n\t\t\t\t\t<help>Locks the mesh normals. Enable if you want to keep custom normals intact.</help>\n\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t<checkable>1</checkable>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"copyBoneWeight\">\n\t\t\t\t<label>Copy Bone Weights</label>\n\t\t\t\t<help>Copies all bone weights from the reference shape to the current shape.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"transferSelectedWeight\">\n\t\t\t\t<label>Transfer Selected Weights</label>\n\t\t\t\t<help>Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"maskWeightedVerts\">\n\t\t\t\t<label>Mask Weighted Vertices</label>\n\t\t\t\t<help>Masks vertices with bone weights, so you can manually assign weights to unweighted vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"checkBadBones\">\n\t\t\t\t<label>Check For Bad Bones...</label>\n\t\t\t\t<help>Looks for bones with inconsistencies in their transforms.  If any are found, a dialog is opened to give options for fixing them.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"copySegPart\">\n\t\t\t\t<label>Copy Partitions/Segments...</label>\n\t\t\t\t<help>Copies partitions/segments and all triangle assignments from the reference shape to the current shape.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"maskSymVert\">\n\t\t\t\t<label>Mask Symmetric Vertices...</label>\n\t\t\t\t<help>Masks unmasked vertices that have a mirrored vertex with identical data.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"symVert\">\n\t\t\t\t<label>Symmetrize Vertices...</label>\n\t\t\t\t<help>Changes vertex data to be identical to mirrored vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"maskSymTri\">\n\t\t\t\t<label>Mask Symmetric Triangles</label>\n\t\t\t\t<help>Masks triangles that can be matched to a mirrored triangle.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"deleteShape\">\n\t\t\t\t<label>Delete\\tDel</label>\n\t\t\t\t<help>Removes the currently selected shape from the outfit.</help>\n\t\t\t\t<extra-accels>\n\t\t\t\t\t<accel>Ctrl+Shift+Del</accel>\n\t\t\t\t</extra-accels>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"shapeProperties\">\n\t\t\t\t<label>Properties...</label>\n\t\t\t\t<help>Opens the properties dialog for shader, texture and more settings of the selected shape.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuSlider\">\n\t\t\t<label>Slider</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderConform\">\n\t\t\t\t<label>Conform Selected\\tCtrl+C</label>\n\t\t\t\t<help>Conform selected outfit shape to all checked sliders.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderConformAll\">\n\t\t\t\t<label>Conform All\\tCtrl+Shift+C</label>\n\t\t\t\t<help>Conform all outfit shapes to all checked sliders.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderFixClipping\">\n\t\t\t\t<label>Fix Clipping...</label>\n\t\t\t\t<help>Fixes clipping of outfit vertices that penetrate the reference shape for the active slider.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"saveBaseShape\">\n\t\t\t\t<label>Set Base Shape</label>\n\t\t\t\t<help>Set the current outfit shape as the base shape and clear slider data.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderLoadPreset\">\n\t\t\t\t<label>Load Preset...</label>\n\t\t\t\t<help>Load and preview a slider preset. Inverted sliders will have inverted values.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderSavePreset\">\n\t\t\t\t<label>Save Preset...</label>\n\t\t\t\t<help>Save a slider preset with the current values. Inverted sliders will have inverted values.</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderNew\">\n\t\t\t\t<label>New Slider</label>\n\t\t\t\t<help>Create a new shape transformation slider.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderNewCombined\">\n\t\t\t\t<label>Coalesce sliders</label>\n\t\t\t\t<help>Create a new shape transformation slider based on the current slider values</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderNewZap\">\n\t\t\t\t<label>New Zap Slider</label>\n\t\t\t\t<help>Create a new Zap slider based on unmasked vertices</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenu\" name=\"menuSliderImportGroup\">\n\t\t\t\t<label>Import</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportOSD\">\n\t\t\t\t\t<label>Import OSD...</label>\n\t\t\t\t\t<help>Imports OSD file and creates sliders for shapes with a matching name.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportTRI\">\n\t\t\t\t\t<label>Import TRI Morphs...</label>\n\t\t\t\t\t<help>Imports TRI morphs from a TRI file and creates sliders for shapes with a matching name.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportMorphsSF\">\n\t\t\t\t\t<label>Import Starfield morphs...</label>\n\t\t\t\t\t<help>Imports Starfield morph.dat file and creates sliders for shapes with a matching name.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"separator\" />\n\t\t\t\t<object class=\"wxMenu\" name=\"menuImportSlider\">\n\t\t\t\t\t<label>Import to active slider</label>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportNIF\">\n\t\t\t\t\t\t<label>Import NIF...</label>\n\t\t\t\t\t\t<help>Import a NIF file and overwrites the current shape's slider data.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportBSD\">\n\t\t\t\t\t\t<label>Import BSD...</label>\n\t\t\t\t\t\t<help>Import a BodySlide BSD file and overwrites the current shape's slider data.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportOBJ\">\n\t\t\t\t\t\t<label>Import OBJ...</label>\n\t\t\t\t\t\t<help>Import an OBJ file matching the current shape's vertex count, and calculate slider data from the difference.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderImportFBX\">\n\t\t\t\t\t\t<label>Import FBX...</label>\n\t\t\t\t\t\t<help>Import an FBX file matching the current shape's vertex count, and calculate slider data from the difference.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenu\" name=\"menuSliderExportGroup\">\n\t\t\t\t<label>Export</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportOSD\">\n\t\t\t\t\t<label>Export OSD...</label>\n\t\t\t\t\t<help>Exports all currently loaded slider data to an OSD file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportTRI\">\n\t\t\t\t\t<label>Export TRI Morphs...</label>\n\t\t\t\t\t<help>Exports TRI morphs to a TRI file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportMorphsSF\">\n\t\t\t\t\t<label>Export Starfield morphs...</label>\n\t\t\t\t\t<help>Exports Starfield morph.dat file.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportToOBJs\">\n\t\t\t\t\t<label>Export to OBJs...</label>\n\t\t\t\t\t<help>Export all sliders to an OBJ file per slider.</help>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"separator\" />\n\t\t\t\t<object class=\"wxMenu\" name=\"menuExportSlider\">\n\t\t\t\t\t<label>Export active slider</label>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportNIF\">\n\t\t\t\t\t\t<label>Export NIF...</label>\n\t\t\t\t\t\t<help>Exports the current slider's data as a NIF file.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportBSD\">\n\t\t\t\t\t\t<label>Export BSD...</label>\n\t\t\t\t\t\t<help>Exports the current slider's data as a BodySlide BSD file.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"wxMenuItem\" name=\"sliderExportOBJ\">\n\t\t\t\t\t\t<label>Export OBJ...</label>\n\t\t\t\t\t\t<help>Exports the current slider's data as an OBJ file.</help>\n\t\t\t\t\t</object>\n\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderClone\">\n\t\t\t\t<label>Clone Slider</label>\n\t\t\t\t<help>Clones the current slider.</help>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderNegate\">\n\t\t\t\t<label>Negate Slider</label>\n\t\t\t\t<help>Negates the current slider, reversing it's effect</help>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderMask\">\n\t\t\t\t<label>Mask Affected Vertices</label>\n\t\t\t\t<help>Masks the vertices the slider is affecting for all selected shapes.</help>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderClear\">\n\t\t\t\t<label>Clear Slider Data</label>\n\t\t\t\t<help>Erases the slider data without removing the slider itself. (Cannot be undone)</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderDelete\">\n\t\t\t\t<label>Delete Slider\\tCtrl+Del</label>\n\t\t\t\t<help>Delete the active slider from the project. (Cannot be undone)</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"sliderProperties\">\n\t\t\t\t<label>Properties...\\tTab</label>\n\t\t\t\t<help>Display and edit the active slider's properties.</help>\n\t\t\t\t<enabled>0</enabled>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuBrush\">\n\t\t\t<label>Tool</label>\n\t\t\t<object class=\"wxMenu\" name=\"brushSelect\">\n\t\t\t\t<label>Current Tool</label>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnSelect\">\n\t\t\t\t\t<label>Select</label>\n\t\t\t\t\t<help>Navigate and select meshes (or vertices in vertex mode).</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnMaskBrush\">\n\t\t\t\t\t<label>Mask</label>\n\t\t\t\t\t<help>Mask vertices to prevent them from being transformed.\\nHold down the ALT key to remove masking.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnInflateBrush\">\n\t\t\t\t\t<label>Inflate</label>\n\t\t\t\t\t<help>Increase mesh volume in an area.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t<checked>1</checked>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnDeflateBrush\">\n\t\t\t\t\t<label>Deflate</label>\n\t\t\t\t\t<help>Decrease mesh volume in an area.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnMoveBrush\">\n\t\t\t\t\t<label>Move</label>\n\t\t\t\t\t<help>Move vertices over a plane parallel to the view.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnSmoothBrush\">\n\t\t\t\t\t<label>Smooth</label>\n\t\t\t\t\t<help>Smooth an area of a mesh.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnUndiffBrush\">\n\t\t\t\t\t<label>Undiff</label>\n\t\t\t\t\t<help>Undiff an area of a slider.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnWeightBrush\">\n\t\t\t\t\t<label>Weight Paint</label>\n\t\t\t\t\t<help>Apply animation weight values for the currently selected bone.\\nHold down the ALT key to weaken the weighting.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnColorBrush\">\n\t\t\t\t\t<label>Color Paint</label>\n\t\t\t\t\t<help>Apply vertex colors.\\nHold down the ALT key to remove colors.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnAlphaBrush\">\n\t\t\t\t\t<label>Alpha Paint</label>\n\t\t\t\t\t<help>Apply vertex alpha.\\nHold down the ALT key to remove alpha.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnCollapseVertex\">\n\t\t\t\t\t<label>Collapse Vertex</label>\n\t\t\t\t\t<help>Deletes vertices with no more than three connections, without creating a hole.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnFlipEdgeTool\">\n\t\t\t\t\t<label>Flip Edge</label>\n\t\t\t\t\t<help>Flips mesh edges so that the opposite pair of vertices is connected.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnSplitEdgeTool\">\n\t\t\t\t\t<label>Split Edge</label>\n\t\t\t\t\t<help>Splits a mesh edge in two with a new vertex.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnMoveVertexTool\">\n\t\t\t\t\t<label>Move Vertex</label>\n\t\t\t\t\t<help>Moves a vertex.</help>\n\t\t\t\t\t<radio>1</radio>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"separator\" />\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnTransform\">\n\t\t\t\t\t<label>Transform\\tF</label>\n\t\t\t\t\t<help>Shows a transform tool to manipulate shapes and vertices with.</help>\n\t\t\t\t\t<checkable>1</checkable>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnPivot\">\n\t\t\t\t\t<label>Pivot\\tP</label>\n\t\t\t\t\t<help>Shows a pivot that can be moved and makes it the center of mesh operations like rotation and scale.</help>\n\t\t\t\t\t<checkable>1</checkable>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"wxMenuItem\" name=\"btnVertexEdit\">\n\t\t\t\t\t<label>Vertex Edit\\tQ</label>\n\t\t\t\t\t<help>Shows vertex points and lets you mask/unmask them.\\nWithout any brush active, click on a vertex to unmask it.\\nHold down CTRL to mask it.</help>\n\t\t\t\t\t<checkable>1</checkable>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnIncreaseSize\">\n\t\t\t\t<label>Increase Brush Size\\tShift++</label>\n\t\t\t\t<help>Increase brush diameter</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnDecreaseSize\">\n\t\t\t\t<label>Decrease Brush Size\\tShift+-</label>\n\t\t\t\t<help>Decrease brush diameter</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnIncreaseStr\">\n\t\t\t\t<label>Increase Brush Strength\\tCtrl++</label>\n\t\t\t\t<help>Increase brush strength</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnDecreaseStr\">\n\t\t\t\t<label>Decrease Brush Strength\\tCtrl+-</label>\n\t\t\t\t<help>Decrease brush strength</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"btnMaskLess\">\n\t\t\t\t<label>Mask Less\\tA</label>\n\t\t\t\t<help>Mask Less</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnMaskMore\">\n\t\t\t\t<label>Mask More\\tD</label>\n\t\t\t\t<help>Mask More</help>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"btnInvertMask\">\n\t\t\t\t<label>Invert Mask\\tCtrl+I</label>\n\t\t\t\t<help>Invert Mask</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnClearMask\">\n\t\t\t\t<label>Clear Mask\\tCtrl+A</label>\n\t\t\t\t<help>Clear Mask</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuView\">\n\t\t\t<label>View</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnViewFront\">\n\t\t\t\t<label>Front\\tShift+1</label>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnViewBack\">\n\t\t\t\t<label>Back\\tShift+2</label>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnViewLeft\">\n\t\t\t\t<label>Left\\tShift+3</label>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnViewRight\">\n\t\t\t\t<label>Right\\tShift+4</label>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnViewPerspective\">\n\t\t\t\t<label>Perspective\\tShift+5</label>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t\t<checked>1</checked>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnToggleRotationCenter\">\n\t\t\t\t<label>Toggle Rotation Center\\tShift+R</label>\n\t\t\t\t<help>Switch between the different rotation center modes.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnFrameSelected\">\n\t\t\t\t<label>Frame Selected\\tR</label>\n\t\t\t\t<help>Center and zoom the camera to frame the selected shapes, ignoring masked vertices.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnShowNodes\">\n\t\t\t\t<label>Show Nodes\\tShift+N</label>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnShowBones\">\n\t\t\t\t<label>Show Bones\\tShift+B</label>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnShowFloor\">\n\t\t\t\t<label>Show Floor\\tG</label>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t\t<object class=\"separator\" />\n\t\t\t<object class=\"wxMenuItem\" name=\"btnToggleVisibility\">\n\t\t\t\t<label>Toggle Visibility\\tE</label>\n\t\t\t\t<help>Switch between the different visibility modes for the selected shapes.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnShowWireframe\">\n\t\t\t\t<label>Show Wireframe\\tW</label>\n\t\t\t\t<help>Show wireframe on all models.</help>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnEnableLighting\">\n\t\t\t\t<label>Enable Lighting\\tL</label>\n\t\t\t\t<help>Turn on or off lighting.</help>\n\t\t\t\t<checked>1</checked>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnEnableTextures\">\n\t\t\t\t<label>Enable Textures\\tT</label>\n\t\t\t\t<help>Display texture maps on models.</help>\n\t\t\t\t<checked>1</checked>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"btnEnableVertexColors\">\n\t\t\t\t<label>Enable Vertex Colors</label>\n\t\t\t\t<help>Display vertex colors on models.</help>\n\t\t\t\t<checked>0</checked>\n\t\t\t\t<checkable>1</checkable>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\n\t<object class=\"wxMenu\" name=\"menuMeshContext\">\n\t\t<label>Shape</label>\n\t\t<object class=\"wxMenu\" name=\"menuExportMesh\">\n\t\t\t<label>Export</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeNIF\">\n\t\t\t\t<label>To NIF...</label>\n\t\t\t\t<help>Export only the selected shapes to a NIF file.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeOBJ\">\n\t\t\t\t<label>To OBJ...</label>\n\t\t\t\t<help>Export only the selected shapes to an OBJ file.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeFBX\">\n\t\t\t\t<label>To FBX...</label>\n\t\t\t\t<help>Export only the selected shapes to an FBX file.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"exportShapeTRIHead\">\n\t\t\t\t<label>To TRI (Head)...</label>\n\t\t\t\t<help>Export head morphs to a TRI file.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuUV\">\n\t\t\t<label>UV</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"uvEdit\">\n\t\t\t\t<label>Edit...</label>\n\t\t\t\t<help>Edit the texture coordinates.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"uvInvertX\">\n\t\t\t\t<label>Invert X</label>\n\t\t\t\t<help>Inverts the X-axis of the texture coordinates.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"uvInvertY\">\n\t\t\t\t<label>Invert Y</label>\n\t\t\t\t<help>Inverts the Y-axis of the texture coordinates.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"deleteVerts\">\n\t\t\t<label>Delete Vertices...\\tShift+Del</label>\n\t\t\t<help>Deletes all unmasked vertices of the currently selected shapes.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"separateVerts\">\n\t\t\t<label>Separate Vertices...\\tShift+S</label>\n\t\t\t<help>Separate the current shape into two by using the mask.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"mirrorShape\">\n\t\t\t<label>Mirror Shape...</label>\n\t\t\t<help>Mirror the selected shapes on any axis.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"copyGeo\">\n\t\t\t<label>Merge Geometry...</label>\n\t\t\t<help>Copies vertices and triangles from one shape to another.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"copyShape\">\n\t\t\t<label>Duplicate...</label>\n\t\t\t<help>Duplicate the current shape.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"refineMesh\">\n\t\t\t<label>Refine Mesh</label>\n\t\t\t<help>Splits all edges between unmasked vertices</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"renameShape\">\n\t\t\t<label>Rename...\\tF2</label>\n\t\t\t<help>Change the name of the current shape.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"setReference\">\n\t\t\t<label>Set Reference</label>\n\t\t\t<help>Turn the shape into the reference shape of the project.</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"moveShape\">\n\t\t\t<label>Move...</label>\n\t\t\t<help>Apply an offset adjustment to the mesh vertices. This permanently moves vertices.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"scaleShape\">\n\t\t\t<label>Scale...</label>\n\t\t\t<help>Apply a scale adjustment to the shape. This permanently moves vertices.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"rotateShape\">\n\t\t\t<label>Rotate...</label>\n\t\t\t<help>Apply a rotation to the mesh vertices. This permanently moves vertices.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"inflateShape\">\n\t\t\t<label>Inflate...</label>\n\t\t\t<help>Inflates/deflates a shape along its normals. This permanently moves vertices.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"fixClippingShape\">\n\t\t\t<label>Fix Clipping...</label>\n\t\t\t<help>Fixes clipping of outfit vertices that penetrate the reference shape.</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"copyBoneWeight\">\n\t\t\t<label>Copy Bone Weights</label>\n\t\t\t<help>Copies all bone weights from the reference shape to the current shape.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"transferSelectedWeight\">\n\t\t\t<label>Transfer Selected Weights</label>\n\t\t\t<help>Transfers selected weights from the reference shape to the current shape. Requires same vertex count and order.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"maskWeightedVerts\">\n\t\t\t<label>Mask Weighted Vertices</label>\n\t\t\t<help>Masks vertices with bone weights, so you can manually assign weights to unweighted vertices.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"checkBadBones\">\n\t\t\t<label>Check For Bad Bones</label>\n\t\t\t<help>Looks for bones with inconsistencies in their transforms.  If any are found, a dialog is opened to give options for fixing them.</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"copySegPart\">\n\t\t\t<label>Copy Partitions/Segments...</label>\n\t\t\t<help>Copies partitions/segments and all triangle assignments from the reference shape to the current shape.</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"maskSymVert\">\n\t\t\t<label>Mask Symmetric Vertices...</label>\n\t\t\t<help>Masks unmasked vertices that have a mirrored vertex with identical data.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"symVert\">\n\t\t\t<label>Symmetrize Vertices...</label>\n\t\t\t<help>Changes vertex data to be identical to mirrored vertices.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"maskSymTri\">\n\t\t\t<label>Mask Symmetric Triangles</label>\n\t\t\t<help>Masks triangles that can be matched to a mirrored triangle.</help>\n\t\t</object>\n\t\t<object class=\"separator\" />\n\t\t<object class=\"wxMenuItem\" name=\"deleteShape\">\n\t\t\t<label>Delete\\tDel</label>\n\t\t\t<help>Removes the currently selected shape from the outfit.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"shapeProperties\">\n\t\t\t<label>Properties...</label>\n\t\t\t<help>Opens the properties dialog for shader, texture and more settings of the selected shape.</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuBoneContext\">\n\t\t<label>Bones</label>\n\t\t<object class=\"wxMenu\" name=\"menuBadBone\">\n\t\t\t<label>Bad Bone</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"setBoneSkin\">\n\t\t\t\t<label>Set Skin Transform From Node</label>\n\t\t\t\t<help>Fixes the bad bone by calculating a new skin-to-bone transform.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"setBoneNode\">\n\t\t\t\t<label>Set Node Transform From Skin</label>\n\t\t\t\t<help>Fixes the bad custom bone by calculating a new bone-to-global transform.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuAddBone\">\n\t\t\t<label>Add</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"addBone\">\n\t\t\t\t<label>From Skeleton...</label>\n\t\t\t\t<help>Choose a bone from the reference skeleton to add to the project.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"addCustomBone\">\n\t\t\t\t<label>Custom Bone...</label>\n\t\t\t\t<help>Add a custom bone to the project.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenu\" name=\"menuDeleteBone\">\n\t\t\t<label>Delete</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"deleteBone\">\n\t\t\t\t<label>From Project</label>\n\t\t\t\t<help>Delete bone(s) from all shapes of the project.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"deleteBoneSelected\">\n\t\t\t\t<label>From Selected Shapes</label>\n\t\t\t\t<help>Delete bone(s) from only the selected shapes.</help>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"editBone\">\n\t\t\t<label>Edit Bone...</label>\n\t\t\t<help>Edit a custom bone or view a standard bone.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"maskBoneWeightedVerts\">\n\t\t\t<label>Mask Weighted Vertices</label>\n\t\t\t<help>Masks vertices with weights for the selected bones.</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuBoneTreeContext\">\n\t\t<label>Bones</label>\n\t\t<object class=\"wxMenu\" name=\"menuAddBone\">\n\t\t\t<label>Add</label>\n\t\t\t<object class=\"wxMenuItem\" name=\"addBone\">\n\t\t\t\t<label>From Skeleton...</label>\n\t\t\t\t<help>Choose a bone from the reference skeleton to add to the project.</help>\n\t\t\t</object>\n\t\t\t<object class=\"wxMenuItem\" name=\"addCustomBone\">\n\t\t\t\t<label>Custom Bone...</label>\n\t\t\t\t<help>Add a custom bone to the project.</help>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuSegmentContext\">\n\t\t<label>Segments</label>\n\t\t<object class=\"wxMenuItem\" name=\"addSegment\">\n\t\t\t<label>Add Segment...</label>\n\t\t\t<help>Choose a segment to add to the shape.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"addSubSegment\">\n\t\t\t<label>Add Sub Segment...</label>\n\t\t\t<help>Add a new sub segment to the currently selected segment.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"deleteSegment\">\n\t\t\t<label>Delete Segment...</label>\n\t\t\t<help>Delete segment and all of its sub segments from the shape.</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuSubSegmentContext\">\n\t\t<label>Sub Segments</label>\n\t\t<object class=\"wxMenuItem\" name=\"addSubSegment\">\n\t\t\t<label>Add Sub Segment...</label>\n\t\t\t<help>Add a new sub segment to the currently selected segment.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"deleteSubSegment\">\n\t\t\t<label>Delete Sub Segment...</label>\n\t\t\t<help>Delete the selected sub segment.</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuSegmentTreeContext\">\n\t\t<label>Segments</label>\n\t\t<object class=\"wxMenuItem\" name=\"addSegment\">\n\t\t\t<label>Add Segment...</label>\n\t\t\t<help>Choose a segment to add to the shape.</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuPartitionContext\">\n\t\t<label>Partitions</label>\n\t\t<object class=\"wxMenuItem\" name=\"addPartition\">\n\t\t\t<label>Add Partition...</label>\n\t\t\t<help>Adds a new partition to the shape.</help>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"deletePartition\">\n\t\t\t<label>Delete Partition...</label>\n\t\t\t<help>Deletes the partition from the shape.</help>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"menuPartitionTreeContext\">\n\t\t<label>Partitions</label>\n\t\t<object class=\"wxMenuItem\" name=\"addPartition\">\n\t\t\t<label>Add Partition...</label>\n\t\t\t<help>Adds a new partition to the shape.</help>\n\t\t</object>\n\t</object>\n</resource>"
  },
  {
    "path": "res/xrc/Project.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxWizard\" name=\"wizNewProject\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>New Project</title>\n\t\t<pos>0,0</pos>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxWizardPageSimple\" name=\"wizpgNewProj1\">\n\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbNewProj1\">\n\t\t\t\t\t\t<label>Welcome to the New Project wizard!\\n\\nFirst, please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders.</label>\n\t\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<size>0,10</size>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Reference</label>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npRefIsTemplate\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>From Template</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npTemplateChoice\">\n\t\t\t\t\t\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npRefIsSliderset\">\n\t\t\t\t\t\t\t\t\t\t<label>From File</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"npSliderSetFile\">\n\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t<message>Select a project or NIF file</message>\n\t\t\t\t\t\t\t\t\t\t<wildcard>*.osp;*.xml;*.nif</wildcard>\n\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSliderSetName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Slider Set:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npSliderSetName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbRefShapeName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Shape:</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npRefShapeName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npRefIsBlank\">\n\t\t\t\t\t\t\t\t<label>Clear Reference</label>\n\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t\t<object class=\"wxWizardPageSimple\" name=\"wizpgNewProj2\">\n\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbNewProj2\">\n\t\t\t\t\t\t<label>Next, select an outfit/mesh to work on and enter a display name for it.</label>\n\t\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbOutfitName\">\n\t\t\t\t\t\t\t\t<label>Display Name</label>\n\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"npOutfitName\">\n\t\t\t\t\t\t\t\t<value translate=\"0\">New Outfit</value>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Outfit/Mesh</label>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npWorkFile\">\n\t\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t\t<label>From File</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"npWorkFilename\">\n\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t<message>Select a file to load as an outfit/mesh</message>\n\t\t\t\t\t\t\t\t\t\t<wildcard>*.nif; *.obj; *.fbx</wildcard>\n\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npWorkNone\">\n\t\t\t\t\t\t\t\t<label>Clear Outfit</label>\n\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<size>0,10</size>\n\t\t\t\t</object>\n\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t<option>0</option>\n\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t<border>5</border>\n\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t<label>Textures</label>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npTexAuto\">\n\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t<label>Automatically search for textures</label>\n\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npTexFile\">\n\t\t\t\t\t\t\t\t\t\t<label>From File</label>\n\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"npTexFilename\">\n\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t<message>Select a texture file</message>\n\t\t\t\t\t\t\t\t\t\t<wildcard>*.png; *.dds; *.jpg</wildcard>\n\t\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgSaveProject\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>486,345</size>\n\t\t<title>Save Project As...</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label translate=\"0\">BodySlide</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_sssName\">\n\t\t\t\t\t\t\t\t\t<label>Display Name</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sssName\">\n\t\t\t\t\t\t\t\t\t<tooltip>The name of the outfit and slider set, as it will appear in BodySlide.</tooltip>\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"sssNameCopy\">\n\t\t\t\t\t\t\t\t\t<tooltip>Copies the current display name to the project text fields below.</tooltip>\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t<label>To Project</label>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText9111\">\n\t\t\t\t\t\t\t\t\t<label>Output File Name</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sssOutputFileName\">\n\t\t\t\t\t\t\t\t\t<tooltip>The name of the outfit file that will end up in the game data path when BodySlide builds it. Should not include __1 or __0 in the name, e.g: lovelydress</tooltip>\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_lowHighInfo\">\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t<label translate=\"0\">__0/__1.nif</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_OutputDataPath\">\n\t\t\t\t\t\t\t\t\t<label>Output Data Path</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sssOutputDataPath\">\n\t\t\t\t\t\t\t\t\t<tooltip>The location in the game's data path where BodySlide-built outfit files will be placed, e.g: meshes\\clothes\\lovelydress</tooltip>\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"sssGenWeightsTrue\">\n\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t<tooltip>If this is enabled, BodySlide creates a low and high weight model when it generates the final outfit.</tooltip>\n\t\t\t\t\t\t\t<label>Low/High Weight Output</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"sssGenWeightsFalse\">\n\t\t\t\t\t\t\t<tooltip>If this is enabled, only one output file will be created (useful for single-weighted things like hair).</tooltip>\n\t\t\t\t\t\t\t<label>Single Weight Output</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Project</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_sssSliderSetFile\">\n\t\t\t\t\t\t\t\t\t<label>Slider Set File</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"sssSliderSetFile\">\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t<tooltip>The .osp slider set project file</tooltip>\n\t\t\t\t\t\t\t\t\t<message>Select slider set .osp file name</message>\n\t\t\t\t\t\t\t\t\t<wildcard>*.osp</wildcard>\n\t\t\t\t\t\t\t\t\t<style>wxFLP_SAVE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_sssShapeDataFolder\">\n\t\t\t\t\t\t\t\t\t<label>Shape Data Folder</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"sssShapeDataFolder\">\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t<tooltip>The folder where all the slider data will go, as well as the base outfit NIF file.</tooltip>\n\t\t\t\t\t\t\t\t\t<message>Select slider data folder</message>\n\t\t\t\t\t\t\t\t\t<style>wxDIRP_DIR_MUST_EXIST|wxDIRP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_sssShapeDataFile\">\n\t\t\t\t\t\t\t\t\t<label>Shape Data File</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"sssShapeDataFile\">\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t<tooltip>The name of the output's base NIF file.</tooltip>\n\t\t\t\t\t\t\t\t\t<message>Select output NIF file name</message>\n\t\t\t\t\t\t\t\t\t<wildcard>*.nif</wildcard>\n\t\t\t\t\t\t\t\t\t<style>wxFLP_SAVE|wxFLP_USE_TEXTCTRL</style>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"sssAutoCopyRef\">\n\t\t\t\t\t\t\t<tooltip>Outfits require the reference body to be a part of the output file. Disable this if you've already copied the reference over or you don't want it included.</tooltip>\n\t\t\t\t\t\t\t<label>Copy reference shape into output</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"sssPreventMorphFile\">\n\t\t\t\t\t\t\t<tooltip>Prevents the building of morph .tri files in BodySlide for this project.</tooltip>\n\t\t\t\t\t\t\t<label>Prevent morph file building in BodySlide</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"sssKeepZappedShapes\">\n\t\t\t\t\t\t\t<tooltip>Prevents the removal of fully zapped shapes when building in BodySlide. Useful when the shape order and count matters, like for retextures using texture sets.</tooltip>\n\t\t\t\t\t\t\t<label>Prevent removal of fully zapped shapes in BodySlide</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;Save</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgLoadRef\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>Load Reference</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadRef\">\n\t\t\t\t\t<label>Please choose a reference. Typically, this is a body (such as CBBE) or a conversion set (such as Vanilla To CBBE) and comes with its sliders.</label>\n\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Reference</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npRefIsTemplate\">\n\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t<label>From Template</label>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npTemplateChoice\">\n\t\t\t\t\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npRefIsSliderset\">\n\t\t\t\t\t\t\t\t\t<label>From File</label>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"npSliderSetFile\">\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t<message>Select a project or NIF file</message>\n\t\t\t\t\t\t\t\t\t<wildcard>*.osp;*.xml;*.nif</wildcard>\n\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSliderSetName\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Slider Set:</label>\n\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npSliderSetName\">\n\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbRefShapeName\">\n\t\t\t\t\t\t\t\t\t\t\t<label>Shape:</label>\n\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"npRefShapeName\">\n\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npRefIsBlank\">\n\t\t\t\t\t\t\t<label>Clear Reference</label>\n\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Merge</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxWrapSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkMergeZaps\">\n\t\t\t\t\t\t\t\t\t<label>Zaps</label>\n\t\t\t\t\t\t\t\t\t<tooltip>Merge existing zaps with new sliders</tooltip>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkMergeSliders\">\n\t\t\t\t\t\t\t\t\t<label>Sliders</label>\n\t\t\t\t\t\t\t\t\t<tooltip>Merge new sliders with existing sliders</tooltip>\n\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkAppendNewSliders\">\n\t\t\t\t\t\t\t\t\t<label>Append new sliders</label>\n\t\t\t\t\t\t\t\t\t<tooltip>Append new sliders that aren't in the project at the end of the list (or don't)</tooltip>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgLoadOutfit\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>Load Outfit</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbLoadOutfit\">\n\t\t\t\t\t<label>Please select an outfit/mesh to work on and enter a display name for it.</label>\n\t\t\t\t\t<wrap>380</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbOutfitName\">\n\t\t\t\t\t\t\t<label>Display Name</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"npOutfitName\">\n\t\t\t\t\t\t\t<value translate=\"0\">New Outfit</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Outfit/Mesh</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npWorkFile\">\n\t\t\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t\t\t<label>From File</label>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"npWorkFilename\">\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t<message>Select a file to load as an outfit/mesh</message>\n\t\t\t\t\t\t\t\t\t<wildcard>*.nif; *.obj; *.fbx</wildcard>\n\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npWorkNone\">\n\t\t\t\t\t\t\t<label>Clear Outfit</label>\n\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"npWorkAdd\">\n\t\t\t\t\t\t\t<label>Keep other shapes</label>\n\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<size>0,10</size>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Textures</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npTexAuto\">\n\t\t\t\t\t\t\t<style>wxRB_GROUP</style>\n\t\t\t\t\t\t\t<label>Automatically search for textures</label>\n\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"npTexFile\">\n\t\t\t\t\t\t\t\t\t<label>From File</label>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"npTexFilename\">\n\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t<message>Select a texture file</message>\n\t\t\t\t\t\t\t\t\t<wildcard>*.png; *.dds; *.jpg</wildcard>\n\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxBOTTOM|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgPackProjects\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>550,300</size>\n\t\t<title>Pack Projects...</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"unknown\" name=\"projectFilter\" />\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCheckListBox\" name=\"projectList\">\n\t\t\t\t\t<style>wxLB_EXTENDED|wxLB_HSCROLL|wxLB_NEEDED_SB</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbGroupFile\">\n\t\t\t\t\t\t\t<label>Group file (optional):</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"groupFile\">\n\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t<tooltip>Group file to pack (optional).</tooltip>\n\t\t\t\t\t\t\t<message>Select a group XML file</message>\n\t\t\t\t\t\t\t<wildcard>*.xml</wildcard>\n\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbMergedFileName\">\n\t\t\t\t\t\t\t<label>Merged file name:</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"mergedFileName\">\n\t\t\t\t\t\t\t<tooltip>File name to use for the merged project file.</tooltip>\t\n\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbOsp\">\n\t\t\t\t\t\t\t<label translate=\"0\">.osp</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"packFolder\">\n\t\t\t\t\t\t\t<label>Pack Folder...</label>\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"packArchive\">\n\t\t\t\t\t\t\t<label>Pack Archive...</label>\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"groupManager\">\n\t\t\t\t\t\t\t<label>Group Manager</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"projectListContext\">\n\t\t<object class=\"wxMenuItem\" name=\"projectListNone\">\n\t\t\t<label>Select None</label>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"projectListAll\">\n\t\t\t<label>Select All</label>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"projectListInvert\">\n\t\t\t<label>Invert Selection</label>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/SavePreset.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgSavePreset\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxCLIP_CHILDREN</style>\n\t\t<size>465,341</size>\n\t\t<title>Enter preset name...</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText15\">\n\t\t\t\t\t<label>Please enter a name for the new preset:</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxTextCtrl\" name=\"spPresetName\">\n\t\t\t\t\t<value translate=\"0\">CustomPreset</value>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText16\">\n\t\t\t\t\t\t\t<label>Select groups to assign to the new preset:</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"unknown\" name=\"spFilter\" />\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCheckListBox\" name=\"spGroupDisplay\">\n\t\t\t\t\t<style>wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_SORT</style>\n\t\t\t\t\t<content>\n\t\t\t\t\t\t<item translate=\"0\">one</item>\n\t\t\t\t\t\t<item translate=\"0\">two</item>\n\t\t\t\t\t\t<item translate=\"0\">three</item>\n\t\t\t\t\t</content>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxTOP</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_SAVE\">\n\t\t\t\t\t\t\t<label>&amp;Save</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/Settings.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n \t<object class=\"wxDialog\" name=\"dlgSettings\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>Settings</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Game</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbTargetGame\">\n\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t<label>Target Game</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceTargetGame\">\n\t\t\t\t\t\t\t\t\t<tooltip>Choose the target game you want to use the program for here.</tooltip>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Fallout 3</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Fallout New Vegas</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Skyrim</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Fallout 4</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Skyrim Special Edition</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Fallout 4 VR</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Skyrim VR</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Fallout 76</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Oblivion</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Starfield</item>\n\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbGameDataPath\">\n\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t<label>Game Data Path</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpGameDataPath\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">,90,90,-1,70,0</value>\n\t\t\t\t\t\t\t\t\t<message>Select the data path of the game...</message>\n\t\t\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t<tooltip>Data path to load textures from.</tooltip>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"advancedPane\">\n\t\t\t\t\t\t\t<style>wxCP_DEFAULT_STYLE|wxCP_NO_TLW_RESIZE</style>\n\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t<label>Advanced</label>\n\t\t\t\t\t\t\t<bg>wxSYS_COLOUR_MENU</bg>\n\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbOutputPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Output Path</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpOutputPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select the output path...</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Data path to build files to. If empty, Game Data Path will be used instead.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbProjectPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Project Path</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dpProjectPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<message>Select the project path...</message>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>Project path where files related to BodySlide are loaded from. If empty, executable directory will be used instead.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbShowForceBodyNormals\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<tooltip>With this turned on, BodySlide receives a new checkbox \"Force Body Normals\". Using it when building adds normal and tangent data to the body meshes (including bodies within outfits) for Skyrim. Use this only if you have a tangent space body mod.</tooltip>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Show &apos;Force Body Normals&apos;</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>General</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbBBOverrideWarn\">\n\t\t\t\t\t\t\t\t\t<tooltip>Enables/disables the dialog for choosing which set to build during a batch build if overrides happen.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Override Warning</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbBSATextures\">\n\t\t\t\t\t\t\t\t\t<tooltip>Enables/disables scanning BSAs in the game data folder for textures to load.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>BSA Textures</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbLeftMousePan\">\n\t\t\t\t\t\t\t\t\t<tooltip>Enables/disables panning the camera with the left mouse button in Outfit Studio.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Left Mouse Pan</label>\n\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbBrushSettingsNearCursor\">\n\t\t\t\t\t\t\t\t\t<tooltip>Enables/disables opening the brush settings near the mouse cursor when hitting the 'space' key.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Brush Settings Near Cursor</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbMaskHistory\">\n\t\t\t\t\t\t\t\t\t<tooltip>Enables/disables the undo history for the mask brush and vertex selection.</tooltip>\n\t\t\t\t\t\t\t\t\t<label>Mask History</label>\n\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSingleInstanceBehavior\">\n\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t<label>Single Instance</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceSingleInstanceBehavior\">\n\t\t\t\t\t\t\t\t\t<tooltip>Controls behavior when opening files and another instance is already running.</tooltip>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"1\">Ask (Message Box)</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"1\">Open in Existing</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"1\">Open in New</item>\n\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLanguage\">\n\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t<label>Language</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceLanguage\">\n\t\t\t\t\t\t\t\t\t<tooltip>Use the selected language for the program.</tooltip>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content></content>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Rendering</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbPerspectiveView\">\n\t\t\t\t\t\t\t<tooltip>Enables/disables the perspective view in the rendering window.</tooltip>\n\t\t\t\t\t\t\t<label>Perspective View</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbColorBackground\">\n\t\t\t\t\t\t\t\t\t<label>Background Color</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpColorBackground\">\n\t\t\t\t\t\t\t\t\t<tooltip>Background color of the renderer.</tooltip>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">rgb(210,210,210)</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbColorWire\">\n\t\t\t\t\t\t\t\t\t<label>Wireframe Color</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>2</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpColorWire\">\n\t\t\t\t\t\t\t\t\t<tooltip>Wireframe color of the renderer.</tooltip>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">rgb(80,80,80)</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbColorPoints\">\n\t\t\t\t\t\t\t\t\t<label>Point Color (normal/masked)</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpColorPoints\">\n\t\t\t\t\t\t\t\t\t<tooltip>Color of points in the renderer.</tooltip>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">rgb(0,255,0)</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"cpColorPointsMasked\">\n\t\t\t\t\t\t\t\t\t<tooltip>Color of masked points in the renderer.</tooltip>\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">rgb(255,0,0)</value>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<minsize>400,125</minsize>\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Data Files</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckListBox\" name=\"DataFileList\">\n\t\t\t\t\t\t\t<style>wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_EXTENDED</style>\n\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Reference Skeleton</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkeletonFile\">\n\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t<label>File</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxFilePickerCtrl\" name=\"fpSkeletonFile\">\n\t\t\t\t\t\t\t\t\t<value translate=\"0\">,90,90,-1,70,0</value>\n\t\t\t\t\t\t\t\t\t<message>Select a reference skeleton .nif file...</message>\n\t\t\t\t\t\t\t\t\t<wildcard>*.nif</wildcard>\n\t\t\t\t\t\t\t\t\t<style>wxFLP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t<tooltip>The reference skeleton file for Outfit Studio.</tooltip>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkeletonRoot\">\n\t\t\t\t\t\t\t\t\t<size>100,-1</size>\n\t\t\t\t\t\t\t\t\t<label>Root Node</label>\n\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>3</option>\n\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"choiceSkeletonRoot\">\n\t\t\t\t\t\t\t\t\t<tooltip>The root node name of the reference skeleton. Can differ from game to game.</tooltip>\n\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Root</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">NPC Root [Root]</item>\n\t\t\t\t\t\t\t\t\t\t<item translate=\"0\">Bip01</item>\n\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<size>0,20</size>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>"
  },
  {
    "path": "res/xrc/Setup.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgSetup\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>Setup</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbDescription\">\n\t\t\t\t\t<style>wxALIGN_CENTRE</style>\n\t\t\t\t\t<label>Please select the data folder and your target game.\\nYou can only choose one game at a time, but it is possible to change the selection in the settings.</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbOblivion\">\n\t\t\t\t\t\t\t<label translate=\"0\">Oblivion</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirOblivion\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btOblivion\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbFallout3\">\n\t\t\t\t\t\t\t<label translate=\"0\">Fallout 3</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirFallout3\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btFallout3\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbFalloutNV\">\n\t\t\t\t\t\t\t<label translate=\"0\">Fallout New Vegas</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirFalloutNV\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btFalloutNV\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkyrim\">\n\t\t\t\t\t\t\t<label translate=\"0\">Skyrim</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirSkyrim\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btSkyrim\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbFallout4\">\n\t\t\t\t\t\t\t<label translate=\"0\">Fallout 4</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirFallout4\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btFallout4\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkyrimSE\">\n\t\t\t\t\t\t\t<label translate=\"0\">Skyrim Special Edition</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirSkyrimSE\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btSkyrimSE\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbFallout4VR\">\n\t\t\t\t\t\t\t<label translate=\"0\">Fallout 4 VR</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirFallout4VR\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btFallout4VR\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkyrimVR\">\n\t\t\t\t\t\t\t<label translate=\"0\">Skyrim VR</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirSkyrimVR\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btSkyrimVR\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbStarfield\">\n\t\t\t\t\t\t\t<label translate=\"0\">Starfield</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxDirPickerCtrl\" name=\"dirStarfield\">\n\t\t\t\t\t\t\t<value>Game not found! Select the data folder manually...</value>\n\t\t\t\t\t\t\t<message>Select a folder</message>\n\t\t\t\t\t\t\t<style>wxDIRP_DEFAULT_STYLE|wxDIRP_SMALL</style>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btStarfield\">\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t<label>Choose Game</label>\n\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/ShapeProperties.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgShapeProp\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<title>Shape Properties</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<minsize>620,480</minsize>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxNotebook\" name=\"nbProperties\">\n\t\t\t\t\t<object class=\"notebookpage\">\n\t\t\t\t\t\t<label>Shader</label>\n\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pgShader\">\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbShaderName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Name</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<size>10,0</size>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP|wxLEFT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"shaderName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxTOP|wxLEFT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnMaterialChooser\">\n\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">...</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<size>50,18</size>\n\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbShaderType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Type</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"shaderType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbShadingType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shading</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"shadingType\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>1</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Hard</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Smooth</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSpecularColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Specular Color</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"specularColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">#ffffff</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCLRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSpecularStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Specular Strength</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"specularStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">2.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>25</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSpecularPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Specular Power</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"specularPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">30.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>25</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND | wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticLine\" name=\"lineShader\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxLI_VERTICAL</style>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbEmissiveColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Emissive Color</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"emissiveColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">#ffffff</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCLRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbEmissiveMultiple\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Emissive Multiple</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"emissiveMultiple\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>25</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlpha\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Alpha</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"alpha\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>25</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbVertexColors\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Vertex Colors</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"vertexColors\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbDoubleSided\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Double Sided</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"doubleSided\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddShader\">\n\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Add</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnRemoveShader\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Remove</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnSetTextures\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Textures...</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"shaderFlagsPane\">\n\t\t\t\t\t\t\t\t\t\t<label>Shader Flags</label>\n\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shader Flags 1</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckListBox\" name=\"shaderFlags1List\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxLB_SINGLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,200</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Shader Flags 2</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckListBox\" name=\"shaderFlags2List\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxLB_SINGLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<size>-1,200</size>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"advancedShaderPane\">\n\t\t\t\t\t\t\t\t\t\t<label>Advanced</label>\n\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>4</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>5</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1,3</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbUVOffset\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>UV Offset</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"uvOffsetU\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"uvOffsetV\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbUVScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>UV Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"uvScaleU\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"uvScaleV\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbTextureClampMode\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Texture Clamp Mode</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"textureClampMode\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>3</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Clamp S Clamp T</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Clamp S Wrap T</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Wrap S Clamp T</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>Wrap S Wrap T</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbEnvironmentMapScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Env Map Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"environmentMapScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbRefractionStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Refraction Strength</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"refractionStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbRefractionFirePeriod\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Refr. Fire Period</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"refractionFirePeriod\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParallaxMaxPasses\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Parallax Max Passes</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxMaxPasses\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">4.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParallaxScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Parallax Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLightingEffect1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Lighting Effect 1</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"lightingEffect1\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.3000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbLightingEffect2\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Lighting Effect 2</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"lightingEffect2\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">2.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkinTintColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Skin Tint Color</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"skinTintColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">#ffffff</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCLRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbHairTintColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Hair Tint Color</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxColourPickerCtrl\" name=\"hairTintColor\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">#ffffff</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCLRP_DEFAULT_STYLE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParallaxInnerLayerThickness\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Inner Layer Thickness</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxInnerLayerThickness\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParallaxRefractionScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Parallax Refr. Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxRefractionScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParallaxInnerLayerTexScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Inner Layer Tex Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxInnerLayerTexScaleU\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxInnerLayerTexScaleV\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParallaxEnvmapStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Parallax Envmap Str.</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"parallaxEnvmapStrength\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSparkleParameters\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Sparkle Parameters</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sparkleParamsR\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sparkleParamsG\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>2</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sparkleParamsB\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"sparkleParamsA\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbEyeCubemapScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Eye Cubemap Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeCubemapScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbEyeLeftReflectionCenter\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Left Eye Refl. Center</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeLeftReflectX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeLeftReflectY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeLeftReflectZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbEyeRightReflectionCenter\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Right Eye Refl. Center</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeRightReflectX\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeRightReflectY\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>0</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"eyeRightReflectZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetMaterialPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wet Material</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetMaterialPath\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSubsurfaceRolloff\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Subsurface Rolloff</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"subsurfaceRolloff\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.3000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbRimlightPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Rimlight Power</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"rimlightPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">2.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbBacklightPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Backlight Power</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"backlightPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbGrayscaleToPaletteScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Grayscale To Palette</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"grayscaleToPaletteScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbFresnelPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Fresnel Power</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"fresnelPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">5.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetnessSpecScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wetness Spec Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetnessSpecScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.6000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetnessSpecPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wetness Spec Power</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetnessSpecPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.4000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetnessMinVar\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wetness Min Var</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetnessMinVar\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.2000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetnessEnvMapScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wetness Env Map Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetnessEnvMapScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetnessFresnelPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wetness Fresnel Power</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetnessFresnelPower\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.6000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbWetnessMetalness\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Wetness Metalness</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>3</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"wetnessMetalness\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.0000</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCollapsiblePane\" name=\"transparencyPane\">\n\t\t\t\t\t\t\t\t\t\t<label>Transparency</label>\n\t\t\t\t\t\t\t\t\t\t<collapsed>1</collapsed>\n\t\t\t\t\t\t\t\t\t\t<object class=\"panewindow\">\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaThreshold\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Threshold</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"alphaThreshold\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxTE_CENTRE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">128</value>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<maxlength>3</maxlength>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND | wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticLine\" name=\"lineTransparency\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<style>wxLI_VERTICAL</style>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<cols>6</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>5</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbVertexAlpha\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Vertex Alpha</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"vertexAlpha\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaTest\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Alpha Test</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"alphaTest\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaBlend\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Alpha Blend</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"alphaBlend\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t\t\t<cols>4</cols>\n\t\t\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<hgap>5</hgap>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablecols>1,3</growablecols>\n\t\t\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaSrcBlend\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Src Blend</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"alphaSrcBlend\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>6</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>ONE</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>ZERO</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>SRC_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_SRC_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>DST_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_DST_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>SRC_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_SRC_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>DST_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_DST_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>SRC_ALPHA_SAT</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaDestBlend\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Dest Blend</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"alphaDestBlend\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>7</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>ONE</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>ZERO</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>SRC_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_SRC_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>DST_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_DST_COLOR</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>SRC_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_SRC_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>DST_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>INV_DST_ALPHA</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>SRC_ALPHA_SAT</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaTestFunc\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Test Function</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxChoice\" name=\"alphaTestFunc\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<selection>4</selection>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>ALWAYS</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>LESS</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>EQUAL</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>LEQUAL</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>GREATER</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>NOTEQUAL</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>GEQUAL</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<item>NEVER</item>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t</content>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAlphaNoSorter\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>No Sorter</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"alphaNoSorter\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddTransparency\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Add</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnRemoveTransparency\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<label>Remove</label>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnCopyShaderFromShape\">\n\t\t\t\t\t\t\t\t\t\t<label>Copy from shape...</label>\n\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"notebookpage\">\n\t\t\t\t\t\t<label>Geometry</label>\n\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pgGeometry\">\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbFullPrecision\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Full Precision</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"fullPrecision\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCHK_3STATE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSubIndex\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Sub Index</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"subIndex\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCHK_3STATE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbSkinned\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Skinned</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"skinned\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCHK_3STATE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbDynamic\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Dynamic</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"dynamic\">\n\t\t\t\t\t\t\t\t\t\t\t\t<style>wxCHK_3STATE</style>\n\t\t\t\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticLine\" name=\"lineGeometry\">\n\t\t\t\t\t\t\t\t\t\t<style>wxLI_VERTICAL</style>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t<cols>2</cols>\n\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<size>0,5</size>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"notebookpage\">\n\t\t\t\t\t\t<label>Extra Data</label>\n\t\t\t\t\t\t<object class=\"wxScrolledWindow\" name=\"pgExtraData\">\n\t\t\t\t\t\t\t<scrollrate>5,5</scrollrate>\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t<cols>4</cols>\n\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t<growablecols>2,3</growablecols>\n\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnAddExtraData\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Add</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<default>0</default>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbExtraDataType\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Type</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbExtraDataName\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Name</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbExtraDataValue\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Value</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"notebookpage\">\n\t\t\t\t\t\t<label>Coordinates</label>\n\t\t\t\t\t\t<object class=\"wxPanel\" name=\"pgCoordinates\">\n\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t<border>10</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbCoordIntro\">\n\t\t\t\t\t\t\t\t\t\t<label>Transform from shape to global coordinates:</label>\n\t\t\t\t\t\t\t\t\t\t<wrap>500</wrap>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Scale</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textScale\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">1.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t\t\t\t\t\t<growablecols>1,2</growablecols>\n\t\t\t\t\t\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelblank\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelorigin\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Origin</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelrot\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label>Rotation</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelX\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textX\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textRX\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelY\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textY\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textRY\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textRZ\">\n\t\t\t\t\t\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t\t<border>10</border>\n\t\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbTransformGeo\">\n\t\t\t\t\t\t\t\t\t\t<label>Recalculate geometry's coordinates so it doesn't move</label>\n\t\t\t\t\t\t\t\t\t\t<tooltip>Transform geometry so its position in global coordinates does not change.</tooltip>\n\t\t\t\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"spacer\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<size>0,5</size>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/Skeleton.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgSkeletonBones\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>443,471</size>\n\t\t<title>Select a bone to add</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"m_staticText5\">\n\t\t\t\t\t<label>Bones in the current reference skeleton:</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxTreeCtrl\" name=\"boneTree\">\n\t\t\t\t\t<style>wxTR_EXTENDED|wxTR_HAS_BUTTONS|wxTR_LINES_AT_ROOT|wxTR_MULTIPLE</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\n\t<object class=\"wxDialog\" name=\"dlgCustomBone\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE</style>\n\t\t<title>Add Custom Bone</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbParentBone\">\n\t\t\t\t\t\t\t<label>Parent</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"cParentBone\">\n\t\t\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t\t\t<content />\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbBoneName\">\n\t\t\t\t\t\t\t<label>Name</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"boneName\">\n\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols>1</growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelblank\">\n\t\t\t\t\t\t\t<label></label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelorigin\">\n\t\t\t\t\t\t\t<label>Origin</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelrot\">\n\t\t\t\t\t\t\t<label>Rotation</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelX\">\n\t\t\t\t\t\t\t<label translate=\"0\">X</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textX\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textRX\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelY\">\n\t\t\t\t\t\t\t<label translate=\"0\">Y</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textY\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textRY\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"labelZ\">\n\t\t\t\t\t\t\t<label translate=\"0\">Z</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textZ\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"textRZ\">\n\t\t\t\t\t\t\t<value translate=\"0\">0.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND|wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbAddCount\">\n\t\t\t\t\t\t\t<label>Add Count #</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxSpinCtrl\" name=\"numAddCount\">\n\t\t\t\t\t\t\t<value>1</value>\n\t\t\t\t\t\t\t<min>1</min>\n\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/Slider.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgChoosePreset\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>325,175</size>\n\t\t<title>Select a slider preset</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"lbChoicePreset\">\n\t\t\t\t\t<label>Choose a preset:</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxChoice\" name=\"choicePreset\">\n\t\t\t\t\t<style>wxCB_SORT</style>\n\t\t\t\t\t<selection>0</selection>\n\t\t\t\t\t<content />\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"weightLo\">\n\t\t\t\t\t\t\t<label>Low weight</label>\n\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxRadioButton\" name=\"weightHi\">\n\t\t\t\t\t\t\t<label>High weight</label>\n\t\t\t\t\t\t\t<value translate=\"0\">1</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxTOP</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxDialog\" name=\"dlgSliderProp\">\n\t\t<style>wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>287,210</size>\n\t\t<title>Slider Properties</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<label>Slider Name</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"edSliderName\">\n\t\t\t\t\t\t\t<value></value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<label>Default Values</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbValLo\">\n\t\t\t\t\t\t\t<label>Low</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"edValLo\">\n\t\t\t\t\t\t\t<value translate=\"0\">0</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxALIGN_CENTER</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"lbValHi\">\n\t\t\t\t\t\t\t<label>High</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"edValHi\">\n\t\t\t\t\t\t\t<value translate=\"0\">100</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"cbValZapped\">\n\t\t\t\t\t\t\t<label>Zapped</label>\n\t\t\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxStaticBoxSizer\">\n\t\t\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t\t\t<label>Options</label>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkInvert\">\n\t\t\t\t\t\t\t\t\t<label>Invert</label>\n\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkHidden\">\n\t\t\t\t\t\t\t\t\t<label>Hidden</label>\n\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkZap\">\n\t\t\t\t\t\t\t\t\t<label>Zap</label>\n\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t\t\t<object class=\"wxCheckBox\" name=\"chkUV\">\n\t\t\t\t\t\t\t\t\t<label>UV</label>\n\t\t\t\t\t\t\t\t\t<checked>0</checked>\n\t\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t\t</object>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"zapToggleLabel\">\n\t\t\t\t\t\t\t<label>Toggle Zaps:</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<minsize>-1,72</minsize>\n\t\t\t\t\t\t<object class=\"wxCheckListBox\" name=\"zapToggleList\">\n\t\t\t\t\t\t\t<style>wxLB_HSCROLL|wxLB_NEEDED_SB</style>\n\t\t\t\t\t\t\t<enabled>0</enabled>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/SliderDataImport.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgSliderDataImport\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE</style>\n\t\t<size>650,500</size>\n\t\t<title>Slider Data Import Options...</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Select the shapes that slider data will be imported for:</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<minsize>300,80</minsize>\n\t\t\t\t<object class=\"wxCheckListBox\" name=\"sliderShapesImportList\">\n\t\t\t\t\t<style>wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_EXTENDED|wxLB_SORT</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\">\n\t\t\t\t\t\t\t<label>Select the sliders to be imported</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxEXPAND</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<size>0,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<minsize>300,200</minsize>\n\t\t\t\t<object class=\"wxCheckListBox\" name=\"sliderImportList\">\n\t\t\t\t\t<style>wxLB_HSCROLL|wxLB_NEEDED_SB|wxLB_EXTENDED|wxLB_SORT</style>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxCheckBox\" name=\"chkImportMergeSliders\">\n\t\t\t\t\t<label>Merge Sliders</label>\n\t\t\t\t\t<checked>1</checked>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStdDialogButtonSizer\">\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"button\">\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_HORIZONTAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n\t<object class=\"wxMenu\" name=\"sliderDataContext\">\n\t\t<object class=\"wxMenuItem\" name=\"sliderDataContextNone\">\n\t\t\t<label>Select None</label>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"sliderDataContextAll\">\n\t\t\t<label>Select All</label>\n\t\t</object>\n\t\t<object class=\"wxMenuItem\" name=\"sliderDataContextInvert\">\n\t\t\t<label>Invert Selection</label>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "res/xrc/WeightCopy.xrc",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>\n<resource xmlns=\"http://www.wxwidgets.org/wxxrc\" version=\"2.5.3.0\">\n\t<object class=\"wxDialog\" name=\"dlgCopyWeights\">\n\t\t<style>wxCAPTION|wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</style>\n\t\t<size>580,520</size>\n\t\t<title>Copy Bone Weights</title>\n\t\t<centered>1</centered>\n\t\t<object class=\"wxBoxSizer\">\n\t\t\t<orient>wxVERTICAL</orient>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"copyWeightsDescription\">\n\t\t\t\t\t<label>Each vertex of the reference will copy its weights to the nearest collection of vertices within the given radius. Bear in mind that some geometry will always require manual tweaking to become weighted and work well. Often, the default values are sufficient.</label>\n\t\t\t\t\t<wrap>550</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxFlexGridSizer\">\n\t\t\t\t\t<rows>0</rows>\n\t\t\t\t\t<cols>3</cols>\n\t\t\t\t\t<vgap>0</vgap>\n\t\t\t\t\t<hgap>0</hgap>\n\t\t\t\t\t<growablecols></growablecols>\n\t\t\t\t\t<growablerows></growablerows>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"proximityRadiusLabel\">\n\t\t\t\t\t\t\t<label>Search Radius</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxSlider\" name=\"proximityRadiusSlider\">\n\t\t\t\t\t\t\t<value translate=\"0\">5000</value>\n\t\t\t\t\t\t\t<min>0</min>\n\t\t\t\t\t\t\t<max>20000</max>\n\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"proximityRadiusText\">\n\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t<value translate=\"0\">5.00000</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"maxResultsLabel\">\n\t\t\t\t\t\t\t<label>Max Vertex Targets</label>\n\t\t\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxSlider\" name=\"maxResultsSlider\">\n\t\t\t\t\t\t\t<value translate=\"0\">4</value>\n\t\t\t\t\t\t\t<min>1</min>\n\t\t\t\t\t\t\t<max>100</max>\n\t\t\t\t\t\t\t<size>400,-1</size>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxTextCtrl\" name=\"maxResultsText\">\n\t\t\t\t\t\t\t<size>60,-1</size>\n\t\t\t\t\t\t\t<value translate=\"0\">4</value>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxCheckBox\" name=\"noTargetLimit\">\n\t\t\t\t\t<label>No Target Limit</label>\n\t\t\t\t\t<checked>0</checked>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"boneListLabel\">\n\t\t\t\t\t<label>Bones to copy (click to preview weights):</label>\n\t\t\t\t\t<wrap>-1</wrap>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>1</option>\n\t\t\t\t<flag>wxEXPAND|wxLEFT|wxRIGHT</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxCheckListBox\" name=\"boneList\">\n\t\t\t\t\t<size>-1,160</size>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnCheckAll\">\n\t\t\t\t\t\t\t<label>Check All</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnUncheckAll\">\n\t\t\t\t\t\t\t<label>Uncheck All</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT|wxRIGHT|wxTOP</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxStaticText\" name=\"poseLabel\">\n\t\t\t\t\t\t\t<label>Pose:</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL</flag>\n\t\t\t\t\t\t<object class=\"wxChoice\" name=\"poseChoice\">\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxALL|wxEXPAND</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxStaticText\" name=\"copyTransDescription\">\n\t\t\t\t\t<label>The skin coordinate system doesn't match the reference shape's. Do you want to copy the transforms?</label>\n\t\t\t\t\t<wrap>550</wrap>\n\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxCheckBox\" name=\"cbCopySkinTrans\">\n\t\t\t\t\t<label>Copy skin transform from reference</label>\n\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxLEFT</flag>\n\t\t\t\t<border>10</border>\n\t\t\t\t<object class=\"wxCheckBox\" name=\"cbTransformGeo\">\n\t\t\t\t\t<label>Recalculate geometry's coordinates so it doesn't move</label>\n\t\t\t\t\t<tooltip>Transform geometry so its position in global coordinates does not change.</tooltip>\n\t\t\t\t\t<checked>1</checked>\n\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t\t<object class=\"sizeritem\">\n\t\t\t\t<option>0</option>\n\t\t\t\t<flag>wxEXPAND|wxALL</flag>\n\t\t\t\t<border>5</border>\n\t\t\t\t<object class=\"wxBoxSizer\">\n\t\t\t\t\t<orient>wxHORIZONTAL</orient>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"btnPreview\">\n\t\t\t\t\t\t\t<label>&amp;Preview</label>\n\t\t\t\t\t\t\t<tooltip>Run the weight copy and preview the results. Click again to update the preview.</tooltip>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>1</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxGauge\" name=\"previewProgress\">\n\t\t\t\t\t\t\t<size>-1,16</size>\n\t\t\t\t\t\t\t<range>100</range>\n\t\t\t\t\t\t\t<value>0</value>\n\t\t\t\t\t\t\t<hidden>1</hidden>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"spacer\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<size>10,0</size>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_OK\">\n\t\t\t\t\t\t\t<label>&amp;OK</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t\t<object class=\"sizeritem\">\n\t\t\t\t\t\t<option>0</option>\n\t\t\t\t\t\t<flag>wxALIGN_CENTER_VERTICAL|wxALL</flag>\n\t\t\t\t\t\t<border>5</border>\n\t\t\t\t\t\t<object class=\"wxButton\" name=\"wxID_CANCEL\">\n\t\t\t\t\t\t\t<label>&amp;Cancel</label>\n\t\t\t\t\t\t</object>\n\t\t\t\t\t</object>\n\t\t\t\t</object>\n\t\t\t</object>\n\t\t</object>\n\t</object>\n</resource>\n"
  },
  {
    "path": "run-wxrc.bat",
    "content": "wxrc --gettext --output=lang/xrctext.cpp res/xrc/*.xrc"
  },
  {
    "path": "src/components/Anim.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"Anim.h\"\n#include \"NifUtil.hpp\"\n#include <unordered_set>\n#include <wx/log.h>\n#include <wx/msgdlg.h>\n\nextern ConfigurationManager Config;\n\nusing namespace nifly;\n\nbool AnimInfo::AddShapeBone(const std::string& shape, const std::string& boneName) {\n\tfor (auto& bone : shapeBones[shape])\n\t\tif (!bone.compare(boneName))\n\t\t\treturn false;\n\n\tshapeSkinning[shape].boneNames[boneName] = shapeBones[shape].size();\n\tshapeBones[shape].push_back(boneName);\n\tAnimSkeleton::getInstance().RefBone(boneName);\n\tRecalcXFormSkinToBone(shape, boneName);\n\treturn true;\n}\n\nbool AnimInfo::RemoveShapeBone(const std::string& shape, const std::string& boneName) {\n\tauto& bones = shapeBones[shape];\n\tif (std::find(bones.begin(), bones.end(), boneName) == bones.end())\n\t\treturn false;\n\n\tbones.erase(std::remove(bones.begin(), bones.end(), boneName), bones.end());\n\tshapeSkinning[shape].RemoveBone(boneName);\n\n\tAnimSkeleton::getInstance().ReleaseBone(boneName);\n\n\tif (refNif && refNif->IsValid()) {\n\t\tif (AnimSkeleton::getInstance().GetBoneRefCount(boneName) <= 0) {\n\t\t\tif (refNif->CanDeleteNode(boneName))\n\t\t\t\trefNif->DeleteNode(boneName);\n\t\t}\n\t}\n\n\treturn true;\n}\n\nvoid AnimInfo::Clear() {\n\tif (refNif && refNif->IsValid()) {\n\t\tfor (auto& shapeBoneList : shapeBones) {\n\t\t\tfor (auto& boneName : shapeBoneList.second) {\n\t\t\t\tAnimSkeleton::getInstance().ReleaseBone(boneName);\n\n\t\t\t\tif (AnimSkeleton::getInstance().GetBoneRefCount(boneName) <= 0) {\n\t\t\t\t\tif (refNif->CanDeleteNode(boneName))\n\t\t\t\t\t\trefNif->DeleteNode(boneName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tshapeSkinning.clear();\n\t\tfor (auto& s : refNif->GetShapeNames())\n\t\t\tshapeBones[s].clear();\n\n\t\trefNif = nullptr;\n\t}\n\telse {\n\t\tfor (auto& shapeBoneList : shapeBones)\n\t\t\tfor (auto& boneName : shapeBoneList.second)\n\t\t\t\tAnimSkeleton::getInstance().ReleaseBone(boneName);\n\n\t\tshapeSkinning.clear();\n\t\tshapeBones.clear();\n\t}\n}\n\nvoid AnimInfo::ClearShape(const std::string& shape) {\n\tif (shape.empty())\n\t\treturn;\n\n\tfor (auto& boneName : shapeBones[shape]) {\n\t\tAnimSkeleton::getInstance().ReleaseBone(boneName);\n\n\t\tif (refNif && refNif->IsValid()) {\n\t\t\tif (AnimSkeleton::getInstance().GetBoneRefCount(boneName) <= 0) {\n\t\t\t\tif (refNif->CanDeleteNode(boneName))\n\t\t\t\t\trefNif->DeleteNode(boneName);\n\t\t\t}\n\t\t}\n\t}\n\n\tshapeBones.erase(shape);\n\tshapeSkinning.erase(shape);\n}\n\nvoid AnimInfo::DeleteVertsForShape(const std::string& shape, const std::vector<uint16_t>& indices) {\n\tif (indices.empty())\n\t\treturn;\n\n\tint highestRemoved = indices.back();\n\tstd::vector<int> indexCollapse = GenerateIndexCollapseMap(indices, highestRemoved + 1);\n\n\tauto& skin = shapeSkinning[shape];\n\tfor (auto& w : skin.boneWeights) {\n\t\tApplyIndexMapToMapKeys(w.second.weights, indexCollapse, -static_cast<int>(indices.size()));\n\t}\n}\n\nvoid AnimSkin::InsertVertexIndices(const std::vector<uint16_t>& indices) {\n\tif (indices.empty())\n\t\treturn;\n\n\tint highestAdded = indices.back();\n\tstd::vector<int> indexExpand = GenerateIndexExpandMap(indices, highestAdded + 1);\n\n\tfor (auto& w : boneWeights) {\n\t\tApplyIndexMapToMapKeys(w.second.weights, indexExpand, static_cast<int>(indices.size()));\n\t}\n}\n\nvoid AnimWeight::LoadFromNif(NifFile* loadFromFile, NiShape* shape, const int& index) {\n\tloadFromFile->GetShapeBoneWeights(shape, index, weights);\n\tloadFromFile->GetShapeTransformSkinToBone(shape, index, xformSkinToBone);\n\tloadFromFile->GetShapeBoneBounds(shape, index, bounds);\n}\n\nvoid AnimSkin::LoadFromNif(NifFile* loadFromFile, NiShape* shape) {\n\tbool gotGTS = loadFromFile->GetShapeTransformGlobalToSkin(shape, xformGlobalToSkin);\n\tstd::vector<int> idList;\n\tloadFromFile->GetShapeBoneIDList(shape, idList);\n\n\tint newID = 0;\n\tstd::vector<MatTransform> eachXformGlobalToSkin;\n\tfor (auto& id : idList) {\n\t\tauto node = loadFromFile->GetHeader().GetBlock<NiNode>(id);\n\t\tif (!node)\n\t\t\tcontinue;\n\t\tboneWeights[newID].LoadFromNif(loadFromFile, shape, newID);\n\t\tboneNames[node->name.get()] = newID;\n\t\tif (!gotGTS) {\n\t\t\t// We don't have a global-to-skin transform, probably because\n\t\t\t// the NIF has BSSkinBoneData instead of NiSkinData (FO4 or\n\t\t\t// newer).  So calculate by:\n\t\t\t// Compose: skin -> bone -> global\n\t\t\t// and inverting.\n\t\t\tMatTransform xformBoneToGlobal;\n\t\t\tif (AnimSkeleton::getInstance().GetBoneTransformToGlobal(node->name.get(), xformBoneToGlobal)) {\n\t\t\t\teachXformGlobalToSkin.push_back(xformBoneToGlobal.ComposeTransforms(boneWeights[newID].xformSkinToBone).InverseTransform());\n\t\t\t}\n\t\t}\n\t\tnewID++;\n\t}\n\tif (!eachXformGlobalToSkin.empty())\n\t\txformGlobalToSkin = CalcMedianMatTransform(eachXformGlobalToSkin);\n}\n\nbool AnimInfo::LoadFromNif(NifFile* nif) {\n\tClear();\n\n\tfor (auto& s : nif->GetShapes())\n\t\tLoadFromNif(nif, s);\n\n\trefNif = nif;\n\treturn true;\n}\n\nbool AnimInfo::LoadFromNif(NifFile* nif, NiShape* shape, bool newRefNif) {\n\tstd::vector<std::string> boneNames;\n\tstd::string nonRefBones;\n\n\tif (newRefNif)\n\t\trefNif = nif;\n\n\tif (!shape)\n\t\treturn false;\n\n\tstd::string shapeName = shape->name.get();\n\tif (!nif->GetShapeBoneList(shape, boneNames)) {\n\t\twxLogWarning(\"No skinning found in shape '%s'.\", shapeName);\n\t\treturn false;\n\t}\n\n\tfor (auto& bn : boneNames) {\n\t\tif (!AnimSkeleton::getInstance().RefBone(bn)) {\n\t\t\tAnimBone* cstm = AnimSkeleton::getInstance().LoadCustomBoneFromNif(nif, bn);\n\t\t\tif (!cstm->isStandardBone)\n\t\t\t\tnonRefBones += bn + \"\\n\";\n\t\t\tAnimSkeleton::getInstance().RefBone(bn);\n\t\t}\n\n\t\tshapeBones[shapeName].push_back(bn);\n\t}\n\n\tshapeSkinning[shapeName].LoadFromNif(nif, shape);\n\n\tif (!nonRefBones.empty())\n\t\twxLogMessage(\"Bones in shape '%s' not found in reference skeleton and added as custom bones:\\n%s\", shapeName, nonRefBones);\n\n\treturn true;\n}\n\nbool AnimInfo::CloneShape(NifFile* nif, NiShape* shape, const std::string& newShape) {\n\tif (!shape || newShape.empty())\n\t\treturn false;\n\n\tstd::string shapeName = shape->name.get();\n\n\tstd::vector<std::string> boneNames;\n\tif (!nif->GetShapeBoneList(shape, boneNames)) {\n\t\twxLogWarning(\"No skinning found in shape '%s'.\", shapeName);\n\t\treturn false;\n\t}\n\n\tfor (auto& bn : boneNames) {\n\t\tAnimSkeleton::getInstance().RefBone(bn);\n\t\tshapeBones[newShape].push_back(bn);\n\t}\n\n\tshapeSkinning[newShape] = shapeSkinning[shapeName];\n\treturn true;\n}\n\nint AnimInfo::GetShapeBoneIndex(const std::string& shapeName, const std::string& boneName) const {\n\tconst auto& skin = shapeSkinning.find(shapeName);\n\tif (skin != shapeSkinning.end()) {\n\t\tconst auto& bone = skin->second.boneNames.find(boneName);\n\t\tif (bone != skin->second.boneNames.end())\n\t\t\treturn bone->second;\n\t}\n\n\treturn -1;\n}\n\nstd::unordered_map<uint16_t, float>* AnimInfo::GetWeightsPtr(const std::string& shape, const std::string& boneName) {\n\tint b = GetShapeBoneIndex(shape, boneName);\n\tif (b < 0)\n\t\treturn nullptr;\n\n\treturn &shapeSkinning[shape].boneWeights[b].weights;\n}\n\nbool AnimInfo::HasWeights(const std::string& shape, const std::string& boneName) {\n\tauto weights = GetWeightsPtr(shape, boneName);\n\tif (weights && weights->size() > 0)\n\t\treturn true;\n\n\treturn false;\n}\n\nvoid AnimInfo::GetWeights(const std::string& shape, const std::string& boneName, std::unordered_map<uint16_t, float>& outVertWeights) {\n\tauto weights = GetWeightsPtr(shape, boneName);\n\tif (weights)\n\t\toutVertWeights = *weights;\n}\n\nbool AnimInfo::GetXFormSkinToBone(const std::string& shape, const std::string& boneName, MatTransform& stransform) {\n\tint b = GetShapeBoneIndex(shape, boneName);\n\tif (b < 0)\n\t\treturn false;\n\n\tstransform = shapeSkinning[shape].boneWeights[b].xformSkinToBone;\n\treturn true;\n}\n\nvoid AnimInfo::SetXFormSkinToBone(const std::string& shape, const std::string& boneName, const MatTransform& stransform) {\n\tint b = GetShapeBoneIndex(shape, boneName);\n\tif (b < 0)\n\t\treturn;\n\n\tshapeSkinning[shape].boneWeights[b].xformSkinToBone = stransform;\n}\n\nvoid AnimInfo::RecalcXFormSkinToBone(const std::string& shape, const std::string& boneName) {\n\t// Calculate a good default value for xformSkinToBone by:\n\t// Composing: bone -> global -> skin\n\t// then inverting\n\tMatTransform xformGlobalToSkin = shapeSkinning[shape].xformGlobalToSkin;\n\tMatTransform xformBoneToGlobal;\n\tAnimSkeleton::getInstance().GetBoneTransformToGlobal(boneName, xformBoneToGlobal);\n\tMatTransform xformBoneToSkin = xformGlobalToSkin.ComposeTransforms(xformBoneToGlobal);\n\tSetXFormSkinToBone(shape, boneName, xformBoneToSkin.InverseTransform());\n}\n\nvoid AnimInfo::RecursiveRecalcXFormSkinToBone(const std::string& shape, AnimBone* bPtr) {\n\tRecalcXFormSkinToBone(shape, bPtr->boneName);\n\tfor (AnimBone* cptr : bPtr->children)\n\t\tRecursiveRecalcXFormSkinToBone(shape, cptr);\n}\n\nvoid AnimInfo::ChangeGlobalToSkinTransform(const std::string& shape, const MatTransform& newTrans) {\n\tshapeSkinning[shape].xformGlobalToSkin = newTrans;\n\tfor (const std::string& bone : shapeBones[shape])\n\t\tRecalcXFormSkinToBone(shape, bone);\n}\n\nbool AnimInfo::BoneHasInconsistentTransforms(const std::string& shape, const std::string& bone) const {\n\tauto asit = shapeSkinning.find(shape);\n\tif (asit == shapeSkinning.end())\n\t\treturn false;\n\tconst AnimSkin& skin = asit->second;\n\n\tauto bnit = skin.boneNames.find(bone);\n\tif (bnit == skin.boneNames.end())\n\t\treturn false;\n\tconst AnimWeight& aw = skin.boneWeights.at(bnit->second);\n\n\tconst AnimBone* animB = AnimSkeleton::getInstance().GetBonePtr(bone);\n\tif (!animB)\n\t\treturn false;\n\n\t// We calculate the loop residual transform by composing:\n\t// global <- bone <- skin <- global\n\t// If the three transforms are consistent, then this residual\n\t// will be the identity transform.\n\tMatTransform residual = animB->xformToGlobal.ComposeTransforms(aw.xformSkinToBone.ComposeTransforms(skin.xformGlobalToSkin));\n\treturn !residual.IsNearlyEqualTo(MatTransform());\n}\n\nvoid AnimInfo::FindBonesWithInconsistentTransforms(const std::string& shape, std::unordered_map<std::string, MatTransform>& badStandard, std::unordered_map<std::string, MatTransform>& badCustom) {\n\tAnimSkin& skin = shapeSkinning[shape];\n\tfor (auto& boneName : skin.boneNames) {\n\t\tAnimBone* animB = AnimSkeleton::getInstance().GetBonePtr(boneName.first);\n\t\tif (!animB)\n\t\t\tcontinue;\n\t\tAnimWeight& aw = skin.boneWeights[boneName.second];\n\n\t\t// We calculate the loop residual transform by composing:\n\t\t// global <- bone <- skin <- global\n\t\t// If the three transforms are consistent, then this residual\n\t\t// will be the identity transform.\n\t\tMatTransform residual = animB->xformToGlobal.ComposeTransforms(aw.xformSkinToBone.ComposeTransforms(skin.xformGlobalToSkin));\n\t\tif (residual.IsNearlyEqualTo(MatTransform()))\n\t\t\tcontinue;\n\n\t\tif (animB->isStandardBone)\n\t\t\tbadStandard[boneName.first] = residual;\n\t\telse\n\t\t\tbadCustom[boneName.first] = residual;\n\t}\n}\n\nvoid AnimInfo::RecalcCustomBoneXFormsFromSkin(const std::string& shape, const std::string& boneName) {\n\tAnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\tif (!bptr)\n\t\treturn;\t// Shouldn't be possible\n\t// Calculate boneToGlobal by composing:\n\t// global -> skin -> bone\n\t// and inverting.\n\tMatTransform globalToSkin = shapeSkinning[shape].xformGlobalToSkin;\n\tMatTransform skinToBone;\n\tGetXFormSkinToBone(shape, boneName, skinToBone);\n\tMatTransform globalToBone = skinToBone.ComposeTransforms(globalToSkin);\n\tMatTransform boneToGlobal = globalToBone.InverseTransform();\n\t// Calculate globalToParent by inverting parentToGlobal:\n\tMatTransform parentToGlobal;\n\tif (bptr->parent)\n\t\tparentToGlobal = bptr->parent->xformToGlobal;\n\tMatTransform globalToParent = parentToGlobal.InverseTransform();\n\t// Calculate boneToParent by composing:\n\t// bone -> global -> parent\n\tMatTransform boneToParent = globalToParent.ComposeTransforms(boneToGlobal);\n\t// Update the bone\n\tbptr->SetTransformBoneToParent(boneToParent);\n}\n\nbool AnimInfo::CalcShapeSkinBounds(const std::string& shapeName, const int& boneIndex) {\n\tif (!refNif || !refNif->IsValid()) // Check for existence of reference nif\n\t\treturn false;\n\n\tif (shapeSkinning.find(shapeName) == shapeSkinning.end()) // Check for shape in skinning data\n\t\treturn false;\n\n\tauto shape = refNif->FindBlockByName<NiShape>(shapeName);\n\n\tstd::vector<Vector3> verts;\n\trefNif->GetVertsForShape(shape, verts);\n\tif (verts.size() == 0) // Check for empty shape\n\t\treturn false;\n\n\tstd::vector<Vector3> boundVerts;\n\tfor (auto& w : shapeSkinning[shapeName].boneWeights[boneIndex].weights) {\n\t\tif (w.first >= verts.size()) // Incoming weights have a larger set of possible verts.\n\t\t\treturn false;\n\n\t\tboundVerts.push_back(verts[w.first]);\n\t}\n\n\tBoundingSphere bounds(boundVerts);\n\n\tconst MatTransform& xformSkinToBone = shapeSkinning[shapeName].boneWeights[boneIndex].xformSkinToBone;\n\n\tbounds.center = xformSkinToBone.ApplyTransform(bounds.center);\n\tbounds.radius = xformSkinToBone.ApplyTransformToDist(bounds.radius);\n\tshapeSkinning[shapeName].boneWeights[boneIndex].bounds = bounds;\n\treturn true;\n}\n\nvoid AnimInfo::SetWeights(const std::string& shape, const std::string& boneName, std::unordered_map<uint16_t, float>& inVertWeights) {\n\tint bid = GetShapeBoneIndex(shape, boneName);\n\tif (bid == -1)\n\t\treturn;\n\n\tshapeSkinning[shape].boneWeights[bid].weights = inVertWeights;\n}\n\nvoid AnimInfo::CleanupBones() {\n\tfor (auto& skin : shapeSkinning) {\n\t\tstd::vector<std::string> bonesToDelete;\n\n\t\tfor (auto& bone : skin.second.boneNames) {\n\t\t\tbool hasInfluence = false;\n\t\t\tfor (auto& bw : skin.second.boneWeights[bone.second].weights) {\n\t\t\t\tif (bw.second > 0.0f) {\n\t\t\t\t\thasInfluence = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!hasInfluence)\n\t\t\t\tbonesToDelete.push_back(bone.first);\n\t\t}\n\n\t\tfor (auto& bone : bonesToDelete)\n\t\t\tRemoveShapeBone(skin.first, bone);\n\t}\n}\n\nvoid AnimInfo::WriteNodesToNif(NifFile* nif, const std::string& shapeException) {\n\t// Collect list of needed bones.  Also delete bones used by shapeException\n\t// and no other shape if they have no children and have root parent.\n\tstd::unordered_set<const AnimBone*> neededBones;\n\tfor (auto& bones : shapeBones) {\n\t\tfor (auto& bone : bones.second) {\n\t\t\tconst AnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(bone);\n\t\t\tif (!bptr)\n\t\t\t\tcontinue;\n\n\t\t\tif (bones.first == shapeException) {\n\t\t\t\tif (bptr->refCount <= 1) {\n\t\t\t\t\tif (nif->CanDeleteNode(bone))\n\t\t\t\t\t\tnif->DeleteNode(bone);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tneededBones.insert(bptr);\n\t\t}\n\t}\n\n\t// Make sure each needed bone has a node by creating it if necessary.\n\t// Also, for each custom bone, set parent and transform to parent.\n\t// Also, generate map of bone names to node IDs.\n\tstd::unordered_map<std::string, int> boneIDMap;\n\tfor (const AnimBone* bptr : neededBones) {\n\t\tNiNode* node = nif->FindBlockByName<NiNode>(bptr->boneName);\n\t\tif (!node) {\n\t\t\tif (bptr->isStandardBone)\n\t\t\t\t// If new standard bone, add to root and use xformToGlobal\n\t\t\t\tnode = nif->AddNode(bptr->boneName, bptr->xformToGlobal);\n\t\t\telse\n\t\t\t\t// If new custom bone, add to parent, recursively\n\t\t\t\tnode = bptr->AddToNif(nif);\n\t\t}\n\t\telse if (!bptr->isStandardBone) {\n\t\t\t// If old (exists in nif) custom bone...\n\t\t\tif (!bptr->parent) {\n\t\t\t\t// If old custom bone with no parent, set parent node to root.\n\t\t\t\tnif->SetParentNode(node, nullptr);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// If old custom bone with parent, find parent bone's node\n\t\t\t\tNiNode* pNode = nif->FindBlockByName<NiNode>(bptr->parent->boneName);\n\t\t\t\tif (!pNode)\n\t\t\t\t\t// No parent: add parent recursively.\n\t\t\t\t\tpNode = bptr->parent->AddToNif(nif);\n\t\t\t\tnif->SetParentNode(node, pNode);\n\t\t\t}\n\t\t\tnode->SetTransformToParent(bptr->xformToParent);\n\t\t}\n\t\tboneIDMap[bptr->boneName] = nif->GetBlockID(node);\n\t}\n\n\t// Set the node-to-parent transform for every standard-bone node,\n\t// even ones we don't use.\n\tfor (NiNode* node : nif->GetNodes()) {\n\t\tconst AnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(node->name.get());\n\t\tif (!bptr)\n\t\t\tcontinue; // Don't touch bones we don't know about\n\t\tif (!bptr->isStandardBone)\n\t\t\tcontinue; // Custom bones have already been set\n\t\tNiNode* pNode = nif->GetParentNode(node);\n\t\tif (!pNode || pNode == nif->GetRootNode())\n\t\t\t// Parent node is root: use xformToGlobal\n\t\t\tnode->SetTransformToParent(bptr->xformToGlobal);\n\t\telse if (bptr->parent && pNode->name.get() == bptr->parent->boneName)\n\t\t\t// Parent node is bone's parent's node: use xformToParent\n\t\t\tnode->SetTransformToParent(bptr->xformToParent);\n\t\telse {\n\t\t\t// The parent node does not match our skeletal structure, so we\n\t\t\t// must calculate the transform.\n\t\t\tconst AnimBone* nparent = AnimSkeleton::getInstance().GetBonePtr(pNode->name.get());\n\t\t\tif (nparent) {\n\t\t\t\tMatTransform p2g = nparent->xformToGlobal;\n\t\t\t\t// Now compose: bone cs -> global cs -> parent node's bone cs\n\t\t\t\tMatTransform b2p = p2g.InverseTransform().ComposeTransforms(bptr->xformToGlobal);\n\t\t\t\tnode->SetTransformToParent(b2p);\n\t\t\t}\n\t\t\t// if nparent is nullptr, give up: the node has an unknown\n\t\t\t// parent, so we can't sensibly set its node-to-parent transform.\n\t\t}\n\t}\n}\n\nvoid AnimInfo::WriteToNif(NifFile* nif, const std::string& shapeException) {\n\t// Add/remove nodes and set transforms\n\tWriteNodesToNif(nif, shapeException);\n\n\t// Generate map of bone names to node IDs in a single pass.\n\tstd::unordered_map<std::string, int> boneIDMap;\n\tfor (auto& bones : shapeBones) {\n\t\tif (bones.first == shapeException)\n\t\t\tcontinue;\n\n\t\tfor (auto& bone : bones.second) {\n\t\t\tif (boneIDMap.find(bone) != boneIDMap.end())\n\t\t\t\tcontinue;\n\n\t\t\tconst AnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(bone);\n\t\t\tif (!bptr)\n\t\t\t\tcontinue;\n\n\t\t\tNiNode* node = nif->FindBlockByName<NiNode>(bptr->boneName);\n\t\t\tif (node)\n\t\t\t\tboneIDMap[bptr->boneName] = nif->GetBlockID(node);\n\t\t}\n\t}\n\n\t// Generate bone node ID list for each shape and set it.\n\tfor (auto& bones : shapeBones) {\n\t\tif (bones.first == shapeException)\n\t\t\tcontinue;\n\t\tstd::vector<int> bids;\n\t\tfor (auto& bone : bones.second) {\n\t\t\tauto it = boneIDMap.find(bone);\n\t\t\tif (it != boneIDMap.end())\n\t\t\t\tbids.push_back(it->second);\n\t\t}\n\t\tauto shape = nif->FindBlockByName<NiShape>(bones.first);\n\t\tnif->SetShapeBoneIDList(shape, bids);\n\t}\n\n\tbool incomplete = false;\n\tbool isFO = nif->GetHeader().GetVersion().IsFO4() || nif->GetHeader().GetVersion().IsFO76();\n\n\tfor (auto& shapeBoneList : shapeBones) {\n\t\tif (shapeBoneList.first == shapeException)\n\t\t\tcontinue;\n\n\t\tauto shape = nif->FindBlockByName<NiShape>(shapeBoneList.first);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\tbool isBSShape = shape->HasType<BSTriShape>();\n\n\t\tstd::unordered_map<uint16_t, VertexBoneWeights> vertWeights;\n\t\tfor (auto& boneName : shapeBoneList.second) {\n\t\t\tAnimBone* bptr = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\n\t\t\tint bid = GetShapeBoneIndex(shapeBoneList.first, boneName);\n\t\t\tAnimWeight& bw = shapeSkinning[shapeBoneList.first].boneWeights[bid];\n\n\t\t\tif (isBSShape)\n\t\t\t\tfor (auto vw : bw.weights)\n\t\t\t\t\tvertWeights[vw.first].Add(bid, vw.second);\n\n\t\t\tnif->SetShapeTransformSkinToBone(shape, bid, bw.xformSkinToBone);\n\t\t\tif (!bptr)\n\t\t\t\tincomplete = true;\n\t\t\tif (!isFO)\n\t\t\t\tnif->SetShapeBoneWeights(shapeBoneList.first, bid, bw.weights);\n\n\t\t\tif (CalcShapeSkinBounds(shapeBoneList.first, bid))\n\t\t\t\tnif->SetShapeBoneBounds(shapeBoneList.first, bid, bw.bounds);\n\t\t}\n\n\t\tif (isBSShape) {\n\t\t\tnif->ClearShapeVertWeights(shapeBoneList.first);\n\n\t\t\tfor (auto& vid : vertWeights)\n\t\t\t\tnif->SetShapeVertWeights(shapeBoneList.first, vid.first, vid.second.boneIds, vid.second.weights);\n\t\t}\n\t}\n\n\tif (incomplete)\n\t\twxMessageBox(_(\"Bone information incomplete. Exported data will not contain correct bone entries! Be sure to load a reference NIF prior to export.\"),\n\t\t\t\t\t _(\"Export Warning\"),\n\t\t\t\t\t wxICON_WARNING);\n}\n\nvoid AnimInfo::RenameShape(const std::string& shapeName, const std::string& newShapeName) {\n\tif (shapeSkinning.find(shapeName) != shapeSkinning.end()) {\n\t\tshapeSkinning[newShapeName] = std::move(shapeSkinning[shapeName]);\n\t\tshapeSkinning.erase(shapeName);\n\t}\n\n\tif (shapeBones.find(shapeName) != shapeBones.end()) {\n\t\tshapeBones[newShapeName] = move(shapeBones[shapeName]);\n\t\tshapeBones.erase(shapeName);\n\t}\n}\n\nvoid AnimInfo::MatchSymmetricBoneNames(std::vector<std::string> boneNames, std::vector<std::pair<std::string, std::string>>& pairs, std::vector<std::string>& singles) {\n\tstd::vector<bool> done(boneNames.size(), false);\n\tfor (size_t bi1 = 0; bi1 < boneNames.size(); ++bi1) {\n\t\tif (done[bi1])\n\t\t\tcontinue;\n\t\tdone[bi1] = true;\n\n\t\tconst size_t b1len = boneNames[bi1].length();\n\t\tint bestFlips = 0;\n\t\tsize_t bestbi2 = 0;\n\t\tfor (size_t bi2 = 0; bi2 < boneNames.size(); ++bi2) {\n\t\t\tif (done[bi2])\n\t\t\t\tcontinue;\n\t\t\tif (b1len != boneNames[bi2].length())\n\t\t\t\tcontinue;\n\n\t\t\tint flips = 0;\n\t\t\tbool nomatch = false;\n\t\t\tfor (size_t i = 0; i < b1len && !nomatch; ++i) {\n\t\t\t\tchar b1c = std::tolower(boneNames[bi1][i]);\n\t\t\t\tchar b2c = std::tolower(boneNames[bi2][i]);\n\t\t\t\tif (b1c == 'l' && b2c == 'r')\n\t\t\t\t\t++flips;\n\t\t\t\telse if (b1c == 'r' && b2c == 'l')\n\t\t\t\t\t++flips;\n\t\t\t\telse if (b1c != b2c)\n\t\t\t\t\tnomatch = true;\n\t\t\t}\n\n\t\t\tif (nomatch)\n\t\t\t\tcontinue;\n\t\t\tif (flips <= bestFlips)\n\t\t\t\tcontinue;\n\n\t\t\tbestFlips = flips;\n\t\t\tbestbi2 = bi2;\n\t\t}\n\t\tif (bestFlips > 0) {\n\t\t\tpairs.emplace_back(boneNames[bi1], boneNames[bestbi2]);\n\t\t\tdone[bestbi2] = true;\n\t\t}\n\t\telse\n\t\t\tsingles.push_back(boneNames[bi1]);\n\t}\n}\n\nvoid AnimInfo::SwapBonesLR(const std::string& shapeName) {\n\tauto shapeBonesIt = shapeBones.find(shapeName);\n\tauto shapeSkinningIt = shapeSkinning.find(shapeName);\n\tif (shapeBonesIt != shapeBones.end() && shapeSkinningIt != shapeSkinning.end()) {\n\t\tstd::vector<std::string> boneNames;\n\t\tAnimSkeleton::getInstance().GetBoneNames(boneNames);\n\n\t\tstd::vector<std::pair<std::string, std::string>> pairs;\n\t\tstd::vector<std::string> singles;\n\t\tMatchSymmetricBoneNames(boneNames, pairs, singles);\n\n\t\tfor (auto& pair : pairs) {\n\t\t\t// Get index of each bone by name\n\t\t\tbool otherSideMissing = false;\n\t\t\tstd::string boneName = pair.first;\n\t\t\tstd::string boneNameOther = pair.second;\n\n\t\t\tauto boneIt = shapeSkinningIt->second.boneNames.find(boneName);\n\t\t\tauto boneOtherIt = shapeSkinningIt->second.boneNames.find(boneNameOther);\n\n\t\t\tif (boneIt != shapeSkinningIt->second.boneNames.end() && boneOtherIt != shapeSkinningIt->second.boneNames.end()) {\n\t\t\t\t// Both bones exist on shape, get weights of each bone by index\n\t\t\t\tauto boneWeightsA = shapeSkinningIt->second.boneWeights.find(boneIt->second);\n\t\t\t\tauto boneWeightsB = shapeSkinningIt->second.boneWeights.find(boneOtherIt->second);\n\t\t\t\tif (boneWeightsA != shapeSkinningIt->second.boneWeights.end() && boneWeightsB != shapeSkinningIt->second.boneWeights.end()) {\n\t\t\t\t\t// Swap weights between bone A and B\n\t\t\t\t\tstd::swap(boneWeightsA->second.weights, boneWeightsB->second.weights);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (boneIt != shapeSkinningIt->second.boneNames.end()) {\n\t\t\t\t// Only bone A exists on shape\n\t\t\t\totherSideMissing = true;\n\t\t\t}\n\t\t\telse if (boneOtherIt != shapeSkinningIt->second.boneNames.end()) {\n\t\t\t\t// Only bone B exists on shape\n\t\t\t\totherSideMissing = true;\n\t\t\t\tstd::swap(boneIt, boneOtherIt);\n\t\t\t\tstd::swap(boneName, boneNameOther);\n\t\t\t}\n\n\t\t\tif (otherSideMissing) {\n\t\t\t\tauto boneWeights = shapeSkinningIt->second.boneWeights.find(boneIt->second);\n\t\t\t\tif (boneWeights != shapeSkinningIt->second.boneWeights.end()) {\n\t\t\t\t\t// Add bone of other side\n\t\t\t\t\tAddShapeBone(shapeName, boneNameOther);\n\t\t\t\t\tauto boneOther = shapeSkinningIt->second.boneNames.find(boneNameOther);\n\n\t\t\t\t\tauto boneWeightsOther = shapeSkinningIt->second.boneWeights.find(boneOther->second);\n\t\t\t\t\tif (boneWeightsOther != shapeSkinningIt->second.boneWeights.end()) {\n\t\t\t\t\t\t// Move weights to bone\n\t\t\t\t\t\tboneWeightsOther->second.weights = std::move(boneWeights->second.weights);\n\t\t\t\t\t\tRemoveShapeBone(shapeName, boneName);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nMatTransform AnimInfo::GetTransformShapeToGlobal(NiShape* shape) const {\n    if (shape->IsSkinned())\n        return GetTransformGlobalToShape(shape).InverseTransform();\n    else {\n        MatTransform ttg = shape->GetTransformToParent();\n        NiNode* parent = refNif->GetParentNode(shape);\n        while (parent) {\n            ttg = parent->GetTransformToParent().ComposeTransforms(ttg);\n            parent = refNif->GetParentNode(parent);\n        }\n        return ttg;\n    }\n}\n\nMatTransform AnimInfo::GetTransformGlobalToShape(NiShape* shape) const {\n\tif (shape->IsSkinned())\n\t\tif (shapeSkinning.find(shape->name.get()) != shapeSkinning.end())\n\t\t\treturn shapeSkinning.at(shape->name.get()).xformGlobalToSkin;\n\t\telse\n\t\t\treturn MatTransform();\n    else\n        return GetTransformShapeToGlobal(shape).InverseTransform();\n}\n\nvoid AnimInfo::SetTransformShapeToGlobal(NiShape* shape, const MatTransform& newShapeToGlobal) {\n    if (shape->IsSkinned())\n        SetTransformGlobalToShape(shape, newShapeToGlobal.InverseTransform());\n    else {\n        // Derive the node-to-parent transform from the new node-to-global and\n        // old parent-to-global transforms.\n        NiNode* parent = refNif->GetParentNode(shape);\n        MatTransform parentToGlobal;\n        while (parent) {\n            parentToGlobal = parent->GetTransformToParent().ComposeTransforms(parentToGlobal);\n            parent = refNif->GetParentNode(parent);\n        }\n        shape->SetTransformToParent(parentToGlobal.InverseTransform().ComposeTransforms(newShapeToGlobal));\n    }\n}\n\nvoid AnimInfo::SetTransformGlobalToShape(NiShape* shape, const MatTransform& newGlobalToShape) {\n    if (shape->IsSkinned()) {\n        ChangeGlobalToSkinTransform(shape->name.get(), newGlobalToShape);\n        // Note that not all nifs have this transform, so setting it in\n        // AnimInfo is the important one, not setting it in refNif.\n        refNif->SetShapeTransformGlobalToSkin(shape, newGlobalToShape);\n    }\n    else\n        SetTransformShapeToGlobal(shape, newGlobalToShape.InverseTransform());\n}\n\nAnimBone& AnimBone::LoadFromNif(NifFile* skeletonNif, uint32_t srcBlock, AnimBone* inParent) {\n\tparent = inParent;\n\tisStandardBone = false;\n\tauto node = skeletonNif->GetHeader().GetBlock<NiNode>(srcBlock);\n\tif (!node)\n\t\treturn *this;\n\tisStandardBone = true;\n\n\tboneName = node->name.get();\n\trefCount = 0;\n\n\tSetTransformBoneToParent(node->GetTransformToParent());\n\n\tfor (auto& child : node->childRefs) {\n\t\tstd::string name = skeletonNif->GetNodeName(child.index);\n\t\tif (!name.empty()) {\n\t\t\tif (name == \"_unnamed_\")\n\t\t\t\tname = AnimSkeleton::getInstance().GenerateBoneName();\n\n\t\t\tAnimBone& bone = AnimSkeleton::getInstance().AddStandardBone(name).LoadFromNif(skeletonNif, child.index, this);\n\t\t\tchildren.push_back(&bone);\n\t\t}\n\t}\n\n\treturn *this;\n}\n\nNiNode* AnimBone::AddToNif(NifFile* nif) const {\n\tNiNode* pnode = nullptr;\n\tif (parent) {\n\t\tpnode = nif->FindBlockByName<NiNode>(parent->boneName);\n\t\tif (!pnode)\n\t\t\tpnode = parent->AddToNif(nif);\n\t}\n\treturn nif->AddNode(boneName, xformToParent, pnode);\n}\n\nvoid AnimSkeleton::Clear() {\n\tallBones.clear();\n\tcustomBones.clear();\n\trefSkeletonNif.Clear();\n\trootBone.clear();\n\tunknownCount = 0;\n}\n\nint AnimSkeleton::LoadFromNif(const std::string& fileName) {\n\tClear();\n\n\tint error = refSkeletonNif.Load(fileName);\n\tif (error) {\n\t\twxLogError(\"Failed to load skeleton '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Failed to load skeleton '%s'!\"), fileName));\n\t\treturn 1;\n\t}\n\n\trootBone = Config[\"Anim/SkeletonRootName\"];\n\tuint32_t nodeID = refSkeletonNif.GetBlockID(refSkeletonNif.FindBlockByName<NiNode>(rootBone));\n\tif (nodeID == 0xFFFFFFFF) {\n\t\twxLogError(\"Root '%s' not found in skeleton '%s'!\", rootBone, fileName);\n\t\twxMessageBox(wxString::Format(_(\"Root '%s' not found in skeleton '%s'!\"), rootBone, fileName));\n\t\treturn 2;\n\t}\n\n\tallBones.clear();\n\tcustomBones.clear();\n\n\tAddStandardBone(rootBone).LoadFromNif(&refSkeletonNif, nodeID, nullptr);\n\twxLogMessage(\"Loaded skeleton '%s' with root '%s'.\", fileName, rootBone);\n\treturn 0;\n}\n\nAnimBone& AnimSkeleton::AddStandardBone(const std::string& boneName) {\n\treturn allBones[boneName];\n}\n\nAnimBone& AnimSkeleton::AddCustomBone(const std::string& boneName) {\n\tAnimBone* cb = &customBones[boneName];\n\tcb->boneName = boneName;\n\treturn *cb;\n}\n\nstd::string AnimSkeleton::GenerateBoneName() {\n\treturn wxString::Format(\"UnnamedBone_%i\", unknownCount++).ToStdString();\n}\n\nAnimBone* AnimSkeleton::LoadCustomBoneFromNif(NifFile* nif, const std::string& boneName) {\n\tNiNode* node = nif->FindBlockByName<NiNode>(boneName);\n\tif (!node)\n\t\treturn nullptr;\n\tAnimBone* parentBone = nullptr;\n\tNiNode* parentNode = nif->GetParentNode(node);\n\tif (parentNode) {\n\t\tparentBone = GetBonePtr(parentNode->name.get());\n\t\tif (!parentBone)\n\t\t\tparentBone = LoadCustomBoneFromNif(nif, parentNode->name.get());\n\t}\n\tif (!parentBone)\n\t\tparentBone = GetRootBonePtr();\n\tAnimBone& cstm = AnimSkeleton::getInstance().AddCustomBone(boneName);\n\tcstm.SetTransformBoneToParent(node->GetTransformToParent());\n\tcstm.SetParentBone(parentBone);\n\treturn &cstm;\n}\n\nbool AnimSkeleton::RefBone(const std::string& boneName) {\n\tif (allBones.find(boneName) != allBones.end()) {\n\t\tallBones[boneName].refCount++;\n\t\treturn true;\n\t}\n\tif (customBones.find(boneName) != customBones.end()) {\n\t\tcustomBones[boneName].refCount++;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nbool AnimSkeleton::ReleaseBone(const std::string& boneName) {\n\tif (allBones.find(boneName) != allBones.end()) {\n\t\tallBones[boneName].refCount--;\n\t\treturn true;\n\t}\n\tif (customBones.find(boneName) != customBones.end()) {\n\t\tcustomBones[boneName].refCount--;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nint AnimSkeleton::GetBoneRefCount(const std::string& boneName) {\n\tif (allBones.find(boneName) != allBones.end())\n\t\treturn allBones[boneName].refCount;\n\n\tif (customBones.find(boneName) != customBones.end())\n\t\treturn customBones[boneName].refCount;\n\n\treturn 0;\n}\n\nAnimBone* AnimSkeleton::GetBonePtr(const std::string& boneName, const bool allowCustom) {\n\tif (allBones.find(boneName) != allBones.end())\n\t\treturn &allBones[boneName];\n\n\tif (allowCustom && customBones.find(boneName) != customBones.end())\n\t\treturn &customBones[boneName];\n\n\treturn nullptr;\n}\n\nAnimBone* AnimSkeleton::GetRootBonePtr() {\n\treturn &allBones[rootBone];\n}\n\nbool AnimSkeleton::GetBoneTransformToGlobal(const std::string& boneName, MatTransform& xform) {\n\tauto bone = GetBonePtr(boneName, allowCustomTransforms);\n\tif (!bone)\n\t\treturn false;\n\n\txform = bone->xformToGlobal;\n\t//xform.scale = 1.0f; // Scale should be ignored?\n\treturn true;\n}\n\nsize_t AnimSkeleton::GetActiveBoneCount() const {\n\tsize_t c = 0;\n\tfor (auto& ab : allBones) {\n\t\tif (ab.second.refCount > 0) {\n\t\t\tc++;\n\t\t}\n\t}\n\n\tfor (auto& cb : customBones) {\n\t\tif (cb.second.refCount > 0) {\n\t\t\tc++;\n\t\t}\n\t}\n\n\treturn c;\n}\n\nsize_t AnimSkeleton::GetActiveBoneNames(std::vector<std::string>& outBoneNames) const {\n\tsize_t c = 0;\n\tfor (auto& ab : allBones) {\n\t\tif (ab.second.refCount > 0) {\n\t\t\toutBoneNames.push_back(ab.first);\n\t\t\tc++;\n\t\t}\n\t}\n\n\tfor (auto& cb : customBones) {\n\t\tif (cb.second.refCount > 0) {\n\t\t\toutBoneNames.push_back(cb.first);\n\t\t\tc++;\n\t\t}\n\t}\n\n\treturn c;\n}\n\nsize_t AnimSkeleton::GetBoneNames(std::vector<std::string>& outBoneNames) const {\n\tsize_t c = 0;\n\tfor (auto& ab : allBones) {\n\t\toutBoneNames.push_back(ab.first);\n\t\tc++;\n\t}\n\n\tfor (auto& cb : customBones) {\n\t\toutBoneNames.push_back(cb.first);\n\t\tc++;\n\t}\n\n\treturn c;\n}\n\nvoid AnimSkeleton::DisableCustomTransforms() {\n\tallowCustomTransforms = false;\n}\n\nvoid AnimBone::UpdateTransformToGlobal() {\n\tif (parent)\n\t\txformToGlobal = parent->xformToGlobal.ComposeTransforms(xformToParent);\n\telse\n\t\txformToGlobal = xformToParent;\n\tfor (AnimBone* cptr : children)\n\t\tcptr->UpdateTransformToGlobal();\n}\n\nvoid AnimBone::UpdatePoseTransform() {\n\t// this bone's pose -> this bone -> parent bone's pose -> global\n\tMatTransform xformPoseToBone;\n\txformPoseToBone.translation = poseTranVec;\n\txformPoseToBone.rotation = RotVecToMat(poseRotVec);\n\txformPoseToBone.scale = poseScale;\n\tMatTransform xformPoseToParent = xformToParent.ComposeTransforms(xformPoseToBone);\n\tif (parent)\n\t\txformPoseToGlobal = parent->xformPoseToGlobal.ComposeTransforms(xformPoseToParent);\n\telse\n\t\txformPoseToGlobal = xformPoseToParent;\n\tfor (AnimBone* cptr : children)\n\t\tcptr->UpdatePoseTransform();\n}\n\nvoid AnimBone::SetTransformBoneToParent(const MatTransform& ttp) {\n\txformToParent = ttp;\n\tUpdateTransformToGlobal();\n\tUpdatePoseTransform();\n}\n\nvoid AnimBone::SetParentBone(AnimBone* newParent) {\n\tif (parent == newParent)\n\t\treturn;\n\tif (parent) {\n\t\t//std::erase(parent->children, this);\n\t\tauto it = std::remove(parent->children.begin(), parent->children.end(), this);\n\t\tparent->children.erase(it, parent->children.end());\n\t}\n\tparent = newParent;\n\tif (parent)\n\t\tparent->children.push_back(this);\n\tUpdateTransformToGlobal();\n\tUpdatePoseTransform();\n}\n\nbool AnimBone::IsUnposed() {\n\treturn poseTranVec.IsZero() && poseRotVec.IsZero() && poseScale == 1.0f;\n}\n\nbool AnimBone::IsFullyUnposed() {\n\tauto p = parent;\n\twhile (p) {\n\t\tif (!p->IsUnposed())\n\t\t\treturn false;\n\n\t\tp = p->parent;\n\t}\n\treturn IsUnposed();\n}\n"
  },
  {
    "path": "src/components/Anim.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../utils/ConfigurationManager.h\"\n#include \"NifFile.hpp\"\n\n#include <map>\n\nstruct VertexBoneWeights {\n\tstd::vector<uint8_t> boneIds;\n\tstd::vector<float> weights;\n\n\tvoid Add(const uint8_t inBoneId, const float inWeight) {\n\t\tif (inWeight == 0.0f)\n\t\t\treturn;\n\n\t\tfor (size_t i = 0; i < weights.size(); ++i) {\n\t\t\tif (inWeight < weights[i])\n\t\t\t\tcontinue;\n\n\t\t\tweights.insert(weights.begin() + i, inWeight);\n\t\t\tboneIds.insert(boneIds.begin() + i, inBoneId);\n\t\t\treturn;\n\t\t}\n\n\t\tweights.push_back(inWeight);\n\t\tboneIds.push_back(inBoneId);\n\t}\n};\n\nclass AnimBone {\npublic:\n\tstd::string boneName = \"bogus\"; // bone names are node names in the nif file\n\tbool isStandardBone = false;\n\tAnimBone* parent = nullptr;\n\tstd::vector<AnimBone*> children;\n\t// xformToGlobal: transforms from this bone's CS to the global CS.\n\tnifly::MatTransform xformToGlobal;\n\t// xformToParent: transforms from this bone's CS to its parent's CS.\n\tnifly::MatTransform xformToParent;\n\t// pose rotation and translation vectors\n\tnifly::Vector3 poseRotVec, poseTranVec;\n\tfloat poseScale = 1.0f;\n\tnifly::MatTransform xformPoseToGlobal;\n\n\tint refCount = 0; // reference count of this bone\n\n\tAnimBone& LoadFromNif(nifly::NifFile* skeletonNif, uint32_t srcBlock, AnimBone* parent = nullptr);\n\t// AddToNif adds this bone to the given nif, as well as its parent\n\t// if missing, recursively.  The new bone's NiNode is returned.\n\tnifly::NiNode* AddToNif(nifly::NifFile* nif) const;\n\t// SetTransformBoneToParent sets xformToParent and updates xformToGlobal\n\t// and xformPoseToGlobal, for this and for descendants.\n\tvoid SetTransformBoneToParent(const nifly::MatTransform& ttp);\n\t// UpdateTransformToGlobal updates xformToGlobal for this and for\n\t// descendants.  This should only be called from itself,\n\t// SetTransformBoneToParent, and SetParentBone.\n\tvoid UpdateTransformToGlobal();\n\t// UpdatePoseTransform updates xformPoseToGlobal for this and all\n\t// descendants.  Call it after poseRotVec, poseTranVec, or\n\t// xformToGlobal is changed.\n\tvoid UpdatePoseTransform();\n\t// SetParentBone updates \"parent\" of this and \"children\" of the old\n\t// and new parents.  It also calls UpdateTransformToGlobal and\n\t// UpdatePoseTranform.\n\tvoid SetParentBone(AnimBone* newParent);\n\t// Returns if the bone is unposed (no trans/rot/scale)\n\tbool IsUnposed();\n\t// Returns if the bone and all of its parents are unposed (no trans/rot/scale)\n\tbool IsFullyUnposed();\n};\n\n// Vertex to weight value association. Also keeps track of skin-to-bone transform and bounding sphere.\nclass AnimWeight {\npublic:\n\tstd::unordered_map<uint16_t, float> weights;\n\tnifly::MatTransform xformSkinToBone;\n\tnifly::BoundingSphere bounds;\n\n\tvoid LoadFromNif(nifly::NifFile* loadFromFile, nifly::NiShape* shape, const int& index);\n};\n\n// Bone to weight list association.\nclass AnimSkin {\npublic:\n\tstd::unordered_map<int, AnimWeight> boneWeights;\n\tstd::unordered_map<std::string, int> boneNames;\n\tnifly::MatTransform xformGlobalToSkin;\n\n\tvoid LoadFromNif(nifly::NifFile* loadFromFile, nifly::NiShape* shape);\n\n\tvoid RemoveBone(const std::string& boneName) {\n\t\tauto bone = boneNames.find(boneName);\n\t\tif (bone == boneNames.end())\n\t\t\treturn;\n\n\t\tint boneID = bone->second;\n\t\tstd::unordered_map<int, AnimWeight> bwTemp;\n\t\tfor (auto& bw : boneWeights) {\n\t\t\tif (bw.first > boneID)\n\t\t\t\tbwTemp[bw.first - 1] = std::move(bw.second);\n\t\t\telse if (bw.first < boneID)\n\t\t\t\tbwTemp[bw.first] = std::move(bw.second);\n\t\t}\n\n\t\tboneWeights.clear();\n\n\t\tfor (auto& bw : bwTemp)\n\t\t\tboneWeights[bw.first] = std::move(bw.second);\n\n\t\tboneNames.erase(boneName);\n\t\tfor (auto& bn : boneNames)\n\t\t\tif (bn.second > boneID)\n\t\t\t\tbn.second--;\n\t}\n\n\tvoid InsertVertexIndices(const std::vector<uint16_t>& indices);\n};\n\nclass AnimPartition {\npublic:\n\tint bodypart;\t\t\t\t\t\t\t\t // Body part number (from BSDismembermentSkinInstance/partiitons).\n\tstd::vector<nifly::Triangle> tris;\t\t\t // Points are indices to the verts list for this partition. (eg. starting at 0).\n\tstd::vector<int> verts;\t\t\t\t\t\t // All referenced verts in this partition.\n\tstd::vector<int> bones;\t\t\t\t\t\t // All referenced bones in this partition.\n\tstd::vector<std::vector<float>> vertWeights; // Vert order list of weights per vertex.\n\tstd::vector<std::vector<int>> vertBones;\t // Vert order list of bones per vertex.\n};\n\n/* Represents animation weighting to a common skeleton across multiple shapes, sourced from nif files*/\nclass AnimInfo {\nprivate:\n\tnifly::NifFile* refNif = nullptr;\n\npublic:\n\tstd::map<std::string, std::vector<std::string>> shapeBones;\n\tstd::unordered_map<std::string, AnimSkin> shapeSkinning; // Shape to skin association.\n\n\tnifly::NifFile* GetRefNif() { return refNif; };\n\tconst nifly::NifFile* GetRefNif() const { return refNif; };\n\tvoid SetRefNif(nifly::NifFile* nif) { refNif = nif; };\n\n\t// Returns true if a new bone is added, false if the bone already exists.\n\tbool AddShapeBone(const std::string& shape, const std::string& boneName);\n\tbool RemoveShapeBone(const std::string& shape, const std::string& boneName);\n\n\tvoid Clear();\n\tvoid ClearShape(const std::string& shape);\n\tvoid DeleteVertsForShape(const std::string& shape, const std::vector<uint16_t>& indices);\n\n\t// Loads the skinning information contained in the nif for all shapes.\n\t// Returns false if there is no skinning information.\n\tbool LoadFromNif(nifly::NifFile* nif);\n\tbool LoadFromNif(nifly::NifFile* nif, nifly::NiShape* shape, bool newRefNif = true);\n\tbool CloneShape(nifly::NifFile* nif, nifly::NiShape* shape, const std::string& newShape);\n\n\tint GetShapeBoneIndex(const std::string& shapeName, const std::string& boneName) const;\n\tstd::unordered_map<uint16_t, float>* GetWeightsPtr(const std::string& shape, const std::string& boneName);\n\tbool HasWeights(const std::string& shape, const std::string& boneName);\n\tvoid GetWeights(const std::string& shape, const std::string& boneName, std::unordered_map<uint16_t, float>& outVertWeights);\n\tvoid SetWeights(const std::string& shape, const std::string& boneName, std::unordered_map<uint16_t, float>& inVertWeights);\n\tbool GetXFormSkinToBone(const std::string& shape, const std::string& boneName, nifly::MatTransform& stransform);\n\tvoid SetXFormSkinToBone(const std::string& shape, const std::string& boneName, const nifly::MatTransform& stransform);\n\t// RecalcXFormSkinToBone recalculates a shape bone's xformSkinToBone\n\t// from other transforms.\n\tvoid RecalcXFormSkinToBone(const std::string& shape, const std::string& boneName);\n\t// RecursiveRecalcXFormSkinToBone calls RecalcXFormSkinToBone for the\n\t// given bone and all its descendants.\n\tvoid RecursiveRecalcXFormSkinToBone(const std::string& shape, AnimBone* bPtr);\n\t// ChangeGlobalToSkinTransform sets the global-to-skin transform for a\n\t// shape and updates all skin-to-bone transforms.\n\tvoid ChangeGlobalToSkinTransform(const std::string& shape, const nifly::MatTransform& newTrans);\n\tbool BoneHasInconsistentTransforms(const std::string& shape, const std::string& bone) const;\n\tvoid FindBonesWithInconsistentTransforms(const std::string& shape, std::unordered_map<std::string, nifly::MatTransform>& badStandard, std::unordered_map<std::string, nifly::MatTransform>& badCustom);\n\tvoid RecalcCustomBoneXFormsFromSkin(const std::string& shape, const std::string& boneName);\n\tbool CalcShapeSkinBounds(const std::string& shapeName, const int& boneIndex);\n\tvoid CleanupBones();\n\tvoid WriteNodesToNif(nifly::NifFile* nif, const std::string& shapeException = \"\");\n\tvoid WriteToNif(nifly::NifFile* nif, const std::string& shapeException = \"\");\n\n\tvoid RenameShape(const std::string& shapeName, const std::string& newShapeName);\n\n\tstatic void MatchSymmetricBoneNames(std::vector<std::string> boneNames, std::vector<std::pair<std::string, std::string>>& pairs, std::vector<std::string>& singles);\n\tvoid SwapBonesLR(const std::string& shapeName);\n\n\tnifly::MatTransform GetTransformShapeToGlobal(nifly::NiShape* shape) const;\n\tnifly::MatTransform GetTransformGlobalToShape(nifly::NiShape* shape) const;\n\tvoid SetTransformShapeToGlobal(nifly::NiShape* shape, const nifly::MatTransform& newShapeToGlobal);\n\tvoid SetTransformGlobalToShape(nifly::NiShape* shape, const nifly::MatTransform& newGlobalToShape);\n};\n\nclass AnimSkeleton {\n\tstd::map<std::string, AnimBone> allBones;\n\tstd::map<std::string, AnimBone> customBones;\n\tstd::string rootBone;\n\tint unknownCount = 0;\n\tbool allowCustomTransforms = true;\n\n\tAnimSkeleton() {}\n\npublic:\n\tstatic AnimSkeleton& getInstance() {\n\t\tstatic AnimSkeleton instance;\n\t\treturn instance;\n\t}\n\n\tnifly::NifFile refSkeletonNif;\n\n\tvoid Clear();\n\n\tint LoadFromNif(const std::string& fileName);\n\tAnimBone& AddStandardBone(const std::string& boneName);\n\tAnimBone& AddCustomBone(const std::string& boneName);\n\tstd::string GenerateBoneName();\n\tAnimBone* LoadCustomBoneFromNif(nifly::NifFile* nif, const std::string& boneName);\n\n\tbool RefBone(const std::string& boneName);\n\tbool ReleaseBone(const std::string& boneName);\n\tint GetBoneRefCount(const std::string& boneName);\n\n\tAnimBone* GetBonePtr(const std::string& boneName, const bool allowCustom = true);\n\tAnimBone* GetRootBonePtr();\n\tbool GetBoneTransformToGlobal(const std::string& boneName, nifly::MatTransform& xform);\n\n\tsize_t GetActiveBoneCount() const;\n\tsize_t GetActiveBoneNames(std::vector<std::string>& outBoneNames) const;\n\tsize_t GetBoneNames(std::vector<std::string>& outBoneNames) const;\n\tvoid DisableCustomTransforms();\n};\n"
  },
  {
    "path": "src/components/Automation.cpp",
    "content": "﻿/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"Automation.h\"\n\n#include \"../utils/PlatformUtil.h\"\n\n#include <regex>\n\nusing namespace tinyxml2;\n\nstd::string AutomationStepTypeToString(AutomationStepType type) {\n\tswitch (type) {\n\t\tcase AutomationStepType::AddCustomBone: return \"AddCustomBone\";\n\t\tcase AutomationStepType::CopyBoneWeights: return \"CopyBoneWeights\";\n\t\tcase AutomationStepType::DeleteBones: return \"DeleteBones\";\n\t\tcase AutomationStepType::EditBone: return \"EditBone\";\n\t\tcase AutomationStepType::RemoveSkinning: return \"RemoveSkinning\";\n\t\tcase AutomationStepType::ExportFile: return \"ExportFile\";\n\t\tcase AutomationStepType::SaveProject: return \"SaveProject\";\n\t\tcase AutomationStepType::ImportFile: return \"ImportFile\";\n\t\tcase AutomationStepType::ImportSliderData: return \"ImportSliderData\";\n\t\tcase AutomationStepType::AddProject: return \"AddProject\";\n\t\tcase AutomationStepType::ClearProject: return \"ClearProject\";\n\t\tcase AutomationStepType::ClearReference: return \"ClearReference\";\n\t\tcase AutomationStepType::LoadReference: return \"LoadReference\";\n\t\tcase AutomationStepType::SetBaseShape: return \"SetBaseShape\";\n\t\tcase AutomationStepType::SetReferenceShape: return \"SetReferenceShape\";\n\t\tcase AutomationStepType::ApplyPose: return \"ApplyPose\";\n\t\tcase AutomationStepType::DeleteShape: return \"DeleteShape\";\n\t\tcase AutomationStepType::DuplicateShape: return \"DuplicateShape\";\n\t\tcase AutomationStepType::InvertUVs: return \"InvertUVs\";\n\t\tcase AutomationStepType::MirrorShape: return \"MirrorShape\";\n\t\tcase AutomationStepType::RefineMesh: return \"RefineMesh\";\n\t\tcase AutomationStepType::RenameShape: return \"RenameShape\";\n\t\tcase AutomationStepType::ResetTransforms: return \"ResetTransforms\";\n\t\tcase AutomationStepType::TransformShape: return \"TransformShape\";\n\t\tcase AutomationStepType::ConformSliders: return \"ConformSliders\";\n\t\tcase AutomationStepType::DeleteSlider: return \"DeleteSlider\";\n\t\tcase AutomationStepType::SetSliderValues: return \"SetSliderValues\";\n\t\tcase AutomationStepType::SetSliderProperties: return \"SetSliderProperties\";\n\t\tcase AutomationStepType::ClearMask: return \"ClearMask\";\n\t\tcase AutomationStepType::LoadMask: return \"LoadMask\";\n\t\tcase AutomationStepType::RemoveUnusedNodes: return \"RemoveUnusedNodes\";\n\t\tcase AutomationStepType::FixClipping: return \"FixClipping\";\n\t\tcase AutomationStepType::FixBadBones: return \"FixBadBones\";\n\t\tdefault: return \"LoadReference\";\n\t}\n}\n\nAutomationStepType AutomationStepTypeFromString(const std::string& str) {\n\tif (str == \"AddCustomBone\") return AutomationStepType::AddCustomBone;\n\tif (str == \"CopyBoneWeights\") return AutomationStepType::CopyBoneWeights;\n\tif (str == \"DeleteBones\") return AutomationStepType::DeleteBones;\n\tif (str == \"EditBone\") return AutomationStepType::EditBone;\n\tif (str == \"RemoveSkinning\") return AutomationStepType::RemoveSkinning;\n\tif (str == \"ExportFile\") return AutomationStepType::ExportFile;\n\tif (str == \"SaveProject\") return AutomationStepType::SaveProject;\n\tif (str == \"ImportFile\") return AutomationStepType::ImportFile;\n\tif (str == \"ImportSliderData\") return AutomationStepType::ImportSliderData;\n\tif (str == \"AddProject\") return AutomationStepType::AddProject;\n\tif (str == \"ClearProject\") return AutomationStepType::ClearProject;\n\tif (str == \"ClearReference\") return AutomationStepType::ClearReference;\n\tif (str == \"LoadReference\") return AutomationStepType::LoadReference;\n\tif (str == \"SetBaseShape\") return AutomationStepType::SetBaseShape;\n\tif (str == \"SetReferenceShape\") return AutomationStepType::SetReferenceShape;\n\tif (str == \"ApplyPose\") return AutomationStepType::ApplyPose;\n\tif (str == \"DeleteShape\") return AutomationStepType::DeleteShape;\n\tif (str == \"DuplicateShape\") return AutomationStepType::DuplicateShape;\n\tif (str == \"InvertUVs\") return AutomationStepType::InvertUVs;\n\tif (str == \"MirrorShape\") return AutomationStepType::MirrorShape;\n\tif (str == \"RefineMesh\") return AutomationStepType::RefineMesh;\n\tif (str == \"RenameShape\") return AutomationStepType::RenameShape;\n\tif (str == \"ResetTransforms\") return AutomationStepType::ResetTransforms;\n\tif (str == \"TransformShape\") return AutomationStepType::TransformShape;\n\tif (str == \"ConformSliders\") return AutomationStepType::ConformSliders;\n\tif (str == \"DeleteSlider\") return AutomationStepType::DeleteSlider;\n\tif (str == \"SetSliderValues\") return AutomationStepType::SetSliderValues;\n\tif (str == \"SetSliderProperties\") return AutomationStepType::SetSliderProperties;\n\tif (str == \"ClearMask\") return AutomationStepType::ClearMask;\n\tif (str == \"LoadMask\") return AutomationStepType::LoadMask;\n\tif (str == \"RemoveUnusedNodes\") return AutomationStepType::RemoveUnusedNodes;\n\tif (str == \"FixClipping\") return AutomationStepType::FixClipping;\n\tif (str == \"FixBadBones\") return AutomationStepType::FixBadBones;\n\treturn AutomationStepType::LoadReference;\n}\n\nstd::string AutomationBatchModeToString(AutomationBatchMode mode) {\n\tswitch (mode) {\n\t\tcase AutomationBatchMode::None: return \"None\";\n\t\tcase AutomationBatchMode::FolderScan: return \"FolderScan\";\n\t\tcase AutomationBatchMode::SliderSets: return \"SliderSets\";\n\t\tdefault: return \"None\";\n\t}\n}\n\nAutomationBatchMode AutomationBatchModeFromString(const std::string& str) {\n\tif (str == \"FolderScan\") return AutomationBatchMode::FolderScan;\n\tif (str == \"SliderSets\") return AutomationBatchMode::SliderSets;\n\treturn AutomationBatchMode::None;\n}\n\nstatic const char* GetChildText(XMLElement* parent, const char* childName) {\n\tXMLElement* child = parent->FirstChildElement(childName);\n\tif (child && child->GetText())\n\t\treturn child->GetText();\n\treturn nullptr;\n}\n\nstatic bool GetChildBool(XMLElement* parent, const char* childName, bool defaultVal) {\n\tconst char* text = GetChildText(parent, childName);\n\tif (!text)\n\t\treturn defaultVal;\n\tstd::string s(text);\n\treturn (s == \"true\" || s == \"1\");\n}\n\nstatic float GetChildFloat(XMLElement* parent, const char* childName, float defaultVal) {\n\tconst char* text = GetChildText(parent, childName);\n\tif (!text)\n\t\treturn defaultVal;\n\ttry {\n\t\treturn std::stof(text);\n\t}\n\tcatch (...) {\n\t\treturn defaultVal;\n\t}\n}\n\nstatic int GetChildInt(XMLElement* parent, const char* childName, int defaultVal) {\n\tconst char* text = GetChildText(parent, childName);\n\tif (!text)\n\t\treturn defaultVal;\n\ttry {\n\t\treturn std::stoi(text);\n\t}\n\tcatch (...) {\n\t\treturn defaultVal;\n\t}\n}\n\nstatic void SetChildText(XMLDocument& doc, XMLElement* parent, const char* childName, const std::string& value) {\n\tif (value.empty())\n\t\treturn;\n\tXMLElement* child = doc.NewElement(childName);\n\tchild->SetText(value.c_str());\n\tparent->InsertEndChild(child);\n}\n\nstatic void SetChildBool(XMLDocument& doc, XMLElement* parent, const char* childName, bool value, bool defaultVal) {\n\tif (value == defaultVal)\n\t\treturn;\n\tXMLElement* child = doc.NewElement(childName);\n\tchild->SetText(value ? \"true\" : \"false\");\n\tparent->InsertEndChild(child);\n}\n\nstatic void SetChildFloat(XMLDocument& doc, XMLElement* parent, const char* childName, float value, float defaultVal) {\n\tif (value == defaultVal)\n\t\treturn;\n\tXMLElement* child = doc.NewElement(childName);\n\tchild->SetText(std::to_string(value).c_str());\n\tparent->InsertEndChild(child);\n}\n\nstatic void SetChildInt(XMLDocument& doc, XMLElement* parent, const char* childName, int value, int defaultVal) {\n\tif (value == defaultVal)\n\t\treturn;\n\tXMLElement* child = doc.NewElement(childName);\n\tchild->SetText(std::to_string(value).c_str());\n\tparent->InsertEndChild(child);\n}\n\nint AutomationScript::Load(const std::string& fileName) {\n\tXMLDocument doc;\n\n\tFILE* fp = nullptr;\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\tint err = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (err || !fp)\n\t\treturn 1;\n#else\n\tfp = fopen(fileName.c_str(), \"rb\");\n\tif (!fp)\n\t\treturn 1;\n#endif\n\n\tXMLError error = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error != XML_SUCCESS)\n\t\treturn 2;\n\n\tXMLElement* root = doc.FirstChildElement(\"AutomationScript\");\n\tif (!root)\n\t\treturn 3;\n\n\tsteps.clear();\n\tvariables.clear();\n\n\t// Reset batch settings\n\tbatchMode = AutomationBatchMode::None;\n\tbatchFolder.clear();\n\tbatchExtension.clear();\n\tbatchSubdirectories = false;\n\tbatchFileFilter.clear();\n\tbatchFileFilterRegex = false;\n\tbatchSliderSetFilter.clear();\n\tbatchSliderSetFilterRegex = false;\n\n\t// Load variables\n\tXMLElement* varsElem = root->FirstChildElement(\"Variables\");\n\tif (varsElem) {\n\t\tXMLElement* varElem = varsElem->FirstChildElement(\"Var\");\n\t\twhile (varElem) {\n\t\t\tconst char* key = varElem->Attribute(\"key\");\n\t\t\tconst char* val = varElem->GetText();\n\t\t\tif (key)\n\t\t\t\tvariables[key] = val ? val : \"\";\n\t\t\tvarElem = varElem->NextSiblingElement(\"Var\");\n\t\t}\n\t}\n\n\t// Load batch settings\n\tXMLElement* batchElem = root->FirstChildElement(\"Batch\");\n\tif (batchElem) {\n\t\tif (batchElem->Attribute(\"mode\"))\n\t\t\tbatchMode = AutomationBatchModeFromString(batchElem->Attribute(\"mode\"));\n\t\tconst char* folder = GetChildText(batchElem, \"Folder\");\n\t\tif (folder)\n\t\t\tbatchFolder = folder;\n\t\tconst char* ext = GetChildText(batchElem, \"Extension\");\n\t\tif (ext)\n\t\t\tbatchExtension = ext;\n\t\tbatchSubdirectories = GetChildBool(batchElem, \"Subdirectories\", false);\n\t\tconst char* filter = GetChildText(batchElem, \"FileFilter\");\n\t\tif (filter)\n\t\t\tbatchFileFilter = filter;\n\t\tbatchFileFilterRegex = GetChildBool(batchElem, \"FileFilterRegex\", false);\n\t\tconst char* ssFilter = GetChildText(batchElem, \"SliderSetFilter\");\n\t\tif (ssFilter)\n\t\t\tbatchSliderSetFilter = ssFilter;\n\t\tbatchSliderSetFilterRegex = GetChildBool(batchElem, \"SliderSetFilterRegex\", false);\n\t}\n\n\tXMLElement* stepElem = root->FirstChildElement(\"Step\");\n\twhile (stepElem) {\n\t\tAutomationStep step;\n\n\t\tif (stepElem->Attribute(\"type\"))\n\t\t\tstep.type = AutomationStepTypeFromString(stepElem->Attribute(\"type\"));\n\n\t\tstep.active = stepElem->BoolAttribute(\"active\", true);\n\n\t\tconst char* noteText = GetChildText(stepElem, \"Note\");\n\t\tif (noteText)\n\t\t\tstep.note = noteText;\n\n\t\tconst char* meshesText = GetChildText(stepElem, \"TargetMeshes\");\n\t\tif (meshesText)\n\t\t\tstep.targetMeshes = SplitCommaSeparated(meshesText);\n\n\t\tstep.targetRegex = GetChildBool(stepElem, \"TargetRegex\", false);\n\n\t\tswitch (step.type) {\n\t\t\tcase AutomationStepType::ClearProject:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::LoadReference:\n\t\t\tcase AutomationStepType::AddProject: {\n\t\t\t\tconst char* src = GetChildText(stepElem, \"SourceFile\");\n\t\t\t\tif (src)\n\t\t\t\t\tstep.refSourceFile = src;\n\t\t\t\tconst char* set = GetChildText(stepElem, \"Set\");\n\t\t\t\tif (set)\n\t\t\t\t\tstep.refSet = set;\n\t\t\t\tconst char* shape = GetChildText(stepElem, \"Shape\");\n\t\t\t\tif (shape)\n\t\t\t\t\tstep.refShape = shape;\n\t\t\t\tstep.refLoadAll = GetChildBool(stepElem, \"LoadAll\", false);\n\t\t\t\tstep.refMergeSliders = GetChildBool(stepElem, \"MergeSliders\", true);\n\t\t\t\tstep.refMergeZaps = GetChildBool(stepElem, \"MergeZaps\", true);\n\t\t\t\tstep.refAppendNewSliders = GetChildBool(stepElem, \"AppendNewSliders\", false);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ConformSliders: {\n\t\t\t\tstep.conformProximityRadius = GetChildFloat(stepElem, \"ProximityRadius\", 10.0f);\n\t\t\t\tstep.conformMaxResults = GetChildInt(stepElem, \"MaxResults\", 10);\n\t\t\t\tstep.conformNoSqueeze = GetChildBool(stepElem, \"NoSqueeze\", false);\n\t\t\t\tstep.conformSolidMode = GetChildBool(stepElem, \"SolidMode\", false);\n\t\t\t\tstep.conformAxisX = GetChildBool(stepElem, \"AxisX\", true);\n\t\t\t\tstep.conformAxisY = GetChildBool(stepElem, \"AxisY\", true);\n\t\t\t\tstep.conformAxisZ = GetChildBool(stepElem, \"AxisZ\", true);\n\t\t\t\tconst char* csn = GetChildText(stepElem, \"SliderNames\");\n\t\t\t\tif (csn)\n\t\t\t\t\tstep.conformSliderNames = SplitCommaSeparated(csn);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::CopyBoneWeights: {\n\t\t\t\tstep.weightProximityRadius = GetChildFloat(stepElem, \"ProximityRadius\", 10.0f);\n\t\t\t\tstep.weightMaxResults = GetChildInt(stepElem, \"MaxResults\", 10);\n\t\t\t\tconst char* bones = GetChildText(stepElem, \"BoneList\");\n\t\t\t\tif (bones)\n\t\t\t\t\tstep.weightBoneList = SplitCommaSeparated(bones);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ImportSliderData: {\n\t\t\t\tconst char* sdf = GetChildText(stepElem, \"SliderDataFile\");\n\t\t\t\tif (sdf)\n\t\t\t\t\tstep.sliderDataFile = sdf;\n\t\t\t\tstep.sliderDataFromFolder = GetChildBool(stepElem, \"FromFolder\", false);\n\t\t\t\tstep.sliderMerge = GetChildBool(stepElem, \"MergeSliders\", false);\n\t\t\t\tconst char* sn = GetChildText(stepElem, \"SliderNames\");\n\t\t\t\tif (sn)\n\t\t\t\t\tstep.sliderNames = SplitCommaSeparated(sn);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::SetSliderValues: {\n\t\t\t\tconst char* svn = GetChildText(stepElem, \"SliderNames\");\n\t\t\t\tif (svn)\n\t\t\t\t\tstep.setSliderNames = SplitCommaSeparated(svn);\n\t\t\t\tstep.setSliderValue = GetChildFloat(stepElem, \"Value\", 1.0f);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ImportFile: {\n\t\t\t\tconst char* filePath = GetChildText(stepElem, \"FilePath\");\n\t\t\t\tif (filePath)\n\t\t\t\t\tstep.importFilePath = filePath;\n\t\t\t\tstep.importFromFolder = GetChildBool(stepElem, \"FromFolder\", false);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::DeleteShape:\n\t\t\t\t// No additional params (uses target meshes)\n\t\t\t\tbreak;\n\t\t\tcase AutomationStepType::RenameShape: {\n\t\t\t\tconst char* on = GetChildText(stepElem, \"OldName\");\n\t\t\t\tif (on)\n\t\t\t\t\tstep.renameOldName = on;\n\t\t\t\tconst char* nn = GetChildText(stepElem, \"NewName\");\n\t\t\t\tif (nn)\n\t\t\t\t\tstep.renameNewName = nn;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::DeleteSlider: {\n\t\t\t\tconst char* sn = GetChildText(stepElem, \"SliderName\");\n\t\t\t\tif (sn)\n\t\t\t\t\tstep.deleteSliderNames = SplitCommaSeparated(sn);\n\t\t\t\tconst char* re = GetChildText(stepElem, \"Regex\");\n\t\t\t\tif (re)\n\t\t\t\t\tstep.deleteSliderRegex = (std::string(re) == \"true\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::SetReferenceShape: {\n\t\t\t\tconst char* sn = GetChildText(stepElem, \"ShapeName\");\n\t\t\t\tif (sn)\n\t\t\t\t\tstep.setRefShapeName = sn;\n\t\t\t\tconst char* ur = GetChildText(stepElem, \"UnsetReference\");\n\t\t\t\tif (ur)\n\t\t\t\t\tstep.setRefUnset = (std::string(ur) == \"true\");\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::RefineMesh:\n\t\t\tcase AutomationStepType::RemoveSkinning:\n\t\t\t\t// No additional params (uses target meshes)\n\t\t\t\tbreak;\n\t\t\tcase AutomationStepType::TransformShape: {\n\t\t\t\tstep.moveX = GetChildFloat(stepElem, \"MoveX\", 0.0f);\n\t\t\t\tstep.moveY = GetChildFloat(stepElem, \"MoveY\", 0.0f);\n\t\t\t\tstep.moveZ = GetChildFloat(stepElem, \"MoveZ\", 0.0f);\n\t\t\t\tstep.rotateX = GetChildFloat(stepElem, \"RotateX\", 0.0f);\n\t\t\t\tstep.rotateY = GetChildFloat(stepElem, \"RotateY\", 0.0f);\n\t\t\t\tstep.rotateZ = GetChildFloat(stepElem, \"RotateZ\", 0.0f);\n\t\t\t\tstep.scaleX = GetChildFloat(stepElem, \"ScaleX\", 1.0f);\n\t\t\t\tstep.scaleY = GetChildFloat(stepElem, \"ScaleY\", 1.0f);\n\t\t\t\tstep.scaleZ = GetChildFloat(stepElem, \"ScaleZ\", 1.0f);\n\t\t\t\tstep.inflateX = GetChildFloat(stepElem, \"InflateX\", 0.0f);\n\t\t\t\tstep.inflateY = GetChildFloat(stepElem, \"InflateY\", 0.0f);\n\t\t\t\tstep.inflateZ = GetChildFloat(stepElem, \"InflateZ\", 0.0f);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::InvertUVs: {\n\t\t\t\tstep.invertU = GetChildBool(stepElem, \"InvertU\", false);\n\t\t\t\tstep.invertV = GetChildBool(stepElem, \"InvertV\", false);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::DeleteBones: {\n\t\t\t\tconst char* bn = GetChildText(stepElem, \"BoneNames\");\n\t\t\t\tif (bn)\n\t\t\t\t\tstep.deleteBoneNames = SplitCommaSeparated(bn);\n\t\t\t\tstep.deleteBoneFromProject = GetChildBool(stepElem, \"FromProject\", true);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::AddCustomBone: {\n\t\t\t\tconst char* bn = GetChildText(stepElem, \"BoneName\");\n\t\t\t\tif (bn)\n\t\t\t\t\tstep.addBoneName = bn;\n\t\t\t\tconst char* pb = GetChildText(stepElem, \"ParentBone\");\n\t\t\t\tif (pb)\n\t\t\t\t\tstep.addBoneParent = pb;\n\t\t\t\tstep.addBoneTransX = GetChildFloat(stepElem, \"TransX\", 0.0f);\n\t\t\t\tstep.addBoneTransY = GetChildFloat(stepElem, \"TransY\", 0.0f);\n\t\t\t\tstep.addBoneTransZ = GetChildFloat(stepElem, \"TransZ\", 0.0f);\n\t\t\t\tstep.addBoneRotX = GetChildFloat(stepElem, \"RotX\", 0.0f);\n\t\t\t\tstep.addBoneRotY = GetChildFloat(stepElem, \"RotY\", 0.0f);\n\t\t\t\tstep.addBoneRotZ = GetChildFloat(stepElem, \"RotZ\", 0.0f);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::EditBone: {\n\t\t\t\tconst char* bn = GetChildText(stepElem, \"BoneName\");\n\t\t\t\tif (bn)\n\t\t\t\t\tstep.editBoneName = bn;\n\t\t\t\tconst char* pb = GetChildText(stepElem, \"ParentBone\");\n\t\t\t\tif (pb)\n\t\t\t\t\tstep.editBoneParent = pb;\n\t\t\t\tstep.editBoneTransX = GetChildFloat(stepElem, \"TransX\", 0.0f);\n\t\t\t\tstep.editBoneTransY = GetChildFloat(stepElem, \"TransY\", 0.0f);\n\t\t\t\tstep.editBoneTransZ = GetChildFloat(stepElem, \"TransZ\", 0.0f);\n\t\t\t\tstep.editBoneRotX = GetChildFloat(stepElem, \"RotX\", 0.0f);\n\t\t\t\tstep.editBoneRotY = GetChildFloat(stepElem, \"RotY\", 0.0f);\n\t\t\t\tstep.editBoneRotZ = GetChildFloat(stepElem, \"RotZ\", 0.0f);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ApplyPose: {\n\t\t\t\tconst char* pn = GetChildText(stepElem, \"PoseName\");\n\t\t\t\tif (pn)\n\t\t\t\t\tstep.poseName = pn;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::SaveProject: {\n\t\t\t\tconst char* dn = GetChildText(stepElem, \"DisplayName\");\n\t\t\t\tif (dn)\n\t\t\t\t\tstep.saveName = dn;\n\t\t\t\tconst char* ofn = GetChildText(stepElem, \"OutputFileName\");\n\t\t\t\tif (ofn)\n\t\t\t\t\tstep.saveOutputFileName = ofn;\n\t\t\t\tconst char* odp = GetChildText(stepElem, \"OutputDataPath\");\n\t\t\t\tif (odp)\n\t\t\t\t\tstep.saveOutputDataPath = odp;\n\t\t\t\tconst char* ssf = GetChildText(stepElem, \"SliderSetFile\");\n\t\t\t\tif (ssf)\n\t\t\t\t\tstep.saveSliderSetFile = ssf;\n\t\t\t\tconst char* sdf = GetChildText(stepElem, \"ShapeDataFolder\");\n\t\t\t\tif (sdf)\n\t\t\t\t\tstep.saveShapeDataFolder = sdf;\n\t\t\t\tconst char* sdfile = GetChildText(stepElem, \"ShapeDataFile\");\n\t\t\t\tif (sdfile)\n\t\t\t\t\tstep.saveShapeDataFile = sdfile;\n\t\t\t\tstep.saveGenWeights = GetChildBool(stepElem, \"GenWeights\", true);\n\t\t\t\tstep.saveAutoCopyRef = GetChildBool(stepElem, \"AutoCopyRef\", true);\n\t\t\t\tstep.saveCopyRefFromProject = GetChildBool(stepElem, \"CopyRefFromProject\", false);\n\t\t\t\tconst char* crsn = GetChildText(stepElem, \"CopyRefShapeName\");\n\t\t\t\tif (crsn)\n\t\t\t\t\tstep.saveCopyRefShapeName = crsn;\n\t\t\t\tstep.saveUseOriginal = GetChildBool(stepElem, \"UseOriginal\", false);\n\t\t\t\tconst char* srf = GetChildText(stepElem, \"ReplaceFrom\");\n\t\t\t\tif (srf)\n\t\t\t\t\tstep.saveReplaceFrom = srf;\n\t\t\t\tconst char* srt = GetChildText(stepElem, \"ReplaceTo\");\n\t\t\t\tif (srt)\n\t\t\t\t\tstep.saveReplaceTo = srt;\n\t\t\t\tconst char* ssuffix = GetChildText(stepElem, \"Suffix\");\n\t\t\t\tif (ssuffix)\n\t\t\t\t\tstep.saveSuffix = ssuffix;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ExportFile: {\n\t\t\t\tconst char* efp = GetChildText(stepElem, \"FilePath\");\n\t\t\t\tif (efp)\n\t\t\t\t\tstep.exportFilePath = efp;\n\t\t\t\tstep.exportWithRef = GetChildBool(stepElem, \"WithRef\", true);\n\t\t\t\tstep.exportUseOriginalPath = GetChildBool(stepElem, \"UseOriginalPath\", false);\n\t\t\t\tconst char* epre = GetChildText(stepElem, \"Prefix\");\n\t\t\t\tif (epre)\n\t\t\t\t\tstep.exportPrefix = epre;\n\t\t\t\tconst char* esuf = GetChildText(stepElem, \"Suffix\");\n\t\t\t\tif (esuf)\n\t\t\t\t\tstep.exportSuffix = esuf;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ResetTransforms:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\t\t\tcase AutomationStepType::DuplicateShape: {\n\t\t\t\tconst char* dn = GetChildText(stepElem, \"NewName\");\n\t\t\t\tif (dn)\n\t\t\t\t\tstep.dupNewName = dn;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::MirrorShape: {\n\t\t\t\tstep.mirrorX = GetChildBool(stepElem, \"MirrorX\", true);\n\t\t\t\tstep.mirrorY = GetChildBool(stepElem, \"MirrorY\", false);\n\t\t\t\tstep.mirrorZ = GetChildBool(stepElem, \"MirrorZ\", false);\n\t\t\t\tstep.mirrorSwapBonesX = GetChildBool(stepElem, \"SwapBonesX\", false);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::ClearMask:\n\t\t\t\t// No additional params (uses target meshes)\n\t\t\t\tbreak;\n\t\t\tcase AutomationStepType::LoadMask: {\n\t\t\t\tconst char* mf = GetChildText(stepElem, \"MaskFile\");\n\t\t\t\tif (mf)\n\t\t\t\t\tstep.loadMaskFile = mf;\n\t\t\t\tconst char* mn = GetChildText(stepElem, \"MaskName\");\n\t\t\t\tif (mn)\n\t\t\t\t\tstep.loadMaskName = mn;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::SetSliderProperties: {\n\t\t\t\tconst char* sn = GetChildText(stepElem, \"SliderNames\");\n\t\t\t\tif (sn)\n\t\t\t\t\tstep.sliderPropNames = SplitCommaSeparated(sn);\n\t\t\t\tstep.sliderPropZap = GetChildInt(stepElem, \"Zap\", -1);\n\t\t\t\tstep.sliderPropHidden = GetChildInt(stepElem, \"Hidden\", -1);\n\t\t\t\tstep.sliderPropDefaultLo = GetChildInt(stepElem, \"DefaultLo\", -1);\n\t\t\t\tstep.sliderPropDefaultHi = GetChildInt(stepElem, \"DefaultHi\", -1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::RemoveUnusedNodes:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\t\t\tcase AutomationStepType::FixClipping: {\n\t\t\t\tstep.fixClipMode = GetChildInt(stepElem, \"Mode\", 0);\n\t\t\t\tstep.fixClipStrength = GetChildFloat(stepElem, \"Strength\", 0.5f);\n\t\t\t\tconst char* sn = GetChildText(stepElem, \"SliderNames\");\n\t\t\t\tif (sn)\n\t\t\t\t\tstep.fixClipSliderNames = SplitCommaSeparated(sn);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase AutomationStepType::FixBadBones:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\t\t}\n\n\t\tsteps.push_back(std::move(step));\n\t\tstepElem = stepElem->NextSiblingElement(\"Step\");\n\t}\n\n\treturn 0;\n}\n\nint AutomationScript::Save(const std::string& fileName) {\n\tXMLDocument doc;\n\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\tXMLElement* root = doc.NewElement(\"AutomationScript\");\n\troot->SetAttribute(\"version\", 1);\n\tdoc.InsertEndChild(root);\n\n\t// Save variables\n\tif (!variables.empty()) {\n\t\tXMLElement* varsElem = doc.NewElement(\"Variables\");\n\t\troot->InsertEndChild(varsElem);\n\t\tfor (const auto& [key, value] : variables) {\n\t\t\tXMLElement* varElem = doc.NewElement(\"Var\");\n\t\t\tvarElem->SetAttribute(\"key\", key.c_str());\n\t\t\tif (!value.empty())\n\t\t\t\tvarElem->SetText(value.c_str());\n\t\t\tvarsElem->InsertEndChild(varElem);\n\t\t}\n\t}\n\n\t// Save batch settings\n\tif (batchMode != AutomationBatchMode::None) {\n\t\tXMLElement* batchElem = doc.NewElement(\"Batch\");\n\t\tbatchElem->SetAttribute(\"mode\", AutomationBatchModeToString(batchMode).c_str());\n\t\troot->InsertEndChild(batchElem);\n\t\t\n\t\tif (batchMode == AutomationBatchMode::FolderScan) {\n\t\t\tSetChildText(doc, batchElem, \"Folder\", batchFolder);\n\t\t\tSetChildText(doc, batchElem, \"Extension\", batchExtension);\n\t\t\tSetChildBool(doc, batchElem, \"Subdirectories\", batchSubdirectories, false);\n\t\t\tSetChildText(doc, batchElem, \"FileFilter\", batchFileFilter);\n\t\t\tSetChildBool(doc, batchElem, \"FileFilterRegex\", batchFileFilterRegex, false);\n\t\t}\n\t\telse if (batchMode == AutomationBatchMode::SliderSets) {\n\t\t\tSetChildText(doc, batchElem, \"SliderSetFilter\", batchSliderSetFilter);\n\t\t\tSetChildBool(doc, batchElem, \"SliderSetFilterRegex\", batchSliderSetFilterRegex, false);\n\t\t}\n\t}\n\n\tfor (const auto& step : steps) {\n\t\tXMLElement* stepElem = doc.NewElement(\"Step\");\n\t\tstepElem->SetAttribute(\"type\", AutomationStepTypeToString(step.type).c_str());\n\t\tstepElem->SetAttribute(\"active\", step.active);\n\t\troot->InsertEndChild(stepElem);\n\n\t\tSetChildText(doc, stepElem, \"Note\", step.note);\n\n\t\tif (!step.targetMeshes.empty())\n\t\t\tSetChildText(doc, stepElem, \"TargetMeshes\", JoinStrings(step.targetMeshes, \", \"));\n\n\t\tSetChildBool(doc, stepElem, \"TargetRegex\", step.targetRegex, false);\n\n\t\tswitch (step.type) {\n\t\t\tcase AutomationStepType::ClearProject:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::LoadReference:\n\t\t\tcase AutomationStepType::AddProject:\n\t\t\t\tSetChildText(doc, stepElem, \"SourceFile\", step.refSourceFile);\n\t\t\t\tSetChildText(doc, stepElem, \"Set\", step.refSet);\n\t\t\t\tSetChildText(doc, stepElem, \"Shape\", step.refShape);\n\t\t\t\tSetChildBool(doc, stepElem, \"LoadAll\", step.refLoadAll, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"MergeSliders\", step.refMergeSliders, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"MergeZaps\", step.refMergeZaps, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"AppendNewSliders\", step.refAppendNewSliders, false);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ConformSliders:\n\t\t\t\tSetChildFloat(doc, stepElem, \"ProximityRadius\", step.conformProximityRadius, 10.0f);\n\t\t\t\tSetChildInt(doc, stepElem, \"MaxResults\", step.conformMaxResults, 10);\n\t\t\t\tSetChildBool(doc, stepElem, \"NoSqueeze\", step.conformNoSqueeze, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"SolidMode\", step.conformSolidMode, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"AxisX\", step.conformAxisX, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"AxisY\", step.conformAxisY, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"AxisZ\", step.conformAxisZ, true);\n\t\t\t\tif (!step.conformSliderNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"SliderNames\", JoinStrings(step.conformSliderNames, \", \"));\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::CopyBoneWeights:\n\t\t\t\tSetChildFloat(doc, stepElem, \"ProximityRadius\", step.weightProximityRadius, 10.0f);\n\t\t\t\tSetChildInt(doc, stepElem, \"MaxResults\", step.weightMaxResults, 10);\n\t\t\t\tif (!step.weightBoneList.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"BoneList\", JoinStrings(step.weightBoneList, \", \"));\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ImportSliderData:\n\t\t\t\tSetChildText(doc, stepElem, \"SliderDataFile\", step.sliderDataFile);\n\t\t\t\tSetChildBool(doc, stepElem, \"FromFolder\", step.sliderDataFromFolder, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"MergeSliders\", step.sliderMerge, false);\n\t\t\t\tif (!step.sliderNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"SliderNames\", JoinStrings(step.sliderNames, \", \"));\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ImportFile:\n\t\t\t\tSetChildText(doc, stepElem, \"FilePath\", step.importFilePath);\n\t\t\t\tSetChildBool(doc, stepElem, \"FromFolder\", step.importFromFolder, false);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::SetSliderValues:\n\t\t\t\tif (!step.setSliderNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"SliderNames\", JoinStrings(step.setSliderNames, \", \"));\n\t\t\t\tSetChildFloat(doc, stepElem, \"Value\", step.setSliderValue, 1.0f);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::DeleteShape:\n\t\t\t\t// No additional params (uses target meshes)\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::RenameShape:\n\t\t\t\tSetChildText(doc, stepElem, \"OldName\", step.renameOldName);\n\t\t\t\tSetChildText(doc, stepElem, \"NewName\", step.renameNewName);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::DeleteSlider:\n\t\t\t\tif (!step.deleteSliderNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"SliderName\", JoinStrings(step.deleteSliderNames, \", \"));\n\t\t\t\tif (step.deleteSliderRegex)\n\t\t\t\t\tSetChildText(doc, stepElem, \"Regex\", \"true\");\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::SetReferenceShape:\n\t\t\t\tSetChildText(doc, stepElem, \"ShapeName\", step.setRefShapeName);\n\t\t\t\tif (step.setRefUnset)\n\t\t\t\t\tSetChildText(doc, stepElem, \"UnsetReference\", \"true\");\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::RefineMesh:\n\t\t\tcase AutomationStepType::SetBaseShape:\n\t\t\tcase AutomationStepType::ClearReference:\n\t\t\tcase AutomationStepType::RemoveSkinning:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::TransformShape:\n\t\t\t\tSetChildFloat(doc, stepElem, \"MoveX\", step.moveX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"MoveY\", step.moveY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"MoveZ\", step.moveZ, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotateX\", step.rotateX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotateY\", step.rotateY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotateZ\", step.rotateZ, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"ScaleX\", step.scaleX, 1.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"ScaleY\", step.scaleY, 1.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"ScaleZ\", step.scaleZ, 1.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"InflateX\", step.inflateX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"InflateY\", step.inflateY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"InflateZ\", step.inflateZ, 0.0f);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::InvertUVs:\n\t\t\t\tSetChildBool(doc, stepElem, \"InvertU\", step.invertU, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"InvertV\", step.invertV, false);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::DeleteBones:\n\t\t\t\tif (!step.deleteBoneNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"BoneNames\", JoinStrings(step.deleteBoneNames, \", \"));\n\t\t\t\tSetChildBool(doc, stepElem, \"FromProject\", step.deleteBoneFromProject, true);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::AddCustomBone:\n\t\t\t\tSetChildText(doc, stepElem, \"BoneName\", step.addBoneName);\n\t\t\t\tSetChildText(doc, stepElem, \"ParentBone\", step.addBoneParent);\n\t\t\t\tSetChildFloat(doc, stepElem, \"TransX\", step.addBoneTransX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"TransY\", step.addBoneTransY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"TransZ\", step.addBoneTransZ, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotX\", step.addBoneRotX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotY\", step.addBoneRotY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotZ\", step.addBoneRotZ, 0.0f);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::EditBone:\n\t\t\t\tSetChildText(doc, stepElem, \"BoneName\", step.editBoneName);\n\t\t\t\tSetChildText(doc, stepElem, \"ParentBone\", step.editBoneParent);\n\t\t\t\tSetChildFloat(doc, stepElem, \"TransX\", step.editBoneTransX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"TransY\", step.editBoneTransY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"TransZ\", step.editBoneTransZ, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotX\", step.editBoneRotX, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotY\", step.editBoneRotY, 0.0f);\n\t\t\t\tSetChildFloat(doc, stepElem, \"RotZ\", step.editBoneRotZ, 0.0f);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ApplyPose:\n\t\t\t\tSetChildText(doc, stepElem, \"PoseName\", step.poseName);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::SaveProject:\n\t\t\t\tSetChildText(doc, stepElem, \"DisplayName\", step.saveName);\n\t\t\t\tSetChildText(doc, stepElem, \"OutputFileName\", step.saveOutputFileName);\n\t\t\t\tSetChildText(doc, stepElem, \"OutputDataPath\", step.saveOutputDataPath);\n\t\t\t\tSetChildText(doc, stepElem, \"SliderSetFile\", step.saveSliderSetFile);\n\t\t\t\tSetChildText(doc, stepElem, \"ShapeDataFolder\", step.saveShapeDataFolder);\n\t\t\t\tSetChildText(doc, stepElem, \"ShapeDataFile\", step.saveShapeDataFile);\n\t\t\t\tSetChildBool(doc, stepElem, \"GenWeights\", step.saveGenWeights, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"AutoCopyRef\", step.saveAutoCopyRef, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"CopyRefFromProject\", step.saveCopyRefFromProject, false);\n\t\t\t\tSetChildText(doc, stepElem, \"CopyRefShapeName\", step.saveCopyRefShapeName);\n\t\t\t\tSetChildBool(doc, stepElem, \"UseOriginal\", step.saveUseOriginal, false);\n\t\t\t\tSetChildText(doc, stepElem, \"ReplaceFrom\", step.saveReplaceFrom);\n\t\t\t\tSetChildText(doc, stepElem, \"ReplaceTo\", step.saveReplaceTo);\n\t\t\t\tSetChildText(doc, stepElem, \"Suffix\", step.saveSuffix);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ExportFile:\n\t\t\t\tSetChildText(doc, stepElem, \"FilePath\", step.exportFilePath);\n\t\t\t\tSetChildBool(doc, stepElem, \"WithRef\", step.exportWithRef, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"UseOriginalPath\", step.exportUseOriginalPath, false);\n\t\t\t\tSetChildText(doc, stepElem, \"Prefix\", step.exportPrefix);\n\t\t\t\tSetChildText(doc, stepElem, \"Suffix\", step.exportSuffix);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ResetTransforms:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::DuplicateShape:\n\t\t\t\tSetChildText(doc, stepElem, \"NewName\", step.dupNewName);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::MirrorShape:\n\t\t\t\tSetChildBool(doc, stepElem, \"MirrorX\", step.mirrorX, true);\n\t\t\t\tSetChildBool(doc, stepElem, \"MirrorY\", step.mirrorY, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"MirrorZ\", step.mirrorZ, false);\n\t\t\t\tSetChildBool(doc, stepElem, \"SwapBonesX\", step.mirrorSwapBonesX, false);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::ClearMask:\n\t\t\t\t// No additional params (uses target meshes)\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::LoadMask:\n\t\t\t\tSetChildText(doc, stepElem, \"MaskFile\", step.loadMaskFile);\n\t\t\t\tSetChildText(doc, stepElem, \"MaskName\", step.loadMaskName);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::SetSliderProperties:\n\t\t\t\tif (!step.sliderPropNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"SliderNames\", JoinStrings(step.sliderPropNames, \", \"));\n\t\t\t\tSetChildInt(doc, stepElem, \"Zap\", step.sliderPropZap, -1);\n\t\t\t\tSetChildInt(doc, stepElem, \"Hidden\", step.sliderPropHidden, -1);\n\t\t\t\tSetChildInt(doc, stepElem, \"DefaultLo\", step.sliderPropDefaultLo, -1);\n\t\t\t\tSetChildInt(doc, stepElem, \"DefaultHi\", step.sliderPropDefaultHi, -1);\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::RemoveUnusedNodes:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::FixClipping:\n\t\t\t\tSetChildInt(doc, stepElem, \"Mode\", step.fixClipMode, 0);\n\t\t\t\tSetChildFloat(doc, stepElem, \"Strength\", step.fixClipStrength, 0.5f);\n\t\t\t\tif (!step.fixClipSliderNames.empty())\n\t\t\t\t\tSetChildText(doc, stepElem, \"SliderNames\", JoinStrings(step.fixClipSliderNames, \", \"));\n\t\t\t\tbreak;\n\n\t\t\tcase AutomationStepType::FixBadBones:\n\t\t\t\t// No additional params\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tFILE* fp = nullptr;\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\tint err = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (err || !fp)\n\t\treturn 1;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp)\n\t\treturn 1;\n#endif\n\n\tXMLError error = doc.SaveFile(fp);\n\tfclose(fp);\n\n\treturn (error != XML_SUCCESS) ? 2 : 0;\n}\n\nstatic void SubstituteInString(std::string& str, const std::map<std::string, std::string>& variables) {\n\tif (str.empty())\n\t\treturn;\n\n\tfor (const auto& [key, value] : variables) {\n\t\tstd::string placeholder = \"{{\" + key + \"}}\";\n\t\tsize_t pos = 0;\n\t\twhile ((pos = str.find(placeholder, pos)) != std::string::npos) {\n\t\t\tstr.replace(pos, placeholder.length(), value);\n\t\t\tpos += value.length();\n\t\t}\n\t}\n}\n\nstatic void SubstituteInStringVector(std::vector<std::string>& vec, const std::map<std::string, std::string>& variables) {\n\tstd::vector<std::string> result;\n\tfor (auto& s : vec) {\n\t\tSubstituteInString(s, variables);\n\t\tauto parts = SplitCommaSeparated(s);\n\t\tfor (auto& p : parts)\n\t\t\tresult.push_back(std::move(p));\n\t}\n\tvec = std::move(result);\n}\n\nvoid AutomationScript::SubstitutePlaceholders(const std::map<std::string, std::string>& vars) {\n\tfor (auto& step : steps) {\n\t\tif (!step.active)\n\t\t\tcontinue;\n\n\t\tSubstituteInString(step.note, vars);\n\t\tSubstituteInStringVector(step.targetMeshes, vars);\n\n\t\tSubstituteInString(step.refSourceFile, vars);\n\t\tSubstituteInString(step.refSet, vars);\n\t\tSubstituteInString(step.refShape, vars);\n\t\tSubstituteInString(step.sliderDataFile, vars);\n\t\tSubstituteInString(step.importFilePath, vars);\n\t\tSubstituteInString(step.renameOldName, vars);\n\t\tSubstituteInString(step.renameNewName, vars);\n\t\tSubstituteInStringVector(step.deleteSliderNames, vars);\n\t\tSubstituteInString(step.setRefShapeName, vars);\n\t\tSubstituteInString(step.addBoneName, vars);\n\t\tSubstituteInString(step.addBoneParent, vars);\n\t\tSubstituteInString(step.editBoneName, vars);\n\t\tSubstituteInString(step.editBoneParent, vars);\n\t\tSubstituteInString(step.poseName, vars);\n\t\tSubstituteInStringVector(step.deleteBoneNames, vars);\n\t\tSubstituteInString(step.saveName, vars);\n\t\tSubstituteInString(step.saveOutputFileName, vars);\n\t\tSubstituteInString(step.saveOutputDataPath, vars);\n\t\tSubstituteInString(step.saveSliderSetFile, vars);\n\t\tSubstituteInString(step.saveShapeDataFolder, vars);\n\t\tSubstituteInString(step.saveShapeDataFile, vars);\n\t\tSubstituteInString(step.saveReplaceFrom, vars);\n\t\tSubstituteInString(step.saveReplaceTo, vars);\n\t\tSubstituteInString(step.saveSuffix, vars);\n\t\tSubstituteInString(step.saveCopyRefShapeName, vars);\n\n\t\tSubstituteInString(step.exportFilePath, vars);\n\t\tSubstituteInString(step.exportPrefix, vars);\n\t\tSubstituteInString(step.exportSuffix, vars);\n\t\tSubstituteInString(step.dupNewName, vars);\n\t\tSubstituteInString(step.loadMaskFile, vars);\n\t\tSubstituteInString(step.loadMaskName, vars);\n\n\t\tSubstituteInStringVector(step.setSliderNames, vars);\n\t\tSubstituteInStringVector(step.conformSliderNames, vars);\n\t\tSubstituteInStringVector(step.weightBoneList, vars);\n\t\tSubstituteInStringVector(step.sliderNames, vars);\n\t\tSubstituteInStringVector(step.sliderPropNames, vars);\n\t\tSubstituteInStringVector(step.fixClipSliderNames, vars);\n\t}\n}\n"
  },
  {
    "path": "src/components/Automation.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include <algorithm>\n#include <map>\n#include <regex>\n#include <string>\n#include <vector>\n\nenum class AutomationStepType {\n\tAddCustomBone,\n\tCopyBoneWeights,\n\tDeleteBones,\n\tEditBone,\n\tRemoveSkinning,\n\tExportFile,\n\tSaveProject,\n\tImportFile,\n\tImportSliderData,\n\tAddProject,\n\tClearProject,\n\tClearReference,\n\tLoadReference,\n\tSetBaseShape,\n\tSetReferenceShape,\n\tApplyPose,\n\tDeleteShape,\n\tDuplicateShape,\n\tFixBadBones,\n\tFixClipping,\n\tInvertUVs,\n\tMirrorShape,\n\tRefineMesh,\n\tRenameShape,\n\tResetTransforms,\n\tTransformShape,\n\tConformSliders,\n\tDeleteSlider,\n\tSetSliderValues,\n\tSetSliderProperties,\n\tClearMask,\n\tLoadMask,\n\tRemoveUnusedNodes\n};\n\nconstexpr int AutomationStepTypeCount = 33;\nstatic_assert(static_cast<int>(AutomationStepType::RemoveUnusedNodes) + 1 == AutomationStepTypeCount,\n\t\"AutomationStepTypeCount must match the number of enum values\");\n\nstd::string AutomationStepTypeToString(AutomationStepType type);\nAutomationStepType AutomationStepTypeFromString(const std::string& str);\n\ninline std::string JoinStrings(const std::vector<std::string>& vec, const std::string& sep) {\n\tstd::string result;\n\tfor (size_t i = 0; i < vec.size(); i++) {\n\t\tif (i > 0)\n\t\t\tresult += sep;\n\t\tresult += vec[i];\n\t}\n\treturn result;\n}\n\ninline std::vector<std::string> SplitCommaSeparated(const std::string& str) {\n\tstd::vector<std::string> result;\n\tif (str.empty())\n\t\treturn result;\n\n\tsize_t start = 0;\n\tsize_t end = str.find(',');\n\twhile (end != std::string::npos) {\n\t\tstd::string token = str.substr(start, end - start);\n\t\tsize_t first = token.find_first_not_of(\" \\t\");\n\t\tsize_t last = token.find_last_not_of(\" \\t\");\n\t\tif (first != std::string::npos)\n\t\t\tresult.push_back(token.substr(first, last - first + 1));\n\t\tstart = end + 1;\n\t\tend = str.find(',', start);\n\t}\n\tstd::string token = str.substr(start);\n\tsize_t first = token.find_first_not_of(\" \\t\");\n\tsize_t last = token.find_last_not_of(\" \\t\");\n\tif (first != std::string::npos)\n\t\tresult.push_back(token.substr(first, last - first + 1));\n\n\treturn result;\n}\n\ninline bool MatchesFilter(const std::string& name, const std::string& filter, bool useRegex, const std::regex& filterRegex) {\n\tif (filter.empty())\n\t\treturn true;\n\n\tif (useRegex)\n\t\treturn std::regex_search(name, filterRegex);\n\n\t// Substring match (case-insensitive)\n\tstd::string nameLower = name;\n\tstd::string filterLower = filter;\n\tstd::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower);\n\tstd::transform(filterLower.begin(), filterLower.end(), filterLower.begin(), ::tolower);\n\treturn nameLower.find(filterLower) != std::string::npos;\n}\n\nenum class AutomationBatchMode {\n\tNone,\n\tFolderScan,\n\tSliderSets\n};\n\nstd::string AutomationBatchModeToString(AutomationBatchMode mode);\nAutomationBatchMode AutomationBatchModeFromString(const std::string& str);\n\nstruct AutomationStep {\n\tbool active = true;\n\tstd::string note;\n\tAutomationStepType type = AutomationStepType::LoadReference;\n\tstd::vector<std::string> targetMeshes;\n\tbool targetRegex = false;\n\n\t// LoadReference / AddProject params\n\tstd::string refSourceFile;\n\tstd::string refSet;\n\tstd::string refShape;\n\tbool refLoadAll = true;\n\tbool refMergeSliders = true;\n\tbool refMergeZaps = true;\n\tbool refAppendNewSliders = true;\n\n\t// SetSliderValues params\n\tstd::vector<std::string> setSliderNames;\n\tfloat setSliderValue = 1.0f;\n\n\t// ConformSliders params\n\tfloat conformProximityRadius = 10.0f;\n\tint conformMaxResults = 10;\n\tbool conformNoSqueeze = false;\n\tbool conformSolidMode = false;\n\tbool conformAxisX = true;\n\tbool conformAxisY = true;\n\tbool conformAxisZ = true;\n\tstd::vector<std::string> conformSliderNames;\n\n\t// CopyBoneWeights params\n\tfloat weightProximityRadius = 10.0f;\n\tint weightMaxResults = 10;\n\tstd::vector<std::string> weightBoneList;\n\n\t// ImportSliderData params\n\tstd::string sliderDataFile;\n\tbool sliderDataFromFolder = false;\n\tbool sliderMerge = false;\n\tstd::vector<std::string> sliderNames;\n\n\t// ImportFile params\n\tstd::string importFilePath;\n\tbool importFromFolder = false;\n\n\t// TransformShape params\n\tfloat moveX = 0.0f, moveY = 0.0f, moveZ = 0.0f;\n\tfloat rotateX = 0.0f, rotateY = 0.0f, rotateZ = 0.0f;\n\tfloat scaleX = 1.0f, scaleY = 1.0f, scaleZ = 1.0f;\n\tfloat inflateX = 0.0f, inflateY = 0.0f, inflateZ = 0.0f;\n\n\t// InvertUVs params\n\tbool invertU = false;\n\tbool invertV = false;\n\n\t// DeleteBones params\n\tstd::vector<std::string> deleteBoneNames;\n\tbool deleteBoneFromProject = true;\n\n\t// AddCustomBone params\n\tstd::string addBoneName;\n\tstd::string addBoneParent;\n\tfloat addBoneTransX = 0.0f, addBoneTransY = 0.0f, addBoneTransZ = 0.0f;\n\tfloat addBoneRotX = 0.0f, addBoneRotY = 0.0f, addBoneRotZ = 0.0f;\n\n\t// EditBone params\n\tstd::string editBoneName;\n\tstd::string editBoneParent;\n\tfloat editBoneTransX = 0.0f, editBoneTransY = 0.0f, editBoneTransZ = 0.0f;\n\tfloat editBoneRotX = 0.0f, editBoneRotY = 0.0f, editBoneRotZ = 0.0f;\n\n\t// ApplyPose params\n\tstd::string poseName;\n\n\t// RenameShape params\n\tstd::string renameOldName;\n\tstd::string renameNewName;\n\n\t// DeleteSlider params\n\tstd::vector<std::string> deleteSliderNames;\n\tbool deleteSliderRegex = false;\n\n\t// SetReferenceShape params\n\tstd::string setRefShapeName;\n\tbool setRefUnset = false;\n\n\t// SaveProject params\n\tstd::string saveName;\n\tstd::string saveOutputFileName;\n\tstd::string saveOutputDataPath;\n\tstd::string saveSliderSetFile;\n\tstd::string saveShapeDataFolder;\n\tstd::string saveShapeDataFile;\n\tbool saveGenWeights = true;\n\tbool saveAutoCopyRef = true;\n\tbool saveCopyRefFromProject = false; // Copy reference based on loaded project\n\tstd::string saveCopyRefShapeName; // Only treat this shape name as reference\n\tbool saveUseOriginal = false; // Use original project from batch mode\n\tstd::string saveReplaceFrom; // Batch: replace this word in original fields\n\tstd::string saveReplaceTo;   // Batch: replace with this word\n\tstd::string saveSuffix;      // Batch: append suffix to original fields\n\n\t// DuplicateShape params\n\tstd::string dupNewName;\n\n\t// MirrorShape params\n\tbool mirrorX = true;\n\tbool mirrorY = false;\n\tbool mirrorZ = false;\n\tbool mirrorSwapBonesX = false;\n\n\t// ExportFile params\n\tstd::string exportFilePath;\n\tbool exportWithRef = true;\n\tbool exportUseOriginalPath = false; // Use original file path from batch mode\n\tstd::string exportPrefix;\n\tstd::string exportSuffix;\n\n\t// SetSliderProperties params\n\tstd::vector<std::string> sliderPropNames;\n\tint sliderPropZap = -1;       // -1 = no change, 0 = false, 1 = true\n\tint sliderPropHidden = -1;    // -1 = no change, 0 = false, 1 = true\n\tint sliderPropDefaultLo = -1; // -1 = no change, 0-100 = set value\n\tint sliderPropDefaultHi = -1; // -1 = no change, 0-100 = set value\n\n\t// LoadMask params\n\tstd::string loadMaskFile;\n\tstd::string loadMaskName;\n\n\t// FixClipping params\n\tint fixClipMode = 0;          // 0 = Shapes, 1 = Sliders\n\tfloat fixClipStrength = 0.5f;  // 0.0 - 1.0\n\tstd::vector<std::string> fixClipSliderNames;\n};\n\nclass AutomationScript {\n\tstd::vector<AutomationStep> steps;\n\tstd::map<std::string, std::string> variables;\n\n\t// Batch settings\n\tAutomationBatchMode batchMode = AutomationBatchMode::None;\n\tstd::string batchFolder;\n\tstd::string batchExtension;\n\tbool batchSubdirectories = false;\n\tstd::string batchFileFilter;\n\tbool batchFileFilterRegex = false;\n\n\t// SliderSet batch settings\n\tstd::string batchSliderSetFilter;\n\tbool batchSliderSetFilterRegex = false;\n\npublic:\n\tAutomationScript() {}\n\n\tint Load(const std::string& fileName);\n\tint Save(const std::string& fileName);\n\n\tstd::vector<AutomationStep>& GetSteps() { return steps; }\n\tconst std::vector<AutomationStep>& GetSteps() const { return steps; }\n\n\tstd::map<std::string, std::string>& GetVariables() { return variables; }\n\tconst std::map<std::string, std::string>& GetVariables() const { return variables; }\n\n\tAutomationBatchMode GetBatchMode() const { return batchMode; }\n\tvoid SetBatchMode(AutomationBatchMode mode) { batchMode = mode; }\n\n\tconst std::string& GetBatchFolder() const { return batchFolder; }\n\tvoid SetBatchFolder(const std::string& folder) { batchFolder = folder; }\n\n\tconst std::string& GetBatchExtension() const { return batchExtension; }\n\tvoid SetBatchExtension(const std::string& ext) { batchExtension = ext; }\n\n\tbool GetBatchSubdirectories() const { return batchSubdirectories; }\n\tvoid SetBatchSubdirectories(bool v) { batchSubdirectories = v; }\n\n\tconst std::string& GetBatchFileFilter() const { return batchFileFilter; }\n\tvoid SetBatchFileFilter(const std::string& f) { batchFileFilter = f; }\n\n\tbool GetBatchFileFilterRegex() const { return batchFileFilterRegex; }\n\tvoid SetBatchFileFilterRegex(bool v) { batchFileFilterRegex = v; }\n\n\tconst std::string& GetBatchSliderSetFilter() const { return batchSliderSetFilter; }\n\tvoid SetBatchSliderSetFilter(const std::string& f) { batchSliderSetFilter = f; }\n\n\tbool GetBatchSliderSetFilterRegex() const { return batchSliderSetFilterRegex; }\n\tvoid SetBatchSliderSetFilterRegex(bool v) { batchSliderSetFilterRegex = v; }\n\n\tvoid AddStep(const AutomationStep& step) { steps.push_back(step); }\n\n\tvoid InsertStep(size_t index, const AutomationStep& step) {\n\t\tif (index <= steps.size())\n\t\t\tsteps.insert(steps.begin() + index, step);\n\t\telse\n\t\t\tsteps.push_back(step);\n\t}\n\n\tvoid RemoveStep(size_t index) {\n\t\tif (index < steps.size())\n\t\t\tsteps.erase(steps.begin() + index);\n\t}\n\n\tvoid MoveStepUp(size_t index) {\n\t\tif (index > 0 && index < steps.size())\n\t\t\tstd::swap(steps[index], steps[index - 1]);\n\t}\n\n\tvoid MoveStepDown(size_t index) {\n\t\tif (index + 1 < steps.size())\n\t\t\tstd::swap(steps[index], steps[index + 1]);\n\t}\n\n\tvoid Clear() { steps.clear(); }\n\n\t// Substitute placeholders like {{KEY}} in all string fields\n\tvoid SubstitutePlaceholders(const std::map<std::string, std::string>& vars);\n};\n"
  },
  {
    "path": "src/components/Automorph.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"Automorph.h\"\n#include \"Anim.h\"\n\nusing namespace nifly;\n\nAutomorph::Automorph() {}\n\nAutomorph::~Automorph() {\n\tClearSourceShapes();\n}\n\nvoid Automorph::ClearSourceShapes() {\n\tfor (auto& shapes : sourceShapes)\n\t\tdelete shapes.second;\n\n\tsourceShapes.clear();\n}\n\nvoid Automorph::RenameResultDiffData(const std::string& shape, const std::string& oldName, const std::string& newName) {\n\tstd::string setName = ResultDataName(shape, oldName);\n\tstd::string newSetName = shape + newName;\n\n\tresultDiffData.RenameSet(setName, newSetName);\n\ttargetSliderDataNames.erase(setName);\n}\n\nvoid Automorph::RenameShape(const std::string& oldShapeName, const std::string& newShapeName) {\n\tif (sourceShapes.find(oldShapeName) != sourceShapes.end()) {\n\t\tsourceShapes[newShapeName] = sourceShapes[oldShapeName];\n\t\tsourceShapes.erase(oldShapeName);\n\t}\n\n\tstd::vector<std::string> oldKeys;\n\tfor (auto& tsdn : targetSliderDataNames) {\n\t\tbool found = false;\n\t\tsize_t p = tsdn.second.find(oldShapeName);\n\t\tif (p == 0)\n\t\t\tfound = true;\n\n\t\tp = tsdn.first.find(oldShapeName);\n\t\tif (p == 0)\n\t\t\tfound = true;\n\n\t\tif (found)\n\t\t\toldKeys.push_back(tsdn.first);\n\t}\n\n\tfor (size_t i = 0; i < oldKeys.size(); i++)\n\t\ttargetSliderDataNames.erase(oldKeys[i]);\n}\n\nvoid Automorph::RenameDataTarget(const std::string& oldTarget, const std::string& newTarget) {\n\tresultDiffData.RenameDataTarget(oldTarget, newTarget);\n}\n\nvoid Automorph::RenameSet(const std::string& oldName, const std::string& newName) {\n\tresultDiffData.RenameSet(oldName, newName);\n}\n\nvoid Automorph::CopySet(const std::string& oldName, const std::string& newName, const std::string& newTargetName) {\n\tresultDiffData.CopySet(oldName, newName, newTargetName);\n}\n\nvoid Automorph::CopyShape(const std::string& srcShapeName, const std::string& destShapeName) {\n\tstd::vector<std::string> newVals;\n\tstd::vector<std::string> oldKeys;\n\tstd::vector<std::string> newKeys;\n\n\tfor (auto& tsdn : targetSliderDataNames) {\n\t\tstd::string newDN = tsdn.second;\n\t\tstd::string newKey = tsdn.first;\n\n\t\tbool found = false;\n\t\tsize_t p = newDN.find(srcShapeName);\n\t\tif (p == 0) {\n\t\t\tnewDN = newDN.substr(srcShapeName.length());\n\t\t\tnewDN = destShapeName + newDN;\n\t\t\tfound = true;\n\t\t}\n\n\t\tp = newKey.find(srcShapeName);\n\t\tif (p == 0) {\n\t\t\tnewKey = newKey.substr(srcShapeName.length());\n\t\t\tnewKey = destShapeName + newKey;\n\t\t\tfound = true;\n\t\t}\n\n\t\tif (found) {\n\t\t\toldKeys.push_back(tsdn.first);\n\t\t\tnewKeys.push_back(newKey);\n\t\t\tnewVals.push_back(newDN);\n\t\t}\n\t}\n\n\tfor (size_t i = 0; i < oldKeys.size(); i++)\n\t\ttargetSliderDataNames[newKeys[i]] = newVals[i];\n}\n\nstd::string Automorph::GetDataTargetName(const std::string& targetName, const std::string& dataNameSuffix) {\n\treturn resultDiffData.GetDataTargetName(targetName, dataNameSuffix);\n}\n\nvoid Automorph::SetRef(NifFile& ref, NiShape* refShape, const AnimInfo* workAnim) {\n\tmorphRef = std::make_unique<Mesh>();\n\tMeshFromNifShape(morphRef.get(), ref, refShape, workAnim);\n\n\trefTree = std::make_unique<kd_tree<uint16_t>>(morphRef->verts.get(), static_cast<uint16_t>(morphRef->nVerts));\n}\n\nvoid Automorph::LinkRefDiffData(DiffDataSets* diffData) {\n\tsrcDiffData = diffData;\n}\n\nvoid Automorph::UnlinkRefDiffData() {\n\tsrcDiffData = &__srcDiffData;\n}\n\nbool Automorph::ApplyDiffToVerts(const std::string& sliderName, const std::string& shapeTargetName, std::vector<Vector3>* inOutResult, float strength) {\n\treturn srcDiffData->ApplyDiff(sliderName, shapeTargetName, strength, inOutResult);\n}\n\nbool Automorph::ApplyResultToVerts(const std::string& sliderName, const std::string& shapeTargetName, std::vector<Vector3>* inOutResult, float strength) {\n\tstd::string setname = ResultDataName(shapeTargetName, sliderName);\n\n\treturn resultDiffData.ApplyDiff(setname, shapeTargetName, strength, inOutResult);\n}\n\nbool Automorph::ApplyResultToUVs(const std::string& sliderName, const std::string& shapeTargetName, std::vector<Vector2>* inOutResult, float strength) {\n\tstd::string setname = ResultDataName(shapeTargetName, sliderName);\n\n\treturn resultDiffData.ApplyUVDiff(setname, shapeTargetName, strength, inOutResult);\n}\n\nvoid Automorph::SourceShapesFromNif(NifFile& baseNif, const AnimInfo* workAnim) {\n\tClearSourceShapes();\n\n\tauto shapes = baseNif.GetShapes();\n\tfor (auto& s : shapes) {\n\t\tMesh* m = new Mesh();\n\t\tMeshFromNifShape(m, baseNif, s, workAnim);\n\t\tsourceShapes[s->name.get()] = m;\n\t}\n}\n\nvoid Automorph::UpdateMeshFromNif(NifFile& baseNif, const std::string& shapeName) {\n\tif (sourceShapes.find(shapeName) == sourceShapes.end())\n\t\treturn;\n\n\tMesh* m = sourceShapes[shapeName];\n\tauto shape = baseNif.FindBlockByName<NiShape>(shapeName);\n\n\tstd::vector<Vector3> upVerts;\n\tbaseNif.GetVertsForShape(shape, upVerts);\n\n\tint numUpVerts = upVerts.size();\n\tif (m->nVerts != numUpVerts)\n\t\treturn;\n\n\tfor (int i = 0; i < m->nVerts; i++)\n\t\tm->verts[i] = upVerts[i];\n}\n\nvoid Automorph::CopyMeshMask(Mesh* m, const std::string& shapeName) {\n\tMesh* dm = sourceShapes[shapeName];\n\tif (dm->nVerts != m->nVerts)\n\t\treturn;\n\n\tif (!m->mask)\n\t\treturn;\n\n\tif (!dm->mask)\n\t\tdm->mask = std::make_unique<float[]>(dm->nVerts);\n\n\tfor (int i = 0; i < dm->nVerts; i++)\n\t\tdm->mask[i] = m->mask[i];\n}\n\nvoid Automorph::MeshFromNifShape(Mesh* m, NifFile& ref, NiShape* shape, const AnimInfo* workAnim) {\n\tstd::vector<Vector3> nifVerts;\n\tref.GetVertsForShape(shape, nifVerts);\n\n\tm->shapeName = shape->name.get();\n\n\tm->SetXformMeshToModel(workAnim->GetTransformShapeToGlobal(shape));\n\n\tm->nVerts = nifVerts.size();\n\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\n\t// Load verts. No CS transformation is done (in contrast to the very similar code in GLSurface).\n\tfor (int i = 0; i < m->nVerts; i++)\n\t\tm->verts[i] = m->TransformPosMeshToModel(nifVerts[i]);\n}\n\nvoid Automorph::DeleteVerts(const std::string& shapeName, const std::vector<uint16_t>& indices) {\n\tresultDiffData.DeleteVerts(shapeName, indices);\n}\n\nvoid Automorph::InsertVertexIndices(const std::string& target, const std::vector<uint16_t>& indices) {\n\tresultDiffData.InsertVertexIndices(target, indices);\n}\n\nvoid Automorph::ClearProximityCache() {\n\tprox_cache.clear();\n}\n\nvoid Automorph::BuildProximityCache(const std::string& shapeName, float proximityRadius, const std::set<uint16_t>* maskIndices) {\n\tif (sourceShapes.find(shapeName) == sourceShapes.end())\n\t\treturn;\n\n\tMesh* m = sourceShapes[shapeName];\n\tuint16_t maxCount = 0;\n\tuint16_t minCount = std::numeric_limits<uint16_t>::max();\n\n\tfor (int i = 0; i < m->nVerts; i++) {\n\t\tuint16_t resultCount = refTree->kd_nn(&m->verts[i], proximityRadius);\n\t\tif (resultCount < minCount)\n\t\t\tminCount = resultCount;\n\t\tif (resultCount > maxCount)\n\t\t\tmaxCount = resultCount;\n\n\t\tstd::vector<kd_query_result<uint16_t>> indexResults;\n\t\tfor (uint16_t id = 0; id < resultCount; id++) {\n\t\t\tauto& result = refTree->queryResult[id];\n\n\t\t\tif (maskIndices) {\n\t\t\t\tif (maskIndices->find(result.vertex_index) != maskIndices->end())\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tindexResults.push_back(std::move(result));\n\t\t}\n\n\t\tprox_cache[i] = std::move(indexResults);\n\t}\n}\n\nvoid Automorph::GetRawResultDiff(const std::string& shapeName, const std::string& sliderName, std::unordered_map<uint16_t, Vector3>& outDiff) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\tif (!resultDiffData.TargetMatch(setName, shapeName))\n\t\treturn;\n\n\toutDiff = *resultDiffData.GetDiffSet(setName);\n}\n\nint Automorph::GetResultDiffSize(const std::string& shapeName, const std::string& sliderName) {\n\tstd::string setname = ResultDataName(shapeName, sliderName);\n\tif (!resultDiffData.TargetMatch(setname, shapeName))\n\t\treturn 0;\n\n\treturn resultDiffData.GetDiffSet(setname)->size();\n}\n\nstd::unordered_map<uint16_t, Vector3>* Automorph::GetDiffSet(const std::string& targetDataName) {\n\treturn resultDiffData.GetDiffSet(targetDataName);\n}\n\nvoid Automorph::ScaleResultDiff(const std::string& shapeName, const std::string& sliderName, float scaleValue) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\tresultDiffData.ScaleDiff(setName, shapeName, scaleValue);\n}\n\nvoid Automorph::LoadResultDiffs(SliderSet& fromSet) {\n\tfromSet.LoadSetDiffData(resultDiffData);\n\ttargetSliderDataNames.clear();\n\tfor (size_t i = 0; i < fromSet.size(); i++)\n\t\tfor (auto& df : fromSet[i].dataFiles)\n\t\t\tif (df.dataName != (df.targetName + fromSet[i].name))\n\t\t\t\tSetResultDataName(df.targetName, fromSet[i].name, df.dataName);\n}\n\nvoid Automorph::MergeResultDiffs(\n\tSliderSet& fromSet, SliderSet& mergeSet, DiffDataSets& baseDiffData, const std::string& baseShape, const bool newDataLocal, const bool appendNewSliders) {\n\tfromSet.Merge(mergeSet, resultDiffData, baseDiffData, baseShape, newDataLocal, appendNewSliders);\n\tfor (size_t i = 0; i < fromSet.size(); i++)\n\t\tfor (auto& df : fromSet[i].dataFiles)\n\t\t\tif (df.dataName != (df.targetName + fromSet[i].name))\n\t\t\t\tSetResultDataName(df.targetName, fromSet[i].name, df.dataName);\n}\n\nvoid Automorph::ClearResultSet(const std::string& sliderName) {\n\tresultDiffData.ClearSet(sliderName);\n}\n\nvoid Automorph::SaveResultDiff(const std::string& shapeName, const std::string& sliderName, const std::string& fileName) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\tresultDiffData.SaveSet(setName, shapeName, fileName);\n}\n\nvoid Automorph::AddEmptySet(const std::string& shapeName, const std::string& sliderName) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\n\tif (!resultDiffData.TargetMatch(setName, shapeName))\n\t\tresultDiffData.AddEmptySet(setName, shapeName);\n}\n\nvoid Automorph::SetResultDiff(const std::string& shapeName, const std::string& sliderName, const TargetDataDiffs& diff) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\n\tif (!resultDiffData.TargetMatch(setName, shapeName))\n\t\tresultDiffData.AddEmptySet(setName, shapeName);\n\n\tfor (auto& i : diff)\n\t\tresultDiffData.UpdateDiff(setName, shapeName, i.first, i.second);\n}\n\nvoid Automorph::UpdateResultDiff(const std::string& shapeName, const std::string& sliderName, const TargetDataDiffs& diff) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\n\tif (!resultDiffData.TargetMatch(setName, shapeName))\n\t\tresultDiffData.AddEmptySet(setName, shapeName);\n\n\tfor (auto& i : diff) {\n\t\tVector3 diffscale = Mesh::TransformDiffMeshToNif(i.second);\n\t\tresultDiffData.SumDiff(setName, shapeName, i.first, diffscale);\n\t}\n}\n\nvoid Automorph::UpdateRefDiff(const std::string& shapeName, const std::string& sliderName, const TargetDataDiffs& diff) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\n\tif (!srcDiffData->TargetMatch(setName, shapeName))\n\t\tsrcDiffData->AddEmptySet(setName, shapeName);\n\n\tfor (auto& i : diff) {\n\t\tVector3 diffscale = Mesh::TransformDiffMeshToNif(i.second);\n\t\tsrcDiffData->SumDiff(setName, shapeName, i.first, diffscale);\n\t}\n}\n\nvoid Automorph::EmptyResultDiff(const std::string& shapeName, const std::string& sliderName) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\tresultDiffData.EmptySet(setName, shapeName);\n}\n\nvoid Automorph::ZeroVertDiff(const std::string& shapeName, const std::string& sliderName, std::vector<uint16_t>* vertSet, std::unordered_map<uint16_t, float>* mask) {\n\tstd::string setName = ResultDataName(shapeName, sliderName);\n\tresultDiffData.ZeroVertDiff(setName, shapeName, vertSet, mask);\n}\n\nvoid Automorph::SetResultDataName(const std::string& shapeName, const std::string& sliderName, const std::string& dataName) {\n\ttargetSliderDataNames[shapeName + sliderName] = dataName;\n}\n\nstd::string Automorph::ResultDataName(const std::string& shapeName, const std::string& sliderName) {\n\tstd::string search = shapeName + sliderName;\n\tauto f = targetSliderDataNames.find(search);\n\tif (f == targetSliderDataNames.end())\n\t\treturn search;\n\n\treturn f->second;\n}\n\nvoid Automorph::GenerateResultDiff(\n\tconst std::string& shapeName, const std::string& sliderName, const std::string& refDataName, bool transformResults, int maxResults, bool noSqueeze, bool solidMode, bool axisX, bool axisY, bool axisZ) {\n\tif (sourceShapes.find(shapeName) == sourceShapes.end())\n\t\treturn;\n\n\tstd::unordered_map<uint16_t, Vector3>* diffData = srcDiffData->GetDiffSet(refDataName);\n\tif (!diffData)\n\t\treturn;\n\n\tMesh* m = sourceShapes[shapeName];\n\tstd::string dataName = shapeName + sliderName;\n\n\tMatTransform transform;\n\tif (transformResults) {\n\t\ttransform = m->xformModelToMesh.ComposeTransforms(morphRef->xformMeshToModel);\n\t\ttransformResults = !transform.IsNearlyEqualTo(MatTransform());\n\t}\n\n\tif (resultDiffData.TargetMatch(dataName, shapeName)) {\n\t\tif (m->mask)\n\t\t\tresultDiffData.ZeroVertDiff(dataName, m->nVerts, m->mask.get());\n\t\telse\n\t\t\tresultDiffData.ClearSet(dataName);\n\t}\n\n\tresultDiffData.AddEmptySet(dataName, shapeName);\n\tauto resultDiffSet = resultDiffData.GetDiffSet(dataName);\n\n\tstd::vector<Vector3> totalMoveList;\n\tstd::vector<float> invDist;\n\tstd::vector<Vector3> effectVector;\n\n\tfor (int i = 0; i < m->nVerts; i++) {\n\t\tstd::vector<kd_query_result<uint16_t>>* vertProx = &prox_cache[i];\n\t\tint nValues = vertProx->size();\n\t\tif (nValues > maxResults)\n\t\t\tnValues = maxResults;\n\n\t\tint nearMoves = 0;\n\t\tfloat invDistTotal = 0.0;\n\n\t\tfloat weight;\n\t\tVector3 totalMove;\n\n\t\tinvDist.assign(nValues, 0.0f);\n\t\teffectVector.assign(nValues, Vector3());\n\n\t\tfor (int j = 0; j < nValues; j++) {\n\t\t\tuint16_t vi = (*vertProx)[j].vertex_index;\n\t\t\tconst Vector3* v = (*vertProx)[j].v;\n\t\t\tauto diffItem = diffData->find(vi);\n\t\t\tif (diffItem != diffData->end()) {\n\t\t\t\tweight = (*vertProx)[j].distance; // \"weight\" is just a placeholder here...\n\t\t\t\tif (weight == 0.0f)\n\t\t\t\t\tinvDist[nearMoves] = 1000.0f; // Exact match, choose big nearness weight.\n\t\t\t\telse\n\t\t\t\t\tinvDist[nearMoves] = 1.0f / weight;\n\n\t\t\t\tinvDistTotal += invDist[nearMoves];\n\n\t\t\t\tauto& effect = effectVector[nearMoves];\n\t\t\t\tif (axisX) {\n\t\t\t\t\tif (!noSqueeze || (noSqueeze && ((diffItem->second.x > 0.0f && v->x > 0.0f) || (diffItem->second.x < 0.0f && v->x < 0.0f))))\n\t\t\t\t\t\teffect.x = diffItem->second.x;\n\t\t\t\t}\n\t\t\t\tif (axisY)\n\t\t\t\t\teffect.y = diffItem->second.y;\n\t\t\t\tif (axisZ)\n\t\t\t\t\teffect.z = diffItem->second.z;\n\n\t\t\t\tnearMoves++;\n\t\t\t}\n\t\t\telse if (j == 0) {\n\t\t\t\t// Closest proximity vert has zero movement\n\t\t\t\tnearMoves = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (nearMoves == 0)\n\t\t\tcontinue;\n\n\t\ttotalMove.Zero();\n\t\tfor (int j = 0; j < nearMoves; j++) {\n\t\t\tweight = invDist[j] / invDistTotal;\n\t\t\ttotalMove += (effectVector[j] * weight);\n\t\t}\n\n\t\tif (m->mask && bEnableMask)\n\t\t\ttotalMove *= (1.0f - m->mask[i]);\n\n\t\tif (totalMove.IsZero(true))\n\t\t\tcontinue;\n\n\t\tif (!solidMode) {\n\t\t\tif (transformResults)\n\t\t\t\ttotalMove = transform.ApplyTransformToDiff(totalMove);\n\t\t\t(*resultDiffSet)[i] += totalMove;\n\t\t}\n\t\telse {\n\t\t\ttotalMoveList.reserve(m->nVerts);\n\t\t\ttotalMoveList.push_back(totalMove);\n\t\t}\n\t}\n\n\tif (solidMode && !totalMoveList.empty()) {\n\t\tVector3 totalSolidMove;\n\t\tVector3 totalSolidMoveNeg;\n\n\t\tfor (const auto& mv : totalMoveList) {\n\t\t\tif (mv.x >= 0.0f) {\n\t\t\t\tif (mv.x > totalSolidMove.x)\n\t\t\t\t\ttotalSolidMove.x = mv.x;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (mv.x < totalSolidMoveNeg.x)\n\t\t\t\t\ttotalSolidMoveNeg.x = mv.x;\n\t\t\t}\n\n\t\t\tif (mv.y >= 0.0f) {\n\t\t\t\tif (mv.y > totalSolidMove.y)\n\t\t\t\t\ttotalSolidMove.y = mv.y;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (mv.y < totalSolidMoveNeg.y)\n\t\t\t\t\ttotalSolidMoveNeg.y = mv.y;\n\t\t\t}\n\n\t\t\tif (mv.z >= 0.0f) {\n\t\t\t\tif (mv.z > totalSolidMove.z)\n\t\t\t\t\ttotalSolidMove.z = mv.z;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (mv.z < totalSolidMoveNeg.z)\n\t\t\t\t\ttotalSolidMoveNeg.z = mv.z;\n\t\t\t}\n\t\t}\n\n\t\ttotalSolidMove += totalSolidMoveNeg;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tVector3 totalMove = totalSolidMove;\n\n\t\t\tif (m->mask && bEnableMask)\n\t\t\t\ttotalMove *= (1.0f - m->mask[i]);\n\n\t\t\tif (totalMove.IsZero(true))\n\t\t\t\tcontinue;\n\n\t\t\tif (transformResults)\n\t\t\t\ttotalMove = transform.ApplyTransformToDiff(totalMove);\n\t\t\t(*resultDiffSet)[i] += totalMove;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/components/Automorph.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"KDMatcher.hpp\"\n#include \"Mesh.h\"\n#include \"NifFile.hpp\"\n#include \"SliderSet.h\"\n\nclass AnimInfo;\n\nclass Automorph {\n\tstd::unique_ptr<nifly::kd_tree<uint16_t>> refTree;\n\tstd::map<std::string, Mesh*> sourceShapes;\n\t// Class - to prevent AutoMorph from deleting it. Golly, smart pointers would be nice.\n\tstd::map<int, std::vector<nifly::kd_query_result<uint16_t>>> prox_cache;\n\tDiffDataSets __srcDiffData;\t\t\t // Unternally loaded and stored diff data.diffs loaded from existing reference .bsd files.\n\tDiffDataSets* srcDiffData = nullptr; // Either __srcDiffData or an external linked data set.\n\tDiffDataSets resultDiffData;\t\t // Diffs calculated by AutoMorph.\n\n\tbool bEnableMask = true; // Use red component of mesh vertex color as a mask for morphing.\n\n\t// A translation between shapetarget + slidername and the data name for the result diff data set.\n\t// This only has values when a sliderset is loaded from disk and a slider's data name for a target\n\t// doesn't match the format targetname + slidername.\n\tstd::unordered_map<std::string, std::string> targetSliderDataNames;\n\npublic:\n\tstd::unique_ptr<Mesh> morphRef;\n\n\tAutomorph();\n\t~Automorph();\n\n\tvoid ClearResultDiff() { resultDiffData.Clear(); }\n\tvoid ClearSourceShapes();\n\n\tvoid RenameResultDiffData(const std::string& shape, const std::string& oldName, const std::string& newName);\n\tvoid RenameShape(const std::string& oldShapeName, const std::string& newShapeName);\n\tvoid RenameSet(const std::string& oldName, const std::string& newName);\n\tvoid RenameDataTarget(const std::string& oldTarget, const std::string& newTarget);\n\tvoid CopySet(const std::string& oldName, const std::string& newName, const std::string& newTargetName);\n\tvoid CopyShape(const std::string& srcShapeName, const std::string& destShapeName);\n\tstd::string GetDataTargetName(const std::string& targetName, const std::string& dataNameSuffix);\n\n\tvoid EnableMasking(bool enable = true) { bEnableMask = enable; }\n\n\tvoid SetRef(nifly::NifFile& Ref, nifly::NiShape* refShape, const AnimInfo* workAnim);\n\n\tvoid LinkRefDiffData(DiffDataSets* diffData);\n\tvoid UnlinkRefDiffData();\n\n\tbool ApplyDiffToVerts(const std::string& sliderName, const std::string& shapeTargetName, std::vector<nifly::Vector3>* inOutResult, float strength = 1.0f);\n\tbool ApplyResultToVerts(const std::string& sliderName, const std::string& shapeTargetName, std::vector<nifly::Vector3>* inOutResult, float strength = 1.0f);\n\tbool ApplyResultToUVs(const std::string& sliderName, const std::string& shapeTargetName, std::vector<nifly::Vector2>* inOutResult, float strength = 1.0f);\n\n\tvoid SourceShapesFromNif(nifly::NifFile& baseNif, const AnimInfo* workAnim);\n\tvoid UpdateMeshFromNif(nifly::NifFile& baseNif, const std::string& shapeName);\n\tvoid CopyMeshMask(Mesh* m, const std::string& shapeName);\n\n\tvoid MeshFromNifShape(Mesh* m, nifly::NifFile& ref, nifly::NiShape* shape, const AnimInfo* workAnim);\n\t// indices must be in ascending order.\n\tvoid DeleteVerts(const std::string& shapeName, const std::vector<uint16_t>& indices);\n\t// indices must be in ascending order.\n\tvoid InsertVertexIndices(const std::string& target, const std::vector<uint16_t>& indices);\n\n\tvoid ClearProximityCache();\n\tvoid BuildProximityCache(const std::string& shapeName, float proximityRadius = 10.0f, const std::set<uint16_t>* maskIndices = nullptr);\n\n\t// shapeName = name of the mesh to morph (eg \"IronArmor\") also known as target name.\n\t// sliderName = name of the morph to apply (eg \"BreastsSH\").\n\tvoid GenerateResultDiff(const std::string& shapeName,\n\t\t\t\t\t\t\tconst std::string& sliderName,\n\t\t\t\t\t\t\tconst std::string& refDataName,\n\t\t\t\t\t\t\tbool transformResults,\n\t\t\t\t\t\t\tint maxResults = 10,\n\t\t\t\t\t\t\tbool noSqueeze = false,\n\t\t\t\t\t\t\tbool solidMode = false,\n\t\t\t\t\t\t\tbool axisX = true,\n\t\t\t\t\t\t\tbool axisY = true,\n\t\t\t\t\t\t\tbool axisZ = true);\n\n\tvoid SetResultDataName(const std::string& shapeName, const std::string& sliderName, const std::string& dataName);\n\tstd::string ResultDataName(const std::string& shapeName, const std::string& sliderName);\n\n\tvoid GetRawResultDiff(const std::string& shapeName, const std::string& sliderName, std::unordered_map<uint16_t, nifly::Vector3>& outDiff);\n\tint GetResultDiffSize(const std::string& shapeName, const std::string& sliderName);\n\tstd::unordered_map<uint16_t, nifly::Vector3>* GetDiffSet(const std::string& targetDataName);\n\n\tvoid AddEmptySet(const std::string& shapeName, const std::string& sliderName);\n\tvoid SetResultDiff(const std::string& shapeName, const std::string& sliderName, const TargetDataDiffs& diff);\n\tvoid UpdateResultDiff(const std::string& shapeName, const std::string& sliderName, const TargetDataDiffs& diff);\n\tvoid UpdateRefDiff(const std::string& shapeName, const std::string& sliderName, const TargetDataDiffs& diff);\n\tvoid EmptyResultDiff(const std::string& shapeName, const std::string& sliderName);\n\tvoid ZeroVertDiff(const std::string& shapeName, const std::string& sliderName, std::vector<uint16_t>* vertSet, std::unordered_map<uint16_t, float>* mask);\n\tvoid ScaleResultDiff(const std::string& shapeName, const std::string& sliderName, float scaleValue);\n\n\tvoid LoadResultDiffs(SliderSet& fromSet);\n\tvoid MergeResultDiffs(\n\t\tSliderSet& fromSet, SliderSet& mergeSet, DiffDataSets& baseDiffData, const std::string& baseShape, const bool newDataLocal = true, const bool appendNewSliders = true);\n\n\tvoid ClearResultSet(const std::string& sliderName);\n\n\tvoid SaveResultDiff(const std::string& shapeName, const std::string& sliderName, const std::string& fileName);\n};\n"
  },
  {
    "path": "src/components/BuildSelection.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"BuildSelection.h\"\n#include \"../utils/PlatformUtil.h\"\n\n\nint BuildSelection::LoadBuildSelection(XMLElement* srcElement) {\n\tif (srcElement == nullptr)\n\t\treturn 1;\n\n\tXMLElement* elem = srcElement->FirstChildElement(\"OutputChoice\");\n\twhile (elem) {\n\t\tif (!elem->Attribute(\"path\")) {\n\t\t\telem = elem->NextSiblingElement(\"OutputChoice\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tstd::string sName = elem->Attribute(\"path\");\n\t\tif (elem->Attribute(\"choice\"))\n\t\t\toutputChoice[sName] = elem->Attribute(\"choice\");\n\t\telse\n\t\t\toutputChoice[sName].clear();\n\n\t\telem = elem->NextSiblingElement(\"OutputChoice\");\n\t}\n\n\telem = srcElement->FirstChildElement(\"ZapChoice\");\n\twhile (elem) {\n\t\tif (!elem->Attribute(\"project\") || !elem->Attribute(\"zap\") || !elem->Attribute(\"choice\")) {\n\t\t\telem = elem->NextSiblingElement(\"ZapChoice\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tstd::string project = elem->Attribute(\"project\");\n\t\tstd::string zap = elem->Attribute(\"zap\");\n\t\tbool choice = elem->BoolAttribute(\"choice\");\n\n\t\tzapChoice[{project, zap}] = choice;\n\n\t\telem = elem->NextSiblingElement(\"ZapChoice\");\n\t}\n\n\treturn 0;\n}\n\nbool BuildSelection::HasOutputPath(const std::string& search) {\n\tfor (auto& c : outputChoice)\n\t\tif (c.first.compare(search) == 0)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nbool BuildSelection::HasZapChoice(const std::string& project, const std::string& zap) {\n\tfor (auto& c : zapChoice)\n\t\tif (c.first.first.compare(project) == 0 && c.first.second.compare(zap) == 0)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nstd::map<std::string, std::string> BuildSelection::GetOutputChoices() {\n\treturn outputChoice;\n}\n\nstd::string BuildSelection::GetOutputChoice(const std::string& outputPath) {\n\tif (!HasOutputPath(outputPath))\n\t\treturn \"\";\n\n\treturn outputChoice[outputPath];\n}\n\nvoid BuildSelection::SetOutputChoice(const std::string& outputPath, const std::string& choice) {\n\toutputChoice[outputPath] = choice;\n}\n\nvoid BuildSelection::RemoveOutputChoice(const std::string& outputPath) {\n\toutputChoice.erase(outputPath);\n}\n\nstd::map<ZapChoiceKey, bool> BuildSelection::GetZapChoices() {\n\treturn zapChoice;\n}\n\nbool BuildSelection::GetZapChoice(const std::string& project, const std::string& zap) {\n\tif (!HasZapChoice(project, zap))\n\t\treturn false;\n\n\treturn zapChoice[{project, zap}];\n}\n\nvoid BuildSelection::SetZapChoice(const std::string& project, const std::string& zap, bool choice) {\n\tzapChoice[{project, zap}] = choice;\n}\n\nvoid BuildSelection::RemoveZapChoice(const std::string& project, const std::string& zap) {\n\tzapChoice.erase({project, zap});\n}\n\nBuildSelectionFile::BuildSelectionFile(const std::string& srcFileName) {\n\tOpen(srcFileName);\n}\n\n// Clears all data of the file\nvoid BuildSelectionFile::Clear() {\n\troot = nullptr;\n\tdoc.Clear();\n\terror = 0;\n}\n\n// Creates a new empty document structure\nvoid BuildSelectionFile::New(const std::string& newFileName) {\n\tif (root)\n\t\treturn;\n\n\tClear();\n\n\tXMLElement* newElement = doc.NewElement(\"BuildSelection\");\n\troot = doc.InsertEndChild(newElement)->ToElement();\n\n\tfileName = newFileName;\n\tdoc.SetUserData(&fileName);\n\n\terror = 0;\n}\n\nvoid BuildSelectionFile::Open(const std::string& srcFileName) {\n\troot = nullptr;\n\terror = 0;\n\tfileName = srcFileName;\n\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(srcFileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn;\n#else\n\tfp = fopen(srcFileName.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn;\n\t}\n#endif\n\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn;\n\n\tdoc.SetUserData(&fileName);\n\troot = doc.FirstChildElement(\"BuildSelection\");\n\tif (!root) {\n\t\terror = 2;\n\t\treturn;\n\t}\n\n\terror = 0;\n}\n\nvoid BuildSelectionFile::Rename(const std::string& newFileName) {\n\tfileName = newFileName;\n}\n\nbool BuildSelectionFile::Save() {\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (error || !fp)\n\t\treturn false;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn false;\n\t}\n#endif\n\n\tdoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = doc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\terror = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (error)\n\t\treturn false;\n\n\treturn true;\n}\n\n// Get the build selection in the file\nvoid BuildSelectionFile::Get(BuildSelection& outBuildSel) {\n\toutBuildSel = root;\n}\n\n// Updates or adds output choices in the XML document\nint BuildSelectionFile::UpdateOutputChoices(BuildSelection& inBuildSel) {\n\tfor (auto& choice : inBuildSel.GetOutputChoices()) {\n\t\tXMLElement* elem = nullptr;\n\n\t\tXMLElement* choiceElem = root->FirstChildElement(\"OutputChoice\");\n\t\twhile (choiceElem) {\n\t\t\tconst char* attrPath = choiceElem->Attribute(\"path\");\n\t\t\tif (attrPath && choice.first.compare(attrPath) == 0) {\n\t\t\t\telem = choiceElem;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tchoiceElem = choiceElem->NextSiblingElement(\"OutputChoice\");\n\t\t}\n\n\t\tif (!elem) {\n\t\t\tXMLElement* newElement = doc.NewElement(\"OutputChoice\");\n\t\t\telem = root->InsertEndChild(newElement)->ToElement();\n\t\t}\n\n\t\tif (elem) {\n\t\t\telem->SetAttribute(\"path\", choice.first.c_str());\n\t\t\telem->SetAttribute(\"choice\", choice.second.c_str());\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n// Updates or adds zap choices in the XML document\nint BuildSelectionFile::UpdateZapChoices(BuildSelection& inBuildSel) {\n\tfor (auto& choice : inBuildSel.GetZapChoices()) {\n\t\tXMLElement* elem = nullptr;\n\n\t\tXMLElement* choiceElem = root->FirstChildElement(\"ZapChoice\");\n\t\twhile (choiceElem) {\n\t\t\tconst char* attrProject = choiceElem->Attribute(\"project\");\n\t\t\tconst char* attrZap = choiceElem->Attribute(\"zap\");\n\t\t\tif (attrProject && attrZap && choice.first.first.compare(attrProject) == 0 && choice.first.second.compare(attrZap) == 0) {\n\t\t\t\telem = choiceElem;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tchoiceElem = choiceElem->NextSiblingElement(\"ZapChoice\");\n\t\t}\n\n\t\tif (!elem) {\n\t\t\tXMLElement* newElement = doc.NewElement(\"ZapChoice\");\n\t\t\telem = root->InsertEndChild(newElement)->ToElement();\n\t\t}\n\n\t\tif (elem) {\n\t\t\telem->SetAttribute(\"project\", choice.first.first.c_str());\n\t\t\telem->SetAttribute(\"zap\", choice.first.second.c_str());\n\t\t\telem->SetAttribute(\"choice\", choice.second);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\n// Removes a single choice from BuildSelection\nvoid BuildSelectionFile::RemoveOutputChoice(const std::string& path) {\n\tXMLElement* elem = root->FirstChildElement(\"OutputChoice\");\n\twhile (elem) {\n\t\tif (path.compare(elem->Attribute(\"path\")) == 0) {\n\t\t\troot->DeleteChild(elem);\n\t\t\treturn;\n\t\t}\n\t\telem = elem->NextSiblingElement(\"OutputChoice\");\n\t}\n}\n\n// Removes a single choice from BuildSelection\nvoid BuildSelectionFile::RemoveZapChoice(const std::string& project, const std::string& zap) {\n\tXMLElement* elem = root->FirstChildElement(\"ZapChoice\");\n\twhile (elem) {\n\t\tif (project.compare(elem->Attribute(\"project\")) == 0 && zap.compare(elem->Attribute(\"zap\")) == 0) {\n\t\t\troot->DeleteChild(elem);\n\t\t\treturn;\n\t\t}\n\t\telem = elem->NextSiblingElement(\"ZapChoice\");\n\t}\n}\n"
  },
  {
    "path": "src/components/BuildSelection.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include <map>\n#include <wx/dir.h>\n\nusing namespace tinyxml2;\n\ntypedef std::pair<std::string, std::string> ZapChoiceKey;\n\nclass BuildSelection {\n\tstd::map<std::string, std::string> outputChoice;\n\tstd::map<ZapChoiceKey, bool> zapChoice;\n\npublic:\n\tBuildSelection() {}\n\tBuildSelection(XMLElement* srcElement) { LoadBuildSelection(srcElement); }\n\n\tbool HasOutputPath(const std::string& search);\n\tbool HasZapChoice(const std::string& project, const std::string& zap);\n\n\tstd::map<std::string, std::string> GetOutputChoices();\n\tstd::string GetOutputChoice(const std::string& outputPath);\n\tvoid SetOutputChoice(const std::string& outputPath, const std::string& choice);\n\tvoid RemoveOutputChoice(const std::string& outputPath);\n\n\tstd::map<ZapChoiceKey, bool> GetZapChoices();\n\tbool GetZapChoice(const std::string& project, const std::string& zap);\n\tvoid SetZapChoice(const std::string& project, const std::string& zap, bool choice);\n\tvoid RemoveZapChoice(const std::string& project, const std::string& zap);\n\n\tint LoadBuildSelection(XMLElement* srcElement);\n};\n\n\nclass BuildSelectionFile {\n\tXMLDocument doc;\n\tXMLElement* root = nullptr;\n\tint error = 0;\n\npublic:\n\tstd::string fileName;\n\tBuildSelectionFile() {}\n\tBuildSelectionFile(const std::string& srcFileName);\n\t~BuildSelectionFile(){};\n\n\tbool fail() { return error != 0; }\n\n\tint GetError() { return error; }\n\n\t// Clears all data of the file\n\tvoid Clear();\n\n\t// Creates a new empty document structure\n\tvoid New(const std::string& newFileName);\n\n\t// Loads the XML document. On a failure, sets the internal error value.\n\tvoid Open(const std::string& srcFileName);\n\n\t// Changes the internal file name. The XML file isn't saved until the Save() function is used.\n\t// Note the original file name is not changed. This method allows you to save build selections as a new file without altering the original.\n\tvoid Rename(const std::string& newFileName);\n\n\t// Writes the XML file using the internal fileName (use Rename() to change the name).\n\tbool Save();\n\n\t// Get the build selection in the file\n\tvoid Get(BuildSelection& outBuildSel);\n\n\t// Updates or adds output choices in the XML document\n\tint UpdateOutputChoices(BuildSelection& inBuildSel);\n\n\t// Updates or adds zap choices in the XML document\n\tint UpdateZapChoices(BuildSelection& inBuildSel);\n\n\t// Removes a single element from the XML document\n\tvoid RemoveOutputChoice(const std::string& path);\n\n\t// Removes a single element from the XML document\n\tvoid RemoveZapChoice(const std::string& project, const std::string& zap);\n};\n"
  },
  {
    "path": "src/components/ClippingFixer.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"ClippingFixer.h\"\n\n#include \"../utils/AABBTree.h\"\n\n#include <algorithm>\n#include <cmath>\n#include <unordered_set>\n\nusing namespace nifly;\n\nNiShape* ClippingFixer::FindReferenceShape(NifFile& nif) {\n\tfor (auto& shape : nif.GetShapes()) {\n\t\tNiShader* shader = nif.GetShader(shape);\n\t\tif (shader && shader->IsSkinTinted())\n\t\t\treturn shape;\n\t}\n\treturn nullptr;\n}\n\nstd::vector<Vector3> ClippingFixer::ComputeVertexNormals(const std::vector<Vector3>& verts,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t const std::vector<Triangle>& tris) {\n\tstd::vector<Vector3> normals(verts.size());\n\n\tfor (auto& tri : tris) {\n\t\tif (tri.p1 >= verts.size() || tri.p2 >= verts.size() || tri.p3 >= verts.size())\n\t\t\tcontinue;\n\n\t\tVector3 faceNormal = tri.trinormal(verts.data());\n\t\tnormals[tri.p1] += faceNormal;\n\t\tnormals[tri.p2] += faceNormal;\n\t\tnormals[tri.p3] += faceNormal;\n\t}\n\n\tfor (auto& n : normals)\n\t\tn.Normalize();\n\n\treturn normals;\n}\n\nfloat ClippingFixer::SignedDistanceToTriangle(const Vector3& point,\n\t\t\t\t\t\t\t\t\t\t\t  const Triangle& tri,\n\t\t\t\t\t\t\t\t\t\t\t  const Vector3* bodyVerts,\n\t\t\t\t\t\t\t\t\t\t\t\t  Vector3& outClosestPoint) {\n\tconst Vector3& v1 = bodyVerts[tri.p1];\n\tconst Vector3& v2 = bodyVerts[tri.p2];\n\tconst Vector3& v3 = bodyVerts[tri.p3];\n\n\tVector3 triNormal = tri.trinormal(bodyVerts);\n\ttriNormal.Normalize();\n\n\t// Project point onto triangle plane\n\tVector3 toPoint = point - v1;\n\tfloat planeDist = toPoint.dot(triNormal);\n\n\t// Project point onto the plane\n\tVector3 projected = point - triNormal * planeDist;\n\n\t// Check if projected point is inside the triangle using edge tests\n\tVector3 edge1 = v2 - v1;\n\tVector3 edge2 = v3 - v2;\n\tVector3 edge3 = v1 - v3;\n\n\tbool inside1 = (projected - v1).dot(edge1.cross(triNormal)) <= 0;\n\tbool inside2 = (projected - v2).dot(edge2.cross(triNormal)) <= 0;\n\tbool inside3 = (projected - v3).dot(edge3.cross(triNormal)) <= 0;\n\n\tif (inside1 && inside2 && inside3) {\n\t\toutClosestPoint = projected;\n\t\treturn planeDist;\n\t}\n\n\t// Point projects outside — find closest point on edges/vertices\n\tfloat minDist = FLT_MAX;\n\tauto ClosestPointOnSegment = [](const Vector3& p, const Vector3& a, const Vector3& b) -> Vector3 {\n\t\tVector3 ab = b - a;\n\t\tfloat t = (p - a).dot(ab) / ab.dot(ab);\n\t\tt = std::max(0.0f, std::min(1.0f, t));\n\t\treturn a + ab * t;\n\t};\n\n\tVector3 cp1 = ClosestPointOnSegment(point, v1, v2);\n\tVector3 cp2 = ClosestPointOnSegment(point, v2, v3);\n\tVector3 cp3 = ClosestPointOnSegment(point, v3, v1);\n\n\tfloat d1 = point.DistanceTo(cp1);\n\tfloat d2 = point.DistanceTo(cp2);\n\tfloat d3 = point.DistanceTo(cp3);\n\n\tif (d1 < minDist) { minDist = d1; outClosestPoint = cp1; }\n\tif (d2 < minDist) { minDist = d2; outClosestPoint = cp2; }\n\tif (d3 < minDist) { minDist = d3; outClosestPoint = cp3; }\n\n\treturn planeDist;\n}\n\nvoid ClippingFixer::BarycentricCoords(const Vector3& p,\n\t\t\t\t\t\t\t\t\t  const Vector3& v1,\n\t\t\t\t\t\t\t\t\t  const Vector3& v2,\n\t\t\t\t\t\t\t\t\t  const Vector3& v3,\n\t\t\t\t\t\t\t\t\t  float& u, float& v, float& w) {\n\tVector3 e0 = v2 - v1;\n\tVector3 e1 = v3 - v1;\n\tVector3 ep = p - v1;\n\tfloat d00 = e0.dot(e0);\n\tfloat d01 = e0.dot(e1);\n\tfloat d11 = e1.dot(e1);\n\tfloat d20 = ep.dot(e0);\n\tfloat d21 = ep.dot(e1);\n\tfloat denom = d00 * d11 - d01 * d01;\n\tif (std::abs(denom) < 1e-12f) {\n\t\tu = v = w = 1.0f / 3.0f;\n\t\treturn;\n\t}\n\tv = (d11 * d20 - d01 * d21) / denom;\n\tw = (d00 * d21 - d01 * d20) / denom;\n\tu = 1.0f - v - w;\n}\n\nstd::vector<std::vector<int>> ClippingFixer::BuildAdjacency(int nVerts, const std::vector<Triangle>& tris) {\n\tstd::vector<std::unordered_set<int>> adjSets(nVerts);\n\tfor (auto& tri : tris) {\n\t\tint a = tri.p1, b = tri.p2, c = tri.p3;\n\t\tif (a < nVerts && b < nVerts && c < nVerts) {\n\t\t\tadjSets[a].insert(b); adjSets[a].insert(c);\n\t\t\tadjSets[b].insert(a); adjSets[b].insert(c);\n\t\t\tadjSets[c].insert(a); adjSets[c].insert(b);\n\t\t}\n\t}\n\tstd::vector<std::vector<int>> adjacency(nVerts);\n\tfor (int i = 0; i < nVerts; i++)\n\t\tadjacency[i].assign(adjSets[i].begin(), adjSets[i].end());\n\treturn adjacency;\n}\n\nvoid ClippingFixer::FixClipping(const std::vector<Vector3>& bodyVerts,\n\t\t\t\t\t\t\t\tconst std::vector<Triangle>& bodyTris,\n\t\t\t\t\t\t\t\tstd::vector<Vector3>& outfitVerts,\n\t\t\t\t\t\t\t\tconst std::vector<Triangle>& outfitTris,\n\t\t\t\t\t\t\t\tconst ClippingFixOptions& options) {\n\tif (bodyVerts.empty() || bodyTris.empty() || outfitVerts.empty())\n\t\treturn;\n\n\tfloat strength = std::max(0.0f, std::min(1.0f, options.strength));\n\tif (strength <= 0.0f)\n\t\treturn;\n\n\t// Inflation distance: how far the body \"inflates\" outward\n\tfloat inflationDist = 0.05f + strength * 0.25f;\n\n\t// Extra margin beyond inflated surface for smooth falloff\n\tfloat influenceMargin = inflationDist * 0.5f;\n\tfloat totalInfluence = inflationDist + influenceMargin;\n\n\t// Determine body normal direction (outward vs inward).\n\t// trinormal() direction depends on winding order which varies across NIF files.\n\tVector3 bodyCentroid;\n\tfor (auto& bv : bodyVerts)\n\t\tbodyCentroid += bv;\n\tbodyCentroid /= static_cast<float>(bodyVerts.size());\n\n\tint outwardCount = 0;\n\tint inwardCount = 0;\n\tfor (auto& tri : bodyTris) {\n\t\tif (tri.p1 >= bodyVerts.size() || tri.p2 >= bodyVerts.size() || tri.p3 >= bodyVerts.size())\n\t\t\tcontinue;\n\t\tVector3 triCenter = (bodyVerts[tri.p1] + bodyVerts[tri.p2] + bodyVerts[tri.p3]) / 3.0f;\n\t\tVector3 toOutward = triCenter - bodyCentroid;\n\t\tVector3 normal = tri.trinormal(bodyVerts.data());\n\t\tif (toOutward.dot(normal) > 0.0f)\n\t\t\toutwardCount++;\n\t\telse\n\t\t\tinwardCount++;\n\t}\n\tfloat normalSign = (outwardCount >= inwardCount) ? 1.0f : -1.0f;\n\n\t// Compute body vertex normals (the \"inflation direction\" at each vertex)\n\tstd::vector<Vector3> bodyNormals = ComputeVertexNormals(bodyVerts, bodyTris);\n\tfor (auto& n : bodyNormals)\n\t\tn = n * normalSign;\n\n\t// Build AABBTree for the body mesh\n\tstd::vector<Vector3> bodyVertsCopy = bodyVerts;\n\tstd::vector<Triangle> bodyTrisCopy = bodyTris;\n\tAABBTree bodyBVH(bodyVertsCopy.data(), bodyTrisCopy.data(), static_cast<uint32_t>(bodyTrisCopy.size()), 100, 2);\n\n\tfloat searchRadius = 2.0f + strength * 3.0f;\n\tint nOutfitVerts = static_cast<int>(outfitVerts.size());\n\n\t// First pass: compute displacement for each outfit vertex (don't apply yet)\n\tstd::vector<Vector3> displacements(nOutfitVerts);\n\n\tfor (int i = 0; i < nOutfitVerts; i++) {\n\t\tVector3 origin = outfitVerts[i];\n\n\t\tstd::vector<IntersectResult> results;\n\t\tif (!bodyBVH.IntersectSphere(origin, searchRadius, &results))\n\t\t\tcontinue;\n\n\t\t// Find the closest body triangle\n\t\tfloat bestDist = FLT_MAX;\n\t\tVector3 bestClosestPoint;\n\t\tfloat bestPlaneDist = 0.0f;\n\t\tuint32_t bestFacet = 0;\n\t\tbool foundClose = false;\n\n\t\tfor (auto& result : results) {\n\t\t\tif (result.HitFacet >= bodyTris.size())\n\t\t\t\tcontinue;\n\n\t\t\tVector3 closestPoint;\n\t\t\tfloat planeDist = SignedDistanceToTriangle(origin, bodyTris[result.HitFacet],\n\t\t\t\t\t\t\t\t\t\t\t\t   bodyVerts.data(), closestPoint);\n\t\t\tfloat dist = origin.DistanceTo(closestPoint);\n\t\t\tif (dist < bestDist) {\n\t\t\t\tbestDist = dist;\n\t\t\t\tbestClosestPoint = closestPoint;\n\t\t\t\tbestPlaneDist = planeDist;\n\t\t\t\tbestFacet = result.HitFacet;\n\t\t\t\tfoundClose = true;\n\t\t\t}\n\t\t}\n\n\t\tif (!foundClose)\n\t\t\tcontinue;\n\n\t\tfloat signedDist = bestPlaneDist * normalSign;\n\n\t\tif (signedDist < totalInfluence) {\n\t\t\t// Interpolate the body normal at the closest point using barycentric coords.\n\t\t\t// This gives the smooth \"inflation direction\" from the body surface.\n\t\t\tconst Triangle& closestTri = bodyTris[bestFacet];\n\t\t\tfloat bu, bv, bw;\n\t\t\tBarycentricCoords(bestClosestPoint,\n\t\t\t\t\t\t\t  bodyVerts[closestTri.p1],\n\t\t\t\t\t\t\t  bodyVerts[closestTri.p2],\n\t\t\t\t\t\t\t  bodyVerts[closestTri.p3],\n\t\t\t\t\t\t\t  bu, bv, bw);\n\n\t\t\t// Clamp barycentric coords (closest point may be on edge/vertex)\n\t\t\tbu = std::max(0.0f, bu);\n\t\t\tbv = std::max(0.0f, bv);\n\t\t\tbw = std::max(0.0f, bw);\n\t\t\tfloat bsum = bu + bv + bw;\n\t\t\tif (bsum > 0.0f) { bu /= bsum; bv /= bsum; bw /= bsum; }\n\n\t\t\tVector3 inflationDir = bodyNormals[closestTri.p1] * bu\n\t\t\t\t\t\t\t\t + bodyNormals[closestTri.p2] * bv\n\t\t\t\t\t\t\t\t + bodyNormals[closestTri.p3] * bw;\n\t\t\tinflationDir.Normalize();\n\n\t\t\tfloat pushDist;\n\t\t\tif (signedDist < inflationDist) {\n\t\t\t\t// Inside or too close: push to inflated surface\n\t\t\t\tpushDist = inflationDist - signedDist;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Influence margin: smooth quadratic falloff\n\t\t\t\tfloat t = (signedDist - inflationDist) / influenceMargin;\n\t\t\t\tfloat falloff = (1.0f - t) * (1.0f - t);\n\t\t\t\tpushDist = falloff * inflationDist * 0.3f;\n\t\t\t}\n\n\t\t\tdisplacements[i] = inflationDir * pushDist;\n\t\t}\n\t}\n\n\t// Propagate displacements through outfit mesh connectivity.\n\t// This preserves the thickness of thin structures like straps:\n\t// when inner vertices get pushed, the push carries to outer vertices\n\t// through mesh edges, moving the whole structure together.\n\tauto adjacency = BuildAdjacency(nOutfitVerts, outfitTris);\n\tconstexpr int propagationRings = 4;\n\tconstexpr float propagationDecay = 0.85f;\n\n\tfor (int ring = 0; ring < propagationRings; ring++) {\n\t\tstd::vector<Vector3> newDisplacements = displacements;\n\n\t\tfor (int i = 0; i < nOutfitVerts; i++) {\n\t\t\tfloat currentLen = displacements[i].length();\n\n\t\t\t// Find the neighbor with the strongest displacement\n\t\t\tVector3 bestNeighborDisp;\n\t\t\tfloat bestNeighborLen = 0.0f;\n\n\t\t\tfor (int adj : adjacency[i]) {\n\t\t\t\tfloat adjLen = displacements[adj].length();\n\t\t\t\tif (adjLen > bestNeighborLen) {\n\t\t\t\t\tbestNeighborLen = adjLen;\n\t\t\t\t\tbestNeighborDisp = displacements[adj];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If a neighbor's decayed displacement exceeds ours, adopt it\n\t\t\tfloat propagatedLen = bestNeighborLen * propagationDecay;\n\t\t\tif (propagatedLen > currentLen + 0.001f)\n\t\t\t\tnewDisplacements[i] = bestNeighborDisp * propagationDecay;\n\t\t}\n\n\t\tdisplacements = std::move(newDisplacements);\n\t}\n\n\t// Unify displacements for co-located (\"welded\") vertices.\n\t// Meshes often have duplicate vertices at the same position with different\n\t// UVs or normals. Without this, one copy gets displaced while the other\n\t// stays put, tearing the mesh apart at seams.\n\t{\n\t\t// Sort vertex indices by x coordinate for efficient neighbor search\n\t\tstd::vector<int> sortedInds(nOutfitVerts);\n\t\tfor (int i = 0; i < nOutfitVerts; i++)\n\t\t\tsortedInds[i] = i;\n\n\t\tstd::sort(sortedInds.begin(), sortedInds.end(),\n\t\t\t\t  [&outfitVerts](int a, int b) { return outfitVerts[a].x < outfitVerts[b].x; });\n\n\t\t// Determine scale-relative epsilon (same approach as SortingMatcher)\n\t\tfloat scale = 0.0f;\n\t\tfor (int i = 0; i < nOutfitVerts; i++)\n\t\t\tscale = std::max(scale, std::max(std::fabs(outfitVerts[i].x),\n\t\t\t\t\t\t\t std::max(std::fabs(outfitVerts[i].y), std::fabs(outfitVerts[i].z))));\n\t\tfloat epsilon = 0.0001f * 0.01f * scale;\n\n\t\tstd::vector<bool> used(nOutfitVerts, false);\n\t\tfor (int si = 0; si < nOutfitVerts; si++) {\n\t\t\tif (used[si])\n\t\t\t\tcontinue;\n\n\t\t\t// Collect co-located vertices and find strongest displacement\n\t\t\tint bestIdx = sortedInds[si];\n\t\t\tfloat bestLen = displacements[bestIdx].length();\n\t\t\tstd::vector<int> group;\n\n\t\t\tfor (int mi = si + 1; mi < nOutfitVerts; mi++) {\n\t\t\t\tif (outfitVerts[sortedInds[mi]].x - outfitVerts[sortedInds[si]].x >= epsilon)\n\t\t\t\t\tbreak;\n\t\t\t\tif (used[mi])\n\t\t\t\t\tcontinue;\n\t\t\t\tif (std::fabs(outfitVerts[sortedInds[si]].y - outfitVerts[sortedInds[mi]].y) >= epsilon)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (std::fabs(outfitVerts[sortedInds[si]].z - outfitVerts[sortedInds[mi]].z) >= epsilon)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Found a co-located vertex\n\t\t\t\tif (group.empty())\n\t\t\t\t\tgroup.push_back(sortedInds[si]);\n\n\t\t\t\tgroup.push_back(sortedInds[mi]);\n\t\t\t\tused[mi] = true;\n\n\t\t\t\tfloat len = displacements[sortedInds[mi]].length();\n\t\t\t\tif (len > bestLen) {\n\t\t\t\t\tbestLen = len;\n\t\t\t\t\tbestIdx = sortedInds[mi];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Apply the strongest displacement to all vertices in the group\n\t\t\tif (!group.empty()) {\n\t\t\t\tfor (int idx : group)\n\t\t\t\t\tdisplacements[idx] = displacements[bestIdx];\n\t\t\t}\n\t\t}\n\t}\n\n\t// Apply final displacements\n\tfor (int i = 0; i < nOutfitVerts; i++)\n\t\toutfitVerts[i] = outfitVerts[i] + displacements[i];\n}\n"
  },
  {
    "path": "src/components/ClippingFixer.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"NifFile.hpp\"\n\n#include <vector>\n\nstruct ClippingFixOptions {\n\tfloat strength = 0.5f; // 0.0 to 1.0, controls inflation distance\n};\n\nclass ClippingFixer {\npublic:\n\t// Find the first shape in the NIF with a skin-tinted shader (the body/reference shape).\n\tstatic nifly::NiShape* FindReferenceShape(nifly::NifFile& nif);\n\n\t// Fix clipping of outfit vertices that penetrate the body mesh.\n\t// Inflates the body surface outward and smoothly displaces nearby outfit\n\t// vertices along the interpolated body normal, preserving outfit detail.\n\tstatic void FixClipping(const std::vector<nifly::Vector3>& bodyVerts,\n\t\t\t\t\t\t\tconst std::vector<nifly::Triangle>& bodyTris,\n\t\t\t\t\t\t\tstd::vector<nifly::Vector3>& outfitVerts,\n\t\t\t\t\t\t\tconst std::vector<nifly::Triangle>& outfitTris,\n\t\t\t\t\t\t\tconst ClippingFixOptions& options);\n\nprivate:\n\t// Compute per-vertex normals for a mesh by averaging face normals.\n\tstatic std::vector<nifly::Vector3> ComputeVertexNormals(const std::vector<nifly::Vector3>& verts,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tconst std::vector<nifly::Triangle>& tris);\n\n\t// Find the closest point on a triangle to a given point, and return\n\t// the signed distance (negative = inside/below the surface).\n\tstatic float SignedDistanceToTriangle(const nifly::Vector3& point,\n\t\t\t\t\t\t\t\t\t\t  const nifly::Triangle& tri,\n\t\t\t\t\t\t\t\t\t\t  const nifly::Vector3* bodyVerts,\n\t\t\t\t\t\t\t\t\t\t  nifly::Vector3& outClosestPoint);\n\n\t// Compute barycentric coordinates of point p on triangle (v1, v2, v3).\n\tstatic void BarycentricCoords(const nifly::Vector3& p,\n\t\t\t\t\t\t\t\t  const nifly::Vector3& v1,\n\t\t\t\t\t\t\t\t  const nifly::Vector3& v2,\n\t\t\t\t\t\t\t\t  const nifly::Vector3& v3,\n\t\t\t\t\t\t\t\t  float& u, float& v, float& w);\n\n\t// Build vertex adjacency lists from triangle data.\n\tstatic std::vector<std::vector<int>> BuildAdjacency(int nVerts, const std::vector<nifly::Triangle>& tris);\n};\n"
  },
  {
    "path": "src/components/DiffData.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"DiffData.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"../utils/StringStuff.h\"\n#include \"NifUtil.hpp\"\n#include \"UndoState.h\"\n\n#include <algorithm>\n#include <fstream>\n\n#ifdef WIN64\n#include <concurrent_unordered_map.h>\n#include <ppl.h>\n#else\n#undef _PPL_H\n#endif\n\nusing namespace nifly;\n\nOSDataFile::OSDataFile() {\n\tversion = 1;\n}\n\nOSDataFile::~OSDataFile() {}\n\n#pragma pack(push, 1)\nstruct DiffStruct {\n\tuint16_t index = 0;\n\tVector3 diff;\n};\n#pragma pack(pop)\n\nbool OSDataFile::Read(const std::string& fileName) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);\n\n\tif (!file)\n\t\treturn false;\n\n\tuint32_t header = 0;\n\tfile.read((char*)&header, 4);\n\tif (header != \"OSD\\0\"_mci)\n\t\treturn false;\n\n\tfile.read((char*)&version, 4);\n\n\tuint32_t dataCount = 0;\n\tfile.read((char*)&dataCount, 4);\n\tdataDiffs.reserve(dataCount);\n\n\tuint8_t nameLength = 0;\n\tstd::string dataName;\n\tuint16_t diffSize = 0;\n\tfor (uint32_t i = 0; i < dataCount; ++i) {\n\t\tfile.read((char*)&nameLength, 1);\n\t\tdataName.resize(nameLength, ' ');\n\t\tfile.read((char*)&dataName.front(), nameLength);\n\n\t\tTargetDataDiffs diffs;\n\t\tfile.read((char*)&diffSize, 2);\n\t\tdiffs.reserve(diffSize);\n\n\t\tstd::vector<DiffStruct> diffData(diffSize);\n\t\tfile.read((char*)diffData.data(), diffSize * sizeof(DiffStruct));\n\n\t\tfor (int j = 0; j < diffSize; ++j) {\n\t\t\tauto& diffEntry = diffData[j];\n\t\t\tdiffEntry.diff.clampEpsilon();\n\t\t\tdiffs[diffEntry.index] = std::move(diffEntry.diff);\n\t\t}\n\n\t\tdataDiffs.emplace(dataName, std::make_unique<TargetDataDiffs>(std::move(diffs)));\n\t}\n\n\treturn true;\n}\n\nbool OSDataFile::Write(const std::string& fileName) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::out | std::ios::binary);\n\n\tif (!file)\n\t\treturn false;\n\n\tuint32_t header = \"OSD\\0\"_mci;\n\tfile.write((char*)&header, 4);\n\tfile.write((char*)&version, 4);\n\n\tuint32_t dataCount = static_cast<uint32_t>(dataDiffs.size());\n\tfile.write((char*)&dataCount, 4);\n\n\tuint8_t nameLength;\n\tuint16_t diffSize;\n\tfor (auto& diffs : dataDiffs) {\n\t\tnameLength = static_cast<uint8_t>(diffs.first.length());\n\t\tfile.write((char*)&nameLength, 1);\n\t\tfile.write(diffs.first.c_str(), nameLength);\n\n\t\tdiffSize = static_cast<uint16_t>(diffs.second->size());\n\n\t\tstd::vector<DiffStruct> diffData(diffSize);\n\t\tdiffData.resize(diffSize);\n\n\t\tsize_t i = 0;\n\n\t\tfor (auto& diff : *diffs.second) {\n\t\t\tif (i >= diffSize)\n\t\t\t\tbreak;\n\n\t\t\tdiffData[i].index = diff.first;\n\t\t\tdiffData[i].diff = diff.second;\n\t\t\t++i;\n\t\t}\n\n\t\tfile.write((char*)&diffSize, 2);\n\t\tfile.write((char*)diffData.data(), diffSize * sizeof(DiffStruct));\n\t}\n\n\treturn true;\n}\n\nTargetData& OSDataFile::GetDataDiffs() {\n\treturn dataDiffs;\n}\n\nstd::unique_ptr<TargetDataDiffs>* OSDataFile::GetDataDiff(const std::string& dataName) {\n\tauto it = dataDiffs.find(dataName);\n\tif (it != dataDiffs.end())\n\t\treturn &it->second;\n\n\treturn nullptr;\n}\n\nvoid OSDataFile::SetDataDiff(const std::string& dataName, const TargetDataDiffs& inDataDiff) {\n\tdataDiffs[dataName] = std::make_unique<TargetDataDiffs>(inDataDiff);\n}\n\n\nvoid DiffDataSets::MoveToSet(const std::string& name, const std::string& target, std::unique_ptr<TargetDataDiffs>& inDiffData) {\n\tnamedSet[name] = std::move(inDiffData);\n\tdataTargets[name] = target;\n}\n\nvoid DiffDataSets::LoadSet(const std::string& name, const std::string& target, const TargetDataDiffs& inDiffData) {\n\tnamedSet[name] = std::make_unique<TargetDataDiffs>(inDiffData);\n\tdataTargets[name] = target;\n}\n\nint DiffDataSets::LoadSet(const std::string& name, const std::string& target, const std::string& fromFile) {\n\tstd::fstream inFile;\n\tPlatformUtil::OpenFileStream(inFile, fromFile, std::ios::in | std::ios::binary);\n\n\tif (!inFile)\n\t\treturn 1;\n\n\tuint32_t sz;\n\tinFile.read((char*)&sz, 4);\n\n\tauto data = std::make_unique<TargetDataDiffs>();\n\tdata->reserve(sz);\n\n\tuint32_t idx;\n\tVector3 v;\n\tfor (uint32_t i = 0; i < sz; i++) {\n\t\tinFile.read((char*)&idx, sizeof(uint32_t));\n\t\tinFile.read((char*)&v, sizeof(Vector3));\n\t\tv.clampEpsilon();\n\t\tdata->emplace(static_cast<uint16_t>(idx), v);\n\t}\n\n\tinFile.close();\n\n\tnamedSet[name] = std::move(data);\n\tdataTargets[name] = target;\n\n\treturn 0;\n}\n\nbool DiffDataSets::LoadData(const std::map<std::string, std::map<std::string, std::string>>& osdNames) {\n#ifdef _PPL_H\n\tConcurrency::concurrent_unordered_map<std::string, std::unique_ptr<OSDataFile>> loaded;\n\tConcurrency::parallel_for_each(osdNames.begin(), osdNames.end(), [&](auto& osd) {\n\t\tauto osdFile = std::make_unique<OSDataFile>();\n\t\tif (!osdFile->Read(osd.first))\n\t\t\treturn;\n\n\t\tloaded[osd.first] = std::move(osdFile);\n\t});\n#endif\n\tfor (auto& osd : osdNames) {\n#ifdef _PPL_H\n\t\tauto kvp = loaded.find(osd.first);\n\t\tif (kvp == loaded.end())\n\t\t\tcontinue;\n\n\t\tauto& osdFile = kvp->second;\n#else\n\t\tauto osdFile = std::make_unique<OSDataFile>();\n\t\tif (!osdFile->Read(osd.first))\n\t\t\tcontinue;\n#endif\n\t\tfor (auto& dataNames : osd.second) {\n\t\t\tauto diff = osdFile->GetDataDiff(dataNames.first);\n\t\t\tif (diff)\n\t\t\t\tMoveToSet(dataNames.first, dataNames.second, *diff);\n\t\t}\n\t}\n\treturn true;\n}\n\nint DiffDataSets::SaveSet(const std::string& name, const std::string& target, const std::string& toFile) {\n\tauto& data = namedSet[name];\n\tif (!TargetMatch(name, target))\n\t\treturn 2;\n\n\tstd::fstream outFile;\n\tPlatformUtil::OpenFileStream(outFile, toFile, std::ios::out | std::ios::binary);\n\n\tif (!outFile)\n\t\treturn 1;\n\n\tuint32_t sz = static_cast<uint32_t>(data->size());\n\toutFile.write((char*)&sz, sizeof(uint32_t));\n\n\tuint32_t idx = 0;\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) {\n\t\tidx = static_cast<uint32_t>(resultIt->first);\n\t\toutFile.write((char*)&idx, sizeof(uint32_t));\n\t\toutFile.write((char*)&resultIt->second, sizeof(Vector3));\n\t}\n\treturn 0;\n}\n\nbool DiffDataSets::SaveData(const std::map<std::string, std::map<std::string, std::string>>& osdNames) {\n\tfor (auto& osd : osdNames) {\n\t\tOSDataFile osdFile;\n\t\tfor (auto& dataNames : osd.second) {\n\t\t\tauto& data = namedSet[dataNames.first];\n\t\t\tif (!TargetMatch(dataNames.first, dataNames.second))\n\t\t\t\tcontinue;\n\n\t\t\tosdFile.SetDataDiff(dataNames.first, *data);\n\t\t}\n\n\t\tif (!osdFile.Write(osd.first))\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid DiffDataSets::RenameSet(const std::string& oldName, const std::string& newName) {\n\tif (namedSet.find(oldName) != namedSet.end()) {\n\t\tnamedSet.insert(std::make_pair(newName, std::move(namedSet[oldName])));\n\t\tnamedSet.erase(oldName);\n\t\tdataTargets[newName] = dataTargets[oldName];\n\t\tdataTargets.erase(oldName);\n\t}\n}\n\nvoid DiffDataSets::RenameDataTarget(const std::string& oldTarget, const std::string& newTarget) {\n\tfor (auto& dt : dataTargets) {\n\t\tif (dt.second == oldTarget)\n\t\t\tdt.second = newTarget;\n\t}\n}\n\nvoid DiffDataSets::CopySet(const std::string& oldName, const std::string& newName, const std::string& newTargetName) {\n\tauto namedSetIt = namedSet.find(oldName);\n\tif (namedSetIt != namedSet.end()) {\n\t\tnamedSet[newName] = std::make_unique<TargetDataDiffs>(*namedSetIt->second);\n\t\tdataTargets[newName] = newTargetName;\n\t}\n}\n\nstd::string DiffDataSets::GetDataTargetName(const std::string& targetName, const std::string& dataNameSuffix) {\n\tfor (auto& dt : dataTargets) {\n\t\tif (dt.second == targetName && StringEndsWith(dt.first, dataNameSuffix))\n\t\t\treturn dt.first;\n\t}\n\treturn \"\";\n}\n\nvoid DiffDataSets::AddEmptySet(const std::string& name, const std::string& target) {\n\tif (namedSet.find(name) == namedSet.end()) {\n\t\tnamedSet[name] = std::make_unique<TargetDataDiffs>();\n\t\tdataTargets[name] = target;\n\t}\n}\n\nvoid DiffDataSets::UpdateDiff(const std::string& name, const std::string& target, uint16_t index, const Vector3& newdiff) {\n\tauto& data = namedSet[name];\n\tif (!TargetMatch(name, target))\n\t\treturn;\n\n\t(*data)[index] = newdiff;\n}\n\nvoid DiffDataSets::SumDiff(const std::string& name, const std::string& target, uint16_t index, const Vector3& newdiff) {\n\tauto& data = namedSet[name];\n\tif (!TargetMatch(name, target))\n\t\treturn;\n\n\tVector3 v = (*data)[index];\n\tv += newdiff;\n\n\tif (v.IsZero(true))\n\t\tdata->erase(index);\n\telse\n\t\t(*data)[index] = v;\n}\n\nvoid DiffDataSets::ScaleDiff(const std::string& name, const std::string& target, float scalevalue) {\n\tauto& data = namedSet[name];\n\n\tif (!TargetMatch(name, target))\n\t\treturn;\n\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt)\n\t\tresultIt->second *= scalevalue;\n}\n\nvoid DiffDataSets::OffsetDiff(const std::string& name, const std::string& target, const Vector3& offset) {\n\tauto& data = namedSet[name];\n\tif (!TargetMatch(name, target))\n\t\treturn;\n\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt)\n\t\tresultIt->second += offset;\n}\n\nbool DiffDataSets::ApplyUVDiff(const std::string& set, const std::string& target, float percent, std::vector<Vector2>* inOutResult) {\n\tif (percent == 0.0f)\n\t\treturn false;\n\n\tif (!TargetMatch(set, target))\n\t\treturn false;\n\n\tuint16_t maxidx = static_cast<uint16_t>(inOutResult->size());\n\tauto& data = namedSet[set];\n\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) {\n\t\tif (resultIt->first >= maxidx)\n\t\t\tcontinue;\n\n\t\t(*inOutResult)[resultIt->first].u += resultIt->second.x * percent;\n\t\t(*inOutResult)[resultIt->first].v += resultIt->second.y * percent;\n\t}\n\n\treturn true;\n}\n\nbool DiffDataSets::ApplyDiff(const std::string& set, const std::string& target, float percent, std::vector<Vector3>* inOutResult) {\n\tif (percent == 0.0f)\n\t\treturn false;\n\n\tif (!TargetMatch(set, target))\n\t\treturn false;\n\n\tuint16_t maxidx = static_cast<uint16_t>(inOutResult->size());\n\tauto& data = namedSet[set];\n\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) {\n\t\tif (resultIt->first >= maxidx)\n\t\t\tcontinue;\n\n\t\t(*inOutResult)[resultIt->first].x += resultIt->second.x * percent;\n\t\t(*inOutResult)[resultIt->first].y += resultIt->second.y * percent;\n\t\t(*inOutResult)[resultIt->first].z += resultIt->second.z * percent;\n\t}\n\n\treturn true;\n}\n\nbool DiffDataSets::ApplyClamp(const std::string& set, const std::string& target, std::vector<Vector3>* inOutResult) {\n\tif (!TargetMatch(set, target))\n\t\treturn false;\n\n\tuint16_t maxidx = static_cast<uint16_t>(inOutResult->size());\n\tauto& data = namedSet[set];\n\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) {\n\t\tif (resultIt->first >= maxidx)\n\t\t\tcontinue;\n\n\t\t(*inOutResult)[resultIt->first].x = resultIt->second.x;\n\t\t(*inOutResult)[resultIt->first].y = resultIt->second.y;\n\t\t(*inOutResult)[resultIt->first].z = resultIt->second.z;\n\t}\n\n\treturn true;\n}\n\nTargetDataDiffs* DiffDataSets::GetDiffSet(const std::string& targetDataName) {\n\tif (namedSet.find(targetDataName) == namedSet.end())\n\t\treturn nullptr;\n\n\treturn namedSet[targetDataName].get();\n}\n\nvoid DiffDataSets::GetDiffIndices(const std::string& set, const std::string& target, std::vector<uint16_t>& outIndices, float threshold) {\n\tif (!TargetMatch(set, target))\n\t\treturn;\n\n\tauto& data = namedSet[set];\n\tfor (auto resultIt = data->begin(); resultIt != data->end(); ++resultIt) {\n\t\tif (fabs(resultIt->second.x) > threshold || fabs(resultIt->second.y) > threshold || fabs(resultIt->second.z) > threshold) {\n\t\t\toutIndices.push_back(resultIt->first);\n\t\t}\n\t}\n\n\tstd::sort(outIndices.begin(), outIndices.end());\n\toutIndices.erase(std::unique(outIndices.begin(), outIndices.end()), outIndices.end());\n}\n\nvoid DiffDataSets::DeleteVerts(const std::string& target, const std::vector<uint16_t>& indices) {\n\tif (indices.empty())\n\t\treturn;\n\n\tuint16_t highestRemoved = indices.back();\n\tstd::vector<int> indexCollapse = GenerateIndexCollapseMap(indices, highestRemoved + 1);\n\n\tfor (auto& data : namedSet) {\n\t\tif (TargetMatch(data.first, target))\n\t\t\tApplyIndexMapToMapKeys(*data.second, indexCollapse, -static_cast<int>(indices.size()));\n\t}\n}\n\nvoid DiffDataSets::InsertVertexIndices(const std::string& target, const std::vector<uint16_t>& indices) {\n\tif (indices.empty())\n\t\treturn;\n\n\tint highestAdded = indices.back();\n\tstd::vector<int> indexExpand = GenerateIndexExpandMap(indices, highestAdded + 1);\n\n\tfor (auto& data : namedSet) {\n\t\tif (!TargetMatch(data.first, target))\n\t\t\tcontinue;\n\n\t\tApplyIndexMapToMapKeys(*data.second, indexExpand, static_cast<int>(indices.size()));\n\t}\n}\n\nvoid DiffDataSets::ClearSet(const std::string& name) {\n\tnamedSet.erase(name);\n\tdataTargets.erase(name);\n}\n"
  },
  {
    "path": "src/components/DiffData.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"Object3d.hpp\"\n\n#include <map>\n#include <string>\n#include <unordered_map>\n#include <memory>\n\nstruct UndoStateVertexSliderDiff;\n\ntypedef std::unordered_map<uint16_t, nifly::Vector3> TargetDataDiffs;\ntypedef std::unordered_map<std::string, std::unique_ptr<TargetDataDiffs>> TargetData;\n\nclass OSDataFile {\n\tuint32_t version;\n\tTargetData dataDiffs;\n\npublic:\n\tOSDataFile();\n\t~OSDataFile();\n\n\tbool Read(const std::string& fileName);\n\tbool Write(const std::string& fileName);\n\n\tTargetData& GetDataDiffs();\n\tstd::unique_ptr<TargetDataDiffs>* GetDataDiff(const std::string& dataName);\n\tvoid SetDataDiff(const std::string& dataName, const TargetDataDiffs& inDataDiff);\n};\n\nclass DiffDataSets {\n\tTargetData namedSet;\n\tstd::map<std::string, std::string> dataTargets;\n\npublic:\n\tinline bool TargetMatch(const std::string& set, const std::string& target);\n\tvoid MoveToSet(const std::string& name, const std::string& target, std::unique_ptr<TargetDataDiffs>& inDiffData);\n\tvoid LoadSet(const std::string& name, const std::string& target, const TargetDataDiffs& inDiffData);\n\tint LoadSet(const std::string& name, const std::string& target, const std::string& fromFile);\n\tint SaveSet(const std::string& name, const std::string& target, const std::string& toFile);\n\tbool LoadData(const std::map<std::string, std::map<std::string, std::string>>& osdNames);\n\tbool SaveData(const std::map<std::string, std::map<std::string, std::string>>& osdNames);\n\n\tvoid RenameSet(const std::string& oldName, const std::string& newName);\n\tvoid RenameDataTarget(const std::string& oldTarget, const std::string& newTarget);\n\tvoid CopySet(const std::string& oldName, const std::string& newName, const std::string& newTargetName);\n\tstd::string GetDataTargetName(const std::string& targetName, const std::string& dataNameSuffix);\n\n\tvoid AddEmptySet(const std::string& name, const std::string& target);\n\tvoid UpdateDiff(const std::string& name, const std::string& target, uint16_t index, const nifly::Vector3& newdiff);\n\tvoid SumDiff(const std::string& name, const std::string& target, uint16_t index, const nifly::Vector3& newdiff);\n\tvoid ScaleDiff(const std::string& name, const std::string& target, float scalevalue);\n\tvoid OffsetDiff(const std::string& name, const std::string& target, const nifly::Vector3& offset);\n\tbool ApplyDiff(const std::string& set, const std::string& target, float percent, std::vector<nifly::Vector3>* inOutResult);\n\tbool ApplyUVDiff(const std::string& set, const std::string& target, float percent, std::vector<nifly::Vector2>* inOutResult);\n\tbool ApplyClamp(const std::string& set, const std::string& target, std::vector<nifly::Vector3>* inOutResult);\n\tTargetDataDiffs* GetDiffSet(const std::string& targetDataName);\n\tvoid GetDiffIndices(const std::string& set, const std::string& target, std::vector<uint16_t>& outIndices, float threshold = 0.0f);\n\n\t// indices must be in ascending order.\n\tvoid DeleteVerts(const std::string& target, const std::vector<uint16_t>& indices);\n\t// indices must be in ascending order.\n\tvoid InsertVertexIndices(const std::string& target, const std::vector<uint16_t>& indices);\n\tvoid ClearSet(const std::string& name);\n\tvoid EmptySet(const std::string& set, const std::string& target) {\n\t\tif (!TargetMatch(set, target))\n\t\t\treturn;\n\n\t\tnamedSet[set]->clear();\n\t}\n\n\n\tvoid ZeroVertDiff(const std::string& set, int vertCount, float* vColorMask) {\n\t\tfor (auto& ns : *namedSet[set]) {\n\t\t\tif (ns.first < vertCount) {\n\t\t\t\tfloat f = vColorMask[ns.first];\n\t\t\t\tif (f == 1.0f)\n\t\t\t\t\tcontinue;\n\t\t\t\telse if (f == 0.0f)\n\t\t\t\t\tns.second *= 0.0f;\n\t\t\t\telse\n\t\t\t\t\tns.second *= f;\n\t\t\t}\n\t\t\telse\n\t\t\t\tns.second *= 0.0f;\n\t\t}\n\t}\n\n\t// Zeroes diffs for the specified verts (or all verts in set if vertSet is null), with an optional mask value. A partially masked vertex will have its diff brought closer to 0,\n\t// a fully masked vertex will have its diff remain the same and a fully unmasked vert will have its diff erased.\n\tvoid ZeroVertDiff(const std::string& set, const std::string& target, std::vector<uint16_t>* vertSet, std::unordered_map<uint16_t, float>* mask) {\n\t\tif (!TargetMatch(set, target))\n\t\t\treturn;\n\n\t\tstd::vector<uint16_t> v;\n\t\tif (vertSet) {\n\t\t\tv = (*vertSet);\n\t\t}\n\t\telse {\n\t\t\tfor (auto& diff : *namedSet[set])\n\t\t\t\tv.push_back(diff.first);\n\t\t}\n\n\t\tfor (auto& i : v) {\n\t\t\tauto d = namedSet[set]->find(i);\n\t\t\tif (d == namedSet[set]->end())\n\t\t\t\tcontinue;\n\n\t\t\tfloat f = 0.0f;\n\t\t\tif (mask) {\n\t\t\t\tauto m = mask->find(i);\n\t\t\t\tif (m != mask->end())\n\t\t\t\t\tf = m->second;\n\t\t\t}\n\n\t\t\tif (f == 1.0f)\n\t\t\t\tcontinue;\n\n\t\t\tif (f == 0.0f) {\n\t\t\t\tnamedSet[set]->erase(i);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t(*namedSet[set])[i] *= f;\n\t\t}\n\t}\n\n\tvoid Clear() {\n\t\tnamedSet.clear();\n\t\tdataTargets.clear();\n\t}\n};\n\n// Set == slider name, target == shape name.\nbool DiffDataSets::TargetMatch(const std::string& set, const std::string& target) {\n\tauto it = dataTargets.find(set);\n\tif (it != dataTargets.end())\n\t\treturn it->second == target;\n\n\treturn false;\n}\n"
  },
  {
    "path": "src/components/Mesh.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"Mesh.h\"\n#include \"KDMatcher.hpp\"\n\nusing namespace nifly;\n\nMesh::Mesh() {}\n\nMesh::~Mesh() {\n\tif (genBuffers) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\t\tglBindVertexArray(0);\n\n\t\tglDeleteBuffers(static_cast<GLsizei>(vbo.size()), vbo.data());\n\t\tglDeleteBuffers(1, &ibo);\n\t\tglDeleteVertexArrays(1, &vao);\n\t}\n}\n\nstd::shared_ptr<AABBTree> Mesh::CreateBVH() {\n\tif (verts && tris && nTris > 0)\n\t\tbvh = std::make_shared<AABBTree>(verts.get(), tris.get(), nTris, 100, 2);\n\telse\n\t\tbvh.reset();\n\n\treturn bvh;\n}\n\nvoid Mesh::BuildVertexAdjacency() {\n\tif (!tris)\n\t\treturn;\n\n\tstd::vector<std::set<int>> adjArray(nVerts);\n\tstd::vector<int> p1ws, p2ws;\n\n\tauto AddWeldSetToAdjacenciesOfWeldSet = [&](int p1, int p2) {\n\t\tGetWeldSet(p1, p1ws);\n\t\tGetWeldSet(p2, p2ws);\n\t\tfor (int p1w : p1ws)\n\t\tfor (int p2w : p2ws) {\n\t\t\tadjArray[p1w].insert(p2w);\n\t\t\tadjArray[p2w].insert(p1w);\n\t\t}\n\t};\n\t\n\tfor (int t = 0; t < nTris; t++) {\n\t\tauto& tri = tris[t];\n\n\t\tAddWeldSetToAdjacenciesOfWeldSet(tri.p1, tri.p2);\n\t\tAddWeldSetToAdjacenciesOfWeldSet(tri.p2, tri.p3);\n\t\tAddWeldSetToAdjacenciesOfWeldSet(tri.p3, tri.p1);\n\t}\n\n\tadjVerts = std::make_unique<std::vector<int>[]>(nVerts);\n\tauto av = adjVerts.get();\n\n\tfor (int v = 0; v < nVerts; v++) {\n\t\tav[v].resize(adjArray[v].size());\n\t\tstd::copy(adjArray[v].begin(), adjArray[v].end(), av[v].begin());\n\t}\n}\n\nvoid Mesh::MakeEdges() {\n\tif (!tris)\n\t\treturn;\n\tif (edges)\n\t\treturn;\n\n\tnEdges = nTris * 3;\n\tedges = std::make_unique<Edge[]>(nEdges);\n\n\tfor (int i = 0; i < nEdges; i++) {\n\t\t// Find correct points for edge\n\t\tuint16_t* points = &tris[i / 3].p1;\n\t\tint pA = i % 3;\n\t\tint pB = i % 3 + 1;\n\t\tif (pB >= 3)\n\t\t\tpB = 0;\n\n\t\t// Create edge from points\n\t\tedges[i] = Edge(std::min(points[pA], points[pB]), std::max(points[pA], points[pB]));\n\t}\n}\n\nvoid Mesh::BuildEdgeList() {\n\tif (!edges)\n\t\tMakeEdges();\n\n\tvertEdges = std::make_unique<std::vector<int>[]>(nVerts);\n\tauto ve = vertEdges.get();\n\tfor (int e = 0; e < nEdges; e++) {\n\t\tuint16_t i1 = edges[e].p1;\n\t\tuint16_t i2 = edges[e].p2;\n\t\tif (i1 >= nVerts || i2 >= nVerts)\n\t\t\tcontinue;\n\n\t\tve[edges[e].p1].push_back(e);\n\t\tve[edges[e].p2].push_back(e);\n\t}\n}\n\nvoid Mesh::CreateBuffers() {\n\tif (!genBuffers) {\n\t\tglGenVertexArrays(1, &vao);\n\t\tglGenBuffers(static_cast<GLsizei>(vbo.size()), vbo.data());\n\t\tglGenBuffers(1, &ibo);\n\t}\n\n\t// NumVertices * (Position + Normal + Colors + Texture Coordinates)\n\tglBindVertexArray(vao);\n\n\tif (verts) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[0]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(Vector3), verts.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (norms) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[1]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(Vector3), norms.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (tangents) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[2]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(Vector3), tangents.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (bitangents) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[3]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(Vector3), bitangents.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (vcolors) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[4]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(Vector3), vcolors.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (valpha) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[5]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(float), valpha.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (texcoord) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[6]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(Vector2), texcoord.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (mask) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[7]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(float), mask.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tif (weight) {\n\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[8]);\n\t\tglBufferData(GL_ARRAY_BUFFER, nVerts * sizeof(float), weight.get(), GL_DYNAMIC_DRAW);\n\t}\n\n\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n\n\t// Element index array\n\tif (verts && tris) {\n\t\trenderTris = std::make_unique<Triangle[]>(nTris);\n\t\tfor (int i = 0; i < nTris; ++i)\n\t\t\trenderTris[i] = tris[i];\n\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);\n\t\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, nTris * sizeof(Triangle), renderTris.get(), GL_DYNAMIC_DRAW);\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\t}\n\telse if (verts && edges) {\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);\n\t\tglBufferData(GL_ELEMENT_ARRAY_BUFFER, nEdges * sizeof(Edge), edges.get(), GL_DYNAMIC_DRAW);\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\t}\n\n\tglBindVertexArray(0);\n\tgenBuffers = true;\n}\n\nvoid Mesh::UpdateBuffers() {\n\tif (genBuffers) {\n\t\tglBindVertexArray(vao);\n\n\t\tif (verts && queueUpdate[UpdateType::Position]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::Position]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(Vector3), verts.get());\n\t\t\tqueueUpdate[UpdateType::Position] = false;\n\t\t}\n\n\t\tif (norms && queueUpdate[UpdateType::Normals]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::Normals]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(Vector3), norms.get());\n\t\t\tqueueUpdate[UpdateType::Normals] = false;\n\t\t}\n\n\t\tif (tangents && queueUpdate[UpdateType::Tangents]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::Tangents]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(Vector3), tangents.get());\n\t\t\tqueueUpdate[UpdateType::Tangents] = false;\n\t\t}\n\n\t\tif (bitangents && queueUpdate[UpdateType::Bitangents]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::Bitangents]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(Vector3), bitangents.get());\n\t\t\tqueueUpdate[UpdateType::Bitangents] = false;\n\t\t}\n\n\t\tif (vcolors && queueUpdate[UpdateType::VertexColors]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::VertexColors]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(Vector3), vcolors.get());\n\t\t\tqueueUpdate[UpdateType::VertexColors] = false;\n\t\t}\n\n\t\tif (valpha && queueUpdate[UpdateType::VertexAlpha]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::VertexAlpha]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(float), valpha.get());\n\t\t\tqueueUpdate[UpdateType::VertexAlpha] = false;\n\t\t}\n\n\t\tif (texcoord && queueUpdate[UpdateType::TextureCoordinates]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::TextureCoordinates]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(Vector2), texcoord.get());\n\t\t\tqueueUpdate[UpdateType::TextureCoordinates] = false;\n\t\t}\n\n\t\tif (mask && queueUpdate[UpdateType::Mask]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::Mask]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(float), mask.get());\n\t\t\tqueueUpdate[UpdateType::Mask] = false;\n\t\t}\n\n\t\tif (weight && queueUpdate[UpdateType::Weight]) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, vbo[UpdateType::Weight]);\n\t\t\tglBufferSubData(GL_ARRAY_BUFFER, 0, nVerts * sizeof(float), weight.get());\n\t\t\tqueueUpdate[UpdateType::Weight] = false;\n\t\t}\n\n\t\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n\n\t\tif (queueUpdate[UpdateType::Indices]) {\n\t\t\tif (tris) {\n\t\t\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);\n\t\t\t\tglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, nTris * sizeof(Triangle), renderTris.get());\n\t\t\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\t\t\t}\n\t\t\telse if (edges) {\n\t\t\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);\n\t\t\t\tglBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, nEdges * sizeof(Edge), edges.get());\n\t\t\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\t\t\t}\n\t\t\tqueueUpdate[UpdateType::Indices] = false;\n\t\t}\n\n\t\tglBindVertexArray(0);\n\t}\n}\n\nvoid Mesh::QueueUpdate(const UpdateType& type) {\n\tqueueUpdate[type] = true;\n}\n\nvoid Mesh::UpdateFromMaterialFile(const MaterialFile& matFile) {\n\tdoublesided = matFile.twoSided;\n\tmodelSpace = matFile.modelSpaceNormals;\n\temissive = matFile.emitEnabled;\n\tspecular = matFile.specularEnabled;\n\tbacklight = matFile.backLighting;\n\trimlight = matFile.rimLighting;\n\tsoftlight = matFile.subsurfaceLighting;\n\tglowmap = matFile.glowMap;\n\tgreyscaleColor = matFile.grayscaleToPaletteColor;\n\tcubemap = matFile.environmentMapping;\n\n\tprop.alpha = matFile.alpha;\n\tprop.uvOffset = matFile.uvOffset;\n\tprop.uvScale = matFile.uvScale;\n\tprop.specularColor = matFile.specularColor;\n\tprop.specularStrength = matFile.specularMult;\n\tprop.shininess = matFile.smoothness;\n\tprop.emissiveColor = matFile.emittanceColor;\n\tprop.emissiveMultiple = matFile.emittanceMult;\n\tprop.envReflection = matFile.environmentMappingMaskScale;\n\tprop.backlightPower = matFile.backLightPower;\n\tprop.rimlightPower = matFile.rimPower;\n\tprop.subsurfaceRolloff = matFile.subsurfaceLightingRolloff;\n\tprop.fresnelPower = matFile.fresnelPower;\n\tprop.paletteScale = matFile.grayscaleToPaletteScale;\n}\n\nbool Mesh::HasAlphaBlend() {\n\tbool alphaBlend = alphaFlags & 1;\n\tif (prop.alpha < 1.0f)\n\t\talphaBlend = true;\n\n\treturn alphaBlend;\n}\n\nvoid Mesh::ScaleVertices(const Vector3& center, const float& factor) {\n\tfor (int i = 0; i < nVerts; i++)\n\t\tverts[i] = center + (verts[i] - center) * factor;\n\n\tCreateBVH();\n\tqueueUpdate[UpdateType::Position] = true;\n}\n\nvoid Mesh::GetAdjacentPoints(int querypoint, std::unordered_set<int>& outPoints) {\n\tif (querypoint >= nVerts)\n\t\treturn;\n\n\tif (!adjVerts)\n\t\tBuildVertexAdjacency();\n\n\tif (!adjVerts)\n\t\treturn;\n\n\tauto av = adjVerts.get();\n\tconst auto& avPoint = av[querypoint];\n\n\toutPoints.insert(avPoint.begin(), avPoint.end());\n}\n\nint Mesh::GetAdjacentPoints(int querypoint, int outPoints[], int maxPoints) {\n\tif (querypoint >= nVerts)\n\t\treturn 0;\n\n\tif (!adjVerts)\n\t\tBuildVertexAdjacency();\n\n\tif (!adjVerts)\n\t\treturn 0;\n\n\tauto av = adjVerts.get();\n\tconst auto& avPoint = av[querypoint];\n\n\tint n = 0;\n\tfor (auto& p : avPoint) {\n\t\tif (n == maxPoints)\n\t\t\tbreak;\n\n\t\toutPoints[n++] = p;\n\t}\n\n\treturn n;\n\t/* TODO: sort by distance */\n}\n\nint Mesh::GetAdjacentUnvisitedPoints(int querypoint, int outPoints[], int maxPoints, bool* visPoint) const {\n\tint n = 0;\n\tfor (int p : adjVerts[querypoint])\n\t\tif (n + 1 < maxPoints && !visPoint[p]) {\n\t\t\toutPoints[n++] = p;\n\t\t\tvisPoint[p] = true;\n\t\t}\n\treturn n;\n\t/* TODO: sort by distance */\n}\n\nint Mesh::FindAdjacentBalancedPairs(int pt, int pairs[]) const {\n\t// If adjPts contains any welded points, this algorithm should pick\n\t// out just one balanced pair from among the welds.\n\n\tconst std::vector<int>& adjPts = adjVerts[pt];\n\tint c = std::min(static_cast<int>(adjPts.size()), MaxAdjacentPoints);\n\tif (c == 0)\n\t\treturn 0;\n\n\t// Calculate direction from pt to each adjPts\n\tVector3 pDirs[MaxAdjacentPoints];\n\tfor (int i = 0; i < c; ++i) {\n\t\tVector3 pDir = verts[adjPts[i]] - verts[pt];\n\t\tpDir.Normalize();\n\t\tpDirs[i] = pDir;\n\t}\n\n\t// For each point in adjPts, find which of the other neighboring points\n\t// has the lowest direction dot product with it.  Ideally, we want -1\n\t// for each matching pair.\n\tint matchInd[MaxAdjacentPoints];\n\tfloat matchDot[MaxAdjacentPoints];\n\tfor (int i = 0; i < c; ++i) {\n\t\tint bestInd = i;\n\t\tfloat bestDot = 1;\n\t\tfor (int j = 0; j < c; ++j) {\n\t\t\tfloat dot = pDirs[j].dot(pDirs[i]);\n\t\t\tif (dot < bestDot) {\n\t\t\t\tbestDot = dot;\n\t\t\t\tbestInd = j;\n\t\t\t}\n\t\t}\n\t\tmatchInd[i] = bestInd;\n\t\tmatchDot[i] = bestDot;\n\t}\n\n\t// Repeatedly pick out the best pairs.  If a point's best match is to\n\t// a point that's already been paired, we won't match it to anything.\n\tbool donePt[MaxAdjacentPoints];\n\tfor (int i = 0; i < c; ++i)\n\t\tdonePt[i] = false;\n\tint pairInd = 0;\n\tbool gotOne = false;\n\tdo {\n\t\tgotOne = false;\n\t\tfloat bestDot = 1;\n\t\tint bestInd = 0;\n\t\tfor (int i = 0; i < c; ++i)\n\t\t\t// Avoid pairing a point with itself: require matchInd[i] != i\n\t\t\tif (!donePt[i] && matchInd[i] != i && !donePt[matchInd[i]] && matchDot[i] < bestDot) {\n\t\t\t\tbestDot = matchDot[i];\n\t\t\t\tbestInd = i;\n\t\t\t\tgotOne = true;\n\t\t\t}\n\t\tif (gotOne) {\n\t\t\tpairs[pairInd++] = adjPts[bestInd];\n\t\t\tpairs[pairInd++] = adjPts[matchInd[bestInd]];\n\t\t\tdonePt[bestInd] = true;\n\t\t\tdonePt[matchInd[bestInd]] = true;\n\t\t}\n\t} while (gotOne);\n\n\treturn pairInd;\n}\n\nint Mesh::FindOpposingPoint(int p1, int p2, float maxdot) const {\n\tconst std::vector<int>& adjPts = adjVerts[p1];\n\tint c = static_cast<int>(adjPts.size());\n    if (c == 0)\n        return -1;\n\n    Vector3 p2dir = verts[p2] - verts[p1];\n    p2dir.Normalize();\n\n    float bestdot = maxdot;\n    int bestpt = -1;\n    for (int i = 0; i < c; ++i) {\n        Vector3 dir = verts[adjPts[i]] - verts[p1];\n        dir.Normalize();\n        float dot = dir.dot(p2dir);\n        if (dot < bestdot) {\n            bestdot = dot;\n            bestpt = adjPts[i];\n        }\n    }\n\n    return bestpt;\n}\n\nvoid Mesh::CalcWeldVerts() {\n\tweldVerts.clear();\n\n\tSortingMatcher matcher(verts.get(), static_cast<uint16_t>(nVerts));\n\tfor (const auto& matchset : matcher.matches) {\n\t\tfor (size_t j = 0; j < matchset.size(); ++j) {\n\t\t\tstd::vector<int>& wv = weldVerts[matchset[j]];\n\t\t\tfor (size_t k = 0; k < matchset.size(); ++k) {\n\t\t\t\tif (j != k)\n\t\t\t\t\twv.push_back(matchset[k]);\n\t\t\t}\n\t\t}\n\t}\n\tbGotWeldVerts = true;\n}\n\nvoid Mesh::SmoothNormals(const std::unordered_set<int>& vertices) {\n\tif (lockNormals || !norms)\n\t\treturn;\n\n\t// Copy old normals into a working temporary\n\tstd::vector<Vector3> tnorms(norms.get(), norms.get() + nVerts);\n\n\t// Zero old normals\n\tbool noVertices = vertices.empty();\n\tfor (int i = 0; i < nVerts; i++) {\n\t\tif (!noVertices && vertices.count(i) == 0)\n\t\t\tcontinue;\n\n\t\tif (lockedNormalIndices.count(i) != 0)\n\t\t\tcontinue;\n\n\t\ttnorms[i].Zero();\n\t}\n\n\t// Face normals\n\tfor (int t = 0; t < nTris; t++) {\n\t\tTriangle& tri = tris[t];\n\t\tbool bn1 = (noVertices || vertices.count(tri.p1) != 0);\n\t\tbool bn2 = (noVertices || vertices.count(tri.p2) != 0);\n\t\tbool bn3 = (noVertices || vertices.count(tri.p3) != 0);\n\n\t\t// None of the three normals should change\n\t\tif (!bn1 && !bn2 && !bn3)\n\t\t\tcontinue;\n\n\t\tVector3 tn = tri.trinormal(verts.get());\n\n\t\tif (bn1 && lockedNormalIndices.count(tri.p1) == 0)\n\t\t\ttnorms[tri.p1] += tn;\n\n\t\tif (bn2 && lockedNormalIndices.count(tri.p2) == 0)\n\t\t\ttnorms[tri.p2] += tn;\n\n\t\tif (bn3 && lockedNormalIndices.count(tri.p3) == 0)\n\t\t\ttnorms[tri.p3] += tn;\n\t}\n\n\tfor (int i = 0; i < nVerts; i++) {\n\t\tif (lockedNormalIndices.count(i) != 0)\n\t\t\tcontinue;\n\n\t\ttnorms[i].Normalize();\n\t}\n\n\t// Smooth welded vertex normals\n\tif (smoothSeamNormals) {\n\t\tif (!bGotWeldVerts)\n\t\t\tCalcWeldVerts();\n\n\t\tfloat smoothThresh = smoothSeamNormalsAngle * DEG2RAD;\n\t\tstd::vector<std::pair<int, Vector3>> seamNorms;\n\n\t\tfor (auto& wvp : weldVerts) {\n\t\t\tauto& key = wvp.first;\n\t\t\tif (!noVertices && vertices.count(key) == 0)\n\t\t\t\tcontinue;\n\n\t\t\tif (lockedNormalIndices.count(key) != 0)\n\t\t\t\tcontinue;\n\n\t\t\tconst Vector3& n = tnorms[key];\n\t\t\tVector3 sn = n;\n\t\t\tauto& value = wvp.second;\n\t\t\tfor (int wvi : value)\n\t\t\t\tif (n.angle(tnorms[wvi]) < smoothThresh)\n\t\t\t\t\tsn += tnorms[wvi];\n\n\t\t\tsn.Normalize();\n\t\t\tseamNorms.emplace_back(key, sn);\n\t\t}\n\n\t\tfor (auto& snp : seamNorms)\n\t\t\ttnorms[snp.first] = snp.second;\n\t}\n\n\t// Copy temporary back into the main.\n\tstd::copy(tnorms.begin(), tnorms.end(), norms.get());\n\n\tqueueUpdate[UpdateType::Normals] = true;\n\tCalcTangentSpace();\n}\n\nvoid Mesh::FacetNormals() {\n\tif (lockNormals)\n\t\treturn;\n\n\t// Zero old normals\n\tfor (int i = 0; i < nVerts; i++) {\n\t\tif (lockedNormalIndices.find(i) != lockedNormalIndices.end())\n\t\t\tcontinue;\n\n\t\tVector3& pn = norms[i];\n\t\tpn.Zero();\n\t}\n\n\tfor (int t = 0; t < nTris; t++) {\n\t\tauto& tri = tris[t];\n\t\tif (tri.p1 >= nVerts || tri.p2 >= nVerts || tri.p3 >= nVerts)\n\t\t\tcontinue;\n\n\t\tVector3 tn = tri.trinormal(verts.get());\n\n\t\tif (lockedNormalIndices.find(tri.p1) == lockedNormalIndices.end()) {\n\t\t\tVector3& pn1 = norms[tri.p1];\n\t\t\tpn1 += tn;\n\t\t}\n\n\t\tif (lockedNormalIndices.find(tri.p2) == lockedNormalIndices.end()) {\n\t\t\tVector3& pn2 = norms[tri.p2];\n\t\t\tpn2 += tn;\n\t\t}\n\n\t\tif (lockedNormalIndices.find(tri.p3) == lockedNormalIndices.end()) {\n\t\t\tVector3& pn3 = norms[tri.p3];\n\t\t\tpn3 += tn;\n\t\t}\n\t}\n\n\tfor (int i = 0; i < nVerts; i++) {\n\t\tif (lockedNormalIndices.find(i) != lockedNormalIndices.end())\n\t\t\tcontinue;\n\n\t\tVector3& pn = norms[i];\n\t\tpn.Normalize();\n\t}\n\n\tqueueUpdate[UpdateType::Normals] = true;\n\tCalcTangentSpace();\n}\n\nvoid Mesh::ColorFill(const Vector3& vcolor) {\n\tif (!vcolors)\n\t\treturn;\n\n\tfor (int i = 0; i < nVerts; i++)\n\t\tvcolors[i] = vcolor;\n\n\tqueueUpdate[UpdateType::VertexColors] = true;\n}\n\nvoid Mesh::AlphaFill(float alpha) {\n\tif (!valpha)\n\t\treturn;\n\n\tfor (int i = 0; i < nVerts; i++)\n\t\tvalpha[i] = alpha;\n\n\tqueueUpdate[UpdateType::VertexAlpha] = true;\n}\n\nvoid Mesh::MaskFill(float maskValue) {\n\tif (!mask)\n\t\treturn;\n\n\tfor (int i = 0; i < nVerts; i++)\n\t\tmask[i] = maskValue;\n\n\tqueueUpdate[UpdateType::Mask] = true;\n}\n\nvoid Mesh::WeightFill(float weightValue) {\n\tif (!weight)\n\t\treturn;\n\n\tfor (int i = 0; i < nVerts; i++)\n\t\tweight[i] = weightValue;\n\n\tqueueUpdate[UpdateType::Weight] = true;\n}\n\nvoid Mesh::ColorChannelFill(int channel, float value) {\n\tif (!vcolors)\n\t\treturn;\n\n\tfor (int i = 0; i < nVerts; i++) {\n\t\tif (channel == 0)\n\t\t\tvcolors[i].x = value;\n\t\telse if (channel == 1)\n\t\t\tvcolors[i].y = value;\n\t\telse if (channel == 2)\n\t\t\tvcolors[i].z = value;\n\t}\n\n\tqueueUpdate[UpdateType::VertexColors] = true;\n}\n\nvoid Mesh::CalcTangentSpace() {\n\tif (!norms || !texcoord)\n\t\treturn;\n\n\tfor (int i = 0; i < nTris; i++) {\n\t\tint i1 = tris[i].p1;\n\t\tint i2 = tris[i].p2;\n\t\tint i3 = tris[i].p3;\n\n\t\tVector3 v1 = verts[i1];\n\t\tVector3 v2 = verts[i2];\n\t\tVector3 v3 = verts[i3];\n\n\t\tVector2 w1 = texcoord[i1];\n\t\tVector2 w2 = texcoord[i2];\n\t\tVector2 w3 = texcoord[i3];\n\n\t\tfloat x1 = v2.x - v1.x;\n\t\tfloat x2 = v3.x - v1.x;\n\t\tfloat y1 = v2.y - v1.y;\n\t\tfloat y2 = v3.y - v1.y;\n\t\tfloat z1 = v2.z - v1.z;\n\t\tfloat z2 = v3.z - v1.z;\n\n\t\tfloat s1 = w2.u - w1.u;\n\t\tfloat s2 = w3.u - w1.u;\n\t\tfloat t1 = w2.v - w1.v;\n\t\tfloat t2 = w3.v - w1.v;\n\n\t\tfloat r = (s1 * t2 - s2 * t1);\n\t\tr = (r >= 0.0f ? +1.0f : -1.0f);\n\n\t\tVector3 sdir = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);\n\t\tVector3 tdir = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);\n\n\t\tsdir.Normalize();\n\t\ttdir.Normalize();\n\n\t\ttangents[i1] += tdir;\n\t\ttangents[i2] += tdir;\n\t\ttangents[i3] += tdir;\n\n\t\tbitangents[i1] += sdir;\n\t\tbitangents[i2] += sdir;\n\t\tbitangents[i3] += sdir;\n\t}\n\n\tfor (int i = 0; i < nVerts; i++) {\n\t\tif (tangents[i].IsZero() || bitangents[i].IsZero()) {\n\t\t\ttangents[i].x = norms[i].y;\n\t\t\ttangents[i].y = norms[i].z;\n\t\t\ttangents[i].z = norms[i].x;\n\t\t\tbitangents[i] = norms[i].cross(tangents[i]);\n\t\t}\n\t\telse {\n\t\t\ttangents[i].Normalize();\n\t\t\ttangents[i] = (tangents[i] - norms[i] * norms[i].dot(tangents[i]));\n\t\t\ttangents[i].Normalize();\n\n\t\t\tbitangents[i].Normalize();\n\n\t\t\tbitangents[i] = (bitangents[i] - norms[i] * norms[i].dot(bitangents[i]));\n\t\t\tbitangents[i] = (bitangents[i] - tangents[i] * tangents[i].dot(bitangents[i]));\n\n\t\t\tbitangents[i].Normalize();\n\t\t}\n\t}\n\n\tqueueUpdate[UpdateType::Tangents] = true;\n\tqueueUpdate[UpdateType::Bitangents] = true;\n}\n\nvoid Mesh::ConnectedPointsInSphere(const Vector3& center, float sqradius, int startTri, std::vector<bool>& pointvisit, int outPoints[], int& nOutPoints) {\n\t// Add the triangle's three vertices to the queue, if they're within the\n\t// radius.\n\tfor (int tvi = 0; tvi < 3; ++tvi) {\n\t\tauto p = tris[startTri][tvi];\n\t\tif (!pointvisit[p] && verts[p].DistanceSquaredTo(center) <= sqradius) {\n\t\t\toutPoints[nOutPoints++] = p;\n\t\t\tpointvisit[p] = true;\n\t\t}\n\t}\n\n\t// Loop through points in the queue\n\tfor (int adjCursor = 0; adjCursor < nOutPoints; ++adjCursor) {\n\t\tint p = outPoints[adjCursor];\n\n\t\t// Add welds of p to the queue\n\t\tDoForEachWeldedVertex(p, [&](int wvi){\n\t\t\tif (!pointvisit[wvi]) {\n\t\t\t\tpointvisit[wvi] = true;\n\t\t\t\toutPoints[nOutPoints++] = wvi;\n\t\t\t}\n\t\t});\n\n\t\t// Add adjacent points of p to the queue, if they're within the radius\n\t\tfor (int ei : vertEdges[p]) {\n\t\t\tint op = edges[ei].p1 == p ? edges[ei].p2 : edges[ei].p1;\n\t\t\tif (!pointvisit[op] && verts[op].DistanceSquaredTo(center) <= sqradius) {\n\t\t\t\tpointvisit[op] = true;\n\t\t\t\toutPoints[nOutPoints++] = op;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Mesh::ConnectedPointsInTwoSpheres(const Vector3& center1, const Vector3& center2, float sqradius, int startTri1, int startTri2, std::vector<bool>& pointvisit, int outPoints[], int& nOutPoints) {\n\t// Add each triangle's three vertices to the queue, if they're within the\n\t// radius.\n\tfor (int triInd = 0; triInd < 2; ++triInd) {\n\t\tint startTri = triInd ? startTri2 : startTri1;\n\t\tfor (int tvi = 0; tvi < 3; ++tvi) {\n\t\t\tauto p = tris[startTri][tvi];\n\t\t\tif (!pointvisit[p] &&\n\t\t\t\t(verts[p].DistanceSquaredTo(center1) <= sqradius ||\n\t\t\t\tverts[p].DistanceSquaredTo(center2) <= sqradius)) {\n\t\t\t\toutPoints[nOutPoints++] = p;\n\t\t\t\tpointvisit[p] = true;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Loop through points in the queue\n\tfor (int adjCursor = 0; adjCursor < nOutPoints; ++adjCursor) {\n\t\tint p = outPoints[adjCursor];\n\n\t\t// Add welds of p to the queue\n\t\tDoForEachWeldedVertex(p, [&](int wvi){\n\t\t\tif (!pointvisit[wvi]) {\n\t\t\t\tpointvisit[wvi] = true;\n\t\t\t\toutPoints[nOutPoints++] = wvi;\n\t\t\t}\n\t\t});\n\n\t\t// Add adjacent points of p to the queue, if they're within the radius\n\t\tfor (int ei : vertEdges[p]) {\n\t\t\tint op = edges[ei].p1 == p ? edges[ei].p2 : edges[ei].p1;\n\t\t\tif (!pointvisit[op] &&\n\t\t\t\t(verts[op].DistanceSquaredTo(center1) <= sqradius ||\n\t\t\t\tverts[op].DistanceSquaredTo(center2) <= sqradius)) {\n\t\t\t\tpointvisit[op] = true;\n\t\t\t\toutPoints[nOutPoints++] = op;\n\t\t\t}\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/components/Mesh.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../files/MaterialFile.h\"\n#include \"../render/GLExtensions.h\"\n#include \"../utils/AABBTree.h\"\n\n#include <glm/gtc/matrix_transform.hpp>\n#include <glm/gtx/euler_angles.hpp>\n\n#include <array>\n#include <memory>\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n\nclass GLMaterial;\n\nclass Mesh {\nprivate:\n\tstd::array<bool, 10> queueUpdate = {false};\n\npublic:\n\tenum class RenderMode { Normal, UnlitSolid, UnlitWire, UnlitWireDepth, UnlitPoints, UnlitPointsDepth, LitWire };\n\tenum UpdateType { Position, Normals, Tangents, Bitangents, VertexColors, VertexAlpha, TextureCoordinates, Mask, Weight, Indices };\n\n\tstruct ShaderProperties {\n\t\tnifly::Vector2 uvOffset;\n\t\tnifly::Vector2 uvScale = nifly::Vector2(1.0f, 1.0f);\n\t\tnifly::Vector3 specularColor = nifly::Vector3(1.0f, 1.0f, 1.0f);\n\t\tfloat specularStrength = 1.0f;\n\t\tfloat shininess = 30.0f;\n\t\tfloat envReflection = 1.0f;\n\t\tnifly::Vector3 emissiveColor = nifly::Vector3(1.0f, 1.0f, 1.0f);\n\t\tfloat emissiveMultiple = 1.0f;\n\t\tfloat alpha = 1.0f;\n\t\tfloat backlightPower = 0.0f;\n\t\tfloat rimlightPower = 2.0f;\n\t\tfloat softlighting = 0.3f;\n\t\tfloat subsurfaceRolloff = 0.3f;\n\t\tfloat fresnelPower = 5.0f;\n\t\tfloat paletteScale = 0.0f;\n\t};\n\n\ttypedef std::unordered_map<int, std::vector<int>> WeldVertsType;\n\n\t// Use SetXformMeshToModel or SetXformModelToMesh to set matModel,\n\t// xformMeshToModel, and xformModelToMesh.\n\tglm::mat4x4 matModel = glm::identity<glm::mat4x4>();\n\tnifly::MatTransform xformMeshToModel, xformModelToMesh;\n\n\tint nVerts = 0;\n\tstd::unique_ptr<nifly::Vector3[]> verts;\n\tstd::unique_ptr<nifly::Vector3[]> norms;\n\tstd::unique_ptr<nifly::Vector3[]> tangents;\n\tstd::unique_ptr<nifly::Vector3[]> bitangents;\n\tstd::unique_ptr<nifly::Vector3[]> vcolors;\n\tstd::unique_ptr<float[]> valpha;\n\tstd::unique_ptr<nifly::Vector2[]> texcoord;\n\tstd::unique_ptr<float[]> mask;\n\tstd::unique_ptr<float[]> weight;\n\n\tstd::unique_ptr<nifly::Triangle[]> tris;\n\t// renderTris is tris re-ordered for rendering with submeshes.  It's\n\t// created automatically in CreateBuffers as a copy of tris.  If\n\t// something changes tris, renderTris needs to be updated too.\n\tstd::unique_ptr<nifly::Triangle[]> renderTris;\n\tint nTris = 0;\n\n\tstd::unique_ptr<nifly::Edge[]> edges;\n\tint nEdges = 0;\n\n\tbool genBuffers = false;\n\tGLuint vao = 0;\n\tstd::vector<GLuint> vbo = std::vector<GLuint>(9, 0);\n\tGLuint ibo = 0;\n\n\tstd::vector<std::pair<uint32_t, uint32_t>> subMeshes; // Start index and size of each sub mesh\n\tstd::vector<nifly::Vector3> subMeshesColor;\t\t\t  // Color of each sub mesh\n\n\tShaderProperties prop;\n\tGLMaterial* material = nullptr;\n\n\tuint32_t overlayLayer = 0;\t\t\t\t\t // Layer for order of rendering overlays\n\n\tstd::unique_ptr<std::vector<int>[]> vertEdges;\t\t // Map of edges for which each vert is a member.\n\tWeldVertsType weldVerts; // Verts that are duplicated for UVs but are in the same position.\n\tbool bGotWeldVerts = false;\t\t\t\t\t\t\t // Whether weldVerts has been calculated yet.\n\t// adjVerts: for each vertex p, adjVerts[p] is a list of all vertices that\n\t// (1) share a triangle with p; (2) share a triangle with a point welded to\n\t// p; (3) are welded to a point that shares a triangle with p; or (4)\n\t// are welded to a point that shares a triangle with a point welded to p.\n\t// Points welded to p are _not_ in adjVerts[p].\n\tstd::unique_ptr<std::vector<int>[]> adjVerts;\n\n\tstd::unordered_set<uint32_t> lockedNormalIndices;\n\n\tRenderMode rendermode = RenderMode::Normal;\n\tbool doublesided = false;\n\tGLenum cullMode = GL_BACK;\n\tbool modelSpace = false;\n\tbool emissive = false;\n\tbool specular = true;\n\tbool vertexColors = false;\n\tbool vertexAlpha = false;\n\tbool backlight = false;\n\tbool backlightMap = false;\n\tbool rimlight = false;\n\tbool softlight = false;\n\tbool glowmap = false;\n\tbool greyscaleColor = false;\n\tbool cubemap = false;\n\tbool textured = false;\n\n\tstd::shared_ptr<AABBTree> bvh = nullptr;\n\n\tbool bVisible = true;\n\tbool bShowPoints = false;\n\tbool smoothSeamNormals = true; // Smoothing for normals on seams.\n\tfloat smoothSeamNormalsAngle = 60.0f; // Smoothing threshold in degrees for generating smooth normals on seams.\n\tbool lockNormals = false;\n\n\tuint16_t alphaFlags = 0;\n\tuint8_t alphaThreshold = 0;\n\n\tstd::string shapeName;\n\tnifly::Vector3 color;\n\n\tMesh();\n\t~Mesh();\n\n\t// Creates a new bvh tree for the mesh.\n\tstd::shared_ptr<AABBTree> CreateBVH();\n\n\tvoid MakeEdges(); // Creates the list of edges from the list of triangles.\n\n\tvoid BuildVertexAdjacency(); // Vertex adjacency optional to reduce overhead when it's not needed.\n\tvoid BuildEdgeList();\t\t // Edge list optional to reduce overhead when it's not needed.\n\n\tvoid CalcWeldVerts();\n\n\tvoid CreateBuffers();\n\tvoid UpdateBuffers();\n\tvoid QueueUpdate(const UpdateType& type);\n\tvoid UpdateFromMaterialFile(const MaterialFile& matFile);\n\tbool HasAlphaBlend();\n\n\tvoid ScaleVertices(const nifly::Vector3& center, const float& factor);\n\n\tvoid FacetNormals();\n\tvoid SmoothNormals(const std::unordered_set<int>& vertices = std::unordered_set<int>());\n\tstatic void SmoothNormalsStatic(Mesh* m) { m->SmoothNormals(); }\n\tstatic void SmoothNormalsStaticArray(Mesh* m, int* vertices, int nVertices) {\n\t\tstd::unordered_set<int> verts;\n\t\tverts.reserve(nVertices * 2);\n\t\tverts.insert(vertices, vertices + nVertices);\n\n\t\tfor (int i = 0; i < nVertices; i++)\n\t\t\tm->GetAdjacentPoints(vertices[i], verts);\n\n\t\tm->SmoothNormals(verts);\n\t}\n\tstatic void SmoothNormalsStaticMap(Mesh* m, const std::unordered_map<int, nifly::Vector3>& vertices) {\n\t\tstd::unordered_set<int> verts;\n\t\tverts.reserve(vertices.size());\n\n\t\tfor (auto& v : vertices) {\n\t\t\tverts.insert(v.first);\n\t\t\tm->GetAdjacentPoints(v.first, verts);\n\t\t}\n\n\t\tm->SmoothNormals(verts);\n\t}\n\n\tvoid CalcTangentSpace();\n\n\t// Convenience functions for using weldVerts\n\tstatic int LeastWeldedVertexIndex(const WeldVertsType& weldVerts, int p) {\n\t\tint li = p;\n\t\tauto wvit = weldVerts.find(p);\n\t\tif (wvit == weldVerts.end())\n\t\t\treturn li;\n\t\tfor (int wvi : wvit->second)\n\t\t\tif (wvi < li)\n\t\t\t\tli = wvi;\n\t\treturn li;\n\t}\n\tint LeastWeldedVertexIndex(int p) const {\n\t\treturn LeastWeldedVertexIndex(weldVerts, p);\n\t}\n\n\ttemplate<typename Func>\n\tstatic void DoForEachWeldedVertex(const WeldVertsType& weldVerts, int p, const Func& f) {\n\t\tauto wvit = weldVerts.find(p);\n\t\tif (wvit == weldVerts.end())\n\t\t\treturn;\n\t\tfor (int wvi : wvit->second)\n\t\t\tf(wvi);\n\t}\n\ttemplate<typename Func>\n\tvoid DoForEachWeldedVertex(int p, const Func& f) const {\n\t\tDoForEachWeldedVertex(weldVerts, p, f);\n\t}\n\n\t// GetWeldSet: gets the weld set of p, which consists of p and all points\n\t// welded to p.  The weld set of p always contains at least one point: p.\n\t// VT is typically std::vector<int>.\n\ttemplate<typename VT>\n\tstatic void GetWeldSet(const WeldVertsType& weldVerts, int p, VT& s) {\n\t\ts.resize(1);\n\t\ts[0] = p;\n\t\tauto wvit = weldVerts.find(p);\n\t\tif (wvit == weldVerts.end())\n\t\t\treturn;\n\t\tstd::copy(wvit->second.begin(), wvit->second.end(), std::back_inserter(s));\n\t}\n\ttemplate<typename VT>\n\tvoid GetWeldSet(int p, VT& s) const {\n\t\tGetWeldSet(weldVerts, p, s);\n\t}\n\n\t// List connected points within the squared radius of the center.\n\t// Requires vertEdges and edges.  pointvisit.size() must be nVerts,\n\t// and it must be initialized to false.  nOutPoints must be initialized\n\t// to zero.\n\tvoid ConnectedPointsInSphere(const nifly::Vector3& center, float sqradius, int startTri, std::vector<bool>& pointvisit, int outPoints[], int& nOutPoints);\n\n\t// List connected points within the squared radius of either center.\n\t// Requires vertEdges and edges.  pointvisit.size() must be nVerts,\n\t// and it must be initialized to false.  nOutPoints must be initialized\n\t// to zero.\n\tvoid ConnectedPointsInTwoSpheres(const nifly::Vector3& center1, const nifly::Vector3& center2, float sqradius, int startTri1, int startTri2, std::vector<bool>& pointvisit, int outPoints[], int& nOutPoints);\n\n\t// Convenience function to gather connected points using adjVerts.\n\t// That is, it adds all points adjacent to querypoint to outPoints,\n\t// taking into consideration welds.\n\tvoid GetAdjacentPoints(int querypoint, std::unordered_set<int>& outPoints);\n\n\t// Convenience function that copies adjVerts[querypoint] into outPoints,\n\t// with a maximum of maxPoints copies, and returns how many were copied.\n\t// That is, it puts all points adjacent to querypoint in outPoints,\n\t// taking into consideration welds.\n\tint GetAdjacentPoints(int querypoint, int outPoints[], int maxPoints);\n\n\t// As above, but also checks if each point has already been looked at (according to vispoint).\n\tint GetAdjacentUnvisitedPoints(int querypoint, int outPoints[], int maxPoints, bool* visPoint) const;\n\n\t// FindAdjacentBalancedPairs: like GetAdjacentPoints, but the points\n\t// are organized in pairs, with the points of each pair on opposite sides\n\t// of pt.  The return result will always be even.  outPoints should have\n\t// size at least MaxAdjacentPoints.\n\tstatic constexpr int MaxAdjacentPoints = 1000;\n\tint FindAdjacentBalancedPairs(int pt, int outPoints[]) const;\n\n\t// FindOpposingPoint: tries to find the vertex on the opposite side of p1\n\t// from p2.  Returns -1 on failure.\n\tint FindOpposingPoint(int p1, int p2, float maxdot = 1.0f) const;\n\n\t// Creates the vertex color array (if necessary) and sets all the colors to the provided value.\n\tvoid ColorFill(const nifly::Vector3& color);\n\tvoid AlphaFill(float alpha);\n\tvoid MaskFill(float maskValue);\n\tvoid WeightFill(float weightValue);\n\n\tvoid ColorChannelFill(int channel, float value);\n\n\tstatic constexpr nifly::MatTransform xformNifToMesh{nifly::Vector3(),nifly::Matrix3(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f),0.1f};\n\tstatic constexpr nifly::MatTransform xformMeshToNif{nifly::Vector3(),nifly::Matrix3(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f),10.0f};\n\n\tstatic constexpr nifly::Vector3 TransformPosNifToMesh(const nifly::Vector3& vec) {\n\t\t// This function efficiently calculates xformNifToMesh.ApplyTransform(vec)\n\t\treturn nifly::Vector3(\n\t\t\tvec.x / -10.0f,\n\t\t\tvec.z / 10.0f,\n\t\t\tvec.y / 10.0f);\n\t}\n\n\tstatic constexpr nifly::Vector3 TransformPosMeshToNif(const nifly::Vector3& vec) {\n\t\t// This function efficiently calculates xformMeshToNif.ApplyTransform(vec)\n\t\treturn nifly::Vector3(\n\t\t\tvec.x * -10.0f,\n\t\t\tvec.z * 10.0f,\n\t\t\tvec.y * 10.0f);\n\t}\n\n\tstatic constexpr nifly::Vector3 TransformDiffNifToMesh(const nifly::Vector3& diff) {\n\t\t// This function efficiently calculates xformNifToMesh::ApplyTransformToDiff(diff)\n\t\treturn nifly::Vector3(\n\t\t\tdiff.x / -10.0f,\n\t\t\tdiff.z / 10.0f,\n\t\t\tdiff.y / 10.0f);\n\t}\n\n\tstatic constexpr nifly::Vector3 TransformDiffMeshToNif(const nifly::Vector3& diff) {\n\t\t// This function efficiently calculates xformMeshToNif::ApplyTransformToDiff(diff)\n\t\treturn nifly::Vector3(\n\t\t\tdiff.x * -10.0f,\n\t\t\tdiff.z * 10.0f,\n\t\t\tdiff.y * 10.0f);\n\t}\n\n\tstatic constexpr nifly::Vector3 TransformDirNifToMesh(const nifly::Vector3& dir) {\n\t\t// This function efficiently calculates xformNifToMesh::ApplyTransformToDir(dir)\n\t\treturn nifly::Vector3(\n\t\t\t-dir.x,\n\t\t\tdir.z,\n\t\t\tdir.y);\n\t}\n\n\tstatic constexpr nifly::Vector3 TransformDirMeshToNif(const nifly::Vector3& dir) {\n\t\t// This function efficiently calculates xformMeshToNif::ApplyTransformToDir(dir)\n\t\treturn nifly::Vector3(\n\t\t\t-dir.x,\n\t\t\tdir.z,\n\t\t\tdir.y);\n\t}\n\n\tstatic constexpr float TransformDistNifToMesh(float d) {\n\t\t// This function calculates xformMeshToNif::ApplyTransformToDist(d)\n\t\treturn d / 10.0f;\n\t}\n\n\tstatic constexpr float TransformDistMeshToNif(float d) {\n\t\t// This function calculates xformMeshToNif::ApplyTransformToDist(d)\n\t\treturn d * 10.0f;\n\t}\n\n\tvoid SetXformMeshToModel(const nifly::MatTransform& tMeshToModel) {\n\t\txformMeshToModel = tMeshToModel;\n\t\txformModelToMesh = tMeshToModel.InverseTransform();\n\t\tmatModel = xformMeshToModel.ToGLMMatrix<glm::mat4x4>();\n\t}\n\n\tvoid SetXformModelToMesh(const nifly::MatTransform& tModelToMesh) {\n\t\txformModelToMesh = tModelToMesh;\n\t\txformMeshToModel = tModelToMesh.InverseTransform();\n\t\tmatModel = xformMeshToModel.ToGLMMatrix<glm::mat4x4>();\n\t}\n\n\tnifly::Vector3 TransformPosMeshToModel(const nifly::Vector3 &pos) {\n\t\treturn xformMeshToModel.ApplyTransform(pos);\n\t}\n\n\tnifly::Vector3 TransformPosModelToMesh(const nifly::Vector3 &pos) {\n\t\treturn xformModelToMesh.ApplyTransform(pos);\n\t}\n\n\tnifly::Vector3 TransformDirMeshToModel(const nifly::Vector3 &dir) {\n\t\treturn xformMeshToModel.ApplyTransformToDir(dir);\n\t}\n\n\tnifly::Vector3 TransformDirModelToMesh(const nifly::Vector3 &dir) {\n\t\treturn xformModelToMesh.ApplyTransformToDir(dir);\n\t}\n\n\tnifly::Vector3 TransformDiffMeshToModel(const nifly::Vector3 &diff) {\n\t\treturn xformMeshToModel.ApplyTransformToDiff(diff);\n\t}\n\n\tnifly::Vector3 TransformDiffModelToMesh(const nifly::Vector3 &diff) {\n\t\treturn xformModelToMesh.ApplyTransformToDiff(diff);\n\t}\n\n\tfloat TransformDistMeshToModel(float dist) {\n\t\treturn xformMeshToModel.ApplyTransformToDist(dist);\n\t}\n\n\tfloat TransformDistModelToMesh(float dist) {\n\t\treturn xformModelToMesh.ApplyTransformToDist(dist);\n\t}\n\n\tstatic nifly::Vector3 ApplyMatrix4(const glm::mat4x4& mat, const nifly::Vector3& p) {\n\t\tglm::vec3 gp(mat * glm::vec4(p.x, p.y, p.z, 1.0f));\n\t\treturn nifly::Vector3(gp.x, gp.y, gp.z);\n\t}\n};\n"
  },
  {
    "path": "src/components/NormalGenLayers.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"NormalGenLayers.h\"\n#include \"../utils/ConfigurationManager.h\"\n#include <sstream>\n\nextern ConfigurationManager Config;\n\nvoid NormalGenLayer::LoadFromXML(tinyxml2::XMLElement* normalGenSource, std::vector<NormalGenLayer>& outLayers) {\n\ttinyxml2::XMLElement* layer = normalGenSource->FirstChildElement(\"NormalsLayer\");\n\tif (layer)\n\t\toutLayers.clear();\n\n\twhile (layer) {\n\t\tNormalGenLayer ngl;\n\t\tngl.layerName = layer->Attribute(\"name\");\n\n\t\tconst char* c = nullptr;\n\t\ttinyxml2::XMLElement* elem = layer->FirstChildElement(\"SourceFile\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tngl.sourceFileName = c ? c : \"\";\n\t\t\tConfig.ReplaceVars(ngl.sourceFileName);\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"FillColor\");\n\t\tif (elem) {\n\t\t\tstd::string v;\n\t\t\tc = elem->GetText();\n\t\t\tstd::stringstream val(c ? c : \"\");\n\t\t\tstd::getline(val, v, ' ');\n\t\t\tngl.fillColor[0] = std::stoi(v);\n\t\t\tstd::getline(val, v, ' ');\n\t\t\tngl.fillColor[1] = std::stoi(v);\n\t\t\tstd::getline(val, v, ' ');\n\t\t\tngl.fillColor[2] = std::stoi(v);\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"Resolution\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tngl.resolution = std::stoi(c ? c : \"\");\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"TangentSpace\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.isTangentSpace = (v == \"true\") ? true : false;\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"UseMeshNormalSource\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.useMeshNormalsSource = (v == \"true\") ? true : false;\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"MaskFile\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tngl.maskFileName = c ? c : \"\";\n\t\t}\n\n\t\tConfig.ReplaceVars(ngl.maskFileName);\n\n\t\telem = layer->FirstChildElement(\"XOffset\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tngl.xOffset = std::stoi(c ? c : \"\");\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"YOffset\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tngl.yOffset = std::stoi(c ? c : \"\");\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"ScaleToFit\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.scaleToResolution = (v == \"true\") ? true : false;\n\t\t}\n\n\t\telem = layer->FirstChildElement(\"SwapRG\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.swapRG = (v == \"true\") ? true : false;\n\t\t}\n\t\telem = layer->FirstChildElement(\"InvertRed\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.invertRed = (v == \"true\") ? true : false;\n\t\t}\n\t\telem = layer->FirstChildElement(\"InvertGreen\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.invertGreen = (v == \"true\") ? true : false;\n\t\t}\n\t\telem = layer->FirstChildElement(\"InvertBlue\");\n\t\tif (elem) {\n\t\t\tc = elem->GetText();\n\t\t\tstd::string v = c ? c : \"\";\n\t\t\tngl.invertBlue = (v == \"true\") ? true : false;\n\t\t}\n\n\t\toutLayers.push_back(ngl);\n\n\t\tlayer = layer->NextSiblingElement(\"NormalsLayer\");\n\t}\n}\n\nvoid NormalGenLayer::SaveToXML(tinyxml2::XMLElement* container, const std::vector<NormalGenLayer>& layers) {\n\tstd::string gamepath = Config[\"GameDataPath\"];\n\tstd::string relfn;\n\tfor (auto& l : layers) {\n\t\ttinyxml2::XMLElement* layerelem = container->GetDocument()->NewElement(\"NormalsLayer\");\n\t\tlayerelem->SetAttribute(\"name\", l.layerName.c_str());\n\n\t\ttinyxml2::XMLElement* elem = container->GetDocument()->NewElement(\"SourceFile\");\n\n\t\trelfn = l.sourceFileName;\n\t\tif (relfn.find(gamepath) != std::string::npos)\n\t\t\trelfn.replace(relfn.find(gamepath), gamepath.length(), \"%GameDataPath%\");\n\n\t\telem->SetText(relfn.c_str());\n\t\tlayerelem->InsertEndChild(elem);\n\n\t\tif (l.layerName == \"Background\") { // Background is a Special layer with limited properties.\n\n\t\t\telem = container->GetDocument()->NewElement(\"FillColor\");\n\t\t\tstd::string s = std::to_string((unsigned char)l.fillColor[0]) + \" \";\n\t\t\ts += std::to_string((unsigned char)l.fillColor[1]) + \" \";\n\t\t\ts += std::to_string((unsigned char)l.fillColor[2]);\n\t\t\telem->SetText(s.c_str());\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\n\t\t\telem = container->GetDocument()->NewElement(\"Resolution\");\n\t\t\telem->SetText(std::to_string(l.resolution).c_str());\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\t\t}\n\t\telse {\n\t\t\telem = container->GetDocument()->NewElement(\"TangentSpace\");\n\t\t\telem->SetText(l.isTangentSpace);\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\n\t\t\tif (l.useMeshNormalsSource) { // not outputting some default values\n\t\t\t\telem = container->GetDocument()->NewElement(\"UseMeshNormalSource\");\n\t\t\t\telem->SetText(true);\n\t\t\t\tlayerelem->InsertEndChild(elem);\n\t\t\t}\n\n\t\t\telem = container->GetDocument()->NewElement(\"MaskFile\");\n\t\t\trelfn = l.maskFileName;\n\t\t\tif (relfn.find(gamepath) != std::string::npos)\n\t\t\t\trelfn.replace(relfn.find(gamepath), gamepath.length(), \"%GameDataPath%\");\n\n\t\t\telem->SetText(relfn.c_str());\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\n\t\t\telem = container->GetDocument()->NewElement(\"XOffset\");\n\t\t\telem->SetText(std::to_string(l.xOffset).c_str());\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\n\t\t\telem = container->GetDocument()->NewElement(\"YOffset\");\n\t\t\telem->SetText(std::to_string(l.yOffset).c_str());\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\n\t\t\telem = container->GetDocument()->NewElement(\"ScaleToFit\");\n\t\t\telem->SetText(l.scaleToResolution);\n\n\t\t\tlayerelem->InsertEndChild(elem);\n\n\t\t\tif (l.swapRG) { // not outputting some default values\n\t\t\t\telem = container->GetDocument()->NewElement(\"SwapRG\");\n\t\t\t\telem->SetText(true);\n\t\t\t\tlayerelem->InsertEndChild(elem);\n\t\t\t}\n\t\t\tif (l.invertRed) { // not outputting some default values\n\t\t\t\telem = container->GetDocument()->NewElement(\"InvertRed\");\n\t\t\t\telem->SetText(true);\n\t\t\t\tlayerelem->InsertEndChild(elem);\n\t\t\t}\n\t\t\tif (l.invertGreen) { // not outputting some default values\n\t\t\t\telem = container->GetDocument()->NewElement(\"InvertGreen\");\n\t\t\t\telem->SetText(true);\n\t\t\t\tlayerelem->InsertEndChild(elem);\n\t\t\t}\n\t\t\tif (l.invertBlue) { // not outputting some default values\n\t\t\t\telem = container->GetDocument()->NewElement(\"InvertBlue\");\n\t\t\t\telem->SetText(true);\n\t\t\t\tlayerelem->InsertEndChild(elem);\n\t\t\t}\n\t\t}\n\t\tcontainer->InsertEndChild(layerelem);\n\t}\n}\n"
  },
  {
    "path": "src/components/NormalGenLayers.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include <string>\n#include <vector>\n\nclass NormalGenLayer {\npublic:\n\tstd::string layerName;\t\t// visual name of the layer -- the name in the dialog is internally managed to avoid conflicts\n\tstd::string sourceFileName; // source texture file name.  Accepts special wildcards %GameDataPath% and %bodyslidepath% on load, but stored as full path.\n\tstd::string maskFileName;\t// mask texture file name.   Accepts special wildcards %GameDataPath% and %bodyslidepath% on load, but stored as full path.\n\n\t// tangent or model space normal map?\n\t// Model space maps are composited by simply copying over top, applying the mask file, while tangent space perturbs the current normals\n\tbool isTangentSpace = true;\n\n\t// use unperturbed mesh normals as the source data.\n\t// This allows a layer to \"erase\" previous layer normals.\n\t// Ex:  An area of burned flesh needs skin pore detail to be gone, use an erase layer (this flag) and a mask to erase tertiary detail prior to layering the scar detail.\n\tbool useMeshNormalsSource = false;\n\n\t// resize source to full resolution of background, this is important for uvs to line up\n\tbool scaleToResolution = true;\n\n\t// UV offset to apply to the normals.\n\t// This only really works when a mask selects a small area of the mesh and you want to reposition the data, or it's a small file without being scaled.\n\tint xOffset = 0;\n\tint yOffset = 0;\n\n\tbool swapRG = false;\t  // Swap red/green channels in source map\n\tbool invertGreen = false; // Channel inverts   Green is commonly opposite between dx and opengl.\n\tbool invertBlue = false;\n\tbool invertRed = false;\n\n\t/* background layer special properties */\n\tuint8_t fillColor[3] = {126, 127, 255}; // A solid color to set the background to, if no original file is to be used as the background\n\tint resolution = 4096;\t\t\t\t\t// the resolution for the in memory texture information and, optionally, output data.\n\n\tNormalGenLayer() {}\n\n\tbool IsBackground() { return layerName == \"Background\"; }\n\n\tstatic void LoadFromXML(tinyxml2::XMLElement* normalGenSource, std::vector<NormalGenLayer>& outLayers);\n\tstatic void SaveToXML(tinyxml2::XMLElement* container, const std::vector<NormalGenLayer>& layers);\n};\n"
  },
  {
    "path": "src/components/PoseData.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PoseData.h\"\n#include \"Anim.h\"\n#include \"../utils/PlatformUtil.h\"\n\nbool PoseData::LoadElement(XMLElement* srcElement) {\n\tif (srcElement == nullptr)\n\t\treturn false;\n\n\tname = srcElement->Attribute(\"name\");\n\n\tXMLElement* boneElement = srcElement->FirstChildElement(\"Bone\");\n\twhile (boneElement) {\n\t\tPoseBoneData poseBoneData{};\n\t\tposeBoneData.name = boneElement->Attribute(\"name\");\n\t\tposeBoneData.rotation.x = boneElement->FloatAttribute(\"rotX\");\n\t\tposeBoneData.rotation.y = boneElement->FloatAttribute(\"rotY\");\n\t\tposeBoneData.rotation.z = boneElement->FloatAttribute(\"rotZ\");\n\t\tposeBoneData.translation.x = boneElement->FloatAttribute(\"transX\");\n\t\tposeBoneData.translation.y = boneElement->FloatAttribute(\"transY\");\n\t\tposeBoneData.translation.z = boneElement->FloatAttribute(\"transZ\");\n\t\tposeBoneData.scale = boneElement->FloatAttribute(\"scale\", 1.0f);\n\t\tboneData.push_back(poseBoneData);\n\n\t\tboneElement = boneElement->NextSiblingElement(\"Bone\");\n\t}\n\n\treturn true;\n}\n\nvoid PoseData::WriteElement(XMLElement* element, bool append) const {\n\tif (!append)\n\t\telement->DeleteChildren();\n\n\tfor (auto& bone : boneData) {\n\t\tXMLElement* newElement = element->GetDocument()->NewElement(\"Bone\");\n\t\tnewElement = element->InsertEndChild(newElement)->ToElement();\n\t\tnewElement->SetAttribute(\"name\", bone.name.c_str());\n\t\tnewElement->SetAttribute(\"rotX\", bone.rotation.x);\n\t\tnewElement->SetAttribute(\"rotY\", bone.rotation.y);\n\t\tnewElement->SetAttribute(\"rotZ\", bone.rotation.z);\n\t\tnewElement->SetAttribute(\"transX\", bone.translation.x);\n\t\tnewElement->SetAttribute(\"transY\", bone.translation.y);\n\t\tnewElement->SetAttribute(\"transZ\", bone.translation.z);\n\t\tif (bone.scale != 1.0f)\n\t\t\tnewElement->SetAttribute(\"scale\", bone.scale);\n\t}\n}\n\nint PoseDataCollection::LoadData(const std::string& basePath) {\n\tposeData.clear();\n\n\twxArrayString files;\n\twxDir::GetAllFiles(basePath, &files, \"*.xml\");\n\n\tfor (auto& file : files) {\n\t\tPoseDataFile poseDataFile(file.ToUTF8().data());\n\n\t\tstd::vector<PoseData> poseDataEntries;\n\t\tposeDataFile.GetData(poseDataEntries);\n\n\t\tfor (auto& pd : poseDataEntries)\n\t\t\tposeData.push_back(pd);\n\t}\n\n\treturn 0;\n}\n\nPoseData* PoseDataCollection::AddPose(PoseData pose) {\n\tposeData.push_back(std::move(pose));\n\treturn &poseData.back();\n}\n\nvoid PoseData::ApplyToSkeleton() const {\n\tusing namespace nifly;\n\n\tstd::vector<std::string> bones;\n\tAnimSkeleton::getInstance().GetBoneNames(bones);\n\n\tfor (const auto& boneName : bones) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (!bone)\n\t\t\tcontinue;\n\n\t\tauto it = std::find_if(boneData.begin(), boneData.end(),\n\t\t\t[&boneName](const PoseBoneData& bd) { return bd.name == boneName; });\n\n\t\tif (it != boneData.end()) {\n\t\t\tif (absoluteLocal) {\n\t\t\t\tMatTransform frameLocal;\n\t\t\t\tframeLocal.translation = it->translation;\n\t\t\t\tframeLocal.rotation = RotVecToMat(it->rotation);\n\t\t\t\tframeLocal.scale = it->scale;\n\n\t\t\t\tMatTransform delta = bone->xformToParent.InverseTransform().ComposeTransforms(frameLocal);\n\t\t\t\tbone->poseRotVec = RotMatToVec(delta.rotation);\n\t\t\t\tbone->poseTranVec = delta.translation;\n\t\t\t\tbone->poseScale = (delta.scale != 0.0f) ? delta.scale : 1.0f;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tbone->poseRotVec = it->rotation;\n\t\t\t\tbone->poseTranVec = it->translation;\n\t\t\t\tbone->poseScale = it->scale;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tbone->poseRotVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseTranVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseScale = 1.0f;\n\t\t}\n\n\t\tbone->UpdatePoseTransform();\n\t}\n}\n\n\nPoseDataFile::PoseDataFile(const std::string& srcFileName) {\n\troot = nullptr;\n\terror = 0;\n\tOpen(srcFileName);\n}\n\nvoid PoseDataFile::Open(const std::string& srcFileName) {\n\tfileName = srcFileName;\n\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(srcFileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn;\n#else\n\tfp = fopen(srcFileName.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn;\n\t}\n#endif\n\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn;\n\n\tdoc.SetUserData(&fileName);\n\troot = doc.FirstChildElement(\"PoseData\");\n\tif (!root) {\n\t\terror = 2;\n\t\treturn;\n\t}\n\n\terror = 0;\n}\n\nvoid PoseDataFile::New(const std::string& newFileName) {\n\tif (root)\n\t\treturn;\n\n\tClear();\n\n\tXMLElement* newElement = doc.NewElement(\"PoseData\");\n\troot = doc.InsertEndChild(newElement)->ToElement();\n\n\tfileName = newFileName;\n\tdoc.SetUserData(&fileName);\n\n\terror = 0;\n}\n\nvoid PoseDataFile::Clear() {\n\tdoc.Clear();\n\troot = nullptr;\n\terror = 0;\n}\n\nvoid PoseDataFile::Rename(const std::string& newFileName) {\n\tfileName = newFileName;\n}\n\nint PoseDataFile::SetData(const std::vector<PoseData>& data) {\n\troot->DeleteChildren();\n\n\tfor (auto& pd : data) {\n\t\tXMLElement* newElement = doc.NewElement(\"Pose\");\n\t\tXMLElement* element = root->InsertEndChild(newElement)->ToElement();\n\t\telement->SetAttribute(\"name\", pd.name.c_str());\n\t\tpd.WriteElement(element);\n\t}\n\n\treturn 0;\n}\n\nbool PoseDataFile::Save() {\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (error || !fp)\n\t\treturn false;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn false;\n\t}\n#endif\n\n\tdoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = doc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\terror = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (error)\n\t\treturn false;\n\n\treturn true;\n}\n\nint PoseDataFile::GetData(std::vector<PoseData>& outData) {\n\tXMLElement* poseElement = root->FirstChildElement(\"Pose\");\n\twhile (poseElement) {\n\t\tPoseData poseData{};\n\t\tposeData.LoadElement(poseElement);\n\t\toutData.push_back(poseData);\n\n\t\tposeElement = poseElement->NextSiblingElement(\"Pose\");\n\t}\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/components/PoseData.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include \"Object3d.hpp\"\n\nclass AnimBone;\n\n#include <deque>\n#include <map>\n#include <set>\n#include <unordered_set>\n#include <vector>\n#include <wx/dir.h>\n\nusing namespace tinyxml2;\n\nstruct PoseBoneData {\n\tstd::string name;\n\tnifly::Vector3 rotation;\n\tnifly::Vector3 translation;\n\tfloat scale;\n};\n\nclass PoseData {\npublic:\n\tstd::string name;\n\tstd::vector<PoseBoneData> boneData;\n\t// When true, the pose was loaded from a read-only source (e.g. a SAM\n\t// YAML file) and must not be modified or deleted by Outfit Studio.\n\tbool readOnly = false;\n\t// When true, rotation/translation/scale in boneData are the absolute\n\t// local-to-parent transform at frame 0 (as stored by Havok HKX), not an\n\t// Outfit-Studio-style delta on top of the bind pose. The caller must\n\t// convert to a delta against the live skeleton's xformToParent before\n\t// assigning poseRotVec/poseTranVec/poseScale.\n\tbool absoluteLocal = false;\n\n\tPoseData() {}\n\n\tPoseData(const std::string& name) { this->name = name; }\n\n\tPoseData(const std::string& name, const std::vector<PoseBoneData>& boneData) {\n\t\tthis->name = name;\n\t\tthis->boneData = boneData;\n\t}\n\n\tPoseData(XMLElement* srcElement) { LoadElement(srcElement); }\n\n\tbool LoadElement(XMLElement* srcElement);\n\tvoid WriteElement(XMLElement* element, bool append = false) const;\n\n\t// Applies this pose to all named bones in the skeleton. For each bone,\n\t// if a matching PoseBoneData entry exists, sets poseRotVec/poseTranVec/\n\t// poseScale (converting from absolute local-to-parent when absoluteLocal\n\t// is set). Bones without a matching entry are reset to the identity pose.\n\t// Calls UpdatePoseTransform on every bone.\n\tvoid ApplyToSkeleton() const;\n};\n\nclass PoseDataCollection {\npublic:\n\t// Stored as a deque so that pointers/references to individual entries\n\t// remain stable across subsequent insertions. The combobox in Outfit\n\t// Studio holds raw PoseData* in its ClientData; with a vector every\n\t// push_back would invalidate every previously stored pointer.\n\tstd::deque<PoseData> poseData;\n\n\t// Loads all pose data in the specified folder.\n\tint LoadData(const std::string& basePath);\n\n\t// Appends a pose to the collection and returns a stable pointer to it.\n\tPoseData* AddPose(PoseData pose);\n\n\t// Loads all SAM pose YAML files from the specified folder (recursively).\n\t// The pose name is derived from the file name (without extension) and is\n\t// prefixed with namePrefix. Entries are appended to poseData.\n\tint LoadYamlData(const std::string& basePath, const std::string& namePrefix);\n\n\t// Loads all SAF pose JSON files from the specified folder (recursively).\n\t// SAF is the Fallout 4 companion of SAM, using a different on-disk format\n\t// (JSON instead of YAML) with yaw/pitch/roll rotation fields in degrees.\n\t// The pose name is derived from the file name (without extension) and is\n\t// prefixed with namePrefix. Entries are appended to poseData.\n\tint LoadJsonData(const std::string& basePath, const std::string& namePrefix);\n\n\t// Loads a single pose from a Havok HKX skeleton + animation pair.\n\t// Both files are parsed natively (no external tools required) for all\n\t// supported variants: Skyrim LE, Skyrim SE/VR and Fallout 4. The bones\n\t// parsed from skeletonHkxPath are matched to the animation's transform\n\t// tracks via the animation binding (when present), otherwise positionally.\n\t// `frameIndex` selects which frame of the animation to extract. On\n\t// success, outPose.boneData is populated and absoluteLocal is set.\n\t// Returns false if either file cannot be parsed.\n\tstatic bool LoadHkxPose(const std::string& skeletonHkxPath, const std::string& animHkxPath, PoseData& outPose, uint32_t frameIndex = 0);\n};\n\nclass PoseDataFile {\n\tXMLDocument doc;\n\tXMLElement* root = nullptr;\n\tint error = 0;\n\npublic:\n\tstd::string fileName;\n\n\tPoseDataFile() {}\n\tPoseDataFile(const std::string& srcFileName);\n\t~PoseDataFile() {}\n\n\tbool fail() { return error != 0; }\n\tint GetError() { return error; }\n\n\t// Loads the XML document and identifies included pose. On a failure, sets the internal error value.\n\tvoid Open(const std::string& srcFileName);\n\n\t// Creates a new empty pose document structure, ready to add new pose to.\n\tvoid New(const std::string& newFileName);\n\n\t// Clears all data of the file.\n\tvoid Clear();\n\n\t// Changes the internal file name. The XML file isn't saved until the Save() function is used.\n\t// Note the original file name is not changed. This method allows you to save a pose as a new file without altering the original.\n\tvoid Rename(const std::string& newFileName);\n\n\t// Updates data in the XML document with the provided information.\n\tint SetData(const std::vector<PoseData>& data);\n\n\t// Writes the xml file using the internal fileName (use Rename() to change the name).\n\tbool Save();\n\n\t// Reads data of the pose element.\n\tint GetData(std::vector<PoseData>& outData);\n};\n"
  },
  {
    "path": "src/components/PoseDataHkx.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PoseData.h\"\n#include \"../files/HkxFile.h\"\n\n#include <algorithm>\n#include <cmath>\n\nnamespace {\n// Convert a unit quaternion (w, x, y, z) to a standard column-vector\n// rotation matrix (R such that R*v rotates v by the quaternion). This\n// matches what nifly stores in AnimBone::xformToParent.rotation (populated\n// directly from the NIF file's 3x3 rotation matrix, which is also a\n// standard column-vector rotation). It does NOT match the internal\n// convention of nifly::RotVecToMat / RotMatToVec, but those are only used\n// to serialize a rotation to/from a rotation-vector representation; when\n// combined via MatTransform::ComposeTransforms the stored matrices are\n// multiplied as standard rotations, so the two sides of the composition\n// must agree on that convention.\nstatic nifly::Matrix3 QuatToNiflyMat(float qw, float qx, float qy, float qz) {\n\tfloat w = qw, x = qx, y = qy, z = qz;\n\n\tfloat len = std::sqrt(w * w + x * x + y * y + z * z);\n\tif (len <= 1e-8f)\n\t\treturn nifly::Matrix3();\n\tw /= len;\n\tx /= len;\n\ty /= len;\n\tz /= len;\n\n\tconst float xx = x * x;\n\tconst float yy = y * y;\n\tconst float zz = z * z;\n\tconst float xy = x * y;\n\tconst float xz = x * z;\n\tconst float yz = y * z;\n\tconst float wx = w * x;\n\tconst float wy = w * y;\n\tconst float wz = w * z;\n\n\tnifly::Matrix3 m;\n\tm[0][0] = 1.0f - 2.0f * (yy + zz);\n\tm[0][1] = 2.0f * (xy - wz);\n\tm[0][2] = 2.0f * (xz + wy);\n\tm[1][0] = 2.0f * (xy + wz);\n\tm[1][1] = 1.0f - 2.0f * (xx + zz);\n\tm[1][2] = 2.0f * (yz - wx);\n\tm[2][0] = 2.0f * (xz - wy);\n\tm[2][1] = 2.0f * (yz + wx);\n\tm[2][2] = 1.0f - 2.0f * (xx + yy);\n\treturn m;\n}\n} // namespace\n\nbool PoseDataCollection::LoadHkxPose(const std::string& skeletonHkxPath, const std::string& animHkxPath, PoseData& outPose, uint32_t frameIndex) {\n\tHKX::File skelFile;\n\tif (!skelFile.Load(skeletonHkxPath, nullptr) || skelFile.GetSkeletons().empty())\n\t\treturn false;\n\n\tHKX::File animFile;\n\tif (!animFile.Load(animHkxPath, nullptr) || animFile.GetAnimations().empty())\n\t\treturn false;\n\n\tconst HKX::Skeleton& skel = skelFile.GetSkeletons().front();\n\tconst HKX::Animation& anim = animFile.GetAnimations().front();\n\n\tif (anim.numTransformTracks == 0 || anim.numFrames == 0)\n\t\treturn false;\n\n\tuint32_t frame = std::min(frameIndex, anim.numFrames - 1);\n\n\toutPose.boneData.clear();\n\toutPose.absoluteLocal = true;\n\n\tconst size_t nTracks = anim.numTransformTracks;\n\tconst size_t nBones = skel.bones.size();\n\tconst auto& binding = anim.binding.transformTrackToBoneIndices;\n\n\toutPose.boneData.reserve(nTracks);\n\n\tfor (size_t track = 0; track < nTracks; ++track) {\n\t\t// Resolve the bone this track addresses. If a binding map is\n\t\t// provided, use it; otherwise fall back to positional matching.\n\t\tsize_t boneIdx;\n\t\tif (!binding.empty() && track < binding.size()) {\n\t\t\tint16_t bi = binding[track];\n\t\t\tif (bi < 0 || size_t(bi) >= nBones)\n\t\t\t\tcontinue;\n\t\t\tboneIdx = size_t(bi);\n\t\t}\n\t\telse {\n\t\t\tif (track >= nBones)\n\t\t\t\tbreak;\n\t\t\tboneIdx = track;\n\t\t}\n\n\t\tconst HKX::Transform& xf = anim.At(frame, uint32_t(track));\n\n\t\tPoseBoneData bd{};\n\t\tbd.name = skel.bones[boneIdx].name;\n\t\tbd.translation = nifly::Vector3(xf.translation[0], xf.translation[1], xf.translation[2]);\n\t\t// HKX quaternion is xyzw; QuatToNiflyMat takes (w, x, y, z).\n\t\tbd.rotation = nifly::RotMatToVec(QuatToNiflyMat(xf.rotation[3], xf.rotation[0], xf.rotation[1], xf.rotation[2]));\n\t\tbd.scale = (xf.scale[0] != 0.0f) ? xf.scale[0] : 1.0f;\n\t\toutPose.boneData.push_back(std::move(bd));\n\t}\n\n\treturn !outPose.boneData.empty();\n}\n"
  },
  {
    "path": "src/components/PoseDataJson.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PoseData.h\"\n#include \"../utils/PlatformUtil.h\"\n\n#include <wx/filename.h>\n\n#include <nlohmann/json.hpp>\n\n#include <cmath>\n#include <fstream>\n\nnamespace {\n// SAF pose JSON reader modeled after ScreenArcherMenu's SAF/io.cpp\n// (ReadTransformJson / LoadPosePath). A SAF pose file is a JSON document\n// containing:\n//   - \"version\" (unsigned int, optional; 0 means legacy transposed format)\n//   - \"skeleton\", \"name\" (strings, ignored here)\n//   - \"transforms\" (object mapping bone name -> transform object)\n// Each transform object has the optional fields x, y, z (translation),\n// yaw, pitch, roll (rotation Euler angles in degrees) and scale (float,\n// default 1.0). If the file has no \"transforms\" key, the root object is\n// treated as the bone map directly (older files).\n\nstatic float GetJsonFloat(const nlohmann::json& obj, const char* key, float defaultValue = 0.0f) {\n\tif (!obj.is_object())\n\t\treturn defaultValue;\n\tauto it = obj.find(key);\n\tif (it == obj.end())\n\t\treturn defaultValue;\n\ttry {\n\t\tif (it->is_number())\n\t\t\treturn it->get<float>();\n\t\tif (it->is_string())\n\t\t\treturn std::stof(it->get<std::string>());\n\t}\n\tcatch (...) {\n\t}\n\treturn defaultValue;\n}\n\n// Convert SAF yaw/pitch/roll (degrees) to an axis-angle rotation vector,\n// reproducing the effective rotation that SAF applies via RotateMatrix().\n//\n// SAF's NiMatrix43::data[col][row] is column-major. RotateMatrix() multiplies\n// as M*pt where M[row][col] = data[col][row]. nifly's Matrix3 is row-major,\n// so we need m[row][col] = data[col][row] to get the same rotation.\n//\n// Version 0 (legacy):  MatrixFromDegree() calls\n//   MatrixFromEulerYPRTransposed(matrix, -x*D2R, -y*D2R, -z*D2R)\n//   which writes data[row][col] = formula (standard indexing).\n//   m[row][col] = data[col][row] = formula[col][row]  → transposed copy.\n//\n// Version >= 1:  MatrixFromPose() calls\n//   MatrixFromEulerYPR(matrix, x*D2R, y*D2R, z*D2R)\n//   which writes data[col][row] = formula (swapped indexing).\n//   m[row][col] = data[col][row] = formula[row][col]  → direct copy.\nstatic nifly::Vector3 SafEulerToRotVec(float yawDeg, float pitchDeg, float rollDeg, unsigned int version) {\n\tconst float deg2rad = 3.14159265358979323846f / 180.0f;\n\n\tfloat x = yawDeg * deg2rad;\n\tfloat y = pitchDeg * deg2rad;\n\tfloat z = rollDeg * deg2rad;\n\n\tif (version == 0) {\n\t\t// Legacy MatrixFromDegree -> MatrixFromEulerYPRTransposed with negated angles.\n\t\tx = -x;\n\t\ty = -y;\n\t\tz = -z;\n\t}\n\n\tfloat sinX = std::sin(x);\n\tfloat cosX = std::cos(x);\n\tfloat sinY = std::sin(y);\n\tfloat cosY = std::cos(y);\n\tfloat sinZ = std::sin(z);\n\tfloat cosZ = std::cos(z);\n\n\t// The nine trig expressions are identical between both SAF functions;\n\t// only the data[i][j] index mapping differs (see comment above). The\n\t// version 0 branch transposes the off-diagonal assignments accordingly.\n\tnifly::Matrix3 m;\n\tif (version == 0) {\n\t\tm[0][0] = cosY * cosZ;\n\t\tm[0][1] = sinX * sinY * cosZ + sinZ * cosX;\n\t\tm[0][2] = sinX * sinZ - cosX * sinY * cosZ;\n\t\tm[1][0] = -cosY * sinZ;\n\t\tm[1][1] = cosX * cosZ - sinX * sinY * sinZ;\n\t\tm[1][2] = cosX * sinY * sinZ + sinX * cosZ;\n\t\tm[2][0] = sinY;\n\t\tm[2][1] = -sinX * cosY;\n\t\tm[2][2] = cosX * cosY;\n\t}\n\telse {\n\t\tm[0][0] = cosY * cosZ;\n\t\tm[0][1] = -cosY * sinZ;\n\t\tm[0][2] = sinY;\n\t\tm[1][0] = sinX * sinY * cosZ + sinZ * cosX;\n\t\tm[1][1] = cosX * cosZ - sinX * sinY * sinZ;\n\t\tm[1][2] = -sinX * cosY;\n\t\tm[2][0] = sinX * sinZ - cosX * sinY * cosZ;\n\t\tm[2][1] = cosX * sinY * sinZ + sinX * cosZ;\n\t\tm[2][2] = cosX * cosY;\n\t}\n\n\treturn nifly::RotMatToVec(m);\n}\n\nstatic bool ParseSafPoseJson(const std::string& filePath, PoseData& outPose) {\n\tnlohmann::json root;\n\ttry {\n#ifdef _WINDOWS\n\t\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath);\n\t\tstd::ifstream ifs(winFileName.c_str());\n#else\n\t\tstd::ifstream ifs(filePath.c_str());\n#endif\n\t\tif (!ifs.is_open())\n\t\t\treturn false;\n\t\troot = nlohmann::json::parse(ifs, nullptr, false, true);\n\t}\n\tcatch (...) {\n\t\treturn false;\n\t}\n\n\tif (root.is_null() || root.is_discarded() || !root.is_object())\n\t\treturn false;\n\n\tunsigned int version = 0;\n\tauto versionIt = root.find(\"version\");\n\tif (versionIt != root.end() && versionIt->is_number_unsigned()) {\n\t\ttry {\n\t\t\tversion = versionIt->get<unsigned int>();\n\t\t}\n\t\tcatch (...) {\n\t\t\tversion = 0;\n\t\t}\n\t}\n\n\t// Newer files wrap bones in a \"transforms\" object. Older files put the\n\t// bone map at the root directly.\n\tconst nlohmann::json* transforms = &root;\n\tauto transformsIt = root.find(\"transforms\");\n\tif (transformsIt != root.end() && transformsIt->is_object())\n\t\ttransforms = &(*transformsIt);\n\n\tif (!transforms->is_object())\n\t\treturn false;\n\n\ttry {\n\t\tfor (auto it = transforms->begin(); it != transforms->end(); ++it) {\n\t\t\tif (!it.value().is_object())\n\t\t\t\tcontinue;\n\n\t\t\t// Skip non-bone metadata keys that appear on older root-level files.\n\t\t\tconst std::string& boneName = it.key();\n\t\t\tif (boneName == \"version\" || boneName == \"skeleton\" || boneName == \"name\" || boneName == \"type\")\n\t\t\t\tcontinue;\n\n\t\t\tPoseBoneData bd{};\n\t\t\tbd.name = boneName;\n\t\t\tbd.translation.x = GetJsonFloat(it.value(), \"x\");\n\t\t\tbd.translation.y = GetJsonFloat(it.value(), \"y\");\n\t\t\tbd.translation.z = GetJsonFloat(it.value(), \"z\");\n\t\t\tfloat yawDeg = GetJsonFloat(it.value(), \"yaw\");\n\t\t\tfloat pitchDeg = GetJsonFloat(it.value(), \"pitch\");\n\t\t\tfloat rollDeg = GetJsonFloat(it.value(), \"roll\");\n\t\t\tbd.rotation = SafEulerToRotVec(yawDeg, pitchDeg, rollDeg, version);\n\t\t\tbd.scale = GetJsonFloat(it.value(), \"scale\", 1.0f);\n\n\t\t\toutPose.boneData.push_back(std::move(bd));\n\t\t}\n\t}\n\tcatch (...) {\n\t\treturn false;\n\t}\n\n\treturn !outPose.boneData.empty();\n}\n} // namespace\n\nint PoseDataCollection::LoadJsonData(const std::string& basePath, const std::string& namePrefix) {\n\twxString wxBase = wxString::FromUTF8(basePath.c_str());\n\tif (!wxDirExists(wxBase))\n\t\treturn 0;\n\n\twxArrayString files;\n\twxDir::GetAllFiles(wxBase, &files, \"*.json\", wxDIR_FILES);\n\n\tint loaded = 0;\n\tfor (auto& file : files) {\n\t\tPoseData pd;\n\t\tpd.readOnly = true;\n\t\tpd.absoluteLocal = true;\n\t\twxFileName fn(file);\n\t\tpd.name = namePrefix + std::string(fn.GetName().ToUTF8().data());\n\n\t\tif (ParseSafPoseJson(file.ToUTF8().data(), pd)) {\n\t\t\tAddPose(std::move(pd));\n\t\t\t++loaded;\n\t\t}\n\t}\n\n\treturn loaded;\n}\n"
  },
  {
    "path": "src/components/PoseDataYaml.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PoseData.h\"\n#include \"../utils/PlatformUtil.h\"\n\n#include <wx/filename.h>\n\n#include <fkYAML/node.hpp>\n\n#include <cmath>\n#include <fstream>\n\nnamespace {\n// SAM pose YAML reader built on top of the fkYAML single-header library.\n// The file format produced by ScreenArcherMenu is a small top-level mapping\n// with at least a `transforms:` node. Each entry in `transforms` is keyed by\n// a bone name and maps to a mapping of the scalar properties tx, ty, tz,\n// rx, ry, rz, s. Other top-level keys of interest are `type` (must be\n// `rltv` for relative poses) and `rotation` (Euler order, e.g. `exyz`).\n\nstatic nifly::Matrix3 MakeAxisRotation(char axis, float angleRad) {\n\tfloat c = std::cos(angleRad);\n\tfloat s = std::sin(angleRad);\n\tswitch (axis) {\n\tcase 'x':\n\tcase 'X':\n\t\treturn nifly::Matrix3(1.0f, 0.0f, 0.0f, 0.0f, c, -s, 0.0f, s, c);\n\tcase 'y':\n\tcase 'Y':\n\t\treturn nifly::Matrix3(c, 0.0f, s, 0.0f, 1.0f, 0.0f, -s, 0.0f, c);\n\tcase 'z':\n\tcase 'Z':\n\t\treturn nifly::Matrix3(c, -s, 0.0f, s, c, 0.0f, 0.0f, 0.0f, 1.0f);\n\t}\n\treturn nifly::Matrix3();\n}\n\n// Convert Euler angles (degrees) to an axis-angle rotation vector.\n// The rotation order string is the SAM convention, e.g. \"exyz\" (leading\n// optional 'e' for Euler). The three axis letters specify the intrinsic\n// rotation order; the resulting matrix is R_axis1 * R_axis2 * R_axis3.\nstatic nifly::Vector3 SamEulerToRotVec(float rxDeg, float ryDeg, float rzDeg, const std::string& order) {\n\tstd::string ord = order;\n\tif (!ord.empty() && (ord.front() == 'e' || ord.front() == 'E'))\n\t\tord.erase(0, 1);\n\tif (ord.size() < 3)\n\t\tord = \"xyz\";\n\n\tconst float deg2rad = 3.14159265358979323846f / 180.0f;\n\tnifly::Matrix3 mats[3];\n\tfor (int i = 0; i < 3; ++i) {\n\t\tchar a = ord[i];\n\t\tfloat ang = 0.0f;\n\t\tif (a == 'x' || a == 'X')\n\t\t\tang = rxDeg * deg2rad;\n\t\telse if (a == 'y' || a == 'Y')\n\t\t\tang = ryDeg * deg2rad;\n\t\telse if (a == 'z' || a == 'Z')\n\t\t\tang = rzDeg * deg2rad;\n\t\tmats[i] = MakeAxisRotation(a, ang);\n\t}\n\n\tnifly::Matrix3 m = mats[0] * mats[1] * mats[2];\n\treturn nifly::RotMatToVec(m);\n}\n\nstatic float GetYamlFloat(const fkyaml::node& map, const char* key, float defaultValue = 0.0f) {\n\tif (!map.is_mapping() || !map.contains(key))\n\t\treturn defaultValue;\n\tconst fkyaml::node& n = map[key];\n\ttry {\n\t\treturn n.get_value<float>();\n\t}\n\tcatch (...) {\n\t\treturn defaultValue;\n\t}\n}\n\nstatic std::string GetYamlString(const fkyaml::node& map, const char* key, const std::string& defaultValue = {}) {\n\tif (!map.is_mapping() || !map.contains(key))\n\t\treturn defaultValue;\n\tconst fkyaml::node& n = map[key];\n\ttry {\n\t\treturn n.get_value<std::string>();\n\t}\n\tcatch (...) {\n\t\treturn defaultValue;\n\t}\n}\n\nstatic bool ParseSamPoseYaml(const std::string& filePath, PoseData& outPose) {\n\tfkyaml::node root;\n\ttry {\n#ifdef _WINDOWS\n\t\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath);\n\t\tstd::ifstream ifs(winFileName.c_str());\n#else\n\t\tstd::ifstream ifs(filePath.c_str());\n#endif\n\t\tif (!ifs.is_open())\n\t\t\treturn false;\n\t\troot = fkyaml::node::deserialize(ifs);\n\t}\n\tcatch (...) {\n\t\treturn false;\n\t}\n\n\tif (!root.is_mapping())\n\t\treturn false;\n\n\t// SAM relative transforms map directly to Outfit Studio's relative pose\n\t// concept. If a file specifies something else (e.g. absolute), skip it\n\t// to avoid producing wrong results.\n\tstd::string poseType = GetYamlString(root, \"type\");\n\tif (!poseType.empty() && poseType != \"rltv\")\n\t\treturn false;\n\n\tstd::string rotationOrder = GetYamlString(root, \"rotation\", \"exyz\");\n\n\tif (!root.contains(\"transforms\"))\n\t\treturn false;\n\n\tconst fkyaml::node& transforms = root[\"transforms\"];\n\tif (!transforms.is_mapping())\n\t\treturn false;\n\n\ttry {\n\t\tfor (auto kv : transforms.map_items()) {\n\t\t\tconst fkyaml::node& bone = kv.value();\n\t\t\tif (!bone.is_mapping())\n\t\t\t\tcontinue;\n\n\t\t\tPoseBoneData bd{};\n\t\t\tbd.name = kv.key().get_value<std::string>();\n\t\t\tbd.translation.x = GetYamlFloat(bone, \"tx\");\n\t\t\tbd.translation.y = GetYamlFloat(bone, \"ty\");\n\t\t\tbd.translation.z = GetYamlFloat(bone, \"tz\");\n\t\t\tfloat rxDeg = GetYamlFloat(bone, \"rx\");\n\t\t\tfloat ryDeg = GetYamlFloat(bone, \"ry\");\n\t\t\tfloat rzDeg = GetYamlFloat(bone, \"rz\");\n\t\t\tbd.rotation = SamEulerToRotVec(rxDeg, ryDeg, rzDeg, rotationOrder);\n\t\t\tbd.scale = GetYamlFloat(bone, \"s\", 1.0f);\n\n\t\t\toutPose.boneData.push_back(std::move(bd));\n\t\t}\n\t}\n\tcatch (...) {\n\t\treturn false;\n\t}\n\n\treturn !outPose.boneData.empty();\n}\n} // namespace\n\nint PoseDataCollection::LoadYamlData(const std::string& basePath, const std::string& namePrefix) {\n\twxString wxBase = wxString::FromUTF8(basePath.c_str());\n\tif (!wxDirExists(wxBase))\n\t\treturn 0;\n\n\twxArrayString files;\n\twxDir::GetAllFiles(wxBase, &files, \"*.yaml\", wxDIR_FILES);\n\twxDir::GetAllFiles(wxBase, &files, \"*.yml\", wxDIR_FILES);\n\n\tint loaded = 0;\n\tfor (auto& file : files) {\n\t\tPoseData pd;\n\t\tpd.readOnly = true;\n\t\twxFileName fn(file);\n\t\tpd.name = namePrefix + std::string(fn.GetName().ToUTF8().data());\n\n\t\tif (ParseSamPoseYaml(file.ToUTF8().data(), pd)) {\n\t\t\tAddPose(std::move(pd));\n\t\t\t++loaded;\n\t\t}\n\t}\n\n\treturn loaded;\n}\n"
  },
  {
    "path": "src/components/RefTemplates.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"RefTemplates.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"../utils/StringStuff.h\"\n\nint RefTemplateCollection::Load(const std::string& basePath) {\n\trefTemplates.clear();\n\n\twxArrayString files;\n\twxDir::GetAllFiles(basePath, &files, \"*.xml\");\n\n\tfor (auto& file : files) {\n\t\tRefTemplateFile templateFile(file.ToUTF8().data());\n\t\tstd::vector<std::string> templates;\n\t\ttemplateFile.GetNames(templates);\n\t\tfor (auto& t : templates) {\n\t\t\tRefTemplate refTemplate;\n\t\t\ttemplateFile.Get(t, refTemplate);\n\t\t\trefTemplates.push_back(std::move(refTemplate));\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint RefTemplateCollection::GetAll(std::vector<RefTemplate>& outAppend) {\n\tint count = 0;\n\n\tfor (auto& rt : refTemplates) {\n\t\toutAppend.emplace_back(rt);\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n\nint RefTemplate::Load(XMLElement* srcElement) {\n\tif (srcElement == nullptr)\n\t\treturn 1;\n\n\tname = srcElement->GetText();\n\n\tif (srcElement->Attribute(\"sourcefile\"))\n\t\tsource = ToOSSlashes(srcElement->Attribute(\"sourcefile\"));\n\n\tif (srcElement->Attribute(\"set\"))\n\t\tset = srcElement->Attribute(\"set\");\n\n\tif (srcElement->Attribute(\"shape\"))\n\t\tshape = srcElement->Attribute(\"shape\");\n\n\tif (srcElement->Attribute(\"loadAll\"))\n\t\tloadAll = srcElement->BoolAttribute(\"loadAll\");\n\n\tstd::string* fileName = static_cast<std::string*>(srcElement->GetDocument()->GetUserData());\n\tsourceFiles.push_back(*fileName);\n\n\treturn 0;\n}\n\nRefTemplateFile::RefTemplateFile(const std::string& srcFileName) {\n\troot = nullptr;\n\terror = 0;\n\tOpen(srcFileName);\n}\n\nvoid RefTemplateFile::Open(const std::string& srcFileName) {\n\tfileName = srcFileName;\n\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(srcFileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn;\n#else\n\tfp = fopen(srcFileName.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn;\n\t}\n#endif\n\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn;\n\n\tdoc.SetUserData(&fileName);\n\troot = doc.FirstChildElement(\"RefTemplates\");\n\tif (!root) {\n\t\terror = 2;\n\t\treturn;\n\t}\n\n\tXMLElement* element = root->FirstChildElement(\"Template\");\n\twhile (element) {\n\t\tauto refTemplate = std::make_pair(element->GetText(), element);\n\t\trefTemplatesInFile.push_back(refTemplate);\n\t\telement = element->NextSiblingElement(\"Template\");\n\t}\n\tif (refTemplatesInFile.empty()) {\n\t\terror = 3;\n\t\treturn;\n\t}\n\n\terror = 0;\n}\n\nvoid RefTemplateFile::Rename(const std::string& newFileName) {\n\tfileName = newFileName;\n}\n\nint RefTemplateFile::GetNames(std::vector<std::string>& outNames, bool append, bool unique) {\n\tstd::unordered_set<std::string> existingNames;\n\tif (!append)\n\t\toutNames.clear();\n\n\tif (unique)\n\t\texistingNames.insert(outNames.begin(), outNames.end());\n\n\tfor (auto& rt : refTemplatesInFile) {\n\t\tif (unique && existingNames.find(rt.first) != existingNames.end())\n\t\t\tcontinue;\n\t\telse if (unique)\n\t\t\texistingNames.insert(rt.first);\n\n\t\toutNames.push_back(rt.first);\n\t}\n\treturn 0;\n}\n\nbool RefTemplateFile::Has(const std::string& queryName) {\n\tauto tmpl = std::find_if(refTemplatesInFile.begin(), refTemplatesInFile.end(), [&queryName](const std::pair<std::string, XMLElement*>& rt) { return rt.first == queryName; });\n\tif (tmpl != refTemplatesInFile.end())\n\t\treturn true;\n\n\treturn false;\n}\n\nint RefTemplateFile::GetAll(std::vector<RefTemplate>& outAppend) {\n\tint count = 0;\n\n\tfor (auto& rt : refTemplatesInFile) {\n\t\tRefTemplate refTemplate;\n\t\trefTemplate.Load(rt.second);\n\n\t\toutAppend.emplace_back(refTemplate);\n\t\tcount++;\n\t}\n\n\treturn count;\n}\n\nint RefTemplateFile::Get(const std::string& templateName, RefTemplate& outTemplates) {\n\tauto tmpl = std::find_if(refTemplatesInFile.begin(), refTemplatesInFile.end(), [&templateName](const std::pair<std::string, XMLElement*>& rt) {\n\t\treturn rt.first == templateName;\n\t});\n\tif (tmpl != refTemplatesInFile.end())\n\t\toutTemplates.Load(tmpl->second);\n\telse\n\t\treturn 1;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/components/RefTemplates.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n#include <wx/dir.h>\n\nusing namespace tinyxml2;\n\nclass NamedValue {\npublic:\n\tvirtual std::string GetName() const = 0;\n};\n\nclass RefTemplate : NamedValue {\n\tstd::string name;\n\tstd::string source;\n\tstd::string set;\n\tstd::string shape;\n\tbool loadAll = false;\n\tstd::vector<std::string> sourceFiles;\n\npublic:\n\tRefTemplate() {}\n\tRefTemplate(XMLElement* srcElement) { Load(srcElement); }\n\n\tstd::string GetName() const override { return name; }\n\tvoid SetName(const std::string& inName) { name = inName; }\n\n\tstd::string GetSource() const { return source; }\n\tvoid SetSource(const std::string& inSource) { source = inSource; }\n\n\tstd::string GetSetName() const { return set; }\n\tvoid SetSetName(const std::string& inSetName) { set = inSetName; }\n\n\tstd::string GetShape() const { return shape; }\n\tvoid SetShape(const std::string& inShape) { shape = inShape; }\n\n\tbool GetLoadAll() const { return loadAll; }\n\tvoid SetLoadAll(const bool inLoadAll) { loadAll = inLoadAll; }\n\n\tint Load(XMLElement* srcElement);\n};\n\n\nclass RefTemplateCollection {\n\tstd::vector<RefTemplate> refTemplates;\n\npublic:\n\t// Loads all in the specified folder.\n\tint Load(const std::string& basePath);\n\tint GetAll(std::vector<RefTemplate>& outAppend);\n};\n\n\nclass RefTemplateFile {\n\tXMLDocument doc;\n\tXMLElement* root = nullptr;\n\tstd::vector<std::pair<std::string, XMLElement*>> refTemplatesInFile;\n\tint error = 0;\n\npublic:\n\tstd::string fileName;\n\tRefTemplateFile() {}\n\tRefTemplateFile(const std::string& srcFileName);\n\t~RefTemplateFile(){};\n\n\tbool fail() { return error != 0; }\n\tint GetError() { return error; }\n\n\tvoid Open(const std::string& srcFileName);\n\tvoid Rename(const std::string& newFileName);\n\tint GetNames(std::vector<std::string>& outNames, bool append = true, bool unique = false);\n\tbool Has(const std::string& queryName);\n\tint GetAll(std::vector<RefTemplate>& outAppend);\n\tint Get(const std::string& templateName, RefTemplate& outTemplates);\n};\n"
  },
  {
    "path": "src/components/SliderCategories.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderCategories.h\"\n#include \"../utils/PlatformUtil.h\"\n\nint SliderCategoryCollection::LoadCategories(const std::string& basePath) {\n\twxArrayString files;\n\twxDir::GetAllFiles(basePath, &files, \"*.xml\");\n\n\tfor (auto& file : files) {\n\t\tSliderCategoryFile catFile(file.ToUTF8().data());\n\t\tstd::vector<std::string> cats;\n\t\tcatFile.GetCategoryNames(cats);\n\t\tfor (auto& cat : cats) {\n\t\t\tSliderCategory sliderCat;\n\t\t\tcatFile.GetCategory(cat, sliderCat);\n\t\t\tif (categories.find(cat) != categories.end())\n\t\t\t\tcategories[cat].MergeSliders(sliderCat);\n\t\t\telse\n\t\t\t\tcategories[cat] = std::move(sliderCat);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint SliderCategoryCollection::GetAllCategories(std::vector<std::string>& outCategories) {\n\toutCategories.clear();\n\tfor (auto& c : categories)\n\t\toutCategories.push_back(c.first);\n\n\treturn outCategories.size();\n}\n\nstd::string SliderCategoryCollection::GetSliderDisplayName(const std::string& categoryName, const std::string& sliderName) {\n\tauto git = categories.find(categoryName);\n\tif (git == categories.end())\n\t\treturn \"\";\n\n\treturn git->second.GetSliderDisplayName(sliderName);\n}\n\nint SliderCategoryCollection::GetSliderCategory(const std::string& sliderName, std::string& outCategory) {\n\tfor (auto& c : categories)\n\t\tif (c.second.HasSlider(sliderName)) {\n\t\t\toutCategory = c.first;\n\t\t\tbreak;\n\t\t}\n\n\treturn outCategory.size();\n}\n\nint SliderCategoryCollection::GetCategorySliders(const std::string& categoryName, std::vector<std::string>& outSliders) {\n\tauto git = categories.find(categoryName);\n\tif (git == categories.end())\n\t\treturn 0;\n\n\treturn git->second.GetSliders(outSliders);\n}\n\nint SliderCategoryCollection::GetCategorySliders(const std::string& categoryName, std::unordered_set<std::string>& outSliders) {\n\tauto git = categories.find(categoryName);\n\tif (git == categories.end())\n\t\treturn 0;\n\n\treturn git->second.GetSliders(outSliders);\n}\n\nbool SliderCategoryCollection::GetCategoryHidden(const std::string& categoryName) {\n\tauto git = categories.find(categoryName);\n\tif (git == categories.end())\n\t\treturn true;\n\n\treturn git->second.GetHidden();\n}\n\nint SliderCategoryCollection::SetCategoryHidden(const std::string& categoryName, bool hide) {\n\tauto git = categories.find(categoryName);\n\tif (git == categories.end())\n\t\treturn 1;\n\n\tgit->second.SetHidden(hide);\n\treturn 0;\n}\n\nvoid SliderCategory::MergeSliders(const SliderCategory& sourceCategory) {\n\tfor (size_t i = 0; i < sourceCategory.sliders.size(); i++) {\n\t\tauto& sliderName = sourceCategory.sliders[i];\n\n\t\tif (std::count(sliders.cbegin(), sliders.cend(), sliderName) == 0)\n\t\t\tsliders.push_back(sliderName);\n\n\t\tauto displayName = sourceCategory.displayNames.find(sliderName);\n\t\tif (displayName != sourceCategory.displayNames.end())\n\t\t\tdisplayNames[sliderName] = displayName->second;\n\t}\n}\n\nint SliderCategory::LoadCategory(XMLElement* srcCategoryElement) {\n\tif (srcCategoryElement == nullptr)\n\t\treturn 1;\n\n\tsrcCategoryElement->QueryBoolAttribute(\"defaultHidden\", &isHidden);\n\n\tname = srcCategoryElement->Attribute(\"name\");\n\tXMLElement* slider = srcCategoryElement->FirstChildElement(\"Slider\");\n\twhile (slider) {\n\t\tif (!slider->Attribute(\"name\")) {\n\t\t\tslider = slider->NextSiblingElement(\"Slider\");\n\t\t\tcontinue;\n\t\t}\n\n\t\tstd::string sName = slider->Attribute(\"name\");\n\t\tsliders.push_back(sName);\n\n\t\tif (slider->Attribute(\"displayname\"))\n\t\t\tdisplayNames[sName] = slider->Attribute(\"displayname\");\n\t\telse\n\t\t\tdisplayNames[sName].clear();\n\n\t\tslider = slider->NextSiblingElement(\"Slider\");\n\t}\n\treturn 0;\n}\n\nbool SliderCategory::HasSlider(const std::string& search) {\n\tfor (auto& m : sliders)\n\t\tif (m.compare(search) == 0)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nstd::string SliderCategory::GetSliderDisplayName(const std::string& sliderName) {\n\tif (!HasSlider(sliderName))\n\t\treturn \"\";\n\n\treturn displayNames[sliderName];\n}\n\nbool SliderCategory::GetHidden() {\n\treturn isHidden;\n}\n\nvoid SliderCategory::SetHidden(bool hide) {\n\tisHidden = hide;\n}\n\nint SliderCategory::GetSliders(std::vector<std::string>& outSliders) {\n\toutSliders.insert(outSliders.end(), sliders.begin(), sliders.end());\n\treturn outSliders.size();\n}\n\nint SliderCategory::GetSliders(std::unordered_set<std::string>& outSliders) {\n\toutSliders.insert(sliders.begin(), sliders.end());\n\treturn outSliders.size();\n}\n\nint SliderCategory::AddSliders(const std::vector<std::string>& inSliders) {\n\tsliders.insert(sliders.end(), inSliders.begin(), inSliders.end());\n\treturn sliders.size();\n}\n\nvoid SliderCategory::WriteCategory(XMLElement* categoryElement, bool append) {\n\tif (!append)\n\t\tcategoryElement->DeleteChildren();\n\n\tfor (auto& slider : sliders) {\n\t\tXMLElement* newElement = categoryElement->GetDocument()->NewElement(\"Slider\");\n\t\tXMLElement* element = categoryElement->InsertEndChild(newElement)->ToElement();\n\t\telement->SetAttribute(\"name\", slider.c_str());\n\t}\n}\n\nSliderCategoryFile::SliderCategoryFile(const std::string& srcFileName) {\n\troot = nullptr;\n\terror = 0;\n\tOpen(srcFileName);\n}\n\nvoid SliderCategoryFile::Open(const std::string& srcFileName) {\n\tfileName = srcFileName;\n\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(srcFileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn;\n#else\n\tfp = fopen(srcFileName.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn;\n\t}\n#endif\n\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn;\n\n\tdoc.SetUserData(&fileName);\n\troot = doc.FirstChildElement(\"SliderCategories\");\n\tif (!root) {\n\t\terror = 2;\n\t\treturn;\n\t}\n\n\tXMLElement* element = root->FirstChildElement(\"Category\");\n\twhile (element) {\n\t\tcategoriesInFile[element->Attribute(\"name\")] = element;\n\t\telement = element->NextSiblingElement(\"Category\");\n\t}\n\tif (categoriesInFile.empty()) {\n\t\terror = 3;\n\t\treturn;\n\t}\n\n\terror = 0;\n}\n\nvoid SliderCategoryFile::Rename(const std::string& newFileName) {\n\tfileName = newFileName;\n}\n\nint SliderCategoryFile::GetCategoryNames(std::vector<std::string>& outCategoryNames, bool append, bool unique) {\n\tstd::unordered_set<std::string> existingNames;\n\tif (!append)\n\t\toutCategoryNames.clear();\n\n\tif (unique)\n\t\texistingNames.insert(outCategoryNames.begin(), outCategoryNames.end());\n\n\tfor (auto& cn : categoriesInFile) {\n\t\tif (unique && existingNames.find(cn.first) != existingNames.end())\n\t\t\tcontinue;\n\t\telse if (unique)\n\t\t\texistingNames.insert(cn.first);\n\n\t\toutCategoryNames.push_back(cn.first);\n\t}\n\treturn 0;\n}\n\nbool SliderCategoryFile::HasCategory(const std::string& queryCategoryName) {\n\tif (categoriesInFile.find(queryCategoryName) != categoriesInFile.end())\n\t\treturn true;\n\n\treturn false;\n}\n\nint SliderCategoryFile::GetAllCategories(std::vector<SliderCategory>& outAppendCategories) {\n\tint count = 0;\n\tbool add = true;\n\tfor (auto& c : categoriesInFile) {\n\t\tadd = true;\n\t\tfor (auto& oc : outAppendCategories) {\n\t\t\tif (oc.GetName() == c.first) {\n\t\t\t\toc.LoadCategory(c.second);\n\t\t\t\tadd = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!add)\n\t\t\tcontinue;\n\n\t\toutAppendCategories.emplace_back(c.second);\n\t\tcount++;\n\t}\n\treturn count;\n}\n\nint SliderCategoryFile::GetCategory(const std::string& categoryName, SliderCategory& outCategories) {\n\tif (categoriesInFile.find(categoryName) != categoriesInFile.end())\n\t\toutCategories.LoadCategory(categoriesInFile[categoryName]);\n\telse\n\t\treturn 1;\n\n\treturn 0;\n}\n\nint SliderCategoryFile::UpdateCategory(SliderCategory& inCategory) {\n\tif (categoriesInFile.find(inCategory.GetName()) != categoriesInFile.end()) {\n\t\tinCategory.WriteCategory(categoriesInFile[inCategory.GetName()]);\n\t}\n\telse {\n\t\tXMLElement* newElement = doc.NewElement(\"Category\");\n\t\tXMLElement* element = root->InsertEndChild(newElement)->ToElement();\n\t\telement->SetAttribute(\"name\", inCategory.GetName().c_str());\n\t\tinCategory.WriteCategory(element);\n\t}\n\treturn 0;\n}\n\nbool SliderCategoryFile::Save() {\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (error || !fp)\n\t\treturn false;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn false;\n\t}\n#endif\n\n\tdoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = doc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\terror = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (error)\n\t\treturn false;\n\n\treturn true;\n}\n"
  },
  {
    "path": "src/components/SliderCategories.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include <set>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n#include <wx/dir.h>\n\nusing namespace tinyxml2;\n\nclass SliderCategory {\n\tstd::string name;\n\tstd::vector<std::string> sliders;\n\tstd::unordered_map<std::string, std::string> displayNames;\n\tbool isHidden = false;\n\npublic:\n\tSliderCategory() {}\n\tSliderCategory(XMLElement* srcCategoryElement) { LoadCategory(srcCategoryElement); }\n\n\tstd::string GetName() { return name; }\n\tvoid SetName(const std::string& inName) { name = inName; }\n\n\tint AddSliders(const std::vector<std::string>& inSliders);\n\tbool HasSlider(const std::string& search);\n\tint GetSliders(std::vector<std::string>& outSliders);\n\tint GetSliders(std::unordered_set<std::string>& outSliders);\n\n\tstd::string GetSliderDisplayName(const std::string& sliderName);\n\n\tbool GetHidden();\n\tvoid SetHidden(bool hide);\n\n\t// Combine the source category's sliders into this one's list. Also merges the source file list.\n\tvoid MergeSliders(const SliderCategory& sourceCategory);\n\n\tint LoadCategory(XMLElement* srcCategoryElement);\n\tvoid WriteCategory(XMLElement* categoryElement, bool append = false);\n};\n\n\nclass SliderCategoryCollection {\n\tstd::unordered_map<std::string, SliderCategory> categories;\n\npublic:\n\tvoid Clear() { categories.clear(); }\n\n\t// Loads all categories in the specified folder (appends, does not clear).\n\tint LoadCategories(const std::string& basePath);\n\n\tint GetAllCategories(std::vector<std::string>& outCategories);\n\tint GetSliderCategory(const std::string& sliderName, std::string& outCategory);\n\tstd::string GetSliderDisplayName(const std::string& categoryName, const std::string& sliderName);\n\n\tbool GetCategoryHidden(const std::string& categoryName);\n\tint SetCategoryHidden(const std::string& categoryName, bool hide);\n\n\tint GetCategorySliders(const std::string& categoryName, std::vector<std::string>& outSliders);\n\tint GetCategorySliders(const std::string& categoryName, std::unordered_set<std::string>& outSliders);\n};\n\n\nclass SliderCategoryFile {\n\tXMLDocument doc;\n\tXMLElement* root = nullptr;\n\tstd::unordered_map<std::string, XMLElement*> categoriesInFile;\n\tint error = 0;\n\npublic:\n\tstd::string fileName;\n\tSliderCategoryFile() {}\n\tSliderCategoryFile(const std::string& srcFileName);\n\t~SliderCategoryFile(){};\n\n\tbool fail() { return error != 0; }\n\tint GetError() { return error; }\n\n\t// Loads the XML document and identifies included category names. On a failure, sets the internal error value.\n\tvoid Open(const std::string& srcFileName);\n\n\t// Changes the internal file name. The XML file isn't saved until the Save() function is used.\n\t// Note the original file name is not changed. This method allows you to save a category as a new file without altering the original.\n\tvoid Rename(const std::string& newFileName);\n\n\t// Returns a list of all the categories found in the file.\n\tint GetCategoryNames(std::vector<std::string>& outCategoryNames, bool append = true, bool unique = false);\n\n\t// Returns true if the category name exists in the file.\n\tbool HasCategory(const std::string& queryCategoryName);\n\n\t// Adds all of the categories in the file to the supplied categories vector. Does not clear the vector before doing so.\n\tint GetAllCategories(std::vector<SliderCategory>& outAppendCategories);\n\n\t// Gets a single category from the XML document based on the name.\n\tint GetCategory(const std::string& categoryName, SliderCategory& outCategories);\n\n\t// Updates a slider category in the xml document with the provided information.\n\t// If the category does not already exist in the file (based on name) the category is added.\n\tint UpdateCategory(SliderCategory& inCategory);\n\n\t// Writes the XML file using the internal fileName (use Rename() to change the name).\n\tbool Save();\n};\n"
  },
  {
    "path": "src/components/SliderData.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderData.h\"\n#include \"../utils/StringStuff.h\"\n\n#include <wx/dir.h>\n#include <wx/tokenzr.h>\n\nSliderData::SliderData(std::string inName)\n\t: name(std::move(inName)) {}\n\nSliderData::~SliderData() {}\n\nint SliderData::LoadSliderData(XMLElement* element, bool genWeights) {\n\t//Outfit Studio state values, not saved in XML.\n\tcurValue = 0;\n\tint numData = 0;\n\n\tXMLElement* root = element->Parent()->Parent()->ToElement();\n\tint version = root->IntAttribute(\"version\");\n\n\tstd::string dataFileStr = version >= 1 ? \"Data\" : \"datafile\";\n\n\tname = element->Attribute(\"name\");\n\tif (element->Attribute(\"invert\"))\n\t\tbInvert = StringsEqualNInsens(element->Attribute(\"invert\"), \"true\", 4);\n\telse\n\t\tbInvert = false;\n\n\tif (element->Attribute(\"uv\"))\n\t\tbUV = StringsEqualNInsens(element->Attribute(\"uv\"), \"true\", 4);\n\telse\n\t\tbUV = false;\n\n\tif (genWeights) {\n\t\tfloat b = element->FloatAttribute(\"big\");\n\t\tfloat s = element->FloatAttribute(\"small\");\n\t\tdefBigValue = b;\n\t\tdefSmallValue = s;\n\t}\n\telse {\n\t\tfloat defValue = element->FloatAttribute(\"default\");\n\t\tdefBigValue = defValue;\n\t\tdefSmallValue = defValue;\n\t}\n\n\tif (element->Attribute(\"hidden\"))\n\t\tbHidden = StringsEqualNInsens(element->Attribute(\"hidden\"), \"true\", 4);\n\telse\n\t\tbHidden = false;\n\n\tif (element->Attribute(\"zap\"))\n\t\tbZap = StringsEqualNInsens(element->Attribute(\"zap\"), \"true\", 4);\n\telse\n\t\tbZap = false;\n\n\tif (element->Attribute(\"uv\"))\n\t\tbUV = StringsEqualNInsens(element->Attribute(\"uv\"), \"true\", 4);\n\telse\n\t\tbUV = false;\n\n\tif (element->Attribute(\"clamp\"))\n\t\tbClamp = StringsEqualNInsens(element->Attribute(\"clamp\"), \"true\", 4);\n\telse\n\t\tbClamp = false;\n\n\tif (bZap) {\n\t\twxStringTokenizer tokenizer(element->Attribute(\"zaptoggles\"), \";\");\n\t\twhile (tokenizer.HasMoreTokens())\n\t\t\tzapToggles.push_back(tokenizer.GetNextToken().ToStdString());\n\t}\n\n\tDiffInfo tmpDataFile;\n\tXMLElement* datafile = element->FirstChildElement(dataFileStr.c_str());\n\twhile (datafile) {\n\t\tdatafile->SetName(\"Data\");\n\t\ttmpDataFile.targetName = datafile->Attribute(\"target\");\n\n\t\tif (datafile->Attribute(\"local\"))\n\t\t\ttmpDataFile.bLocal = StringsEqualNInsens(datafile->Attribute(\"local\"), \"true\", 4);\n\t\telse\n\t\t\ttmpDataFile.bLocal = false;\n\n\t\tif (datafile->Attribute(\"name\"))\n\t\t\ttmpDataFile.dataName = datafile->Attribute(\"name\");\n\t\telse\n\t\t\ttmpDataFile.dataName = name;\n\n\t\tconst char* dataFileText = datafile->GetText();\n\t\tif (dataFileText)\n\t\t\ttmpDataFile.fileName = ToOSSlashes(dataFileText);\n\n\t\tdataFiles.push_back(tmpDataFile);\n\n\t\tdatafile = datafile->NextSiblingElement(dataFileStr.c_str());\n\t\tnumData++;\n\t}\n\tif (numData == 0)\n\t\treturn 1;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/components/SliderData.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include \"DiffData.h\"\n#include \"../utils/StringStuff.h\"\n\nusing namespace tinyxml2;\n\nstruct DiffInfo {\n\tbool bLocal;\t\t\t// Local files use the slider set's directory for path info. Otherwise, it uses the target's data path.\n\tstd::string dataName;\t// Alias for the data.\n\tstd::string targetName; // Shape affected by the data.\n\tstd::string fileName;\t// File name not including path.\n\tDiffInfo(bool l = false, const std::string& dn = \"\", const std::string& tn = \"\", const std::string& fn = \"\")\n\t\t: bLocal(l)\n\t\t, dataName(dn)\n\t\t, targetName(tn)\n\t\t, fileName(fn) {}\n};\n\nclass SliderData {\npublic:\n\tstd::string name;\n\tbool bHidden = false;\n\tbool bInvert = false;\n\tbool bZap = false;\n\tbool bClamp = false;\n\tbool bUV = false;\n\tfloat defSmallValue = 0.0f;\n\tfloat defBigValue = 0.0f;\n\tstd::vector<std::string> zapToggles;\n\n\tfloat curValue = 0.0f;\n\tbool bShow = true;\n\n\tstd::vector<DiffInfo> dataFiles;\n\n\tSliderData(std::string inName = \"\");\n\t~SliderData();\n\n\t// Gets the slider's data record name for the specified target.\n\tstd::string TargetDataName(const std::string& targetName) {\n\t\tfor (auto& df : dataFiles)\n\t\t\tif (df.targetName == targetName)\n\t\t\t\treturn df.dataName;\n\n\t\treturn \"\";\n\t}\n\n\tstd::string DataFileName(const std::string& targetDataName) {\n\t\tfor (auto& df : dataFiles)\n\t\t\tif (df.dataName == targetDataName)\n\t\t\t\treturn df.fileName;\n\n\t\treturn \"\";\n\t}\n\n\tvoid RenameTarget(const std::string& oldTarget, const std::string& newTarget, const std::string& dataName) {\n\t\tfor (auto& df : dataFiles) {\n\t\t\tif (df.targetName == oldTarget) {\n\t\t\t\tdf.targetName = newTarget;\n\n\t\t\t\tif (df.dataName == oldTarget + dataName) {\n\t\t\t\t\tdf.dataName = newTarget + dataName;\n\t\t\t\t}\n\t\t\t\telse if (StringStartsWith(df.dataName, oldTarget)) {\n\t\t\t\t\tstd::string dtname = df.dataName.substr(oldTarget.length());\n\t\t\t\t\tdf.dataName = newTarget + dtname;\n\t\t\t\t}\n\t\t\t\telse if (StringEndsWith(df.dataName, name)) {\n\t\t\t\t\tdf.dataName = newTarget + name;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid RenameData(const std::string& oldDT, const std::string& newDT) {\n\t\tfor (auto& df : dataFiles) {\n\t\t\tif (df.dataName == oldDT)\n\t\t\t\tdf.dataName = newDT;\n\t\t}\n\t}\n\n\t// Creates a data file record and returns the record index.\n\tsize_t AddDataFile(const std::string& shapeTarget, const std::string& dataAlias, const std::string& fileName, bool localData = true) {\n\t\tdataFiles.emplace_back(localData, dataAlias, shapeTarget, fileName);\n\t\treturn dataFiles.size() - 1;\n\t}\n\n\tbool IsLocalData(const std::string& dataAlias) {\n\t\tfor (auto& df : dataFiles)\n\t\t\tif (df.dataName == dataAlias)\n\t\t\t\treturn df.bLocal;\n\n\t\treturn false;\n\t}\n\n\tvoid SetLocalData(const std::string& dataAlias) {\n\t\tfor (auto& df : dataFiles)\n\t\t\tif (df.dataName == dataAlias)\n\t\t\t\tdf.bLocal = true;\n\t}\n\n\tvoid Clear() { dataFiles.clear(); }\n\n\tint LoadSliderData(XMLElement* srcdata, bool genWeights);\n};\n"
  },
  {
    "path": "src/components/SliderGroup.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderGroup.h\"\n#include \"../utils/PlatformUtil.h\"\n\nint SliderSetGroupCollection::LoadGroups(const std::string& basePath) {\n\tgroups.clear();\n\n\twxArrayString files;\n\twxDir::GetAllFiles(basePath, &files, \"*.xml\");\n\n\tfor (auto& file : files) {\n\t\tSliderSetGroupFile groupFile(file.ToUTF8().data());\n\t\tstd::vector<std::string> groupNames;\n\t\tgroupFile.GetGroupNames(groupNames);\n\t\tfor (auto& group : groupNames) {\n\t\t\tSliderSetGroup ssg;\n\t\t\tgroupFile.GetGroup(group, ssg);\n\t\t\tif (groups.find(group) != groups.end())\n\t\t\t\tgroups[group].MergeMembers(ssg);\n\t\t\telse\n\t\t\t\tgroups[group] = std::move(ssg);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint SliderSetGroupCollection::GetAllGroups(std::set<std::string>& outGroups) {\n\toutGroups.clear();\n\tfor (auto& g : groups)\n\t\toutGroups.insert(g.first);\n\n\treturn outGroups.size();\n}\n\nint SliderSetGroupCollection::GetOutfitGroups(const std::string& outfitName, std::vector<std::string>& outGroups) {\n\toutGroups.clear();\n\tfor (auto& g : groups)\n\t\tif (g.second.HasMember(outfitName))\n\t\t\toutGroups.push_back(g.first);\n\n\treturn outGroups.size();\n}\n\nint SliderSetGroupCollection::GetGroupMembers(const std::string& groupName, std::vector<std::string>& outMembers) {\n\tauto git = groups.find(groupName);\n\tif (git == groups.end())\n\t\treturn 0;\n\n\treturn git->second.GetMembers(outMembers);\n}\n\nint SliderSetGroupCollection::GetGroupMembers(const std::string& groupName, std::unordered_set<std::string>& outMembers) {\n\tauto git = groups.find(groupName);\n\tif (git == groups.end())\n\t\treturn 0;\n\n\treturn git->second.GetMembers(outMembers);\n}\n\n// Combine the source groups members into this one's list. Also merges the source file list.\nvoid SliderSetGroup::MergeMembers(const SliderSetGroup& sourceGroup) {\n\tfor (size_t i = 0; i < sourceGroup.members.size(); i++) {\n\t\tmembers.push_back(sourceGroup.members[i]);\n\t\tsourceFiles.push_back(sourceGroup.sourceFiles[i]);\n\t}\n}\n\nint SliderSetGroup::LoadGroup(XMLElement* srcGroupElement) {\n\tif (srcGroupElement == nullptr)\n\t\treturn 1;\n\n\tname = srcGroupElement->Attribute(\"name\");\n\tXMLElement* member = srcGroupElement->FirstChildElement(\"Member\");\n\twhile (member) {\n\t\tstd::string mName = member->Attribute(\"name\");\n\t\tmembers.push_back(mName);\n\n\t\tstd::string* fileName = static_cast<std::string*>(member->GetDocument()->GetUserData());\n\t\tsourceFiles.push_back(*fileName);\n\t\tmember = member->NextSiblingElement(\"Member\");\n\t}\n\treturn 0;\n}\n\nbool SliderSetGroup::HasMember(const std::string& search) {\n\tfor (auto& m : members)\n\t\tif (m.compare(search) == 0)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nint SliderSetGroup::GetMembers(std::vector<std::string>& outMembers) {\n\toutMembers.insert(outMembers.end(), members.begin(), members.end());\n\treturn outMembers.size();\n}\n\nint SliderSetGroup::GetMembers(std::unordered_set<std::string>& outMembers) {\n\toutMembers.insert(members.begin(), members.end());\n\treturn outMembers.size();\n}\n\nint SliderSetGroup::AddMembers(const std::vector<std::string>& inMembers) {\n\tmembers.insert(members.end(), inMembers.begin(), inMembers.end());\n\treturn members.size();\n}\n\nvoid SliderSetGroup::WriteGroup(XMLElement* groupElement, bool append) {\n\tif (!append)\n\t\tgroupElement->DeleteChildren();\n\n\tfor (auto& member : members) {\n\t\tXMLElement* newElement = groupElement->GetDocument()->NewElement(\"Member\");\n\t\tXMLElement* element = groupElement->InsertEndChild(newElement)->ToElement();\n\t\telement->SetAttribute(\"name\", member.c_str());\n\t}\n}\n\nSliderSetGroupFile::SliderSetGroupFile(const std::string& srcFileName) {\n\troot = nullptr;\n\terror = 0;\n\tOpen(srcFileName);\n}\n\n// Loads the XML document and identifies included group names. On a failure, sets the internal error value.\nvoid SliderSetGroupFile::Open(const std::string& srcFileName) {\n\tfileName = srcFileName;\n\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(srcFileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn;\n#else\n\tfp = fopen(srcFileName.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn;\n\t}\n#endif\n\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn;\n\n\tdoc.SetUserData(&fileName);\n\troot = doc.FirstChildElement(\"SliderGroups\");\n\tif (!root) {\n\t\terror = 2;\n\t\treturn;\n\t}\n\n\tXMLElement* element = root->FirstChildElement(\"Group\");\n\twhile (element) {\n\t\tgroupsInFile[element->Attribute(\"name\")] = element;\n\t\telement = element->NextSiblingElement(\"Group\");\n\t}\n\tif (groupsInFile.empty()) {\n\t\terror = 3;\n\t\treturn;\n\t}\n\n\terror = 0;\n}\n\n// Creates a new empty group document structure, ready to add new groups and members to.\nvoid SliderSetGroupFile::New(const std::string& newFileName) {\n\tif (root)\n\t\treturn;\n\n\tClear();\n\n\tXMLElement* newElement = doc.NewElement(\"SliderGroups\");\n\troot = doc.InsertEndChild(newElement)->ToElement();\n\n\tfileName = newFileName;\n\tdoc.SetUserData(&fileName);\n\n\terror = 0;\n}\n\n// Clears all data of the file.\nvoid SliderSetGroupFile::Clear() {\n\troot = nullptr;\n\tdoc.Clear();\n\tgroupsInFile.clear();\n\terror = 0;\n}\n\n// Changes the internal file name. The XML file isn't saved until the save() function is used.\n// Note the original file name is not changed. This method allows you to save a group as a new file without altering the original.\nvoid SliderSetGroupFile::Rename(const std::string& newFileName) {\n\tfileName = newFileName;\n}\n\n// Returns a list of all the groups found in the file.\nint SliderSetGroupFile::GetGroupNames(std::vector<std::string>& outGroupNames, bool append, bool unique) {\n\tif (!append)\n\t\toutGroupNames.clear();\n\n\tstd::unordered_set<std::string> existingNames;\n\tif (unique)\n\t\texistingNames.insert(outGroupNames.begin(), outGroupNames.end());\n\n\tfor (auto& gn : groupsInFile) {\n\t\tif (unique && existingNames.find(gn.first) != existingNames.end())\n\t\t\tcontinue;\n\t\telse if (unique)\n\t\t\texistingNames.insert(gn.first);\n\n\t\toutGroupNames.push_back(gn.first);\n\t}\n\treturn 0;\n}\n\n// Returns true if the group name exists in the file.\nbool SliderSetGroupFile::HasGroup(const std::string& queryGroupName) {\n\tif (groupsInFile.find(queryGroupName) != groupsInFile.end())\n\t\treturn true;\n\n\treturn false;\n}\n\n// Adds all of the groups in the file to the supplied groups vector. Does not clear the vector before doing so.\nint SliderSetGroupFile::GetAllGroups(std::vector<SliderSetGroup>& outAppendGroups) {\n\tint count = 0;\n\tbool add = true;\n\tfor (auto& g : groupsInFile) {\n\t\tadd = true;\n\t\tfor (auto& og : outAppendGroups) {\n\t\t\tif (og.GetName() == g.first) {\n\t\t\t\tog.LoadGroup(g.second);\n\t\t\t\tadd = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!add)\n\t\t\tcontinue;\n\n\t\toutAppendGroups.emplace_back(g.second);\n\t\tcount++;\n\t}\n\treturn count;\n}\n\n// Gets a single group from the XML document based on the name.\nint SliderSetGroupFile::GetGroup(const std::string& groupName, SliderSetGroup& outSliderSetGroup) {\n\tif (groupsInFile.find(groupName) != groupsInFile.end())\n\t\toutSliderSetGroup.LoadGroup(groupsInFile[groupName]);\n\telse\n\t\treturn 1;\n\n\treturn 0;\n}\n\n// Updates a slider set group in the XML document with the provided information.\n// If the group does not already exist in the file (based on name) the group is added.\nint SliderSetGroupFile::UpdateGroup(SliderSetGroup& inGroup) {\n\tif (groupsInFile.find(inGroup.GetName()) != groupsInFile.end()) {\n\t\tinGroup.WriteGroup(groupsInFile[inGroup.GetName()]);\n\t}\n\telse {\n\t\tXMLElement* newElement = doc.NewElement(\"Group\");\n\t\tXMLElement* element = root->InsertEndChild(newElement)->ToElement();\n\t\telement->SetAttribute(\"name\", inGroup.GetName().c_str());\n\t\tinGroup.WriteGroup(element);\n\t\tgroupsInFile[inGroup.GetName()] = element;\n\t}\n\treturn 0;\n}\n\n// Writes the XML file using the internal fileName (use Rename() to change the name).\nbool SliderSetGroupFile::Save() {\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (error || !fp)\n\t\treturn false;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn false;\n\t}\n#endif\n\n\tdoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = doc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\terror = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (error)\n\t\treturn false;\n\n\treturn true;\n}\n"
  },
  {
    "path": "src/components/SliderGroup.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include <map>\n#include <set>\n#include <unordered_set>\n#include <vector>\n#include <wx/dir.h>\n\nusing namespace tinyxml2;\n\nclass SliderSetGroup {\n\tstd::string name;\n\tstd::vector<std::string> members;\n\tstd::vector<std::string> sourceFiles;\n\npublic:\n\tSliderSetGroup() {}\n\tSliderSetGroup(XMLElement* srcGroupElement) { LoadGroup(srcGroupElement); }\n\n\tstd::string GetName() { return name; }\n\tvoid SetName(const std::string& inName) { name = inName; }\n\n\tbool HasMember(const std::string& search);\n\tint GetMembers(std::vector<std::string>& outMembers);\n\tint GetMembers(std::unordered_set<std::string>& outMembers);\n\tint AddMembers(const std::vector<std::string>& inMembers);\n\n\t// Combine the source groups members into this one's list. Also merges the source file list.\n\tvoid MergeMembers(const SliderSetGroup& sourceGroup);\n\n\tint LoadGroup(XMLElement* srcGroupElement);\n\tvoid WriteGroup(XMLElement* groupElement, bool append = false);\n};\n\n\nclass SliderSetGroupCollection {\n\tstd::map<std::string, SliderSetGroup> groups;\n\npublic:\n\t// Loads all groups in the specified folder.\n\tint LoadGroups(const std::string& basePath);\n\n\tint GetAllGroups(std::set<std::string>& outGroups);\n\tint GetOutfitGroups(const std::string& outfitName, std::vector<std::string>& outGroups);\n\n\tint GetGroupMembers(const std::string& groupName, std::vector<std::string>& outMembers);\n\tint GetGroupMembers(const std::string& groupName, std::unordered_set<std::string>& outMembers);\n};\n\n\nclass SliderSetGroupFile {\n\tXMLDocument doc;\n\tXMLElement* root = nullptr;\n\tstd::map<std::string, XMLElement*> groupsInFile;\n\tint error = 0;\n\npublic:\n\tstd::string fileName;\n\tSliderSetGroupFile() {}\n\tSliderSetGroupFile(const std::string& srcFileName);\n\t~SliderSetGroupFile() {}\n\n\tbool fail() { return error != 0; }\n\tint GetError() { return error; }\n\n\t// Loads the XML document and identifies included group names. On a failure, sets the internal error value.\n\tvoid Open(const std::string& srcFileName);\n\n\t// Creates a new empty group document structure, ready to add new groups and members to.\n\tvoid New(const std::string& newFileName);\n\n\t// Clears all data of the file.\n\tvoid Clear();\n\n\t// Changes the internal file name. The XML file isn't saved until the Save() function is used.\n\t// Note the original file name is not changed. This method allows you to save a group as a new file without altering the original.\n\tvoid Rename(const std::string& newFileName);\n\n\t// Returns a list of all the groups found in the file.\n\tint GetGroupNames(std::vector<std::string>& outGroupNames, bool append = true, bool unique = false);\n\n\t// Returns true if the group name exists in the file.\n\tbool HasGroup(const std::string& queryGroupName);\n\n\t// Adds all of the groups in the file to the supplied groups vector. Does not clear the vector before doing so.\n\tint GetAllGroups(std::vector<SliderSetGroup>& outAppendGroups);\n\n\t// Gets a single group from the XML document based on the name.\n\tint GetGroup(const std::string& groupName, SliderSetGroup& outSliderSetGroup);\n\n\t// Updates a slider set group in the xml document with the provided information.\n\t// If the group does not already exist in the file (based on name) the group is added.\n\tint UpdateGroup(SliderSetGroup& inGroup);\n\n\t// Writes the xml file using the internal fileName (use Rename() to change the name).\n\tbool Save();\n};\n"
  },
  {
    "path": "src/components/SliderManager.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderManager.h\"\n\nSliderManager::SliderManager() {\n\tmSliderCount = 0;\n\tbNeedReload = true;\n}\n\nSliderManager::~SliderManager() {}\n\nvoid SliderManager::AddSlidersInSet(SliderSet& inSet) {\n\tint sz = static_cast<int>(inSet.size());\n\n\tfor (int i = 0; i < sz; i++) {\n\t\tif (inSet[i].bHidden) {\n\t\t\tAddHiddenSlider(inSet[i].name, inSet[i].bInvert, inSet[i].bZap, inSet[i].bUV);\n\t\t}\n\t\telse {\n\t\t\tif (inSet[i].bZap && inSet[i].bUV)\n\t\t\t\tAddUVSlider(inSet[i].name, inSet[i].bInvert, true);\n\t\t\telse if (inSet[i].bZap)\n\t\t\t\tAddZapSlider(inSet[i].name, inSet[i].zapToggles);\n\t\t\telse if (inSet[i].bUV)\n\t\t\t\tAddUVSlider(inSet[i].name, inSet[i].bInvert);\n\t\t\telse\n\t\t\t\tAddSlider(inSet[i].name, inSet[i].bInvert);\n\t\t}\n\n\t\tSetSliderDefaults(inSet[i].name, inSet[i].defBigValue / 100.0f, inSet[i].defSmallValue / 100.0f);\n\t\tif (inSet[i].bClamp)\n\t\t\tSetClampSlider(inSet[i].name);\n\n\t\tfor (size_t j = 0; j < inSet[i].dataFiles.size(); j++)\n\t\t\tAddSliderLink(inSet[i].name, inSet[i].dataFiles[j].dataName);\n\t}\n}\n\nvoid SliderManager::AddSlider(const std::string& name, bool invert, const std::string& dataSetName) {\n\tSlider s;\n\ts.name = name;\n\tif (dataSetName.length() > 0)\n\t\ts.linkedDataSets.push_back(dataSetName);\n\n\ts.value = 0.0f;\n\ts.defValue = 0.0f;\n\ts.invert = invert;\n\ts.zap = false;\n\ts.clamp = false;\n\ts.uv = false;\n\ts.changed = false;\n\n\tslidersSmall.push_back(s);\n\tslidersBig.push_back(s);\n\tmSliderCount++;\n}\n\nvoid SliderManager::AddUVSlider(const std::string& name, bool invert, bool isZap, const std::string& dataSetName) {\n\tSlider s;\n\ts.name = name;\n\tif (dataSetName.length() > 0)\n\t\ts.linkedDataSets.push_back(dataSetName);\n\n\ts.value = 0;\n\ts.defValue = 0;\n\ts.invert = invert;\n\ts.zap = isZap;\n\ts.clamp = false;\n\ts.uv = true;\n\ts.changed = false;\n\n\tslidersSmall.push_back(s);\n\tslidersBig.push_back(s);\n\tmSliderCount++;\n}\n\nvoid SliderManager::AddZapSlider(const std::string& name, const std::vector<std::string>& zapToggles, const std::string& dataSetName) {\n\tSlider s;\n\ts.name = name;\n\tif (dataSetName.length() > 0)\n\t\ts.linkedDataSets.push_back(dataSetName);\n\n\ts.value = 0;\n\ts.defValue = 0;\n\ts.invert = false;\n\ts.zap = true;\n\ts.clamp = false;\n\ts.uv = false;\n\ts.zapToggles = zapToggles;\n\ts.changed = false;\n\n\tslidersSmall.push_back(s);\n\tslidersBig.push_back(s);\n\tmSliderCount++;\n}\n\nvoid SliderManager::AddHiddenSlider(const std::string& name, bool invert, bool isZap, bool isUv, const std::string& dataSetName) {\n\tSlider s;\n\ts.name = name;\n\tif (dataSetName.length() > 0)\n\t\ts.linkedDataSets.push_back(dataSetName);\n\n\ts.value = 0;\n\ts.defValue = 0;\n\ts.invert = invert;\n\ts.zap = isZap;\n\ts.clamp = false;\n\ts.uv = isUv;\n\ts.changed = false;\n\n\tslidersSmall.push_back(s);\n\tslidersBig.push_back(s);\n}\n\nvoid SliderManager::SetSliderDefaults(const std::string& sliderName, float bigVal, float smallVal) {\n\tfor (auto& slider : slidersBig)\n\t\tif (slider.name == sliderName)\n\t\t\tslider.defValue = bigVal;\n\n\tfor (auto& slider : slidersSmall)\n\t\tif (slider.name == sliderName)\n\t\t\tslider.defValue = smallVal;\n}\n\nvoid SliderManager::SetClampSlider(const std::string& sliderName) {\n\tfor (auto& slider : slidersBig)\n\t\tif (slider.name == sliderName)\n\t\t\tslider.clamp = true;\n\n\tfor (auto& slider : slidersSmall)\n\t\tif (slider.name == sliderName)\n\t\t\tslider.clamp = true;\n}\n\nvoid SliderManager::AddSliderLink(const std::string& sliderName, const std::string& dataSetName) {\n\tfor (auto& slider : slidersBig)\n\t\tif (slider.name == sliderName)\n\t\t\tslider.linkedDataSets.push_back(dataSetName);\n\n\tfor (auto& slider : slidersSmall)\n\t\tif (slider.name == sliderName)\n\t\t\tslider.linkedDataSets.push_back(dataSetName);\n}\n\nfloat SliderManager::GetSlider(const std::string& sliderName, bool isSmall) {\n\tif (!isSmall) {\n\t\tfor (auto& slider : slidersBig)\n\t\t\tif (slider.name == sliderName)\n\t\t\t\treturn slider.value;\n\t}\n\telse {\n\t\tfor (auto& slider : slidersSmall)\n\t\t\tif (slider.name == sliderName)\n\t\t\t\treturn slider.value;\n\t}\n\treturn 0.0f;\n}\n\nstd::vector<std::string> SliderManager::GetSliderZapToggles(const std::string& sliderName) {\n\tfor (auto& slider : slidersBig)\n\t\tif (slider.name == sliderName)\n\t\t\treturn slider.zapToggles;\n\n\treturn std::vector<std::string>();\n}\n\nvoid SliderManager::SetSlider(const std::string& sliderName, bool isSmall, float val) {\n\tif (!isSmall) {\n\t\tfor (auto& slider : slidersBig) {\n\t\t\tif (slider.name == sliderName) {\n\t\t\t\tif (slider.zap) {\n\t\t\t\t\tFlagReload(true);\n\t\t\t\t\tif (val > 0.0f)\n\t\t\t\t\t\tval = 1.0f;\n\t\t\t\t}\n\t\t\t\tslider.value = val;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor (auto& slider : slidersSmall) {\n\t\t\tif (slider.name == sliderName) {\n\t\t\t\tif (slider.zap) {\n\t\t\t\t\tFlagReload(true);\n\t\t\t\t\tif (val > 0.0f)\n\t\t\t\t\t\tval = 1.0f;\n\t\t\t\t}\n\t\t\t\tslider.value = val;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid SliderManager::SetChanged(const std::string& sliderName, bool isSmall) {\n\tif (!isSmall) {\n\t\tfor (size_t i = 0; i < slidersBig.size(); i++) {\n\t\t\tauto& sl = slidersBig[i];\n\t\t\tif (sl.name == sliderName) {\n\t\t\t\tsl.changed = true;\n\n\t\t\t\tif (sl.zap && slidersSmall.size() > i) {\n\t\t\t\t\tauto& sls = slidersSmall[i];\n\t\t\t\t\tsls.changed = true;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor (size_t i = 0; i < slidersSmall.size(); i++) {\n\t\t\tauto& sl = slidersSmall[i];\n\t\t\tif (sl.name == sliderName) {\n\t\t\t\tsl.changed = true;\n\n\t\t\t\tif (sl.zap && slidersBig.size() > i) {\n\t\t\t\t\tauto& slb = slidersBig[i];\n\t\t\t\t\tslb.changed = true;\n\t\t\t\t}\n\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfloat SliderManager::GetBigPresetValue(const std::string& presetName, const std::string& sliderName, float defVal) {\n\tfloat ps;\n\tif (!presetCollection.GetBigPreset(presetName, sliderName, ps))\n\t\tps = defVal;\n\n\treturn ps;\n}\n\nfloat SliderManager::GetSmallPresetValue(const std::string& presetName, const std::string& sliderName, float defVal) {\n\tfloat ps;\n\tif (!presetCollection.GetSmallPreset(presetName, sliderName, ps))\n\t\tps = defVal;\n\n\treturn ps;\n}\n\nvoid SliderManager::InitializeSliders(const std::string& presetName) {\n\tfloat ps = 0.0f;\n\n\tfor (auto& slider : slidersBig) {\n\t\tif (!presetCollection.GetBigPreset(presetName, slider.name, ps)) {\n\t\t\tps = slider.defValue;\n\t\t\tslider.changed = false;\n\t\t}\n\n\t\tslider.value = ps;\n\t}\n\n\tfor (auto& slider : slidersSmall) {\n\t\tif (!presetCollection.GetSmallPreset(presetName, slider.name, ps)) {\n\t\t\tps = slider.defValue;\n\t\t\tslider.changed = false;\n\t\t}\n\n\t\tslider.value = ps;\n\t}\n}\n\nbool SliderManager::SliderHasChanged(const std::string& sliderName, bool getBig) {\n\tif (getBig) {\n\t\tfor (auto& slider : slidersBig)\n\t\t\tif (slider.name == sliderName)\n\t\t\t\treturn (slider.defValue != slider.value || (slider.changed && slider.zap));\n\t}\n\telse {\n\t\tfor (auto& slider : slidersSmall)\n\t\t\tif (slider.name == sliderName)\n\t\t\t\treturn (slider.defValue != slider.value || (slider.changed && slider.zap));\n\t}\n\treturn false;\n}\n\nfloat SliderManager::SliderValue(const std::string& sliderName, bool getBig) {\n\tif (getBig) {\n\t\tfor (auto& slider : slidersBig)\n\t\t\tif (slider.name == sliderName)\n\t\t\t\treturn slider.value;\n\t}\n\telse {\n\t\tfor (auto& slider : slidersSmall)\n\t\t\tif (slider.name == sliderName)\n\t\t\t\treturn slider.value;\n\t}\n\treturn 0.0f;\n}\n\nvoid SliderManager::GetSmallSliderList(std::vector<std::string>& names) {\n\tfor (auto& slider : slidersSmall)\n\t\tnames.push_back(slider.name);\n}\n\nvoid SliderManager::GetBigSliderList(std::vector<std::string>& names) {\n\tfor (auto& slider : slidersBig)\n\t\tnames.push_back(slider.name);\n}\n"
  },
  {
    "path": "src/components/SliderManager.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"SliderPresets.h\"\n#include \"SliderSet.h\"\n\nclass Slider {\npublic:\n\tstd::string name;\n\tbool invert = false;\n\tbool zap = false;\n\tbool clamp = false;\n\tbool uv = false;\n\tbool changed = false;\n\tfloat defValue = 0.0f;\n\tfloat value = 0.0f;\n\tstd::vector<std::string> zapToggles;\n\tstd::vector<std::string> linkedDataSets;\n};\n\nclass SliderManager {\n\tint mSliderCount;\n\tPresetCollection presetCollection;\n\tbool bNeedReload;\n\npublic:\n\tstd::vector<Slider> slidersBig;\n\tstd::vector<Slider> slidersSmall;\n\n\tSliderManager();\n\t~SliderManager();\n\n\tvoid ClearSliders() {\n\t\tslidersBig.clear();\n\t\tslidersSmall.clear();\n\t\tmSliderCount = 0;\n\t}\n\n\tbool LoadPresets(const std::string& basePath, const std::string& sliderSet, std::vector<std::string>& groupFilters, const bool allPresets = false) {\n\t\treturn presetCollection.LoadPresets(basePath, sliderSet, groupFilters, allPresets);\n\t}\n\n\tint SavePreset(const std::string& filePath, const std::string& presetName, const std::string& sliderSetName, std::vector<std::string>& assignGroups) {\n\t\tint index = 0;\n\t\tfor (auto& s : slidersBig) {\n\t\t\tif (SliderHasChanged(s.name, true))\n\t\t\t\tpresetCollection.SetSliderPreset(presetName, s.name, s.value);\n\t\t\telse\n\t\t\t\tpresetCollection.ClearSlider(presetName, s.name, true);\n\n\t\t\tif (SliderHasChanged(s.name, false))\n\t\t\t\tpresetCollection.SetSliderPreset(presetName, slidersSmall[index].name, -10000.0f, slidersSmall[index].value);\n\t\t\telse\n\t\t\t\tpresetCollection.ClearSlider(presetName, slidersSmall[index].name, false);\n\n\t\t\tindex++;\n\t\t}\n\t\treturn presetCollection.SavePreset(filePath, presetName, sliderSetName, assignGroups);\n\t}\n\n\tint DeletePreset(const std::string& filePath, const std::string& presetName) { return presetCollection.DeletePreset(filePath, presetName); }\n\n\tvoid SetSliderPreset(const std::string& presetName, const std::string& slider, float big = -1, float little = -1) {\n\t\tpresetCollection.SetSliderPreset(presetName, slider, big, little);\n\t}\n\n\tfloat GetBigPresetValue(const std::string& presetName, const std::string& sliderName, float defVal = 0.0f);\n\tfloat GetSmallPresetValue(const std::string& presetName, const std::string& sliderName, float defVal = 0.0f);\n\n\tvoid GetPresetNames(std::vector<std::string>& outNames) { presetCollection.GetPresetNames(outNames); }\n\n\tstd::string GetPresetFileNames(const std::string& set) { return presetCollection.GetPresetFileName(set); }\n\n\tvoid GetPresetGroups(const std::string& set, std::vector<std::string>& outGroups) { presetCollection.GetPresetGroups(set, outGroups); }\n\n\tvoid ClearPresets() { presetCollection.Clear(); }\n\n\tvoid AddSlidersInSet(SliderSet& inSet);\n\n\tvoid AddSlider(const std::string& name, bool invert = false, const std::string& dataSetName = \"\");\n\tvoid AddHiddenSlider(const std::string& name, bool invert = false, bool isZap = false, bool isUV = false, const std::string& dataSetName = \"\");\n\tvoid AddZapSlider(const std::string& name, const std::vector<std::string>& zapToggles, const std::string& dataSetName = \"\");\n\tvoid AddUVSlider(const std::string& name, bool invert = false, bool isZap = false, const std::string& dataSetName = \"\");\n\tvoid SetSliderDefaults(const std::string& sliderName, float bigVal, float smallVal);\n\tvoid SetClampSlider(const std::string& sliderName);\n\tvoid AddSliderLink(const std::string& sliderName, const std::string& dataSetName);\n\n\tfloat GetSlider(const std::string& sliderName, bool isSmall);\n\tstd::vector<std::string> GetSliderZapToggles(const std::string& sliderName);\n\tvoid SetSlider(const std::string& sliderName, bool isSmall, float val);\n\tvoid SetChanged(const std::string& sliderName, bool isSmall);\n\n\tvoid InitializeSliders(const std::string& presetName = \"\");\n\n\tbool SliderHasChanged(const std::string& sliderName, bool getBig);\n\tfloat SliderValue(const std::string& sliderName, bool getBig);\n\n\tvoid FlagReload(bool needReload) { bNeedReload = needReload; }\n\n\tbool NeedReload() { return bNeedReload; }\n\n\tvoid GetSmallSliderList(std::vector<std::string>& names);\n\tvoid GetBigSliderList(std::vector<std::string>& names);\n\tint VisibleSliderCount() { return mSliderCount; }\n};\n"
  },
  {
    "path": "src/components/SliderPresets.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderPresets.h\"\n#include \"../TinyXML-2/tinyxml2.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"../utils/StringStuff.h\"\n\n#include <wx/dir.h>\n\nusing namespace tinyxml2;\n\nvoid PresetCollection::Clear() {\n\tnamedSliderPresets.clear();\n\tpresetFileNames.clear();\n\tpresetGroups.clear();\n}\n\nvoid PresetCollection::ClearSlider(const std::string& presetName, const std::string& sliderName, const bool big) {\n\tif (namedSliderPresets.find(presetName) != namedSliderPresets.end()) {\n\t\tif (big)\n\t\t\tnamedSliderPresets[presetName][sliderName].big = -10000.0f;\n\t\telse\n\t\t\tnamedSliderPresets[presetName][sliderName].small = -10000.0f;\n\t}\n}\n\nvoid PresetCollection::GetPresetNames(std::vector<std::string>& outNames) {\n\tfor (auto& it : namedSliderPresets)\n\t\toutNames.push_back(it.first);\n}\n\nvoid PresetCollection::AddEmptyPreset(const std::string& set) {\n\tnamedSliderPresets.try_emplace(set);\n}\n\nvoid PresetCollection::SetSliderPreset(const std::string& set, const std::string& slider, float big, float small) {\n\tstd::map<std::string, SliderPreset> newPreset;\n\tSliderPreset sp;\n\tif (namedSliderPresets.find(set) == namedSliderPresets.end()) {\n\t\tsp.big = sp.small = -10000.0f;\n\n\t\tif (big > -10000.0f)\n\t\t\tsp.big = big;\n\t\tif (small > -10000.0f)\n\t\t\tsp.small = small;\n\n\t\tnewPreset[slider] = sp;\n\t\tnamedSliderPresets[set] = newPreset;\n\t}\n\telse {\n\t\tif (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end()) {\n\t\t\tsp.big = sp.small = -10000.0f;\n\n\t\t\tif (big > -10000.0f)\n\t\t\t\tsp.big = big;\n\t\t\tif (small > -10000.0f)\n\t\t\t\tsp.small = small;\n\n\t\t\tnamedSliderPresets[set][slider] = sp;\n\t\t}\n\t\telse {\n\t\t\tif (big > -10000.0f)\n\t\t\t\tnamedSliderPresets[set][slider].big = big;\n\t\t\tif (small > -10000.0f)\n\t\t\t\tnamedSliderPresets[set][slider].small = small;\n\t\t}\n\t}\n}\n\nbool PresetCollection::GetSliderExists(const std::string& set, const std::string& slider) {\n\tif (namedSliderPresets.find(set) == namedSliderPresets.end())\n\t\treturn false;\n\tif (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end())\n\t\treturn false;\n\n\treturn true;\n}\n\nbool PresetCollection::GetBigPreset(const std::string& set, const std::string& slider, float& big) {\n\tfloat b;\n\tif (namedSliderPresets.find(set) == namedSliderPresets.end())\n\t\treturn false;\n\tif (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end())\n\t\treturn false;\n\tb = namedSliderPresets[set][slider].big;\n\tif (b > -10000.0f) {\n\t\tbig = b;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nbool PresetCollection::GetSmallPreset(const std::string& set, const std::string& slider, float& small) {\n\tfloat b;\n\tif (namedSliderPresets.find(set) == namedSliderPresets.end())\n\t\treturn false;\n\tif (namedSliderPresets[set].find(slider) == namedSliderPresets[set].end())\n\t\treturn false;\n\tb = namedSliderPresets[set][slider].small;\n\tif (b > -10000.0f) {\n\t\tsmall = b;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nstd::string PresetCollection::GetPresetFileName(const std::string& set) {\n\tauto result = presetFileNames.find(set);\n\tif (result != presetFileNames.end())\n\t\treturn result->second;\n\n\treturn \"\";\n}\n\nvoid PresetCollection::GetPresetGroups(const std::string& set, std::vector<std::string>& outGroups) {\n\toutGroups.clear();\n\n\tauto result = presetGroups.find(set);\n\tif (result != presetGroups.end())\n\t\toutGroups = result->second;\n}\n\nbool PresetCollection::LoadPresets(const std::string& basePath, const std::string& sliderSet, std::vector<std::string>& groupFilter, bool allPresets) {\n\tXMLDocument doc;\n\tXMLElement* root;\n\tXMLElement* element;\n\tXMLElement* g;\n\tXMLElement* setSlider;\n\n\tstd::string presetName, sliderName, applyTo;\n\tfloat o, b, s;\n\n\twxArrayString files;\n\twxString path = wxString::FromUTF8(basePath);\n\twxDir::GetAllFiles(path, &files, \"*.xml\");\n\n\tfor (auto& file : files) {\n\t\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\t\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(file.ToUTF8().data());\n\t\tint ret = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\t\tif (ret || !fp)\n\t\t\tcontinue;\n#else\n\t\tfp = fopen(file.ToUTF8().data(), \"rb\");\n\t\tif (!fp)\n\t\t\tcontinue;\n#endif\n\n\t\tint ret2 = doc.LoadFile(fp);\n\t\tfclose(fp);\n\n\t\tif (ret2)\n\t\t\tcontinue;\n\n\t\troot = doc.FirstChildElement(\"SliderPresets\");\n\t\tif (!root)\n\t\t\tcontinue;\n\n\t\telement = root->FirstChildElement(\"Preset\");\n\t\twhile (element) {\n\t\t\tbool skip = true;\n\t\t\tstd::vector<std::string> groups;\n\n\t\t\tg = element->FirstChildElement(\"Group\");\n\t\t\twhile (g) {\n\t\t\t\tstd::string groupName = g->Attribute(\"name\");\n\t\t\t\tgroups.push_back(groupName);\n\n\t\t\t\tfor (auto& filter : groupFilter) {\n\t\t\t\t\tif (groupName == filter) {\n\t\t\t\t\t\tskip = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tg = g->NextSiblingElement(\"Group\");\n\t\t\t}\n\t\t\tif (element->Attribute(\"set\") == sliderSet || allPresets)\n\t\t\t\tskip = false;\n\n\t\t\tif (skip) {\n\t\t\t\telement = element->NextSiblingElement(\"Preset\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tpresetName = element->Attribute(\"name\");\n\t\t\tif (presetFileNames.find(presetName) != presetFileNames.end()) {\n\t\t\t\telement = element->NextSiblingElement(\"Preset\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tpresetFileNames[presetName] = file.ToUTF8();\n\t\t\tpresetGroups[presetName] = groups;\n\n\t\t\tAddEmptyPreset(presetName);\n\n\t\t\tsetSlider = element->FirstChildElement(\"SetSlider\");\n\t\t\twhile (setSlider) {\n\t\t\t\tsliderName = setSlider->Attribute(\"name\");\n\t\t\t\tapplyTo = setSlider->Attribute(\"size\");\n\t\t\t\to = setSlider->FloatAttribute(\"value\") / 100.0f;\n\t\t\t\ts = b = -10000.0f;\n\t\t\t\tif (applyTo == \"small\")\n\t\t\t\t\ts = o;\n\t\t\t\telse if (applyTo == \"big\")\n\t\t\t\t\tb = o;\n\t\t\t\telse if (applyTo == \"both\")\n\t\t\t\t\ts = b = o;\n\n\t\t\t\tSetSliderPreset(presetName, sliderName, b, s);\n\t\t\t\tsetSlider = setSlider->NextSiblingElement(\"SetSlider\");\n\t\t\t}\n\t\t\telement = element->NextSiblingElement(\"Preset\");\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint PresetCollection::SavePreset(const std::string& filePath, const std::string& presetName, const std::string& sliderSetName, std::vector<std::string>& assignGroups) {\n\tXMLElement* newElement = nullptr;\n\tXMLDocument outDoc;\n\tXMLNode* slidersNode = nullptr;\n\tXMLElement* presetElem = nullptr;\n\n\tbool loaded = false;\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath);\n\tint ret = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (ret == 0 && fp)\n\t\tloaded = true;\n#else\n\tfp = fopen(filePath.c_str(), \"rb\");\n\tif (fp)\n\t\tloaded = true;\n#endif\n\n\tif (loaded) {\n\t\tint retDoc = outDoc.LoadFile(fp);\n\t\tfclose(fp);\n\t\tfp = nullptr;\n\n\t\tif (retDoc != 0)\n\t\t\tloaded = false;\n\t}\n\n\tif (loaded) {\n\t\t// File exists - merge data.\n\t\tslidersNode = outDoc.FirstChildElement(\"SliderPresets\");\n\t\tpresetElem = slidersNode->FirstChildElement(\"Preset\");\n\t\twhile (presetElem) {\n\t\t\t// Replace preset if found in file.\n\t\t\tif (StringsEqualInsens(presetElem->Attribute(\"name\"), presetName.c_str())) {\n\t\t\t\tXMLElement* tmpElem = presetElem;\n\t\t\t\tpresetElem = presetElem->NextSiblingElement(\"Preset\");\n\t\t\t\tslidersNode->DeleteChild(tmpElem);\n\t\t\t}\n\t\t\telse\n\t\t\t\tpresetElem = presetElem->NextSiblingElement(\"Preset\");\n\t\t}\n\t}\n\telse {\n\t\tnewElement = outDoc.NewElement(\"SliderPresets\");\n\t\tslidersNode = outDoc.InsertEndChild(newElement);\n\t}\n\n\tnewElement = outDoc.NewElement(\"Preset\");\n\tpresetElem = slidersNode->InsertEndChild(newElement)->ToElement();\n\tpresetElem->SetAttribute(\"name\", presetName.c_str());\n\tpresetElem->SetAttribute(\"set\", sliderSetName.c_str());\n\n\tXMLElement* sliderElem;\n\tfor (auto& group : assignGroups) {\n\t\tnewElement = outDoc.NewElement(\"Group\");\n\t\tsliderElem = presetElem->InsertEndChild(newElement)->ToElement();\n\t\tsliderElem->SetAttribute(\"name\", group.c_str());\n\t}\n\tfor (auto& p : namedSliderPresets[presetName]) {\n\t\tif (p.second.big > -10000.0f) {\n\t\t\tnewElement = outDoc.NewElement(\"SetSlider\");\n\t\t\tsliderElem = presetElem->InsertEndChild(newElement)->ToElement();\n\t\t\tsliderElem->SetAttribute(\"name\", p.first.c_str());\n\t\t\tsliderElem->SetAttribute(\"size\", \"big\");\n\t\t\tsliderElem->SetAttribute(\"value\", (int)(p.second.big * 100.0f));\n\t\t}\n\t\tif (p.second.small > -10000.0f) {\n\t\t\tnewElement = outDoc.NewElement(\"SetSlider\");\n\t\t\tsliderElem = presetElem->InsertEndChild(newElement)->ToElement();\n\t\t\tsliderElem->SetAttribute(\"name\", p.first.c_str());\n\t\t\tsliderElem->SetAttribute(\"size\", \"small\");\n\t\t\tsliderElem->SetAttribute(\"value\", (int)(p.second.small * 100.0f));\n\t\t}\n\t}\n\n#ifdef _WINDOWS\n\twinFileName = PlatformUtil::MultiByteToWideUTF8(filePath);\n\tret = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (ret || !fp)\n\t\treturn 1;\n#else\n\tfp = fopen(filePath.c_str(), \"w\");\n\tif (!fp)\n\t\treturn 1;\n#endif\n\n\toutDoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = outDoc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\toutDoc.InsertFirstChild(outDoc.NewDeclaration());\n\n\tint retSaveDoc = outDoc.SaveFile(fp);\n\tfclose(fp);\n\tif (retSaveDoc)\n\t\treturn retSaveDoc;\n\n\treturn 0;\n}\n\nint PresetCollection::DeletePreset(const std::string& filePath, const std::string& presetName) {\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(filePath);\n\tint ret = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (ret || !fp)\n\t\treturn -1;\n#else\n\tfp = fopen(filePath.c_str(), \"rb\");\n\tif (!fp)\n\t\treturn -1;\n#endif\n\n\tXMLDocument doc;\n\tint ret2 = doc.LoadFile(fp);\n\tfclose(fp);\n\tfp = nullptr;\n\n\tif (ret2)\n\t\treturn -1;\n\n\tXMLNode* slidersNode = doc.FirstChildElement(\"SliderPresets\");\n\tif (slidersNode) {\n\t\tXMLElement* presetElem = slidersNode->FirstChildElement(\"Preset\");\n\t\twhile (presetElem) {\n\t\t\tif (StringsEqualInsens(presetElem->Attribute(\"name\"), presetName.c_str())) {\n\t\t\t\tslidersNode->DeleteChild(presetElem);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t\tpresetElem = presetElem->NextSiblingElement(\"Preset\");\n\t\t}\n\t}\n\n#ifdef _WINDOWS\n\twinFileName = PlatformUtil::MultiByteToWideUTF8(filePath);\n\tret = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (ret || !fp)\n\t\treturn -1;\n#else\n\tfp = fopen(filePath.c_str(), \"w\");\n\tif (!fp)\n\t\treturn -1;\n#endif\n\n\tdoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = doc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\tint retSaveDoc = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (retSaveDoc)\n\t\treturn retSaveDoc;\n\n\tnamedSliderPresets.erase(presetName);\n\tpresetFileNames.erase(presetName);\n\tpresetGroups.erase(presetName);\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/components/SliderPresets.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <map>\n#include <string>\n#include <vector>\n\nclass SliderPreset {\npublic:\n\tfloat big;\n\tfloat small;\n};\n\nclass PresetCollection {\n\tstd::map<std::string, std::map<std::string, SliderPreset>> namedSliderPresets;\n\tstd::map<std::string, std::string> presetFileNames;\n\tstd::map<std::string, std::vector<std::string>> presetGroups;\n\npublic:\n\tvoid Clear();\n\tvoid ClearSlider(const std::string& presetName, const std::string& sliderName, const bool big = true);\n\n\tvoid GetPresetNames(std::vector<std::string>& outNames);\n\tvoid AddEmptyPreset(const std::string& set);\n\tvoid SetSliderPreset(const std::string& set, const std::string& slider, float big = -10000.0f, float small = -10000.0f);\n\tbool GetSliderExists(const std::string& set, const std::string& slider);\n\tbool GetBigPreset(const std::string& set, const std::string& slider, float& big);\n\tbool GetSmallPreset(const std::string& set, const std::string& slider, float& small);\n\n\tstd::string GetPresetFileName(const std::string& set);\n\tvoid GetPresetGroups(const std::string& set, std::vector<std::string>& outGroups);\n\n\tbool LoadPresets(const std::string& basePath, const std::string& sliderSet, std::vector<std::string>& groupFilter, bool allPresets = false);\n\tint SavePreset(const std::string& filePath, const std::string& presetName, const std::string& sliderSetName, std::vector<std::string>& assignGroups);\n\tint DeletePreset(const std::string& filePath, const std::string& presetName);\n};\n"
  },
  {
    "path": "src/components/SliderSet.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderSet.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"../utils/StringStuff.h\"\n\n#include <filesystem>\n\n\nSliderSet::SliderSet() {}\n\nSliderSet::~SliderSet() {}\n\nSliderSet::SliderSet(XMLElement* element) {\n\tLoadSliderSet(element);\n}\n\n\nsize_t SliderSet::CloneSlider(const std::string& sliderName, const std::string& cloneName) {\n\t// Find slider\n\tauto sliderIt = std::find_if(sliders.begin(), sliders.end(), [&sliderName](const SliderData& s) {\n\t\treturn s.name == sliderName;\n\t});\n\n\tif (sliderIt == sliders.end())\n\t\treturn 0xFFFFFFFF;\n\n\t// Clone slider\n\tauto& clonedSlider = sliders.emplace_back(*sliderIt);\n\tclonedSlider.name = cloneName;\n\tclonedSlider.curValue = 0.0f;\n\tclonedSlider.zapToggles.clear();\n\n\treturn sliders.size() - 1;\n}\n\nvoid SliderSet::DeleteSlider(const std::string& sliderName) {\n\t// Delete toggles from other sliders\n\tfor (auto& slider : sliders) {\n\t\tslider.zapToggles.erase(std::remove(slider.zapToggles.begin(), slider.zapToggles.end(), sliderName), slider.zapToggles.end());\n\t}\n\n\t// Find and delete slider\n\tfor (size_t i = 0; i < sliders.size(); i++) {\n\t\tif (sliders[i].name == sliderName) {\n\t\t\tsliders.erase(sliders.begin() + i);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nsize_t SliderSet::CreateSlider(const std::string& sliderName) {\n\tsliders.emplace_back(sliderName);\n\treturn sliders.size() - 1;\n}\n\nsize_t SliderSet::CopySlider(SliderData* other) {\n\tsliders.emplace_back(other->name);\n\n\tSliderData* ms = &sliders.back();\n\tms->bClamp = other->bClamp;\n\tms->bHidden = other->bHidden;\n\tms->bInvert = other->bInvert;\n\tms->bZap = other->bZap;\n\tms->bUV = other->bUV;\n\tms->defBigValue = other->defBigValue;\n\tms->defSmallValue = other->defSmallValue;\n\tms->zapToggles = other->zapToggles;\n\tms->dataFiles = other->dataFiles;\n\treturn sliders.size() - 1;\n}\n\nint SliderSet::LoadSliderSet(XMLElement* element, bool appendNewSliders) {\n\tXMLElement* root = element->Parent()->ToElement();\n\tint version = root->IntAttribute(\"version\");\n\n\tstd::string shapeStr = version >= 1 ? \"Shape\" : \"BaseShapeName\";\n\tstd::string dataFolderStr = version >= 1 ? \"DataFolder\" : \"SetFolder\";\n\n\tname = element->Attribute(\"name\");\n\n\tXMLElement* tmpElement = element->FirstChildElement(dataFolderStr.c_str());\n\tif (tmpElement) {\n\t\ttmpElement->SetName(\"DataFolder\");\n\t\tdatafolder = ToOSSlashes(tmpElement->GetText());\n\t}\n\n\ttmpElement = element->FirstChildElement(\"SourceFile\");\n\tif (tmpElement)\n\t\tinputfile = tmpElement->GetText();\n\n\ttmpElement = element->FirstChildElement(\"OutputPath\");\n\tif (tmpElement)\n\t\toutputpath = ToOSSlashes(tmpElement->GetText());\n\n\tgenWeights = true;\n\tpreventMorphFile = false;\n\tkeepZappedShapes = false;\n\n\ttmpElement = element->FirstChildElement(\"OutputFile\");\n\tif (tmpElement) {\n\t\toutputfile = tmpElement->GetText();\n\t\tgenWeights = tmpElement->BoolAttribute(\"GenWeights\", true);\n\t\tpreventMorphFile = tmpElement->BoolAttribute(\"PreventMorphFile\");\n\t\tkeepZappedShapes = tmpElement->BoolAttribute(\"KeepZappedShapes\");\n\t}\n\n\tXMLElement* shapeName = element->FirstChildElement(shapeStr.c_str());\n\twhile (shapeName) {\n\t\tshapeName->SetName(\"Shape\");\n\n\t\tauto shapeText = shapeName->GetText();\n\t\tif (shapeText) {\n\t\t\tauto& shape = shapeAttributes[shapeText];\n\t\t\tif (shapeName->Attribute(\"DataFolder\")) {\n\t\t\t\tstd::string dataFolderAttr = ToOSSlashes(shapeName->Attribute(\"DataFolder\"));\n\t\t\t\tshape.dataFolders = SplitString(dataFolderAttr, ';');\n\t\t\t}\n\t\t\telse if (shape.dataFolders.empty())\n\t\t\t\tshape.dataFolders.push_back(datafolder);\n\n\t\t\tif (shapeName->Attribute(\"target\"))\n\t\t\t\tshape.targetShape = shapeName->Attribute(\"target\");\n\n\t\t\tshape.smoothSeamNormals = shapeName->BoolAttribute(\"SmoothSeamNormals\", true);\n\t\t\tshape.smoothSeamNormalsAngle = shapeName->FloatAttribute(\"SmoothSeamNormalsAngle\", SliderSetShape::SliderSetDefaultSmoothAngle);\n\t\t\tshape.lockNormals = shapeName->BoolAttribute(\"LockNormals\", false);\n\t\t}\n\n\t\tshapeName = shapeName->NextSiblingElement(shapeStr.c_str());\n\t}\n\n\tXMLElement* sliderEntry = element->FirstChildElement(\"Slider\");\n\twhile (sliderEntry) {\n\t\tSliderData tmpSlider;\n\t\tif (tmpSlider.LoadSliderData(sliderEntry, genWeights) == 0) {\n\t\t\t// Check if slider already exists\n\t\t\tfor (auto& s : sliders) {\n\t\t\t\tif (s.name == tmpSlider.name) {\n\t\t\t\t\t// Merge data of existing sliders\n\t\t\t\t\tfor (auto& df : tmpSlider.dataFiles)\n\t\t\t\t\t\ts.AddDataFile(df.targetName, df.dataName, df.fileName, df.bLocal);\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (appendNewSliders && !SliderExists(tmpSlider.name))\n\t\t\t\tsliders.push_back(std::move(tmpSlider));\n\t\t}\n\n\t\tsliderEntry = sliderEntry->NextSiblingElement(\"Slider\");\n\t}\n\n\t// A slider set/project can optionally specify a default normals generation configuration.  If present,\n\t// it activates the normals generation functionality in the preview window. Note customized normals generation settings\n\t// are saved in separate xml files -- the project-homed ones are default settings only.\n\tXMLElement* normalsGeneration = element->FirstChildElement(\"NormalsGeneration\");\n\tif (normalsGeneration) {\n\t\t// Only load default settings if none are currently specified\n\t\tif (defNormalGen.size() == 0)\n\t\t\tNormalGenLayer::LoadFromXML(normalsGeneration, defNormalGen);\n\t}\n\telse\n\t\tdefNormalGen.clear();\n\n\ttmpElement = element->FirstChildElement(\"Notes\");\n\tif (tmpElement && tmpElement->GetText())\n\t\tnotes = tmpElement->GetText();\n\telse\n\t\tnotes.clear();\n\n\ttmpElement = element->FirstChildElement(\"ReferenceInfo\");\n\tif (tmpElement) {\n\t\tif (tmpElement->Attribute(\"ProjectFile\"))\n\t\t\trefProjectFile = ToOSSlashes(tmpElement->Attribute(\"ProjectFile\"));\n\t\tif (tmpElement->Attribute(\"ProjectName\"))\n\t\t\trefProjectName = tmpElement->Attribute(\"ProjectName\");\n\t\tif (tmpElement->Attribute(\"ShapeName\"))\n\t\t\trefShapeName = tmpElement->Attribute(\"ShapeName\");\n\t}\n\telse {\n\t\trefProjectFile.clear();\n\t\trefProjectName.clear();\n\t\trefShapeName.clear();\n\t}\n\n\treturn 0;\n}\n\nvoid SliderSet::LoadSetDiffData(DiffDataSets& inDataStorage, const std::string& forShape) {\n\tstd::map<std::string, std::map<std::string, std::string>> osdNames;\n\n\tfor (auto& slider : sliders) {\n\t\tfor (auto& ddf : slider.dataFiles) {\n\t\t\tif (ddf.fileName.size() <= 4)\n\t\t\t\tcontinue;\n\n\t\t\tstd::string shapeName = TargetToShape(ddf.targetName);\n\t\t\tif (!forShape.empty() && shapeName != forShape)\n\t\t\t\tcontinue;\n\n\t\t\tbool isBSDFile = ddf.fileName.compare(ddf.fileName.size() - 4, ddf.fileName.size(), \".bsd\") == 0;\n\t\t\tstd::string fullFilePath = baseDataPath + PathSepStr;\n\t\t\tstd::string dataName;\n\n\t\t\tstd::vector<std::string> dataFolders;\n\t\t\tif (!ddf.bLocal)\n\t\t\t\tdataFolders = GetShapeDataFolders(shapeName);\n\t\t\telse\n\t\t\t\tdataFolders.push_back(datafolder);\n\n\t\t\tfor (auto& df : dataFolders) {\n\t\t\t\tif (isBSDFile) {\n\t\t\t\t\tstd::string filePath = df + PathSepStr + ddf.fileName;\n\n\t\t\t\t\t// Use data folder that contains the external file\n\t\t\t\t\tif (PlatformUtil::FileExists(fullFilePath + filePath)) {\n\t\t\t\t\t\tfullFilePath += filePath;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// Split file name to get file and data name in it\n\t\t\t\t\tsize_t split = ddf.fileName.find_last_of('/');\n\t\t\t\t\tif (split == std::string::npos)\n\t\t\t\t\t\tsplit = ddf.fileName.find_last_of('\\\\');\n\t\t\t\t\tif (split == std::string::npos)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tstd::string fileName = ddf.fileName.substr(0, split);\n\t\t\t\t\tdataName = ddf.fileName.substr(split + 1);\n\n\t\t\t\t\tstd::string filePath = df + PathSepStr + fileName;\n\n\t\t\t\t\t// Use data folder that contains the external file\n\t\t\t\t\tif (PlatformUtil::FileExists(fullFilePath + filePath)) {\n\t\t\t\t\t\tfullFilePath += filePath;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// BSD format\n\t\t\tif (isBSDFile) {\n\t\t\t\tinDataStorage.LoadSet(ddf.dataName, ddf.targetName, fullFilePath);\n\t\t\t}\n\t\t\t// OSD format\n\t\t\telse {\n\t\t\t\t// Cache data locations\n\t\t\t\tosdNames[fullFilePath][dataName] = ddf.targetName;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load from cached data locations at once\n\tinDataStorage.LoadData(osdNames);\n}\n\nvoid SliderSet::Merge(\n\tSliderSet& mergeSet, DiffDataSets& inDataStorage, DiffDataSets& baseDiffData, const std::string& baseShape, const bool newDataLocal, const bool appendNewSliders) {\n\tstd::map<std::string, std::map<std::string, std::string>> osdNames;\n\tstd::map<std::string, std::map<std::string, std::string>> osdNamesBase;\n\n\tauto addSlider = [&](DiffInfo& ddf) {\n\t\tif (ddf.fileName.size() <= 4)\n\t\t\treturn;\n\n\t\tstd::string shapeName = mergeSet.TargetToShape(ddf.targetName);\n\t\tbool isBSDFile = ddf.fileName.compare(ddf.fileName.size() - 4, ddf.fileName.size(), \".bsd\") == 0;\n\n\t\tstd::string fullFilePath = mergeSet.baseDataPath + PathSepStr;\n\t\tstd::string dataName;\n\n\t\tstd::vector<std::string> dataFolders;\n\t\tif (!ddf.bLocal)\n\t\t\tdataFolders = mergeSet.GetShapeDataFolders(shapeName);\n\t\telse\n\t\t\tdataFolders.push_back(mergeSet.datafolder);\n\n\t\tfor (auto& df : dataFolders) {\n\t\t\tif (isBSDFile) {\n\t\t\t\tstd::string filePath = df + PathSepStr + ddf.fileName;\n\n\t\t\t\t// Use data folder that contains the external file\n\t\t\t\tif (PlatformUtil::FileExists(fullFilePath + filePath)) {\n\t\t\t\t\tfullFilePath += filePath;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Split file name to get file and data name in it\n\t\t\t\tsize_t split = ddf.fileName.find_last_of('/');\n\t\t\t\tif (split == std::string::npos)\n\t\t\t\t\tsplit = ddf.fileName.find_last_of('\\\\');\n\t\t\t\tif (split == std::string::npos)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::string fileName = ddf.fileName.substr(0, split);\n\t\t\t\tdataName = ddf.fileName.substr(split + 1);\n\n\t\t\t\tstd::string filePath = df + PathSepStr + fileName;\n\n\t\t\t\t// Use data folder that contains the external file\n\t\t\t\tif (PlatformUtil::FileExists(fullFilePath + filePath)) {\n\t\t\t\t\tfullFilePath += filePath;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// BSD format\n\t\tif (isBSDFile) {\n\t\t\tif (shapeName != baseShape)\n\t\t\t\tinDataStorage.LoadSet(ddf.dataName, ddf.targetName, fullFilePath);\n\t\t\telse\n\t\t\t\tbaseDiffData.LoadSet(ddf.dataName, ddf.targetName, fullFilePath);\n\t\t}\n\t\t// OSD format\n\t\telse {\n\t\t\t// Cache data locations\n\t\t\tif (shapeName != baseShape)\n\t\t\t\tosdNames[fullFilePath][dataName] = ddf.targetName;\n\t\t\telse\n\t\t\t\tosdNamesBase[fullFilePath][dataName] = ddf.targetName;\n\t\t}\n\n\t\t// Make new data local or not\n\t\tddf.bLocal = newDataLocal;\n\t};\n\n\tfor (auto& s : mergeSet.sliders) {\n\t\tauto sliderIt = std::find_if(sliders.begin(), sliders.end(), [&s](const SliderData& rs) { return rs.name == s.name; });\n\n\t\tif (sliderIt != sliders.end()) {\n\t\t\t// Copy missing data of existing slider\n\t\t\tfor (auto& sd : s.dataFiles) {\n\t\t\t\tauto sliderDataIt = std::find_if(sliderIt->dataFiles.begin(), sliderIt->dataFiles.end(), [&](const DiffInfo& rd) {\n\t\t\t\t\tstd::string shapeName = TargetToShape(rd.targetName);\n\t\t\t\t\tstd::string shapeNameMerge = mergeSet.TargetToShape(sd.targetName);\n\t\t\t\t\treturn rd.targetName == sd.targetName && rd.dataName == sd.dataName && shapeName == shapeNameMerge;\n\t\t\t\t});\n\n\t\t\t\tif (sliderDataIt == sliderIt->dataFiles.end()) {\n\t\t\t\t\tsize_t df = sliderIt->AddDataFile(sd.targetName, sd.dataName, sd.fileName, sd.bLocal);\n\t\t\t\t\taddSlider(sliderIt->dataFiles[df]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (appendNewSliders) {\n\t\t\t// Copy new slider to the set\n\t\t\tsliders.push_back(s);\n\t\t\tfor (auto& ddf : sliders.back().dataFiles)\n\t\t\t\taddSlider(ddf);\n\t\t}\n\t}\n\n\tfor (auto& s : mergeSet.shapeAttributes) {\n\t\t// Copy new shapes to the set\n\t\tif (newDataLocal)\n\t\t\ts.second.dataFolders.clear();\n\n\t\tshapeAttributes[s.first] = s.second;\n\t}\n\n\t// Load from cached data locations at once\n\tinDataStorage.LoadData(osdNames);\n\tbaseDiffData.LoadData(osdNamesBase);\n}\n\nvoid SliderSet::WriteSliderSet(XMLElement* sliderSetElement) {\n\tsliderSetElement->DeleteChildren();\n\tsliderSetElement->SetAttribute(\"name\", name.c_str());\n\n\tif (HasReferenceInfo()) {\n\t\tXMLElement* newElement = sliderSetElement->GetDocument()->NewElement(\"ReferenceInfo\");\n\t\tXMLElement* refElement = sliderSetElement->InsertEndChild(newElement)->ToElement();\n\t\tstd::string projectFile_bs = ToBackslashes(refProjectFile);\n\t\trefElement->SetAttribute(\"ProjectFile\", projectFile_bs.c_str());\n\t\trefElement->SetAttribute(\"ProjectName\", refProjectName.c_str());\n\t\trefElement->SetAttribute(\"ShapeName\", refShapeName.c_str());\n\t}\n\n\tXMLElement* newElement = sliderSetElement->GetDocument()->NewElement(\"DataFolder\");\n\tstd::string datafolder_bs = ToBackslashes(datafolder);\n\tXMLText* newText = sliderSetElement->GetDocument()->NewText(datafolder_bs.c_str());\n\tsliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText);\n\n\tnewElement = sliderSetElement->GetDocument()->NewElement(\"SourceFile\");\n\tnewText = sliderSetElement->GetDocument()->NewText(inputfile.c_str());\n\tsliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText);\n\n\tnewElement = sliderSetElement->GetDocument()->NewElement(\"OutputPath\");\n\tstd::string outputpath_bs = ToBackslashes(outputpath);\n\tnewText = sliderSetElement->GetDocument()->NewText(outputpath_bs.c_str());\n\tsliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText);\n\n\tnewElement = sliderSetElement->GetDocument()->NewElement(\"OutputFile\");\n\tXMLElement* outputFileElement = sliderSetElement->InsertEndChild(newElement)->ToElement();\n\n\toutputFileElement->SetAttribute(\"GenWeights\", genWeights);\n\toutputFileElement->SetAttribute(\"PreventMorphFile\", preventMorphFile);\n\toutputFileElement->SetAttribute(\"KeepZappedShapes\", keepZappedShapes);\n\n\tnewText = sliderSetElement->GetDocument()->NewText(outputfile.c_str());\n\toutputFileElement->InsertEndChild(newText);\n\n\tXMLElement* baseShapeElement;\n\tXMLElement* sliderElement;\n\tXMLElement* dataFileElement;\n\n\tfor (auto& s : shapeAttributes) {\n\t\tnewElement = sliderSetElement->GetDocument()->NewElement(\"Shape\");\n\t\tbaseShapeElement = sliderSetElement->InsertEndChild(newElement)->ToElement();\n\n\t\tif (!s.second.targetShape.empty())\n\t\t\tbaseShapeElement->SetAttribute(\"target\", s.second.targetShape.c_str());\n\n\t\tif (!s.second.dataFolders.empty()) {\n\t\t\tstd::string dataFolder_bs = ToBackslashes(JoinStrings(s.second.dataFolders, \";\"));\n\t\t\tbaseShapeElement->SetAttribute(\"DataFolder\", dataFolder_bs.c_str());\n\t\t}\n\n\t\tif (!s.second.smoothSeamNormals)\n\t\t\tbaseShapeElement->SetAttribute(\"SmoothSeamNormals\", s.second.smoothSeamNormals);\n\n\t\tif (s.second.smoothSeamNormals && s.second.smoothSeamNormalsAngle != SliderSetShape::SliderSetDefaultSmoothAngle)\n\t\t\tbaseShapeElement->SetAttribute(\"SmoothSeamNormalsAngle\", s.second.smoothSeamNormalsAngle);\n\n\t\tif (s.second.lockNormals)\n\t\t\tbaseShapeElement->SetAttribute(\"LockNormals\", s.second.lockNormals);\n\n\t\tnewText = sliderSetElement->GetDocument()->NewText(s.first.c_str());\n\t\tbaseShapeElement->InsertEndChild(newText);\n\t}\n\n\tfor (auto& slider : sliders) {\n\t\tif (slider.dataFiles.size() == 0)\n\t\t\tcontinue;\n\n\t\tnewElement = sliderSetElement->GetDocument()->NewElement(\"Slider\");\n\t\tsliderElement = sliderSetElement->InsertEndChild(newElement)->ToElement();\n\t\tsliderElement->SetAttribute(\"name\", slider.name.c_str());\n\t\tsliderElement->SetAttribute(\"invert\", slider.bInvert);\n\n\t\tif (genWeights) {\n\t\t\tsliderElement->SetAttribute(\"small\", (int)slider.defSmallValue);\n\t\t\tsliderElement->SetAttribute(\"big\", (int)slider.defBigValue);\n\t\t}\n\t\telse\n\t\t\tsliderElement->SetAttribute(\"default\", (int)slider.defBigValue);\n\n\t\tif (slider.bHidden)\n\t\t\tsliderElement->SetAttribute(\"hidden\", true);\n\t\tif (slider.bClamp)\n\t\t\tsliderElement->SetAttribute(\"clamp\", true);\n\n\t\tif (slider.bZap) {\n\t\t\tsliderElement->SetAttribute(\"zap\", true);\n\n\t\t\tstd::string zapToggles;\n\t\t\tfor (auto& toggle : slider.zapToggles) {\n\t\t\t\tzapToggles.append(toggle);\n\t\t\t\tzapToggles.append(\";\");\n\t\t\t}\n\n\t\t\tif (!zapToggles.empty())\n\t\t\t\tsliderElement->SetAttribute(\"zaptoggles\", zapToggles.c_str());\n\t\t}\n\n\t\tif (slider.bUV)\n\t\t\tsliderElement->SetAttribute(\"uv\", true);\n\n\t\tfor (auto& df : slider.dataFiles) {\n\t\t\tnewElement = sliderSetElement->GetDocument()->NewElement(\"Data\");\n\t\t\tdataFileElement = sliderElement->InsertEndChild(newElement)->ToElement();\n\t\t\tdataFileElement->SetAttribute(\"name\", df.dataName.c_str());\n\t\t\tdataFileElement->SetAttribute(\"target\", df.targetName.c_str());\n\t\t\tif (df.bLocal)\n\t\t\t\tdataFileElement->SetAttribute(\"local\", true);\n\n\t\t\tstd::string fileName_bs = ToBackslashes(df.fileName);\n\t\t\tnewText = sliderSetElement->GetDocument()->NewText(fileName_bs.c_str());\n\t\t\tdataFileElement->InsertEndChild(newText);\n\t\t}\n\t}\n\n\tif (!notes.empty()) {\n\t\tnewElement = sliderSetElement->GetDocument()->NewElement(\"Notes\");\n\t\tnewText = sliderSetElement->GetDocument()->NewText(notes.c_str());\n\t\tnewText->SetCData(true);\n\t\tsliderSetElement->InsertEndChild(newElement)->ToElement()->InsertEndChild(newText);\n\t}\n\n}\n\nstd::string SliderSet::GetInputFileName() {\n\tstd::string o;\n\to = baseDataPath + PathSepStr;\n\to += datafolder + PathSepStr;\n\to += inputfile;\n\treturn o;\n}\n\nstd::string SliderSet::GetOutputFilePath() {\n\treturn outputpath + PathSepStr + outputfile;\n}\n\nbool SliderSet::GenWeights() {\n\treturn genWeights;\n}\n\nbool SliderSet::PreventMorphFile() {\n\treturn preventMorphFile;\n}\n\nbool SliderSet::KeepZappedShapes() {\n\treturn keepZappedShapes;\n}\n\nSliderSetFile::SliderSetFile(const std::string& srcFileName)\n\t: error(0) {\n\tOpen(srcFileName);\n}\n\nvoid SliderSetFile::Open(const std::string& srcFileName) {\n\tfileName = srcFileName;\n\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(srcFileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn;\n#else\n\tfp = fopen(srcFileName.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn;\n\t}\n#endif\n\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn;\n\n\troot = doc.FirstChildElement(\"SliderSetInfo\");\n\tif (!root) {\n\t\terror = 100;\n\t\treturn;\n\t}\n\n\tversion = root->IntAttribute(\"version\");\n\n\tXMLElement* setElement;\n\tstd::string setname;\n\tsetElement = root->FirstChildElement(\"SliderSet\");\n\twhile (setElement) {\n\t\tsetname = setElement->Attribute(\"name\");\n\t\tsetsInFile[setname] = setElement;\n\t\tsetsOrder.push_back(setname);\n\t\tsetElement = setElement->NextSiblingElement(\"SliderSet\");\n\t}\n}\n\nvoid SliderSetFile::New(const std::string& newFileName) {\n\tversion = 1; // Most recent\n\terror = 0;\n\tfileName = newFileName;\n\tdoc.Clear();\n\n\tXMLElement* rootElement = doc.NewElement(\"SliderSetInfo\");\n\tif (version > 0)\n\t\trootElement->SetAttribute(\"version\", version);\n\n\tdoc.InsertEndChild(rootElement);\n\troot = doc.FirstChildElement(\"SliderSetInfo\");\n}\n\nint SliderSetFile::GetSetNames(std::vector<std::string>& outSetNames, bool append) {\n\tif (!append)\n\t\toutSetNames.clear();\n\n\tfor (auto& xmlit : setsInFile)\n\t\toutSetNames.push_back(xmlit.first);\n\n\treturn static_cast<int>(outSetNames.size());\n}\n\nint SliderSetFile::GetSetNamesUnsorted(std::vector<std::string>& outSetNames, bool append) {\n\tif (!append) {\n\t\toutSetNames.clear();\n\t\toutSetNames.assign(setsOrder.begin(), setsOrder.end());\n\t}\n\telse\n\t\toutSetNames.insert(outSetNames.end(), setsOrder.begin(), setsOrder.end());\n\n\treturn static_cast<int>(outSetNames.size());\n}\n\nbool SliderSetFile::HasSet(const std::string& querySetName) {\n\treturn (setsInFile.find(querySetName) != setsInFile.end());\n}\n\nvoid SliderSetFile::SetShapes(const std::string& set, std::vector<std::string>& outShapeNames) {\n\tif (!HasSet(set))\n\t\treturn;\n\n\tXMLElement* setElement = setsInFile[set];\n\tXMLElement* shapeElement = setElement->FirstChildElement(\"Shape\");\n\twhile (shapeElement) {\n\t\toutShapeNames.push_back(shapeElement->GetText());\n\t\tshapeElement = shapeElement->NextSiblingElement(\"Shape\");\n\t}\n}\n\nint SliderSetFile::GetSet(const std::string& setName, SliderSet& outSliderSet, bool appendNewSliders) {\n\tXMLElement* setPtr;\n\tif (!HasSet(setName))\n\t\treturn 1;\n\n\tsetPtr = setsInFile[setName];\n\n\tint ret;\n\tret = outSliderSet.LoadSliderSet(setPtr, appendNewSliders);\n\n\treturn ret;\n}\n\nint SliderSetFile::GetAllSets(std::vector<SliderSet>& outAppendSets) {\n\tint err;\n\tSliderSet tmpSet;\n\tfor (auto& xmlit : setsInFile) {\n\t\terr = tmpSet.LoadSliderSet(xmlit.second);\n\t\tif (err)\n\t\t\treturn err;\n\t\toutAppendSets.push_back(tmpSet);\n\t}\n\treturn 0;\n}\n\nvoid SliderSetFile::GetSetOutputFilePath(const std::string& setName, std::string& outFilePath) {\n\toutFilePath.clear();\n\n\tif (!HasSet(setName))\n\t\treturn;\n\n\tXMLElement* setPtr = setsInFile[setName];\n\tXMLElement* tmpElement = setPtr->FirstChildElement(\"OutputPath\");\n\tif (tmpElement)\n\t\toutFilePath += ToOSSlashes(tmpElement->GetText());\n\n\ttmpElement = setPtr->FirstChildElement(\"OutputFile\");\n\tif (tmpElement) {\n\t\toutFilePath += PathSepStr;\n\t\toutFilePath += tmpElement->GetText();\n\t}\n}\n\nint SliderSetFile::UpdateSet(SliderSet& inSliderSet) {\n\tXMLElement* setPtr;\n\tstd::string setName;\n\tsetName = inSliderSet.GetName();\n\tif (HasSet(setName)) {\n\t\tsetPtr = setsInFile[setName];\n\t}\n\telse {\n\t\tXMLElement* tmpElement = doc.NewElement(\"SliderSet\");\n\t\ttmpElement->SetAttribute(\"name\", setName.c_str());\n\t\tsetPtr = root->InsertEndChild(tmpElement)->ToElement();\n\t}\n\tinSliderSet.WriteSliderSet(setPtr);\n\n\treturn 0;\n}\n\nint SliderSetFile::DeleteSet(const std::string& setName) {\n\tif (!HasSet(setName))\n\t\treturn 1;\n\n\tXMLElement* setPtr = setsInFile[setName];\n\tsetsInFile.erase(setName);\n\tdoc.DeleteNode(setPtr);\n\n\treturn 0;\n}\n\nbool SliderSetFile::Save() {\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (error || !fp)\n\t\treturn false;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn false;\n\t}\n#endif\n\n\tdoc.SetBOM(true);\n\n\tconst tinyxml2::XMLNode* firstChild = doc.FirstChild();\n\tif (!firstChild || !firstChild->ToDeclaration())\n\t\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\terror = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (error)\n\t\treturn false;\n\n\treturn true;\n}\n"
  },
  {
    "path": "src/components/SliderSet.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <tinyxml2.h>\n\n#include \"../components/NormalGenLayers.h\"\n#include \"SliderData.h\"\n\nusing namespace tinyxml2;\n\n\nstruct SliderSetShape {\npublic:\n\tconstexpr static float SliderSetDefaultSmoothAngle = 60.0f;\n\n\tstd::string targetShape; // Target names mapped to nif file shape names.\n\tstd::vector<std::string> dataFolders; // Overwrites default data folder of slider set.\n\tbool smoothSeamNormals = true;\n\tfloat smoothSeamNormalsAngle = SliderSetDefaultSmoothAngle;\n\tbool lockNormals = false;\n};\n\nclass SliderSet {\n\tstd::string name;\n\tstd::string baseDataPath; // Base data path - from application configuration.\n\tstd::string datafolder;\t  // Default data folder specified for a slider set.\n\tstd::string inputfile;\n\tstd::string outputpath;\n\tstd::string outputfile;\n\tbool genWeights = false; // Generate both low and high weight meshes on output.\n\tbool preventMorphFile = false; // Prevents the building of morph .tri files in BodySlide for this project.\n\tbool keepZappedShapes = false; // Prevents the removal of fully zapped shapes when building in BodySlide.\n\n\tstd::map<std::string, SliderSetShape> shapeAttributes;\n\n\tstd::vector<SliderData> sliders;\n\tstd::vector<NormalGenLayer> defNormalGen;\n\n\tstd::string notes;\n\n\t// Reference project info\n\tstd::string refProjectFile;     // OSP file path relative to project dir\n\tstd::string refProjectName;     // Slider set name in the OSP file\n\tstd::string refShapeName;       // Shape name in the project\n\n\tSliderData Empty;\n\npublic:\n\tSliderSet();\n\tSliderSet(XMLElement* sliderSetSource);\n\t~SliderSet();\n\n\tvoid SetName(const std::string& newName) { name = newName; }\n\tvoid SetDataFolder(const std::string& newDataFolder) { datafolder = newDataFolder; }\n\tvoid SetInputFile(const std::string& newInputFile) { inputfile = newInputFile; }\n\tvoid SetOutputPath(const std::string& newOutputpath) { outputpath = newOutputpath; }\n\tvoid SetOutputFile(const std::string& newOutputFile) { outputfile = newOutputFile; }\n\tvoid SetGenWeights(bool inGenWeights) { genWeights = inGenWeights; }\n\tvoid SetPreventMorphFile(bool inPreventMorphFile) { preventMorphFile = inPreventMorphFile; }\n\tvoid SetKeepZappedShapes(bool inKeepZappedShapes) { keepZappedShapes = inKeepZappedShapes; }\n\n\tstd::string GetNotes() { return notes; }\n\tvoid SetNotes(const std::string& inNotes) { notes = inNotes; }\n\n\tbool HasReferenceInfo() const { return !refProjectFile.empty() && !refProjectName.empty() && !refShapeName.empty(); }\n\tvoid SetReferenceInfo(const std::string& projectFile, const std::string& projectName, const std::string& shapeName) {\n\t\trefProjectFile = projectFile;\n\t\trefProjectName = projectName;\n\t\trefShapeName = shapeName;\n\t}\n\tvoid ClearReferenceInfo() {\n\t\trefProjectFile.clear();\n\t\trefProjectName.clear();\n\t\trefShapeName.clear();\n\t}\n\tconst std::string& GetReferenceProjectFile() const { return refProjectFile; }\n\tconst std::string& GetReferenceProjectName() const { return refProjectName; }\n\tconst std::string& GetReferenceShapeName() const { return refShapeName; }\n\n\tvoid Clear() {\n\t\tshapeAttributes.clear();\n\t\tsliders.clear();\n\t}\n\n\tstd::string GetBaseDataPath() { return baseDataPath; }\n\tvoid SetBaseDataPath(const std::string& inPath) { baseDataPath = inPath; }\n\n\tstd::vector<NormalGenLayer>& GetNormalsGenLayers() { return defNormalGen; }\n\n\tint LoadSliderSet(XMLElement* sliderSetSource, bool appendNewSliders = true);\n\tvoid LoadSetDiffData(DiffDataSets& inDataStorage, const std::string& forShape = \"\");\n\n\tvoid Merge(SliderSet& mergeSet,\n\t\t\t   DiffDataSets& inDataStorage,\n\t\t\t   DiffDataSets& baseDiffData,\n\t\t\t   const std::string& baseShape,\n\t\t\t   const bool newDataLocal = true,\n\t\t\t   const bool appendNewSliders = true);\n\n\t// Add an empty slider.\n\tsize_t CreateSlider(const std::string& sliderName);\n\n\tsize_t CopySlider(SliderData* other);\n\n\tvoid WriteSliderSet(XMLElement* sliderSetElement);\n\n\tsize_t CloneSlider(const std::string& sliderName, const std::string& cloneName);\n\tvoid DeleteSlider(const std::string& sliderName);\n\n\tstd::string GetName() { return name; }\n\n\tstd::string GetInputFile() { return inputfile; }\n\tstd::string GetInputFileName();\n\tstd::string GetOutputPath() { return outputpath; }\n\tstd::string GetOutputFile() { return outputfile; }\n\tstd::string GetOutputFilePath();\n\tstd::string GetDefaultDataFolder() { return datafolder; }\n\n\tbool GenWeights();\n\tbool PreventMorphFile();\n\tbool KeepZappedShapes();\n\n\tbool GetSmoothSeamNormals(const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end())\n\t\t\treturn shape->second.smoothSeamNormals;\n\n\t\treturn true;\n\t}\n\n\tfloat GetSmoothSeamNormalsAngle(const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end())\n\t\t\treturn shape->second.smoothSeamNormalsAngle;\n\n\t\treturn SliderSetShape::SliderSetDefaultSmoothAngle;\n\t}\n\n\tvoid SetSmoothSeamNormals(const std::string& shapeName, const bool smooth) {\n\t\tAddMissingTarget(shapeName);\n\n\t\tauto& shape = shapeAttributes[shapeName];\n\t\tshape.smoothSeamNormals = smooth;\n\t}\n\n\tvoid SetSmoothSeamNormalsAngle(const std::string& shapeName, const float angle) {\n\t\tAddMissingTarget(shapeName);\n\n\t\tauto& shape = shapeAttributes[shapeName];\n\t\tshape.smoothSeamNormalsAngle = angle;\n\t}\n\n\tbool GetLockNormals(const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end())\n\t\t\treturn shape->second.lockNormals;\n\n\t\treturn false;\n\t}\n\n\tvoid SetLockNormals(const std::string& shapeName, bool lock) {\n\t\tAddMissingTarget(shapeName);\n\n\t\tauto& shape = shapeAttributes[shapeName];\n\t\tshape.lockNormals = lock;\n\t}\n\n\t// Gets the target names in the targetdatafolders map - these are the shapes with non-local or referenced data.\n\t// Use TargetToShape to get the NIF file shape name.\n\tvoid GetReferencedTargets(std::vector<std::string>& outTargets) {\n\t\tfor (auto& s : shapeAttributes) {\n\t\t\tif (s.second.dataFolders.empty()) {\n\t\t\t\toutTargets.push_back(s.second.targetShape);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tfor (auto& df : s.second.dataFolders) {\n\t\t\t\tif (df != datafolder) {\n\t\t\t\t\toutTargets.push_back(s.second.targetShape);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid SetReferencedData(const std::string& shapeName, const bool local, bool* hadLocalData = nullptr) {\n\t\tstd::string targetName = ShapeToTarget(shapeName);\n\n\t\tfor (auto& s : sliders) {\n\t\t\tfor (auto& df : s.dataFiles) {\n\t\t\t\tif (df.targetName == targetName) {\n\t\t\t\t\tif (hadLocalData && df.bLocal)\n\t\t\t\t\t\t*hadLocalData = true;\n\t\t\t\t\tdf.bLocal = local;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid SetReferencedDataByName(const std::string& shapeName, const std::string& dataName, const bool local = false) {\n\t\tstd::string targetName = ShapeToTarget(shapeName);\n\t\tfor (auto& s : sliders)\n\t\t\tfor (auto& df : s.dataFiles)\n\t\t\t\tif (df.targetName == targetName && df.dataName == dataName)\n\t\t\t\t\tdf.bLocal = local;\n\t}\n\n\tstd::vector<std::string> GetLocalData(const std::string& shapeName) {\n\t\tstd::vector<std::string> outDataNames;\n\t\tstd::string targetName = ShapeToTarget(shapeName);\n\t\tfor (auto& s : sliders)\n\t\t\tfor (auto& df : s.dataFiles)\n\t\t\t\tif (df.targetName == targetName && df.bLocal)\n\t\t\t\t\toutDataNames.push_back(df.dataName);\n\n\t\treturn outDataNames;\n\t}\n\n\tstd::string SliderFromDataName(const std::string& targetName, const std::string& dataName) {\n\t\tfor (auto& s : sliders) {\n\t\t\tfor (auto& df : s.dataFiles) {\n\t\t\t\tif (df.targetName == targetName && df.dataName == dataName)\n\t\t\t\t\treturn s.name;\n\t\t\t}\n\t\t}\n\t\treturn \"\";\n\t}\n\n\tstd::string TargetToShape(const std::string& targetName) {\n\t\tfor (auto& s : shapeAttributes)\n\t\t\tif (s.second.targetShape == targetName)\n\t\t\t\treturn s.first;\n\n\t\treturn \"\";\n\t}\n\n\tvoid ClearTargets(const std::string& oldTarget) {\n\t\tfor (auto& s : shapeAttributes) {\n\t\t\tif (s.second.targetShape == oldTarget) {\n\t\t\t\ts.second.targetShape.clear();\n\t\t\t\ts.second.dataFolders.clear();\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Retarget(const std::string& oldTarget, const std::string& newTarget) {\n\t\tfor (auto& s : sliders)\n\t\t\tfor (auto& df : s.dataFiles)\n\t\t\t\tif (df.targetName == oldTarget)\n\t\t\t\t\tdf.targetName = newTarget;\n\t}\n\n\tvoid AddMissingTarget(const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape == shapeAttributes.end()) {\n\t\t\tauto& newShape = shapeAttributes[shapeName];\n\t\t\tnewShape.targetShape = shapeName;\n\t\t}\n\t}\n\n\tvoid AddShapeTarget(const std::string& shapeName, const std::string& targetName) {\n\t\tauto& shape = shapeAttributes[shapeName];\n\t\tshape.targetShape = targetName;\n\t}\n\n\tvoid RenameShape(const std::string& shapeName, const std::string& newShapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end()) {\n\t\t\tfor (auto& slider : sliders)\n\t\t\t\tslider.RenameTarget(shape->second.targetShape, newShapeName, slider.name);\n\n\t\t\tshape->second.targetShape = newShapeName;\n\t\t\tshapeAttributes[newShapeName] = shape->second;\n\t\t\tshapeAttributes.erase(shapeName);\n\t\t}\n\t}\n\n\tvoid SetTargetDataFolders(const std::string& targetName, const std::vector<std::string>& dataFolders) {\n\t\tfor (auto& s : shapeAttributes)\n\t\t\tif (s.second.targetShape == targetName)\n\t\t\t\ts.second.dataFolders = dataFolders;\n\t}\n\n\tvoid AddTargetDataFolder(const std::string& targetName, const std::string& dataFolder) {\n\t\tfor (auto& s : shapeAttributes) {\n\t\t\tif (s.second.targetShape == targetName) {\n\t\t\t\tif (std::find(std::cbegin(s.second.dataFolders), std::cend(s.second.dataFolders), dataFolder) == s.second.dataFolders.cend())\n\t\t\t\t\ts.second.dataFolders.push_back(dataFolder);\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::map<std::string, SliderSetShape>::const_iterator ShapesBegin() { return shapeAttributes.cbegin(); }\n\tstd::map<std::string, SliderSetShape>::const_iterator ShapesEnd() { return shapeAttributes.cend(); }\n\n\tstd::string ShapeToDataName(const size_t index, const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end() && sliders.size() > index)\n\t\t\treturn sliders[index].TargetDataName(shape->second.targetShape);\n\n\t\treturn \"\";\n\t}\n\n\tstd::string ShapeToTarget(const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end())\n\t\t\treturn shape->second.targetShape;\n\n\t\treturn \"\";\n\t}\n\n\tstd::vector<std::string> GetShapeDataFolders(const std::string& shapeName) {\n\t\tauto shape = shapeAttributes.find(shapeName);\n\t\tif (shape != shapeAttributes.end()) {\n\t\t\tif (!shape->second.dataFolders.empty())\n\t\t\t\treturn shape->second.dataFolders;\n\t\t}\n\n\t\tstd::vector<std::string> dataFolders;\n\t\tdataFolders.push_back(datafolder);\n\t\treturn dataFolders;\n\t}\n\n\tsize_t size() { return sliders.size(); }\n\n\tSliderData& operator[](const size_t idx) { return sliders[idx]; }\n\n\tSliderData& operator[](const std::string& sliderName) {\n\t\tfor (size_t i = 0; i < sliders.size(); i++)\n\t\t\tif (sliders[i].name == sliderName)\n\t\t\t\treturn sliders[i];\n\n\t\treturn Empty; // Err... sorry... this is bad, but I really like returning references.\n\t}\n\n\tbool SliderExists(const std::string& sliderName) {\n\t\tfor (size_t i = 0; i < sliders.size(); i++)\n\t\t\tif (sliders[i].name == sliderName)\n\t\t\t\treturn true;\n\n\t\treturn false;\n\t}\n};\n\n/* Does not manage set information, just provides an interface for loading/saving to specfic set files.\ninformation is maintained in the tinyxml document object, and sets can be retrieved and added/updated to that\ndocument while the slidersetfile object exists.\n*/\nclass SliderSetFile {\n\tXMLDocument doc;\n\tXMLElement* root = nullptr;\n\tstd::map<std::string, XMLElement*> setsInFile;\n\tstd::vector<std::string> setsOrder;\n\tint version = 1;\n\tint error = 0;\n\npublic:\n\tstd::string fileName;\n\n\tSliderSetFile() {}\n\tSliderSetFile(const std::string& srcFileName);\n\n\tbool fail() { return error != 0; }\n\tint GetError() { return error; }\n\n\t// Loads the XML document and identifies included slider set names. On a failure, sets the internal error value.\n\tvoid Open(const std::string& srcFileName);\n\n\t// Creates a new empty slider set document structure, ready to add new slider sets to.\n\tvoid New(const std::string& newFileName);\n\n\t// Returns a list of all the slider sets found in the slider set file.\n\tint GetSetNames(std::vector<std::string>& outSetNames, bool append = true);\n\t// Returns a list of all the slider sets found in the slider set file in the order they appear.\n\tint GetSetNamesUnsorted(std::vector<std::string>& outSetNames, bool append = true);\n\t// Returns true if the set name exists.\n\tbool HasSet(const std::string& querySetName);\n\n\tvoid SetShapes(const std::string& set, std::vector<std::string>& outShapeNames);\n\n\t// Gets a single slider set from the XML document based on the name.\n\tint GetSet(const std::string& setName, SliderSet& outSliderSet, bool appendNewSliders = true);\n\t// Adds all of the slider sets in the file to the supplied slider set vector. Does not clear the vector before doing so.\n\tint GetAllSets(std::vector<SliderSet>& outAppendSets);\n\t// Gets only the output file path for the set\n\tvoid GetSetOutputFilePath(const std::string& setName, std::string& outFilePath);\n\t// Updates a slider set in the xml document with the provided set's information.\n\t// If the set does not already exist in the file (based on name) the set is added.\n\tint UpdateSet(SliderSet& inSliderSet);\n\n\t// Deletes a single slider set from the XML document based on the name.\n\tint DeleteSet(const std::string& setName);\n\n\t// Writes the xml file using the internal fileName (use Rename() to change the name).\n\tbool Save();\n};\n"
  },
  {
    "path": "src/components/TweakBrush.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"TweakBrush.h\"\n#include \"Anim.h\"\n#include \"WeightNorm.h\"\n\nusing namespace nifly;\n\nstd::vector<std::future<void>> TweakStroke::normalUpdates{};\n\nvoid TweakStroke::beginStroke(TweakPickInfo& pickInfo) {\n\tconst int nMesh = refMeshes.size();\n\tusp.usss.resize(nMesh);\n\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\tMesh* m = refMeshes[mi];\n\t\tusp.usss[mi].shapeName = m->shapeName;\n\n\t\tpts1[m] = std::make_unique<int[]>(m->nVerts);\n\t\tif (refBrush->isMirrored())\n\t\t\tpts2[m] = std::make_unique<int[]>(m->nVerts);\n\t}\n\n\trefBrush->strokeInit(refMeshes, pickInfo, usp);\n}\n\nvoid TweakStroke::beginStroke(TweakPickInfo& pickInfo, std::vector<std::vector<Vector3>>& positionData) {\n\tbeginStroke(pickInfo);\n\trefBrush->strokeInit(refMeshes, pickInfo, usp, positionData);\n}\n\nvoid TweakStroke::updateStroke(TweakPickInfo& pickInfo) {\n\tTweakBrush::BrushType brushType = refBrush->Type();\n\n\tTweakPickInfo mirrorPick = pickInfo;\n\tmirrorPick.origin.x *= -1.0f;\n\tmirrorPick.normal.x *= -1.0f;\n\n\tif (!newStroke) {\n\t\tif (!refBrush->checkSpacing(lastPoint, pickInfo.origin))\n\t\t\treturn;\n\t}\n\telse\n\t\tnewStroke = false;\n\n\t// Remove finished tasks\n\tfor (size_t i = 0; i < normalUpdates.size(); i++) {\n\t\tif (normalUpdates[i].wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {\n\t\t\tnormalUpdates.erase(normalUpdates.begin() + i);\n\t\t\ti--;\n\t\t}\n\t}\n\n\tconst int nMesh = refMeshes.size();\n\t// Move/transform handles most operations differently than other brushes.\n\t// Mirroring is done internally, most of the pick info values are ignored.\n\tif (brushType == TweakBrush::BrushType::Move || brushType == TweakBrush::BrushType::Transform) {\n\t\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\t\tMesh* m = refMeshes[mi];\n\t\t\tUndoStateShape& uss = usp.usss[mi];\n\t\t\tint nPts1 = 0;\n\n\t\t\tif (!refBrush->queryPoints(m, pickInfo, mirrorPick, nullptr, nPts1, affectedNodes[m]))\n\t\t\t\tcontinue;\n\n\t\t\trefBrush->brushAction(m, pickInfo, nullptr, nPts1, uss);\n\n\t\t\tif (refBrush->LiveNormals() && normalUpdates.empty()) {\n\t\t\t\tauto pending = async(std::launch::async, Mesh::SmoothNormalsStaticMap, m, uss.pointStartState);\n\t\t\t\tnormalUpdates.push_back(std::move(pending));\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\t\tMesh* m = refMeshes[mi];\n\t\t\tUndoStateShape& uss = usp.usss[mi];\n\t\t\tint nPts1 = 0;\n\t\t\tint nPts2 = 0;\n\n\t\t\tif (!refBrush->queryPoints(m, pickInfo, mirrorPick, pts1[m].get(), nPts1, affectedNodes[m]))\n\t\t\t\tcontinue;\n\n\t\t\tif (refBrush->isMirrored() && !refBrush->NeedMirrorMergedQuery())\n\t\t\t\trefBrush->queryPoints(m, mirrorPick, pickInfo, pts2[m].get(), nPts2, affectedNodes[m]);\n\n\t\t\trefBrush->brushAction(m, pickInfo, pts1[m].get(), nPts1, uss);\n\n\t\t\tif (refBrush->isMirrored() && nPts2 > 0)\n\t\t\t\trefBrush->brushAction(m, mirrorPick, pts2[m].get(), nPts2, uss);\n\n\t\t\tif (refBrush->LiveNormals() && normalUpdates.empty()) {\n\t\t\t\tauto pending1 = std::async(std::launch::async, Mesh::SmoothNormalsStaticArray, m, pts1[m].get(), nPts1);\n\t\t\t\tnormalUpdates.push_back(std::move(pending1));\n\n\t\t\t\tif (refBrush->isMirrored() && nPts2 > 0 && normalUpdates.size() <= 1) {\n\t\t\t\t\tauto pending2 = std::async(std::launch::async, Mesh::SmoothNormalsStaticArray, m, pts2[m].get(), nPts2);\n\t\t\t\t\tnormalUpdates.push_back(std::move(pending2));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlastPoint = pickInfo.origin;\n\n\tif (refBrush->LiveBVH()) {\n\t\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\t\tMesh* m = refMeshes[mi];\n\t\t\tfor (auto& bvhNode : affectedNodes[m])\n\t\t\t\tbvhNode->UpdateAABB();\n\t\t}\n\t}\n}\n\nvoid TweakStroke::endStroke() {\n\tconst int nMesh = refMeshes.size();\n\tif (refBrush->Type() == TweakBrush::BrushType::Move) {\n\t\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\t\tMesh* m = refMeshes[mi];\n\t\t\tTweakBrushMeshCache* meshCache = refBrush->getCache(m);\n\t\t\taffectedNodes[m].swap(meshCache->cachedNodes);\n\t\t\taffectedNodes[m].insert(meshCache->cachedNodesM.begin(), meshCache->cachedNodesM.end());\n\t\t\tmeshCache->cachedNodes.clear();\n\t\t\tmeshCache->cachedNodesM.clear();\n\t\t}\n\t}\n\telse if (refBrush->Type() == TweakBrush::BrushType::Transform)\n\t\tfor (int mi = 0; mi < nMesh; ++mi)\n\t\t\trefMeshes[mi]->CreateBVH();\n\n\tif (!refBrush->LiveBVH() && refBrush->Type() != TweakBrush::BrushType::Weight)\n\t\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\t\tMesh* m = refMeshes[mi];\n\t\t\tfor (auto& bvhNode : affectedNodes[m])\n\t\t\t\tbvhNode->UpdateAABB();\n\t\t}\n\n\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\tauto pending = std::async(std::launch::async, Mesh::SmoothNormalsStatic, refMeshes[mi]);\n\t\tnormalUpdates.push_back(std::move(pending));\n\t}\n\n\tbool notReady = true;\n\twhile (notReady) {\n\t\tnotReady = false;\n\t\tfor (size_t i = 0; i < normalUpdates.size(); i++) {\n\t\t\tif (normalUpdates[i].wait_for(std::chrono::milliseconds(1)) == std::future_status::ready) {\n\t\t\t\tnormalUpdates.erase(normalUpdates.begin() + i);\n\t\t\t\ti--;\n\t\t\t}\n\t\t\telse\n\t\t\t\tnotReady = true;\n\t\t}\n\t}\n}\n\nTweakBrush::TweakBrush() {\n\tresetSettings();\n\n\tbMirror = true;\n\tbLiveBVH = true;\n\tbLiveNormals = true;\n\tbConnected = false;\n}\n\nTweakBrush::~TweakBrush() {}\n\nvoid TweakBrush::strokeInit(const std::vector<Mesh*>& refMeshes, TweakPickInfo&, UndoStateProject&) {\n\tcache.clear();\n\n\tif (NeedStartNorms()) {\n\t\tfor (Mesh* m : refMeshes) {\n\t\t\tTweakBrushMeshCache& meshCache = cache[m];\n\t\t\tmeshCache.startNorms = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tstd::copy(m->norms.get(), m->norms.get() + m->nVerts, meshCache.startNorms.get());\n\t\t}\n\t}\n}\n\nbool TweakBrush::checkSpacing(Vector3& start, Vector3& end) {\n\tfloat d = start.DistanceTo(end);\n\tif (d > spacing)\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\nfloat TweakBrush::getFalloff(float dist, float meshradius) {\n\t// Beyond the radius, no strength\n\tif (dist > meshradius)\n\t\treturn 0.0;\n\n\t// No distance, keep strength\n\tif (dist == 0.0f)\n\t\treturn 1.0;\n\n\tfloat p = std::pow(6.0f, focus * 2.0f - 1.0f);\n\tfloat x = std::pow(dist / meshradius, p);\n\treturn (2 * x - 3) * x * x + 1;\n}\n\nvoid TweakBrush::applyFalloff(Vector3& deltaVec, float dist, float meshradius) {\n\tdeltaVec *= getFalloff(dist, meshradius);\n}\n\nbool TweakBrush::queryPoints(\n\tMesh* m, TweakPickInfo& pickInfo, TweakPickInfo& mirrorPick, int* resultPoints, int& outResultCount, std::unordered_set<AABBTree::AABBTreeNode*>& affectedNodes) {\n\tstd::vector<IntersectResult> IResults;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\tVector3 meshmirrororigin = m->TransformPosModelToMesh(mirrorPick.origin);\n\n\tif (!m->bvh || !m->bvh->IntersectSphere(meshorigin, meshradius, &IResults))\n\t\treturn false;\n\tunsigned int mirrorStartInd = IResults.size();\n\tbool mergeMirror = NeedMirrorMergedQuery();\n\tif (mergeMirror)\n\t\tm->bvh->IntersectSphere(meshmirrororigin, meshradius, &IResults);\n\n\tstd::vector<bool> pointVisit(m->nVerts, false);\n\n\tif (bConnected && !IResults.empty()) {\n\t\tint pickFacet1 = IResults[0].HitFacet;\n\t\tfloat minDist = IResults[0].HitDistance;\n\t\tfor (unsigned int i = 0; i < mirrorStartInd; ++i) {\n\t\t\tauto& r = IResults[i];\n\t\t\tif (r.HitDistance < minDist) {\n\t\t\t\tminDist = r.HitDistance;\n\t\t\t\tpickFacet1 = r.HitFacet;\n\t\t\t}\n\t\t}\n\n\t\tif (mergeMirror && mirrorStartInd < IResults.size()) {\n\t\t\tint pickFacet2 = IResults[mirrorStartInd].HitFacet;\n\t\t\tminDist = IResults[mirrorStartInd].HitDistance;\n\t\t\tfor (unsigned int i = mirrorStartInd; i < IResults.size(); ++i) {\n\t\t\t\tauto& r = IResults[i];\n\t\t\t\tif (r.HitDistance < minDist) {\n\t\t\t\t\tminDist = r.HitDistance;\n\t\t\t\t\tpickFacet2 = r.HitFacet;\n\t\t\t\t}\n\t\t\t}\n\t\t\tm->ConnectedPointsInTwoSpheres(meshorigin, meshmirrororigin, meshradius * meshradius, pickFacet1, pickFacet2, pointVisit, resultPoints, outResultCount);\n\t\t}\n\t\telse\n\t\t\tm->ConnectedPointsInSphere(meshorigin, meshradius * meshradius, pickFacet1, pointVisit, resultPoints, outResultCount);\n\t}\n\telse\n\t\toutResultCount = 0;\n\n\tfor (unsigned int i = 0; i < IResults.size(); i++) {\n\t\tif (!bConnected) {\n\t\t\tconst Triangle& t = m->tris[IResults[i].HitFacet];\n\t\t\tif (!pointVisit[t.p1]) {\n\t\t\t\tresultPoints[outResultCount++] = t.p1;\n\t\t\t\tpointVisit[t.p1] = true;\n\t\t\t}\n\t\t\tif (!pointVisit[t.p2]) {\n\t\t\t\tresultPoints[outResultCount++] = t.p2;\n\t\t\t\tpointVisit[t.p2] = true;\n\t\t\t}\n\t\t\tif (!pointVisit[t.p3]) {\n\t\t\t\tresultPoints[outResultCount++] = t.p3;\n\t\t\t\tpointVisit[t.p3] = true;\n\t\t\t}\n\t\t}\n\t\taffectedNodes.insert(IResults[i].bvhNode);\n\t}\n\n\treturn true;\n}\n\n/* ParabolaFit: this function fits a parabola through the values for five\npoints: pti, p1, p2, op1, and op2.  This parabola fit gives a new value for\npti, which is returned.  */\ntemplate<typename ValueFuncType>\nfloat ParabolaFit(Mesh* m, int pti, int p1, int p2, const ValueFuncType& ValueFunc) {\n\tconstexpr float maxDotForDeriv = -0.5f;\n\n\tconst Vector3& tv = m->verts[pti];\n\tconst Vector3& v1 = m->verts[p1];\n\tconst Vector3& v2 = m->verts[p2];\n\tfloat tvw = ValueFunc(pti);\n\tfloat v1w = ValueFunc(p1);\n\tfloat v2w = ValueFunc(p2);\n\n\t// Find derivative of weight at p1 in roughly the direction\n\t// from p1 to pti.\n\tint op1 = m->FindOpposingPoint(p1, pti, maxDotForDeriv);\n\tfloat deriv1 = 0.0f;\n\tif (op1 == -1) {\n\t\tfloat len1 = (tv - v1).length();\n\t\tif (len1 > 1e-6f)\n\t\t\tderiv1 = (tvw - v1w) / len1;\n\t\telse\n\t\t\tderiv1 = 0.0f;\n\t}\n\telse {\n\t\tconst Vector3& ov1 = m->verts[op1];\n\t\tfloat ov1w = ValueFunc(op1);\n\t\tfloat len1 = (tv - ov1).length();\n\t\tif (len1 > 1e-6f)\n\t\t\tderiv1 = (tvw - ov1w) / len1;\n\t\telse\n\t\t\tderiv1 = 0.0f;\n\t}\n\n\t// Find derivative of weight at p2 in roughly the direction\n\t// from p2 to pti.\n\tint op2 = m->FindOpposingPoint(p2, pti, maxDotForDeriv);\n\tfloat deriv2 = 0.0f;\n\tif (op2 == -1) {\n\t\tfloat len2 = (tv - v2).length();\n\t\tif (len2 > 1e-6f)\n\t\t\tderiv2 = (tvw - v2w) / len2;\n\t\telse\n\t\t\tderiv2 = 0.0f;\n\t}\n\telse {\n\t\tconst Vector3& ov2 = m->verts[op2];\n\t\tfloat ov2w = ValueFunc(op2);\n\t\tfloat len2 = (tv - ov2).length();\n\t\tif (len2 > 1e-6f)\n\t\t\tderiv2 = (tvw - ov2w) / len2;\n\t\telse\n\t\t\tderiv2 = 0.0f;\n\t}\n\n\t// Second derivative of weight at pti in roughly the direction\n\t// from p1 to p2, wrt t, with t=0 at p1 and t=1 at p2.\n\tfloat secderiv = -(deriv1 + deriv2) * (v2 - v1).length();\n\n\t// Calculate t, which is where pti is along the segment from\n\t// p1 to p2.\n\tfloat denom = (v2 - v1).length2();\n\tfloat t = 0.5f;\n\tif (denom > 1e-12f)\n\t\tt = (tv - v1).dot(v2 - v1) / denom;\n\n\t// Parabola fit of weight at pti.\n\treturn v1w + (v2w - v1w) * t - 0.5f * secderiv * t * (1 - t);\n}\n\nTB_Inflate::TB_Inflate() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Inflate;\n\tbrushName = \"Inflate Brush\";\n}\n\nTB_Inflate::~TB_Inflate() {}\n\nvoid TB_Inflate::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tMatrix4 xform;\n\tfloat meshstrength = m->TransformDistModelToMesh(strength);\n\txform.Translate(m->TransformDirModelToMesh(pickInfo.normal) * meshstrength);\n\tVector3 vs;\n\tVector3 ve;\n\tVector3 vf;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vs;\n\t\tif (restrictNormal) {\n\t\t\tconst Vector3& n = cache[m].startNorms[points[i]];\n\t\t\tve = n * meshstrength;\n\t\t}\n\t\telse {\n\t\t\tve = xform * vs;\n\t\t\tve -= vs;\n\t\t}\n\n\t\tapplyFalloff(ve, meshorigin.DistanceTo(vs), meshradius);\n\n\t\tve = ve * (1.0f - m->mask[points[i]]);\n\n\t\tvf = vs + ve;\n\n\t\tendState[points[i]] = m->verts[points[i]] = (vf);\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n}\n\nTB_Mask::TB_Mask() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Mask;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Mask Brush\";\n}\n\nTB_Mask::~TB_Mask() {}\n\nvoid TB_Mask::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tVector3 vs;\n\tVector3 vc;\n\tVector3 ve;\n\tVector3 vf;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tvc = Vector3(m->mask[points[i]], 0.0f, 0.0f);\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vc;\n\n\t\tve = vc;\n\t\tif (strength < 1.0f)\n\t\t\tve.x += strength;\n\t\telse\n\t\t\tve.x += 1.0f;\n\t\tve -= vc;\n\n\t\tfloat originToV = meshorigin.DistanceTo(vs);\n\t\tif (originToV > meshradius)\n\t\t\tve.Zero();\n\t\telse if (strength < 1.0f)\n\t\t\tapplyFalloff(ve, originToV, meshradius);\n\n\t\tvf = vc + ve;\n\t\tif (vf.x > 1.0f)\n\t\t\tvf.x = 1.0f;\n\n\t\tm->mask[points[i]] = vf.x;\n\t\tendState[points[i]] = vf;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Mask);\n}\n\nTB_Unmask::TB_Unmask() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Mask;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Unmask Brush\";\n}\n\nTB_Unmask::~TB_Unmask() {}\n\nvoid TB_Unmask::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tVector3 vs;\n\tVector3 vc;\n\tVector3 ve;\n\tVector3 vf;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tvc = Vector3(m->mask[points[i]], 0.0f, 0.0f);\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vc;\n\n\t\tve = vc;\n\t\tif (strength > -1.0f)\n\t\t\tve.x += strength;\n\t\telse\n\t\t\tve.x -= 1.0f;\n\t\tve -= vc;\n\n\t\tfloat originToV = meshorigin.DistanceTo(vs);\n\t\tif (originToV > meshradius)\n\t\t\tve.Zero();\n\t\telse if (strength > -1.0f)\n\t\t\tapplyFalloff(ve, originToV, meshradius);\n\n\t\tvf = vc + ve;\n\t\tif (vf.x < 0.0f)\n\t\t\tvf.x = 0.0f;\n\n\t\tm->mask[points[i]] = vf.x;\n\t\tendState[points[i]] = vf;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Mask);\n}\n\nTB_SmoothMask::TB_SmoothMask() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Mask;\n\tmethod = 2;\n\thcAlpha = 0.2f;\n\thcBeta = 0.5f;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Mask Smooth\";\n}\n\nTB_SmoothMask::~TB_SmoothMask() {}\n\nvoid TB_SmoothMask::lapFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, Vector3>& wv) {\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[points[i]];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\t\t// average adjacent points positions, using values from last iteration.\n\t\tfloat d = 0.0f;\n\t\tfor (int apt : adjPoints)\n\t\t\td += m->mask[apt];\n\t\tVector3 result(d / c, 0.0f, 0.0f);\n\t\twv[points[i]] = result;\n\n\t\tm->DoForEachWeldedVertex(points[i], [&](int p) {wv[p] = result;});\n\t}\n}\n\nvoid TB_SmoothMask::hclapFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, Vector3>& wv, UndoStateShape& uss) {\n\tstd::vector<Vector3> b(m->nVerts);\n\n\t// First step is to calculate the laplacian\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[i];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\t\t// average adjacent points positions, using values from last iteration.\n\t\tVector3 d;\n\t\tfor (int apt : adjPoints)\n\t\t\td += Vector3(m->mask[apt], 0.0f, 0.0f);\n\t\twv[i] = d / (float)c;\n\t\t// Calculate the difference between the new position and a blend of the original and previous positions\n\t\tb[i] = wv[i] - ((uss.pointStartState[i] * hcAlpha) + (Vector3(m->mask[i], 0.0f, 0.0f) * (1.0f - hcAlpha)));\n\t}\n\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\t// Check if it's a welded vertex; only do welded vertices once.\n\t\tif (m->LeastWeldedVertexIndex(i) != i)\n\t\t\tcontinue;\n\t\t// Average 'b' for adjacent points\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[i];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\t\tVector3 d;\n\t\tfor (int apt : adjPoints)\n\t\t\td += b[apt];\n\n\t\t// blend the new position and the average of the distance moved\n\t\tfloat avgB = (1 - hcBeta) / (float)c;\n\t\twv[i] -= ((b[i] * hcBeta) + (d * avgB));\n\n\t\tm->DoForEachWeldedVertex(i, [&](int pt) {wv[pt] = wv[i];});\n\t}\n}\n\nvoid TB_SmoothMask::bppfFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, Vector3>& wv, UndoStateShape& uss) {\n\tint balPts[Mesh::MaxAdjacentPoints];\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tint pti = points[i];\n\n\t\t// Check if it's a welded vertex; only do welded vertices once.\n\t\tif (m->LeastWeldedVertexIndex(pti) != pti)\n\t\t\tcontinue;\n\n\t\tint balCount = m->FindAdjacentBalancedPairs(pti, balPts);\n\t\tif (balCount == 0)\n\t\t\tcontinue;\n\n\t\tfloat d = 0.0;\n\t\tfor (int n = 0; n < balCount; n += 2) {\n\t\t\tint p1 = balPts[n];\n\t\t\tint p2 = balPts[n + 1];\n\t\t\tfloat fitm = ParabolaFit(m, pti, p1, p2, [&uss, &m](int p) {\n\t\t\t\tauto pssit = uss.pointStartState.find(p);\n\t\t\t\tif (pssit != uss.pointStartState.end())\n\t\t\t\t\treturn pssit->second.x;\n\t\t\t\treturn m->mask[p];\n\t\t\t});\n\n\t\t\td += fitm;\n\t\t}\n\n\t\twv[pti] = Vector3(d / (balCount / 2), 0.0f, 0.0f);\n\n\t\tm->DoForEachWeldedVertex(pti, [&](int p) {wv[p] = wv[pti];});\n\t}\n}\n\nvoid TB_SmoothMask::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tstd::unordered_map<int, Vector3> wv;\n\tVector3 vs;\n\tVector3 vc;\n\tfloat vm;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvc = Vector3(m->mask[points[i]], 0.0f, 0.0f);\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vc;\n\t\twv[points[i]] = vc;\n\t}\n\n\tif (method == 0) // laplacian smooth\n\t\tlapFilter(m, points, nPoints, wv);\n\telse if (method == 1) // HC-laplacian smooth\n\t\thclapFilter(m, points, nPoints, wv, uss);\n\telse\t// balanced-pair parabola-fit smooth\n\t\tbppfFilter(m, points, nPoints, wv, uss);\n\n\tVector3 delta;\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\tvs = m->verts[i];\n\t\tvm = m->mask[i];\n\t\tdelta.x = wv[i].x - vm;\n\t\tdelta.x *= strength;\n\n\t\tapplyFalloff(delta, meshorigin.DistanceTo(vs), meshradius);\n\n\t\tvm += delta.x;\n\n\t\tif (vm < EPSILON)\n\t\t\tvm = 0.0f;\n\t\tif (vm > 1.0f)\n\t\t\tvm = 1.0f;\n\t\tendState[i].x = m->mask[i] = vm;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Mask);\n}\n\nTB_Deflate::TB_Deflate() {\n\tresetSettings();\n\n\tbrushName = \"Deflate Brush\";\n}\n\nTB_Deflate::~TB_Deflate() {}\n\nvoid TB_Deflate::setStrength(float newStr) {\n\tstrength = -(newStr / 10.0f);\n}\n\nfloat TB_Deflate::getStrength() {\n\treturn -strength * 10.0f;\n}\n\nTB_Smooth::TB_Smooth() {\n\tresetSettings();\n\n\tmethod = 2;\n\thcAlpha = 0.2f;\n\thcBeta = 0.5f;\n\tbrushName = \"Smooth Brush\";\n}\n\nTB_Smooth::~TB_Smooth() {}\n\nvoid TB_Smooth::lapFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, Vector3>& wv) {\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[points[i]];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\t\t// average adjacent points positions, using values from last iteration.\n\t\tVector3 d;\n\t\tfor (int apt : adjPoints)\n\t\t\td += m->verts[apt];\n\t\tVector3 result = d / c;\n\t\twv[points[i]] = result;\n\n\t\tm->DoForEachWeldedVertex(points[i], [&](int p) {wv[p] = result;});\n\t}\n}\n\nvoid TB_Smooth::hclapFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, Vector3>& wv, UndoStateShape& uss) {\n\tstd::vector<Vector3> b(m->nVerts);\n\n\t// First step is to calculate the laplacian\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[i];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\t\t// average adjacent points positions, using values from last iteration.\n\t\tVector3 d;\n\t\tfor (int apt : adjPoints)\n\t\t\td += m->verts[apt];\n\t\twv[i] = d / (float)c;\n\t\t// Calculate the difference between the new position and a blend of the original and previous positions\n\t\tb[i] = wv[i] - ((uss.pointStartState[i] * hcAlpha) + (m->verts[i] * (1.0f - hcAlpha)));\n\t}\n\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\t// Check if it's a welded vertex; only do welded vertices once.\n\t\tif (m->LeastWeldedVertexIndex(i) != i)\n\t\t\tcontinue;\n\n\t\t// Average 'b' for adjacent points\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[i];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\t\tVector3 d;\n\t\tfor (int apt : adjPoints)\n\t\t\td += b[apt];\n\n\t\t// blend the new position and the average of the distance moved\n\t\tfloat avgB = (1 - hcBeta) / (float)c;\n\t\twv[i] -= ((b[i] * hcBeta) + (d * avgB));\n\n\t\tm->DoForEachWeldedVertex(i, [&](int pt) {wv[pt] = wv[i];});\n\t}\n}\n\nstatic Vector3 CircleFitMidpoint(const Vector3& p1, const Vector3& p2, const Vector3& n1, const Vector3& n2) {\n\t// This code is copied from PrepareRefineMesh.\n\t/* We wish to calculate the midpoint of a circular arc between\n\tp1 and p2.  We want the normals at p1 and p2 to be perpendicular\n\tto this arc.  But there's no guarantee that that's possible: the\n\tnormals could have different angles to the arc; and they could\n\teven be non-coplanar.  So we need to average the angles of the\n\tnormals somehow.  */\n\n\t// First, get the unit vector along the segment between p1 and p2\n\tVector3 u12 = p2 - p1;\t// unit vector from p1 to p2\n\tfloat halfseglen = u12.length() * 0.5f;\t// half segment length\n\tu12.Normalize();\n\n\t// Calculate the desired normal at the arc midpoint.  We average the\n\t// two point normals and make the result perpendicular to u12.\n\tVector3 n = n1 + n2;\n\tn -= u12 * u12.dot(n);\n\tn.Normalize();\n\n\t// If we wanted to calculate the angle between one of the two normals and\n\t// n, in the plane of that normal and the segment (since n isn't\n\t// necessarily in that plane), we would do asin(u12.dot(ni)).  We want to\n\t// average this for the two normals and carefully preserve the sign.\n\tfloat sina = u12.dot(n2 - n1) * 0.5f;\n\tfloat alpha = asin(sina);\n\n\t// Alpha is the desired circle angle between the arc midpoint and either\n\t// of our input points.  It's positive for convex, negative for concave.\n\t// To figure out how far off of the segment we need to go, we need to take\n\t// the trigonometric tangent of the correct angle.  It turns out that the\n\t// correct angle is alpha divided by 2.\n\tfloat curveOffsetFactor = tan(alpha * 0.5f);\n\n\t// Now calculate the point.  (curveOffsetFactor is between -1 and 1.)\n\tVector3 mp = (p1 + p2) * 0.5f;\n\tmp += n * (curveOffsetFactor * halfseglen);\n\treturn mp;\n}\n\nstatic Vector3 CircleFitNearestPoint(const Vector3& p1, const Vector3& p2, const Vector3& n1, const Vector3& n2, const Vector3& p) {\n\t// Much of this code is the same as CircleFitMidpoint.  See the comments\n\t// in that function.\n\tVector3 u12 = p2 - p1;\t// unit vector from p1 to p2\n\tfloat halfseglen = u12.length() * 0.5f;\t// half segment length\n\tu12.Normalize();\n\tVector3 n = n1 + n2;\n\tn -= u12 * u12.dot(n);\n\tn.Normalize();\n\tfloat sina = u12.dot(n2 - n1) * 0.5f;\n\tfloat alpha = asin(sina);\n\tfloat curveOffsetFactor = tan(alpha * 0.5f);\n\tVector3 mp = (p1 + p2) * 0.5f;\n\tVector3 amp = mp + n * (curveOffsetFactor * halfseglen);\n\n\t// Now we have some relatively simple new stuff.\n\tfloat cosa = cos(alpha);\n\tVector3 poff = p - mp;\n\tVector3 perp = u12.cross(n);\n\tpoff -= perp * perp.dot(poff); // project poff to circle's plane\n\n\t// Now things get weird.  These formulas make no sense.  I derived them\n\t// from straightforward geometric concepts, but the simple geometric\n\t// formulas had division-by-zero and large-cancellation numerical problems.\n\t// The formulas used here have those numerical problems removed, at the\n\t// expense of making them completely obscure and opaque.  Alpha is the\n\t// (signed) circle angle between p1/p2 and mp.  Beta is the (signed)\n\t// circle angle between (projected) p and mp.  Note that there could\n\t// easily be a gross mistake here, and probably no one would ever\n\t// realize it because the adjustment to amp is tiny.\n\tVector3 denvec = sina * poff + (halfseglen * cosa) * n;\n\tfloat den = denvec.length();\n\tfloat sinboversina = poff.dot(u12) / den;\n\tfloat eoff = halfseglen * sinboversina;\n\tfloat sinb = sina * sinboversina;\n\tfloat beta = asin(sinb);\n\tfloat noff = eoff * tan(beta * 0.5f);\n\treturn amp + eoff * u12 - noff * n;\n}\n\nvoid TB_Smooth::bpcfFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, Vector3>& wv) {\n\tint balPts[Mesh::MaxAdjacentPoints];\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tint pti = points[i];\n\n\t\t// Check if it's a welded vertex; only do welded vertices once.\n\t\tif (m->LeastWeldedVertexIndex(pti) != pti)\n\t\t\tcontinue;\n\n\t\tint balCount = m->FindAdjacentBalancedPairs(pti, balPts);\n\t\tif (balCount == 0)\n\t\t\tcontinue;\n\n\t\t// Average the circle-fit results for each balanced pair\n\t\tVector3 d;\n\t\tfor (int n = 0; n < balCount; n += 2) {\n\t\t\tconst Vector3& p1 = m->verts[balPts[n]];\n\t\t\tconst Vector3& p2 = m->verts[balPts[n + 1]];\n\t\t\tconst Vector3& n1 = cache[m].startNorms[balPts[n]];\n\t\t\tconst Vector3& n2 = cache[m].startNorms[balPts[n + 1]];\n\t\t\tif (restrictNormal)\n\t\t\t\td += CircleFitNearestPoint(p1, p2, n1, n2, m->verts[pti]);\n\t\t\telse\n\t\t\t\td += CircleFitMidpoint(p1, p2, n1, n2);\n\t\t}\n\t\twv[pti] = d / (balCount / 2);\n\n\t\t// Update welded points\n\t\tm->DoForEachWeldedVertex(pti, [&](int p) {wv[p] = wv[pti];});\n\t}\n}\n\nvoid TB_Smooth::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tstd::unordered_map<int, Vector3> wv;\n\tVector3 vs;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vs;\n\t\twv[points[i]] = vs;\n\t}\n\n\tif (method == 0) // laplacian smooth\n\t\tlapFilter(m, points, nPoints, wv);\n\telse if (method == 1) // HC-laplacian smooth\n\t\thclapFilter(m, points, nPoints, wv, uss);\n\telse\t// balanced-pair circle-fit smooth\n\t\tbpcfFilter(m, points, nPoints, wv);\n\n\tVector3 delta;\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\tvs = m->verts[i];\n\t\tdelta = wv[i] - m->verts[i];\n\t\tdelta *= strength;\n\t\tapplyFalloff(delta, meshorigin.DistanceTo(vs), meshradius);\n\n\t\tdelta = delta * (1.0f - m->mask[i]);\n\t\tVector3 ve = m->verts[i] + delta;\n\n\t\tif (restrictNormal) {\n\t\t\tconst Vector3& n = cache[m].startNorms[i];\n\t\t\tve = startState[i] + n * (ve - startState[i]).dot(n);\n\t\t}\n\n\t\tif (restrictPlane) {\n\t\t\tconst Vector3& n = cache[m].startNorms[i];\n\t\t\tve -= startState[i];\n\t\t\tve -= n * ve.dot(n);\n\t\t\tve += startState[i];\n\t\t}\n\n\t\tm->verts[i] = ve;\n\t\tendState[i] = ve;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n}\n\nTB_Undiff::TB_Undiff() {\n\tresetSettings();\n\n\tbrushName = \"Undiff Brush\";\n\tbrushType = TweakBrush::BrushType::Undiff;\n}\n\nTB_Undiff::~TB_Undiff() {}\n\nvoid TB_Undiff::strokeInit(const std::vector<Mesh*>& refMeshes, TweakPickInfo& pickInfo, UndoStateProject& usp, std::vector<std::vector<Vector3>>& positionData) {\n\tTweakBrush::strokeInit(refMeshes, pickInfo, usp);\n\n\tconst int nMesh = refMeshes.size();\n\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\tMesh* m = refMeshes[mi];\n\t\tTweakBrushMeshCache* meshCache = &cache[m];\n\t\tmeshCache->positionData = std::move(positionData[mi]);\n\t}\n}\n\nvoid TB_Undiff::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tTweakBrushMeshCache* meshCache = &cache[m];\n\tstd::vector<Vector3>& basePosition = meshCache->positionData;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tint p;\n\tVector3 vs;\n\tVector3 ve;\n\tVector3 vf;\n\tVector3 bp;\n\tVector3 dv;\n\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tp = points[i];\n\n\t\tif (basePosition.size() > (size_t)p) {\n\t\t\tvs = m->verts[p];\n\t\t\tbp = basePosition[p];\n\n\t\t\tif (startState.find(p) == startState.end())\n\t\t\t\tstartState[p] = vs;\n\n\t\t\tdv = bp - vs;\n\t\t\tve = dv * strength;\n\n\t\t\tapplyFalloff(ve, meshorigin.DistanceTo(vs), meshradius);\n\n\t\t\tve = ve * (1.0f - m->mask[p]);\n\t\t\tvf = vs + ve;\n\n\t\t\tif (vf.IsNearlyEqualTo(bp))\n\t\t\t\tvf = bp;\n\n\t\t\tendState[p] = m->verts[p] = (vf);\n\t\t}\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n}\n\nTB_Move::TB_Move() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Move;\n\tbrushName = \"Move Brush\";\n\tbLiveBVH = false;\n}\n\nTB_Move::~TB_Move() {}\n\nvoid TB_Move::strokeInit(const std::vector<Mesh*>& refMeshes, TweakPickInfo& pickInfo, UndoStateProject& usp) {\n\tpick = pickInfo;\n\tmpick = pickInfo;\n\tmpick.origin.x = -mpick.origin.x;\n\tmpick.view.x = -mpick.view.x;\n\td = pick.origin.dot(pick.view);\n\tmd = mpick.origin.dot(mpick.view);\n\n\tTweakBrush::strokeInit(refMeshes, pickInfo, usp);\n\n\tconst int nMesh = refMeshes.size();\n\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\tMesh* m = refMeshes[mi];\n\t\tUndoStateShape& uss = usp.usss[mi];\n\t\tTweakBrushMeshCache* meshCache = &cache[m];\n\t\tmeshCache->nCachedPoints = 0;\n\t\tmeshCache->nCachedPointsM = 0;\n\t\tauto& startState = uss.pointStartState;\n\t\tmeshCache->cachedPoints.resize(m->nVerts);\n\n\t\tif (bMirror)\n\t\t\tmeshCache->cachedPointsM.resize(m->nVerts);\n\n\t\tif (!TweakBrush::queryPoints(m, pick, mpick, &meshCache->cachedPoints.front(), meshCache->nCachedPoints, meshCache->cachedNodes))\n\t\t\tcontinue;\n\n\t\tfor (int i = 0; i < meshCache->nCachedPoints; i++) {\n\t\t\tint vi = meshCache->cachedPoints[i];\n\t\t\tstartState[vi] = m->verts[vi];\n\t\t}\n\n\t\tif (bMirror) {\n\t\t\tTweakBrush::queryPoints(m, mpick, pick, &meshCache->cachedPointsM.front(), meshCache->nCachedPointsM, meshCache->cachedNodesM);\n\n\t\t\tfor (int i = 0; i < meshCache->nCachedPointsM; i++) {\n\t\t\t\tint vi = meshCache->cachedPointsM[i];\n\t\t\t\tstartState[vi] = m->verts[vi];\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool TB_Move::queryPoints(Mesh* m, TweakPickInfo&, TweakPickInfo&, int* resultPoints, int& outResultCount, std::unordered_set<AABBTree::AABBTreeNode*>&) {\n\tTweakBrushMeshCache* meshCache = &cache[m];\n\tif (meshCache->nCachedPoints == 0)\n\t\treturn false;\n\n\tif (resultPoints) {\n\t\tstd::memcpy(resultPoints, &meshCache->cachedPoints.front(), meshCache->nCachedPoints * sizeof(int));\n\t\tstd::memcpy(resultPoints + meshCache->nCachedPoints, &meshCache->cachedPointsM.front(), meshCache->nCachedPointsM * sizeof(int));\n\t}\n\n\toutResultCount = meshCache->nCachedPoints + meshCache->nCachedPointsM;\n\n\treturn true;\n}\n\nvoid TB_Move::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int*, int, UndoStateShape& uss) {\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 start = m->TransformPosModelToMesh(pick.origin);\n\tVector3 mirrorstart = m->TransformPosModelToMesh(mpick.origin);\n\n\tstd::set<int> touchedIndices;\n\n\tTweakBrushMeshCache* meshCache = &cache[m];\n\tif (bMirror) {\n\t\tVector3 lmo;\n\t\tlmo.x = -pickInfo.origin.x;\n\t\tlmo.y = pickInfo.origin.y;\n\t\tlmo.z = pickInfo.origin.z;\n\t\tfloat dist = lmo.dot(mpick.view) - md;\n\t\tVector3 v = lmo - mpick.view * dist;\n\t\tVector3 dv = (v - mpick.origin) * strength;\n\t\tVector3 meshdv = m->TransformDiffModelToMesh(dv);\n\n\t\tfor (int p = 0; p < meshCache->nCachedPointsM; p++) {\n\t\t\tint i = meshCache->cachedPointsM[p];\n\t\t\tVector3 vs = startState[i];\n\t\t\tVector3 ve = meshdv;\n\t\t\tapplyFalloff(ve, mirrorstart.DistanceTo(vs), meshradius);\n\n\t\t\tif (m->mask)\n\t\t\t\tve = ve * (1.0f - m->mask[i]);\n\n\t\t\tif (restrictNormal) {\n\t\t\t\tconst Vector3& n = cache[m].startNorms[i];\n\t\t\t\tve = n * ve.dot(n);\n\t\t\t}\n\n\t\t\tif (restrictPlane) {\n\t\t\t\tconst Vector3& n = cache[m].startNorms[i];\n\t\t\t\tve -= n * ve.dot(n);\n\t\t\t}\n\n\t\t\tif (!ve.IsZero(true)) {\n\t\t\t\tendState[i] = m->verts[i] = vs + ve;\n\t\t\t\ttouchedIndices.insert(i);\n\t\t\t}\n\t\t}\n\t}\n\n\tfloat dist = pickInfo.origin.dot(pick.view) - d;\n\tVector3 v = pickInfo.origin - pick.view * dist;\n\tVector3 dv = (v - pick.origin) * strength;\n\tVector3 meshdv = m->TransformDiffModelToMesh(dv);\n\n\tfor (int p = 0; p < meshCache->nCachedPoints; p++) {\n\t\tint i = meshCache->cachedPoints[p];\n\t\tVector3 vs = startState[i];\n\n\t\tVector3 ve = meshdv;\n\t\tapplyFalloff(ve, start.DistanceTo(vs), meshradius);\n\n\t\tif (m->mask)\n\t\t\tve = ve * (1.0f - m->mask[i]);\n\n\t\tif (restrictNormal) {\n\t\t\tconst Vector3& n = cache[m].startNorms[i];\n\t\t\tve = n * ve.dot(n);\n\t\t}\n\n\t\tif (restrictPlane) {\n\t\t\tconst Vector3& n = cache[m].startNorms[i];\n\t\t\tve -= n * ve.dot(n);\n\t\t}\n\n\t\tif (ve.IsZero(true))\n\t\t\tcontinue;\n\n\t\tif (bMirror) {\n\t\t\tif (touchedIndices.find(i) != touchedIndices.end()) {\n\t\t\t\tfloat distStart = std::fabs(vs.x - start.x);\n\t\t\t\tfloat distStartMirror = std::fabs(vs.x - mirrorstart.x);\n\t\t\t\tif (std::fabs(distStart - distStartMirror) <= 0.01f) {\n\t\t\t\t\t// Reset X axis to start state\n\t\t\t\t\tendState[i].x = vs.x;\n\t\t\t\t\tm->verts[i].x = vs.x;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (start.DistanceTo(vs) > mirrorstart.DistanceTo(vs))\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tendState[i] = m->verts[i] = vs + ve;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n}\n\nvoid TB_Move::GetWorkingPlane(Vector3& outPlaneNormal, float& outPlaneDist) {\n\toutPlaneNormal = pick.view;\n\toutPlaneDist = d;\n}\n\nTB_XForm::TB_XForm() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Transform;\n\tbrushName = \"Transform Brush\";\n\tbLiveBVH = false;\n}\n\nTB_XForm::~TB_XForm() {}\n\nvoid TB_XForm::GetWorkingPlane(Vector3& outPlaneNormal, float& outPlaneDist) {\n\toutPlaneNormal = pick.normal;\n\toutPlaneDist = pick.origin.dot(pick.normal);\n}\n\nvoid TB_XForm::strokeInit(const std::vector<Mesh*>& refMeshes, TweakPickInfo& pickInfo, UndoStateProject& usp) {\n\tpick = pickInfo;\n\n\tTweakBrush::strokeInit(refMeshes, pickInfo, usp);\n\n\tconst int nMesh = refMeshes.size();\n\tfor (int mi = 0; mi < nMesh; ++mi) {\n\t\tMesh* m = refMeshes[mi];\n\t\tUndoStateShape& uss = usp.usss[mi];\n\t\tTweakBrushMeshCache* meshCache = &cache[m];\n\t\tmeshCache->nCachedPoints = m->nVerts;\n\t\tauto& startState = uss.pointStartState;\n\t\tfor (int i = 0; i < meshCache->nCachedPoints; i++)\n\t\t\tstartState[i] = m->verts[i];\n\t}\n}\n\nbool TB_XForm::queryPoints(Mesh* m, TweakPickInfo&, TweakPickInfo&, int* resultPoints, int& outResultCount, std::unordered_set<AABBTree::AABBTreeNode*>&) {\n\tTweakBrushMeshCache* meshCache = &cache[m];\n\tif (meshCache->nCachedPoints == 0)\n\t\treturn false;\n\n\tif (resultPoints) {\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tresultPoints[i] = i;\n\t\t}\n\t}\n\n\toutResultCount = m->nVerts;\n\treturn true;\n}\n\nvoid TB_XForm::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int*, int, UndoStateShape& uss) {\n\tVector3 v = pickInfo.origin;\n\tVector3 dv = v - pick.origin;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\n\t// Project dv onto movement axis (which is stored in pick.view)\n\tdv.x *= pick.view.x;\n\tdv.y *= pick.view.y;\n\tdv.z *= pick.view.z;\n\n\tVector3 center = m->TransformPosModelToMesh(pick.center);\n\n\tMatrix4 xform;\n\tif (xformType == 0) {\n\t\txform.Translate(m->TransformDiffModelToMesh(dv) * strength);\n\t}\n\telse if (xformType == 1) {\n\t\txform.PushTranslate(center);\n\n\t\tVector3 a = pick.origin - center;\n\t\tVector3 b = pickInfo.origin - center;\n\t\tVector3 dir = a.cross(b);\n\t\tfloat sign = dir.dot(pick.normal);\n\t\tfloat angle = a.angle(pickInfo.origin - center);\n\t\tif (sign < 0)\n\t\t\tangle = -angle;\n\n\t\txform.PushRotate(angle, pick.normal);\n\t\txform.PushTranslate(center * -1.0f);\n\t}\n\telse if (xformType == 2) {\n\t\txform.PushTranslate(center);\n\n\t\tVector3 dist(1.0f, 1.0f, 1.0f);\n\t\tif (fabs(dv.x) > EPSILON)\n\t\t\tdist.x = fabs(1.0f + dv.x / 10.0f);\n\t\telse if (fabs(dv.y) > EPSILON)\n\t\t\tdist.y = fabs(1.0f + dv.y / 10.0f);\n\t\telse if (fabs(dv.z) > EPSILON)\n\t\t\tdist.z = fabs(1.0f + dv.z / 10.0f);\n\n\t\txform.PushScale(dist.x, dist.y, dist.z);\n\t\txform.PushTranslate(center * -1.0f);\n\t}\n\telse if (xformType == 3) {\n\t\txform.PushTranslate(center);\n\n\t\tVector3 a = m->TransformPosModelToMesh(pick.origin) - center;\n\t\tVector3 b = m->TransformPosModelToMesh(pickInfo.origin) - center;\n\t\tVector3 dist = a + b;\n\n\t\tfloat scale = (dist.x + dist.y) / 2.0f;\n\t\tscale = fabs(1.0f + scale / 10.0f);\n\t\tif (scale > EPSILON)\n\t\t\txform.PushScale(scale, scale, scale);\n\n\t\txform.PushTranslate(center * -1.0f);\n\t}\n\n\tVector3 vs;\n\tVector3 ve;\n\tVector3 vf;\n\n\tTweakBrushMeshCache* meshCache = &cache[m];\n\tfor (int p = 0; p < meshCache->nCachedPoints; p++) {\n\t\tvs = startState[p];\n\t\tve = xform * vs;\n\t\tve -= vs;\n\n\t\tif (m->mask)\n\t\t\tve = ve * (1.0f - m->mask[p]);\n\n\t\tvf = vs + ve;\n\n\t\tendState[p] = m->verts[p] = (vf);\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n}\n\nstatic inline void ClampWeight(float& w) {\n\tif (w > 1.0f)\n\t\tw = 1.0f;\n\tif (w < EPSILON)\n\t\tw = 0.0f;\n}\n\nTB_Weight::TB_Weight() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Weight;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbFixedWeight = false;\n\tbrushName = \"Weight Paint\";\n}\n\nTB_Weight::~TB_Weight() {}\n\nvoid TB_Weight::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tBoneWeightAutoNormalizer nzer;\n\tnzer.SetUp(&uss, animInfo, m->shapeName, boneNames, lockedBoneNames, bXMirrorBone ? 2 : 1, bSpreadWeight);\n\tnzer.GrabStartingWeights(points, nPoints);\n\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tVector3 mOrigin = pickInfo.origin;\n\tmOrigin.x = -mOrigin.x;\n\tmOrigin = m->TransformPosModelToMesh(mOrigin);\n\n\tfor (int pi = 0; pi < nPoints; pi++) {\n\t\tint i = points[pi];\n\t\tbool adjFlag[2] = {true, false};\n\t\tfloat orDist = meshorigin.DistanceTo(m->verts[i]);\n\t\tfloat morDist = mOrigin.DistanceTo(m->verts[i]);\n\t\tfloat falloff = getFalloff(orDist, meshradius);\n\t\tfloat mFalloff = getFalloff(morDist, meshradius);\n\t\tfloat b0falloff = falloff;\n\n\t\tif (bMirror && morDist < orDist)\n\t\t\tb0falloff = mFalloff;\n\n\t\tadjFlag[0] = b0falloff > 0.0;\n\n\t\tfloat sw = uss.boneWeights[0].weights[i].endVal;\n\t\tfloat str = bFixedWeight ? strength - sw : strength;\n\t\tfloat maskF = 1.0f - m->mask[i];\n\n\t\tuss.boneWeights[0].weights[i].endVal += str * maskF * b0falloff;\n\n\t\tif (!bNormalizeWeights)\n\t\t\tClampWeight(uss.boneWeights[0].weights[i].endVal);\n\n\t\tif (bXMirrorBone) {\n\t\t\tfloat b1falloff = mFalloff;\n\t\t\tif (bMirror && orDist < morDist)\n\t\t\t\tb1falloff = falloff;\n\n\t\t\tadjFlag[1] = b1falloff > 0.0;\n\t\t\tsw = uss.boneWeights[1].weights[i].endVal;\n\t\t\tstr = bFixedWeight ? strength - sw : strength;\n\t\t\tuss.boneWeights[1].weights[i].endVal += str * maskF * b1falloff;\n\n\t\t\tif (!bNormalizeWeights)\n\t\t\t\tClampWeight(uss.boneWeights[1].weights[i].endVal);\n\t\t}\n\n\t\tif (bNormalizeWeights)\n\t\t\tnzer.AdjustWeights(i, adjFlag);\n\n\t\tm->weight[i] = uss.boneWeights[0].weights[i].endVal;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Weight);\n}\n\nTB_Unweight::TB_Unweight() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Weight;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Weight Erase\";\n}\n\nTB_Unweight::~TB_Unweight() {}\n\nvoid TB_Unweight::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tBoneWeightAutoNormalizer nzer;\n\tnzer.SetUp(&uss, animInfo, m->shapeName, boneNames, lockedBoneNames, bXMirrorBone ? 2 : 1, bSpreadWeight);\n\tnzer.GrabStartingWeights(points, nPoints);\n\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tVector3 mOrigin = pickInfo.origin;\n\tmOrigin.x = -mOrigin.x;\n\tmOrigin = m->TransformPosModelToMesh(mOrigin);\n\n\tfor (int pi = 0; pi < nPoints; pi++) {\n\t\tint i = points[pi];\n\t\tbool adjFlag[2] = {true, false};\n\t\tfloat orDist = meshorigin.DistanceTo(m->verts[i]);\n\t\tfloat morDist = mOrigin.DistanceTo(m->verts[i]);\n\t\tfloat falloff = getFalloff(orDist, meshradius);\n\t\tfloat mFalloff = getFalloff(morDist, meshradius);\n\t\tfloat b0falloff = falloff;\n\n\t\tif (bMirror && morDist < orDist)\n\t\t\tb0falloff = mFalloff;\n\n\t\tadjFlag[0] = b0falloff > 0.0;\n\n\t\tfloat maskF = 1.0f - m->mask[i];\n\n\t\tuss.boneWeights[0].weights[i].endVal += strength * maskF * b0falloff;\n\n\t\tif (!bNormalizeWeights)\n\t\t\tClampWeight(uss.boneWeights[0].weights[i].endVal);\n\n\t\tif (bXMirrorBone) {\n\t\t\tfloat b1falloff = mFalloff;\n\t\t\tif (bMirror && orDist < morDist)\n\t\t\t\tb1falloff = falloff;\n\n\t\t\tadjFlag[1] = b1falloff > 0.0;\n\t\t\tuss.boneWeights[1].weights[i].endVal += strength * maskF * b1falloff;\n\n\t\t\tif (!bNormalizeWeights)\n\t\t\t\tClampWeight(uss.boneWeights[1].weights[i].endVal);\n\t\t}\n\n\t\tif (bNormalizeWeights)\n\t\t\tnzer.AdjustWeights(i, adjFlag);\n\n\t\tm->weight[i] = uss.boneWeights[0].weights[i].endVal;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Weight);\n}\n\nTB_SmoothWeight::TB_SmoothWeight() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Weight;\n\tmethod = 2;\n\thcAlpha = 0.2f;\n\thcBeta = 0.5f;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Weight Smooth\";\n}\n\nTB_SmoothWeight::~TB_SmoothWeight() {}\n\nvoid TB_SmoothWeight::lapFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, float>& wv) {\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[points[i]];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\n\t\t// average adjacent points values, using values from last iteration.\n\t\tfloat d = 0.0;\n\t\tfor (int apt : adjPoints)\n\t\t\td += m->weight[apt];\n\n\t\tfloat result = d / c;\n\t\twv[points[i]] = result;\n\n\t\tm->DoForEachWeldedVertex(points[i], [&](int p) {wv[p] = result;});\n\t}\n}\n\nvoid TB_SmoothWeight::hclapFilter(\n\tMesh* m, const int* points, int nPoints, std::unordered_map<int, float>& wv, UndoStateShape& uss, const int boneInd, const std::unordered_map<uint16_t, float>* wPtr) {\n\tauto& ubw = uss.boneWeights[boneInd].weights;\n\tstd::vector<float> b(m->nVerts);\n\n\t// First step is to calculate the laplacian\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[i];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\n\t\t// average adjacent points positions, using values from last iteration.\n\t\tfloat d = 0.0;\n\t\tfor (int apt : adjPoints) {\n\t\t\tif (ubw.find(apt) != ubw.end())\n\t\t\t\td += ubw[apt].endVal;\n\t\t\telse if (wPtr && wPtr->find(apt) != wPtr->end())\n\t\t\t\td += wPtr->at(apt);\n\t\t\t// otherwise the previous weight is zero\n\t\t}\n\n\t\twv[i] = d / (float)c;\n\n\t\t// Calculate the difference between the new position and a blend of the original and previous positions\n\t\tb[i] = wv[i] - ((ubw[i].startVal * hcAlpha) + (ubw[i].endVal * (1.0f - hcAlpha)));\n\t}\n\n\tfor (int p = 0; p < nPoints; p++) {\n\t\tint i = points[p];\n\n\t\t// Check if it's a welded vertex; only do welded vertices once.\n\t\tif (m->LeastWeldedVertexIndex(i) != i)\n\t\t\tcontinue;\n\n\t\t// Average 'b' for adjacent points\n\t\tconst std::vector<int>& adjPoints = m->adjVerts[i];\n\t\tint c = static_cast<int>(adjPoints.size());\n\t\tif (c == 0)\n\t\t\tcontinue;\n\n\t\tfloat d = 0.0;\n\n\t\tfor (int apt : adjPoints)\n\t\t\td += b[apt];\n\n\t\t// blend the new position and the average of the distance moved\n\t\tfloat avgB = (1 - hcBeta) / (float)c;\n\t\twv[i] -= ((b[i] * hcBeta) + (d * avgB));\n\n\t\tm->DoForEachWeldedVertex(i, [&](int p) {wv[p] = wv[i];});\n\t}\n}\n\nvoid TB_SmoothWeight::bppfFilter(Mesh* m, const int* points, int nPoints, std::unordered_map<int, float>& wv, UndoStateShape& uss, const int boneInd, const std::unordered_map<uint16_t, float>* wPtr) {\n\tauto& weights = uss.boneWeights[boneInd].weights;\n\n\tint balPts[Mesh::MaxAdjacentPoints];\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tint pti = points[i];\n\n\t\t// Check if it's a welded vertex; only do welded vertices once.\n\t\tif (m->LeastWeldedVertexIndex(pti) != pti)\n\t\t\tcontinue;\n\n\t\tint balCount = m->FindAdjacentBalancedPairs(pti, balPts);\n\t\tif (balCount == 0)\n\t\t\tcontinue;\n\n\t\tfloat d = 0.0;\n\t\tfor (int n = 0; n < balCount; n += 2) {\n\t\t\tint p1 = balPts[n];\n\t\t\tint p2 = balPts[n + 1];\n\t\t\tfloat fitw = ParabolaFit(m, pti, p1, p2, [&weights, &wPtr](int p) {\n\t\t\t\tauto wit = weights.find(p);\n\t\t\t\tif (wit != weights.end())\n\t\t\t\t\treturn wit->second.startVal;\n\t\t\t\tif (wPtr) {\n\t\t\t\t\tauto wpit = wPtr->find(p);\n\t\t\t\t\tif (wpit != wPtr->end())\n\t\t\t\t\t\treturn wpit->second;\n\t\t\t\t}\n\t\t\t\treturn 0.0f;\n\t\t\t});\n\n\t\t\td += fitw;\n\t\t}\n\n\t\twv[pti] = d / (balCount / 2);\n\n\t\tm->DoForEachWeldedVertex(pti, [&](int p) {wv[p] = wv[pti];});\n\t}\n}\n\nvoid TB_SmoothWeight::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tBoneWeightAutoNormalizer nzer;\n\tnzer.SetUp(&uss, animInfo, m->shapeName, boneNames, lockedBoneNames, bXMirrorBone ? 2 : 1, bSpreadWeight);\n\tnzer.GrabStartingWeights(points, nPoints);\n\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tVector3 mOrigin = pickInfo.origin;\n\tmOrigin.x = -mOrigin.x;\n\tmOrigin = m->TransformPosModelToMesh(mOrigin);\n\n\t// Copy previous iteration's results into wv\n\tstd::unordered_map<int, float> wv, mwv;\n\tfor (int pi = 0; pi < nPoints; pi++) {\n\t\tint i = points[pi];\n\t\twv[i] = uss.boneWeights[0].weights[i].endVal;\n\n\t\tif (bXMirrorBone)\n\t\t\tmwv[i] = uss.boneWeights[1].weights[i].endVal;\n\t}\n\n\tif (method == 0) // laplacian smooth\n\t\tlapFilter(m, points, nPoints, wv);\n\telse if (method == 1) // HC-laplacian smooth\n\t\thclapFilter(m, points, nPoints, wv, uss, 0, animInfo->GetWeightsPtr(m->shapeName, boneNames[0]));\n\telse // balanced-pair parabola-fit smooth\n\t\tbppfFilter(m, points, nPoints, wv, uss, 0, animInfo->GetWeightsPtr(m->shapeName, boneNames[0]));\n\n\tif (bXMirrorBone) {\n\t\tif (method == 0) // laplacian smooth\n\t\t\tlapFilter(m, points, nPoints, mwv);\n\t\telse if (method == 1) // HC-laplacian smooth\n\t\t\thclapFilter(m, points, nPoints, mwv, uss, 1, animInfo->GetWeightsPtr(m->shapeName, boneNames[1]));\n\t\telse // balanced-pair parabola-fit smooth\n\t\t\tbppfFilter(m, points, nPoints, mwv, uss, 1, animInfo->GetWeightsPtr(m->shapeName, boneNames[1]));\n\t}\n\n\tfor (int pi = 0; pi < nPoints; pi++) {\n\t\tint i = points[pi];\n\t\tbool adjFlag[2] = {true, false};\n\t\tfloat orDist = meshorigin.DistanceTo(m->verts[i]);\n\t\tfloat morDist = mOrigin.DistanceTo(m->verts[i]);\n\t\tfloat falloff = getFalloff(orDist, meshradius);\n\t\tfloat mFalloff = getFalloff(morDist, meshradius);\n\t\tfloat b0falloff = falloff;\n\n\t\tif (bMirror && morDist < orDist)\n\t\t\tb0falloff = mFalloff;\n\n\t\tadjFlag[0] = b0falloff > 0.0;\n\n        float str = wv[i] - uss.boneWeights[0].weights[i].endVal;\n\t\tfloat maskF = 1.0f - m->mask[i];\n\n\t\tuss.boneWeights[0].weights[i].endVal += str * maskF * b0falloff;\n\n\t\tif (!bNormalizeWeights)\n\t\t\tClampWeight(uss.boneWeights[0].weights[i].endVal);\n\n\t\tif (bXMirrorBone) {\n\t\t\tfloat b1falloff = mFalloff;\n\n\t\t\tif (bMirror && orDist < morDist)\n\t\t\t\tb1falloff = falloff;\n\n\t\t\tadjFlag[1] = b1falloff > 0.0;\n            str = mwv[i] - uss.boneWeights[1].weights[i].endVal;\n\t\t\tuss.boneWeights[1].weights[i].endVal += str * maskF * b1falloff;\n\n\t\t\tif (!bNormalizeWeights)\n\t\t\t\tClampWeight(uss.boneWeights[1].weights[i].endVal);\n\t\t}\n\n\t\tif (bNormalizeWeights)\n\t\t\tnzer.AdjustWeights(i, adjFlag);\n\n\t\tm->weight[i] = uss.boneWeights[0].weights[i].endVal;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Weight);\n}\n\nTB_Color::TB_Color() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Color;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Color Paint\";\n}\n\nTB_Color::~TB_Color() {}\n\nvoid TB_Color::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tVector3 vs;\n\tVector3 vc;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tvc = m->vcolors[points[i]];\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vc;\n\n\t\tfloat originToV = meshorigin.DistanceTo(vs);\n\t\tif (originToV <= meshradius) {\n\t\t\tfloat maskF = 1.0f - m->mask[points[i]];\n\t\t\tVector3 falloff(strength, strength, strength);\n\t\t\tapplyFalloff(falloff, originToV, meshradius);\n\n\t\t\tvc.x = color.x * falloff.x * maskF + vc.x * (1.0f - falloff.x * maskF);\n\t\t\tvc.y = color.y * falloff.y * maskF + vc.y * (1.0f - falloff.y * maskF);\n\t\t\tvc.z = color.z * falloff.z * maskF + vc.z * (1.0f - falloff.z * maskF);\n\t\t}\n\n\t\tif (vc.x > 1.0f)\n\t\t\tvc.x = 1.0f;\n\t\telse if (vc.x < 0.0f)\n\t\t\tvc.x = 0.0f;\n\n\t\tif (vc.y > 1.0f)\n\t\t\tvc.y = 1.0f;\n\t\telse if (vc.y < 0.0f)\n\t\t\tvc.y = 0.0f;\n\n\t\tif (vc.z > 1.0f)\n\t\t\tvc.z = 1.0f;\n\t\telse if (vc.z < 0.0f)\n\t\t\tvc.z = 0.0f;\n\n\t\tendState[points[i]] = m->vcolors[points[i]] = vc;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::VertexColors);\n}\n\nTB_Uncolor::TB_Uncolor() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Color;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Color Erase\";\n}\n\nTB_Uncolor::~TB_Uncolor() {}\n\nvoid TB_Uncolor::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tVector3 vs;\n\tVector3 vc;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tfloat maskF = 1.0f - m->mask[points[i]];\n\t\tvs = m->verts[points[i]];\n\t\tvc = m->vcolors[points[i]];\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]] = vc;\n\n\t\tfloat originToV = meshorigin.DistanceTo(vs);\n\t\tif (originToV <= meshradius) {\n\t\t\tVector3 falloff(-strength, -strength, -strength);\n\t\t\tapplyFalloff(falloff, originToV, meshradius);\n\n\t\t\tvc.x = falloff.x * maskF + vc.x * (1.0f - falloff.x * maskF);\n\t\t\tvc.y = falloff.y * maskF + vc.y * (1.0f - falloff.y * maskF);\n\t\t\tvc.z = falloff.z * maskF + vc.z * (1.0f - falloff.z * maskF);\n\t\t}\n\n\t\tif (vc.x > 1.0f)\n\t\t\tvc.x = 1.0f;\n\t\telse if (vc.x < 0.0f)\n\t\t\tvc.x = 0.0f;\n\n\t\tif (vc.y > 1.0f)\n\t\t\tvc.y = 1.0f;\n\t\telse if (vc.y < 0.0f)\n\t\t\tvc.y = 0.0f;\n\n\t\tif (vc.z > 1.0f)\n\t\t\tvc.z = 1.0f;\n\t\telse if (vc.z < 0.0f)\n\t\t\tvc.z = 0.0f;\n\n\t\tendState[points[i]] = m->vcolors[points[i]] = vc;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::VertexColors);\n}\n\nTB_Alpha::TB_Alpha() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Alpha;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Alpha Brush\";\n}\n\nTB_Alpha::~TB_Alpha() {}\n\nvoid TB_Alpha::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tVector3 vs;\n\tfloat vc;\n\tfloat ve;\n\tfloat vf;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tvc = m->valpha[points[i]];\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]].x = vc;\n\n\t\tve = vc;\n\t\tif (strength < 1.0f)\n\t\t\tve -= strength;\n\t\telse\n\t\t\tve -= 1.0f;\n\t\tve -= vc;\n\n\t\tVector3 vev(ve, ve, ve);\n\t\tfloat originToV = meshorigin.DistanceTo(vs);\n\t\tif (originToV > meshradius)\n\t\t\tvev.Zero();\n\t\telse if (strength < 1.0f)\n\t\t\tapplyFalloff(vev, originToV, meshradius);\n\n\t\tvf = vc + vev.x;\n\t\tif (vf < clampMaxValue)\n\t\t\tvf = clampMaxValue;\n\n\t\tendState[points[i]].x = m->valpha[points[i]] = vf;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::VertexAlpha);\n}\n\nTB_Unalpha::TB_Unalpha() {\n\tresetSettings();\n\n\tbrushType = TweakBrush::BrushType::Alpha;\n\tbMirror = false;\n\tbLiveBVH = false;\n\tbLiveNormals = false;\n\tbrushName = \"Unalpha Brush\";\n}\n\nTB_Unalpha::~TB_Unalpha() {}\n\nvoid TB_Unalpha::brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) {\n\tVector3 vs;\n\tfloat vc;\n\tfloat ve;\n\tfloat vf;\n\tauto& startState = uss.pointStartState;\n\tauto& endState = uss.pointEndState;\n\tfloat meshradius = m->TransformDistModelToMesh(radius);\n\tVector3 meshorigin = m->TransformPosModelToMesh(pickInfo.origin);\n\n\tfor (int i = 0; i < nPoints; i++) {\n\t\tvs = m->verts[points[i]];\n\t\tvc = m->valpha[points[i]];\n\t\tif (startState.find(points[i]) == startState.end())\n\t\t\tstartState[points[i]].x = vc;\n\n\t\tve = vc;\n\t\tif (strength > -1.0f)\n\t\t\tve -= strength;\n\t\telse\n\t\t\tve += 1.0f;\n\t\tve -= vc;\n\n\t\tVector3 vev(ve, ve, ve);\n\t\tfloat originToV = meshorigin.DistanceTo(vs);\n\t\tif (originToV > meshradius)\n\t\t\tvev.Zero();\n\t\telse if (strength > -1.0f)\n\t\t\tapplyFalloff(vev, originToV, meshradius);\n\n\t\tvf = vc + vev.x;\n\t\tif (vf > 1.0f)\n\t\t\tvf = 1.0f;\n\n\t\tendState[points[i]].x = m->valpha[points[i]] = vf;\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::VertexAlpha);\n}\n"
  },
  {
    "path": "src/components/TweakBrush.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n/* Vertex tweaking classes. Patterned off of 3d sculpting applications like ZBrush.\n\tProcess overview:\n\t1) App enters edit mode.\n\t\t- default standard brush is created and selected.\n\t\t- undo stack is created.\n\t\t- the original shape of the model is saved as a duplicate hidden mesh.\n\t2) User begins a stroke by pressing down the mouse button while over the active mesh.\n\t\t- new stroke is created and the active mesh and brush are saved in the stroke data.\n\t\t- Begin Stroke is called to initialize the stroke.\n\t\t- Update Stroke is called.\n\t\t\t- Brush queries mesh for vertices in its realm of influence.\n\t\t\t- Stroke saves result BVH facet pointers in the affectednodes set.\n\t\t\t- Stroke saves result set of vertices and their positions in the pointstartstate map.\n\t\t\t- Brush applies transformation to result vertices.\n\t\t\t- Stroke saves transformed vertices to pointcurrentstate map.\n\t\t- mesh->updateBVH is called.\n\t\t- Window is redrawn.\n\t3) User continues stroke by dragging mouse with button still down.\n\t\t- Update stroke is called.\n\t\t\t- Vertices not already in the pointstartstate map are added with their original positions.\n\t\t- BVH is updated and the window is redrawn.\n\t4) User releases mouse button at end of stroke.\n\t\t- stroke is saved to the undo stack. If the stack is full, the oldest state is erased.\n\t5) User uses the undo function.\n\t\t- mesh data is reverted to the stroke's pointstartstate map.\n\t\t- the affectedNodes set is used to update the BVH.\n\t\t- the undo stack position is decremented.\n\t\t- the window is redrawn.\n\t5) User uses the redo function.\n\t\t- mesh data is set to the stroke's pointendstate map.\n\t\t- the affectedNodes set is used to update the BVH.\n\t\t- the undo stack position is incremented.\n\t\t- the window is rerawn.\n\t6) User performs a new edit after using the undo function.\n\t\t- the edit is performed as normal (stroke begin, stroke update, stroke end).\n\t\t- the undo stack position indicator is checked against the length of the stack.\n\t\t- if there are states after the current position, those states are discarded and a new stroke is added to the stack.\n\t7) User completes changes and exits edit mode.\n\t\t- user is prompted to save the changes.\n\t8) User chooses to save it.\n\t\t- if the user chooses to save as an .obj file, the current mesh is exported in .obj format.\n\t\t- if the user chooses to save as a .bsd file,\n\t\t\t- the last stroke's position information is compared with the saved original mesh data to generate\n\t\t\t\tdiff information, which is saved to the .bsd file.\n\t\t\t- a small XML file containing a slider set entry is saved?\n\t9) App enters view mode (if user turned off editing rather than close the window)\n\t\t- undo history is discarded.\n\t\t- original mesh data is retained until window exits.\n\t10) User changes brush with 1-9 keys.\n\t11) User changes active mesh with ALT + 1-9 keys\n*/\n\n#pragma once\n\n#include \"Mesh.h\"\n#include \"UndoState.h\"\n\n#include <future>\n\n// Collecton of information that identifies the position and attributes where a brush stroke is taking place.\nclass TweakPickInfo {\npublic:\n\t// All vectors are in model space, not mesh\n\tnifly::Vector3 origin; // Point on the surface of the mesh that was touched.\n\tnifly::Vector3 normal; // Surface normal at the point of impact.\n\tnifly::Vector3 view;   // View vector.\n\tnifly::Vector3 center; // Center point for a transform.\n};\n\nclass TweakBrushMeshCache {\npublic:\n\tstd::vector<int> cachedPoints;\n\tstd::vector<int> cachedPointsM;\n\tint nCachedPoints = 0;\n\tint nCachedPointsM = 0;\n\tstd::unordered_set<AABBTree::AABBTreeNode*> cachedNodes;\n\tstd::unordered_set<AABBTree::AABBTreeNode*> cachedNodesM;\n\tstd::vector<nifly::Vector3> positionData;\n\tstd::unique_ptr<nifly::Vector3[]> startNorms;\n};\n\n\nclass TweakBrush {\npublic:\n\tenum class BrushType { Inflate = 1, Move, Mask, Weight, Color, Alpha, Transform, Undiff };\n\nprotected:\n\tBrushType brushType;\n\tstd::string brushName;\n\tfloat radius;\n\tfloat focus; // Focus between 0 and 1.\n\tfloat strength;\n\tfloat spacing;\t   // Distance between points; movements less than this distance don't update the stroke.\n\tbool bMirror;\t   // X-axis mirror enabled\n\tbool bLiveBVH;\t   // Update BVH at each update instead of at stroke completion.\n\tbool bLiveNormals; // Update mesh normals at each update instead of at stroke completion.\n\tbool bConnected;   // Operate on connected vertices only.\n\tbool restrictPlane = false;\n\tbool restrictNormal = false;\n\n\tstd::unordered_map<Mesh*, TweakBrushMeshCache> cache;\n\npublic:\n\tTweakBrush();\n\tvirtual ~TweakBrush();\n\n\tBrushType Type() { return brushType; }\n\tstd::string Name() { return brushName; }\n\n\tvirtual UndoType GetUndoType() { return UndoType::VertexPosition; }\n\n\tTweakBrushMeshCache* getCache(Mesh* m) { return &cache[m]; }\n\n\tvirtual float getRadius() { return radius; }\n\tvirtual float getStrength() { return strength; }\n\tvirtual float getFocus() { return focus; }\n\tvirtual float getSpacing() { return spacing; }\n\tvirtual void setRadius(float newRadius) { radius = newRadius; }\n\tvirtual void setFocus(float newFocus) { focus = newFocus; }\n\tvirtual void setStrength(float newStr) { strength = newStr; }\n\tvirtual void setSpacing(float newSpacing) { spacing = newSpacing; }\n\n\tvirtual void resetSettings() {\n\t\tradius = 0.45f;\n\t\tfocus = 0.5f;\n\t\tstrength = 0.0015f;\n\t\tspacing = 0.015f;\n\t};\n\n\tvirtual int CachedPointIndex(Mesh*, int) { return 0; }\n\n\tvirtual bool isMirrored() { return bMirror; }\n\tvirtual void setMirror(bool wantMirror = true) { bMirror = wantMirror; }\n\n\tvirtual bool isConnected() { return bConnected; }\n\tvirtual void setConnected(bool wantConnected = true) { bConnected = wantConnected; }\n\tvirtual void setRestrictPlane(bool on) { restrictPlane = on; }\n\tvirtual void setRestrictNormal(bool on) { restrictNormal = on; }\n\tvirtual bool LiveBVH() { return bLiveBVH; }\n\tvirtual bool LiveNormals() { return bLiveNormals; }\n\n\tvirtual bool NeedMirrorMergedQuery() { return false; }\n\tvirtual bool NeedStartNorms() { return restrictPlane || restrictNormal; }\n\n\t// Stroke initialization interface, allows a brush to set up initial conditions.\n\tvirtual void strokeInit(const std::vector<Mesh*>&, TweakPickInfo&, UndoStateProject&);\n\tvirtual void strokeInit(const std::vector<Mesh*>&, TweakPickInfo&, UndoStateProject&, std::vector<std::vector<nifly::Vector3>>&) {}\n\n\t// Using the start and end points, determine if enough distance has been covered to satisfy the spacing setting.\n\tvirtual bool checkSpacing(nifly::Vector3& start, nifly::Vector3& end);\n\n\tvirtual float getFalloff(float dist, float meshradius);\n\tvirtual void applyFalloff(nifly::Vector3& deltaVec, float dist, float meshradius);\n\n\t// Get the list of points, facets and BVH nodes within the brush sphere of influence.\n\t// Normally, the origin point is used for sphere center and assumed to be an arbitrary point on the surface.\n\t// Optionally, the operation can use the nearest vertex  on the mesh as the center point, using the provided facet to determine candidate points.\n\t// Also optionally, the query can return only connected points within the sphere.\n\n\tvirtual bool queryPoints(\n\t\tMesh* refmesh, TweakPickInfo& pickInfo, TweakPickInfo& mirrorPick, int* resultPoints, int& outResultCount, std::unordered_set<AABBTree::AABBTreeNode*>& affectedNodes);\n\n\t// Apply the brush effect to the mesh\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss) = 0;\n};\n\nclass ClampBrush {\npublic:\n\tfloat clampMaxValue = 0.0f;\n};\n\nclass TB_Inflate : public TweakBrush {\npublic:\n\tTB_Inflate();\n\tvirtual ~TB_Inflate();\n\n\tvirtual float getStrength() { return strength * 10.0f; }\n\tvirtual void setStrength(float newStr) { strength = newStr / 10.0f; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_Mask : public TweakBrush {\npublic:\n\tTB_Mask();\n\tvirtual ~TB_Mask();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Mask; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 1.0f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n};\n\nclass TB_Unmask : public TweakBrush {\npublic:\n\tTB_Unmask();\n\tvirtual ~TB_Unmask();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Mask; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = -1.0f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n};\n\nclass TB_SmoothMask : public TweakBrush {\npublic:\n\tuint8_t method; // 0 for laplacian, 1 for HC-Smooth.\n\tfloat hcAlpha;\t// Blending constants.\n\tfloat hcBeta;\n\n\tvoid lapFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, nifly::Vector3>& wv);\n\tvoid hclapFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, nifly::Vector3>& wv, UndoStateShape& uss);\n\t// Balanced-pair parabola-fit smoothing filter.  This smoothing filter\n\t// uses only balanced pairs of neighboring vertices.  It fits a parabola\n\t// through each balanced pair to determine the destination.\n\tvoid bppfFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, nifly::Vector3>& wv, UndoStateShape& uss);\n\n\tTB_SmoothMask();\n\tvirtual ~TB_SmoothMask();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Mask; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.2f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_Deflate : public TB_Inflate {\npublic:\n\tTB_Deflate();\n\tvirtual ~TB_Deflate();\n\n\tvirtual void setStrength(float newStr);\n\tvirtual float getStrength();\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = -0.0015f;\n\t}\n};\n\n\n// Smooth brush implementing a laplacian smooth function with HC-Smooth modifier.\nclass TB_Smooth : public TweakBrush {\n\tuint8_t method; // 0 for laplacian, 1 for HC-Smooth.\n\tfloat hcAlpha;\t// Blending constants.\n\tfloat hcBeta;\n\n\t// Laplacian smoothing filter. Points are the set of point indices into refmesh to smooth.\n\t// wv is the current position of those points. This function can be called iteratively, reusing wv.\n\tvoid lapFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, nifly::Vector3>& wv);\n\n\t// Improved laplacian smoothing filter (HC-Smooth) points are the set of point indices into refmesh to smooth.\n\t// wv is the current position of those points. This function can be called iteratively, reusing wv.\n\t// This algo is much slower than lap, but tries to maintain mesh volume.\n\tvoid hclapFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, nifly::Vector3>& wv, UndoStateShape& uss);\n\n\t// Balanced-pair circle-fit smoothing filter.  This smoothing filter\n\t// uses only balanced pairs of neighboring vertices and tries\n\t// to fit a circle through each pair to determine the destination of the\n\t// point (using normals).\n\tvoid bpcfFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, nifly::Vector3>& wv);\n\npublic:\n\tTB_Smooth();\n\tvirtual ~TB_Smooth();\n\n\tvirtual bool NeedStartNorms() { return true; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.1f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n};\n\n\n// Undiff brush moving points towards their base position\nclass TB_Undiff : public TweakBrush {\npublic:\n\tTB_Undiff();\n\tvirtual ~TB_Undiff();\n\n\tvirtual void strokeInit(const std::vector<Mesh*>&, TweakPickInfo&, UndoStateProject&, std::vector<std::vector<nifly::Vector3>>&);\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n\n\tvirtual float getStrength() { return strength * 10.0f; }\n\tvirtual void setStrength(float newStr) { strength = newStr / 10.0f; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.01f;\n\t}\n};\n\n// Move brush behavior is significantly different from other brush types.\n// The largest difference is that the brush itself caches the initial set of vertices and their positions.\n// The cached info is reused on each brush update. Additionally, there is no spacing.\nclass TB_Move : public TweakBrush {\n\tTweakPickInfo pick;\n\tTweakPickInfo mpick;\n\tfloat d = 0.0f; // Plane dist.\n\tfloat md = 0.0f;\n\npublic:\n\tTB_Move();\n\tvirtual ~TB_Move();\n\n\tvirtual void strokeInit(const std::vector<Mesh*>&, TweakPickInfo&, UndoStateProject&);\n\n\tvirtual bool queryPoints(\n\t\tMesh* m, TweakPickInfo& pickInfo, TweakPickInfo& mirrorPick, int* resultPoints, int& outResultCount, std::unordered_set<AABBTree::AABBTreeNode*>& affectedNodes);\n\tvirtual void brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 1.0f;\n\t}\n\n\tvoid GetWorkingPlane(nifly::Vector3& outPlaneNormal, float& outPlaneDist);\n\tint CachedPointIndex(Mesh* m, int query) {\n\t\tTweakBrushMeshCache* meshCache = &cache[m];\n\t\tif (query >= meshCache->nCachedPoints)\n\t\t\treturn meshCache->cachedPointsM[query - meshCache->nCachedPoints];\n\t\telse\n\t\t\treturn meshCache->cachedPoints[query];\n\t}\n};\n\nclass TB_XForm : public TweakBrush {\n\tTweakPickInfo pick;\n\tint xformType = 0; // 0 = Move, 1 = Rotate, 2 = Scale, 3 = Uniform Scale\n\npublic:\n\tTB_XForm();\n\tvirtual ~TB_XForm();\n\n\tvoid GetWorkingPlane(nifly::Vector3& outPlaneNormal, float& outPlaneDist);\n\tint CachedPointIndex(Mesh*, int query) { return query; }\n\tvoid SetXFormType(int type) { xformType = type; }\n\n\tvirtual void strokeInit(const std::vector<Mesh*>&, TweakPickInfo&, UndoStateProject&);\n\tvirtual bool queryPoints(\n\t\tMesh* m, TweakPickInfo& pickInfo, TweakPickInfo& mirrorPick, int* resultPoints, int& outResultCount, std::unordered_set<AABBTree::AABBTreeNode*>& affectedNodes);\n\tvirtual void brushAction(Mesh* m, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 1.0f;\n\t}\n};\n\nclass AnimInfo;\n\nclass TB_Weight : public TweakBrush {\npublic:\n\tbool bFixedWeight;\n\tAnimInfo* animInfo;\n\t// boneNames: first is bone being edited; second is x-mirror bone if\n\t// bXMirrorBone is true; the rest are normalize bones\n\tstd::vector<std::string> boneNames, lockedBoneNames;\n\t// bSpreadWeight: if true, leftover weight is spread across normalize bones.\n\tbool bSpreadWeight;\n\t// bXMirrorBone:  if true, boneNames[1] is the x-mirror bone\n\tbool bXMirrorBone;\n\tbool bNormalizeWeights = false;\n\n\tTB_Weight();\n\tvirtual ~TB_Weight();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Weight; }\n\tvirtual bool NeedMirrorMergedQuery() { return bMirror || bXMirrorBone; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.015f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_Unweight : public TweakBrush {\npublic:\n\tAnimInfo* animInfo;\n\t// boneNames: first is bone being edited; second is x-mirror bone if\n\t// bXMirrorBone is true; the rest are normalize bones\n\tstd::vector<std::string> boneNames, lockedBoneNames;\n\t// bSpreadWeight: if true, leftover weight is spread across normalize bones.\n\tbool bSpreadWeight;\n\t// bXMirrorBone:  if true, boneNames[1] is the x-mirror bone\n\tbool bXMirrorBone;\n\tbool bNormalizeWeights = false;\n\n\tTB_Unweight();\n\tvirtual ~TB_Unweight();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Weight; }\n\tvirtual bool NeedMirrorMergedQuery() { return bMirror || bXMirrorBone; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = -0.015f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_SmoothWeight : public TweakBrush {\npublic:\n\tAnimInfo* animInfo;\n\t// boneNames: first is bone being edited; second is x-mirror bone if\n\t// bXMirrorBone is true; the rest are normalize bones\n\tstd::vector<std::string> boneNames, lockedBoneNames;\n\t// bSpreadWeight: if true, leftover weight is spread across normalize bones.\n\tbool bSpreadWeight;\n\t// bXMirrorBone:  if true, boneNames[1] is the x-mirror bone\n\tbool bXMirrorBone;\n\tbool bNormalizeWeights = false;\n\tuint8_t method; // 0 for laplacian, 1 for HC-Smooth.\n\tfloat hcAlpha;\t// Blending constants.\n\tfloat hcBeta;\n\n\tvoid lapFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, float>& wv);\n\tvoid hclapFilter(\n\t\tMesh* refmesh, const int* points, int nPoints, std::unordered_map<int, float>& wv, UndoStateShape& uss, const int boneInd, const std::unordered_map<uint16_t, float>* wPtr);\n\t// Balanced-pair parabola-fit smoothing filter.  This smoothing filter\n\t// uses only balanced pairs of neighboring vertices.  It fits a parabola\n\t// through those balanced pairs to determine the destination.\n\tvoid bppfFilter(Mesh* refmesh, const int* points, int nPoints, std::unordered_map<int, float>& wv, UndoStateShape& uss, const int boneInd, const std::unordered_map<uint16_t, float>* wPtr);\n\n\tTB_SmoothWeight();\n\tvirtual ~TB_SmoothWeight();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Weight; }\n\tvirtual bool NeedMirrorMergedQuery() { return bMirror || bXMirrorBone; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.15f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_Color : public TweakBrush {\npublic:\n\tnifly::Vector3 color;\n\n\tTB_Color();\n\tvirtual ~TB_Color();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Color; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.03f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_Uncolor : public TweakBrush {\npublic:\n\tTB_Uncolor();\n\tvirtual ~TB_Uncolor();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Color; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = -0.03f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n};\n\nclass TB_Alpha : public TweakBrush, public ClampBrush {\npublic:\n\tTB_Alpha();\n\tvirtual ~TB_Alpha();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Alpha; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = 0.03f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n};\n\nclass TB_Unalpha : public TweakBrush {\npublic:\n\tTB_Unalpha();\n\tvirtual ~TB_Unalpha();\n\n\tvirtual UndoType GetUndoType() { return UndoType::Alpha; }\n\n\tvirtual void resetSettings() {\n\t\tTweakBrush::resetSettings();\n\t\tstrength = -0.03f;\n\t}\n\n\tvirtual void brushAction(Mesh* refmesh, TweakPickInfo& pickInfo, const int* points, int nPoints, UndoStateShape& uss);\n\tvirtual bool checkSpacing(nifly::Vector3&, nifly::Vector3&) { return true; }\n};\n\nclass TweakStroke {\n\tstd::vector<Mesh*> refMeshes;\n\tTweakBrush* refBrush;\n\tbool newStroke = true;\n\tnifly::Vector3 lastPoint;\n\n\tstatic std::vector<std::future<void>> normalUpdates;\n\tstd::unordered_map<Mesh*, std::unique_ptr<int[]>> pts1;\n\tstd::unordered_map<Mesh*, std::unique_ptr<int[]>> pts2;\n\n\tstd::unordered_map<Mesh*, std::unordered_set<AABBTree::AABBTreeNode*>> affectedNodes;\n\npublic:\n\tUndoStateProject& usp;\n\n\tTweakStroke(const std::vector<Mesh*>& meshes, TweakBrush* theBrush, UndoStateProject& uspi)\n\t\t: usp(uspi) {\n\t\trefMeshes = meshes;\n\t\trefBrush = theBrush;\n\t\tusp.undoType = refBrush->GetUndoType();\n\t}\n\n\tvoid beginStroke(TweakPickInfo& pickInfo);\n\tvoid beginStroke(TweakPickInfo& pickInfo, std::vector<std::vector<nifly::Vector3>>& positionData);\n\tvoid updateStroke(TweakPickInfo& pickInfo);\n\tvoid endStroke();\n\n\tTweakBrush::BrushType BrushType() { return refBrush->Type(); }\n\tstd::string BrushName() { return refBrush->Name(); }\n\tTweakBrush* GetRefBrush() { return refBrush; }\n\tstd::vector<Mesh*> GetRefMeshes() { return refMeshes; }\n};\n"
  },
  {
    "path": "src/components/UndoHistory.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"UndoHistory.h\"\n#include \"UndoState.h\"\n\nvoid UndoHistory::ClearHistory() {\n\tstates.clear();\n\tcurIndex = UH_NONE;\n}\n\nbool UndoHistory::PopState() {\n\tif (states.empty())\n\t\treturn false;\n\n\tif (curIndex + 1 == states.size())\n\t\tcurIndex--;\n\n\tstates.pop_back();\n\treturn true;\n}\n\nUndoStateProject* UndoHistory::PushState(std::unique_ptr<UndoStateProject> uspp) {\n\tsize_t nStrokes = states.size();\n\tif (curIndex + 1 < nStrokes)\n\t\tstates.resize(curIndex + 1);\n\telse if (nStrokes == UH_MAX_UNDO)\n\t\tstates.erase(states.begin());\n\tstates.push_back(std::move(uspp));\n\tcurIndex = static_cast<uint32_t>(states.size() - 1);\n\treturn states.back().get();\n}\n\nbool UndoHistory::BackStepHistory() {\n\tif (curIndex != UH_NONE) {\n\t\tcurIndex--;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nbool UndoHistory::ForwardStepHistory() {\n\tif (states.empty())\n\t\treturn false;\n\n\tsize_t nStrokes = states.size();\n\tif (curIndex == UH_NONE || curIndex < nStrokes - 1) {\n\t\t++curIndex;\n\t\treturn true;\n\t}\n\treturn false;\n}\n"
  },
  {
    "path": "src/components/UndoHistory.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <vector>\n\nstruct UndoStateProject;\n\nclass UndoHistory {\n\tstatic constexpr uint32_t UH_NONE = 0xFFFFFFFF;\n\tstatic constexpr uint32_t UH_MAX_UNDO = 40;\n\n\tuint32_t curIndex = UH_NONE;\n\tstd::vector<std::unique_ptr<UndoStateProject>> states;\n\npublic:\n\tbool PopState();\n\tUndoStateProject* PushState(std::unique_ptr<UndoStateProject> uspp = std::make_unique<UndoStateProject>());\n\tbool BackStepHistory();\n\tbool ForwardStepHistory();\n\tvoid ClearHistory();\n\n\tbool CanUndo() const { return curIndex != UH_NONE; }\n\n\tbool CanRedo() const { return !states.empty() && curIndex + 1 < states.size(); }\n\n\tUndoStateProject* GetCurState() const {\n\t\tif (curIndex == UH_NONE)\n\t\t\treturn nullptr;\n\t\treturn states[curIndex].get();\n\t}\n\n\tUndoStateProject* GetBackState() const {\n\t\tif (states.empty())\n\t\t\treturn nullptr;\n\t\treturn states.back().get();\n\t}\n\n\tUndoStateProject* GetNextState() const {\n\t\tif (curIndex + 1 >= states.size())\n\t\t\treturn nullptr;\n\t\treturn states[curIndex + 1].get();\n\t}\n};\n"
  },
  {
    "path": "src/components/UndoState.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../utils/AABBTree.h\"\n#include \"../files/MaterialFile.h\"\n#include \"NifFile.hpp\"\n#include <memory>\n#include <optional>\n#include <string>\n#include <unordered_map>\n#include <unordered_set>\n#include <vector>\n\nenum class UndoType { VertexPosition, Mask, Weight, Color, Alpha, Mesh, Mirror, ShapeDelete, NodeTransform };\n\nstruct UndoStateVertexWeight {\n\tfloat startVal, endVal;\n};\n\nstruct UndoStateBoneWeights {\n\tstd::string boneName;\n\tstd::unordered_map<uint16_t, UndoStateVertexWeight> weights;\n};\n\nstruct UndoStateVertexBoneWeight {\n\tstd::string boneName;\n\tfloat w;\n};\n\nstruct UndoStateVertexSliderDiff {\n\tstd::string sliderName; // NOT the set name\n\tnifly::Vector3 diff;\n};\n\nstruct UndoStateVertex {\n\tuint16_t index = 0; // index into array of vertices\n\tnifly::Vector3 pos; // position in skin coordinates\n\tnifly::Vector2 uv;\n\tnifly::Color4 color;\n\t// normal, tangent, and bitangent are directions in skin coordinates\n\t// (so use ApplyTransformToDir instead of ApplyTransform).\n\tnifly::Vector3 normal, tangent, bitangent;\n\tfloat eyeData = 0.0f;\n\tfloat mask = 0.0f;\n\tstd::vector<UndoStateVertexBoneWeight> weights;\n\tstd::vector<UndoStateVertexSliderDiff> diffs;\n};\n\nstruct UndoStateTriangle {\n\tuint32_t index = 0; // index into array of triangles\n\tnifly::Triangle t;\n\tint partID = -1; // partition ID if there are partitions or segments\n};\n\ninline bool operator<(const UndoStateTriangle& t1, const UndoStateTriangle& t2) {\n\treturn t1.index < t2.index;\n}\n\nstruct UndoStateShape {\n\tstd::string shapeName;\n\t// pointStartState and pointEndState are only meaningful for\n\t// UndoType::VertexPosition, UndoType::Mask, UndoType::Color,\n\t// and UndoType::Alpha.\n\t// For UndoType::Mask and UndoType::Alpha, only the x coordinate\n\t// is meaningful.\n\tstd::unordered_map<int, nifly::Vector3> pointStartState;\n\tstd::unordered_map<int, nifly::Vector3> pointEndState;\n\t// restDiffs is only meaningful for UndoType::VertexPosition when the\n\t// edit occurred while posed. Contains rest-space NIF diffs per vertex,\n\t// used for pose-independent undo/redo (so changing the pose between\n\t// the edit and the undo doesn't break the mesh).\n\tstd::unordered_map<int, nifly::Vector3> restDiffs;\n\t// boneWeights is only meaningful for UndoType::Weight.\n\tstd::vector<UndoStateBoneWeights> boneWeights;\n\t// delVerts, addVerts, delTris, and addTris are only meaningful for\n\t// UndoType::Mesh.  They are stored in sorted order by index.\n\tstd::vector<UndoStateVertex> delVerts, addVerts;\n\tstd::vector<UndoStateTriangle> delTris, addTris;\n\tbool hadVertexColors = false;\n};\n\nstruct UndoStateShapeSliderDiff {\n\tstd::string sliderName;\n\tstd::string targetDataName;\n\tstd::unordered_map<uint16_t, nifly::Vector3> diffs;\n};\n\nstruct UndoStateShapeDelete {\n\tstd::string shapeName;\n\tbool wasBaseShape = false;\n\tnifly::NifFile nifBackup;\n\tstd::vector<UndoStateShapeSliderDiff> sliderDiffs;\n\tstd::vector<std::string> textures;\n\tstd::optional<MaterialFile> materialFile;\n};\n\nstruct UndoStateProject {\n\tUndoType undoType = UndoType::VertexPosition;\n\tstd::vector<UndoStateShape> usss;\n\n\t// Shapes that were fully deleted. Used by UndoType::ShapeDelete and\n\t// UndoType::Mesh (when vertex deletion removes an entire shape).\n\tstd::vector<UndoStateShapeDelete> deletedShapes;\n\n\t// if undoType is UndoType::VertexPosition and sliderName is not empty,\n\t// this is a slider shape edit rather than a base shape edit.\n\tstd::string sliderName;\n\n\t// sliderscale is only set if this is a slider shape edit.  Non-zero.\n\tfloat sliderscale = 1.0f;\n\n\tbool mirrorX = false;\n\tbool mirrorY = false;\n\tbool mirrorZ = false;\n\tbool swapBonesX = false;\n\n\t// Fields below are only meaningful for UndoType::NodeTransform.  They\n\t// record the start/end transform-to-parent of a single bone/node whose\n\t// local transform was edited by the user.\n\tstd::string boneName;\n\tnifly::MatTransform nodeStartXformToParent;\n\tnifly::MatTransform nodeEndXformToParent;\n};\n"
  },
  {
    "path": "src/components/WeightNorm.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"WeightNorm.h\"\n#include \"Anim.h\"\n\nvoid BoneWeightAutoNormalizer::SetUp(UndoStateShape* ussi,\n\t\t\t\t\t\t\t\t\t AnimInfo* animInfo,\n\t\t\t\t\t\t\t\t\t const std::string& shapeName,\n\t\t\t\t\t\t\t\t\t const std::vector<std::string>& boneNames,\n\t\t\t\t\t\t\t\t\t const std::vector<std::string>& lockedBoneNames,\n\t\t\t\t\t\t\t\t\t uint32_t nMBonesi,\n\t\t\t\t\t\t\t\t\t bool bSprWt) {\n\tuss = ussi;\n\twPtrs.clear();\n\tlWPtrs.clear();\n\tnMBones = nMBonesi;\n\tbSpreadWeight = bSprWt;\n\n\tconst size_t nBones = boneNames.size();\n\tconst size_t nLBones = lockedBoneNames.size();\n\n\t// Create uss->boneWeights if necessary\n\tif (uss->boneWeights.size() != nBones) {\n\t\tuss->boneWeights.resize(nBones);\n\t\tfor (size_t bi = 0; bi < nBones; ++bi)\n\t\t\tuss->boneWeights[bi].boneName = boneNames[bi];\n\t}\n\n\t// Stash weights pointers so we don't look them up over and over.\n\twPtrs.resize(nBones);\n\tlWPtrs.resize(nLBones);\n\n\tfor (size_t bi = 0; bi < nBones; ++bi)\n\t\twPtrs[bi] = animInfo->GetWeightsPtr(shapeName, boneNames[bi]);\n\n\tfor (size_t bi = 0; bi < nLBones; ++bi)\n\t\tlWPtrs[bi] = animInfo->GetWeightsPtr(shapeName, lockedBoneNames[bi]);\n}\n\nvoid BoneWeightAutoNormalizer::GrabOneVertexStartingWeights(int i) {\n\tconst size_t nBones = wPtrs.size();\n\n\t// Fill in uss start and end values if the vertex doesn't have them yet.\n\tfor (size_t bi = 0; bi < nBones; ++bi) {\n\t\tauto& bw = uss->boneWeights[bi].weights;\n\t\tif (bw.find(i) == bw.end()) {\n\t\t\tfloat val = 0.0;\n\t\t\tif (wPtrs[bi] && wPtrs[bi]->find(i) != wPtrs[bi]->end())\n\t\t\t\tval = (*wPtrs[bi])[i];\n\t\t\tif (val > 0.0 || bi < nMBones)\n\t\t\t\tbw[i].startVal = bw[i].endVal = val;\n\t\t}\n\t}\n}\n\nvoid BoneWeightAutoNormalizer::GrabStartingWeights(const int* points, int nPoints) {\n\tfor (int pi = 0; pi < nPoints; pi++)\n\t\tGrabOneVertexStartingWeights(points[pi]);\n}\n\nvoid BoneWeightAutoNormalizer::AdjustWeights(int vInd, bool* adjFlag) {\n\t// We have three sets of bones: modified, normalizable, and locked:\n\t// modified bones are those with bi < nMBones.\n\t// normalizable bones are those with bi >= nMBones.\n\t// locked bones are listed separately, in lWPtrs.\n\tconst size_t nBones = wPtrs.size();\n\tconst size_t nLBones = lWPtrs.size();\n\n\t// Calculate total locked and normalizable weight\n\tfloat totNW = 0.0;\n\tfor (size_t bi = 0; bi < nBones; ++bi) {\n\t\tif (bi < nMBones && (!adjFlag || adjFlag[bi]))\n\t\t\tcontinue;\n\t\tauto& bw = uss->boneWeights[bi].weights;\n\t\tif (bw.find(vInd) != bw.end())\n\t\t\ttotNW += bw[vInd].endVal;\n\t}\n\n\tfloat totLW = 0.0;\n\tfor (size_t bi = 0; bi < nLBones; ++bi) {\n\t\tif (!lWPtrs[bi])\n\t\t\tcontinue;\n\n\t\tauto wpit = lWPtrs[bi]->find(vInd);\n\t\tif (wpit != lWPtrs[bi]->end())\n\t\t\ttotLW += wpit->second;\n\t}\n\n\t// Calculate available weight\n\tif (totLW < WEIGHT_EPSILON)\n\t\ttotLW = 0.0;\n\n\tfloat availW = 1.0 - totLW;\n\tif (availW < WEIGHT_EPSILON)\n\t\tavailW = 0.0;\n\n\t// Limit modified weights and total them.\n\tfloat totMW = 0.0;\n\tfor (uint32_t bi = 0; bi < nMBones; ++bi) {\n\t\tif (adjFlag && !adjFlag[bi])\n\t\t\tcontinue;\n\n\t\tauto wi = uss->boneWeights[bi].weights.find(vInd);\n\t\tif (wi == uss->boneWeights[bi].weights.end())\n\t\t\tcontinue;\n\n\t\tfloat& w = wi->second.endVal;\n\t\tif (w < WEIGHT_EPSILON)\n\t\t\tw = 0.0;\n\n\t\tif (w - 1.0 > -WEIGHT_EPSILON)\n\t\t\tw = 1.0;\n\n\t\ttotMW += w;\n\t}\n\n\t// If the total modified weight is too high, reduce it.\n\tif (totMW > availW) {\n\t\tfloat modFac = totMW <= WEIGHT_EPSILON ? 0.0 : availW / totMW;\n\t\ttotMW = 0.0;\n\n\t\tfor (uint32_t bi = 0; bi < nMBones; ++bi) {\n\t\t\tif (adjFlag && !adjFlag[bi])\n\t\t\t\tcontinue;\n\n\t\t\tauto wi = uss->boneWeights[bi].weights.find(vInd);\n\t\t\tif (wi == uss->boneWeights[bi].weights.end())\n\t\t\t\tcontinue;\n\n\t\t\twi->second.endVal *= modFac;\n\t\t\ttotMW += wi->second.endVal;\n\t\t}\n\n\t\tif (totMW > availW)\n\t\t\ttotMW = availW;\n\t}\n\n\t// Normalize, adjusting only normalizable bones\n\tfloat nrmFac = totNW <= WEIGHT_EPSILON ? 0.0 : (availW - totMW) / totNW;\n\ttotNW = 0.0;\n\n\tfor (size_t bi = 0; bi < nBones; ++bi) {\n\t\tif (bi < nMBones && (!adjFlag || adjFlag[bi]))\n\t\t\tcontinue;\n\n\t\tauto owi = uss->boneWeights[bi].weights.find(vInd);\n\t\tif (owi == uss->boneWeights[bi].weights.end())\n\t\t\tcontinue;\n\n\t\tfloat& ow = owi->second.endVal;\n\t\tow *= nrmFac;\n\n\t\tif (ow < WEIGHT_EPSILON)\n\t\t\tow = 0.0;\n\t\tif (ow - 1.0 > -WEIGHT_EPSILON)\n\t\t\tow = 1.0;\n\n\t\ttotNW += ow;\n\t}\n\n\t// Check if normalization didn't work; if so, split the missing\n\t// weight among the normalizable bones, if any, and only if\n\t// bSpreadWeight is true.\n\tif (1.0 - totNW - totMW - totLW > WEIGHT_EPSILON && nBones > nMBones && bSpreadWeight) {\n\t\tfloat remainW = (1.0 - totNW - totMW - totLW) / (nBones - nMBones);\n\t\tfor (size_t bi = 0; bi < nBones; ++bi) {\n\t\t\tif (bi < nMBones && (!adjFlag || adjFlag[bi]))\n\t\t\t\tcontinue;\n\n\t\t\tauto& bw = uss->boneWeights[bi].weights;\n\t\t\tauto owi = bw.find(vInd);\n\t\t\tif (owi == bw.end())\n\t\t\t\tbw[vInd].startVal = bw[vInd].endVal = 0.0;\n\n\t\t\tbw[vInd].endVal += remainW;\n\t\t}\n\t}\n}\n\nfloat BoneWeightAutoNormalizer::SetWeight(int vInd, float w) {\n\tuss->boneWeights[0].weights[vInd].endVal = w;\n\tAdjustWeights(vInd);\n\treturn uss->boneWeights[0].weights[vInd].endVal;\n}\n"
  },
  {
    "path": "src/components/WeightNorm.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"UndoState.h\"\n\nclass AnimInfo;\n\n/* BoneWeightAutoNormalizer: this class has the algorithm for\nautomatic normalization of bone weights.  The algorithm itself is\nin AdjustWeights.  The rest is setup.\n\nThe algorithm adjusts the weights of the normalize bones to follow the\nfollowing rules, from highest to lowest priority:\n1.  The locked bones' weights are not changed (and are not even present\nin uss->boneWeights).\n2.  All weights must be between zero and one.\n4.  The sum of the weights is no more than one.\n5.  The specified weights are set.\n6.  If not bSpreadWeight, zero weights are not changed.\n7.  The sum of the weights is at least one.\n8.  Weights are multiplied by a scale factor if nonzero; an amount\nis added to each if zero.\n\nNote that, while uss->boneWeights is the main output, it can also be\na source of input, containing the results of previous changes.\n*/\nclass BoneWeightAutoNormalizer {\n\tstatic constexpr double WEIGHT_EPSILON = .001;\n\tUndoStateShape* uss = nullptr;\n\tstd::vector<std::unordered_map<uint16_t, float>*> wPtrs, lWPtrs;\n\tuint32_t nMBones = 0;\n\tbool bSpreadWeight = false;\n\npublic:\n\t/* SetUp: fills in the class's private data.  ussi->boneWeights\n\tmust either already match boneNames or be empty, in which case\n\tit is initialized.  boneNames and lockedBoneNames must not have\n\tany common names, and together they must include all bones with\n\tnon-zero weights for the shape.  boneNames is the \"normalize\n\tbones\", the bones whose weights can be adjusted, and must start\n\twith the bones whose weights will actually be modified; the number\n\tof these modified bones is nMBones.  */\n\tvoid SetUp(UndoStateShape* ussi,\n\t\t\t   AnimInfo* animInfo,\n\t\t\t   const std::string& shapeName,\n\t\t\t   const std::vector<std::string>& boneNames,\n\t\t\t   const std::vector<std::string>& lockedBoneNames,\n\t\t\t   uint32_t nMBones,\n\t\t\t   bool bSprWt);\n\n\t/* GrabOneVertexStartingWeights: initializes missing startVal\n\tand endVal in uss->boneweights for normalize bones for the vertex\n\twith the given index by copying weights from animInfo.  For\n\tbones with index >= nMBones, only nonzero weights are copied. */\n\tvoid GrabOneVertexStartingWeights(int ptInd);\n\n\t/* GrabStartingWeights: calls GrabOneVertexStartingWeights for\n\tthe given vertex indices. */\n\tvoid GrabStartingWeights(const int* points, int nPoints);\n\n\t/* AdjustWeights: normalizes the weights for the vertex, preferring\n\tto adjust weights for bones with index >= nMBones (the unmodified\n\tbut normalizable bones) before those with index < nBones (the\n\tmodified bones).  If adjFlag is not null, it points to an array\n\tof size nMBones, with each array element indicating whether the\n\tweight for that bone was adjusted or not.  Note that only weight\n\tdata in uss is accessed for unlocked bones, so you must ensure\n\tthat all necessary data is grabbed first. */\n\tvoid AdjustWeights(int ptInd, bool* adjFlag = nullptr);\n\n\t/* SetWeight: sets the weight for the vertex with the given\n\tindex for bone 0 (indexed into boneNames or uss->boneWeights) and\n\tnormalizes the weights for the vertex (by calling AdjustWeights).\n\tReturns the adjusted w. */\n\tfloat SetWeight(int ptInd, float w);\n};\n"
  },
  {
    "path": "src/files/FBXWrangler.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#ifdef USE_FBXSDK\n\n#include \"FBXWrangler.h\"\n#include <fbxsdk.h>\n\nextern ConfigurationManager Config;\n\nusing namespace nifly;\n\n// Recursive function to get a node's global default position.\n// As a prerequisite, parent node's default local position must be already set.\nFbxAMatrix GetGlobalDefaultPosition(FbxNode* pNode) {\n\tFbxAMatrix lLocalPosition;\n\tFbxAMatrix lGlobalPosition;\n\tFbxAMatrix lParentGlobalPosition;\n\tlLocalPosition.SetT(pNode->LclTranslation.Get());\n\tlLocalPosition.SetR(pNode->LclRotation.Get());\n\tlLocalPosition.SetS(pNode->LclScaling.Get());\n\n\tif (pNode->GetParent()) {\n\t\tlParentGlobalPosition = GetGlobalDefaultPosition(pNode->GetParent());\n\t\tlGlobalPosition = lParentGlobalPosition * lLocalPosition;\n\t}\n\telse\n\t\tlGlobalPosition = lLocalPosition;\n\n\treturn lGlobalPosition;\n}\n\n// Function to set a node's local position from a global position.\n// As a prerequisite, parent node's default local position must be already set.\nvoid SetGlobalDefaultPosition(FbxNode* pNode, FbxAMatrix pGlobalPosition) {\n\tFbxAMatrix lLocalPosition;\n\tFbxAMatrix lParentGlobalPosition;\n\n\tif (pNode->GetParent()) {\n\t\tlParentGlobalPosition = GetGlobalDefaultPosition(pNode->GetParent());\n\t\tlLocalPosition = lParentGlobalPosition.Inverse() * pGlobalPosition;\n\t}\n\telse\n\t\tlLocalPosition = pGlobalPosition;\n\n\tpNode->LclTranslation.Set(lLocalPosition.GetT());\n\tpNode->LclRotation.Set(lLocalPosition.GetR());\n\tpNode->LclScaling.Set(lLocalPosition.GetS());\n}\n\nstruct FBXWrangler::Priv {\n\tFbxManager* sdkManager = nullptr;\n\tFbxScene* scene = nullptr;\n\tstd::map<std::string, FBXShape> shapes;\n\n\t// Recursively add bones to the skeleton in a depth-first manner\n\tFbxNode* AddLimb(FbxNode* parent, NifFile* nif, NiNode* nifBone);\n\tvoid AddLimbChildren(FbxNode* node, NifFile* nif, NiNode* nifBone);\n\n\tvoid AddGeometry(NiShape* shape, const std::vector<Vector3>* verts, const std::vector<Vector3>* norms, const std::vector<Triangle>* tris, const std::vector<Vector2>* uvs);\n\n\tbool LoadMeshes(const FBXImportOptions& options);\n\tvoid LoadMesh(const FBXImportOptions& options, FbxNode* node);\n};\n\nFBXWrangler::FBXWrangler()\n\t: priv(new Priv) {\n\tpriv->sdkManager = FbxManager::Create();\n\n\tFbxIOSettings* ios = FbxIOSettings::Create(priv->sdkManager, IOSROOT);\n\tpriv->sdkManager->SetIOSettings(ios);\n\n\tNewScene();\n}\n\nFBXWrangler::~FBXWrangler() {\n\tif (priv->scene)\n\t\tCloseScene();\n\n\tif (priv->sdkManager)\n\t\tpriv->sdkManager->Destroy();\n}\n\nvoid FBXWrangler::NewScene() {\n\tif (priv->scene)\n\t\tCloseScene();\n\n\tpriv->scene = FbxScene::Create(priv->sdkManager, \"OutfitStudioScene\");\n}\n\nvoid FBXWrangler::CloseScene() {\n\tif (priv->scene)\n\t\tpriv->scene->Destroy();\n\n\tpriv->scene = nullptr;\n\tcomName.clear();\n}\n\nvoid FBXWrangler::GetShapeNames(std::vector<std::string>& outNames) {\n\tfor (auto& s : priv->shapes)\n\t\toutNames.push_back(s.first);\n}\n\nFBXShape* FBXWrangler::GetShape(const std::string& shapeName) {\n\treturn &(priv->shapes[shapeName]);\n}\n\nvoid FBXWrangler::Priv::AddGeometry(\n\tNiShape* shape, const std::vector<Vector3>* verts, const std::vector<Vector3>* norms, const std::vector<Triangle>* tris, const std::vector<Vector2>* uvs) {\n\tif (!verts || verts->empty())\n\t\treturn;\n\n\tFbxMesh* m = FbxMesh::Create(sdkManager, shape->name.get().c_str());\n\n\tFbxGeometryElementNormal* normElement = nullptr;\n\tif (norms && !norms->empty()) {\n\t\tnormElement = m->CreateElementNormal();\n\t\tnormElement->SetMappingMode(FbxLayerElement::eByControlPoint);\n\t\tnormElement->SetReferenceMode(FbxLayerElement::eDirect);\n\t}\n\n\tFbxGeometryElementUV* uvElement = nullptr;\n\tif (uvs && !uvs->empty()) {\n\t\tstd::string uvName = shape->name.get() + \"UV\";\n\t\tuvElement = m->CreateElementUV(uvName.c_str());\n\t\tuvElement->SetMappingMode(FbxGeometryElement::eByControlPoint);\n\t\tuvElement->SetReferenceMode(FbxGeometryElement::eDirect);\n\t}\n\n\tm->InitControlPoints((*verts).size());\n\tFbxVector4* points = m->GetControlPoints();\n\n\tfor (int i = 0; i < m->GetControlPointsCount(); i++) {\n\t\tpoints[i] = FbxVector4((*verts)[i].y, (*verts)[i].z, (*verts)[i].x);\n\t\tif (normElement)\n\t\t\tnormElement->GetDirectArray().Add(FbxVector4((*norms)[i].y, (*norms)[i].z, (*norms)[i].x));\n\t\tif (uvElement)\n\t\t\tuvElement->GetDirectArray().Add(FbxVector2((*uvs)[i].u, (*uvs)[i].v));\n\t}\n\n\tif (tris) {\n\t\tfor (auto& t : (*tris)) {\n\t\t\tm->BeginPolygon();\n\t\t\tm->AddPolygon(t.p1);\n\t\t\tm->AddPolygon(t.p2);\n\t\t\tm->AddPolygon(t.p3);\n\t\t\tm->EndPolygon();\n\t\t}\n\t}\n\n\tFbxNode* mNode = FbxNode::Create(sdkManager, shape->name.get().c_str());\n\tmNode->SetNodeAttribute(m);\n\n\t// Intended for Maya\n\t//mNode->LclScaling.Set(FbxDouble3(1, 1, 1));\n\t//mNode->LclRotation.Set(FbxDouble3(-90, 0, 0));\n\t//mNode->LclTranslation.Set(FbxDouble3(0, 120, 0));\n\n\tFbxNode* rootNode = scene->GetRootNode();\n\trootNode->AddChild(mNode);\n}\n\nvoid FBXWrangler::AddSkeleton(NifFile* nif, bool onlyNonSkeleton) {\n\tauto root = nif->FindBlockByName<NiNode>(Config[\"Anim/SkeletonRootName\"]);\n\tauto com = nif->FindBlockByName<NiNode>(\"COM\");\n\tif (!com)\n\t\tcom = nif->FindBlockByName<NiNode>(\"NPC COM [COM ]\");\n\tif (!com)\n\t\tcom = nif->FindBlockByName<NiNode>(\"Bip01 NonAccum\");\n\n\t// Likely a NIF with non-hierarchical nodes\n\tif (!com)\n\t\tcom = nif->GetRootNode();\n\tif (!com)\n\t\treturn;\n\n\tif (comName.empty())\n\t\tcomName = com->name.get();\n\n\t// Check if skeleton already exists\n\tstd::string skelName = \"NifSkeleton\";\n\tFbxNode* skelNode = priv->scene->GetRootNode()->FindChild(skelName.c_str());\n\tif (skelNode && onlyNonSkeleton) {\n\t\t// Add non-skeleton nodes to the existing skeleton\n\t\tFbxNode* comNode = skelNode->FindChild(comName.c_str());\n\t\tif (comNode) {\n\t\t\tstd::vector<NiNode*> boneNodes = nif->GetChildren<NiNode>(com);\n\t\t\tfor (auto& b : boneNodes)\n\t\t\t\tpriv->AddLimb(comNode, nif, b);\n\t\t}\n\t}\n\telse if (!skelNode) {\n\t\t// Create new skeleton\n\t\tFbxSkeleton* skel = FbxSkeleton::Create(priv->scene, skelName.c_str());\n\t\tskel->SetSkeletonType(FbxSkeleton::eRoot);\n\n\t\tskelNode = FbxNode::Create(priv->scene, skelName.c_str());\n\t\tskelNode->SetNodeAttribute(skel);\n\t\t//skelNode->SetPivotState(FbxNode::eSourcePivot, FbxNode::ePivotActive);\n\t\t//skelNode->SetRotationOrder(FbxNode::eSourcePivot, eEulerYZX);\n\n\t\tFbxNode* parentNode = skelNode;\n\t\tif (root) {\n\t\t\tFbxSkeleton* rootBone = FbxSkeleton::Create(priv->scene, root->name.get().c_str());\n\t\t\trootBone->SetSkeletonType(FbxSkeleton::eLimbNode);\n\t\t\trootBone->Size.Set(1.0);\n\n\t\t\tFbxNode* rootNode = FbxNode::Create(priv->scene, root->name.get().c_str());\n\t\t\trootNode->SetNodeAttribute(rootBone);\n\n\t\t\tconst MatTransform& ttp = root->GetTransformToParent();\n\t\t\trootNode->LclTranslation.Set(FbxDouble3(ttp.translation.y, ttp.translation.z, ttp.translation.x));\n\n\t\t\tfloat rx, ry, rz;\n\t\t\tttp.ToEulerDegrees(rx, ry, rz);\n\t\t\trootNode->LclRotation.Set(FbxDouble3(ry, rz, rx));\n\t\t\trootNode->LclScaling.Set(FbxDouble3(ttp.scale));\n\n\t\t\t//rootNode->SetPivotState(FbxNode::eSourcePivot, FbxNode::ePivotActive);\n\t\t\t//rootNode->SetRotationOrder(FbxNode::eSourcePivot, eEulerYZX);\n\n\t\t\t// Add root as first node\n\t\t\tparentNode->AddChild(rootNode);\n\t\t\tparentNode = rootNode;\n\t\t}\n\n\t\tif (com) {\n\t\t\tFbxSkeleton* comBone = FbxSkeleton::Create(priv->scene, com->name.get().c_str());\n\t\t\tcomBone->SetSkeletonType(FbxSkeleton::eLimbNode);\n\t\t\tcomBone->Size.Set(1.0);\n\n\t\t\tFbxNode* comNode = FbxNode::Create(priv->scene, com->name.get().c_str());\n\t\t\tcomNode->SetNodeAttribute(comBone);\n\n\t\t\tconst MatTransform& ttp = com->GetTransformToParent();\n\t\t\tcomNode->LclTranslation.Set(FbxDouble3(ttp.translation.y, ttp.translation.z, ttp.translation.x));\n\n\t\t\tfloat rx, ry, rz;\n\t\t\tttp.ToEulerDegrees(rx, ry, rz);\n\t\t\tcomNode->LclRotation.Set(FbxDouble3(ry, rz, rx));\n\t\t\tcomNode->LclScaling.Set(FbxDouble3(ttp.scale));\n\n\t\t\t//comNode->SetPivotState(FbxNode::eSourcePivot, FbxNode::ePivotActive);\n\t\t\t//comNode->SetRotationOrder(FbxNode::eSourcePivot, eEulerYZX);\n\n\t\t\t// Add COM as child of root\n\t\t\tparentNode->AddChild(comNode);\n\t\t\tparentNode = comNode;\n\t\t}\n\n\t\tstd::vector<NiNode*> boneNodes = nif->GetChildren<NiNode>(com);\n\t\tfor (auto bn : boneNodes)\n\t\t\tpriv->AddLimb(parentNode, nif, bn);\n\n\t\tpriv->scene->GetRootNode()->AddChild(skelNode);\n\t}\n}\n\nFbxNode* FBXWrangler::Priv::AddLimb(FbxNode* parent, NifFile* nif, NiNode* nifBone) {\n\tFbxNode* node = scene->GetRootNode()->FindChild(nifBone->name.get().c_str());\n\tif (!node) {\n\t\t// Add new bone\n\t\tFbxSkeleton* bone = FbxSkeleton::Create(scene, nifBone->name.get().c_str());\n\t\tbone->SetSkeletonType(FbxSkeleton::eLimbNode);\n\t\tbone->Size.Set(1.0f);\n\n\t\tnode = FbxNode::Create(scene, nifBone->name.get().c_str());\n\t\tnode->SetNodeAttribute(bone);\n\n\t\t//node->SetPivotState(FbxNode::eSourcePivot, FbxNode::ePivotActive);\n\t\t//node->SetRotationOrder(FbxNode::eSourcePivot, eEulerYZX);\n\n\t\tFbxVector4 lT, lR, lS;\n\t\tFbxAMatrix lGM;\n\t\tMatTransform xformGlobal;\n\t\tnif->GetNodeTransformToGlobal(nifBone->name.get(), xformGlobal);\n\n\t\tfloat rx, ry, rz;\n\t\txformGlobal.ToEulerDegrees(rx, ry, rz);\n\n\t\tlT.Set(xformGlobal.translation.y, xformGlobal.translation.z, xformGlobal.translation.x);\n\t\tlR.Set(ry, rz, rx);\n\t\tlS.Set(xformGlobal.scale, xformGlobal.scale, xformGlobal.scale);\n\n\t\tlGM.SetT(lT);\n\t\tlGM.SetR(lR);\n\t\tlGM.SetS(lS);\n\n\t\tparent->AddChild(node);\n\t\tSetGlobalDefaultPosition(node, lGM);\n\t}\n\telse {\n\t\t// Bone already exists, but go through children and return nullptr\n\t\tAddLimbChildren(node, nif, nifBone);\n\t\treturn nullptr;\n\t}\n\n\tAddLimbChildren(node, nif, nifBone);\n\treturn node;\n}\n\nvoid FBXWrangler::Priv::AddLimbChildren(FbxNode* node, NifFile* nif, NiNode* nifBone) {\n\tstd::vector<NiNode*> boneNodes = nif->GetChildren<NiNode>(nifBone);\n\tfor (auto& b : boneNodes)\n\t\tAddLimb(node, nif, b);\n}\n\nvoid FBXWrangler::AddNif(NifFile* nif, AnimInfo* anim, bool transToGlobal, NiShape* shape) {\n\tAddSkeleton(nif, true);\n\n\tfor (auto& s : nif->GetShapes()) {\n\t\tif (!shape || s == shape) {\n\t\t\tstd::vector<Triangle> tris;\n\t\t\tif (s && s->GetTriangles(tris)) {\n\t\t\t\tconst std::vector<Vector3>* verts = nif->GetVertsForShape(s);\n\t\t\t\tconst std::vector<Vector3>* norms = nif->GetNormalsForShape(s);\n\t\t\t\tconst std::vector<Vector2>* uvs = nif->GetUvsForShape(s);\n\n\t\t\t\tstd::vector<Vector3> gVerts, gNorms;\n\t\t\t\tif (verts && transToGlobal) {\n\t\t\t\t\tMatTransform toGlobal = anim->GetTransformShapeToGlobal(s);\n\n\t\t\t\t\tgVerts.resize(verts->size());\n\t\t\t\t\tfor (size_t i = 0; i < gVerts.size(); ++i)\n\t\t\t\t\t\tgVerts[i] = toGlobal.ApplyTransform((*verts)[i]);\n\n\t\t\t\t\tverts = &gVerts;\n\n\t\t\t\t\tif (norms) {\n\t\t\t\t\t\tgNorms.resize(norms->size());\n\t\t\t\t\t\tfor (size_t i = 0; i < gNorms.size(); ++i)\n\t\t\t\t\t\t\tgNorms[i] = toGlobal.ApplyTransformToDir((*norms)[i]);\n\n\t\t\t\t\t\tnorms = &gNorms;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tpriv->AddGeometry(s, verts, norms, &tris, uvs);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid FBXWrangler::AddSkinning(AnimInfo* anim, NiShape* shape) {\n\tFbxNode* rootNode = priv->scene->GetRootNode();\n\tFbxNode* skelNode = rootNode->FindChild(\"NifSkeleton\");\n\n\tif (!skelNode || !shape)\n\t\treturn;\n\n\tfor (auto& animSkin : anim->shapeSkinning) {\n\t\tif (shape->name != animSkin.first && !shape->name.get().empty())\n\t\t\tcontinue;\n\n\t\tstd::string shapeName = animSkin.first;\n\t\tFbxNode* shapeNode = rootNode->FindChild(shapeName.c_str());\n\t\tif (!shapeNode)\n\t\t\tcontinue;\n\n\t\tstd::string shapeSkin = shapeName + \"_sk\";\n\t\tFbxSkin* skin = FbxSkin::Create(priv->scene, shapeSkin.c_str());\n\n\t\tfor (auto& bone : anim->shapeBones[shapeName]) {\n\t\t\tFbxNode* jointNode = skelNode->FindChild(bone.c_str());\n\t\t\tif (jointNode) {\n\t\t\t\tstd::string boneSkin = bone + \"_sk\";\n\t\t\t\tFbxCluster* aCluster = FbxCluster::Create(priv->scene, boneSkin.c_str());\n\t\t\t\taCluster->SetLink(jointNode);\n\t\t\t\taCluster->SetLinkMode(FbxCluster::eTotalOne);\n\n\t\t\t\tauto weights = anim->GetWeightsPtr(shapeName, bone);\n\t\t\t\tif (weights) {\n\t\t\t\t\tfor (auto& vw : *weights)\n\t\t\t\t\t\taCluster->AddControlPointIndex(vw.first, vw.second);\n\t\t\t\t}\n\n\t\t\t\tFbxAMatrix lXMatrix = rootNode->EvaluateGlobalTransform();\n\t\t\t\taCluster->SetTransformMatrix(lXMatrix);\n\n\t\t\t\tlXMatrix = jointNode->EvaluateGlobalTransform();\n\t\t\t\taCluster->SetTransformLinkMatrix(lXMatrix);\n\n\t\t\t\tskin->AddCluster(aCluster);\n\t\t\t}\n\t\t}\n\n\t\tFbxMesh* shapeMesh = (FbxMesh*)shapeNode->GetNodeAttribute();\n\t\tif (shapeMesh)\n\t\t\tshapeMesh->AddDeformer(skin);\n\t}\n}\n\nbool FBXWrangler::ExportScene(const std::string& fileName) {\n\tFbxExporter* iExporter = FbxExporter::Create(priv->sdkManager, \"\");\n\tif (!iExporter->Initialize(fileName.c_str(), -1, priv->sdkManager->GetIOSettings())) {\n\t\tiExporter->Destroy();\n\t\treturn false;\n\t}\n\n\t// Export options determine what kind of data is to be imported.\n\t// The default (except for the option eEXPORT_TEXTURE_AS_EMBEDDED)\n\t// is true, but here we set the options explicitly.\n\tFbxIOSettings* ios = priv->sdkManager->GetIOSettings();\n\tios->SetBoolProp(EXP_FBX_MATERIAL, true);\n\tios->SetBoolProp(EXP_FBX_TEXTURE, true);\n\tios->SetBoolProp(EXP_FBX_EMBEDDED, false);\n\tios->SetBoolProp(EXP_FBX_SHAPE, true);\n\tios->SetBoolProp(EXP_FBX_GOBO, true);\n\tios->SetBoolProp(EXP_FBX_ANIMATION, true);\n\tios->SetBoolProp(EXP_FBX_GLOBAL_SETTINGS, true);\n\n\tiExporter->SetFileExportVersion(FBX_2014_00_COMPATIBLE);\n\n\tFbxAxisSystem axis(FbxAxisSystem::eMax);\n\taxis.ConvertScene(priv->scene);\n\n\tbool status = iExporter->Export(priv->scene);\n\tiExporter->Destroy();\n\n\treturn status;\n}\n\nbool FBXWrangler::ImportScene(const std::string& fileName, const FBXImportOptions& options) {\n\tFbxIOSettings* ios = priv->sdkManager->GetIOSettings();\n\tios->SetBoolProp(IMP_FBX_MATERIAL, true);\n\tios->SetBoolProp(IMP_FBX_TEXTURE, true);\n\tios->SetBoolProp(IMP_FBX_LINK, false);\n\tios->SetBoolProp(IMP_FBX_SHAPE, true);\n\tios->SetBoolProp(IMP_FBX_GOBO, true);\n\tios->SetBoolProp(IMP_FBX_ANIMATION, true);\n\tios->SetBoolProp(IMP_FBX_GLOBAL_SETTINGS, true);\n\n\tFbxImporter* iImporter = FbxImporter::Create(priv->sdkManager, \"\");\n\tif (!iImporter->Initialize(fileName.c_str(), -1, ios)) {\n\t\tiImporter->Destroy();\n\t\treturn false;\n\t}\n\n\tNewScene();\n\n\tbool status = iImporter->Import(priv->scene);\n\tiImporter->Destroy();\n\n\tif (!status)\n\t\treturn false;\n\n\treturn priv->LoadMeshes(options);\n}\n\nbool FBXWrangler::Priv::LoadMeshes(const FBXImportOptions& options) {\n\tif (!scene)\n\t\treturn false;\n\n\tstd::function<void(FbxNode*)> loadNodeChildren = [&](FbxNode* root) {\n\t\tfor (int i = 0; i < root->GetChildCount(); i++) {\n\t\t\tFbxNode* child = root->GetChild(i);\n\n\t\t\tif (child->GetNodeAttribute()->GetAttributeType() == FbxNodeAttribute::eMesh)\n\t\t\t\tLoadMesh(options, child);\n\n\t\t\tloadNodeChildren(child);\n\t\t}\n\t};\n\n\tFbxNode* root = scene->GetRootNode();\n\tloadNodeChildren(root);\n\n\treturn true;\n}\n\nvoid FBXWrangler::Priv::LoadMesh(const FBXImportOptions& options, FbxNode* node) {\n\tFBXShape shape;\n\tshape.name = node->GetName();\n\n\tif (!options.ImportAll && options.ImportShapes.count(shape.name) == 0)\n\t\treturn;\n\n\tFbxMesh* m = (FbxMesh*)node->GetNodeAttribute();\n\n\tif (!m->IsTriangleMesh()) {\n\t\tFbxGeometryConverter converter(sdkManager);\n\t\tm = (FbxMesh*)converter.Triangulate((FbxNodeAttribute*)m, true);\n\t}\n\n\tFbxGeometryElementUV* geuv = m->GetElementUV(0);\n\tbool haveUVs = geuv && (\n\t\tgeuv->GetMappingMode() == FbxGeometryElement::eByControlPoint ||\n\t\tgeuv->GetMappingMode() == FbxGeometryElement::eByPolygonVertex);\n\tconst char* uvName = nullptr;\n\tif (geuv)\n\t\tuvName = geuv->GetName();\n\n\tFbxGeometryElementNormal* genrm = m->GetElementNormal(0);\n\tbool haveNorms = genrm && (\n\t\tgenrm->GetMappingMode() == FbxGeometryElement::eByControlPoint ||\n\t\tgenrm->GetMappingMode() == FbxGeometryElement::eByPolygonVertex);\n\n\tint nVerts = m->GetControlPointsCount();\n\n\t// Each vertex in the file may need to be duplicated if it's used with\n\t// different texture coordinates or normals.  vdata keeps track of all\n\t// the duplicates of a vertex.\n\tstruct VertData {\n\t\tint tmpvi, finvi;\n\t\tVector2 uv;\n\t\tVector3 nrm;\n\t};\n\tstd::vector<std::vector<VertData>> vdata(nVerts);\n\n\t// As we find distinct vertices, we assign each a unique temporary vertex\n\t// index, tmpvi.  Later, we'll renumber the vertices to preserve the file's\n\t// vertex ordering as well as possible; that final vertex ordering will\n\t// be called finvi.\n\tint tmpvi = 0;\n\n\tint numTris = m->GetPolygonCount();\n\tshape.tris.resize(numTris);\n\tfor (int ti = 0; ti < numTris; ti++) {\n\t\tif (m->GetPolygonSize(ti) != 3)\n\t\t\tcontinue;\t// Shouldn't be possible since we called Triangulate\n\n\t\t// For now, each of the triangle's vertex indices will be filled in\n\t\t// with the tmpvi for the vertex.  We'll update them to finvi later.\n\t\tTriangle& t = shape.tris[ti];\n\n\t\tfor (int tvi = 0; tvi < 3; ++tvi) {\n\t\t\tint vi = m->GetPolygonVertex(ti, tvi);\n\n\t\t\t// Find UV\n\t\t\tVector2 uv;\n\t\t\tif (geuv && geuv->GetMappingMode() == FbxGeometryElement::eByControlPoint) {\n\t\t\t\tint index = vi;\n\t\t\t\tif (geuv->GetReferenceMode() == FbxLayerElement::eIndexToDirect)\n\t\t\t\t\tindex = geuv->GetIndexArray().GetAt(vi);\n\n\t\t\t\tuv.u = geuv->GetDirectArray().GetAt(index).mData[0];\n\t\t\t\tuv.v = geuv->GetDirectArray().GetAt(index).mData[1];\n\t\t\t}\n\t\t\tif (geuv && geuv->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {\n\t\t\t\tFbxVector2 v_uv;\n\t\t\t\tbool isUnmapped;\n\n\t\t\t\tif (m->GetPolygonVertexUV(ti, tvi, uvName, v_uv, isUnmapped)) {\n\t\t\t\t\tuv.u = v_uv.mData[0];\n\t\t\t\t\tuv.v = v_uv.mData[1];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Find normal\n\t\t\tVector3 nrm;\n\t\t\tif (genrm && genrm->GetMappingMode() == FbxGeometryElement::eByControlPoint) {\n\t\t\t\tint index = vi;\n\t\t\t\tif (genrm->GetReferenceMode() == FbxLayerElement::eIndexToDirect)\n\t\t\t\t\tindex = genrm->GetIndexArray().GetAt(vi);\n\n\t\t\t\tnrm.x = genrm->GetDirectArray().GetAt(index).mData[2];\n\t\t\t\tnrm.y = genrm->GetDirectArray().GetAt(index).mData[0];\n\t\t\t\tnrm.z = genrm->GetDirectArray().GetAt(index).mData[1];\n\t\t\t}\n\t\t\tif (genrm && genrm->GetMappingMode() == FbxGeometryElement::eByPolygonVertex) {\n\t\t\t\tFbxVector4 v_nrm;\n\t\t\t\tif (m->GetPolygonVertexNormal(ti, tvi, v_nrm)) {\n\t\t\t\t\tnrm.x = v_nrm.mData[2];\n\t\t\t\t\tnrm.y = v_nrm.mData[0];\n\t\t\t\t\tnrm.z = v_nrm.mData[1];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Try to find tmpvi by searching VertData\n\t\t\tbool found = false;\n\t\t\tfor (VertData& vd : vdata[vi]) {\n\t\t\t\tif (haveUVs && uv != vd.uv)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (haveNorms && nrm != vd.nrm)\n\t\t\t\t\tcontinue;\n\t\t\t\tfound = true;\n\t\t\t\t// Found existing tmpvi\n\t\t\t\tt[tvi] = vd.tmpvi;\n\t\t\t}\n\t\t\tif (!found) {\n\t\t\t\t// New vertex: add to vdata and use new tmpvi\n\t\t\t\tvdata[vi].push_back(VertData{tmpvi, 0, uv, nrm});\n\t\t\t\tt[tvi] = tmpvi++;\n\t\t\t}\n\t\t}\t// end tvi loop\n\t}\t// end ti loop\n\n\t// vdata now has a complete list of vertices used by this shape.  The\n\t// number of vertices used is tmpvi.  We create the \"final\" vertex ordering\n\t// by going through vdata in order, assigning a finvi to each used vertex.\n\t// We also prepare a map from tmpvi to finvi.  We store the data\n\t// in shape.verts, shape.uvs, and shape.normals.\n\tint finvi = 0;\n\tstd::vector<int> tmpviToFinvi(tmpvi);\n\tshape.verts.resize(tmpvi);\n\tif (haveUVs)\n\t\tshape.uvs.resize(tmpvi);\n\tif (haveNorms)\n\t\tshape.normals.resize(tmpvi);\n\tfor (int filevi = 0; filevi < nVerts; ++filevi) {\n\t\tFbxVector4 fvert = m->GetControlPointAt(filevi);\n\t\tVector3 vert;\n\t\tvert.x = fvert.mData[2];\n\t\tvert.y = fvert.mData[0];\n\t\tvert.z = fvert.mData[1];\n\t\tfor (VertData& vd : vdata[filevi]) {\n\t\t\ttmpviToFinvi[vd.tmpvi] = finvi;\n\t\t\tshape.verts[finvi] = vert;\n\t\t\tif (haveUVs)\n\t\t\t\tshape.uvs[finvi] = vd.uv;\n\t\t\tif (haveNorms)\n\t\t\t\tshape.normals[finvi] = vd.nrm;\n\t\t\tvd.finvi = finvi;\n\t\t\t++finvi;\n\t\t}\n\t}\n\t// assert(finvi == tmpvi)\n\n\t// Map the triangle vertex indices from tmpvi to finvi\n\tfor (Triangle& t : shape.tris)\n\t\tfor (int tvi = 0; tvi < 3; ++tvi)\n\t\t\tt[tvi] = tmpviToFinvi[t[tvi]];\n\n\t// Get bone weights\n\tfor (int iSkin = 0; iSkin < m->GetDeformerCount(FbxDeformer::eSkin); iSkin++) {\n\t\tFbxSkin* skin = (FbxSkin*)m->GetDeformer(iSkin, FbxDeformer::eSkin);\n\n\t\tfor (int iCluster = 0; iCluster < skin->GetClusterCount(); iCluster++) {\n\t\t\tFbxCluster* cluster = skin->GetCluster(iCluster);\n\t\t\tif (!cluster->GetLink())\n\t\t\t\tcontinue;\n\n\t\t\tstd::string bone = cluster->GetLink()->GetName();\n\t\t\tshape.boneNames.insert(bone);\n\t\t\tfor (int iPoint = 0; iPoint < cluster->GetControlPointIndicesCount(); iPoint++) {\n\t\t\t\tint filevi = cluster->GetControlPointIndices()[iPoint];\n\t\t\t\tfloat w = cluster->GetControlPointWeights()[iPoint];\n\t\t\t\t// The single vertex in the file may have been expanded to\n\t\t\t\t// multiple vertices because of differing UV or normals.\n\t\t\t\t// Set the weight for all of these vertices.\n\t\t\t\tfor (VertData& vd : vdata[filevi])\n\t\t\t\t\tshape.boneSkin[bone].SetWeight(vd.finvi, w);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (options.InvertU)\n\t\tfor (auto& uv : shape.uvs)\n\t\t\tuv.u = 1.0f - uv.u;\n\n\tif (options.InvertV)\n\t\tfor (auto& uv : shape.uvs)\n\t\t\tuv.v = 1.0f - uv.v;\n\n\tMatrix4 mat;\n\tmat.PushScale(options.Scale, options.Scale, options.Scale);\n\tmat.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmat.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmat.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tMatrix4 matRot;\n\tmatRot.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmatRot.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmatRot.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tfor (auto& v : shape.verts)\n\t\tv = mat * v;\n\n\tfor (auto& n : shape.normals)\n\t\tn = matRot * n;\n\n\tshapes[shape.name] = std::move(shape);\n}\n\n#endif\n"
  },
  {
    "path": "src/files/FBXWrangler.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#ifdef USE_FBXSDK\n\n#include \"../components/Anim.h\"\n#include \"../components/Mesh.h\"\n#include \"../program/FBXImportOptions.h\"\n#include \"NifFile.hpp\"\n\n#include <memory>\n#include <set>\n\nstruct FBXImportOptions {\n\tbool InvertU = false;\n\tbool InvertV = false;\n\tfloat Scale = 1.0f;\n\tfloat RotateX = 0.0f;\n\tfloat RotateY = 0.0f;\n\tfloat RotateZ = 0.0f;\n\n\tbool ImportAll = true;\n\tstd::set<std::string> ImportShapes;\n};\n\nclass FBXShape {\npublic:\n\tclass FBXSkin {\n\tprivate:\n\t\tstd::unordered_map<uint16_t, float> vertWeights;\n\n\tpublic:\n\t\tvoid SetWeight(uint16_t vert, float wt) { vertWeights[vert] = wt; }\n\n\t\tfloat GetWeight(uint16_t vert) {\n\t\t\tauto it = vertWeights.find(vert);\n\t\t\tif (it == vertWeights.end())\n\t\t\t\treturn 0.0f;\n\n\t\t\treturn vertWeights[vert];\n\t\t}\n\n\t\tstd::unordered_map<uint16_t, float>& GetWeights() { return vertWeights; }\n\t};\n\n\tstd::string name;\n\tstd::vector<nifly::Vector3> verts;\n\tstd::vector<nifly::Triangle> tris;\n\tstd::vector<nifly::Vector2> uvs;\n\tstd::vector<nifly::Vector3> normals;\n\n\tstd::unordered_map<std::string, FBXSkin> boneSkin;\n\tstd::set<std::string> boneNames;\n};\n\nclass FBXWrangler {\nprivate:\n\tstruct Priv;\n\tstd::unique_ptr<Priv> priv;\n\n\tstd::string comName;\n\npublic:\n\tFBXWrangler();\n\t~FBXWrangler();\n\n\tvoid NewScene();\n\tvoid CloseScene();\n\n\tvoid GetShapeNames(std::vector<std::string>& outNames);\n\tFBXShape* GetShape(const std::string& shapeName);\n\n\tvoid AddSkeleton(nifly::NifFile* nif, bool onlyNonSkeleton = false);\n\tvoid AddNif(nifly::NifFile* meshNif, AnimInfo* anim, bool transToGlobal, nifly::NiShape* shape = nullptr);\n\tvoid AddSkinning(AnimInfo* anim, nifly::NiShape* shape = nullptr);\n\n\tbool ExportScene(const std::string& fileName);\n\tbool ImportScene(const std::string& fileName, const FBXImportOptions& options = FBXImportOptions());\n};\n\n#endif\n"
  },
  {
    "path": "src/files/HkxFile.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n\nNative reader for Havok HKX packfile skeletons and spline-compressed\nanimations. See HkxFile.h for the supported variants.\n\nSpline decompression and the binary layout descriptions are ported from\nPyNifly's anim_fo4.py / anim_skyrim.py (GPLv3) by Bad Dog Skyrim,\nwhich is itself derived from Dagobaking's skyrim-fo4-animation-conversion\nand PredatorCZ/HavokLib (both GPLv3).\n*/\n\n#include \"HkxFile.h\"\n\n#include \"../utils/PlatformUtil.h\"\n\n#include <algorithm>\n#include <array>\n#include <cmath>\n#include <cstring>\n#include <fstream>\n#include <unordered_map>\n#include <vector>\n\nnamespace HKX {\n\nnamespace {\n\n// ─── Little-endian primitive readers ──────────────────────────────────────\n\ninline uint32_t ReadU32(const uint8_t* d) {\n\treturn uint32_t(d[0]) | (uint32_t(d[1]) << 8) | (uint32_t(d[2]) << 16) | (uint32_t(d[3]) << 24);\n}\ninline int32_t ReadI32(const uint8_t* d) { return int32_t(ReadU32(d)); }\ninline uint16_t ReadU16(const uint8_t* d) { return uint16_t(d[0]) | (uint16_t(d[1]) << 8); }\ninline int16_t ReadI16(const uint8_t* d) { return int16_t(ReadU16(d)); }\ninline float ReadF32(const uint8_t* d) {\n\tuint32_t u = ReadU32(d);\n\tfloat f;\n\tstd::memcpy(&f, &u, sizeof(f));\n\treturn f;\n}\n\n// Bounds-checked variants returning false on overrun.\nstruct Buf {\n\tconst uint8_t* data = nullptr;\n\tsize_t size = 0;\n\n\tbool InBounds(size_t off, size_t len) const { return off <= size && len <= size - off; }\n\tbool U32(size_t off, uint32_t& v) const {\n\t\tif (!InBounds(off, 4))\n\t\t\treturn false;\n\t\tv = ReadU32(data + off);\n\t\treturn true;\n\t}\n\tbool I16(size_t off, int16_t& v) const {\n\t\tif (!InBounds(off, 2))\n\t\t\treturn false;\n\t\tv = ReadI16(data + off);\n\t\treturn true;\n\t}\n\tbool F32(size_t off, float& v) const {\n\t\tif (!InBounds(off, 4))\n\t\t\treturn false;\n\t\tv = ReadF32(data + off);\n\t\treturn true;\n\t}\n\tbool U8(size_t off, uint8_t& v) const {\n\t\tif (!InBounds(off, 1))\n\t\t\treturn false;\n\t\tv = data[off];\n\t\treturn true;\n\t}\n};\n\nbool ReadAllFile(const std::string& path, std::vector<uint8_t>& out) {\n#ifdef _WINDOWS\n\tstd::wstring wpath = PlatformUtil::MultiByteToWideUTF8(path);\n\tstd::ifstream ifs(wpath.c_str(), std::ios::binary);\n#else\n\tstd::ifstream ifs(path.c_str(), std::ios::binary);\n#endif\n\tif (!ifs.is_open())\n\t\treturn false;\n\tifs.seekg(0, std::ios::end);\n\tstd::streampos endPos = ifs.tellg();\n\tif (endPos <= 0) {\n\t\tout.clear();\n\t\treturn false;\n\t}\n\tifs.seekg(0, std::ios::beg);\n\tout.resize(static_cast<size_t>(endPos));\n\tconst std::streamsize bytesToRead = static_cast<std::streamsize>(out.size());\n\tifs.read(reinterpret_cast<char*>(out.data()), bytesToRead);\n\treturn ifs && ifs.gcount() == bytesToRead;\n}\n\n// ─── Fixup tables and section descriptors ─────────────────────────────────\n\nstruct Section {\n\tstd::string name;\n\tuint32_t absStart = 0;        // absolute file offset of section data\n\tuint32_t localFixupAbs = 0;   // absolute offsets to fixup-table starts\n\tuint32_t globalFixupAbs = 0;\n\tuint32_t virtualFixupAbs = 0;\n\tuint32_t exportsAbs = 0;\n\tuint32_t endAbs = 0;\n};\n\nstruct VirtualObject {\n\tuint32_t relOffset; // relative to data section start\n\tstd::string className;\n};\n\n// Extract the file format from the 0x40-byte file header (magic already\n// validated by caller).\nFormat DetectFormat(const Buf& buf) {\n\tif (buf.size < 0x38)\n\t\treturn Format::Unknown;\n\tuint32_t version = ReadU32(buf.data + 0x0C);\n\tuint8_t ptrSize = buf.data[0x10]; // 4 or 8\n\tif (version == 11 && ptrSize == 8)\n\t\treturn Format::Fallout64;\n\tif (version == 8 && ptrSize == 8)\n\t\treturn Format::Skyrim64;\n\tif (version == 8 && ptrSize == 4)\n\t\treturn Format::Skyrim32;\n\treturn Format::Unknown;\n}\n\n// Parse the three packfile sections (__classnames__, __types__, __data__).\n// FO4 (v11) has a 16-byte padding block before the section headers and uses\n// 0x40-byte section headers; Skyrim (v8) uses 0x30-byte section headers and\n// no padding.\nbool ParseSections(const Buf& buf, Format fmt, Section out[3]) {\n\tconst size_t hdrStart = 0x40;\n\tconst size_t hdrSize = (fmt == Format::Fallout64) ? 0x40 : 0x30;\n\tconst size_t firstSection = (fmt == Format::Fallout64) ? 0x50 : 0x40;\n\n\t(void)hdrStart;\n\tif (!buf.InBounds(firstSection, hdrSize * 3))\n\t\treturn false;\n\n\tfor (int i = 0; i < 3; ++i) {\n\t\tconst uint8_t* h = buf.data + firstSection + i * hdrSize;\n\t\tconst char* nameStart = reinterpret_cast<const char*>(h);\n\t\tconst void* nameEnd = std::memchr(nameStart, '\\0', 16);\n\t\tconst size_t nameLen = nameEnd ? static_cast<const char*>(nameEnd) - nameStart : 16;\n\t\tout[i].name.assign(nameStart, nameLen);\n\t\tuint32_t s = ReadU32(h + 0x14);\n\t\tout[i].absStart = s;\n\t\tout[i].localFixupAbs = s + ReadU32(h + 0x18);\n\t\tout[i].globalFixupAbs = s + ReadU32(h + 0x1C);\n\t\tout[i].virtualFixupAbs = s + ReadU32(h + 0x20);\n\t\tout[i].exportsAbs = s + ReadU32(h + 0x24);\n\t\tout[i].endAbs = s + ReadU32(h + 0x2C);\n\t\tif (out[i].endAbs > buf.size)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\nconst Section* FindSection(const Section sec[3], const char* name) {\n\tfor (int i = 0; i < 3; ++i)\n\t\tif (sec[i].name == name)\n\t\t\treturn &sec[i];\n\treturn nullptr;\n}\n\nbool ParseLocalFixups(const Buf& buf, const Section& dataSec, std::unordered_map<uint32_t, uint32_t>& out) {\n\tuint32_t pos = dataSec.localFixupAbs;\n\tuint32_t end = dataSec.globalFixupAbs;\n\tif (end > buf.size)\n\t\treturn false;\n\twhile (pos + 8 <= end) {\n\t\tuint32_t src = ReadU32(buf.data + pos);\n\t\tuint32_t dst = ReadU32(buf.data + pos + 4);\n\t\tif (src == 0xFFFFFFFFu)\n\t\t\tbreak;\n\t\tout[src] = dst;\n\t\tpos += 8;\n\t}\n\treturn true;\n}\n\nbool ParseVirtualFixups(const Buf& buf, const Section& dataSec, uint32_t cnStart, std::vector<VirtualObject>& out) {\n\tuint32_t pos = dataSec.virtualFixupAbs;\n\tuint32_t end = dataSec.exportsAbs;\n\tif (end > buf.size)\n\t\treturn false;\n\twhile (pos + 12 <= end) {\n\t\tuint32_t src = ReadU32(buf.data + pos);\n\t\t// section index at +4 unused\n\t\tuint32_t nameOff = ReadU32(buf.data + pos + 8);\n\t\tif (src == 0xFFFFFFFFu)\n\t\t\tbreak;\n\t\tuint32_t absName = cnStart + nameOff;\n\t\tstd::string cls;\n\t\t// Class names live in the classnames section as null-terminated\n\t\t// ASCII; cap the search to keep us bounded.\n\t\tif (absName < buf.size) {\n\t\t\tsize_t scanEnd = std::min<size_t>(buf.size, absName + 256);\n\t\t\tsize_t p = absName;\n\t\t\twhile (p < scanEnd && buf.data[p] != 0)\n\t\t\t\t++p;\n\t\t\tcls.assign(reinterpret_cast<const char*>(buf.data + absName), p - absName);\n\t\t}\n\t\tout.push_back({src, std::move(cls)});\n\t\tpos += 12;\n\t}\n\treturn true;\n}\n\nstd::string ReadCString(const Buf& buf, size_t absOff) {\n\tif (absOff >= buf.size)\n\t\treturn {};\n\tsize_t scanEnd = std::min<size_t>(buf.size, absOff + 1024);\n\tsize_t p = absOff;\n\twhile (p < scanEnd && buf.data[p] != 0)\n\t\t++p;\n\treturn std::string(reinterpret_cast<const char*>(buf.data + absOff), p - absOff);\n}\n\n// Resolve a pointer field at relative offset relPtrOff in the data section.\n// Returns the relative target offset, or -1 if no fixup exists.\nint64_t ResolveLocal(const std::unordered_map<uint32_t, uint32_t>& fixups, uint32_t relPtrOff) {\n\tauto it = fixups.find(relPtrOff);\n\tif (it == fixups.end())\n\t\treturn -1;\n\treturn it->second;\n}\n\n// Read an hkArray<T>'s element count (which sits at +ptrSize within the\n// hkArray struct) plus its content offset (resolved through local fixups).\nstruct HkArray {\n\tuint32_t count = 0;\n\tint64_t contentRel = -1;\n};\n\nHkArray ReadHkArray(const Buf& buf,\n\t\t\t\t\tuint32_t dataAbs,\n\t\t\t\t\tuint32_t objRel,\n\t\t\t\t\tuint32_t fieldOff,\n\t\t\t\t\tuint32_t ptrSize,\n\t\t\t\t\tconst std::unordered_map<uint32_t, uint32_t>& fixups) {\n\tHkArray a;\n\tuint32_t arrRel = objRel + fieldOff;\n\tuint32_t countAbs = dataAbs + arrRel + ptrSize;\n\tif (countAbs + 4 > buf.size)\n\t\treturn a;\n\ta.count = ReadU32(buf.data + countAbs);\n\ta.contentRel = ResolveLocal(fixups, arrRel);\n\treturn a;\n}\n\ninline uint32_t HkArrayStride(uint32_t ptrSize) { return ptrSize + 8; }\n\n// ─── Quaternion helpers ───────────────────────────────────────────────────\n\nvoid QuatNormalize(float q[4]) {\n\tfloat mag = std::sqrt(q[0] * q[0] + q[1] * q[1] + q[2] * q[2] + q[3] * q[3]);\n\tif (mag < 1e-10f) {\n\t\tq[0] = 0.0f;\n\t\tq[1] = 0.0f;\n\t\tq[2] = 0.0f;\n\t\tq[3] = 1.0f;\n\t\treturn;\n\t}\n\tfloat inv = 1.0f / mag;\n\tq[0] *= inv;\n\tq[1] *= inv;\n\tq[2] *= inv;\n\tq[3] *= inv;\n}\n\n// ─── Spline-compressed scalar/quat decoders ───────────────────────────────\n// Ported from anim_fo4.py.\n\ninline float Read8BitScalar(uint8_t v, float mn, float mx) {\n\treturn mn + (mx - mn) * (float(v) / 255.0f);\n}\ninline float Read16BitScalar(uint16_t v, float mn, float mx) {\n\treturn mn + (mx - mn) * (float(v) / 65535.0f);\n}\n\nbool Read32BitQuat(const uint8_t* d, size_t avail, float out[4]) {\n\tif (avail < 4)\n\t\treturn false;\n\tuint32_t cval = ReadU32(d);\n\tconst uint32_t r_mask = (1u << 10) - 1u;\n\tconst float r_frac = 1.0f / float(r_mask);\n\tfloat R = float((cval >> 18) & r_mask) * r_frac;\n\tR = 1.0f - R * R;\n\tfloat phi_theta = float(cval & 0x3FFFFu);\n\tfloat phi = std::floor(std::sqrt(phi_theta));\n\tfloat theta = 0.0f;\n\tif (phi > 0.0f) {\n\t\ttheta = (3.14159265358979323846f / 4.0f) * (phi_theta - phi * phi) / phi;\n\t\tphi = (3.14159265358979323846f / 2.0f / 511.0f) * phi;\n\t}\n\tfloat magnitude = std::sqrt(std::max(0.0f, 1.0f - R * R));\n\tfloat sp = std::sin(phi), cp = std::cos(phi);\n\tfloat st = std::sin(theta), ct = std::cos(theta);\n\tout[0] = sp * ct * magnitude;\n\tout[1] = sp * st * magnitude;\n\tout[2] = cp * magnitude;\n\tout[3] = R;\n\tconst uint32_t signMasks[4] = {0x10000000u, 0x20000000u, 0x40000000u, 0x80000000u};\n\tfor (int i = 0; i < 4; ++i)\n\t\tif (cval & signMasks[i])\n\t\t\tout[i] = -out[i];\n\tQuatNormalize(out);\n\treturn true;\n}\n\nbool Read40BitQuat(const uint8_t* d, size_t avail, float out[4]) {\n\tif (avail < 5)\n\t\treturn false;\n\tconst float FRACTAL = 0.000345436f;\n\tuint64_t raw = 0;\n\tfor (int i = 0; i < 5; ++i)\n\t\traw |= uint64_t(d[i]) << (i * 8);\n\tuint32_t a = uint32_t(raw & 0xFFF);\n\tuint32_t b = uint32_t((raw >> 12) & 0xFFF);\n\tuint32_t c = uint32_t((raw >> 24) & 0xFFF);\n\tfloat vals[3] = {(float(a) - 2049.0f) * FRACTAL, (float(b) - 2049.0f) * FRACTAL, (float(c) - 2049.0f) * FRACTAL};\n\tfloat sumSq = vals[0] * vals[0] + vals[1] * vals[1] + vals[2] * vals[2];\n\tfloat w = std::sqrt(std::max(0.0f, 1.0f - sumSq));\n\tif ((raw >> 38) & 1)\n\t\tw = -w;\n\tuint32_t shift = uint32_t((raw >> 36) & 3);\n\tswitch (shift) {\n\t\tcase 0:\n\t\t\tout[0] = w;\n\t\t\tout[1] = vals[0];\n\t\t\tout[2] = vals[1];\n\t\t\tout[3] = vals[2];\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tout[0] = vals[0];\n\t\t\tout[1] = w;\n\t\t\tout[2] = vals[1];\n\t\t\tout[3] = vals[2];\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tout[0] = vals[0];\n\t\t\tout[1] = vals[1];\n\t\t\tout[2] = w;\n\t\t\tout[3] = vals[2];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tout[0] = vals[0];\n\t\t\tout[1] = vals[1];\n\t\t\tout[2] = vals[2];\n\t\t\tout[3] = w;\n\t\t\tbreak;\n\t}\n\tQuatNormalize(out);\n\treturn true;\n}\n\nbool Read48BitQuat(const uint8_t* d, size_t avail, float out[4]) {\n\tif (avail < 6)\n\t\treturn false;\n\tconst float FRACTAL = 0.000043161f;\n\tconst uint32_t MASK = (1u << 15) - 1u;\n\tconst uint32_t HALF = MASK >> 1;\n\tuint16_t xRaw = ReadU16(d);\n\tuint16_t yRaw = ReadU16(d + 2);\n\tuint16_t zRaw = ReadU16(d + 4);\n\tuint32_t shift = ((uint32_t(yRaw) >> 14) & 2u) | ((uint32_t(xRaw) >> 15) & 1u);\n\tbool rSign = (zRaw >> 15) != 0;\n\tfloat vals[3] = {(float(xRaw & MASK) - float(HALF)) * FRACTAL,\n\t\t\t\t\t (float(yRaw & MASK) - float(HALF)) * FRACTAL,\n\t\t\t\t\t (float(zRaw & MASK) - float(HALF)) * FRACTAL};\n\tfloat sumSq = vals[0] * vals[0] + vals[1] * vals[1] + vals[2] * vals[2];\n\tfloat w = std::sqrt(std::max(0.0f, 1.0f - sumSq));\n\tif (rSign)\n\t\tw = -w;\n\tswitch (shift) {\n\t\tcase 0:\n\t\t\tout[0] = w;\n\t\t\tout[1] = vals[0];\n\t\t\tout[2] = vals[1];\n\t\t\tout[3] = vals[2];\n\t\t\tbreak;\n\t\tcase 1:\n\t\t\tout[0] = vals[0];\n\t\t\tout[1] = w;\n\t\t\tout[2] = vals[1];\n\t\t\tout[3] = vals[2];\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tout[0] = vals[0];\n\t\t\tout[1] = vals[1];\n\t\t\tout[2] = w;\n\t\t\tout[3] = vals[2];\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tout[0] = vals[0];\n\t\t\tout[1] = vals[1];\n\t\t\tout[2] = vals[2];\n\t\t\tout[3] = w;\n\t\t\tbreak;\n\t}\n\tQuatNormalize(out);\n\treturn true;\n}\n\nbool ReadUncompressedQuat(const uint8_t* d, size_t avail, float out[4]) {\n\tif (avail < 16)\n\t\treturn false;\n\tout[0] = ReadF32(d);\n\tout[1] = ReadF32(d + 4);\n\tout[2] = ReadF32(d + 8);\n\tout[3] = ReadF32(d + 12);\n\tQuatNormalize(out);\n\treturn true;\n}\n\nbool ReadQuat(uint32_t fmt, const uint8_t* d, size_t avail, float out[4], uint32_t& consumed) {\n\tswitch (fmt) {\n\t\tcase 0:\n\t\t\tconsumed = 4;\n\t\t\treturn Read32BitQuat(d, avail, out);\n\t\tcase 1:\n\t\t\tconsumed = 5;\n\t\t\treturn Read40BitQuat(d, avail, out);\n\t\tcase 2:\n\t\t\tconsumed = 6;\n\t\t\treturn Read48BitQuat(d, avail, out);\n\t\tcase 5:\n\t\t\tconsumed = 16;\n\t\t\treturn ReadUncompressedQuat(d, avail, out);\n\t\tdefault:\n\t\t\t// Fallback to 40-bit (matches PyNifly behavior).\n\t\t\tconsumed = 5;\n\t\t\treturn Read40BitQuat(d, avail, out);\n\t}\n}\n\nuint32_t QuatAlign(uint32_t fmt) {\n\tswitch (fmt) {\n\t\tcase 0: return 4;\n\t\tcase 1: return 1;\n\t\tcase 2: return 2;\n\t\tcase 3: return 1;\n\t\tcase 4: return 2;\n\t\tcase 5: return 4;\n\t\tdefault: return 1;\n\t}\n}\n\ninline uint32_t Align(uint32_t off, uint32_t alignment) {\n\tuint32_t r = off % alignment;\n\treturn r ? off + (alignment - r) : off;\n}\n\n// ─── B-spline evaluation (De Boor) ────────────────────────────────────────\n\nuint32_t FindKnotSpan(uint32_t degree, float value, uint32_t numCp, const std::vector<float>& knots) {\n\tif (numCp == 0)\n\t\treturn 0;\n\tif (value >= knots[numCp])\n\t\treturn numCp - 1;\n\tuint32_t low = degree;\n\tuint32_t high = numCp;\n\tuint32_t mid = (low + high) / 2;\n\tfor (int it = 0; it < 100; ++it) {\n\t\tif (value < knots[mid])\n\t\t\thigh = mid;\n\t\telse if (value >= knots[mid + 1])\n\t\t\tlow = mid;\n\t\telse\n\t\t\tbreak;\n\t\tmid = (low + high) / 2;\n\t}\n\treturn mid;\n}\n\n// Evaluate B-spline scalar.\nfloat EvalBSplineScalar(uint32_t knotSpan, uint32_t degree, float t, const std::vector<float>& knots, const std::vector<float>& cps) {\n\tif (cps.empty())\n\t\treturn 0.0f;\n\tif (cps.size() == 1)\n\t\treturn cps[0];\n\tstd::vector<float> N(degree + 1, 0.0f);\n\tN[0] = 1.0f;\n\tfor (uint32_t i = 1; i <= degree; ++i) {\n\t\tfor (int j = int(i) - 1; j >= 0; --j) {\n\t\t\tfloat denom = knots[knotSpan + i - j] - knots[knotSpan - j];\n\t\t\tfloat A = (denom >= 1e-10f) ? (t - knots[knotSpan - j]) / denom : 0.0f;\n\t\t\tfloat tmp = N[j] * A;\n\t\t\tif (uint32_t(j) + 1 < N.size())\n\t\t\t\tN[j + 1] += N[j] - tmp;\n\t\t\tN[j] = tmp;\n\t\t}\n\t}\n\tfloat result = 0.0f;\n\tfor (uint32_t i = 0; i <= degree; ++i) {\n\t\tint idx = int(knotSpan) - int(i);\n\t\tif (idx >= 0 && idx < int(cps.size()))\n\t\t\tresult += cps[idx] * N[i];\n\t}\n\treturn result;\n}\n\n// Evaluate B-spline 4-vector (quaternion).\nvoid EvalBSplineQuat(uint32_t knotSpan,\n\t\t\t\t\t uint32_t degree,\n\t\t\t\t\t float t,\n\t\t\t\t\t const std::vector<float>& knots,\n\t\t\t\t\t const std::vector<std::array<float, 4>>& cps,\n\t\t\t\t\t float out[4]) {\n\tout[0] = out[1] = out[2] = 0.0f;\n\tout[3] = 1.0f;\n\tif (cps.empty())\n\t\treturn;\n\tif (cps.size() == 1) {\n\t\tout[0] = cps[0][0];\n\t\tout[1] = cps[0][1];\n\t\tout[2] = cps[0][2];\n\t\tout[3] = cps[0][3];\n\t\treturn;\n\t}\n\tstd::vector<float> N(degree + 1, 0.0f);\n\tN[0] = 1.0f;\n\tfor (uint32_t i = 1; i <= degree; ++i) {\n\t\tfor (int j = int(i) - 1; j >= 0; --j) {\n\t\t\tfloat denom = knots[knotSpan + i - j] - knots[knotSpan - j];\n\t\t\tfloat A = (denom >= 1e-10f) ? (t - knots[knotSpan - j]) / denom : 0.0f;\n\t\t\tfloat tmp = N[j] * A;\n\t\t\tif (uint32_t(j) + 1 < N.size())\n\t\t\t\tN[j + 1] += N[j] - tmp;\n\t\t\tN[j] = tmp;\n\t\t}\n\t}\n\tfloat r[4] = {0.0f, 0.0f, 0.0f, 0.0f};\n\tfor (uint32_t i = 0; i <= degree; ++i) {\n\t\tint idx = int(knotSpan) - int(i);\n\t\tif (idx >= 0 && idx < int(cps.size())) {\n\t\t\tr[0] += cps[idx][0] * N[i];\n\t\t\tr[1] += cps[idx][1] * N[i];\n\t\t\tr[2] += cps[idx][2] * N[i];\n\t\t\tr[3] += cps[idx][3] * N[i];\n\t\t}\n\t}\n\tout[0] = r[0];\n\tout[1] = r[1];\n\tout[2] = r[2];\n\tout[3] = r[3];\n}\n\n// ─── Track mask interpretation ────────────────────────────────────────────\n\nstruct TrackMask {\n\tuint8_t posQuant;   // 0 = 8-bit, 1 = 16-bit\n\tuint8_t rotQuant;   // quaternion format index (0,1,2,5...)\n\tuint8_t scaleQuant; // 0 = 8-bit, 1 = 16-bit\n\tuint8_t posFlags;\n\tuint8_t rotFlags;\n\tuint8_t scaleFlags;\n\tenum Type { Identity, Static, Spline };\n\n\tType PosType(int axis) const {\n\t\tif ((posFlags >> (axis + 4)) & 1)\n\t\t\treturn Spline;\n\t\tif ((posFlags >> axis) & 1)\n\t\t\treturn Static;\n\t\treturn Identity;\n\t}\n\tType ScaleType(int axis) const {\n\t\tif ((scaleFlags >> (axis + 4)) & 1)\n\t\t\treturn Spline;\n\t\tif ((scaleFlags >> axis) & 1)\n\t\t\treturn Static;\n\t\treturn Identity;\n\t}\n\tType RotType() const {\n\t\tif ((rotFlags >> 4) & 0x0F)\n\t\t\treturn Spline;\n\t\tif (rotFlags & 0x0F)\n\t\t\treturn Static;\n\t\treturn Identity;\n\t}\n\tbool HasAnyPosSpline() const { return PosType(0) == Spline || PosType(1) == Spline || PosType(2) == Spline; }\n\tbool HasAnyScaleSpline() const { return ScaleType(0) == Spline || ScaleType(1) == Spline || ScaleType(2) == Spline; }\n};\n\n// ─── Spline decompression (block-by-block) ────────────────────────────────\n\nbool DecompressSpline(const uint8_t* blob,\n\t\t\t\t\t  size_t blobSize,\n\t\t\t\t\t  uint32_t numTracks,\n\t\t\t\t\t  uint32_t numFrames,\n\t\t\t\t\t  uint32_t numBlocks,\n\t\t\t\t\t  uint32_t maxFramesPerBlock,\n\t\t\t\t\t  const std::vector<uint32_t>& blockOffsets,\n\t\t\t\t\t  uint32_t maskAndQuantSize,\n\t\t\t\t\t  std::vector<Transform>& out) {\n\tout.assign(size_t(numFrames) * numTracks, Transform{});\n\tif (numTracks == 0 || numFrames == 0 || numBlocks == 0)\n\t\treturn true;\n\tif (blockOffsets.size() < numBlocks)\n\t\treturn false;\n\tif (maskAndQuantSize == 0)\n\t\tmaskAndQuantSize = Align(4u * numTracks, 4u);\n\n\tstd::vector<TrackMask> masks(numTracks);\n\tstd::vector<float> knots;\n\tstd::vector<float> scalarCps[3];\n\tstd::vector<std::array<float, 4>> quatCps;\n\n\tauto ensureBytes = [&](uint32_t off, uint32_t need) -> bool { return uint64_t(off) + need <= blobSize; };\n\n\tfor (uint32_t blockIdx = 0; blockIdx < numBlocks; ++blockIdx) {\n\t\tuint32_t blockStart = blockOffsets[blockIdx];\n\t\tuint32_t firstFrame = blockIdx * maxFramesPerBlock;\n\t\tuint32_t framesInBlock = (blockIdx == numBlocks - 1) ? (numFrames - firstFrame) : maxFramesPerBlock;\n\n\t\t// Parse masks (4 bytes per track).\n\t\tuint32_t off = blockStart;\n\t\tif (!ensureBytes(off, 4u * numTracks))\n\t\t\treturn false;\n\t\tfor (uint32_t t = 0; t < numTracks; ++t) {\n\t\t\tmasks[t].posQuant = blob[off] & 0x03;\n\t\t\tmasks[t].rotQuant = (blob[off] >> 2) & 0x0F;\n\t\t\tmasks[t].scaleQuant = (blob[off] >> 6) & 0x03;\n\t\t\tmasks[t].posFlags = blob[off + 1];\n\t\t\tmasks[t].rotFlags = blob[off + 2];\n\t\t\tmasks[t].scaleFlags = blob[off + 3];\n\t\t\toff += 4;\n\t\t}\n\t\toff = blockStart + maskAndQuantSize;\n\n\t\tfor (uint32_t trackIdx = 0; trackIdx < numTracks; ++trackIdx) {\n\t\t\tconst TrackMask& m = masks[trackIdx];\n\n\t\t\t// ─── POSITION ───\n\t\t\tstd::vector<std::array<float, 3>> posFrames(framesInBlock, {0.0f, 0.0f, 0.0f});\n\t\t\tif (m.HasAnyPosSpline()) {\n\t\t\t\tif (!ensureBytes(off, 3))\n\t\t\t\t\treturn false;\n\t\t\t\tuint32_t numItems = ReadU16(blob + off);\n\t\t\t\tuint32_t degree = blob[off + 2];\n\t\t\t\toff += 3;\n\t\t\t\tuint32_t numKnots = numItems + degree + 2;\n\t\t\t\tif (!ensureBytes(off, numKnots))\n\t\t\t\t\treturn false;\n\t\t\t\tknots.assign(numKnots, 0.0f);\n\t\t\t\tfor (uint32_t k = 0; k < numKnots; ++k)\n\t\t\t\t\tknots[k] = float(blob[off + k]);\n\t\t\t\toff += numKnots;\n\t\t\t\toff = Align(off, 4);\n\n\t\t\t\tstruct AxisInfo {\n\t\t\t\t\tTrackMask::Type type;\n\t\t\t\t\tfloat mn, mx;\n\t\t\t\t};\n\t\t\t\tAxisInfo info[3];\n\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\tTrackMask::Type t = m.PosType(axis);\n\t\t\t\t\tif (t == TrackMask::Spline) {\n\t\t\t\t\t\tif (!ensureBytes(off, 8))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\tinfo[axis] = {t, ReadF32(blob + off), ReadF32(blob + off + 4)};\n\t\t\t\t\t\toff += 8;\n\t\t\t\t\t}\n\t\t\t\t\telse if (t == TrackMask::Static) {\n\t\t\t\t\t\tif (!ensureBytes(off, 4))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\tfloat v = ReadF32(blob + off);\n\t\t\t\t\t\tinfo[axis] = {t, v, v};\n\t\t\t\t\t\toff += 4;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tinfo[axis] = {t, 0.0f, 0.0f};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (int axis = 0; axis < 3; ++axis)\n\t\t\t\t\tscalarCps[axis].clear();\n\t\t\t\tfor (uint32_t i = 0; i < numItems + 1; ++i) {\n\t\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\t\tif (info[axis].type == TrackMask::Spline) {\n\t\t\t\t\t\t\tif (m.posQuant == 0) {\n\t\t\t\t\t\t\t\tif (!ensureBytes(off, 1))\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\tscalarCps[axis].push_back(Read8BitScalar(blob[off], info[axis].mn, info[axis].mx));\n\t\t\t\t\t\t\t\toff += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tif (!ensureBytes(off, 2))\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\tscalarCps[axis].push_back(Read16BitScalar(ReadU16(blob + off), info[axis].mn, info[axis].mx));\n\t\t\t\t\t\t\t\toff += 2;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toff = Align(off, 4);\n\n\t\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f) {\n\t\t\t\t\tfloat ft = float(f);\n\t\t\t\t\tfloat pos[3] = {0.0f, 0.0f, 0.0f};\n\t\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\t\tif (info[axis].type == TrackMask::Spline) {\n\t\t\t\t\t\t\tuint32_t span = FindKnotSpan(degree, ft, uint32_t(scalarCps[axis].size()), knots);\n\t\t\t\t\t\t\tpos[axis] = EvalBSplineScalar(span, degree, ft, knots, scalarCps[axis]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (info[axis].type == TrackMask::Static) {\n\t\t\t\t\t\t\tpos[axis] = info[axis].mn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tposFrames[f] = {pos[0], pos[1], pos[2]};\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfloat pos[3] = {0.0f, 0.0f, 0.0f};\n\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\tif (m.PosType(axis) == TrackMask::Static) {\n\t\t\t\t\t\tif (!ensureBytes(off, 4))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\tpos[axis] = ReadF32(blob + off);\n\t\t\t\t\t\toff += 4;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f)\n\t\t\t\t\tposFrames[f] = {pos[0], pos[1], pos[2]};\n\t\t\t}\n\t\t\toff = Align(off, 4);\n\n\t\t\t// ─── ROTATION ───\n\t\t\tstd::vector<std::array<float, 4>> rotFrames(framesInBlock, {0.0f, 0.0f, 0.0f, 1.0f});\n\t\t\tTrackMask::Type rotType = m.RotType();\n\t\t\tuint32_t qfmt = m.rotQuant;\n\t\t\tuint32_t qalign = QuatAlign(qfmt);\n\n\t\t\tif (rotType == TrackMask::Spline) {\n\t\t\t\tif (!ensureBytes(off, 3))\n\t\t\t\t\treturn false;\n\t\t\t\tuint32_t numItems = ReadU16(blob + off);\n\t\t\t\tuint32_t degree = blob[off + 2];\n\t\t\t\toff += 3;\n\t\t\t\tuint32_t numKnots = numItems + degree + 2;\n\t\t\t\tif (!ensureBytes(off, numKnots))\n\t\t\t\t\treturn false;\n\t\t\t\tknots.assign(numKnots, 0.0f);\n\t\t\t\tfor (uint32_t k = 0; k < numKnots; ++k)\n\t\t\t\t\tknots[k] = float(blob[off + k]);\n\t\t\t\toff += numKnots;\n\t\t\t\tif (qalign > 1)\n\t\t\t\t\toff = Align(off, qalign);\n\n\t\t\t\tquatCps.clear();\n\t\t\t\tfor (uint32_t i = 0; i < numItems + 1; ++i) {\n\t\t\t\t\tfloat q[4];\n\t\t\t\t\tuint32_t consumed = 0;\n\t\t\t\t\tif (!ReadQuat(qfmt, blob + off, blobSize - off, q, consumed))\n\t\t\t\t\t\treturn false;\n\t\t\t\t\toff += consumed;\n\t\t\t\t\tif (!quatCps.empty()) {\n\t\t\t\t\t\tconst auto& prev = quatCps.back();\n\t\t\t\t\t\tfloat dot = q[0] * prev[0] + q[1] * prev[1] + q[2] * prev[2] + q[3] * prev[3];\n\t\t\t\t\t\tif (dot < 0.0f) {\n\t\t\t\t\t\t\tq[0] = -q[0];\n\t\t\t\t\t\t\tq[1] = -q[1];\n\t\t\t\t\t\t\tq[2] = -q[2];\n\t\t\t\t\t\t\tq[3] = -q[3];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tquatCps.push_back({q[0], q[1], q[2], q[3]});\n\t\t\t\t}\n\t\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f) {\n\t\t\t\t\tfloat ft = float(f);\n\t\t\t\t\tuint32_t span = FindKnotSpan(degree, ft, uint32_t(quatCps.size()), knots);\n\t\t\t\t\tfloat q[4];\n\t\t\t\t\tEvalBSplineQuat(span, degree, ft, knots, quatCps, q);\n\t\t\t\t\tQuatNormalize(q);\n\t\t\t\t\trotFrames[f] = {q[0], q[1], q[2], q[3]};\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (rotType == TrackMask::Static) {\n\t\t\t\tif (qalign > 1)\n\t\t\t\t\toff = Align(off, qalign);\n\t\t\t\tfloat q[4];\n\t\t\t\tuint32_t consumed = 0;\n\t\t\t\tif (!ReadQuat(qfmt, blob + off, blobSize - off, q, consumed))\n\t\t\t\t\treturn false;\n\t\t\t\toff += consumed;\n\t\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f)\n\t\t\t\t\trotFrames[f] = {q[0], q[1], q[2], q[3]};\n\t\t\t}\n\t\t\toff = Align(off, 4);\n\n\t\t\t// ─── SCALE ───\n\t\t\tstd::vector<std::array<float, 3>> scaleFrames(framesInBlock, {1.0f, 1.0f, 1.0f});\n\t\t\tif (m.HasAnyScaleSpline()) {\n\t\t\t\tif (!ensureBytes(off, 3))\n\t\t\t\t\treturn false;\n\t\t\t\tuint32_t numItems = ReadU16(blob + off);\n\t\t\t\tuint32_t degree = blob[off + 2];\n\t\t\t\toff += 3;\n\t\t\t\tuint32_t numKnots = numItems + degree + 2;\n\t\t\t\tif (!ensureBytes(off, numKnots))\n\t\t\t\t\treturn false;\n\t\t\t\tknots.assign(numKnots, 0.0f);\n\t\t\t\tfor (uint32_t k = 0; k < numKnots; ++k)\n\t\t\t\t\tknots[k] = float(blob[off + k]);\n\t\t\t\toff += numKnots;\n\t\t\t\toff = Align(off, 4);\n\n\t\t\t\tstruct AxisInfo {\n\t\t\t\t\tTrackMask::Type type;\n\t\t\t\t\tfloat mn, mx;\n\t\t\t\t};\n\t\t\t\tAxisInfo info[3];\n\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\tTrackMask::Type t = m.ScaleType(axis);\n\t\t\t\t\tif (t == TrackMask::Spline) {\n\t\t\t\t\t\tif (!ensureBytes(off, 8))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\tinfo[axis] = {t, ReadF32(blob + off), ReadF32(blob + off + 4)};\n\t\t\t\t\t\toff += 8;\n\t\t\t\t\t}\n\t\t\t\t\telse if (t == TrackMask::Static) {\n\t\t\t\t\t\tif (!ensureBytes(off, 4))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\tfloat v = ReadF32(blob + off);\n\t\t\t\t\t\tinfo[axis] = {t, v, v};\n\t\t\t\t\t\toff += 4;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tinfo[axis] = {t, 1.0f, 1.0f};\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (int axis = 0; axis < 3; ++axis)\n\t\t\t\t\tscalarCps[axis].clear();\n\t\t\t\tfor (uint32_t i = 0; i < numItems + 1; ++i) {\n\t\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\t\tif (info[axis].type == TrackMask::Spline) {\n\t\t\t\t\t\t\tif (m.scaleQuant == 0) {\n\t\t\t\t\t\t\t\tif (!ensureBytes(off, 1))\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\tscalarCps[axis].push_back(Read8BitScalar(blob[off], info[axis].mn, info[axis].mx));\n\t\t\t\t\t\t\t\toff += 1;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tif (!ensureBytes(off, 2))\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\tscalarCps[axis].push_back(Read16BitScalar(ReadU16(blob + off), info[axis].mn, info[axis].mx));\n\t\t\t\t\t\t\t\toff += 2;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\toff = Align(off, 4);\n\n\t\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f) {\n\t\t\t\t\tfloat ft = float(f);\n\t\t\t\t\tfloat s[3] = {1.0f, 1.0f, 1.0f};\n\t\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\t\tif (info[axis].type == TrackMask::Spline) {\n\t\t\t\t\t\t\tuint32_t span = FindKnotSpan(degree, ft, uint32_t(scalarCps[axis].size()), knots);\n\t\t\t\t\t\t\ts[axis] = EvalBSplineScalar(span, degree, ft, knots, scalarCps[axis]);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (info[axis].type == TrackMask::Static) {\n\t\t\t\t\t\t\ts[axis] = info[axis].mn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tscaleFrames[f] = {s[0], s[1], s[2]};\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfloat s[3] = {1.0f, 1.0f, 1.0f};\n\t\t\t\tfor (int axis = 0; axis < 3; ++axis) {\n\t\t\t\t\tif (m.ScaleType(axis) == TrackMask::Static) {\n\t\t\t\t\t\tif (!ensureBytes(off, 4))\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\ts[axis] = ReadF32(blob + off);\n\t\t\t\t\t\toff += 4;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f)\n\t\t\t\t\tscaleFrames[f] = {s[0], s[1], s[2]};\n\t\t\t}\n\t\t\toff = Align(off, 4);\n\n\t\t\t// Write into the global output array.\n\t\t\tfor (uint32_t f = 0; f < framesInBlock; ++f) {\n\t\t\t\tTransform& dst = out[size_t(firstFrame + f) * numTracks + trackIdx];\n\t\t\t\tdst.translation[0] = posFrames[f][0];\n\t\t\t\tdst.translation[1] = posFrames[f][1];\n\t\t\t\tdst.translation[2] = posFrames[f][2];\n\t\t\t\tdst.rotation[0] = rotFrames[f][0];\n\t\t\t\tdst.rotation[1] = rotFrames[f][1];\n\t\t\t\tdst.rotation[2] = rotFrames[f][2];\n\t\t\t\tdst.rotation[3] = rotFrames[f][3];\n\t\t\t\tdst.scale[0] = scaleFrames[f][0];\n\t\t\t\tdst.scale[1] = scaleFrames[f][1];\n\t\t\t\tdst.scale[2] = scaleFrames[f][2];\n\t\t\t}\n\t\t}\n\t}\n\treturn true;\n}\n\n// ─── Object parsing ───────────────────────────────────────────────────────\n\nbool ParseSkeleton(const Buf& buf,\n\t\t\t\t   uint32_t dataAbs,\n\t\t\t\t   uint32_t skelRel,\n\t\t\t\t   uint32_t ptrSize,\n\t\t\t\t   Format fmt,\n\t\t\t\t   const std::unordered_map<uint32_t, uint32_t>& fixups,\n\t\t\t\t   Skeleton& outSkel) {\n\tconst uint32_t baseSize = 2u * ptrSize;\n\tconst uint32_t arrSize = HkArrayStride(ptrSize);\n\n\tconst uint32_t nameOff = baseSize;\n\tconst uint32_t piOff = nameOff + ptrSize;\n\tconst uint32_t bonesOff = piOff + arrSize;\n\tconst uint32_t poseOff = bonesOff + arrSize;\n\n\tint64_t nameTarget = ResolveLocal(fixups, skelRel + nameOff);\n\tif (nameTarget >= 0)\n\t\toutSkel.name = ReadCString(buf, dataAbs + uint32_t(nameTarget));\n\n\tauto pi = ReadHkArray(buf, dataAbs, skelRel, piOff, ptrSize, fixups);\n\tstd::vector<int16_t> parents;\n\tif (pi.contentRel >= 0 && pi.count > 0) {\n\t\tuint32_t piAbs = dataAbs + uint32_t(pi.contentRel);\n\t\tif (!buf.InBounds(piAbs, size_t(pi.count) * 2))\n\t\t\treturn false;\n\t\tparents.resize(pi.count);\n\t\tfor (uint32_t i = 0; i < pi.count; ++i)\n\t\t\tparents[i] = ReadI16(buf.data + piAbs + i * 2);\n\t}\n\n\tauto bones = ReadHkArray(buf, dataAbs, skelRel, bonesOff, ptrSize, fixups);\n\tuint32_t boneStride = (ptrSize == 8) ? 16u : (ptrSize + 4u);\n\t(void)fmt;\n\tif (bones.contentRel >= 0 && bones.count > 0) {\n\t\tuint32_t boneContentAbs = dataAbs + uint32_t(bones.contentRel);\n\t\tif (!buf.InBounds(boneContentAbs, size_t(bones.count) * boneStride))\n\t\t\treturn false;\n\t\toutSkel.bones.resize(bones.count);\n\t\tfor (uint32_t i = 0; i < bones.count; ++i) {\n\t\t\tuint32_t boneRel = uint32_t(bones.contentRel) + i * boneStride;\n\t\t\tBone& b = outSkel.bones[i];\n\t\t\tint64_t strRel = ResolveLocal(fixups, boneRel);\n\t\t\tif (strRel >= 0)\n\t\t\t\tb.name = ReadCString(buf, dataAbs + uint32_t(strRel));\n\t\t\tb.lockTranslation = (buf.data[dataAbs + boneRel + ptrSize] != 0);\n\t\t\tb.parentIndex = (i < parents.size()) ? parents[i] : -1;\n\t\t}\n\t}\n\n\tauto pose = ReadHkArray(buf, dataAbs, skelRel, poseOff, ptrSize, fixups);\n\tif (pose.contentRel >= 0 && pose.count > 0) {\n\t\tconst uint32_t POSE_STRIDE = 0x30;\n\t\tuint32_t poseContentAbs = dataAbs + uint32_t(pose.contentRel);\n\t\tif (!buf.InBounds(poseContentAbs, size_t(pose.count) * POSE_STRIDE))\n\t\t\treturn false;\n\t\toutSkel.referencePose.resize(pose.count);\n\t\tfor (uint32_t i = 0; i < pose.count; ++i) {\n\t\t\tconst uint8_t* p = buf.data + poseContentAbs + i * POSE_STRIDE;\n\t\t\tTransform& t = outSkel.referencePose[i];\n\t\t\tt.translation[0] = ReadF32(p + 0);\n\t\t\tt.translation[1] = ReadF32(p + 4);\n\t\t\tt.translation[2] = ReadF32(p + 8);\n\t\t\tt.rotation[0] = ReadF32(p + 16);\n\t\t\tt.rotation[1] = ReadF32(p + 20);\n\t\t\tt.rotation[2] = ReadF32(p + 24);\n\t\t\tt.rotation[3] = ReadF32(p + 28);\n\t\t\tt.scale[0] = ReadF32(p + 32);\n\t\t\tt.scale[1] = ReadF32(p + 36);\n\t\t\tt.scale[2] = ReadF32(p + 40);\n\t\t}\n\t}\n\treturn true;\n}\n\nbool ParseAnimation(const Buf& buf,\n\t\t\t\t\tuint32_t dataAbs,\n\t\t\t\t\tuint32_t animRel,\n\t\t\t\t\tuint32_t ptrSize,\n\t\t\t\t\tconst std::unordered_map<uint32_t, uint32_t>& fixups,\n\t\t\t\t\tAnimation& outAnim,\n\t\t\t\t\tstd::string* errorOut) {\n\tconst uint32_t base = 2u * ptrSize;\n\tconst uint32_t arrSize = HkArrayStride(ptrSize);\n\n\t// hkaAnimation members\n\tconst uint32_t oType = base;\n\t(void)oType;\n\tconst uint32_t oDuration = base + 4;\n\tconst uint32_t oNumTracks = base + 8;\n\tconst uint32_t oNumFloatTracks = base + 12;\n\t(void)oNumFloatTracks;\n\tconst uint32_t oExtractedMotion = base + 16;\n\tconst uint32_t oAnnTracks = oExtractedMotion + ptrSize;\n\n\t// hkaSplineCompressedAnimation members\n\tconst uint32_t splineBase = oAnnTracks + arrSize;\n\tconst uint32_t oNumFrames = splineBase;\n\tconst uint32_t oNumBlocks = splineBase + 4;\n\tconst uint32_t oMaxFrames = splineBase + 8;\n\tconst uint32_t oMaskQuant = splineBase + 12;\n\tconst uint32_t oBlockDur = splineBase + 16;\n\t(void)oBlockDur;\n\tconst uint32_t oFrameDur = splineBase + 24;\n\tuint32_t alignedAfter = splineBase + 28;\n\tif (ptrSize > 1)\n\t\talignedAfter = (alignedAfter + ptrSize - 1) & ~(ptrSize - 1);\n\tconst uint32_t oBlockOffsets = alignedAfter;\n\tconst uint32_t oFloatBlockOffsets = oBlockOffsets + arrSize;\n\t(void)oFloatBlockOffsets;\n\tconst uint32_t oTransformOffsets = oFloatBlockOffsets + arrSize;\n\t(void)oTransformOffsets;\n\tconst uint32_t oFloatOffsets = oTransformOffsets + arrSize;\n\t(void)oFloatOffsets;\n\tconst uint32_t oData = oFloatOffsets + arrSize;\n\n\tuint32_t a = dataAbs + animRel;\n\tif (!buf.InBounds(a, oData + arrSize)) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Animation object truncated\";\n\t\treturn false;\n\t}\n\n\toutAnim.duration = ReadF32(buf.data + a + oDuration);\n\toutAnim.numTransformTracks = ReadU32(buf.data + a + oNumTracks);\n\toutAnim.numFrames = ReadU32(buf.data + a + oNumFrames);\n\tuint32_t numBlocks = ReadU32(buf.data + a + oNumBlocks);\n\tuint32_t maxFramesPerBlock = ReadU32(buf.data + a + oMaxFrames);\n\tuint32_t maskAndQuantSize = ReadU32(buf.data + a + oMaskQuant);\n\toutAnim.frameDuration = ReadF32(buf.data + a + oFrameDur);\n\n\t// Block offsets (hkArray<u32>).\n\tstd::vector<uint32_t> blockOffsets;\n\t{\n\t\tauto ar = ReadHkArray(buf, dataAbs, animRel, oBlockOffsets, ptrSize, fixups);\n\t\tif (ar.contentRel >= 0 && ar.count > 0) {\n\t\t\tuint32_t cAbs = dataAbs + uint32_t(ar.contentRel);\n\t\t\tif (!buf.InBounds(cAbs, size_t(ar.count) * 4)) {\n\t\t\t\tif (errorOut)\n\t\t\t\t\t*errorOut = \"Block offsets truncated\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tblockOffsets.resize(ar.count);\n\t\t\tfor (uint32_t i = 0; i < ar.count; ++i)\n\t\t\t\tblockOffsets[i] = ReadU32(buf.data + cAbs + i * 4);\n\t\t}\n\t}\n\n\t// Spline data blob (hkArray<u8>).\n\tconst uint8_t* blob = nullptr;\n\tuint32_t blobSize = 0;\n\t{\n\t\tauto ar = ReadHkArray(buf, dataAbs, animRel, oData, ptrSize, fixups);\n\t\tif (ar.contentRel >= 0 && ar.count > 0) {\n\t\t\tuint32_t cAbs = dataAbs + uint32_t(ar.contentRel);\n\t\t\tif (!buf.InBounds(cAbs, ar.count)) {\n\t\t\t\tif (errorOut)\n\t\t\t\t\t*errorOut = \"Spline blob truncated\";\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tblob = buf.data + cAbs;\n\t\t\tblobSize = ar.count;\n\t\t}\n\t}\n\n\tif (!blob || blockOffsets.empty()) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Animation has no spline data\";\n\t\treturn false;\n\t}\n\n\t// Annotation tracks: per-track names.\n\t{\n\t\tauto ar = ReadHkArray(buf, dataAbs, animRel, oAnnTracks, ptrSize, fixups);\n\t\tif (ar.contentRel >= 0 && ar.count > 0) {\n\t\t\tconst uint32_t annStride = ptrSize + arrSize;\n\t\t\toutAnim.trackNames.assign(ar.count, std::string{});\n\t\t\tfor (uint32_t i = 0; i < ar.count; ++i) {\n\t\t\t\tuint32_t trackRel = uint32_t(ar.contentRel) + i * annStride;\n\t\t\t\tint64_t strRel = ResolveLocal(fixups, trackRel);\n\t\t\t\tif (strRel >= 0)\n\t\t\t\t\toutAnim.trackNames[i] = ReadCString(buf, dataAbs + uint32_t(strRel));\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!DecompressSpline(blob, blobSize, outAnim.numTransformTracks, outAnim.numFrames, numBlocks, maxFramesPerBlock, blockOffsets, maskAndQuantSize, outAnim.trackTransforms)) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Spline decompression failed\";\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nbool ParseAnimationBinding(const Buf& buf,\n\t\t\t\t\t\t   uint32_t dataAbs,\n\t\t\t\t\t\t   uint32_t bindRel,\n\t\t\t\t\t\t   uint32_t ptrSize,\n\t\t\t\t\t\t   const std::unordered_map<uint32_t, uint32_t>& fixups,\n\t\t\t\t\t\t   AnimationBinding& outBind) {\n\tconst uint32_t base = 2u * ptrSize;\n\tconst uint32_t arrSize = HkArrayStride(ptrSize);\n\tconst uint32_t bindNameOff = base;\n\tconst uint32_t bindAnimOff = bindNameOff + ptrSize;\n\t(void)bindAnimOff;\n\tconst uint32_t bindIdxOff = bindAnimOff + ptrSize;\n\n\tint64_t skelNameRel = ResolveLocal(fixups, bindRel + bindNameOff);\n\tif (skelNameRel >= 0)\n\t\toutBind.originalSkeletonName = ReadCString(buf, dataAbs + uint32_t(skelNameRel));\n\n\tauto idxArr = ReadHkArray(buf, dataAbs, bindRel, bindIdxOff, ptrSize, fixups);\n\tif (idxArr.contentRel >= 0 && idxArr.count > 0) {\n\t\tuint32_t cAbs = dataAbs + uint32_t(idxArr.contentRel);\n\t\tif (buf.InBounds(cAbs, size_t(idxArr.count) * 2)) {\n\t\t\toutBind.transformTrackToBoneIndices.resize(idxArr.count);\n\t\t\tfor (uint32_t i = 0; i < idxArr.count; ++i)\n\t\t\t\toutBind.transformTrackToBoneIndices[i] = ReadI16(buf.data + cAbs + i * 2);\n\t\t}\n\t}\n\n\t// blendHint follows the two hkArray fields after bindIdxOff.\n\tuint32_t blendHintOff = bindIdxOff + 2u * arrSize;\n\tuint32_t blendAbs = dataAbs + bindRel + blendHintOff;\n\tif (buf.InBounds(blendAbs, 4))\n\t\toutBind.blendHint = ReadI32(buf.data + blendAbs);\n\treturn true;\n}\n\n} // namespace\n\nbool File::Load(const std::string& path, std::string* errorOut) {\n\tskeletons.clear();\n\tanimations.clear();\n\tformat = Format::Unknown;\n\n\tstd::vector<uint8_t> raw;\n\tif (!ReadAllFile(path, raw)) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Cannot open file\";\n\t\treturn false;\n\t}\n\n\tBuf buf{raw.data(), raw.size()};\n\tif (buf.size < 0x40) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"File too small\";\n\t\treturn false;\n\t}\n\n\t// Validate magic bytes (0x57E0E057, 0x10C0C010 in LE).\n\tstatic const uint8_t MAGIC[8] = {0x57, 0xE0, 0xE0, 0x57, 0x10, 0xC0, 0xC0, 0x10};\n\tif (std::memcmp(buf.data, MAGIC, 8) != 0) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Not a Havok packfile (bad magic)\";\n\t\treturn false;\n\t}\n\n\tformat = DetectFormat(buf);\n\tif (format == Format::Unknown) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Unsupported HKX variant\";\n\t\treturn false;\n\t}\n\tuint32_t ptrSize = (format == Format::Skyrim32) ? 4u : 8u;\n\n\tSection sec[3];\n\tif (!ParseSections(buf, format, sec)) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Failed to parse section headers\";\n\t\treturn false;\n\t}\n\n\tconst Section* cnSec = FindSection(sec, \"__classnames__\");\n\tconst Section* dataSec = FindSection(sec, \"__data__\");\n\tif (!cnSec || !dataSec) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Missing required HKX sections\";\n\t\treturn false;\n\t}\n\n\tstd::unordered_map<uint32_t, uint32_t> localFixups;\n\tif (!ParseLocalFixups(buf, *dataSec, localFixups)) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Failed to parse local fixups\";\n\t\treturn false;\n\t}\n\n\tstd::vector<VirtualObject> objects;\n\tif (!ParseVirtualFixups(buf, *dataSec, cnSec->absStart, objects)) {\n\t\tif (errorOut)\n\t\t\t*errorOut = \"Failed to parse virtual fixups\";\n\t\treturn false;\n\t}\n\n\t// Map each animation object to its (optional) binding.\n\tstruct AnimRec {\n\t\tuint32_t rel;\n\t};\n\tstd::vector<AnimRec> animObjs;\n\tstd::vector<uint32_t> bindingObjs;\n\n\tfor (const auto& obj : objects) {\n\t\tif (obj.className == \"hkaSkeleton\") {\n\t\t\tSkeleton skel;\n\t\t\tif (ParseSkeleton(buf, dataSec->absStart, obj.relOffset, ptrSize, format, localFixups, skel))\n\t\t\t\tskeletons.push_back(std::move(skel));\n\t\t}\n\t\telse if (obj.className == \"hkaSplineCompressedAnimation\") {\n\t\t\tanimObjs.push_back({obj.relOffset});\n\t\t}\n\t\telse if (obj.className == \"hkaAnimationBinding\") {\n\t\t\tbindingObjs.push_back(obj.relOffset);\n\t\t}\n\t}\n\n\t// Parse animations and pair with bindings (positionally — every binding\n\t// references its corresponding animation; in vanilla files there is at\n\t// most one of each).\n\tfor (size_t i = 0; i < animObjs.size(); ++i) {\n\t\tAnimation anim;\n\t\tstd::string err;\n\t\tif (!ParseAnimation(buf, dataSec->absStart, animObjs[i].rel, ptrSize, localFixups, anim, &err)) {\n\t\t\tif (errorOut && errorOut->empty())\n\t\t\t\t*errorOut = err;\n\t\t\tcontinue;\n\t\t}\n\t\tif (i < bindingObjs.size()) {\n\t\t\tParseAnimationBinding(buf, dataSec->absStart, bindingObjs[i], ptrSize, localFixups, anim.binding);\n\t\t}\n\t\tanimations.push_back(std::move(anim));\n\t}\n\n\treturn !skeletons.empty() || !animations.empty();\n}\n\n} // namespace HKX\n"
  },
  {
    "path": "src/files/HkxFile.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n\nNative reader for Havok HKX packfile skeletons and spline-compressed\nanimations as shipped by Bethesda for Skyrim LE, Skyrim SE/VR and Fallout 4.\n\nSupports:\n  - Skyrim LE        hk_2010.2.0-r1, file version 8, 32-bit pointers\n  - Skyrim SE / VR   hk_2010.2.0-r1, file version 8, 64-bit pointers\n  - Fallout 4 / VR   hk_2014.1.0-r1, file version 11, 64-bit pointers\n\nOnly enough of the format is decoded to load skeletons (bones, parent\nindices, local reference pose) and animations (per-frame TRS for every\ntransform track plus the track-to-bone binding). Physics, ragdolls,\nfloats and textual annotations are ignored.\n\nSpline decompression is ported from PyNifly's anim_fo4.py (GPLv3),\nwhich itself is derived from Dagobaking's skyrim-fo4-animation-conversion\nand PredatorCZ/HavokLib (both GPLv3).\n*/\n\n#pragma once\n\n#include <cstdint>\n#include <string>\n#include <vector>\n\nnamespace HKX {\n\nenum class Format {\n\tUnknown,\n\tSkyrim32, // hk_2010, version 8, 32-bit pointers (Skyrim LE)\n\tSkyrim64, // hk_2010, version 8, 64-bit pointers (Skyrim SE/VR)\n\tFallout64 // hk_2014, version 11, 64-bit pointers (Fallout 4/VR)\n};\n\nstruct Bone {\n\tstd::string name;\n\tint16_t parentIndex = -1;\n\tbool lockTranslation = false;\n};\n\n// Local-space TRS as stored in an hkQsTransform. Quaternion is xyzw.\nstruct Transform {\n\tfloat translation[3] = {0.0f, 0.0f, 0.0f};\n\tfloat rotation[4] = {0.0f, 0.0f, 0.0f, 1.0f};\n\tfloat scale[3] = {1.0f, 1.0f, 1.0f};\n};\n\nstruct Skeleton {\n\tstd::string name;\n\tstd::vector<Bone> bones;\n\t// Parallel to bones; size matches bones.size() (or empty if missing).\n\tstd::vector<Transform> referencePose;\n};\n\nstruct AnimationBinding {\n\tstd::string originalSkeletonName;\n\t// Maps transform-track index -> bone index in the bound skeleton.\n\t// May be empty, in which case track index equals bone index.\n\tstd::vector<int16_t> transformTrackToBoneIndices;\n\tint32_t blendHint = 0; // 0 = NORMAL, 1 = ADDITIVE\n};\n\nstruct Animation {\n\tfloat duration = 0.0f;\n\tfloat frameDuration = 1.0f / 30.0f;\n\tuint32_t numFrames = 0;\n\tuint32_t numTransformTracks = 0;\n\t// Per-track names sourced from annotationTracks. May be empty if the\n\t// file has no annotation tracks.\n\tstd::vector<std::string> trackNames;\n\t// Decompressed per-frame, per-track local TRS in row-major\n\t// [frame * numTransformTracks + track] order.\n\t// size() == numFrames * numTransformTracks.\n\tstd::vector<Transform> trackTransforms;\n\tAnimationBinding binding;\n\n\t// Convenience accessor.\n\tconst Transform& At(uint32_t frame, uint32_t track) const {\n\t\treturn trackTransforms[frame * numTransformTracks + track];\n\t}\n};\n\nclass File {\npublic:\n\t// Parse the given .hkx file. Returns false on failure; if errorOut is\n\t// non-null it receives a short human-readable description.\n\tbool Load(const std::string& path, std::string* errorOut = nullptr);\n\n\tFormat GetFormat() const { return format; }\n\tconst std::vector<Skeleton>& GetSkeletons() const { return skeletons; }\n\tconst std::vector<Animation>& GetAnimations() const { return animations; }\n\nprivate:\n\tFormat format = Format::Unknown;\n\tstd::vector<Skeleton> skeletons;\n\tstd::vector<Animation> animations;\n};\n\n} // namespace HKX\n"
  },
  {
    "path": "src/files/MaskFile.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"MaskFile.h\"\n\n#include \"../utils/PlatformUtil.h\"\n\n#include <tinyxml2.h>\n\nusing namespace tinyxml2;\n\nstatic void LoadMaskDataElement(XMLElement* maskDataElem, MaskEntry& entry) {\n\tconst char* nameAttr = maskDataElem->Attribute(\"name\");\n\tentry.name = nameAttr ? nameAttr : \"\";\n\n\tXMLElement* shapeElem = maskDataElem->FirstChildElement(\"Shape\");\n\twhile (shapeElem) {\n\t\tMaskShapeData shapeData;\n\n\t\tconst char* sn = shapeElem->Attribute(\"name\");\n\t\tif (sn)\n\t\t\tshapeData.name = sn;\n\n\t\tshapeData.vertexCount = shapeElem->IntAttribute(\"vertexCount\", 0);\n\n\t\tXMLElement* vertElem = shapeElem->FirstChildElement(\"V\");\n\t\twhile (vertElem) {\n\t\t\tint idx = vertElem->IntAttribute(\"i\", -1);\n\t\t\tfloat val = vertElem->FloatAttribute(\"m\", 0.0f);\n\t\t\tif (idx >= 0)\n\t\t\t\tshapeData.mask[static_cast<uint16_t>(idx)] = val;\n\t\t\tvertElem = vertElem->NextSiblingElement(\"V\");\n\t\t}\n\n\t\tentry.shapes.push_back(std::move(shapeData));\n\t\tshapeElem = shapeElem->NextSiblingElement(\"Shape\");\n\t}\n}\n\nint MaskFile::Load(const std::string& fileName) {\n\tXMLDocument doc;\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\tint err = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (err || !fp)\n\t\treturn 1;\n#else\n\tfp = fopen(fileName.c_str(), \"rb\");\n\tif (!fp)\n\t\treturn 1;\n#endif\n\n\tXMLError error = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error != XML_SUCCESS)\n\t\treturn 2;\n\n\tentries.clear();\n\n\tXMLElement* root = doc.FirstChildElement(\"MaskFile\");\n\tif (!root)\n\t\treturn 3;\n\n\tversion = root->IntAttribute(\"version\", 1);\n\n\tXMLElement* maskDataElem = root->FirstChildElement(\"MaskData\");\n\twhile (maskDataElem) {\n\t\tMaskEntry entry;\n\t\tLoadMaskDataElement(maskDataElem, entry);\n\t\tentries.push_back(std::move(entry));\n\t\tmaskDataElem = maskDataElem->NextSiblingElement(\"MaskData\");\n\t}\n\n\treturn 0;\n}\n\nint MaskFile::Save(const std::string& fileName) const {\n\tXMLDocument doc;\n\tdoc.InsertFirstChild(doc.NewDeclaration());\n\n\tXMLElement* root = doc.NewElement(\"MaskFile\");\n\troot->SetAttribute(\"version\", version);\n\tdoc.InsertEndChild(root);\n\n\tfor (const auto& entry : entries) {\n\t\tXMLElement* maskDataElem = doc.NewElement(\"MaskData\");\n\t\tmaskDataElem->SetAttribute(\"name\", entry.name.c_str());\n\t\troot->InsertEndChild(maskDataElem);\n\n\t\tfor (const auto& shapeData : entry.shapes) {\n\t\t\tXMLElement* shapeElem = doc.NewElement(\"Shape\");\n\t\t\tshapeElem->SetAttribute(\"name\", shapeData.name.c_str());\n\t\t\tshapeElem->SetAttribute(\"vertexCount\", shapeData.vertexCount);\n\t\t\tmaskDataElem->InsertEndChild(shapeElem);\n\n\t\t\tfor (const auto& [vertIndex, value] : shapeData.mask) {\n\t\t\t\tXMLElement* vertElem = doc.NewElement(\"V\");\n\t\t\t\tvertElem->SetAttribute(\"i\", vertIndex);\n\t\t\t\tvertElem->SetAttribute(\"m\", std::to_string(value).c_str());\n\t\t\t\tshapeElem->InsertEndChild(vertElem);\n\t\t\t}\n\t\t}\n\t}\n\n\tFILE* fp = nullptr;\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(fileName);\n\tint err = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (err || !fp)\n\t\treturn 1;\n#else\n\tfp = fopen(fileName.c_str(), \"w\");\n\tif (!fp)\n\t\treturn 1;\n#endif\n\n\tXMLError error = doc.SaveFile(fp);\n\tfclose(fp);\n\n\treturn (error != XML_SUCCESS) ? 2 : 0;\n}\n\nstd::string MaskFile::GetFirstName() const {\n\tif (entries.empty())\n\t\treturn {};\n\treturn entries.front().name;\n}\n\nconst MaskEntry* MaskFile::FindEntry(const std::string& entryName) const {\n\tfor (const auto& entry : entries) {\n\t\tif (entry.name == entryName)\n\t\t\treturn &entry;\n\t}\n\treturn nullptr;\n}\n\nvoid MaskEntry::SetFromMaskData(const std::map<std::string, std::unordered_map<uint16_t, float>>& maskData,\n\tconst std::map<std::string, int>& vertexCounts) {\n\tshapes.clear();\n\tfor (const auto& [shapeName, mask] : maskData) {\n\t\tMaskShapeData shapeData;\n\t\tshapeData.name = shapeName;\n\t\tshapeData.mask = mask;\n\n\t\tauto it = vertexCounts.find(shapeName);\n\t\tif (it != vertexCounts.end())\n\t\t\tshapeData.vertexCount = it->second;\n\n\t\tshapes.push_back(std::move(shapeData));\n\t}\n}\n\nstd::map<std::string, std::unordered_map<uint16_t, float>> MaskEntry::ToMaskData() const {\n\tstd::map<std::string, std::unordered_map<uint16_t, float>> result;\n\tfor (const auto& shapeData : shapes)\n\t\tresult[shapeData.name] = shapeData.mask;\n\treturn result;\n}\n\nconst MaskShapeData* MaskEntry::FindMatchingMask(const std::string& shapeName, int vertexCount) const {\n\t// First try: match by shape name\n\tfor (const auto& sd : shapes) {\n\t\tif (sd.name == shapeName)\n\t\t\treturn &sd;\n\t}\n\n\t// Fallback: match by vertex count\n\tfor (const auto& sd : shapes) {\n\t\tif (sd.vertexCount > 0 && sd.vertexCount == vertexCount)\n\t\t\treturn &sd;\n\t}\n\n\treturn nullptr;\n}\n"
  },
  {
    "path": "src/files/MaskFile.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <map>\n#include <string>\n#include <unordered_map>\n#include <vector>\n\nstruct MaskShapeData {\n\tstd::string name;\n\tint vertexCount = 0;\n\tstd::unordered_map<uint16_t, float> mask;\n};\n\nstruct MaskEntry {\n\tstd::string name;\n\tstd::vector<MaskShapeData> shapes;\n\n\tvoid SetFromMaskData(const std::map<std::string, std::unordered_map<uint16_t, float>>& maskData,\n\t\tconst std::map<std::string, int>& vertexCounts);\n\n\tstd::map<std::string, std::unordered_map<uint16_t, float>> ToMaskData() const;\n\n\t// Find a mask matching by shape name, or fall back to vertex count.\n\tconst MaskShapeData* FindMatchingMask(const std::string& shapeName, int vertexCount) const;\n};\n\nclass MaskFile {\n\tint version = 1;\n\tstd::vector<MaskEntry> entries;\n\npublic:\n\tint Load(const std::string& fileName);\n\tint Save(const std::string& fileName) const;\n\n\tint GetVersion() const { return version; }\n\n\tconst std::vector<MaskEntry>& GetEntries() const { return entries; }\n\tstd::vector<MaskEntry>& GetEntries() { return entries; }\n\n\t// Get the name of the first entry, or empty if no entries.\n\tstd::string GetFirstName() const;\n\n\t// Find an entry by name. Returns nullptr if not found.\n\tconst MaskEntry* FindEntry(const std::string& entryName) const;\n};\n"
  },
  {
    "path": "src/files/MaterialFile.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"MaterialFile.h\"\n#include \"../utils/StringStuff.h\"\n\nusing namespace nifly;\n\nMaterialFile::MaterialFile(const Type& signature) {\n\tthis->signature = signature;\n}\n\nMaterialFile::MaterialFile(const std::string& fileName) {\n\tstd::ifstream input(fileName, std::ifstream::binary);\n\tif (!input) {\n\t\tfailed = true;\n\t\treturn;\n\t}\n\n\tif (Read(input))\n\t\tfailed = true;\n}\n\nMaterialFile::MaterialFile(std::istream& input) {\n\tif (!input) {\n\t\tfailed = true;\n\t\treturn;\n\t}\n\n\tif (Read(input))\n\t\tfailed = true;\n}\n\nint MaterialFile::Read(std::istream& input) {\n\tuint32_t magic;\n\tinput.read((char*)&magic, 4);\n\tif (magic != BGSM && magic != BGEM)\n\t\treturn 1;\n\n\tsignature = (Type)magic;\n\n\tinput.read((char*)&version, 4);\n\n\tuint32_t tileFlags;\n\tinput.read((char*)&tileFlags, 4);\n\ttileU = (tileFlags & 2) != 0;\n\ttileV = (tileFlags & 1) != 0;\n\n\tinput.read((char*)&uvOffset, 8);\n\tinput.read((char*)&uvScale, 8);\n\n\tinput.read((char*)&alpha, 4);\n\tuint8_t alphaBlendMode0;\n\tuint32_t alphaBlendMode1;\n\tuint32_t alphaBlendMode2;\n\tinput.read((char*)&alphaBlendMode0, 1);\n\tinput.read((char*)&alphaBlendMode1, 4);\n\tinput.read((char*)&alphaBlendMode2, 4);\n\talphaBlendMode = ConvertAlphaBlendMode(alphaBlendMode0, alphaBlendMode1, alphaBlendMode2);\n\tinput.read((char*)&alphaTestRef, 1);\n\tinput.read((char*)&alphaTest, 1);\n\n\tinput.read((char*)&zBufferWrite, 1);\n\tinput.read((char*)&zBufferTest, 1);\n\tinput.read((char*)&screenSpaceReflections, 1);\n\tinput.read((char*)&wetnessControlScreenSpaceReflections, 1);\n\tinput.read((char*)&decal, 1);\n\tinput.read((char*)&twoSided, 1);\n\tinput.read((char*)&decalNoFade, 1);\n\tinput.read((char*)&nonOccluder, 1);\n\n\tinput.read((char*)&refraction, 1);\n\tinput.read((char*)&refractionFalloff, 1);\n\tinput.read((char*)&refractionPower, 4);\n\n\tif (version < 10) {\n\t\tinput.read((char*)&environmentMapping, 1);\n\t\tinput.read((char*)&environmentMappingMaskScale, 4);\n\t}\n\telse\n\t\tinput.read((char*)&depthBias, 1);\n\n\tinput.read((char*)&grayscaleToPaletteColor, 1);\n\n\tif (version >= 6)\n\t\tinput.read((char*)&maskWrites, 1);\n\n\tuint32_t length = 0;\n\tif (signature == BGSM) {\n\t\tdiffuseTexture = ReadString(input);\n\t\tnormalTexture = ReadString(input);\n\t\tsmoothSpecTexture = ReadString(input);\n\t\tgreyscaleTexture = ReadString(input);\n\n\t\tif (version > 2) {\n\t\t\tglowTexture = ReadString(input);\n\t\t\twrinklesTexture = ReadString(input);\n\t\t\tspecularTexture = ReadString(input);\n\t\t\tlightingTexture = ReadString(input);\n\t\t\tflowTexture = ReadString(input);\n\n\t\t\tif (version >= 17)\n\t\t\t\tdistanceFieldAlphaTexture = ReadString(input);\n\t\t}\n\t\telse {\n\t\t\tenvmapTexture = ReadString(input);\n\t\t\tglowTexture = ReadString(input);\n\t\t\tinnerLayerTexture = ReadString(input);\n\t\t\twrinklesTexture = ReadString(input);\n\t\t\tdisplacementTexture = ReadString(input);\n\t\t}\n\n\t\tinput.read((char*)&enableEditorAlphaRef, 1);\n\n\t\tif (version >= 8) {\n\t\t\tinput.read((char*)&translucency, 1);\n\t\t\tinput.read((char*)&translucencyThickObject, 1);\n\t\t\tinput.read((char*)&translucencyMixAlbedoWithSubsurfaceColor, 1);\n\t\t\tinput.read((char*)&translucencySubsurfaceColor, 12);\n\t\t\tinput.read((char*)&translucencyTransmissiveScale, 4);\n\t\t\tinput.read((char*)&translucencyTurbulence, 4);\n\t\t}\n\t\telse {\n\t\t\tinput.read((char*)&rimLighting, 1);\n\t\t\tinput.read((char*)&rimPower, 4);\n\t\t\tinput.read((char*)&backLightPower, 4);\n\n\t\t\tinput.read((char*)&subsurfaceLighting, 1);\n\t\t\tinput.read((char*)&subsurfaceLightingRolloff, 4);\n\t\t}\n\n\t\tinput.read((char*)&specularEnabled, 1);\n\t\tinput.read((char*)&specularColor, 12);\n\t\tinput.read((char*)&specularMult, 4);\n\t\tinput.read((char*)&smoothness, 4);\n\t\tinput.read((char*)&fresnelPower, 4);\n\t\tinput.read((char*)&wetnessControlSpecScale, 4);\n\t\tinput.read((char*)&wetnessControlSpecPowerScale, 4);\n\t\tinput.read((char*)&wetnessControlSpecMinvar, 4);\n\n\t\tif (version < 10)\n\t\t\tinput.read((char*)&wetnessControlEnvMapScale, 4);\n\n\t\tinput.read((char*)&wetnessControlFresnelPower, 4);\n\t\tinput.read((char*)&wetnessControlMetalness, 4);\n\n\t\tif (version > 2) {\n\t\t\tinput.read((char*)&pbr, 1);\n\n\t\t\tif (version >= 9) {\n\t\t\t\tinput.read((char*)&customPorosity, 1);\n\t\t\t\tinput.read((char*)&porosityValue, 4);\n\t\t\t}\n\t\t}\n\n\t\tinput.read((char*)&length, 4);\n\t\trootMaterialPath.resize(length);\n\t\tinput.read((char*)&rootMaterialPath.front(), length);\n\n\t\tinput.read((char*)&anisoLighting, 1);\n\t\tinput.read((char*)&emitEnabled, 1);\n\t\tif (emitEnabled)\n\t\t\tinput.read((char*)&emittanceColor, 12);\n\n\t\tinput.read((char*)&emittanceMult, 4);\n\t\tinput.read((char*)&modelSpaceNormals, 1);\n\t\tinput.read((char*)&externalEmittance, 1);\n\n\t\tif (version >= 12)\n\t\t\tinput.read((char*)&lumEmittance, 4);\n\n\t\tif (version >= 13) {\n\t\t\tinput.read((char*)&useAdaptativeEmissive, 1);\n\t\t\tinput.read((char*)&adaptativeEmissive_ExposureOffset, 4);\n\t\t\tinput.read((char*)&adaptativeEmissive_FinalExposureMin, 4);\n\t\t\tinput.read((char*)&adaptativeEmissive_FinalExposureMax, 4);\n\t\t}\n\n\t\tif (version < 8)\n\t\t\tinput.read((char*)&backLighting, 1);\n\n\t\tinput.read((char*)&receiveShadows, 1);\n\t\tinput.read((char*)&hideSecret, 1);\n\t\tinput.read((char*)&castShadows, 1);\n\t\tinput.read((char*)&dissolveFade, 1);\n\t\tinput.read((char*)&assumeShadowmask, 1);\n\n\t\tinput.read((char*)&glowMap, 1);\n\n\t\tif (version < 7) {\n\t\t\tinput.read((char*)&environmentMappingWindow, 1);\n\t\t\tinput.read((char*)&environmentMappingEye, 1);\n\t\t}\n\n\t\tinput.read((char*)&hair, 1);\n\t\tinput.read((char*)&hairTintColor, 12);\n\t\tinput.read((char*)&tree, 1);\n\t\tinput.read((char*)&facegen, 1);\n\t\tinput.read((char*)&skinTint, 1);\n\n\t\tinput.read((char*)&tessellate, 1);\n\n\t\tif (version < 3) {\n\t\t\tinput.read((char*)&displacementTextureBias, 4);\n\t\t\tinput.read((char*)&displacementTextureScale, 4);\n\t\t\tinput.read((char*)&tessellationPNScale, 4);\n\t\t\tinput.read((char*)&tessellationBaseFactor, 4);\n\t\t\tinput.read((char*)&tessellationFadeDistance, 4);\n\t\t}\n\n\t\tinput.read((char*)&grayscaleToPaletteScale, 4);\n\t\tif (version >= 1)\n\t\t\tinput.read((char*)&skewSpecularAlpha, 1);\n\n\t\tif (version >= 3) {\n\t\t\tinput.read((char*)&terrain, 1);\n\n\t\t\tif (terrain) {\n\t\t\t\tif (version == 3)\n\t\t\t\t\tinput.read((char*)&unkInt1, 4);\n\n\t\t\t\tinput.read((char*)&terrainThresholdFalloff, 4);\n\t\t\t\tinput.read((char*)&terrainTilingDistance, 4);\n\t\t\t\tinput.read((char*)&terrainRotationAngle, 4);\n\t\t\t}\n\t\t}\n\t}\n\telse if (signature == BGEM) {\n\t\tbaseTexture = ReadString(input);\n\t\tgrayscaleTexture = ReadString(input);\n\t\tfxEnvmapTexture = ReadString(input);\n\t\tfxNormalTexture = ReadString(input);\n\t\tenvmapMaskTexture = ReadString(input);\n\n\t\tif (version >= 11) {\n\t\t\tspecularTexture = ReadString(input);\n\t\t\tlightingTexture = ReadString(input);\n\t\t\tglowTexture = ReadString(input);\n\t\t}\n\n\t\tif (version >= 10) {\n\t\t\tinput.read((char*)&environmentMapping, 1);\n\t\t\tinput.read((char*)&environmentMappingMaskScale, 4);\n\t\t}\n\n\t\tinput.read((char*)&bloodEnabled, 1);\n\t\tinput.read((char*)&effectLightingEnabled, 1);\n\t\tinput.read((char*)&falloffEnabled, 1);\n\t\tinput.read((char*)&falloffColorEnabled, 1);\n\t\tinput.read((char*)&grayscaleToPaletteAlpha, 1);\n\t\tinput.read((char*)&softEnabled, 1);\n\n\t\tinput.read((char*)&baseColor, 12);\n\t\tinput.read((char*)&falloffStartAngle, 4);\n\t\tinput.read((char*)&falloffStopAngle, 4);\n\t\tinput.read((char*)&falloffStartOpacity, 4);\n\t\tinput.read((char*)&falloffStopOpacity, 4);\n\t\tinput.read((char*)&lightingInfluence, 4);\n\t\tinput.read((char*)&envmapMinLOD, 1);\n\t\tinput.read((char*)&softDepth, 4);\n\n\t\tif (version >= 11)\n\t\t\tinput.read((char*)&emittanceColor, 12);\n\n\t\tif (version >= 15) {\n\t\t\tinput.read((char*)&adaptativeEmissive_ExposureOffset, 4);\n\t\t\tinput.read((char*)&adaptativeEmissive_FinalExposureMin, 4);\n\t\t\tinput.read((char*)&adaptativeEmissive_FinalExposureMax, 4);\n\t\t}\n\n\t\tif (version >= 16)\n\t\t\tinput.read((char*)&glowMap, 1);\n\n\t\tif (version >= 20)\n\t\t\tinput.read((char*)&effectPbrSpecular, 1);\n\t}\n\n\treturn 0;\n}\n\nint MaterialFile::Write(std::ostream& output) {\n\toutput.write((char*)&signature, 4);\n\n\toutput.write((char*)&version, 4);\n\n\tuint32_t tileFlags = 0;\n\tif (tileU)\n\t\ttileFlags += 2;\n\tif (tileV)\n\t\ttileFlags += 1;\n\toutput.write((char*)&tileFlags, 4);\n\n\toutput.write((char*)&uvOffset, 8);\n\toutput.write((char*)&uvScale, 8);\n\n\toutput.write((char*)&alpha, 4);\n\tuint8_t alphaBlendMode0;\n\tuint32_t alphaBlendMode1;\n\tuint32_t alphaBlendMode2;\n\tConvertAlphaBlendMode(alphaBlendMode, alphaBlendMode0, alphaBlendMode1, alphaBlendMode2);\n\toutput.write((char*)&alphaBlendMode0, 1);\n\toutput.write((char*)&alphaBlendMode1, 4);\n\toutput.write((char*)&alphaBlendMode2, 4);\n\toutput.write((char*)&alphaTestRef, 1);\n\toutput.write((char*)&alphaTest, 1);\n\n\toutput.write((char*)&zBufferWrite, 1);\n\toutput.write((char*)&zBufferTest, 1);\n\toutput.write((char*)&screenSpaceReflections, 1);\n\toutput.write((char*)&wetnessControlScreenSpaceReflections, 1);\n\toutput.write((char*)&decal, 1);\n\toutput.write((char*)&twoSided, 1);\n\toutput.write((char*)&decalNoFade, 1);\n\toutput.write((char*)&nonOccluder, 1);\n\n\toutput.write((char*)&refraction, 1);\n\toutput.write((char*)&refractionFalloff, 1);\n\toutput.write((char*)&refractionPower, 4);\n\n\tif (version < 10) {\n\t\toutput.write((char*)&environmentMapping, 1);\n\t\toutput.write((char*)&environmentMappingMaskScale, 4);\n\t}\n\telse\n\t\toutput.write((char*)&depthBias, 1);\n\n\toutput.write((char*)&grayscaleToPaletteColor, 1);\n\n\tif (version >= 6)\n\t\toutput.write((char*)&maskWrites, 1);\n\n\tuint32_t length = 0;\n\tif (signature == BGSM) {\n\t\tWriteString(output, diffuseTexture);\n\t\tWriteString(output, normalTexture);\n\t\tWriteString(output, smoothSpecTexture);\n\t\tWriteString(output, greyscaleTexture);\n\n\t\tif (version > 2) {\n\t\t\tWriteString(output, glowTexture);\n\t\t\tWriteString(output, wrinklesTexture);\n\t\t\tWriteString(output, specularTexture);\n\t\t\tWriteString(output, lightingTexture);\n\t\t\tWriteString(output, flowTexture);\n\n\t\t\tif (version >= 17)\n\t\t\t\tWriteString(output, distanceFieldAlphaTexture);\n\t\t}\n\t\telse {\n\t\t\tWriteString(output, envmapTexture);\n\t\t\tWriteString(output, glowTexture);\n\t\t\tWriteString(output, innerLayerTexture);\n\t\t\tWriteString(output, wrinklesTexture);\n\t\t\tWriteString(output, displacementTexture);\n\t\t}\n\n\t\toutput.write((char*)&enableEditorAlphaRef, 1);\n\n\t\tif (version >= 8) {\n\t\t\toutput.write((char*)&translucency, 1);\n\t\t\toutput.write((char*)&translucencyThickObject, 1);\n\t\t\toutput.write((char*)&translucencyMixAlbedoWithSubsurfaceColor, 1);\n\t\t\toutput.write((char*)&translucencySubsurfaceColor, 12);\n\t\t\toutput.write((char*)&translucencyTransmissiveScale, 4);\n\t\t\toutput.write((char*)&translucencyTurbulence, 4);\n\t\t}\n\t\telse {\n\t\t\toutput.write((char*)&rimLighting, 1);\n\t\t\toutput.write((char*)&rimPower, 4);\n\t\t\toutput.write((char*)&backLightPower, 4);\n\n\t\t\toutput.write((char*)&subsurfaceLighting, 1);\n\t\t\toutput.write((char*)&subsurfaceLightingRolloff, 4);\n\t\t}\n\n\t\toutput.write((char*)&specularEnabled, 1);\n\t\toutput.write((char*)&specularColor, 12);\n\t\toutput.write((char*)&specularMult, 4);\n\t\toutput.write((char*)&smoothness, 4);\n\t\toutput.write((char*)&fresnelPower, 4);\n\t\toutput.write((char*)&wetnessControlSpecScale, 4);\n\t\toutput.write((char*)&wetnessControlSpecPowerScale, 4);\n\t\toutput.write((char*)&wetnessControlSpecMinvar, 4);\n\n\t\tif (version < 10)\n\t\t\toutput.write((char*)&wetnessControlEnvMapScale, 4);\n\n\t\toutput.write((char*)&wetnessControlFresnelPower, 4);\n\t\toutput.write((char*)&wetnessControlMetalness, 4);\n\n\t\tif (version > 2) {\n\t\t\toutput.write((char*)&pbr, 1);\n\n\t\t\tif (version >= 9) {\n\t\t\t\toutput.write((char*)&customPorosity, 1);\n\t\t\t\toutput.write((char*)&porosityValue, 4);\n\t\t\t}\n\t\t}\n\n\t\tlength = static_cast<uint32_t>(rootMaterialPath.length());\n\t\toutput.write((char*)&length, 4);\n\t\toutput.write(rootMaterialPath.c_str(), length);\n\n\t\toutput.write((char*)&anisoLighting, 1);\n\t\toutput.write((char*)&emitEnabled, 1);\n\t\tif (emitEnabled)\n\t\t\toutput.write((char*)&emittanceColor, 12);\n\n\t\toutput.write((char*)&emittanceMult, 4);\n\t\toutput.write((char*)&modelSpaceNormals, 1);\n\t\toutput.write((char*)&externalEmittance, 1);\n\n\t\tif (version >= 12)\n\t\t\toutput.write((char*)&lumEmittance, 4);\n\n\t\tif (version >= 13) {\n\t\t\toutput.write((char*)&useAdaptativeEmissive, 1);\n\t\t\toutput.write((char*)&adaptativeEmissive_ExposureOffset, 4);\n\t\t\toutput.write((char*)&adaptativeEmissive_FinalExposureMin, 4);\n\t\t\toutput.write((char*)&adaptativeEmissive_FinalExposureMax, 4);\n\t\t}\n\n\t\tif (version < 8)\n\t\t\toutput.write((char*)&backLighting, 1);\n\n\t\toutput.write((char*)&receiveShadows, 1);\n\t\toutput.write((char*)&hideSecret, 1);\n\t\toutput.write((char*)&castShadows, 1);\n\t\toutput.write((char*)&dissolveFade, 1);\n\t\toutput.write((char*)&assumeShadowmask, 1);\n\n\t\toutput.write((char*)&glowMap, 1);\n\n\t\tif (version < 7) {\n\t\t\toutput.write((char*)&environmentMappingWindow, 1);\n\t\t\toutput.write((char*)&environmentMappingEye, 1);\n\t\t}\n\n\t\toutput.write((char*)&hair, 1);\n\t\toutput.write((char*)&hairTintColor, 12);\n\t\toutput.write((char*)&tree, 1);\n\t\toutput.write((char*)&facegen, 1);\n\t\toutput.write((char*)&skinTint, 1);\n\n\t\toutput.write((char*)&tessellate, 1);\n\n\t\tif (version < 3) {\n\t\t\toutput.write((char*)&displacementTextureBias, 4);\n\t\t\toutput.write((char*)&displacementTextureScale, 4);\n\t\t\toutput.write((char*)&tessellationPNScale, 4);\n\t\t\toutput.write((char*)&tessellationBaseFactor, 4);\n\t\t\toutput.write((char*)&tessellationFadeDistance, 4);\n\t\t}\n\n\t\toutput.write((char*)&grayscaleToPaletteScale, 4);\n\t\tif (version >= 1)\n\t\t\toutput.write((char*)&skewSpecularAlpha, 1);\n\n\t\tif (version >= 3) {\n\t\t\toutput.write((char*)&terrain, 1);\n\n\t\t\tif (terrain) {\n\t\t\t\tif (version == 3)\n\t\t\t\t\toutput.write((char*)&unkInt1, 4);\n\n\t\t\t\toutput.write((char*)&terrainThresholdFalloff, 4);\n\t\t\t\toutput.write((char*)&terrainTilingDistance, 4);\n\t\t\t\toutput.write((char*)&terrainRotationAngle, 4);\n\t\t\t}\n\t\t}\n\t}\n\telse if (signature == BGEM) {\n\t\tWriteString(output, baseTexture);\n\t\tWriteString(output, grayscaleTexture);\n\t\tWriteString(output, fxEnvmapTexture);\n\t\tWriteString(output, fxNormalTexture);\n\t\tWriteString(output, envmapMaskTexture);\n\n\t\tif (version >= 11) {\n\t\t\tWriteString(output, specularTexture);\n\t\t\tWriteString(output, lightingTexture);\n\t\t\tWriteString(output, glowTexture);\n\t\t}\n\n\t\tif (version >= 10) {\n\t\t\toutput.write((char*)&environmentMapping, 1);\n\t\t\toutput.write((char*)&environmentMappingMaskScale, 4);\n\t\t}\n\n\t\toutput.write((char*)&bloodEnabled, 1);\n\t\toutput.write((char*)&effectLightingEnabled, 1);\n\t\toutput.write((char*)&falloffEnabled, 1);\n\t\toutput.write((char*)&falloffColorEnabled, 1);\n\t\toutput.write((char*)&grayscaleToPaletteAlpha, 1);\n\t\toutput.write((char*)&softEnabled, 1);\n\n\t\toutput.write((char*)&baseColor, 12);\n\t\toutput.write((char*)&falloffStartAngle, 4);\n\t\toutput.write((char*)&falloffStopAngle, 4);\n\t\toutput.write((char*)&falloffStartOpacity, 4);\n\t\toutput.write((char*)&falloffStopOpacity, 4);\n\t\toutput.write((char*)&lightingInfluence, 4);\n\t\toutput.write((char*)&envmapMinLOD, 1);\n\t\toutput.write((char*)&softDepth, 4);\n\n\t\tif (version >= 11)\n\t\t\toutput.write((char*)&emittanceColor, 12);\n\n\t\tif (version >= 15) {\n\t\t\toutput.write((char*)&adaptativeEmissive_ExposureOffset, 4);\n\t\t\toutput.write((char*)&adaptativeEmissive_FinalExposureMin, 4);\n\t\t\toutput.write((char*)&adaptativeEmissive_FinalExposureMax, 4);\n\t\t}\n\n\t\tif (version >= 16)\n\t\t\toutput.write((char*)&glowMap, 1);\n\n\t\tif (version >= 20)\n\t\t\toutput.write((char*)&effectPbrSpecular, 1);\n\t}\n\n\treturn 0;\n}\n\nstd::string MaterialFile::ReadString(std::istream& input) {\n\tuint32_t length = 0;\n\tinput.read((char*)&length, 4);\n\n\tstd::string tmp;\n\ttmp.resize(length);\n\tinput.read((char*)&tmp.front(), length);\n\n\treturn ToOSSlashes(tmp);\n}\n\nvoid MaterialFile::WriteString(std::ostream& output, const std::string& str) {\n\tstd::string tmp = ToBackslashes(str);\n\tuint32_t length = static_cast<uint32_t>(tmp.length());\n\n\toutput.write((char*)&length, 4);\n\toutput.write(tmp.c_str(), length);\n}\n\nMaterialFile::AlphaBlendModeType MaterialFile::ConvertAlphaBlendMode(const uint8_t a, const uint32_t b, const uint32_t c) {\n\tif (a == 0 && b == 6 && c == 7)\n\t\treturn AlphaBlendModeType::Unknown;\n\telse if (a == 0 && b == 0 && c == 0)\n\t\treturn AlphaBlendModeType::None;\n\telse if (a == 1 && b == 6 && c == 7)\n\t\treturn AlphaBlendModeType::Standard;\n\telse if (a == 1 && b == 6 && c == 0)\n\t\treturn AlphaBlendModeType::Additive;\n\telse if (a == 1 && b == 4 && c == 1)\n\t\treturn AlphaBlendModeType::Multiplicative;\n\telse\n\t\treturn AlphaBlendModeType::None;\n}\n\nvoid MaterialFile::ConvertAlphaBlendMode(const AlphaBlendModeType& type, uint8_t& a, uint32_t& b, uint32_t& c) {\n\tif (type == AlphaBlendModeType::Unknown) {\n\t\ta = 0;\n\t\tb = 6;\n\t\tc = 7;\n\t}\n\telse if (type == AlphaBlendModeType::None) {\n\t\ta = 0;\n\t\tb = 0;\n\t\tc = 0;\n\t}\n\telse if (type == AlphaBlendModeType::Standard) {\n\t\ta = 1;\n\t\tb = 6;\n\t\tc = 7;\n\t}\n\telse if (type == AlphaBlendModeType::Additive) {\n\t\ta = 1;\n\t\tb = 6;\n\t\tc = 0;\n\t}\n\telse if (type == AlphaBlendModeType::Multiplicative) {\n\t\ta = 1;\n\t\tb = 4;\n\t\tc = 1;\n\t}\n\telse {\n\t\ta = 0;\n\t\tb = 0;\n\t\tc = 0;\n\t}\n}\n"
  },
  {
    "path": "src/files/MaterialFile.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"Object3d.hpp\"\n#include <fstream>\n\nclass MaterialFile {\n\tbool failed = false;\n\npublic:\n\tenum Type { BGSM = 0x4D534742, BGEM = 0x4D454742 };\n\n\tenum AlphaBlendModeType { Unknown, None, Standard, Additive, Multiplicative };\n\n\tenum MaskWriteFlags : uint8_t { Albedo = 1 << 0, Normal = 1 << 1, Specular = 1 << 2, AmbientOcclusion = 1 << 3, Emissive = 1 << 4, Gloss = 1 << 5 };\n\n\t// Base\n\tType signature = Type::BGSM;\n\tuint32_t version = 1;\n\tbool tileU = true;\n\tbool tileV = true;\n\tnifly::Vector2 uvOffset;\n\tnifly::Vector2 uvScale{1.0f, 1.0f};\n\tfloat alpha = 1.0f;\n\tAlphaBlendModeType alphaBlendMode = AlphaBlendModeType::Unknown;\n\tchar alphaTestRef = -128;\n\tbool alphaTest = false;\n\tbool zBufferWrite = true;\n\tbool zBufferTest = true;\n\tbool screenSpaceReflections = false;\n\tbool wetnessControlScreenSpaceReflections = false;\n\tbool decal = false;\n\tbool twoSided = false;\n\tbool decalNoFade = false;\n\tbool nonOccluder = false;\n\tbool refraction = false;\n\tbool refractionFalloff = false;\n\tfloat refractionPower = 0.0f;\n\tbool environmentMapping = false;\n\tfloat environmentMappingMaskScale = 1.0f;\n\tbool depthBias = false;\n\tbool grayscaleToPaletteColor = false;\n\tMaskWriteFlags maskWrites = (MaskWriteFlags)(MaskWriteFlags::Albedo | MaskWriteFlags::Normal | MaskWriteFlags::Specular | MaskWriteFlags::AmbientOcclusion\n\t\t\t\t\t\t\t\t\t\t\t\t | MaskWriteFlags::Emissive | MaskWriteFlags::Gloss);\n\n\t// BGSM 0x4D534742\n\tstd::string diffuseTexture;\n\tstd::string normalTexture;\n\tstd::string smoothSpecTexture;\n\tstd::string greyscaleTexture;\n\tstd::string specularTexture;\n\tstd::string lightingTexture;\n\tstd::string flowTexture;\n\tstd::string distanceFieldAlphaTexture;\n\tstd::string envmapTexture;\n\tstd::string glowTexture;\n\tstd::string innerLayerTexture;\n\tstd::string wrinklesTexture;\n\tstd::string displacementTexture;\n\tbool enableEditorAlphaRef = false;\n\tbool translucency = false;\n\tbool translucencyThickObject = false;\n\tbool translucencyMixAlbedoWithSubsurfaceColor = false;\n\tnifly::Vector3 translucencySubsurfaceColor = nifly::Vector3(1.0f, 1.0f, 1.0f);\n\tfloat translucencyTransmissiveScale = 1.0f;\n\tfloat translucencyTurbulence = 0.5f;\n\tbool rimLighting = false;\n\tfloat rimPower = 2.0f;\n\tfloat backLightPower = 0.0f;\n\tbool subsurfaceLighting = false;\n\tfloat subsurfaceLightingRolloff = 0.3f;\n\tbool specularEnabled = false;\n\tnifly::Vector3 specularColor = {1.0f, 1.0f, 1.0f};\n\tfloat specularMult = 1.0f;\n\tfloat smoothness = 1.0f;\n\tfloat fresnelPower = 5.0f;\n\tfloat wetnessControlSpecScale = -1.0f;\n\tfloat wetnessControlSpecPowerScale = -1.0f;\n\tfloat wetnessControlSpecMinvar = -1.0f;\n\tfloat wetnessControlEnvMapScale = -1.0f;\n\tfloat wetnessControlFresnelPower = -1.0f;\n\tfloat wetnessControlMetalness = -1.0f;\n\tbool pbr = false;\n\tfloat customPorosity = 0.0f;\n\tfloat porosityValue = 0.0f;\n\tstd::string rootMaterialPath;\n\tbool anisoLighting = false;\n\tbool emitEnabled = false;\n\tnifly::Vector3 emittanceColor = {1.0f, 1.0f, 1.0f};\n\tfloat emittanceMult = 1.0f;\n\tbool modelSpaceNormals = false;\n\tbool externalEmittance = false;\n\tfloat lumEmittance = 100.0f;\n\tbool useAdaptativeEmissive = false;\n\tfloat adaptativeEmissive_ExposureOffset = 13.5f;\n\tfloat adaptativeEmissive_FinalExposureMin = 2.0f;\n\tfloat adaptativeEmissive_FinalExposureMax = 3.0f;\n\tbool backLighting = false;\n\tbool receiveShadows = false;\n\tbool hideSecret = false;\n\tbool castShadows = false;\n\tbool dissolveFade = false;\n\tbool assumeShadowmask = false;\n\tbool glowMap = false;\n\tbool environmentMappingWindow = false;\n\tbool environmentMappingEye = false;\n\tbool hair = false;\n\tnifly::Vector3 hairTintColor = {0.5f, 0.5f, 0.5f};\n\tbool tree = false;\n\tbool facegen = false;\n\tbool skinTint = false;\n\tbool tessellate = false;\n\tfloat displacementTextureBias = -0.5f;\n\tfloat displacementTextureScale = 10.0f;\n\tfloat tessellationPNScale = 1.0f;\n\tfloat tessellationBaseFactor = 1.0f;\n\tfloat tessellationFadeDistance = 0.0f;\n\tfloat grayscaleToPaletteScale = 1.0f;\n\tbool skewSpecularAlpha = false;\n\tbool terrain = false;\n\tuint32_t unkInt1 = 0;\n\tfloat terrainThresholdFalloff = 0.0f;\n\tfloat terrainTilingDistance = 0.0f;\n\tfloat terrainRotationAngle = 0.0f;\n\n\t// BGEM 0x4D454742\n\tstd::string baseTexture;\n\tstd::string grayscaleTexture;\n\tstd::string fxEnvmapTexture;\n\tstd::string fxNormalTexture;\n\tstd::string envmapMaskTexture;\n\tbool bloodEnabled = false;\n\tbool effectLightingEnabled = false;\n\tbool falloffEnabled = false;\n\tbool falloffColorEnabled = false;\n\tbool grayscaleToPaletteAlpha = false;\n\tbool softEnabled = false;\n\tnifly::Vector3 baseColor = {1.0f, 1.0f, 1.0f};\n\tfloat baseColorScale = 1.0f;\n\tfloat falloffStartAngle = 1.0f;\n\tfloat falloffStopAngle = 1.0f;\n\tfloat falloffStartOpacity = 0.0f;\n\tfloat falloffStopOpacity = 0.0f;\n\tfloat lightingInfluence = 1.0f;\n\tuint8_t envmapMinLOD = 0;\n\tfloat softDepth = 100.0f;\n\tbool effectPbrSpecular = false;\n\n\tMaterialFile() {}\n\tMaterialFile(const Type&);\n\tMaterialFile(const std::string&);\n\tMaterialFile(std::istream&);\n\n\tint Read(std::istream&);\n\tint Write(std::ostream&);\n\n\tstd::string ReadString(std::istream&);\n\tvoid WriteString(std::ostream&, const std::string&);\n\n\tbool Failed() { return failed; }\n\n\tAlphaBlendModeType ConvertAlphaBlendMode(const uint8_t, const uint32_t, const uint32_t);\n\tvoid ConvertAlphaBlendMode(const AlphaBlendModeType&, uint8_t&, uint32_t&, uint32_t&);\n};\n"
  },
  {
    "path": "src/files/ObjFile.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"ObjFile.h\"\n#include \"../utils/PlatformUtil.h\"\n#include <sstream>\n#include <unordered_map>\n\nusing namespace nifly;\n\nint ObjFile::AddGroup(\n\tconst std::string& name, const std::vector<Vector3>& verts, const std::vector<Triangle>& tris, const std::vector<Vector2>& uvs, const std::vector<Vector3>& norms) {\n\tif (name.empty() || verts.empty())\n\t\treturn 1;\n\n\tObjData& newData = data[name];\n\tnewData.name = name;\n\tnewData.verts = verts;\n\tnewData.tris = tris;\n\tnewData.uvs = uvs;\n\tnewData.norms = norms;\n\n\treturn 0;\n}\n\nint ObjFile::LoadForNif(const std::string& fileName, const ObjImportOptions& options) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);\n\tif (file.fail())\n\t\treturn 1;\n\n\tif (options.NoFaces)\n\t\tLoadNoFaces(file, options);\n\telse\n\t\tLoadForNif(file, options);\n\n\treturn 0;\n}\n\nvoid ObjFile::LoadNoFaces(std::istream& ins, const ObjImportOptions& options) {\n\tMatrix4 mat;\n\tmat.PushScale(options.Scale, options.Scale, options.Scale);\n\tmat.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmat.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmat.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tObjData d;\n\n\twhile (!ins.eof()) {\n\t\tstd::string line;\n\t\tstd::getline(ins, line);\n\t\tif (line.empty() || line[0] == '#')\n\t\t\tcontinue;\n\n\t\tstd::istringstream lineiss(line);\n\t\tstd::string cmd;\n\t\tlineiss >> cmd;\n\n\t\tif (cmd == \"v\") {\n\t\t\tVector3 v;\n\t\t\tlineiss >> v.x >> v.y >> v.z;\n\t\t\tv = mat * v;\n\t\t\td.verts.push_back(v);\n\t\t}\n\t\telse if (cmd == \"o\" || cmd == \"g\") {\n\t\t\tstd::string curgrp;\n\t\t\tlineiss >> curgrp;\n\n\t\t\tif (!d.name.empty()) {\n\t\t\t\tif (options.ImportAll || options.ImportShapes.count(d.name) > 0)\n\t\t\t\t\tdata[d.name] = std::move(d);\n\n\t\t\t\td = ObjData();\n\t\t\t}\n\n\t\t\td.name = curgrp;\n\t\t}\n\t\telse if (cmd == \"vt\") {\n\t\t\tVector2 uv;\n\t\t\tlineiss >> uv.u >> uv.v;\n\t\t\tuv.v = 1.0f - uv.v;\n\n\t\t\tif (options.InvertU)\n\t\t\t\tuv.u = 1.0f - uv.u;\n\t\t\tif (options.InvertV)\n\t\t\t\tuv.v = 1.0f - uv.v;\n\n\t\t\td.uvs.push_back(uv);\n\t\t}\n\t}\n\n\tif (d.name.empty())\n\t\td.name = \"object\";\n\n\tif (!d.verts.empty())\n\t\tif (options.ImportAll || options.ImportShapes.count(d.name) > 0)\n\t\t\tdata[d.name] = std::move(d);\n\telse\n\t\tdata.erase(d.name);\n}\n\nvoid ObjFile::LoadForNif(std::istream& ins, const ObjImportOptions& options) {\n\tMatrix4 mat;\n\tmat.PushScale(options.Scale, options.Scale, options.Scale);\n\tmat.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmat.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmat.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tMatrix4 matRot;\n\tmatRot.PushRotate(options.RotateX * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmatRot.PushRotate(options.RotateY * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmatRot.PushRotate(options.RotateZ * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\t// First, parse the file into verts, uvs, norms, and faces.  Faces\n\t// are grouped by group/object name; the rest are not.\n\tstd::vector<Vector3> verts;\n\tstd::vector<Vector2> uvs;\n\tstd::vector<Vector3> norms;\n\tstruct FaceVertex {\n\t\t// vi, ti, and ni are indexes into verts, uvs, and norms.  In the\n\t\t// file, the three are offset by 1 so vi==1 means verts[0].\n\t\t// Negative values are also possible, and indicate offsets from the end\n\t\t// of the respective array using its size at the moment the face line\n\t\t// is encountered.\n\t\tint vi = 0, ti = 0, ni = 0;\n\t\tvoid Parse(const std::string& s) {\n\t\t\tvi = atoi(s.c_str());\n\t\t\tsize_t pos = s.find('/');\n\t\t\tti = atoi(s.substr(pos + 1).c_str());\n\t\t\tpos = s.find('/', pos + 1);\n\t\t\tni = atoi(s.substr(pos + 1).c_str());\n\t\t}\n\t};\n\n\t// groups[group/object name][face index][face-vertex index]\n\tstd::unordered_map<std::string, std::vector<std::vector<FaceVertex>>> groups;\n\tstd::vector<std::vector<FaceVertex>>* currentgroup = &groups[\"object\"];\n\n\twhile (!ins.eof()) {\n\t\tstd::string line;\n\t\tstd::getline(ins, line);\n\t\tif (line.empty() || line[0] == '#')\n\t\t\tcontinue;\n\n\t\tstd::istringstream lineiss(line);\n\t\tstd::string cmd;\n\t\tlineiss >> cmd;\n\n\t\tif (cmd == \"v\") {\n\t\t\tVector3 v;\n\t\t\tlineiss >> v.x >> v.y >> v.z;\n\t\t\tv = mat * v;\n\t\t\tverts.push_back(v);\n\t\t}\n\t\telse if (cmd == \"o\" || cmd == \"g\") {\n\t\t\tstd::string grp;\n\t\t\tlineiss >> grp;\n\t\t\tcurrentgroup = &groups[grp];\n\t\t}\n\t\telse if (cmd == \"vt\") {\n\t\t\tVector2 uv;\n\t\t\tlineiss >> uv.u >> uv.v;\n\t\t\tuv.v = 1.0f - uv.v;\n\n\t\t\tif (options.InvertU)\n\t\t\t\tuv.u = 1.0f - uv.u;\n\t\t\tif (options.InvertV)\n\t\t\t\tuv.v = 1.0f - uv.v;\n\n\t\t\tuvs.push_back(uv);\n\t\t}\n\t\telse if (cmd == \"vn\") {\n\t\t\tVector3 vn;\n\t\t\tlineiss >> vn.x >> vn.y >> vn.z;\n\t\t\tvn = matRot * vn;\n\t\t\tnorms.push_back(vn);\n\t\t}\n\t\telse if (cmd == \"f\") {\n\t\t\tcurrentgroup->emplace_back();\n\t\t\tstd::vector<FaceVertex>& face = currentgroup->back();\n\t\t\twhile (true) {\n\t\t\t\tstd::string vertstring;\n\t\t\t\tlineiss >> vertstring;\n\t\t\t\tFaceVertex v;\n\t\t\t\tv.Parse(vertstring);\n\t\t\t\tif (v.vi == 0)\n\t\t\t\t\tbreak;\n\t\t\t\tif (v.vi < 0)\n\t\t\t\t\tv.vi += static_cast<int>(verts.size());\n\t\t\t\telse\n\t\t\t\t\t--v.vi;\n\t\t\t\tif (v.ti < 0)\n\t\t\t\t\tv.ti += static_cast<int>(uvs.size());\n\t\t\t\telse\n\t\t\t\t\t--v.ti;\n\t\t\t\tif (v.ni < 0)\n\t\t\t\t\tv.ni += static_cast<int>(norms.size());\n\t\t\t\telse\n\t\t\t\t\t--v.ni;\n\t\t\t\tface.push_back(v);\n\t\t\t}\n\t\t}\n\t}\n\n\tint nVerts = static_cast<int>(verts.size());\n\tint nUvs = static_cast<int>(uvs.size());\n\tint nNorms = static_cast<int>(norms.size());\n\n\t// Each vertex in verts may need to be duplicated if it's used with\n\t// different texture coordinates or normal.  vdata keeps track of all the\n\t// duplicates for a vertex in a group.\n\tstruct VertData {\n\t\t// grpvi: index into vertices used by this group, in order encountered\n\t\t// in the group's face vertices.  This is not the same as the final\n\t\t// vertex ordering.\n\t\tint grpvi;\n\t\tVector2 uv;\n\t\tVector3 nrm;\n\t};\n\tstd::vector<std::vector<VertData>> vdata;\n\tstd::vector<int> facegrpvi;\n\n\t// We're done parsing the file, but the data needs a lot more work to\n\t// get it into the right form.  We work on one group/object at a time.\n\tfor (auto& gfp : groups) {\n\t\tstd::string groupName = gfp.first;\n\t\tif (!options.ImportAll && options.ImportShapes.count(groupName) == 0)\n\t\t\tcontinue;\n\n\t\tconst std::vector<std::vector<FaceVertex>>& faces = gfp.second;\n\t\tif (faces.empty())\n\t\t\tcontinue;\n\n\t\t// Determine if we have UVs or normals\n\t\tbool haveUVs = true, haveNorms = true, goodVerts = true;\n\t\tfor (const std::vector<FaceVertex>& face : faces)\n\t\t\tfor (const FaceVertex& fv : face) {\n\t\t\t\tif (fv.vi < 0 || fv.vi >= nVerts)\n\t\t\t\t\tgoodVerts = false;\n\t\t\t\tif (fv.ti < 0 || fv.ti >= nUvs)\n\t\t\t\t\thaveUVs = false;\n\t\t\t\tif (fv.ni < 0 || fv.ni >= nNorms)\n\t\t\t\t\thaveNorms = false;\n\t\t\t}\n\t\tif (!goodVerts)\n\t\t\tcontinue;\n\n\t\tObjData& d = data[groupName];\n\t\td.name = groupName;\n\t\tvdata.clear();\n\t\tvdata.resize(nVerts);\n\n\t\t// Collect list of all vertices used by group, temporarily indexed\n\t\t// by grpvi and listed in vdata; also fill in d.tris.\n\t\tint grpvi = 0;\n\t\tfor (const std::vector<FaceVertex>& face : faces) {\n\t\t\t// Find grpvi for each vertex of this face.\n\t\t\tfacegrpvi.clear();\n\t\t\tfor (const FaceVertex& fv : face) {\n\t\t\t\t// Look up vertex's uv and nrm.\n\t\t\t\tVector2 uv;\n\t\t\t\tif (haveUVs)\n\t\t\t\t\tuv = uvs[fv.ti];\n\t\t\t\tVector3 nrm;\n\t\t\t\tif (haveNorms)\n\t\t\t\t\tnrm = norms[fv.ni];\n\n\t\t\t\t// Search for vertex in vdata so we can get its grpvi\n\t\t\t\tstd::vector<VertData>& vds = vdata[fv.vi];\n\t\t\t\tbool found = false;\n\t\t\t\tfor (VertData& vd : vds) {\n\t\t\t\t\tif (haveUVs && uv != vd.uv)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (haveNorms && nrm != vd.nrm)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tfound = true;\n\t\t\t\t\t// Found existing grpvi\n\t\t\t\t\tfacegrpvi.push_back(vd.grpvi);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif (!found) {\n\t\t\t\t\t// New vertex: add to vdata and use new grpvi\n\t\t\t\t\tvds.push_back(VertData{grpvi, uv, nrm});\n\t\t\t\t\tfacegrpvi.push_back(grpvi++);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// facegrpvi now has the grpvi for each of the face's vertices.\n\t\t\t// Turn this into triangles.  Note that the vertex indices are\n\t\t\t// _group_ vertex indices (grpvi), not finished vertex indices.\n\t\t\tfor (size_t fvi = 2; fvi < facegrpvi.size(); ++fvi)\n\t\t\t\td.tris.emplace_back(facegrpvi[0], facegrpvi[fvi - 1], facegrpvi[fvi]);\n\t\t}\n\n\t\t// vdata now has a complete list of vertices used by this group.\n\t\t// The number of vertices used is grpvi.  We create\n\t\t// the \"finished\" vertex ordering by going through vdata in order,\n\t\t// assigning a finvi to each used vertex found.  We prepare\n\t\t// a map from grpvi to finvi.  We store the data in d.verts, d.uvs,\n\t\t// and d.norms.\n\t\tint finvi = 0;\n\t\tstd::vector<int> grpviToFinvi(grpvi);\n\t\td.verts.resize(grpvi);\n\t\tif (haveUVs)\n\t\t\td.uvs.resize(grpvi);\n\t\tif (haveNorms)\n\t\t\td.norms.resize(grpvi);\n\t\tfor (int filevi = 0; filevi < nVerts; ++filevi)\n\t\t\tfor (VertData& vd : vdata[filevi]) {\n\t\t\t\tgrpviToFinvi[vd.grpvi] = finvi;\n\t\t\t\td.verts[finvi] = verts[filevi];\n\t\t\t\tif (haveUVs)\n\t\t\t\t\td.uvs[finvi] = vd.uv;\n\t\t\t\tif (haveNorms)\n\t\t\t\t\td.norms[finvi] = vd.nrm;\n\t\t\t\t++finvi;\n\t\t\t}\n\t\t// assert(finvi == grpvi);\n\n\t\t// Map the triangle vertex indices from grpvi to finvi\n\t\tfor (Triangle& t : d.tris)\n\t\t\tfor (int tvi = 0; tvi < 3; ++tvi)\n\t\t\t\tt[tvi] = static_cast<uint16_t>(grpviToFinvi[t[tvi]]);\n\t}\n}\n\nint ObjFile::Save(const std::string& fileName) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::out | std::ios::binary);\n\tif (file.fail())\n\t\treturn 1;\n\n\tfile << \"# Outfit Studio - OBJ Export\" << std::endl;\n\tfile << \"# https://github.com/ousnius/BodySlide-and-Outfit-Studio\" << std::endl << std::endl;\n\n\tsize_t groupCount = 1;\n\tsize_t pointOffset = 1;\n\n\tfor (auto& odp : data) {\n\t\tconst ObjData& d = odp.second;\n\t\tfile << \"# object \" << d.name << std::endl;\n\t\tfile << \"# \" << d.verts.size() << \" vertices\" << std::endl;\n\t\tfile << \"# \" << d.uvs.size() << \" texture coordinates\" << std::endl;\n\t\tfile << \"# \" << d.norms.size() << \" normals\" << std::endl;\n\t\tfile << \"# \" << d.tris.size() << \" triangles\" << std::endl;\n\n\t\tfor (size_t i = 0; i < d.verts.size(); i++) {\n\t\t\tfile << \"v \" << (d.verts[i].x + offset.x) * scale.x << \" \" << (d.verts[i].y + offset.y) * scale.y << \" \" << (d.verts[i].z + offset.z) * scale.z\n\t\t\t\t << std::endl;\n\t\t}\n\t\tfile << std::endl;\n\n\t\tfor (size_t i = 0; i < d.uvs.size(); i++) {\n\t\t\tfile << \"vt \" << d.uvs[i].u << \" \" << (1.0f - d.uvs[i].v) << std::endl;\n\t\t}\n\t\tfile << std::endl;\n\n\t\tfor (size_t i = 0; i < d.norms.size(); i++) {\n\t\t\tfile << \"vn \" << d.norms[i].x << \" \" << d.norms[i].y << \" \" << d.norms[i].z << std::endl;\n\t\t}\n\t\tfile << std::endl;\n\n\t\tfile << \"g \" << d.name << std::endl;\n\t\tfile << \"usemtl NoMaterial_\" << groupCount << std::endl << std::endl;\n\n\t\tfile << \"s 1\" << std::endl;\n\n\t\tfor (size_t i = 0; i < d.tris.size(); i++) {\n\t\t\tfile << \"f \" << d.tris[i].p1 + pointOffset;\n\n\t\t\tif (!d.uvs.empty())\n\t\t\t\tfile << \"/\" << d.tris[i].p1 + pointOffset;\n\n\t\t\tif (!d.norms.empty()) {\n\t\t\t\tif (d.uvs.empty())\n\t\t\t\t\tfile << \"/\";\n\n\t\t\t\tfile << \"/\" << d.tris[i].p1 + pointOffset;\n\t\t\t}\n\n\t\t\tfile << \" \" << d.tris[i].p2 + pointOffset;\n\n\t\t\tif (!d.uvs.empty())\n\t\t\t\tfile << \"/\" << d.tris[i].p2 + pointOffset;\n\n\t\t\tif (!d.norms.empty()) {\n\t\t\t\tif (d.uvs.empty())\n\t\t\t\t\tfile << \"/\";\n\n\t\t\t\tfile << \"/\" << d.tris[i].p2 + pointOffset;\n\t\t\t}\n\n\t\t\tfile << \" \" << d.tris[i].p3 + pointOffset;\n\n\t\t\tif (!d.uvs.empty())\n\t\t\t\tfile << \"/\" << d.tris[i].p3 + pointOffset;\n\n\t\t\tif (!d.norms.empty()) {\n\t\t\t\tif (d.uvs.empty())\n\t\t\t\t\tfile << \"/\";\n\n\t\t\t\tfile << \"/\" << d.tris[i].p3 + pointOffset;\n\t\t\t}\n\n\t\t\tfile << std::endl;\n\t\t}\n\t\tfile << std::endl;\n\n\t\tpointOffset += d.verts.size();\n\t\tgroupCount++;\n\t}\n\n\tfile.close();\n\treturn 0;\n}\n\nbool ObjFile::CopyDataForGroup(const std::string& name, std::vector<Vector3>* v, std::vector<Triangle>* t, std::vector<Vector2>* uv, std::vector<Vector3>* norms) {\n\tif (data.find(name) == data.end())\n\t\treturn false;\n\n\tObjData& d = data[name];\n\tif (v) {\n\t\tv->clear();\n\t\tv->resize(d.verts.size());\n\t\tfor (size_t i = 0; i < d.verts.size(); i++) {\n\t\t\t(*v)[i].x = (d.verts[i].x + offset.x) * scale.x;\n\t\t\t(*v)[i].y = (d.verts[i].y + offset.y) * scale.y;\n\t\t\t(*v)[i].z = (d.verts[i].z + offset.z) * scale.z;\n\t\t}\n\t}\n\n\tif (t)\n\t\t*t = d.tris;\n\tif (uv)\n\t\t*uv = d.uvs;\n\tif (norms)\n\t\t*norms = d.norms;\n\n\treturn true;\n}\n\nstd::vector<std::string> ObjFile::GetGroupList() {\n\tstd::vector<std::string> groupList;\n\tgroupList.reserve(data.size());\n\n\tfor (const auto& group : data)\n\t\tgroupList.push_back(group.first);\n\n\treturn groupList;\n}\n"
  },
  {
    "path": "src/files/ObjFile.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"Object3d.hpp\"\n\n#include <fstream>\n#include <map>\n#include <string>\n#include <set>\n\nstruct ObjImportOptions {\n\tbool InvertU = false;\n\tbool InvertV = false;\n\tfloat Scale = 1.0f;\n\tfloat RotateX = 0.0f;\n\tfloat RotateY = 0.0f;\n\tfloat RotateZ = 0.0f;\n\n\tbool ImportAll = true;\n\tstd::set<std::string> ImportShapes;\n\n\tbool NoFaces = false;\n};\n\nstruct ObjData {\n\tstd::string name;\n\tstd::vector<nifly::Vector3> verts;\n\tstd::vector<nifly::Triangle> tris;\n\tstd::vector<nifly::Vector2> uvs;\n\tstd::vector<nifly::Vector3> norms;\n};\n\nclass ObjFile {\n\tstd::map<std::string, ObjData> data;\n\npublic:\n\tnifly::Vector3 scale = nifly::Vector3(1.0f, 1.0f, 1.0f);\n\tnifly::Vector3 offset;\n\n\tint AddGroup(const std::string& name,\n\t\t\t\t const std::vector<nifly::Vector3>& verts,\n\t\t\t\t const std::vector<nifly::Triangle>& tris,\n\t\t\t\t const std::vector<nifly::Vector2>& uvs,\n\t\t\t\t const std::vector<nifly::Vector3>& norms);\n\n\tvoid SetScale(const nifly::Vector3& inScale) { scale = inScale; }\n\tvoid SetOffset(const nifly::Vector3& inOffset) { offset = inOffset; }\n\n\tint LoadForNif(const std::string& fileName, const ObjImportOptions& options = ObjImportOptions());\n\tvoid LoadNoFaces(std::istream& base, const ObjImportOptions& options);\n\tvoid LoadForNif(std::istream& base, const ObjImportOptions& options);\n\n\tint Save(const std::string& fileName);\n\n\tbool CopyDataForGroup(\n\t\tconst std::string& name, std::vector<nifly::Vector3>* v, std::vector<nifly::Triangle>* t, std::vector<nifly::Vector2>* uv, std::vector<nifly::Vector3>* norms);\n\tstd::vector<std::string> GetGroupList();\n};\n"
  },
  {
    "path": "src/files/ResourceLoader.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"../render/GLMaterial.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include \"../FSEngine/FSEngine.h\"\n#include \"../FSEngine/FSManager.h\"\n\n#include <wx/filename.h>\n#include <wx/log.h>\n\nextern ConfigurationManager Config;\n\nResourceLoader::ResourceLoader() {}\n\nResourceLoader::~ResourceLoader() {\n\tCleanup();\n}\n\nbool ResourceLoader::extChecked = false;\n\nGLuint ResourceLoader::LoadTexture(const std::string& inFileName, bool isCubeMap, bool reloadTextures) {\n\tauto ti = textures.find(inFileName);\n\tif (!reloadTextures) {\n\t\t// Return existing texture index\n\t\tif (ti != textures.end())\n\t\t\treturn ti->second;\n\t}\n\n\twxFileName fileName(inFileName);\n\twxString fileExt = fileName.GetExt().Lower();\n\tstd::string fileExtStr = std::string(fileExt.c_str());\n\n\tGLuint textureID = 0;\n\n\t// Get existing index to overwrite texture data for, otherwise generate new index later\n\tif (reloadTextures && ti != textures.end())\n\t\ttextureID = ti->second;\n\n\t// All textures (GLI)\n\tif (fileExtStr == \"dds\" || fileExtStr == \"ktx\")\n\t\ttextureID = GLI_load_texture(inFileName, textureID);\n\n\t// Cubemap fallback (SOIL)\n\tif (!textureID && isCubeMap)\n\t\ttextureID = SOIL_load_OGL_single_cubemap(inFileName.c_str(), SOIL_DDS_CUBEMAP_FACE_ORDER, SOIL_LOAD_AUTO, textureID, SOIL_FLAG_GL_MIPMAPS);\n\n\t// Texture and image fallback (SOIL)\n\tif (!textureID)\n\t\ttextureID = SOIL_load_OGL_texture(inFileName.c_str(), SOIL_LOAD_AUTO, textureID, SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MIPMAPS | SOIL_FLAG_GL_MIPMAPS);\n\n\tif (!textureID && Config.MatchValue(\"BSATextureScan\", \"true\")) {\n\t\tif (Config[\"GameDataPath\"].empty()) {\n\t\t\twxLogWarning(\"Texture file '%s' not found.\", inFileName);\n\t\t\treturn 0;\n\t\t}\n\n\t\twxMemoryBuffer data;\n\t\twxString texFile = inFileName;\n\t\ttexFile.Replace(wxString(Config[\"GameDataPath\"]), \"\");\n\t\ttexFile.Replace(\"\\\\\", \"/\");\n\t\tfor (FSArchiveFile* archive : FSManager::archiveList()) {\n\t\t\tif (archive) {\n\t\t\t\tif (archive->hasFile(texFile.ToStdString())) {\n\t\t\t\t\twxMemoryBuffer outData;\n\t\t\t\t\tarchive->fileContents(texFile.ToStdString(), outData);\n\n\t\t\t\t\tif (!outData.IsEmpty()) {\n\t\t\t\t\t\tdata = std::move(outData);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!data.IsEmpty()) {\n\t\t\tuint8_t* texBuffer = static_cast<uint8_t*>(data.GetData());\n\n\t\t\t// All textures (GLI)\n\t\t\tif (fileExtStr == \"dds\" || fileExtStr == \"ktx\")\n\t\t\t\ttextureID = GLI_load_texture_from_memory((char*)texBuffer, data.GetDataLen(), textureID);\n\n\t\t\t// Cubemap fallback (SOIL)\n\t\t\tif (!textureID && isCubeMap)\n\t\t\t\ttextureID = SOIL_load_OGL_single_cubemap_from_memory(texBuffer, data.GetDataLen(), SOIL_DDS_CUBEMAP_FACE_ORDER, SOIL_LOAD_AUTO, textureID, SOIL_FLAG_GL_MIPMAPS);\n\n\t\t\t// Texture and image fallback (SOIL)\n\t\t\tif (!textureID)\n\t\t\t\ttextureID = SOIL_load_OGL_texture_from_memory(texBuffer,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  data.GetDataLen(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  SOIL_LOAD_AUTO,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  textureID,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  SOIL_FLAG_TEXTURE_REPEATS | SOIL_FLAG_MIPMAPS | SOIL_FLAG_GL_MIPMAPS);\n\t\t}\n\t\telse {\n\t\t\twxLogWarning(\"Texture file '%s' not found.\", inFileName);\n\t\t\treturn 0;\n\t\t}\n\t}\n\telse if (!textureID) {\n\t\twxLogWarning(\"Texture file '%s' not found.\", inFileName);\n\t\treturn 0;\n\t}\n\n\ttextures[inFileName] = textureID;\n\n\treturn textureID;\n}\n\nGLuint ResourceLoader::GenerateTextureID(const std::string& texName) {\n\tDeleteTexture(texName);\n\n\tGLuint textureID;\n\tglGenTextures(1, &textureID);\n\ttextures[texName] = textureID;\n\n\treturn textureID;\n}\n\nGLuint ResourceLoader::GetTexID(const std::string& texName) {\n\tauto ti = textures.find(texName);\n\tif (ti != textures.end())\n\t\treturn ti->second;\n\n\treturn 0;\n}\n\nvoid ResourceLoader::DeleteTexture(const std::string& texName) {\n\tauto ti = textures.find(texName);\n\tif (ti != textures.end()) {\n\t\tcacheTime++;\n\t\tglDeleteTextures(1, &ti->second);\n\t\ttextures.erase(ti);\n\t}\n}\n\nbool ResourceLoader::RenameTexture(const std::string& texNameSrc, const std::string& texNameDest, bool overwrite) {\n\tstd::string src = texNameSrc;\n\tstd::string dst = texNameDest;\n\n\tauto tid = textures.find(dst);\n\tif (tid != textures.end()) {\n\t\tif (!overwrite)\n\t\t\treturn false;\n\n\t\tDeleteTexture(dst);\n\t}\n\n\tauto ti = textures.find(src);\n\tif (ti != textures.end()) {\n\t\t// If a texture is replaced, cacheTime increment by 2 in this function (DeleteTexture also increments it)\n\t\tcacheTime++;\n\t\ttextures[dst] = ti->second;\n\t\ttextures.erase(ti);\n\t}\n\treturn true;\n}\n\n// File extension can be KTX or DDS\nGLuint ResourceLoader::GLI_create_texture(gli::texture& texture, GLuint textureID) {\n\tif (!extGLISupported) {\n\t\tif (!extChecked) {\n\t\t\twxLogWarning(\"OpenGL features required for GLI_create_texture to work aren't there!\");\n\t\t\textChecked = true;\n\t\t}\n\t\treturn textureID;\n\t}\n\n\tgli::gl glProfile(gli::gl::PROFILE_GL33);\n\tgli::gl::format const format = glProfile.translate(texture.format(), texture.swizzles());\n\tGLenum target = glProfile.translate(texture.target());\n\n\tif (textureID == 0)\n\t\tglGenTextures(1, &textureID);\n\n\tglBindTexture(target, textureID);\n\tglTexParameteri(target, GL_TEXTURE_BASE_LEVEL, 0);\n\tglTexParameteri(target, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(texture.levels() - 1));\n\tglTexParameteri(target, GL_TEXTURE_SWIZZLE_R, format.Swizzles[0]);\n\tglTexParameteri(target, GL_TEXTURE_SWIZZLE_G, format.Swizzles[1]);\n\tglTexParameteri(target, GL_TEXTURE_SWIZZLE_B, format.Swizzles[2]);\n\tglTexParameteri(target, GL_TEXTURE_SWIZZLE_A, format.Swizzles[3]);\n\n\tglm::tvec3<GLsizei> const textureExtent(texture.extent());\n\tGLsizei const faceTotal = static_cast<GLsizei>(texture.layers() * texture.faces());\n\n\tswitch (texture.target()) {\n\t\tcase gli::TARGET_1D: glTexStorage1D(target, static_cast<GLint>(texture.levels()), format.Internal, textureExtent.x); break;\n\n\t\tcase gli::TARGET_1D_ARRAY:\n\t\tcase gli::TARGET_2D:\n\t\tcase gli::TARGET_CUBE:\n\t\t\tglTexStorage2D(target, static_cast<GLint>(texture.levels()), format.Internal, textureExtent.x, texture.target() != gli::TARGET_1D_ARRAY ? textureExtent.y : faceTotal);\n\t\t\tbreak;\n\n\t\tcase gli::TARGET_2D_ARRAY:\n\t\tcase gli::TARGET_3D:\n\t\tcase gli::TARGET_CUBE_ARRAY:\n\t\t\tglTexStorage3D(target,\n\t\t\t\t\t\t   static_cast<GLint>(texture.levels()),\n\t\t\t\t\t\t   format.Internal,\n\t\t\t\t\t\t   textureExtent.x,\n\t\t\t\t\t\t   textureExtent.y,\n\t\t\t\t\t\t   texture.target() == gli::TARGET_3D ? textureExtent.z : faceTotal);\n\t\t\tbreak;\n\n\t\tdefault: assert(0); break;\n\t}\n\n\tfor (size_t layer = 0; layer < texture.layers(); ++layer) {\n\t\tfor (size_t face = 0; face < texture.faces(); ++face) {\n\t\t\tfor (size_t level = 0; level < texture.levels(); ++level) {\n\t\t\t\tGLsizei const layerGL = static_cast<GLsizei>(layer);\n\t\t\t\tglm::tvec3<GLsizei> textureLevelExtent(texture.extent(level));\n\t\t\t\ttarget = gli::is_target_cube(texture.target()) ? static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face) : target;\n\n\t\t\t\tswitch (texture.target()) {\n\t\t\t\t\tcase gli::TARGET_1D:\n\t\t\t\t\t\tif (gli::is_compressed(texture.format()))\n\t\t\t\t\t\t\tglCompressedTexSubImage1D(target,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  static_cast<GLint>(level),\n\t\t\t\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  textureLevelExtent.x,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  format.Internal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  static_cast<GLsizei>(texture.size(level)),\n\t\t\t\t\t\t\t\t\t\t\t\t\t  texture.data(layer, face, level));\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tglTexSubImage1D(target, static_cast<GLint>(level), 0, textureLevelExtent.x, format.External, format.Type, texture.data(layer, face, level));\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase gli::TARGET_1D_ARRAY:\n\t\t\t\t\tcase gli::TARGET_2D:\n\t\t\t\t\tcase gli::TARGET_CUBE:\n\t\t\t\t\t\tif (gli::is_compressed(texture.format()))\n\t\t\t\t\t\t\tglCompressedTexSubImage2D(target,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  static_cast<GLint>(level),\n\t\t\t\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  textureLevelExtent.x,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  texture.target() == gli::TARGET_1D_ARRAY ? layerGL : textureLevelExtent.y,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  format.Internal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  static_cast<GLsizei>(texture.size(level)),\n\t\t\t\t\t\t\t\t\t\t\t\t\t  texture.data(layer, face, level));\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tglTexSubImage2D(target,\n\t\t\t\t\t\t\t\t\t\t\tstatic_cast<GLint>(level),\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t\ttextureLevelExtent.x,\n\t\t\t\t\t\t\t\t\t\t\ttexture.target() == gli::TARGET_1D_ARRAY ? layerGL : textureLevelExtent.y,\n\t\t\t\t\t\t\t\t\t\t\tformat.External,\n\t\t\t\t\t\t\t\t\t\t\tformat.Type,\n\t\t\t\t\t\t\t\t\t\t\ttexture.data(layer, face, level));\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase gli::TARGET_2D_ARRAY:\n\t\t\t\t\tcase gli::TARGET_3D:\n\t\t\t\t\tcase gli::TARGET_CUBE_ARRAY:\n\t\t\t\t\t\tif (gli::is_compressed(texture.format()))\n\t\t\t\t\t\t\tglCompressedTexSubImage3D(target,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  static_cast<GLint>(level),\n\t\t\t\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  0,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  textureLevelExtent.x,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  textureLevelExtent.y,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  texture.target() == gli::TARGET_3D ? textureLevelExtent.z : layerGL,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  format.Internal,\n\t\t\t\t\t\t\t\t\t\t\t\t\t  static_cast<GLsizei>(texture.size(level)),\n\t\t\t\t\t\t\t\t\t\t\t\t\t  texture.data(layer, face, level));\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\tglTexSubImage3D(target,\n\t\t\t\t\t\t\t\t\t\t\tstatic_cast<GLint>(level),\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t\t\t\ttextureLevelExtent.x,\n\t\t\t\t\t\t\t\t\t\t\ttextureLevelExtent.y,\n\t\t\t\t\t\t\t\t\t\t\ttexture.target() == gli::TARGET_3D ? textureLevelExtent.z : layerGL,\n\t\t\t\t\t\t\t\t\t\t\tformat.External,\n\t\t\t\t\t\t\t\t\t\t\tformat.Type,\n\t\t\t\t\t\t\t\t\t\t\ttexture.data(layer, face, level));\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault: assert(0); break;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn textureID;\n}\n\nGLuint ResourceLoader::GLI_load_texture(const std::string& fileName, GLuint textureID) {\n\tgli::texture texture = gli::load(fileName);\n\tif (texture.empty())\n\t\treturn textureID;\n\n\treturn GLI_create_texture(texture, textureID);\n}\n\nGLuint ResourceLoader::GLI_load_texture_from_memory(const char* buffer, size_t size, GLuint textureID) {\n\tgli::texture texture = gli::load(buffer, size);\n\tif (texture.empty())\n\t\treturn textureID;\n\n\treturn GLI_create_texture(texture, textureID);\n}\n\nGLMaterial* ResourceLoader::AddMaterial(const std::vector<std::string>& textureFiles, const std::string& vShaderFile, const std::string& fShaderFile, const bool reloadTextures) {\n\tauto texFiles = textureFiles;\n\n\tMaterialKey key(texFiles, vShaderFile, fShaderFile);\n\tif (!reloadTextures) {\n\t\tauto it = materials.find(key);\n\t\tif (it != materials.end())\n\t\t\treturn it->second.get();\n\t}\n\n\tstd::vector<GLuint> texRefs(texFiles.size(), 0);\n\tfor (size_t i = 0; i < texFiles.size(); i++) {\n\t\tif (texFiles[i].empty())\n\t\t\tcontinue;\n\n\t\tbool isCubeMap = (i == 4);\n\t\tGLuint textureID = LoadTexture(texFiles[i], isCubeMap, reloadTextures);\n\t\tif (!textureID)\n\t\t\tcontinue;\n\n\t\ttexRefs[i] = textureID;\n\t}\n\n\t// No diffuse found\n\tif (texRefs.empty())\n\t\ttexRefs.resize(1, 0);\n\n\tif (texRefs[0] == 0) {\n\t\t// Load default image\n\t\tstd::string defaultTex = Config[\"AppDir\"] + \"/res/images/NoImg.png\";\n\n\t\ttexRefs[0] = LoadTexture(defaultTex, false);\n\n\t\tif (!texFiles.empty())\n\t\t\ttexFiles[0] = defaultTex;\n\t\telse\n\t\t\ttexFiles.resize(1, defaultTex);\n\t}\n\n\tauto& entry = materials[key];\n\tif (!entry || !reloadTextures)\n\t\tentry.reset(new GLMaterial(this, texFiles, vShaderFile, fShaderFile));\n\n\treturn entry.get();\n}\n\nvoid ResourceLoader::Cleanup() {\n\tfor (auto& tp : textures)\n\t\tglDeleteTextures(1, &tp.second);\n\n\ttextures.clear();\n\tmaterials.clear();\n}\n\nsize_t ResourceLoader::MatKeyHash::operator()(const MaterialKey& key) const {\n\tstd::hash<std::string> strHash;\n\tsize_t resHash = strHash(std::get<1>(key)) ^ strHash(std::get<2>(key));\n\n\tfor (size_t i = 0; i < std::get<0>(key).size(); i++)\n\t\tresHash ^= strHash(std::get<0>(key)[i]);\n\n\treturn resHash;\n}\n"
  },
  {
    "path": "src/files/ResourceLoader.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <map>\n#include <memory>\n#include <string>\n#include <unordered_map>\n\n#include \"../utils/StringStuff.h\"\n\n#include <../SOIL2/SOIL2.h>\n#include <gli.hpp>\n\ntypedef unsigned int GLuint;\nclass GLMaterial;\n\nclass ResourceLoader {\npublic:\n\tResourceLoader();\n\t~ResourceLoader();\n\n\tGLMaterial* AddMaterial(const std::vector<std::string>& textureFiles, const std::string& vShaderFile, const std::string& fShaderFile, const bool reloadTextures = false);\n\n\n\t//Central Point for loading texture files.  Calls appropriate resource loading subroutine, and\n\t// tracks the resulting GL texture identifier so subsequent access to the same texture does not result\n\t// in a new load.\n\tGLuint LoadTexture(const std::string& fileName, bool isCubeMap = false, bool reloadTextures = false);\n\n\t// The following functions manage non-file-sourced texture ids.  This facilitates named textures generated\n\t//  within the program either for temporary use (generate/delete) or persistent use\n\tGLuint GenerateTextureID(const std::string& texName);\n\n\tGLuint GetTexID(const std::string& texName);\n\n\n\t/* The following functions update cacheTime, which will cause any linked material to re-search for texture ids.\n\t\twhile this is not a tremendous performance impact, these functions should not be called every frame.\n\t\tFunctions above (that add new textures) do NOT update the cacheTime, because old Texture IDs remain valid.\n\t\t*/\n\n\t// Deletes all materials and textures.\n\tvoid Cleanup();\n\t// Deletes a specfic texture and removes it from video memory.\n\tvoid DeleteTexture(const std::string& texName);\n\t// rename texture moves the internal texture id to a new name. this allows a function to safely 'steal' a\n\t//  texture generated elsewhere.  EG: in GLOffscreenBuffer, while the buffer is active, one of the textures\n\t//  generated can be renamed to prevent the texture from being deleted when the object is deleted, so it can\n\t//  be used elsewhere.\n\t//  Fails if texture already exist and overwrite is not set to true.\n\tbool RenameTexture(const std::string& texNameSrc, const std::string& texNameDest, bool overwrite = false);\n\n\n\t// compares the incoming cacheTime with the internal cacheTime, and returns true if they match.\n\t//  if they do not match, the incoming cacheTime is updated to match and the function returns false.\n\tbool CacheStamp(int64_t& inCacheTime) {\n\t\tif (cacheTime == inCacheTime)\n\t\t\treturn true;\n\t\telse {\n\t\t\tinCacheTime = cacheTime;\n\t\t\treturn false;\n\t\t}\n\t}\n\nprivate:\n\tstatic bool extChecked;\n\tGLuint GLI_create_texture(gli::texture& texture, GLuint textureID = 0);\n\tGLuint GLI_load_texture(const std::string& fileName, GLuint textureID = 0);\n\tGLuint GLI_load_texture_from_memory(const char* buffer, size_t size, GLuint textureID = 0);\n\n\t// If N3983 gets accepted into a future C++ standard then\n\t// we wouldn't have to explicitly define our own hash here.\n\ttypedef std::tuple<std::vector<std::string>, std::string, std::string> MaterialKey;\n\tstruct MatKeyHash {\n\t\tsize_t operator()(const MaterialKey& key) const;\n\t};\n\ttypedef std::unordered_map<MaterialKey, std::unique_ptr<GLMaterial>, MatKeyHash> MaterialCache;\n\t// defining texture cache like this both for consitency, might also make it easier to add features like\n\t// reference tracking later.  For now, Textures are only unloaded when ResourceLoader is destroyed.\n\ttypedef std::map<std::string, GLuint, case_insensitive_compare> TextureCache;\n\n\tTextureCache textures;\n\tMaterialCache materials;\n\n\tint64_t cacheTime = 1;\n};\n"
  },
  {
    "path": "src/files/SFMorphFile.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SFMorphFile.h\"\n#include \"../utils/PlatformUtil.h\"\n\n#include \"half.hpp\"\n\n#include <array>\n\nusing namespace nifly;\n\nstatic std::vector<uint32_t> BinaryPositions(uint32_t* n, uint32_t length) {\n\tstd::vector<uint32_t> positions;\n\tuint32_t count = 0;\n\tfor (size_t i = 0; i < length; i++) {\n\t\tuint32_t _n = n[i];\n\t\tfor (int j = 0; j < 32; j++) {\n\t\t\tif (_n & 1) {\n\t\t\t\tpositions.push_back(count);\n\t\t\t}\n\t\t\tcount++;\n\t\t\t_n >>= 1;\n\t\t}\n\t}\n\treturn positions;\n}\n\nstatic Vector3 DecodeUDEC3(const uint32_t data) {\n\tVector3 vec;\n\tvec.x = static_cast<float>(((data & 1023) / 511.5) - 1.0);\n\tvec.y = static_cast<float>((((data >> 10) & 1023) / 511.5) - 1.0);\n\tvec.z = static_cast<float>((((data >> 20) & 1023) / 511.5) - 1.0);\n\treturn vec;\n}\n\nstatic uint32_t EncodeUDEC3(const Vector3& vec) {\n\tuint32_t data = 0;\n\tdata |= static_cast<std::uint32_t>((vec.x + 1.0f) * 511.5f) & 1023;\n\tdata |= (static_cast<std::uint32_t>((vec.y + 1.0f) * 511.5f) & 1023) << 10;\n\tdata |= (static_cast<std::uint32_t>((vec.z + 1.0f) * 511.5f) & 1023) << 20;\n\n\tdata |= static_cast<uint8_t>(1.0f) << 30;\n\treturn data;\n}\n\nstatic std::uint16_t EncodeRGB565(uint8_t r, uint8_t g, uint8_t b) {\n\tuint16_t rgb565 = 0;\n\n\trgb565 |= (r >> 3) << 11;\n\trgb565 |= (g >> 2) << 5;\n\trgb565 |= (b >> 3) << 0;\n\n\treturn rgb565;\n}\n\nstatic void DecodeRGB565(uint16_t rgb565, uint8_t& r, uint8_t& g, uint8_t& b) {\n\tr = (rgb565 >> 11) << 3;\n\tg = ((rgb565 >> 5) & 0x3F) << 2;\n\tb = (rgb565 & 0x1F) << 3;\n}\n\nbool SFMorphFile::Read(const std::string& fileName) {\n\tstd::fstream morphFile;\n\tPlatformUtil::OpenFileStream(morphFile, fileName, std::ios::in | std::ios::binary);\n\n\tif (!morphFile.is_open())\n\t\treturn false;\n\n\tchar hdr[4];\n\tmorphFile.read(hdr, 4);\n\n\tuint32_t magic = \"TADM\"_mci; // MDAT\n\tif (memcmp(hdr, &magic, 4) != 0)\n\t\treturn false;\n\n\tmorphFile.read((char*)&numAxis, sizeof(numAxis)); // Unknown. Always 3?\n\tmorphFile.read((char*)&numVertices, sizeof(numVertices));\n\tmorphFile.read((char*)&numShapeKeys, sizeof(numShapeKeys));\n\n\tfor (size_t i = 0; i < numShapeKeys; i++) {\n\t\tuint32_t morphNameLength = 0;\n\t\tmorphFile.read((char*)&morphNameLength, sizeof(morphNameLength));\n\n\t\tstd::string morphName;\n\t\tmorphName.resize(morphNameLength, ' ');\n\t\tif (morphNameLength > 0)\n\t\t\tmorphFile.read((char*)&morphName.front(), morphNameLength);\n\n\t\tmorphNames.push_back(morphName);\n\t}\n\n\tmorphFile.read((char*)&numMorphData, sizeof(numMorphData));\n\tmorphFile.read((char*)&numOffsets, sizeof(numOffsets)); // Must always match numVertices?\n\n\tmorphDataRaw.resize(numMorphData);\n\tmorphFile.read((char*)morphDataRaw.data(), sizeof(SFMorphData) * numMorphData);\n\n\toffsets.resize(numOffsets);\n\tmorphFile.read((char*)offsets.data(), sizeof(SFMorphOffset) * numOffsets);\n\n\treturn true;\n}\n\nbool SFMorphFile::Write(const std::string& fileName) {\n\tstd::fstream morphFile;\n\tPlatformUtil::OpenFileStream(morphFile, fileName, std::ios::out | std::ios::binary);\n\n\tif (!morphFile.is_open())\n\t\treturn false;\n\n\tuint32_t hdr = \"TADM\"_mci;\n\tmorphFile.write((char*)&hdr, sizeof(hdr));\n\n\tmorphFile.write((char*)&numAxis, sizeof(numAxis)); // Unknown. Always 3?\n\tmorphFile.write((char*)&numVertices, sizeof(numVertices));\n\n\tnumShapeKeys = static_cast<uint32_t>(morphNames.size());\n\tmorphFile.write((char*)&numShapeKeys, sizeof(numShapeKeys));\n\n\tfor (auto& morphName : morphNames) {\n\t\tuint32_t morphNameLength = static_cast<uint32_t>(morphName.length());\n\t\tmorphFile.write((char*)&morphNameLength, sizeof(morphNameLength));\n\t\tif (morphNameLength > 0)\n\t\t\tmorphFile.write(morphName.c_str(), morphNameLength);\n\t}\n\n\tnumMorphData = static_cast<uint32_t>(morphDataRaw.size());\n\tmorphFile.write((char*)&numMorphData, sizeof(numMorphData));\n\n\tnumOffsets = numVertices;\n\tmorphFile.write((char*)&numOffsets, sizeof(numOffsets)); // Must always match numVertices?\n\n\tmorphFile.write((char*)morphDataRaw.data(), sizeof(SFMorphData) * numMorphData);\n\tmorphFile.write((char*)offsets.data(), sizeof(SFMorphOffset) * numOffsets);\n\n\treturn true;\n}\n\nbool SFMorphFile::FileToCacheData() {\n\tmorphDataRawUnpacked.resize(numMorphData);\n\n\tfor (size_t i = 0; i < numMorphData; i++) {\n\t\tconst SFMorphData& morphData = morphDataRaw[i];\n\t\tSFMorphDataUnpacked& morphDataUnpacked = morphDataRawUnpacked[i];\n\n\t\tmorphDataUnpacked.offset.x = (float)*((half_float::half*)&morphData.offset[0]);\n\t\tmorphDataUnpacked.offset.y = (float)*((half_float::half*)&morphData.offset[1]);\n\t\tmorphDataUnpacked.offset.z = (float)*((half_float::half*)&morphData.offset[2]);\n\n\t\tDecodeRGB565(morphData.targetVertColor, morphDataUnpacked.targetVertColor.r, morphDataUnpacked.targetVertColor.g, morphDataUnpacked.targetVertColor.b);\n\n\t\tmorphDataUnpacked.normal = DecodeUDEC3(morphData.x);\n\t\tmorphDataUnpacked.tangent = DecodeUDEC3(morphData.y);\n\t}\n\n\tsize_t morphDataSize = 0;\n\n\tfor (size_t i = 0; i < numVertices; i++) {\n\t\tint size = 0;\n\t\tif (numVertices > 0 && i != numVertices - 1)\n\t\t\tsize = offsets[i + 1].offset - offsets[i].offset;\n\t\telse\n\t\t\tsize = numMorphData - offsets[i].offset;\n\n\t\tstd::vector<SFMorphData> morphData;\n\t\tstd::vector<SFMorphDataUnpacked> morphDataUnpacked;\n\t\tstd::vector<uint32_t> morphKeyIndices = BinaryPositions((uint32_t*)offsets[i].keyMarker, 4);\n\n\t\tif (!morphKeyIndices.empty() && morphKeyIndices.back() >= numShapeKeys) {\n\t\t\t// Invalid morph key index\n\t\t\treturn false;\n\t\t}\n\n\t\tuint32_t t = offsets[i].offset;\n\n\t\tfor (size_t j = 0; j < size; j++) {\n\t\t\tmorphData.push_back(morphDataRaw[t + j]);\n\t\t\tmorphDataUnpacked.push_back(morphDataRawUnpacked[t + j]);\n\t\t}\n\n\t\tvertexMorphData.push_back(morphData);\n\t\tvertexMorphDataUnpacked.push_back(morphDataUnpacked);\n\n\t\tvertexMorphKeyIndices.push_back(morphKeyIndices);\n\t\tmorphDataSize += morphKeyIndices.size();\n\t}\n\n\tif (numMorphData != 1 && morphDataSize != numMorphData) {\n\t\t// Invalid morph data size\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid SFMorphFile::CacheToFileData() {\n\t// Traditional scale based on havok to unit transform used in skyrim, fallout, etc. In Starfield mesh files are normalized to metric units,\n\t// this scale makes default vertex positions closely match the older games\n\tconst float havokScale = 69.969f;\n\t// experimentally, the below scale produced very accurate values to SSE mesh sizes (comparing markerxheading.nif)\n\t// const float havokScale = 69.9866f;\n\n\tmorphDataRaw.clear();\n\tmorphDataRawUnpacked.clear();\n\tvertexMorphData.clear();\n\tvertexMorphDataUnpacked.clear();\n\tvertexMorphKeyIndices.clear();\n\n\tconstexpr size_t maxVertIndex = std::numeric_limits<uint16_t>().max();\n\n\tuint16_t numVerticesShort;\n\tif (numVertices <= maxVertIndex)\n\t\tnumVerticesShort = static_cast<uint16_t>(numVertices);\n\telse\n\t\tnumVerticesShort = maxVertIndex;\n\n\tnumShapeKeys = static_cast<uint32_t>(morphNames.size());\n\n\tfor (uint16_t i = 0; i < numVerticesShort; i++) {\n\t\tstd::vector<uint32_t> morphKeyIndices;\n\n\t\tuint32_t morphKey = 0;\n\t\tfor (auto& morph : morphNames) {\n\t\t\tif (morphKeyIndices.size() < 128) {\n\t\t\t\tauto& morphIndex = morphNamesCacheMap[morph];\n\n\t\t\t\tauto& morphOffsets = morphOffsetsCache[morphIndex];\n\t\t\t\tauto& morphColors = morphColorsCache[morphIndex];\n\t\t\t\tauto& morphNormals = morphNormalsCache[morphIndex];\n\t\t\t\tauto& morphTangents = morphTangentsCache[morphIndex];\n\n\t\t\t\tauto morphOffsetIt = morphOffsets.find(i);\n\t\t\t\tif (morphOffsetIt != morphOffsets.end()) {\n\t\t\t\t\tif (std::fabs(morphOffsetIt->second.x) > EPSILON || std::fabs(morphOffsetIt->second.y) > EPSILON || std::fabs(morphOffsetIt->second.z) > EPSILON) {\n\t\t\t\t\t\tSFMorphData morphData{};\n\n\t\t\t\t\t\thalf_float::half hx(morphOffsetIt->second.x / havokScale);\n\t\t\t\t\t\thalf_float::half hy(morphOffsetIt->second.y / havokScale);\n\t\t\t\t\t\thalf_float::half hz(morphOffsetIt->second.z / havokScale);\n\t\t\t\t\t\tmorphData.offset[0] = *reinterpret_cast<uint16_t*>(&hx);\n\t\t\t\t\t\tmorphData.offset[1] = *reinterpret_cast<uint16_t*>(&hy);\n\t\t\t\t\t\tmorphData.offset[2] = *reinterpret_cast<uint16_t*>(&hz);\n\n\t\t\t\t\t\tauto morphColorIt = morphColors.find(i);\n\t\t\t\t\t\tif (morphColorIt != morphColors.end()) {\n\t\t\t\t\t\t\tnifly::ByteColor3 color;\n\n\t\t\t\t\t\t\tfloat f = std::max(0.0f, std::min(1.0f, morphColorIt->second.r));\n\t\t\t\t\t\t\tcolor.r = static_cast<uint8_t>(std::floor(f == 1.0f ? 255 : f * 256.0));\n\n\t\t\t\t\t\t\tf = std::max(0.0f, std::min(1.0f, morphColorIt->second.g));\n\t\t\t\t\t\t\tcolor.g = static_cast<uint8_t>(std::floor(f == 1.0f ? 255 : f * 256.0));\n\n\t\t\t\t\t\t\tf = std::max(0.0f, std::min(1.0f, morphColorIt->second.b));\n\t\t\t\t\t\t\tcolor.b = static_cast<uint8_t>(std::floor(f == 1.0f ? 255 : f * 256.0));\n\n\t\t\t\t\t\t\tmorphData.targetVertColor = EncodeRGB565(color.r, color.g, color.b);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tauto morphNormalIt = morphNormals.find(i);\n\t\t\t\t\t\tif (morphNormalIt != morphNormals.end())\n\t\t\t\t\t\t\tmorphData.x = EncodeUDEC3(morphNormalIt->second);\n\n\t\t\t\t\t\tauto morphTangentIt = morphTangents.find(i);\n\t\t\t\t\t\tif (morphTangentIt != morphTangents.end())\n\t\t\t\t\t\t\tmorphData.y = EncodeUDEC3(morphTangentIt->second);\n\n\t\t\t\t\t\tmorphDataRaw.push_back(morphData);\n\n\t\t\t\t\t\tmorphKeyIndices.push_back(morphKey);\n\t\t\t\t\t\tmorphKey++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tvertexMorphKeyIndices.push_back(morphKeyIndices);\n\t}\n\n\tnumMorphData = static_cast<uint32_t>(morphDataRaw.size());\n\n\tuint32_t offset = 0;\n\tfor (uint16_t i = 0; i < numVerticesShort; i++) {\n\t\tSFMorphOffset offsetData{};\n\t\toffsetData.offset = offset;\n\n\t\tauto& morphKeyIndices = vertexMorphKeyIndices[i];\n\n\t\tstd::array<uint32_t, 4> binaryMarkers{};\n\t\tfor (int p = 0; p < morphKeyIndices.size(); p++)\n\t\t\tbinaryMarkers[morphKeyIndices[p] / 32] |= 1 << (morphKeyIndices[p] % 32);\n\n\t\toffsetData.keyMarker[0] = static_cast<SFMorphKey>(binaryMarkers[0]);\n\t\toffsetData.keyMarker[1] = static_cast<SFMorphKey>(binaryMarkers[1]);\n\t\toffsetData.keyMarker[2] = static_cast<SFMorphKey>(binaryMarkers[2]);\n\t\toffsetData.keyMarker[3] = static_cast<SFMorphKey>(binaryMarkers[3]);\n\n\t\toffsets.push_back(offsetData);\n\t\toffset += static_cast<uint32_t>(morphKeyIndices.size());\n\t}\n}\n\nvoid SFMorphFile::UpdateCachedMorphData() {\n\tif (morphOffsetsCache.empty()) {\n\t\t// Traditional scale based on havok to unit transform used in skyrim, fallout, etc. In Starfield mesh files are normalized to metric units,\n\t\t// this scale makes default vertex positions closely match the older games\n\t\tconst float havokScale = 69.969f;\n\t\t// experimentally, the below scale produced very accurate values to SSE mesh sizes (comparing markerxheading.nif)\n\t\t// const float havokScale = 69.9866f;\n\n\t\tif (numVertices <= std::numeric_limits<uint16_t>().max()) {\n\t\t\tstd::unordered_map<uint16_t, Vector3> diff;\n\t\t\tfor (uint16_t i = 0; i < numVertices; i++) {\n\t\t\t\tauto& indices = vertexMorphKeyIndices[i];\n\t\t\t\tfor (int j = 0; j < indices.size(); ++j) {\n\t\t\t\t\tauto& id = indices[j];\n\t\t\t\t\tauto& morphName = morphNames[id];\n\t\t\t\t\tauto& data = vertexMorphDataUnpacked[i][j];\n\n\t\t\t\t\tVector3 offset(data.offset * havokScale);\n\t\t\t\t\tColor3 targetVertColor(data.targetVertColor.r / 255.0f, data.targetVertColor.g / 255.0f, data.targetVertColor.b / 255.0f);\n\n\t\t\t\t\tauto morphCacheIt = morphNamesCacheMap.find(morphName);\n\t\t\t\t\tif (morphCacheIt == morphNamesCacheMap.end()) {\n\t\t\t\t\t\tmorphNamesCacheMap[morphName] = static_cast<uint32_t>(morphOffsetsCache.size());\n\t\t\t\t\t\tmorphOffsetsCache.emplace_back()[i] = offset;\n\t\t\t\t\t\tmorphColorsCache.emplace_back()[i] = targetVertColor;\n\t\t\t\t\t\tmorphNormalsCache.emplace_back()[i] = data.normal;\n\t\t\t\t\t\tmorphTangentsCache.emplace_back()[i] = data.tangent;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tmorphOffsetsCache[morphCacheIt->second][i] = offset;\n\t\t\t\t\t\tmorphColorsCache[morphCacheIt->second][i] = targetVertColor;\n\t\t\t\t\t\tmorphNormalsCache[morphCacheIt->second][i] = data.normal;\n\t\t\t\t\t\tmorphTangentsCache[morphCacheIt->second][i] = data.tangent;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool SFMorphFile::AddMorph(const std::string& morphName,\n\t\t\t\t\t\t   const std::unordered_map<uint16_t, nifly::Vector3>& morphOffsets,\n\t\t\t\t\t\t   const std::unordered_map<uint16_t, nifly::Color3>& morphColors,\n\t\t\t\t\t\t   const std::unordered_map<uint16_t, nifly::Vector3>& morphNormals,\n\t\t\t\t\t\t   const std::unordered_map<uint16_t, nifly::Vector3>& morphTangents) {\n\tauto morphIt = morphNamesCacheMap.find(morphName);\n\tif (morphIt != morphNamesCacheMap.end())\n\t\treturn false;\n\n\tmorphNamesCacheMap[morphName] = static_cast<uint32_t>(morphOffsetsCache.size());\n\tmorphNames.push_back(morphName);\n\n\tmorphOffsetsCache.push_back(morphOffsets);\n\tmorphColorsCache.push_back(morphColors);\n\tmorphNormalsCache.push_back(morphNormals);\n\tmorphTangentsCache.push_back(morphTangents);\n\treturn true;\n}\n\nuint32_t SFMorphFile::GetMorphCount() {\n\treturn numShapeKeys;\n}\n\nstd::vector<std::string> SFMorphFile::GetMorphNames() {\n\treturn morphNames;\n}\n"
  },
  {
    "path": "src/files/SFMorphFile.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"Object3d.hpp\"\n\n#include <algorithm>\n#include <fstream>\n#include <unordered_map>\n#include <map>\n#include <memory>\n\nenum SFMorphKey : uint32_t {\n\tNone = 0,\n\tMorph0 = 1 << 0,\n\tMorph1 = 1 << 1,\n\tMorph2 = 1 << 2,\n\tMorph3 = 1 << 3,\n\tMorph4 = 1 << 4,\n\tMorph5 = 1 << 5,\n\tMorph6 = 1 << 6,\n\tMorph7 = 1 << 7,\n\tMorph8 = 1 << 8,\n\tMorph9 = 1 << 9,\n\tMorph10 = 1 << 10,\n\tMorph11 = 1 << 11,\n\tMorph12 = 1 << 12,\n\tMorph13 = 1 << 13,\n\tMorph14 = 1 << 14,\n\tMorph15 = 1 << 15,\n\tMorph16 = 1 << 16,\n\tMorph17 = 1 << 17,\n\tMorph18 = 1 << 18,\n\tMorph19 = 1 << 19,\n\tMorph20 = 1 << 20,\n\tMorph21 = 1 << 21,\n\tMorph22 = 1 << 22,\n\tMorph23 = 1 << 23,\n\tMorph24 = 1 << 24,\n\tMorph25 = 1 << 25,\n\tMorph26 = 1 << 26,\n\tMorph27 = 1 << 27,\n\tMorph28 = 1 << 28,\n\tMorph29 = 1 << 29,\n\tMorph30 = 1 << 30,\n\tMorph31 = static_cast<uint32_t>(1) << 31\n};\n\nstruct SFMorphData {\n\tuint16_t offset[3]{0, 0, 0};\n\tuint16_t targetVertColor = 0;\n\tuint32_t x = 0, y = 0;\n};\n\nstruct SFMorphDataUnpacked {\n\tnifly::Vector3 offset;\n\tnifly::ByteColor3 targetVertColor;\n\tnifly::Vector3 normal;\n\tnifly::Vector3 tangent;\n};\n\nstruct SFMorphOffset {\n\tuint32_t offset = 0;\n\tSFMorphKey keyMarker[4];\n};\n\nclass SFMorphFile {\n\tuint32_t numAxis = 3;\n\tuint32_t numShapeKeys = 0;\n\tuint32_t numVertices = 0;\n\n\tstd::vector<std::string> morphNames;\n\tuint32_t numMorphData = 0;\n\tuint32_t numOffsets = 0;\n\n\tstd::vector<SFMorphData> morphDataRaw;\n\tstd::vector<SFMorphDataUnpacked> morphDataRawUnpacked;\n\tstd::vector<SFMorphOffset> offsets;\n\n\tstd::vector<std::vector<SFMorphData>> vertexMorphData;\n\tstd::vector<std::vector<SFMorphDataUnpacked>> vertexMorphDataUnpacked;\n\tstd::vector<std::vector<uint32_t>> vertexMorphKeyIndices;\n\npublic:\n\tstd::map<std::string, uint32_t> morphNamesCacheMap;\n\tstd::vector<std::unordered_map<uint16_t, nifly::Vector3>> morphOffsetsCache;\n\tstd::vector<std::unordered_map<uint16_t, nifly::Color3>> morphColorsCache;\n\tstd::vector<std::unordered_map<uint16_t, nifly::Vector3>> morphNormalsCache;\n\tstd::vector<std::unordered_map<uint16_t, nifly::Vector3>> morphTangentsCache;\n\n\tbool Read(const std::string& fileName);\n\tbool Write(const std::string& fileName);\n\n\tvoid CacheToFileData();\n\tbool FileToCacheData();\n\n\tvoid UpdateCachedMorphData();\n\n\tuint32_t GetMorphCount();\n\tstd::vector<std::string> GetMorphNames();\n\n\tvoid SetVertexCount(uint32_t vertexCount) {\n\t\tnumVertices = vertexCount;\n\t\tnumOffsets = numVertices;\n\t}\n\n\tbool AddMorph(const std::string& morphName,\n\t\t\t\t  const std::unordered_map<uint16_t, nifly::Vector3>& morphOffsets,\n\t\t\t\t  const std::unordered_map<uint16_t, nifly::Color3>& morphColors,\n\t\t\t\t  const std::unordered_map<uint16_t, nifly::Vector3>& morphNormals,\n\t\t\t\t  const std::unordered_map<uint16_t, nifly::Vector3>& morphTangents);\n};\n\n"
  },
  {
    "path": "src/files/TriFile.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"TriFile.h\"\n#include \"../utils/PlatformUtil.h\"\n\nusing namespace nifly;\n\nbool IsBodyTriFile(const std::string& fileName) {\n\tstd::fstream triFile;\n\tPlatformUtil::OpenFileStream(triFile, fileName, std::ios::in | std::ios::binary);\n\n\tif (triFile.is_open()) {\n\t\tchar hdr[4];\n\t\ttriFile.read(hdr, 4);\n\n\t\tuint32_t magic = \"TRIP\"_mci;\n\t\tif (memcmp(hdr, &magic, 4) != 0)\n\t\t\treturn false;\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nbool TriFile::Read(const std::string& fileName) {\n\tstd::fstream triFile;\n\tPlatformUtil::OpenFileStream(triFile, fileName, std::ios::in | std::ios::binary);\n\n\tif (triFile.is_open()) {\n\t\tchar hdr[4];\n\t\ttriFile.read(hdr, 4);\n\n\t\tuint32_t magic = \"TRIP\"_mci;\n\t\tif (memcmp(hdr, &magic, 4) != 0)\n\t\t\treturn false;\n\n\t\t// Load position offsets\n\t\tuint16_t shapeCount = 0;\n\t\ttriFile.read((char*)&shapeCount, 2);\n\n\t\tfor (int i = 0; i < shapeCount; i++) {\n\t\t\tuint8_t shapeLength = 0;\n\t\t\tstd::string shapeName;\n\t\t\ttriFile.read((char*)&shapeLength, 1);\n\t\t\tshapeName.resize(shapeLength, ' ');\n\t\t\tif (shapeLength > 0)\n\t\t\t\ttriFile.read((char*)&shapeName.front(), shapeLength);\n\n\t\t\tuint16_t morphCount = 0;\n\t\t\ttriFile.read((char*)&morphCount, 2);\n\n\t\t\tfor (int j = 0; j < morphCount; j++) {\n\t\t\t\tuint8_t morphLength = 0;\n\t\t\t\tstd::string morphName;\n\t\t\t\ttriFile.read((char*)&morphLength, 1);\n\t\t\t\tmorphName.resize(morphLength, ' ');\n\t\t\t\tif (morphLength > 0)\n\t\t\t\t\ttriFile.read((char*)&morphName.front(), morphLength);\n\n\t\t\t\tstd::map<uint16_t, Vector3> morphOffsets;\n\t\t\t\tfloat mult = 0.0f;\n\t\t\t\tuint16_t morphVertCount = 0;\n\t\t\t\ttriFile.read((char*)&mult, 4);\n\t\t\t\ttriFile.read((char*)&morphVertCount, 2);\n\n\t\t\t\tfor (int k = 0; k < morphVertCount; k++) {\n\t\t\t\t\tuint16_t id = 0;\n\t\t\t\t\tshort x = 0;\n\t\t\t\t\tshort y = 0;\n\t\t\t\t\tshort z = 0;\n\t\t\t\t\ttriFile.read((char*)&id, 2);\n\t\t\t\t\ttriFile.read((char*)&x, 2);\n\t\t\t\t\ttriFile.read((char*)&y, 2);\n\t\t\t\t\ttriFile.read((char*)&z, 2);\n\n\t\t\t\t\tVector3 offset = Vector3(x * mult, y * mult, z * mult);\n\t\t\t\t\tif (!offset.IsZero(true))\n\t\t\t\t\t\tmorphOffsets.emplace(id, offset);\n\t\t\t\t}\n\n\t\t\t\tif (morphOffsets.size() > 0) {\n\t\t\t\t\tMorphDataPtr morph = std::make_shared<MorphData>();\n\t\t\t\t\tmorph->name = morphName;\n\t\t\t\t\tmorph->type = MORPHTYPE_POSITION;\n\t\t\t\t\tmorph->offsets = morphOffsets;\n\t\t\t\t\tAddMorph(shapeName, morph);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Load UV offsets if EOF wasn't reached\n\t\tif (!triFile.eof()) {\n\t\t\tuint16_t shapeCountUV = 0;\n\t\t\ttriFile.read((char*)&shapeCountUV, 2);\n\n\t\t\tfor (int i = 0; i < shapeCountUV; i++) {\n\t\t\t\tuint8_t shapeLength = 0;\n\t\t\t\tstd::string shapeName;\n\t\t\t\ttriFile.read((char*)&shapeLength, 1);\n\t\t\t\tshapeName.resize(shapeLength, ' ');\n\t\t\t\tif (shapeLength > 0)\n\t\t\t\t\ttriFile.read((char*)&shapeName.front(), shapeLength);\n\n\t\t\t\tuint16_t morphCount = 0;\n\t\t\t\ttriFile.read((char*)&morphCount, 2);\n\n\t\t\t\tfor (int j = 0; j < morphCount; j++) {\n\t\t\t\t\tuint8_t morphLength = 0;\n\t\t\t\t\tstd::string morphName;\n\t\t\t\t\ttriFile.read((char*)&morphLength, 1);\n\t\t\t\t\tmorphName.resize(morphLength, ' ');\n\t\t\t\t\tif (morphLength > 0)\n\t\t\t\t\t\ttriFile.read((char*)&morphName.front(), morphLength);\n\n\t\t\t\t\tstd::map<uint16_t, Vector3> morphOffsets;\n\t\t\t\t\tfloat mult = 0.0f;\n\t\t\t\t\tuint16_t morphVertCount = 0;\n\t\t\t\t\ttriFile.read((char*)&mult, 4);\n\t\t\t\t\ttriFile.read((char*)&morphVertCount, 2);\n\n\t\t\t\t\tfor (int k = 0; k < morphVertCount; k++) {\n\t\t\t\t\t\tuint16_t id = 0;\n\t\t\t\t\t\tshort x = 0;\n\t\t\t\t\t\tshort y = 0;\n\t\t\t\t\t\ttriFile.read((char*)&id, 2);\n\t\t\t\t\t\ttriFile.read((char*)&x, 2);\n\t\t\t\t\t\ttriFile.read((char*)&y, 2);\n\n\t\t\t\t\t\tVector3 offset = Vector3(x * mult, y * mult, 0.0f);\n\t\t\t\t\t\tif (!offset.IsZero(true))\n\t\t\t\t\t\t\tmorphOffsets.emplace(id, offset);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (morphOffsets.size() > 0) {\n\t\t\t\t\t\tMorphDataPtr morph = std::make_shared<MorphData>();\n\t\t\t\t\t\tmorph->name = morphName;\n\t\t\t\t\t\tmorph->type = MORPHTYPE_UV;\n\t\t\t\t\t\tmorph->offsets = morphOffsets;\n\t\t\t\t\t\tAddMorph(shapeName, morph);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nbool TriFile::Write(const std::string& fileName) {\n\tstd::fstream triFile;\n\tPlatformUtil::OpenFileStream(triFile, fileName, std::ios::out | std::ios::binary);\n\n\tif (triFile.is_open()) {\n\t\tuint32_t hdr = \"TRIP\"_mci;\n\t\ttriFile.write((char*)&hdr, 4);\n\n\t\tuint16_t shapeCount = GetShapeCount(MORPHTYPE_POSITION);\n\t\ttriFile.write((char*)&shapeCount, 2);\n\n\t\t// Write position offsets\n\t\tif (shapeCount > 0) {\n\t\t\tfor (auto& shape : shapeMorphs) {\n\t\t\t\tuint16_t morphCount = GetMorphCount(shape.first, MORPHTYPE_POSITION);\n\t\t\t\tif (morphCount > 0) {\n\t\t\t\t\tuint8_t shapeLength = static_cast<uint8_t>(shape.first.length());\n\t\t\t\t\tstd::string shapeName = shape.first;\n\t\t\t\t\ttriFile.write((char*)&shapeLength, 1);\n\t\t\t\t\tif (shapeLength > 0)\n\t\t\t\t\t\ttriFile.write(shapeName.c_str(), shapeLength);\n\n\t\t\t\t\ttriFile.write((char*)&morphCount, 2);\n\n\t\t\t\t\tfor (auto& morph : shape.second) {\n\t\t\t\t\t\tif (morph->type != MORPHTYPE_POSITION)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tuint8_t morphLength = static_cast<uint8_t>(morph->name.length());\n\t\t\t\t\t\tstd::string morphName = morph->name;\n\t\t\t\t\t\ttriFile.write((char*)&morphLength, 1);\n\t\t\t\t\t\tif (morphLength > 0)\n\t\t\t\t\t\t\ttriFile.write(morphName.c_str(), morphLength);\n\n\t\t\t\t\t\tfloat mult = 0.0f;\n\t\t\t\t\t\tfor (auto& v : morph->offsets) {\n\t\t\t\t\t\t\tif (std::abs(v.second.x) > mult)\n\t\t\t\t\t\t\t\tmult = std::abs(v.second.x);\n\t\t\t\t\t\t\tif (std::abs(v.second.y) > mult)\n\t\t\t\t\t\t\t\tmult = std::abs(v.second.y);\n\t\t\t\t\t\t\tif (std::abs(v.second.z) > mult)\n\t\t\t\t\t\t\t\tmult = std::abs(v.second.z);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmult /= 0x7FFF;\n\t\t\t\t\t\ttriFile.write((char*)&mult, 4);\n\n\t\t\t\t\t\tuint16_t morphVertCount = static_cast<uint16_t>(morph->offsets.size());\n\t\t\t\t\t\ttriFile.write((char*)&morphVertCount, 2);\n\n\t\t\t\t\t\tfor (auto& v : morph->offsets) {\n\t\t\t\t\t\t\tuint16_t id = v.first;\n\t\t\t\t\t\t\tshort x = (short)(v.second.x / mult);\n\t\t\t\t\t\t\tshort y = (short)(v.second.y / mult);\n\t\t\t\t\t\t\tshort z = (short)(v.second.z / mult);\n\t\t\t\t\t\t\ttriFile.write((char*)&id, 2);\n\t\t\t\t\t\t\ttriFile.write((char*)&x, 2);\n\t\t\t\t\t\t\ttriFile.write((char*)&y, 2);\n\t\t\t\t\t\t\ttriFile.write((char*)&z, 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Write UV offsets\n\t\tuint16_t shapeCountUV = GetShapeCount(MORPHTYPE_UV);\n\t\ttriFile.write((char*)&shapeCountUV, 2);\n\n\t\tif (shapeCountUV > 0) {\n\t\t\tfor (auto& shape : shapeMorphs) {\n\t\t\t\tuint16_t morphCount = GetMorphCount(shape.first, MORPHTYPE_UV);\n\t\t\t\tif (morphCount > 0) {\n\t\t\t\t\tuint8_t shapeLength = static_cast<uint8_t>(shape.first.length());\n\t\t\t\t\tstd::string shapeName = shape.first;\n\t\t\t\t\ttriFile.write((char*)&shapeLength, 1);\n\t\t\t\t\tif (shapeLength > 0)\n\t\t\t\t\t\ttriFile.write(shapeName.c_str(), shapeLength);\n\n\t\t\t\t\ttriFile.write((char*)&morphCount, 2);\n\n\t\t\t\t\tfor (auto& morph : shape.second) {\n\t\t\t\t\t\tif (morph->type != MORPHTYPE_UV)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tuint8_t morphLength = static_cast<uint8_t>(morph->name.length());\n\t\t\t\t\t\tstd::string morphName = morph->name;\n\t\t\t\t\t\ttriFile.write((char*)&morphLength, 1);\n\t\t\t\t\t\tif (morphLength > 0)\n\t\t\t\t\t\t\ttriFile.write(morphName.c_str(), morphLength);\n\n\t\t\t\t\t\tfloat mult = 0.0f;\n\t\t\t\t\t\tfor (auto& v : morph->offsets) {\n\t\t\t\t\t\t\tif (std::abs(v.second.x) > mult)\n\t\t\t\t\t\t\t\tmult = std::abs(v.second.x);\n\t\t\t\t\t\t\tif (std::abs(v.second.y) > mult)\n\t\t\t\t\t\t\t\tmult = std::abs(v.second.y);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmult /= 0x7FFF;\n\t\t\t\t\t\ttriFile.write((char*)&mult, 4);\n\n\t\t\t\t\t\tuint16_t morphVertCount = static_cast<uint16_t>(morph->offsets.size());\n\t\t\t\t\t\ttriFile.write((char*)&morphVertCount, 2);\n\n\t\t\t\t\t\tfor (auto& v : morph->offsets) {\n\t\t\t\t\t\t\tuint16_t id = v.first;\n\t\t\t\t\t\t\tshort x = (short)(v.second.x / mult);\n\t\t\t\t\t\t\tshort y = (short)(v.second.y / mult);\n\t\t\t\t\t\t\ttriFile.write((char*)&id, 2);\n\t\t\t\t\t\t\ttriFile.write((char*)&x, 2);\n\t\t\t\t\t\t\ttriFile.write((char*)&y, 2);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nvoid TriFile::AddMorph(const std::string& shapeName, MorphDataPtr data) {\n\tauto shape = shapeMorphs.find(shapeName);\n\tif (shape != shapeMorphs.end()) {\n\t\tauto morph = find_if(shape->second.begin(), shape->second.end(), [&](MorphDataPtr searchData) {\n\t\t\tif (searchData->name == data->name)\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t});\n\t\tif (morph == shape->second.end())\n\t\t\tshape->second.push_back(data);\n\t}\n\telse {\n\t\tshapeMorphs.emplace(shapeName, std::vector<MorphDataPtr>());\n\t\tAddMorph(shapeName, data);\n\t}\n}\n\nvoid TriFile::DeleteMorph(const std::string& shapeName, const std::string& morphName) {\n\tfor (auto shape = shapeMorphs.begin(); shape != shapeMorphs.end();) {\n\t\tif (shape->first == shapeName) {\n\t\t\tauto morph = find_if(shape->second.begin(), shape->second.end(), [&](MorphDataPtr searchData) {\n\t\t\t\tif (searchData->name == morphName)\n\t\t\t\t\treturn true;\n\t\t\t\treturn false;\n\t\t\t});\n\t\t\tif (morph != shape->second.end()) {\n\t\t\t\tshapeMorphs.erase(shape);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\t++shape;\n\t}\n}\n\nvoid TriFile::DeleteMorphs(const std::string& shapeName) {\n\tauto shape = shapeMorphs.find(shapeName);\n\tif (shape != shapeMorphs.end())\n\t\tshape->second.clear();\n}\n\nvoid TriFile::DeleteMorphFromAll(const std::string& morphName) {\n\tfor (auto shape = shapeMorphs.begin(); shape != shapeMorphs.end();) {\n\t\tauto morph = find_if(shape->second.begin(), shape->second.end(), [&](MorphDataPtr searchData) {\n\t\t\tif (searchData->name == morphName)\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t});\n\t\tif (morph != shape->second.end())\n\t\t\tshapeMorphs.erase(shape);\n\t\t++shape;\n\t}\n}\n\nMorphDataPtr TriFile::GetMorph(const std::string& shapeName, const std::string& morphName) {\n\tauto shape = shapeMorphs.find(shapeName);\n\tif (shape != shapeMorphs.end()) {\n\t\tauto morph = find_if(shape->second.begin(), shape->second.end(), [&](MorphDataPtr searchData) {\n\t\t\tif (searchData->name == morphName)\n\t\t\t\treturn true;\n\t\t\treturn false;\n\t\t});\n\t\tif (morph != shape->second.end())\n\t\t\treturn *morph;\n\t}\n\n\treturn nullptr;\n}\n\nstd::map<std::string, std::vector<MorphDataPtr>> TriFile::GetMorphs() {\n\treturn shapeMorphs;\n}\n\nuint16_t TriFile::GetShapeCount(MorphType morphType) {\n\tuint16_t shapeCount = 0;\n\n\tfor (auto& shape : shapeMorphs) {\n\t\tfor (auto& morph : shape.second) {\n\t\t\tif (morph->type == morphType) {\n\t\t\t\tshapeCount++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn shapeCount;\n}\n\nuint16_t TriFile::GetMorphCount(const std::string& shapeName, MorphType morphType) {\n\tuint16_t morphCount = 0;\n\n\tauto shape = shapeMorphs.find(shapeName);\n\tif (shape != shapeMorphs.end()) {\n\t\tfor (auto& morph : shape->second) {\n\t\t\tif (morph->type == morphType)\n\t\t\t\tmorphCount++;\n\t\t}\n\t}\n\n\treturn morphCount;\n}\n\nbool TriHeadFile::Read(const std::string& fileName) {\n\tstd::fstream triHeadFile;\n\tPlatformUtil::OpenFileStream(triHeadFile, fileName, std::ios::in | std::ios::binary);\n\n\tif (triHeadFile.is_open()) {\n\t\tidentifier.resize(2, ' ');\n\t\ttriHeadFile.read((char*)&identifier.front(), 2);\n\n\t\tconst std::string ident = \"FR\";\n\t\tif (identifier != ident)\n\t\t\treturn false;\n\n\t\tfileType.resize(3, ' ');\n\t\ttriHeadFile.read((char*)&fileType.front(), 3);\n\n\t\tconst std::string type = \"TRI\";\n\t\tif (fileType != type)\n\t\t\treturn false;\n\n\t\tversion.resize(3, ' ');\n\t\ttriHeadFile.read((char*)&version.front(), 3);\n\n\t\ttriHeadFile.read((char*)&numVertices, 4);\n\t\ttriHeadFile.read((char*)&numTriangles, 4);\n\t\ttriHeadFile.read((char*)&numQuads, 4);\n\t\ttriHeadFile.read((char*)&unknown2, 4);\n\t\ttriHeadFile.read((char*)&unknown3, 4);\n\t\ttriHeadFile.read((char*)&numUV, 4);\n\t\ttriHeadFile.read((char*)&flags, 4);\n\t\ttriHeadFile.read((char*)&numMorphs, 4);\n\t\ttriHeadFile.read((char*)&numModifiers, 4);\n\t\ttriHeadFile.read((char*)&numModVertices, 4);\n\t\ttriHeadFile.read((char*)&unknown7, 4);\n\t\ttriHeadFile.read((char*)&unknown8, 4);\n\t\ttriHeadFile.read((char*)&unknown9, 4);\n\t\ttriHeadFile.read((char*)&unknown10, 4);\n\n\t\tvertices.resize(numVertices);\n\t\tfor (uint32_t i = 0; i < numVertices; i++)\n\t\t\ttriHeadFile.read((char*)&vertices[i], 12);\n\n\t\tmodVertices.resize(numModVertices);\n\t\tfor (uint32_t i = 0; i < numModVertices; i++)\n\t\t\ttriHeadFile.read((char*)&modVertices[i], 12);\n\n\t\ttriangles.resize(numTriangles);\n\t\tfor (uint32_t i = 0; i < numTriangles; i++) {\n\t\t\tuint32_t x = 0;\n\t\t\ttriHeadFile.read((char*)&x, 4);\n\t\t\tuint32_t y = 0;\n\t\t\ttriHeadFile.read((char*)&y, 4);\n\t\t\tuint32_t z = 0;\n\t\t\ttriHeadFile.read((char*)&z, 4);\n\n\t\t\ttriangles[i] = Triangle((uint16_t)x, (uint16_t)y, (uint16_t)z);\n\t\t}\n\n\t\tuv.resize(numUV);\n\t\tfor (uint32_t i = 0; i < numUV; i++)\n\t\t\ttriHeadFile.read((char*)&uv[i], 8);\n\n\t\ttex.resize(numTriangles);\n\t\tfor (uint32_t i = 0; i < numTriangles; i++) {\n\t\t\tuint32_t x = 0;\n\t\t\ttriHeadFile.read((char*)&x, 4);\n\t\t\tuint32_t y = 0;\n\t\t\ttriHeadFile.read((char*)&y, 4);\n\t\t\tuint32_t z = 0;\n\t\t\ttriHeadFile.read((char*)&z, 4);\n\n\t\t\ttex[i] = Triangle((uint16_t)x, (uint16_t)y, (uint16_t)z);\n\t\t}\n\n\t\tmorphs.resize(numMorphs);\n\t\tfor (uint32_t i = 0; i < numMorphs; i++) {\n\t\t\tauto& morph = morphs[i];\n\n\t\t\tuint32_t morphNameLength = 0;\n\t\t\ttriHeadFile.read((char*)&morphNameLength, 4);\n\t\t\tmorph.morphName.resize(morphNameLength, ' ');\n\n\t\t\tif (morphNameLength > 0) {\n\t\t\t\ttriHeadFile.read((char*)&morph.morphName.front(), morphNameLength);\n\t\t\t\tmorph.morphName = morph.morphName.c_str();\n\t\t\t}\n\n\t\t\ttriHeadFile.read((char*)&morph.multiplier, 4);\n\n\t\t\tmorph.vertices.resize(numVertices);\n\t\t\tfor (uint32_t j = 0; j < numVertices; j++) {\n\t\t\t\tshort x = 0;\n\t\t\t\ttriHeadFile.read((char*)&x, 2);\n\t\t\t\tshort y = 0;\n\t\t\t\ttriHeadFile.read((char*)&y, 2);\n\t\t\t\tshort z = 0;\n\t\t\t\ttriHeadFile.read((char*)&z, 2);\n\n\t\t\t\tmorph.vertices[j] = Vector3(x * morph.multiplier, y * morph.multiplier, z * morph.multiplier);\n\t\t\t}\n\t\t}\n\n\t\t// Read but don't store\n\t\tfor (uint32_t i = 0; i < numModifiers; i++) {\n\t\t\tuint32_t morphNameLength = 0;\n\t\t\ttriHeadFile.read((char*)&morphNameLength, 4);\n\n\t\t\tstd::string morphName;\n\t\t\tmorphName.resize(morphNameLength, ' ');\n\n\t\t\tif (morphNameLength > 0)\n\t\t\t\ttriHeadFile.read((char*)&morphName.front(), morphNameLength);\n\n\t\t\tuint32_t blockLength = 0;\n\t\t\ttriHeadFile.read((char*)&blockLength, 4);\n\n\t\t\tfor (uint32_t j = 0; j < blockLength; j++) {\n\t\t\t\tuint32_t index = 0;\n\t\t\t\ttriHeadFile.read((char*)&index, 4);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nbool TriHeadFile::Write(const std::string& fileName) {\n\tstd::fstream triHeadFile;\n\tPlatformUtil::OpenFileStream(triHeadFile, fileName, std::ios::out | std::ios::binary);\n\n\tif (triHeadFile.is_open()) {\n\t\ttriHeadFile.write(identifier.c_str(), 2);\n\t\ttriHeadFile.write(fileType.c_str(), 3);\n\t\ttriHeadFile.write(version.c_str(), 3);\n\n\t\t// Not supported yet\n\t\tnumModVertices = 0;\n\t\tnumModifiers = 0;\n\n\t\ttriHeadFile.write((char*)&numVertices, 4);\n\t\ttriHeadFile.write((char*)&numTriangles, 4);\n\t\ttriHeadFile.write((char*)&numQuads, 4);\n\t\ttriHeadFile.write((char*)&unknown2, 4);\n\t\ttriHeadFile.write((char*)&unknown3, 4);\n\t\ttriHeadFile.write((char*)&numUV, 4);\n\t\ttriHeadFile.write((char*)&flags, 4);\n\t\ttriHeadFile.write((char*)&numMorphs, 4);\n\t\ttriHeadFile.write((char*)&numModifiers, 4);\n\t\ttriHeadFile.write((char*)&numModVertices, 4);\n\t\ttriHeadFile.write((char*)&unknown7, 4);\n\t\ttriHeadFile.write((char*)&unknown8, 4);\n\t\ttriHeadFile.write((char*)&unknown9, 4);\n\t\ttriHeadFile.write((char*)&unknown10, 4);\n\n\t\tfor (uint32_t i = 0; i < numVertices; i++)\n\t\t\ttriHeadFile.write((char*)&vertices[i], 12);\n\n\t\tfor (uint32_t i = 0; i < numTriangles; i++) {\n\t\t\tuint32_t x = triangles[i].p1;\n\t\t\ttriHeadFile.write((char*)&x, 4);\n\t\t\tuint32_t y = triangles[i].p2;\n\t\t\ttriHeadFile.write((char*)&y, 4);\n\t\t\tuint32_t z = triangles[i].p3;\n\t\t\ttriHeadFile.write((char*)&z, 4);\n\t\t}\n\n\t\tfor (uint32_t i = 0; i < numUV; i++)\n\t\t\ttriHeadFile.write((char*)&uv[i], 8);\n\n\t\tfor (uint32_t i = 0; i < numTriangles; i++) {\n\t\t\tuint32_t x = tex[i].p1;\n\t\t\ttriHeadFile.write((char*)&x, 4);\n\t\t\tuint32_t y = tex[i].p2;\n\t\t\ttriHeadFile.write((char*)&y, 4);\n\t\t\tuint32_t z = tex[i].p3;\n\t\t\ttriHeadFile.write((char*)&z, 4);\n\t\t}\n\n\t\tfor (uint32_t i = 0; i < numMorphs; i++) {\n\t\t\tauto& morph = morphs[i];\n\n\t\t\tuint32_t morphNameLength = static_cast<uint32_t>(morph.morphName.length() + 1);\n\t\t\ttriHeadFile.write((char*)&morphNameLength, 4);\n\t\t\tif (!morph.morphName.empty()) {\n\t\t\t\ttriHeadFile.write(morph.morphName.c_str(), morph.morphName.length());\n\t\t\t\ttriHeadFile.put('\\0');\n\t\t\t}\n\n\t\t\tmorph.multiplier = 0.0f;\n\t\t\tfor (auto& v : morph.vertices) {\n\t\t\t\tif (std::abs(v.x) > morph.multiplier)\n\t\t\t\t\tmorph.multiplier = std::abs(v.x);\n\t\t\t\tif (std::abs(v.y) > morph.multiplier)\n\t\t\t\t\tmorph.multiplier = std::abs(v.y);\n\t\t\t\tif (std::abs(v.z) > morph.multiplier)\n\t\t\t\t\tmorph.multiplier = std::abs(v.z);\n\t\t\t}\n\n\t\t\tmorph.multiplier /= 0x7FFF;\n\t\t\ttriHeadFile.write((char*)&morph.multiplier, 4);\n\n\t\t\tfor (auto& v : morph.vertices) {\n\t\t\t\tshort x = (short)(v.x / morph.multiplier);\n\t\t\t\tshort y = (short)(v.y / morph.multiplier);\n\t\t\t\tshort z = (short)(v.z / morph.multiplier);\n\t\t\t\ttriHeadFile.write((char*)&x, 2);\n\t\t\t\ttriHeadFile.write((char*)&y, 2);\n\t\t\t\ttriHeadFile.write((char*)&z, 2);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nstd::vector<Vector3> TriHeadFile::GetVertices() {\n\treturn vertices;\n}\n\nstd::vector<Triangle> TriHeadFile::GetTriangles() {\n\treturn triangles;\n}\n\nstd::vector<Vector2> TriHeadFile::GetUV() {\n\treturn uv;\n}\n\nvoid TriHeadFile::SetVertices(const std::vector<Vector3> verts) {\n\tvertices = verts;\n\tnumVertices = static_cast<uint32_t>(vertices.size());\n}\n\nvoid TriHeadFile::SetTriangles(const std::vector<Triangle> tris) {\n\ttriangles = tris;\n\ttex = triangles;\n\tnumTriangles = static_cast<uint32_t>(triangles.size());\n}\n\nvoid TriHeadFile::SetUV(const std::vector<Vector2> uvs) {\n\tuv = uvs;\n\tnumUV = static_cast<uint32_t>(uv.size());\n}\n\nvoid TriHeadFile::AddMorph(const TriHeadMorph& morph) {\n\tmorphs.push_back(morph);\n\tnumMorphs++;\n}\n\nvoid TriHeadFile::DeleteMorph(const std::string& morphName) {\n\tmorphs.erase(std::remove_if(morphs.begin(), morphs.end(), [&morphName](const TriHeadMorph& morph) { return morph.morphName == morphName; }), morphs.end());\n\n\tnumMorphs = static_cast<uint32_t>(morphs.size());\n}\n\nTriHeadMorph* TriHeadFile::GetMorph(const std::string& morphName) {\n\tfor (auto& m : morphs) {\n\t\tif (m.morphName == morphName) {\n\t\t\treturn &m;\n\t\t}\n\t}\n\n\treturn nullptr;\n}\n\nstd::vector<TriHeadMorph> TriHeadFile::GetMorphs() {\n\treturn morphs;\n}\n"
  },
  {
    "path": "src/files/TriFile.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"Object3d.hpp\"\n\n#include <algorithm>\n#include <fstream>\n#include <map>\n#include <memory>\n\nenum MorphType : uint8_t { MORPHTYPE_POSITION, MORPHTYPE_UV };\n\nstruct MorphData {\n\tstd::string name;\n\tMorphType type = MORPHTYPE_POSITION;\n\tstd::map<uint16_t, nifly::Vector3> offsets;\n};\n\ntypedef std::shared_ptr<MorphData> MorphDataPtr;\n\nbool IsBodyTriFile(const std::string& fileName);\n\nclass TriFile {\n\tstd::map<std::string, std::vector<MorphDataPtr>> shapeMorphs;\n\npublic:\n\tbool Read(const std::string& fileName);\n\tbool Write(const std::string& fileName);\n\n\tvoid AddMorph(const std::string& shapeName, MorphDataPtr data);\n\tvoid DeleteMorph(const std::string& shapeName, const std::string& morphName);\n\tvoid DeleteMorphs(const std::string& shapeName);\n\tvoid DeleteMorphFromAll(const std::string& morphName);\n\n\tMorphDataPtr GetMorph(const std::string& shapeName, const std::string& morphName);\n\tstd::map<std::string, std::vector<MorphDataPtr>> GetMorphs();\n\n\tuint16_t GetShapeCount(MorphType morphType);\n\tuint16_t GetMorphCount(const std::string& shapeName, MorphType morphType);\n};\n\nstruct TriHeadMorph {\n\tstd::string morphName;\n\tfloat multiplier = 1.0f;\n\tstd::vector<nifly::Vector3> vertices;\n};\n\nclass TriHeadFile {\n\tstd::string identifier = \"FR\";\n\tstd::string fileType = \"TRI\";\n\tstd::string version = \"003\";\n\tuint32_t numVertices = 0;\n\tuint32_t numTriangles = 0;\n\tuint32_t numQuads = 0;\n\tuint32_t unknown2 = 0;\n\tuint32_t unknown3 = 0;\n\tuint32_t numUV = 0;\n\tuint32_t flags = 1;\n\tuint32_t numMorphs = 0;\n\tuint32_t numModifiers = 0;\n\tuint32_t numModVertices = 0;\n\tuint32_t unknown7 = 0;\n\tuint32_t unknown8 = 0;\n\tuint32_t unknown9 = 0;\n\tuint32_t unknown10 = 0;\n\tstd::vector<nifly::Vector3> vertices;\n\tstd::vector<nifly::Vector3> modVertices;\n\tstd::vector<nifly::Triangle> triangles;\n\tstd::vector<nifly::Vector2> uv;\n\tstd::vector<nifly::Triangle> tex;\n\tstd::vector<TriHeadMorph> morphs;\n\npublic:\n\tbool Read(const std::string& fileName);\n\tbool Write(const std::string& fileName);\n\n\tstd::vector<nifly::Vector3> GetVertices();\n\tstd::vector<nifly::Triangle> GetTriangles();\n\tstd::vector<nifly::Vector2> GetUV();\n\n\tvoid SetVertices(const std::vector<nifly::Vector3> verts);\n\tvoid SetTriangles(const std::vector<nifly::Triangle> tris);\n\tvoid SetUV(const std::vector<nifly::Vector2> uvs);\n\n\tvoid AddMorph(const TriHeadMorph& morph);\n\tvoid DeleteMorph(const std::string& morphName);\n\n\tTriHeadMorph* GetMorph(const std::string& morphName);\n\tstd::vector<TriHeadMorph> GetMorphs();\n};\n"
  },
  {
    "path": "src/files/wxDDSImage.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"wxDDSImage.h\"\n\n#include <gli.hpp>\n\nwxIMPLEMENT_DYNAMIC_CLASS(wxDDSHandler, wxImageHandler);\n\nbool wxDDSHandler::LoadFile(wxImage* image, wxInputStream& stream, bool WXUNUSED(verbose), int WXUNUSED(index)) {\n\tsize_t datasize = stream.GetSize();\n\tif (datasize <= 0)\n\t\treturn false;\n\n\tchar* buf = new char[datasize];\n\tif (!stream.ReadAll(buf, datasize)) {\n\t\tdelete[] buf;\n\t\treturn false;\n\t}\n\n\tgli::texture intex = gli::load(buf, datasize);\n\tif (intex.empty()) {\n\t\tdelete[] buf;\n\t\treturn false;\n\t}\n\n\tgli::texture2d tex2d(intex);\n\tgli::extent2d dim = tex2d.extent();\n\tunsigned char* srcptr = (unsigned char*)tex2d.data();\n\timage->Destroy();\n\timage->Create(dim.x, dim.y, false);\n\tunsigned char* destPtr = image->GetData();\n\n\tuint32_t pxcount = dim.x * dim.y * 3;\n\tif (!gli::is_compressed(intex.format())) {\n\t\tfor (uint32_t i = 0; i < pxcount; i += 3) {\n\t\t\tdestPtr[i] = *srcptr++;\n\t\t\tdestPtr[i + 1] = *srcptr++;\n\t\t\tdestPtr[i + 2] = *srcptr++;\n\n\t\t\t// skipping alpha\n\t\t\tsrcptr++;\n\t\t}\n\t}\n\telse {\n\t\tfor (uint32_t i = 0; i < pxcount; i += 3) {\n\t\t\tdestPtr[i] = 66;\n\t\t\tdestPtr[i + 1] = 66;\n\t\t\tdestPtr[i + 2] = 66;\n\t\t}\n\t}\n\n\tdelete[] buf;\n\t/* Compressed image loading leads to heap corruption... :(\n\n\tfor (int y = 0; y < dim.y; y += 4) {\n\t\tfor (int x= 0; x < dim.x; x += 4) {\n\t\t\tunsigned char targetcolor[4 * 16];\n\t\t\tDecompressColor(targetcolor, srcptr, true);\n\t\t\tunsigned char* sourcePixel = targetcolor;\n\t\t\tfor (int py = 0; py < 4; py++) {\n\t\t\t\tfor (int px = 0; px < 4; px++) {\n\t\t\t\t\tint sx = x + px;\n\t\t\t\t\tint sy = y + py;\n\t\t\t\t\tif (sx < dim.x && sy < dim.y) {\n\t\t\t\t\t\tunsigned char* targetPixel = destPtr + 4 * (dim.x*sy + sx);\n\t\t\t\t\t\tfor (int i = 0; i < 4; i++) {\n\t\t\t\t\t\t\t*targetPixel++ = *sourcePixel++;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tsourcePixel += 4;\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tsrcptr += 8;\n\t}\n\t*/\n\n\n\treturn true;\n}\n\nbool wxDDSHandler::SaveFile(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose)) {\n\treturn false;\n}\n\n\nbool wxDDSHandler::DoCanRead(wxInputStream& stream) {\n\tunsigned char hdr[4];\n\n\tif (!stream.Read(hdr, WXSIZEOF(hdr))) // it's ok to modify the stream position here\n\t\treturn false;\n\n\treturn memcmp(hdr, \"DDS \", WXSIZEOF(hdr)) == 0;\n}\n\n/* Decompression functions cribbed from libsquish */\nvoid wxDDSHandler::DecompressColor(unsigned char* outPixels, unsigned char* block, bool dxt1) {\n\tunsigned char codes[16];\n\tint a = Unpack565(block, codes);\n\tint b = Unpack565(block + 2, codes + 4);\n\n\tfor (int i = 0; i < 3; i++) {\n\t\tint c = codes[i];\n\t\tint d = codes[4 + i];\n\n\t\tif (dxt1 && a <= b) {\n\t\t\tcodes[8 + i] = (c + d) / 2;\n\t\t\tcodes[12 + i] = 0;\n\t\t}\n\t\telse {\n\t\t\tcodes[8 + i] = (2 * c + d) / 3;\n\t\t\tcodes[12 + i] = (c + 2 * d) / 3;\n\t\t}\n\t}\n\n\tcodes[8 + 3] = 255;\n\tcodes[12 + 3] = (dxt1 && a <= b) ? 0 : 255;\n\n\tunsigned char indices[16];\n\tfor (int i = 0; i < 4; i++) {\n\t\tunsigned char* ind = indices + 4 * i;\n\t\tunsigned char packed = block[4 + i];\n\t\tind[0] = packed & 0x3;\n\t\tind[1] = (packed >> 2) & 0x3;\n\t\tind[2] = (packed >> 4) & 0x3;\n\t\tind[3] = (packed >> 6) & 0x3;\n\t}\n\n\tfor (int i = 0; i < 16; ++i) {\n\t\tunsigned char offset = 4 * indices[i];\n\t\tfor (int j = 0; j < 4; ++j)\n\t\t\toutPixels[4 * i + j] = codes[offset + j];\n\t}\n}\n\n/* Decompression functions cribbed from libsquish */\nint wxDDSHandler::Unpack565(unsigned char* bytes, unsigned char* color) {\n\tint value = (int)bytes[0] | ((int)bytes[1] << 8);\n\n\t// get the components in the stored range\n\tunsigned char red = (unsigned char)((value >> 11) & 0x1f);\n\tunsigned char green = (unsigned char)((value >> 5) & 0x3f);\n\tunsigned char blue = (unsigned char)(value & 0x1f);\n\n\t// scale up to 8 bits\n\tcolor[0] = (red << 3) | (red >> 2);\n\tcolor[1] = (green << 2) | (green >> 4);\n\tcolor[2] = (blue << 3) | (blue >> 2);\n\tcolor[3] = 255;\n\n\t// return the value\n\treturn value;\n}\n"
  },
  {
    "path": "src/files/wxDDSImage.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"wx/defs.h\"\n#include \"wx/image.h\"\n\n\nclass WXDLLIMPEXP_CORE wxDDSHandler : public wxImageHandler {\npublic:\n\tinline wxDDSHandler() {\n\t\tm_name = wxT(\"DDS file\");\n\t\tm_extension = wxT(\"dds\");\n\t\tm_type = wxBITMAP_TYPE_ANY;\n\t\tm_mime = wxT(\"image/dds\");\n\t}\n\n#if wxUSE_STREAMS\n\tvirtual bool LoadFile(wxImage* image, wxInputStream& stream, bool verbose = true, int index = -1) wxOVERRIDE;\n\tvirtual bool SaveFile(wxImage* image, wxOutputStream& stream, bool verbose = true) wxOVERRIDE;\n\nprotected:\n\tvirtual bool DoCanRead(wxInputStream& stream) wxOVERRIDE;\n#endif\n\nprivate:\n\twxDECLARE_DYNAMIC_CLASS(wxDDSHandler);\n\n\t/* Decompression functions cribbed from libsquish */\n\tvoid DecompressColor(unsigned char* outPixels, unsigned char* block, bool dxt1);\n\tint Unpack565(unsigned char* bytes, unsigned char* color);\n};\n"
  },
  {
    "path": "src/program/AutomationDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"AutomationDialog.h\"\n\n#include \"OutfitProject.h\"\n#include \"OutfitStudio.h\"\n\n#include \"../files/MaskFile.h\"\n#include \"../files/TriFile.h\"\n#include \"../components/ClippingFixer.h\"\n#include \"../utils/PlatformUtil.h\"\n\n#include <NifFile.hpp>\n\n#include <wx/dir.h>\n#include <wx/filedlg.h>\n#include <wx/msgdlg.h>\n#include <wx/filename.h>\n\n#include <tinyxml2.h>\n\n#include <regex>\n#include <set>\n\n#include \"../components/SliderSet.h\"\n\nusing namespace nifly;\n\nextern ConfigurationManager Config;\nextern ConfigurationManager OutfitStudioConfig;\n\nwxBEGIN_EVENT_TABLE(AutomationDialog, wxDialog)\n\tEVT_COMBOBOX(XRCID(\"cmbAutomation\"), AutomationDialog::OnAutomationSelected)\n\tEVT_BUTTON(XRCID(\"btnSaveScript\"), AutomationDialog::OnSaveScript)\n\tEVT_BUTTON(XRCID(\"btnDeleteScript\"), AutomationDialog::OnDeleteScript)\n\tEVT_BUTTON(XRCID(\"btnOpenFolder\"), AutomationDialog::OnOpenFolder)\n\tEVT_LIST_ITEM_SELECTED(XRCID(\"listSteps\"), AutomationDialog::OnStepSelected)\n\tEVT_CHOICE(XRCID(\"choiceStepType\"), AutomationDialog::OnStepTypeChanged)\n\tEVT_BUTTON(XRCID(\"btnExecuteAll\"), AutomationDialog::OnExecuteAll)\n\tEVT_BUTTON(wxID_CLOSE, AutomationDialog::OnClose)\n\tEVT_BUTTON(XRCID(\"btnAddVariable\"), AutomationDialog::OnAddVariable)\n\tEVT_BUTTON(XRCID(\"btnRemoveVariable\"), AutomationDialog::OnRemoveVariable)\n\tEVT_CHOICE(XRCID(\"choiceRefTemplate\"), AutomationDialog::OnRefTemplateChanged)\n\tEVT_FILEPICKER_CHANGED(XRCID(\"fpRefSourceFile\"), AutomationDialog::OnRefSourceFileChanged)\n\tEVT_CHOICE(XRCID(\"choiceRefSet\"), AutomationDialog::OnRefSetChanged)\n\tEVT_FILEPICKER_CHANGED(XRCID(\"fpAddProjSourceFile\"), AutomationDialog::OnAddProjSourceFileChanged)\n\tEVT_CHOICE(XRCID(\"choiceAddProjSet\"), AutomationDialog::OnAddProjSetChanged)\n\tEVT_CHECKBOX(XRCID(\"chkImportFromFolder\"), AutomationDialog::OnImportFolderChanged)\n\tEVT_CHECKBOX(XRCID(\"chkSliderDataFromFolder\"), AutomationDialog::OnSliderDataFolderChanged)\n\tEVT_CHECKBOX(XRCID(\"chkSaveUseOriginal\"), AutomationDialog::OnSaveUseOriginalChanged)\n\tEVT_CHECKBOX(XRCID(\"chkExportUseOriginalPath\"), AutomationDialog::OnExportUseOriginalChanged)\n\tEVT_CHECKBOX(XRCID(\"chkSetRefUnset\"), AutomationDialog::OnSetRefUnsetChanged)\n\tEVT_FILEPICKER_CHANGED(XRCID(\"fpLoadMaskFile\"), AutomationDialog::OnLoadMaskFileChanged)\n\tEVT_CHOICE(XRCID(\"choiceSliderPropZap\"), AutomationDialog::OnSliderPropZapChanged)\n\tEVT_RADIOBOX(XRCID(\"radioBatchMode\"), AutomationDialog::OnBatchModeChanged)\nwxEND_EVENT_TABLE()\n\nAutomationDialog::AutomationDialog(OutfitStudioFrame* outfitStudio, OutfitProject* project)\n\t: outfitStudio(outfitStudio), project(project) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Automation.xrc\");\n\txrc->LoadDialog(this, outfitStudio, \"dlgAutomation\");\n\n\tlistSteps = XRCCTRL(*this, \"listSteps\", wxListCtrl);\n\tbookStepPages = XRCCTRL(*this, \"bookStepPages\", wxSimplebook);\n\tchoiceStepType = XRCCTRL(*this, \"choiceStepType\", wxChoice);\n\n\t// Verify the number of step type pages matches the enum count\n\tif (bookStepPages && choiceStepType) {\n\t\twxASSERT_MSG(bookStepPages->GetPageCount() == AutomationStepTypeCount,\n\t\t\t\"bookStepPages page count must match AutomationStepTypeCount\");\n\t\twxASSERT_MSG(choiceStepType->GetCount() == AutomationStepTypeCount,\n\t\t\t\"choiceStepType item count must match AutomationStepTypeCount\");\n\t}\n\n\tchkActive = XRCCTRL(*this, \"chkActive\", wxCheckBox);\n\ttxtTargetMeshes = XRCCTRL(*this, \"txtTargetMeshes\", wxTextCtrl);\n\tchkTargetRegex = XRCCTRL(*this, \"chkTargetRegex\", wxCheckBox);\n\ttxtNote = XRCCTRL(*this, \"txtNote\", wxTextCtrl);\n\tradioBatchMode = XRCCTRL(*this, \"radioBatchMode\", wxRadioBox);\n\tpanelStepSettings = XRCCTRL(*this, \"panelStepSettings\", wxPanel);\n\tcmbAutomation = XRCCTRL(*this, \"cmbAutomation\", wxComboBox);\n\tbtnSaveScript = XRCCTRL(*this, \"btnSaveScript\", wxButton);\n\tbtnExecuteAll = XRCCTRL(*this, \"btnExecuteAll\", wxButton);\n\tbtnClose = dynamic_cast<wxButton*>(FindWindow(wxID_CLOSE));\n\n\tlistSteps->InsertColumn(0, _(\"Active\"), wxLIST_FORMAT_CENTER, 65);\n\tlistSteps->InsertColumn(1, _(\"Type\"), wxLIST_FORMAT_LEFT, 165);\n\tlistSteps->InsertColumn(2, _(\"Target\"), wxLIST_FORMAT_LEFT, 100);\n\tlistSteps->InsertColumn(3, _(\"Note\"), wxLIST_FORMAT_LEFT, 250);\n\n\tlistSteps->Bind(wxEVT_CONTEXT_MENU, &AutomationDialog::OnStepListContextMenu, this);\n\tlistSteps->Bind(wxEVT_KEY_DOWN, &AutomationDialog::OnStepListKeyDown, this);\n\n\tBind(wxEVT_CHAR_HOOK, &AutomationDialog::OnCharHook, this);\n\tBind(wxEVT_CLOSE_WINDOW, &AutomationDialog::OnWindowClose, this);\n\n\t// Placeholder label shown when step list is empty\n\tlblStepsPlaceholder = new wxStaticText(listSteps, wxID_ANY, _(\"Right-click to add steps...\"), wxPoint(0, 40), wxDefaultSize, wxALIGN_CENTER_HORIZONTAL | wxST_NO_AUTORESIZE);\n\tlblStepsPlaceholder->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT));\n\tlblStepsPlaceholder->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));\n\tlblStepsPlaceholder->Bind(wxEVT_CONTEXT_MENU, &AutomationDialog::OnStepListContextMenu, this);\n\t// Keep placeholder centered when list is resized\n\tlistSteps->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {\n\t\tif (lblStepsPlaceholder)\n\t\t\tlblStepsPlaceholder->SetSize(evt.GetSize().GetWidth(), lblStepsPlaceholder->GetSize().GetHeight());\n\t\tevt.Skip();\n\t});\n\n\t// Hide step settings until a step is selected\n\tif (panelStepSettings)\n\t\tpanelStepSettings->Hide();\n\n\t// Collapse panes by default\n\tauto* paneVariables = XRCCTRL(*this, \"paneVariables\", wxCollapsiblePane);\n\tauto* paneBatch = XRCCTRL(*this, \"paneBatch\", wxCollapsiblePane);\n\tif (paneVariables)\n\t\tpaneVariables->Collapse(true);\n\tif (paneBatch)\n\t\tpaneBatch->Collapse(true);\n\n\t// Output log pane (collapsed by default, shown during execution)\n\tpaneOutput = XRCCTRL(*this, \"paneOutput\", wxCollapsiblePane);\n\tif (paneOutput) {\n\t\tpaneOutput->Collapse(true);\n\t\tauto* paneWin = paneOutput->GetPane();\n\t\tauto* paneSizer = new wxBoxSizer(wxVERTICAL);\n\t\ttxtOutput = new wxTextCtrl(paneWin, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, 200), wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH | wxHSCROLL);\n\t\ttxtOutput->SetFont(wxFont(9, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL));\n\t\tpaneSizer->Add(txtOutput, 1, wxEXPAND);\n\t\tpaneWin->SetSizer(paneSizer);\n\t}\n\n\toutfitStudio->UpdateReferenceTemplates();\n\tPopulateRefTemplates();\n\tUpdateBatchPanelVisibility();\n\tPopulateAutomationList();\n\tUpdateButtonState();\n\n\t// Bind \"+\" buttons for appending shapes/sliders to comma-separated fields\n\tauto* btnAddTargetMesh = XRCCTRL(*this, \"btnAddTargetMesh\", wxButton);\n\tif (btnAddTargetMesh)\n\t\tbtnAddTargetMesh->Bind(wxEVT_BUTTON, &AutomationDialog::OnAddShapeToField, this);\n\n\tauto* btnAddDeleteSlider = XRCCTRL(*this, \"btnAddDeleteSlider\", wxButton);\n\tif (btnAddDeleteSlider)\n\t\tbtnAddDeleteSlider->Bind(wxEVT_BUTTON, &AutomationDialog::OnAddSliderToField, this);\n\n\tauto* btnAddSetSlider = XRCCTRL(*this, \"btnAddSetSlider\", wxButton);\n\tif (btnAddSetSlider)\n\t\tbtnAddSetSlider->Bind(wxEVT_BUTTON, &AutomationDialog::OnAddSliderToField, this);\n\n\tauto* btnAddConformSlider = XRCCTRL(*this, \"btnAddConformSlider\", wxButton);\n\tif (btnAddConformSlider)\n\t\tbtnAddConformSlider->Bind(wxEVT_BUTTON, &AutomationDialog::OnAddSliderToField, this);\n\n\tauto* btnAddSliderProp = XRCCTRL(*this, \"btnAddSliderProp\", wxButton);\n\tif (btnAddSliderProp)\n\t\tbtnAddSliderProp->Bind(wxEVT_BUTTON, &AutomationDialog::OnAddSliderToField, this);\n\n\tauto* btnAddFixClipSlider = XRCCTRL(*this, \"btnAddFixClipSlider\", wxButton);\n\tif (btnAddFixClipSlider)\n\t\tbtnAddFixClipSlider->Bind(wxEVT_BUTTON, &AutomationDialog::OnAddSliderToField, this);\n\n\t// Restore last selected automation script\n\tstd::string lastScript = OutfitStudioConfig[\"AutomationDialog.lastScript\"];\n\tif (!lastScript.empty()) {\n\t\twxString name = wxString::FromUTF8(lastScript);\n\t\tif (cmbAutomation && cmbAutomation->FindString(name) != wxNOT_FOUND) {\n\t\t\tcmbAutomation->SetValue(name);\n\t\t\tLoadAutomation(name);\n\t\t}\n\t}\n\n\t// Add status bar at the bottom\n\tstatusBar = new wxStatusBar(this, wxID_ANY);\n\tint widths[] = {-1, 150};\n\tstatusBar->SetFieldsCount(2, widths);\n\tstatusBar->SetStatusText(_(\"Ready.\"));\n\tGetSizer()->Add(statusBar, 0, wxEXPAND);\n\n\tFit();\n\tSetMinSize(GetSize());\n\tSetSize(wxSize(std::max(GetSize().GetWidth(), 950), std::max(GetSize().GetHeight(), 680)));\n\tCenterOnParent();\n}\n\nAutomationDialog::~AutomationDialog() {\n\t// Save last selected automation script\n\twxString name = cmbAutomation ? cmbAutomation->GetValue().Trim().Trim(false) : wxString();\n\tOutfitStudioConfig.SetValue(\"AutomationDialog.lastScript\", name.ToUTF8().data());\n\tOutfitStudioConfig.SaveConfig(Config[\"AppDir\"] + \"/OutfitStudio.xml\", \"OutfitStudioConfig\");\n\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Automation.xrc\");\n}\n\n// UI helper methods\n\nvoid AutomationDialog::SetCheckboxValue(const char* name, bool value) {\n\tauto* chk = XRCCTRL(*this, name, wxCheckBox);\n\tif (chk)\n\t\tchk->SetValue(value);\n}\n\nbool AutomationDialog::GetCheckboxValue(const char* name) const {\n\tauto* chk = XRCCTRL(*this, name, wxCheckBox);\n\treturn chk ? chk->GetValue() : false;\n}\n\nvoid AutomationDialog::SetTextValue(const char* name, const std::string& value) {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\tif (txt)\n\t\ttxt->SetValue(wxString::FromUTF8(value));\n}\n\nstd::string AutomationDialog::GetTextValue(const char* name) const {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\treturn txt ? std::string(txt->GetValue().ToUTF8().data()) : \"\";\n}\n\nAutomationBatchMode AutomationDialog::GetSelectedBatchMode() const {\n\tif (!radioBatchMode)\n\t\treturn AutomationBatchMode::None;\n\n\treturn static_cast<AutomationBatchMode>(radioBatchMode->GetSelection());\n}\n\nbool AutomationDialog::IsBatchMode(AutomationBatchMode mode) const {\n\treturn GetSelectedBatchMode() == mode;\n}\n\nvoid AutomationDialog::ApplyBatchModeDefaults(AutomationStep& step) const {\n\tif (step.type == AutomationStepType::SaveProject) {\n\t\tif (IsBatchMode(AutomationBatchMode::SliderSets)) {\n\t\t\tstep.saveUseOriginal = true;\n\t\t\tstep.saveCopyRefFromProject = true;\n\t\t}\n\t\telse if (IsBatchMode(AutomationBatchMode::FolderScan)) {\n\t\t\tstep.saveUseOriginal = false;\n\t\t}\n\t}\n\telse if (step.type == AutomationStepType::ExportFile && IsBatchMode(AutomationBatchMode::FolderScan)) {\n\t\tstep.exportUseOriginalPath = true;\n\t}\n}\n\nvoid AutomationDialog::UpdateSaveProjectBatchModeUI(const AutomationStep& step) {\n\tauto* chkUseOrig = XRCCTRL(*this, \"chkSaveUseOriginal\", wxCheckBox);\n\tif (chkUseOrig) {\n\t\tif (IsBatchMode(AutomationBatchMode::SliderSets)) {\n\t\t\tchkUseOrig->SetValue(true);\n\t\t\tchkUseOrig->Enable(false);\n\t\t}\n\t\telse if (IsBatchMode(AutomationBatchMode::FolderScan)) {\n\t\t\tchkUseOrig->SetValue(false);\n\t\t\tchkUseOrig->Enable(false);\n\t\t}\n\t\telse {\n\t\t\tchkUseOrig->Enable(true);\n\t\t}\n\t}\n\n\tbool fieldsEnabled = IsBatchMode(AutomationBatchMode::SliderSets) ? false :\n\t\t(IsBatchMode(AutomationBatchMode::FolderScan) ? true : !step.saveUseOriginal);\n\tUpdateSaveFieldsEnabled(fieldsEnabled);\n}\n\nvoid AutomationDialog::UpdateExportFileBatchModeUI(const AutomationStep& step) {\n\tauto* chkUseOrig = XRCCTRL(*this, \"chkExportUseOriginalPath\", wxCheckBox);\n\tif (chkUseOrig) {\n\t\tif (IsBatchMode(AutomationBatchMode::FolderScan)) {\n\t\t\tchkUseOrig->SetValue(true);\n\t\t\tchkUseOrig->Enable(false);\n\t\t}\n\t\telse {\n\t\t\tchkUseOrig->Enable(true);\n\t\t}\n\t}\n\n\tUpdateExportFieldsEnabled(!step.exportUseOriginalPath);\n}\n\nvoid AutomationDialog::SetFloatValue(const char* name, float value) {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\tif (txt)\n\t\ttxt->SetValue(wxString::Format(\"%.5g\", value));\n}\n\nfloat AutomationDialog::GetFloatValue(const char* name) const {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\treturn txt ? static_cast<float>(atof(txt->GetValue().c_str())) : 0.0f;\n}\n\nint AutomationDialog::GetIntValue(const char* name) const {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\treturn txt ? atoi(txt->GetValue().c_str()) : 0;\n}\n\nvoid AutomationDialog::SetVectorValue(const char* name, const std::vector<std::string>& values) {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\tif (txt)\n\t\ttxt->SetValue(wxString::FromUTF8(JoinStrings(values, \", \")));\n}\n\nstd::vector<std::string> AutomationDialog::GetVectorValue(const char* name) const {\n\tauto* txt = XRCCTRL(*this, name, wxTextCtrl);\n\treturn txt ? SplitCommaSeparated(std::string(txt->GetValue().ToUTF8().data())) : std::vector<std::string>();\n}\n\n// Progress methods\n\nvoid AutomationDialog::StartProgress(const wxString& msg) {\n\tif (progressBar)\n\t\treturn;\n\n\tcancelRequested = false;\n\tSetExecutionUIState(true);\n\n\twxRect rect;\n\tstatusBar->GetFieldRect(1, rect);\n\tprogressBar = new wxGauge(statusBar, wxID_ANY, 10000, rect.GetPosition(), rect.GetSize());\n\n\tstatusBar->SetStatusText(msg.IsEmpty() ? _(\"Starting...\") : msg);\n\n\t// Redirect log output to the output pane\n\tif (paneOutput && txtOutput) {\n\t\ttxtOutput->Clear();\n\t\tpaneOutput->Collapse(false);\n\t\tGetSizer()->Layout();\n\t\toldLogTarget = wxLog::SetActiveTarget(new wxLogTextCtrl(txtOutput));\n\t}\n}\n\nvoid AutomationDialog::UpdateProgress(int val, const wxString& msg) {\n\tif (!progressBar)\n\t\treturn;\n\n\tint scaled = val * 100;\n\tif (scaled > 10000)\n\t\tscaled = 10000;\n\tprogressBar->SetValue(scaled);\n\tstatusBar->SetStatusText(msg);\n\twxYield();\n}\n\nvoid AutomationDialog::OnCharHook(wxKeyEvent& event) {\n\tif (event.GetKeyCode() == WXK_ESCAPE && progressBar) {\n\t\tcancelRequested = true;\n\t\tstatusBar->SetStatusText(_(\"Cancelling...\"));\n\t\treturn;\n\t}\n\tevent.Skip();\n}\n\nvoid AutomationDialog::EndProgress(const wxString& msg) {\n\tif (!progressBar)\n\t\treturn;\n\n\tprogressBar->SetValue(10000);\n\tdelete progressBar;\n\tprogressBar = nullptr;\n\tstatusBar->SetStatusText(msg.IsEmpty() ? _(\"Ready.\") : msg);\n\n\t// Restore previous log target\n\tif (oldLogTarget) {\n\t\tdelete wxLog::SetActiveTarget(oldLogTarget);\n\t\toldLogTarget = nullptr;\n\t}\n\n\tSetExecutionUIState(false);\n}\n\nvoid AutomationDialog::SetExecutionUIState(bool running) {\n\tisExecuting = running;\n\n\twxWindowList children = GetChildren();\n\tfor (wxWindowList::iterator it = children.begin(); it != children.end(); ++it) {\n\t\twxWindow* child = *it;\n\t\tif (!child)\n\t\t\tcontinue;\n\n\t\tif (child == statusBar || child == btnClose || child == paneOutput)\n\t\t\tcontinue;\n\n\t\tchild->Enable(!running);\n\t}\n\n\tif (btnClose)\n\t\tbtnClose->SetLabel(running ? _(\"Cancel\") : _(\"Close\"));\n}\n\nvoid AutomationDialog::OnWindowClose(wxCloseEvent& event) {\n\tif (isExecuting) {\n\t\tcancelRequested = true;\n\t\tif (statusBar)\n\t\t\tstatusBar->SetStatusText(_(\"Cancelling...\"));\n\t\tevent.Veto();\n\t\treturn;\n\t}\n\n\tevent.Skip();\n}\n\nvoid AutomationDialog::PopulateStepList() {\n\tlistSteps->DeleteAllItems();\n\tauto& steps = script.GetSteps();\n\n\tif (lblStepsPlaceholder)\n\t\tlblStepsPlaceholder->Show(steps.empty());\n\n\tfor (size_t i = 0; i < steps.size(); i++) {\n\t\tlong idx = listSteps->InsertItem(i, steps[i].active ? wxString(L\"\\u2713\") : wxString(\"\"));\n\t\tlistSteps->SetItem(idx, 1, wxString::FromUTF8(AutomationStepTypeToString(steps[i].type)));\n\n\t\tstd::string targetStr = JoinStrings(steps[i].targetMeshes, \", \");\n\t\tif (targetStr.empty())\n\t\t\ttargetStr = \"(all)\";\n\t\tlistSteps->SetItem(idx, 2, wxString::FromUTF8(targetStr));\n\n\t\tlistSteps->SetItem(idx, 3, wxString::FromUTF8(steps[i].note));\n\t}\n}\n\nvoid AutomationDialog::RefreshStepRow(int index) {\n\tif (index < 0 || index >= static_cast<int>(script.GetSteps().size()))\n\t\treturn;\n\n\tauto& step = script.GetSteps()[index];\n\tlistSteps->SetItem(index, 0, step.active ? wxString(L\"\\u2713\") : wxString(\"\"));\n\tlistSteps->SetItem(index, 1, wxString::FromUTF8(AutomationStepTypeToString(step.type)));\n\n\tstd::string targetStr = JoinStrings(step.targetMeshes, \", \");\n\tif (targetStr.empty())\n\t\ttargetStr = \"(all)\";\n\tlistSteps->SetItem(index, 2, wxString::FromUTF8(targetStr));\n\n\tlistSteps->SetItem(index, 3, wxString::FromUTF8(step.note));\n}\n\nvoid AutomationDialog::ShowStepSettings(bool show) {\n\tif (!panelStepSettings)\n\t\treturn;\n\n\tpanelStepSettings->Show(show);\n\tGetSizer()->Layout();\n\n\tif (show) {\n\t\twxSize minSize = GetSizer()->GetMinSize();\n\t\twxSize curSize = GetSize();\n\t\tif (minSize.GetWidth() > curSize.GetWidth() || minSize.GetHeight() > curSize.GetHeight()) {\n\t\t\tSetSize(wxSize(std::max(curSize.GetWidth(), minSize.GetWidth()), std::max(curSize.GetHeight(), minSize.GetHeight())));\n\t\t}\n\t}\n}\n\nvoid AutomationDialog::OnStepListContextMenu(wxContextMenuEvent& WXUNUSED(event)) {\n\tenum {\n\t\tID_CTX_ADD_STEP = wxID_HIGHEST + 100,\n\t\tID_CTX_DUPLICATE_STEP,\n\t\tID_CTX_REMOVE_STEP,\n\t\tID_CTX_MOVE_UP,\n\t\tID_CTX_MOVE_DOWN,\n\t\tID_CTX_EXECUTE_SELECTED\n\t};\n\n\twxMenu menu;\n\tmenu.Append(ID_CTX_ADD_STEP, _(\"Add Step\"));\n\n\tbool hasSelection = (selectedStep >= 0);\n\tmenu.Append(ID_CTX_DUPLICATE_STEP, _(\"Duplicate Step\"))->Enable(hasSelection);\n\tmenu.Append(ID_CTX_REMOVE_STEP, _(\"Remove Step\"))->Enable(hasSelection);\n\tmenu.AppendSeparator();\n\tmenu.Append(ID_CTX_MOVE_UP, _(\"Move Up\"))->Enable(hasSelection && selectedStep > 0);\n\tmenu.Append(ID_CTX_MOVE_DOWN, _(\"Move Down\"))->Enable(hasSelection && selectedStep < static_cast<int>(script.GetSteps().size()) - 1);\n\tmenu.AppendSeparator();\n\tmenu.Append(ID_CTX_EXECUTE_SELECTED, _(\"Execute Selected\"))->Enable(hasSelection);\n\n\tint result = GetPopupMenuSelectionFromUser(menu);\n\twxCommandEvent evt;\n\tswitch (result) {\n\t\tcase ID_CTX_ADD_STEP: OnAddStep(evt); break;\n\t\tcase ID_CTX_DUPLICATE_STEP: OnDuplicateStep(evt); break;\n\t\tcase ID_CTX_REMOVE_STEP: OnRemoveStep(evt); break;\n\t\tcase ID_CTX_MOVE_UP: OnMoveUp(evt); break;\n\t\tcase ID_CTX_MOVE_DOWN: OnMoveDown(evt); break;\n\t\tcase ID_CTX_EXECUTE_SELECTED: OnExecuteSelected(evt); break;\n\t}\n}\n\nvoid AutomationDialog::SelectStep(int index) {\n\tif (selectedStep >= 0 && selectedStep < static_cast<int>(script.GetSteps().size()))\n\t\tUpdateStepFromUI();\n\n\tselectedStep = index;\n\n\tif (index < 0 || index >= static_cast<int>(script.GetSteps().size())) {\n\t\tselectedStep = -1;\n\t\treturn;\n\t}\n\n\tShowStepSettings(true);\n\tUpdateUIFromStep(script.GetSteps()[index]);\n}\n\nvoid AutomationDialog::UpdateUIFromStep(const AutomationStep& step) {\n\tchkActive->SetValue(step.active);\n\ttxtNote->SetValue(wxString::FromUTF8(step.note));\n\n\ttxtTargetMeshes->SetValue(wxString::FromUTF8(JoinStrings(step.targetMeshes, \", \")));\n\n\tif (chkTargetRegex)\n\t\tchkTargetRegex->SetValue(step.targetRegex);\n\n\tint typeIndex = static_cast<int>(step.type);\n\tchoiceStepType->SetSelection(typeIndex);\n\tbookStepPages->SetSelection(typeIndex);\n\n\tswitch (step.type) {\n\t\tcase AutomationStepType::ClearProject:\n\t\t\t// No parameters to set\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::LoadReference: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpRefSourceFile\", wxFilePickerCtrl);\n\t\t\tif (fp) {\n\t\t\t\t// If path is relative, resolve it for the file picker display\n\t\t\t\twxString path = wxString::FromUTF8(step.refSourceFile);\n\t\t\t\tif (!path.IsEmpty()) {\n\t\t\t\t\twxFileName fn(path);\n\t\t\t\t\tif (fn.IsRelative()) {\n\t\t\t\t\t\tstd::string projPath = GetProjectPath();\n\t\t\t\t\t\tfn.MakeAbsolute(wxString::FromUTF8(projPath));\n\t\t\t\t\t}\n\t\t\t\t\tfp->SetPath(fn.GetFullPath());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfp->SetPath(wxEmptyString);\n\t\t\t\t}\n\n\t\t\t\t// Populate set/shape dropdowns from the file\n\t\t\t\tPopulateSetsFromFile(fp->GetPath(), \"choiceRefSet\", \"choiceRefShape\");\n\t\t\t}\n\n\t\t\tauto* choiceSet = XRCCTRL(*this, \"choiceRefSet\", wxChoice);\n\t\t\tif (choiceSet) {\n\t\t\t\twxString setName = wxString::FromUTF8(step.refSet);\n\t\t\t\tint idx = choiceSet->FindString(setName);\n\t\t\t\tif (idx != wxNOT_FOUND) {\n\t\t\t\t\tchoiceSet->SetSelection(idx);\n\t\t\t\t}\n\t\t\t\telse if (!setName.IsEmpty()) {\n\t\t\t\t\tchoiceSet->Append(setName);\n\t\t\t\t\tchoiceSet->SetSelection(choiceSet->GetCount() - 1);\n\t\t\t\t}\n\n\t\t\t\t// Populate shapes for the selected set\n\t\t\t\tif (fp)\n\t\t\t\t\tPopulateRefShapesForSet(fp->GetPath(), choiceSet->GetStringSelection());\n\t\t\t}\n\n\t\t\tauto* choiceShape = XRCCTRL(*this, \"choiceRefShape\", wxChoice);\n\t\t\tif (choiceShape) {\n\t\t\t\twxString shapeName = wxString::FromUTF8(step.refShape);\n\t\t\t\tint idx = choiceShape->FindString(shapeName);\n\t\t\t\tif (idx != wxNOT_FOUND)\n\t\t\t\t\tchoiceShape->SetSelection(idx);\n\t\t\t\telse if (!shapeName.IsEmpty()) {\n\t\t\t\t\tchoiceShape->Append(shapeName);\n\t\t\t\t\tchoiceShape->SetSelection(choiceShape->GetCount() - 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Select the matching template if any\n\t\t\tauto* choiceTemplate = XRCCTRL(*this, \"choiceRefTemplate\", wxChoice);\n\t\t\tif (choiceTemplate)\n\t\t\t\tchoiceTemplate->SetSelection(0); // \"(None)\" by default\n\n\t\t\tSetCheckboxValue(\"chkRefLoadAll\", step.refLoadAll);\n\t\t\tSetCheckboxValue(\"chkRefMergeSliders\", step.refMergeSliders);\n\t\t\tSetCheckboxValue(\"chkRefMergeZaps\", step.refMergeZaps);\n\t\t\tSetCheckboxValue(\"chkRefAppendNewSliders\", step.refAppendNewSliders);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::AddProject: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpAddProjSourceFile\", wxFilePickerCtrl);\n\t\t\tif (fp) {\n\t\t\t\twxString path = wxString::FromUTF8(step.refSourceFile);\n\t\t\t\tif (!path.IsEmpty()) {\n\t\t\t\t\twxFileName fn(path);\n\t\t\t\t\tif (fn.IsRelative()) {\n\t\t\t\t\t\tstd::string projPath = GetProjectPath();\n\t\t\t\t\t\tfn.MakeAbsolute(wxString::FromUTF8(projPath));\n\t\t\t\t\t}\n\t\t\t\t\tfp->SetPath(fn.GetFullPath());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfp->SetPath(wxEmptyString);\n\t\t\t\t}\n\t\t\t\tPopulateSetsFromFile(fp->GetPath(), \"choiceAddProjSet\");\n\t\t\t}\n\n\t\t\tauto* choiceSet = XRCCTRL(*this, \"choiceAddProjSet\", wxChoice);\n\t\t\tif (choiceSet) {\n\t\t\t\twxString setName = wxString::FromUTF8(step.refSet);\n\t\t\t\tint idx = choiceSet->FindString(setName);\n\t\t\t\tif (idx != wxNOT_FOUND)\n\t\t\t\t\tchoiceSet->SetSelection(idx);\n\t\t\t\telse if (!setName.IsEmpty()) {\n\t\t\t\t\tchoiceSet->Append(setName);\n\t\t\t\t\tchoiceSet->SetSelection(choiceSet->GetCount() - 1);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tSetCheckboxValue(\"chkAddProjAppendSliders\", step.refAppendNewSliders);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ConformSliders: {\n\t\t\tauto* txt = XRCCTRL(*this, \"txtConformRadius\", wxTextCtrl);\n\t\t\tif (txt)\n\t\t\t\ttxt->SetValue(wxString::Format(\"%.1f\", step.conformProximityRadius));\n\t\t\ttxt = XRCCTRL(*this, \"txtConformMaxResults\", wxTextCtrl);\n\t\t\tif (txt)\n\t\t\t\ttxt->SetValue(wxString::Format(\"%d\", step.conformMaxResults));\n\n\t\t\tSetCheckboxValue(\"chkConformNoSqueeze\", step.conformNoSqueeze);\n\t\t\tSetCheckboxValue(\"chkConformSolidMode\", step.conformSolidMode);\n\t\t\tSetCheckboxValue(\"chkConformAxisX\", step.conformAxisX);\n\t\t\tSetCheckboxValue(\"chkConformAxisY\", step.conformAxisY);\n\t\t\tSetCheckboxValue(\"chkConformAxisZ\", step.conformAxisZ);\n\t\t\tSetVectorValue(\"txtConformSliderNames\", step.conformSliderNames);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::CopyBoneWeights: {\n\t\t\tauto* txt = XRCCTRL(*this, \"txtWeightRadius\", wxTextCtrl);\n\t\t\tif (txt)\n\t\t\t\ttxt->SetValue(wxString::Format(\"%.1f\", step.weightProximityRadius));\n\t\t\ttxt = XRCCTRL(*this, \"txtWeightMaxResults\", wxTextCtrl);\n\t\t\tif (txt)\n\t\t\t\ttxt->SetValue(wxString::Format(\"%d\", step.weightMaxResults));\n\t\t\tSetVectorValue(\"txtWeightBoneList\", step.weightBoneList);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ImportSliderData: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpSliderDataFile\", wxFilePickerCtrl);\n\t\t\tif (fp)\n\t\t\t\tfp->SetPath(wxString::FromUTF8(step.sliderDataFile));\n\t\t\tSetCheckboxValue(\"chkSliderDataFromFolder\", step.sliderDataFromFolder);\n\t\t\tauto* dp = XRCCTRL(*this, \"dpSliderDataFolder\", wxDirPickerCtrl);\n\t\t\tif (dp)\n\t\t\t\tdp->SetPath(wxString::FromUTF8(step.sliderDataFile));\n\t\t\tUpdateSliderDataFolderVisibility(step.sliderDataFromFolder);\n\t\t\tSetCheckboxValue(\"chkSliderMerge\", step.sliderMerge);\n\t\t\tSetVectorValue(\"txtSliderNames\", step.sliderNames);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::SetSliderValues: {\n\t\t\tSetVectorValue(\"txtSetSliderNames\", step.setSliderNames);\n\t\t\tauto* txt = XRCCTRL(*this, \"txtSetSliderValue\", wxTextCtrl);\n\t\t\tif (txt)\n\t\t\t\ttxt->SetValue(wxString::Format(\"%d\", static_cast<int>(step.setSliderValue * 100)));\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::SetSliderProperties: {\n\t\t\tSetVectorValue(\"txtSliderPropNames\", step.sliderPropNames);\n\t\t\tauto* choiceZap = XRCCTRL(*this, \"choiceSliderPropZap\", wxChoice);\n\t\t\tif (choiceZap)\n\t\t\t\tchoiceZap->SetSelection(step.sliderPropZap < 0 ? 0 : step.sliderPropZap + 1);\n\t\t\tauto* choiceHidden = XRCCTRL(*this, \"choiceSliderPropHidden\", wxChoice);\n\t\t\tif (choiceHidden)\n\t\t\t\tchoiceHidden->SetSelection(step.sliderPropHidden < 0 ? 0 : step.sliderPropHidden + 1);\n\n\t\t\tbool isZap = step.sliderPropZap == 1;\n\t\t\tauto* choiceZapped = XRCCTRL(*this, \"choiceSliderPropZapped\", wxChoice);\n\t\t\tif (choiceZapped) {\n\t\t\t\tif (isZap) {\n\t\t\t\t\t// Map lo/hi to zapped state: -1 = no change, both 0 = not zapped, any > 0 = zapped\n\t\t\t\t\tif (step.sliderPropDefaultLo < 0 && step.sliderPropDefaultHi < 0)\n\t\t\t\t\t\tchoiceZapped->SetSelection(0);\n\t\t\t\t\telse if (step.sliderPropDefaultLo > 0 || step.sliderPropDefaultHi > 0)\n\t\t\t\t\t\tchoiceZapped->SetSelection(2);\n\t\t\t\t\telse\n\t\t\t\t\t\tchoiceZapped->SetSelection(1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tchoiceZapped->SetSelection(0);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tauto* txtLo = XRCCTRL(*this, \"txtSliderPropDefaultLo\", wxTextCtrl);\n\t\t\tif (txtLo)\n\t\t\t\ttxtLo->SetValue(step.sliderPropDefaultLo >= 0 ? wxString::Format(\"%d\", step.sliderPropDefaultLo) : \"\");\n\t\t\tauto* txtHi = XRCCTRL(*this, \"txtSliderPropDefaultHi\", wxTextCtrl);\n\t\t\tif (txtHi)\n\t\t\t\ttxtHi->SetValue(step.sliderPropDefaultHi >= 0 ? wxString::Format(\"%d\", step.sliderPropDefaultHi) : \"\");\n\n\t\t\tUpdateSliderPropDefaultVisibility();\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ImportFile: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpImportFile\", wxFilePickerCtrl);\n\t\t\tif (fp)\n\t\t\t\tfp->SetPath(wxString::FromUTF8(step.importFilePath));\n\t\t\tSetCheckboxValue(\"chkImportFromFolder\", step.importFromFolder);\n\t\t\tauto* dp = XRCCTRL(*this, \"dpImportFolder\", wxDirPickerCtrl);\n\t\t\tif (dp)\n\t\t\t\tdp->SetPath(wxString::FromUTF8(step.importFilePath));\n\t\t\tUpdateImportFolderVisibility(step.importFromFolder);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::DeleteShape:\n\t\t\t// No parameters — uses Target Meshes\n\t\t\tbreak;\n\t\tcase AutomationStepType::RenameShape: {\n\t\t\tSetTextValue(\"txtRenameOldName\", step.renameOldName);\n\t\t\tSetTextValue(\"txtRenameNewName\", step.renameNewName);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::DeleteSlider: {\n\t\t\tSetVectorValue(\"txtDeleteSliderName\", step.deleteSliderNames);\n\t\t\tSetCheckboxValue(\"chkDeleteSliderRegex\", step.deleteSliderRegex);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::SetReferenceShape: {\n\t\t\tSetTextValue(\"txtSetRefShapeName\", step.setRefShapeName);\n\t\t\tSetCheckboxValue(\"chkSetRefUnset\", step.setRefUnset);\n\t\t\tUpdateSetRefFieldsEnabled(!step.setRefUnset);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::RefineMesh:\n\t\tcase AutomationStepType::SetBaseShape:\n\t\tcase AutomationStepType::ClearReference:\n\t\tcase AutomationStepType::RemoveSkinning:\n\t\t\t// No parameters to set\n\t\t\tbreak;\n\t\tcase AutomationStepType::TransformShape: {\n\t\t\tSetFloatValue(\"txtMoveX\", step.moveX);\n\t\t\tSetFloatValue(\"txtMoveY\", step.moveY);\n\t\t\tSetFloatValue(\"txtMoveZ\", step.moveZ);\n\t\t\tSetFloatValue(\"txtRotateX\", step.rotateX);\n\t\t\tSetFloatValue(\"txtRotateY\", step.rotateY);\n\t\t\tSetFloatValue(\"txtRotateZ\", step.rotateZ);\n\t\t\tSetFloatValue(\"txtScaleX\", step.scaleX);\n\t\t\tSetFloatValue(\"txtScaleY\", step.scaleY);\n\t\t\tSetFloatValue(\"txtScaleZ\", step.scaleZ);\n\t\t\tSetFloatValue(\"txtInflateX\", step.inflateX);\n\t\t\tSetFloatValue(\"txtInflateY\", step.inflateY);\n\t\t\tSetFloatValue(\"txtInflateZ\", step.inflateZ);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::InvertUVs: {\n\t\t\tSetCheckboxValue(\"chkInvertU\", step.invertU);\n\t\t\tSetCheckboxValue(\"chkInvertV\", step.invertV);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::DeleteBones: {\n\t\t\tSetVectorValue(\"txtDeleteBoneNames\", step.deleteBoneNames);\n\t\t\tSetCheckboxValue(\"chkDeleteBoneFromProject\", step.deleteBoneFromProject);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::AddCustomBone: {\n\t\t\tSetTextValue(\"txtAddBoneName\", step.addBoneName);\n\t\t\tSetTextValue(\"txtAddBoneParent\", step.addBoneParent);\n\t\t\tSetFloatValue(\"txtAddBoneTransX\", step.addBoneTransX);\n\t\t\tSetFloatValue(\"txtAddBoneTransY\", step.addBoneTransY);\n\t\t\tSetFloatValue(\"txtAddBoneTransZ\", step.addBoneTransZ);\n\t\t\tSetFloatValue(\"txtAddBoneRotX\", step.addBoneRotX);\n\t\t\tSetFloatValue(\"txtAddBoneRotY\", step.addBoneRotY);\n\t\t\tSetFloatValue(\"txtAddBoneRotZ\", step.addBoneRotZ);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::EditBone: {\n\t\t\tSetTextValue(\"txtEditBoneName\", step.editBoneName);\n\t\t\tSetTextValue(\"txtEditBoneParent\", step.editBoneParent);\n\t\t\tSetFloatValue(\"txtEditBoneTransX\", step.editBoneTransX);\n\t\t\tSetFloatValue(\"txtEditBoneTransY\", step.editBoneTransY);\n\t\t\tSetFloatValue(\"txtEditBoneTransZ\", step.editBoneTransZ);\n\t\t\tSetFloatValue(\"txtEditBoneRotX\", step.editBoneRotX);\n\t\t\tSetFloatValue(\"txtEditBoneRotY\", step.editBoneRotY);\n\t\t\tSetFloatValue(\"txtEditBoneRotZ\", step.editBoneRotZ);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ApplyPose: {\n\t\t\tSetTextValue(\"txtPoseName\", step.poseName);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::SaveProject: {\n\t\t\tSetTextValue(\"txtSaveDisplayName\", step.saveName);\n\t\t\tSetTextValue(\"txtSaveOutputFileName\", step.saveOutputFileName);\n\t\t\tSetTextValue(\"txtSaveOutputDataPath\", step.saveOutputDataPath);\n\t\t\tSetTextValue(\"txtSaveSliderSetFile\", step.saveSliderSetFile);\n\t\t\tSetTextValue(\"txtSaveShapeDataFolder\", step.saveShapeDataFolder);\n\t\t\tSetTextValue(\"txtSaveShapeDataFile\", step.saveShapeDataFile);\n\n\t\t\tSetCheckboxValue(\"chkSaveGenWeights\", step.saveGenWeights);\n\t\t\tSetCheckboxValue(\"chkSaveAutoCopyRef\", step.saveAutoCopyRef);\n\t\t\tSetCheckboxValue(\"chkSaveCopyRefFromProject\", step.saveCopyRefFromProject);\n\t\t\tSetTextValue(\"txtSaveCopyRefShapeName\", step.saveCopyRefShapeName);\n\t\t\tSetCheckboxValue(\"chkSaveUseOriginal\", step.saveUseOriginal);\n\t\t\tSetTextValue(\"txtSaveReplaceFrom\", step.saveReplaceFrom);\n\t\t\tSetTextValue(\"txtSaveReplaceTo\", step.saveReplaceTo);\n\t\t\tSetTextValue(\"txtSaveSuffix\", step.saveSuffix);\n\t\t\tUpdateSaveProjectBatchModeUI(step);\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ExportFile: {\n\t\t\tbool isBatch = GetSelectedBatchMode() != AutomationBatchMode::None;\n\t\t\tif (isBatch) {\n\t\t\t\tauto* dp = XRCCTRL(*this, \"dpExportFolder\", wxDirPickerCtrl);\n\t\t\t\tif (dp)\n\t\t\t\t\tdp->SetPath(wxString::FromUTF8(step.exportFilePath));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto* fp = XRCCTRL(*this, \"fpExportFile\", wxFilePickerCtrl);\n\t\t\t\tif (fp)\n\t\t\t\t\tfp->SetPath(wxString::FromUTF8(step.exportFilePath));\n\t\t\t}\n\t\t\tSetCheckboxValue(\"chkExportWithRef\", step.exportWithRef);\n\t\t\tSetCheckboxValue(\"chkExportUseOriginalPath\", step.exportUseOriginalPath);\n\t\t\tSetTextValue(\"txtExportPrefix\", step.exportPrefix);\n\t\t\tSetTextValue(\"txtExportSuffix\", step.exportSuffix);\n\t\t\tUpdateExportForBatchMode();\n\t\t\tUpdateExportFileBatchModeUI(step);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::ResetTransforms:\n\t\t\t// No parameters to set\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::DuplicateShape: {\n\t\t\tSetTextValue(\"txtDupNewName\", step.dupNewName);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::MirrorShape: {\n\t\t\tSetCheckboxValue(\"chkMirrorX\", step.mirrorX);\n\t\t\tSetCheckboxValue(\"chkMirrorY\", step.mirrorY);\n\t\t\tSetCheckboxValue(\"chkMirrorZ\", step.mirrorZ);\n\t\t\tSetCheckboxValue(\"chkMirrorSwapBonesX\", step.mirrorSwapBonesX);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::ClearMask:\n\t\t\t// No parameters to set\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::LoadMask: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpLoadMaskFile\", wxFilePickerCtrl);\n\t\t\tif (fp) {\n\t\t\t\t// If path is relative, resolve it for the file picker display\n\t\t\t\twxString path = wxString::FromUTF8(step.loadMaskFile);\n\t\t\t\tif (!path.IsEmpty()) {\n\t\t\t\t\twxFileName fn(path);\n\t\t\t\t\tif (fn.IsRelative()) {\n\t\t\t\t\t\tstd::string projPath = GetProjectPath();\n\t\t\t\t\t\tfn.MakeAbsolute(wxString::FromUTF8(projPath));\n\t\t\t\t\t}\n\t\t\t\t\tfp->SetPath(fn.GetFullPath());\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfp->SetPath(wxEmptyString);\n\t\t\t\t}\n\n\t\t\t\t// Populate dropdown from the mask file\n\t\t\t\tPopulateMaskNamesFromFile(fp->GetPath());\n\t\t\t}\n\n\t\t\tauto* choice = XRCCTRL(*this, \"choiceLoadMaskName\", wxChoice);\n\t\t\tif (choice) {\n\t\t\t\twxString maskName = wxString::FromUTF8(step.loadMaskName);\n\t\t\t\tint idx = choice->FindString(maskName);\n\t\t\t\tif (idx != wxNOT_FOUND)\n\t\t\t\t\tchoice->SetSelection(idx);\n\t\t\t\telse if (!maskName.IsEmpty()) {\n\t\t\t\t\tchoice->Append(maskName);\n\t\t\t\t\tchoice->SetSelection(choice->GetCount() - 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::RemoveUnusedNodes:\n\t\t\t// No parameters to set\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::FixClipping: {\n\t\t\tauto* choice = XRCCTRL(*this, \"choiceFixClipMode\", wxChoice);\n\t\t\tif (choice)\n\t\t\t\tchoice->SetSelection(step.fixClipMode);\n\t\t\tauto* txt = XRCCTRL(*this, \"txtFixClipStrength\", wxTextCtrl);\n\t\t\tif (txt)\n\t\t\t\ttxt->SetValue(wxString::Format(\"%d\", static_cast<int>(step.fixClipStrength * 100)));\n\t\t\tSetVectorValue(\"txtFixClipSliderNames\", step.fixClipSliderNames);\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::FixBadBones:\n\t\t\t// No parameters to set\n\t\t\tbreak;\n\t}\n}\n\nvoid AutomationDialog::UpdateStepFromUI() {\n\tif (selectedStep < 0 || selectedStep >= static_cast<int>(script.GetSteps().size()))\n\t\treturn;\n\n\tauto& step = script.GetSteps()[selectedStep];\n\tstep.active = chkActive->GetValue();\n\tstep.note = txtNote->GetValue().ToUTF8().data();\n\tstep.targetMeshes = SplitCommaSeparated(txtTargetMeshes->GetValue().ToUTF8().data());\n\tstep.targetRegex = chkTargetRegex ? chkTargetRegex->GetValue() : false;\n\tstep.type = static_cast<AutomationStepType>(choiceStepType->GetSelection());\n\n\tswitch (step.type) {\n\t\tcase AutomationStepType::ClearProject:\n\t\t\t// No parameters to read\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::LoadReference: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpRefSourceFile\", wxFilePickerCtrl);\n\t\t\tif (fp)\n\t\t\t\tstep.refSourceFile = MakeRelativeToProject(fp->GetPath()).ToUTF8().data();\n\t\t\tauto* choiceSet = XRCCTRL(*this, \"choiceRefSet\", wxChoice);\n\t\t\tif (choiceSet && choiceSet->GetSelection() != wxNOT_FOUND)\n\t\t\t\tstep.refSet = choiceSet->GetStringSelection().ToUTF8().data();\n\t\t\tauto* choiceShape = XRCCTRL(*this, \"choiceRefShape\", wxChoice);\n\t\t\tif (choiceShape && choiceShape->GetSelection() != wxNOT_FOUND)\n\t\t\t\tstep.refShape = choiceShape->GetStringSelection().ToUTF8().data();\n\n\t\t\tstep.refLoadAll = GetCheckboxValue(\"chkRefLoadAll\");\n\t\t\tstep.refMergeSliders = GetCheckboxValue(\"chkRefMergeSliders\");\n\t\t\tstep.refMergeZaps = GetCheckboxValue(\"chkRefMergeZaps\");\n\t\t\tstep.refAppendNewSliders = GetCheckboxValue(\"chkRefAppendNewSliders\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::AddProject: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpAddProjSourceFile\", wxFilePickerCtrl);\n\t\t\tif (fp)\n\t\t\t\tstep.refSourceFile = MakeRelativeToProject(fp->GetPath()).ToUTF8().data();\n\t\t\tauto* choiceSet = XRCCTRL(*this, \"choiceAddProjSet\", wxChoice);\n\t\t\tif (choiceSet && choiceSet->GetSelection() != wxNOT_FOUND)\n\t\t\t\tstep.refSet = choiceSet->GetStringSelection().ToUTF8().data();\n\t\t\tstep.refAppendNewSliders = GetCheckboxValue(\"chkAddProjAppendSliders\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ConformSliders: {\n\t\t\tstep.conformProximityRadius = GetFloatValue(\"txtConformRadius\");\n\t\t\tstep.conformMaxResults = GetIntValue(\"txtConformMaxResults\");\n\t\t\tstep.conformNoSqueeze = GetCheckboxValue(\"chkConformNoSqueeze\");\n\t\t\tstep.conformSolidMode = GetCheckboxValue(\"chkConformSolidMode\");\n\t\t\tstep.conformAxisX = GetCheckboxValue(\"chkConformAxisX\");\n\t\t\tstep.conformAxisY = GetCheckboxValue(\"chkConformAxisY\");\n\t\t\tstep.conformAxisZ = GetCheckboxValue(\"chkConformAxisZ\");\n\t\t\tstep.conformSliderNames = GetVectorValue(\"txtConformSliderNames\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::CopyBoneWeights: {\n\t\t\tstep.weightProximityRadius = GetFloatValue(\"txtWeightRadius\");\n\t\t\tstep.weightMaxResults = GetIntValue(\"txtWeightMaxResults\");\n\t\t\tstep.weightBoneList = GetVectorValue(\"txtWeightBoneList\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ImportSliderData: {\n\t\t\tauto* chkFolder = XRCCTRL(*this, \"chkSliderDataFromFolder\", wxCheckBox);\n\t\t\tstep.sliderDataFromFolder = chkFolder && chkFolder->GetValue();\n\t\t\tif (step.sliderDataFromFolder) {\n\t\t\t\tauto* dp = XRCCTRL(*this, \"dpSliderDataFolder\", wxDirPickerCtrl);\n\t\t\t\tif (dp)\n\t\t\t\t\tstep.sliderDataFile = dp->GetPath().ToUTF8().data();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto* fp = XRCCTRL(*this, \"fpSliderDataFile\", wxFilePickerCtrl);\n\t\t\t\tif (fp)\n\t\t\t\t\tstep.sliderDataFile = fp->GetPath().ToUTF8().data();\n\t\t\t}\n\t\t\tstep.sliderMerge = GetCheckboxValue(\"chkSliderMerge\");\n\t\t\tstep.sliderNames = GetVectorValue(\"txtSliderNames\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ImportFile: {\n\t\t\tauto* chkFolder = XRCCTRL(*this, \"chkImportFromFolder\", wxCheckBox);\n\t\t\tstep.importFromFolder = chkFolder && chkFolder->GetValue();\n\t\t\tif (step.importFromFolder) {\n\t\t\t\tauto* dp = XRCCTRL(*this, \"dpImportFolder\", wxDirPickerCtrl);\n\t\t\t\tif (dp)\n\t\t\t\t\tstep.importFilePath = dp->GetPath().ToUTF8().data();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto* fp = XRCCTRL(*this, \"fpImportFile\", wxFilePickerCtrl);\n\t\t\t\tif (fp)\n\t\t\t\t\tstep.importFilePath = fp->GetPath().ToUTF8().data();\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::SetSliderValues: {\n\t\t\tstep.setSliderNames = GetVectorValue(\"txtSetSliderNames\");\n\t\t\tstep.setSliderValue = GetFloatValue(\"txtSetSliderValue\") / 100.0f;\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::SetSliderProperties: {\n\t\t\tstep.sliderPropNames = GetVectorValue(\"txtSliderPropNames\");\n\t\t\tauto* choiceZap = XRCCTRL(*this, \"choiceSliderPropZap\", wxChoice);\n\t\t\tif (choiceZap) {\n\t\t\t\tint sel = choiceZap->GetSelection();\n\t\t\t\tstep.sliderPropZap = sel <= 0 ? -1 : sel - 1;\n\t\t\t}\n\t\t\tauto* choiceHidden = XRCCTRL(*this, \"choiceSliderPropHidden\", wxChoice);\n\t\t\tif (choiceHidden) {\n\t\t\t\tint sel = choiceHidden->GetSelection();\n\t\t\t\tstep.sliderPropHidden = sel <= 0 ? -1 : sel - 1;\n\t\t\t}\n\n\t\t\tbool isZap = step.sliderPropZap == 1;\n\t\t\tif (isZap) {\n\t\t\t\t// Read from zapped choice instead of lo/hi text fields\n\t\t\t\tauto* choiceZapped = XRCCTRL(*this, \"choiceSliderPropZapped\", wxChoice);\n\t\t\t\tif (choiceZapped) {\n\t\t\t\t\tint sel = choiceZapped->GetSelection();\n\t\t\t\t\tif (sel == 2) {\n\t\t\t\t\t\tstep.sliderPropDefaultLo = 100;\n\t\t\t\t\t\tstep.sliderPropDefaultHi = 100;\n\t\t\t\t\t}\n\t\t\t\t\telse if (sel == 1) {\n\t\t\t\t\t\tstep.sliderPropDefaultLo = 0;\n\t\t\t\t\t\tstep.sliderPropDefaultHi = 0;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tstep.sliderPropDefaultLo = -1;\n\t\t\t\t\t\tstep.sliderPropDefaultHi = -1;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto* txtLo = XRCCTRL(*this, \"txtSliderPropDefaultLo\", wxTextCtrl);\n\t\t\t\tif (txtLo) {\n\t\t\t\t\twxString val = txtLo->GetValue().Trim();\n\t\t\t\t\tstep.sliderPropDefaultLo = val.IsEmpty() ? -1 : wxAtoi(val);\n\t\t\t\t}\n\t\t\t\tauto* txtHi = XRCCTRL(*this, \"txtSliderPropDefaultHi\", wxTextCtrl);\n\t\t\t\tif (txtHi) {\n\t\t\t\t\twxString val = txtHi->GetValue().Trim();\n\t\t\t\t\tstep.sliderPropDefaultHi = val.IsEmpty() ? -1 : wxAtoi(val);\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::DeleteShape:\n\t\t\t// No parameters — uses Target Meshes\n\t\t\tbreak;\n\t\tcase AutomationStepType::RenameShape: {\n\t\t\tstep.renameOldName = GetTextValue(\"txtRenameOldName\");\n\t\t\tstep.renameNewName = GetTextValue(\"txtRenameNewName\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::DeleteSlider: {\n\t\t\tstep.deleteSliderNames = GetVectorValue(\"txtDeleteSliderName\");\n\t\t\tstep.deleteSliderRegex = GetCheckboxValue(\"chkDeleteSliderRegex\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::SetReferenceShape: {\n\t\t\tstep.setRefShapeName = GetTextValue(\"txtSetRefShapeName\");\n\t\t\tstep.setRefUnset = GetCheckboxValue(\"chkSetRefUnset\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::RefineMesh:\n\t\tcase AutomationStepType::SetBaseShape:\n\t\tcase AutomationStepType::ClearReference:\n\t\tcase AutomationStepType::RemoveSkinning:\n\t\t\t// No parameters to read\n\t\t\tbreak;\n\t\tcase AutomationStepType::TransformShape: {\n\t\t\tstep.moveX = GetFloatValue(\"txtMoveX\");\n\t\t\tstep.moveY = GetFloatValue(\"txtMoveY\");\n\t\t\tstep.moveZ = GetFloatValue(\"txtMoveZ\");\n\t\t\tstep.rotateX = GetFloatValue(\"txtRotateX\");\n\t\t\tstep.rotateY = GetFloatValue(\"txtRotateY\");\n\t\t\tstep.rotateZ = GetFloatValue(\"txtRotateZ\");\n\t\t\tstep.scaleX = GetFloatValue(\"txtScaleX\");\n\t\t\tstep.scaleY = GetFloatValue(\"txtScaleY\");\n\t\t\tstep.scaleZ = GetFloatValue(\"txtScaleZ\");\n\t\t\tstep.inflateX = GetFloatValue(\"txtInflateX\");\n\t\t\tstep.inflateY = GetFloatValue(\"txtInflateY\");\n\t\t\tstep.inflateZ = GetFloatValue(\"txtInflateZ\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::InvertUVs: {\n\t\t\tstep.invertU = GetCheckboxValue(\"chkInvertU\");\n\t\t\tstep.invertV = GetCheckboxValue(\"chkInvertV\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::DeleteBones: {\n\t\t\tstep.deleteBoneNames = GetVectorValue(\"txtDeleteBoneNames\");\n\t\t\tstep.deleteBoneFromProject = GetCheckboxValue(\"chkDeleteBoneFromProject\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::AddCustomBone: {\n\t\t\tstep.addBoneName = GetTextValue(\"txtAddBoneName\");\n\t\t\tstep.addBoneParent = GetTextValue(\"txtAddBoneParent\");\n\t\t\tstep.addBoneTransX = GetFloatValue(\"txtAddBoneTransX\");\n\t\t\tstep.addBoneTransY = GetFloatValue(\"txtAddBoneTransY\");\n\t\t\tstep.addBoneTransZ = GetFloatValue(\"txtAddBoneTransZ\");\n\t\t\tstep.addBoneRotX = GetFloatValue(\"txtAddBoneRotX\");\n\t\t\tstep.addBoneRotY = GetFloatValue(\"txtAddBoneRotY\");\n\t\t\tstep.addBoneRotZ = GetFloatValue(\"txtAddBoneRotZ\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::EditBone: {\n\t\t\tstep.editBoneName = GetTextValue(\"txtEditBoneName\");\n\t\t\tstep.editBoneParent = GetTextValue(\"txtEditBoneParent\");\n\t\t\tstep.editBoneTransX = GetFloatValue(\"txtEditBoneTransX\");\n\t\t\tstep.editBoneTransY = GetFloatValue(\"txtEditBoneTransY\");\n\t\t\tstep.editBoneTransZ = GetFloatValue(\"txtEditBoneTransZ\");\n\t\t\tstep.editBoneRotX = GetFloatValue(\"txtEditBoneRotX\");\n\t\t\tstep.editBoneRotY = GetFloatValue(\"txtEditBoneRotY\");\n\t\t\tstep.editBoneRotZ = GetFloatValue(\"txtEditBoneRotZ\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ApplyPose: {\n\t\t\tstep.poseName = GetTextValue(\"txtPoseName\");\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::SaveProject: {\n\t\t\tstep.saveName = GetTextValue(\"txtSaveDisplayName\");\n\t\t\tstep.saveOutputFileName = GetTextValue(\"txtSaveOutputFileName\");\n\t\t\tstep.saveOutputDataPath = GetTextValue(\"txtSaveOutputDataPath\");\n\t\t\tstep.saveSliderSetFile = GetTextValue(\"txtSaveSliderSetFile\");\n\t\t\tstep.saveShapeDataFolder = GetTextValue(\"txtSaveShapeDataFolder\");\n\t\t\tstep.saveShapeDataFile = GetTextValue(\"txtSaveShapeDataFile\");\n\n\t\t\tstep.saveGenWeights = GetCheckboxValue(\"chkSaveGenWeights\");\n\t\t\tstep.saveAutoCopyRef = GetCheckboxValue(\"chkSaveAutoCopyRef\");\n\t\t\tstep.saveCopyRefFromProject = GetCheckboxValue(\"chkSaveCopyRefFromProject\");\n\t\t\tstep.saveCopyRefShapeName = GetTextValue(\"txtSaveCopyRefShapeName\");\n\t\t\tstep.saveUseOriginal = GetCheckboxValue(\"chkSaveUseOriginal\");\n\t\t\tstep.saveReplaceFrom = GetTextValue(\"txtSaveReplaceFrom\");\n\t\t\tstep.saveReplaceTo = GetTextValue(\"txtSaveReplaceTo\");\n\t\t\tstep.saveSuffix = GetTextValue(\"txtSaveSuffix\");\n\t\t\tbreak;\n\t\t}\n\t\tcase AutomationStepType::ExportFile: {\n\t\t\tbool isBatch = radioBatchMode && radioBatchMode->GetSelection() != 0;\n\t\t\tif (isBatch) {\n\t\t\t\tauto* dp = XRCCTRL(*this, \"dpExportFolder\", wxDirPickerCtrl);\n\t\t\t\tif (dp)\n\t\t\t\t\tstep.exportFilePath = dp->GetPath().ToUTF8().data();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto* fp = XRCCTRL(*this, \"fpExportFile\", wxFilePickerCtrl);\n\t\t\t\tif (fp)\n\t\t\t\t\tstep.exportFilePath = fp->GetPath().ToUTF8().data();\n\t\t\t}\n\t\t\tstep.exportWithRef = GetCheckboxValue(\"chkExportWithRef\");\n\t\t\tstep.exportUseOriginalPath = GetCheckboxValue(\"chkExportUseOriginalPath\");\n\t\t\tstep.exportPrefix = GetTextValue(\"txtExportPrefix\");\n\t\t\tstep.exportSuffix = GetTextValue(\"txtExportSuffix\");\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::ResetTransforms:\n\t\t\t// No parameters to read\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::DuplicateShape: {\n\t\t\tstep.dupNewName = GetTextValue(\"txtDupNewName\");\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::MirrorShape: {\n\t\t\tstep.mirrorX = GetCheckboxValue(\"chkMirrorX\");\n\t\t\tstep.mirrorY = GetCheckboxValue(\"chkMirrorY\");\n\t\t\tstep.mirrorZ = GetCheckboxValue(\"chkMirrorZ\");\n\t\t\tstep.mirrorSwapBonesX = GetCheckboxValue(\"chkMirrorSwapBonesX\");\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::ClearMask:\n\t\t\t// No parameters to read\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::LoadMask: {\n\t\t\tauto* fp = XRCCTRL(*this, \"fpLoadMaskFile\", wxFilePickerCtrl);\n\t\t\tif (fp)\n\t\t\t\tstep.loadMaskFile = MakeRelativeToProject(fp->GetPath()).ToUTF8().data();\n\t\t\tauto* choice = XRCCTRL(*this, \"choiceLoadMaskName\", wxChoice);\n\t\t\tif (choice && choice->GetSelection() != wxNOT_FOUND)\n\t\t\t\tstep.loadMaskName = choice->GetStringSelection().ToUTF8().data();\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::RemoveUnusedNodes:\n\t\t\t// No parameters to read\n\t\t\tbreak;\n\n\t\tcase AutomationStepType::FixClipping: {\n\t\t\tauto* choice = XRCCTRL(*this, \"choiceFixClipMode\", wxChoice);\n\t\t\tif (choice)\n\t\t\t\tstep.fixClipMode = choice->GetSelection();\n\t\t\tstep.fixClipStrength = GetFloatValue(\"txtFixClipStrength\") / 100.0f;\n\t\t\tstep.fixClipSliderNames = GetVectorValue(\"txtFixClipSliderNames\");\n\t\t\tbreak;\n\t\t}\n\n\t\tcase AutomationStepType::FixBadBones:\n\t\t\t// No parameters to read\n\t\t\tbreak;\n\t}\n\n\tRefreshStepRow(selectedStep);\n}\n\nstd::map<std::string, std::string> AutomationDialog::CollectVariables() {\n\tstd::map<std::string, std::string> vars;\n\n\t// Collect from the variables panel\n\tfor (int i = 1; i <= 10; i++) {\n\t\twxString keyName = wxString::Format(\"txtVarKey%d\", i);\n\t\twxString valName = wxString::Format(\"txtVarVal%d\", i);\n\t\tauto* keyCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(keyName));\n\t\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(valName));\n\t\tif (keyCtrl && valCtrl) {\n\t\t\tstd::string key = keyCtrl->GetValue().ToUTF8().data();\n\t\t\tstd::string val = valCtrl->GetValue().ToUTF8().data();\n\t\t\tif (!key.empty())\n\t\t\t\tvars[key] = val;\n\t\t}\n\t}\n\n\treturn vars;\n}\n\nNiShape* AutomationDialog::FindShapeByName(const std::string& name) {\n\tauto shapes = project->GetWorkNif()->GetShapes();\n\tfor (auto* shape : shapes) {\n\t\tif (shape->name.get() == name)\n\t\t\treturn shape;\n\t}\n\treturn nullptr;\n}\n\nstd::vector<NiShape*> AutomationDialog::ResolveTargetShapes(const AutomationStep& step) {\n\tif (step.targetMeshes.empty()) {\n\t\tauto allShapes = project->GetWorkNif()->GetShapes();\n\t\tstd::vector<NiShape*> result;\n\t\tauto* baseShape = project->GetBaseShape();\n\t\tfor (auto* shape : allShapes) {\n\t\t\tif (shape != baseShape)\n\t\t\t\tresult.push_back(shape);\n\t\t}\n\t\treturn result;\n\t}\n\n\tstd::vector<NiShape*> result;\n\n\tif (step.targetRegex) {\n\t\tauto allShapes = project->GetWorkNif()->GetShapes();\n\t\tfor (const auto& pattern : step.targetMeshes) {\n\t\t\ttry {\n\t\t\t\tstd::regex re(pattern, std::regex::icase);\n\t\t\t\tfor (auto* shape : allShapes) {\n\t\t\t\t\tif (std::regex_search(shape->name.get(), re)) {\n\t\t\t\t\t\t// Avoid duplicates\n\t\t\t\t\t\tif (std::find(result.begin(), result.end(), shape) == result.end())\n\t\t\t\t\t\t\tresult.push_back(shape);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcatch (const std::regex_error&) {\n\t\t\t\twxLogWarning(\"Automation: Invalid regex pattern '%s', treating as literal.\", pattern);\n\t\t\t\tNiShape* shape = FindShapeByName(pattern);\n\t\t\t\tif (shape && std::find(result.begin(), result.end(), shape) == result.end())\n\t\t\t\t\tresult.push_back(shape);\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor (const auto& name : step.targetMeshes) {\n\t\t\tNiShape* shape = FindShapeByName(name);\n\t\t\tif (shape)\n\t\t\t\tresult.push_back(shape);\n\t\t}\n\t}\n\n\treturn result;\n}\n\nstd::string AutomationDialog::GetAutomationsFolder() {\n\treturn GetProjectPath() + \"/Automations\";\n}\n\nvoid AutomationDialog::CollectScripts(const wxString& baseFolder, const wxString& currentFolder, std::vector<std::pair<wxString, wxString>>& entries) {\n\twxDir dir(currentFolder);\n\tif (!dir.IsOpened())\n\t\treturn;\n\n\t// Collect .xml files in this folder\n\twxString filename;\n\tif (dir.GetFirst(&filename, \"*.xml\", wxDIR_FILES)) {\n\t\tdo {\n\t\t\twxString fullPath = currentFolder + \"/\" + filename;\n\n\t\t\t// Only include files whose root element is <AutomationScript>\n\t\t\ttinyxml2::XMLDocument doc;\n\t\t\tif (doc.LoadFile(fullPath.ToUTF8().data()) != tinyxml2::XML_SUCCESS)\n\t\t\t\tcontinue;\n\t\t\tif (!doc.FirstChildElement(\"AutomationScript\"))\n\t\t\t\tcontinue;\n\n\t\t\twxFileName fn(filename);\n\t\t\twxString relativePath;\n\t\t\tif (currentFolder == baseFolder) {\n\t\t\t\trelativePath = fn.GetName();\n\t\t\t}\n\t\t\telse {\n\t\t\t\twxString subPath;\n\t\t\t\twxFileName::SplitPath(currentFolder, nullptr, nullptr, &subPath);\n\t\t\t\t// Get the relative folder path from baseFolder\n\t\t\t\twxString relFolder = currentFolder.Mid(baseFolder.length() + 1);\n\t\t\t\trelativePath = relFolder + \"/\" + fn.GetName();\n\t\t\t}\n\t\t\tentries.push_back({relativePath, relativePath});\n\t\t} while (dir.GetNext(&filename));\n\t}\n\n\t// Recurse into subdirectories\n\twxString dirName;\n\tif (dir.GetFirst(&dirName, wxEmptyString, wxDIR_DIRS)) {\n\t\tdo {\n\t\t\tCollectScripts(baseFolder, currentFolder + \"/\" + dirName, entries);\n\t\t} while (dir.GetNext(&dirName));\n\t}\n}\n\nvoid AutomationDialog::PopulateAutomationList() {\n\tif (!cmbAutomation)\n\t\treturn;\n\n\twxString currentText = cmbAutomation->GetValue();\n\tcmbAutomation->Clear();\n\tcmbAutomation->Append(_(\"<New>\"));\n\n\twxString folder = wxString::FromUTF8(GetAutomationsFolder());\n\tif (!wxDir::Exists(folder)) {\n\t\tif (!currentText.IsEmpty())\n\t\t\tcmbAutomation->SetValue(currentText);\n\t\treturn;\n\t}\n\n\t// Collect all scripts recursively: {relativePath, displayName}\n\tstd::vector<std::pair<wxString, wxString>> entries;\n\tCollectScripts(folder, folder, entries);\n\n\t// Separate root-level scripts from subfolder scripts\n\tstd::vector<wxString> rootScripts;\n\tstd::map<wxString, std::vector<wxString>> folderScripts;\n\n\tfor (auto& [path, display] : entries) {\n\t\tint sep = path.Find('/');\n\t\tif (sep == wxNOT_FOUND) {\n\t\t\trootScripts.push_back(path);\n\t\t}\n\t\telse {\n\t\t\twxString folderName = path.Left(sep);\n\t\t\tfolderScripts[folderName].push_back(path);\n\t\t}\n\t}\n\n\t// Sort root scripts (case-insensitive)\n\tstd::sort(rootScripts.begin(), rootScripts.end(),\n\t\t[](const wxString& a, const wxString& b) { return a.CmpNoCase(b) < 0; });\n\n\t// Add root-level scripts\n\tfor (auto& name : rootScripts)\n\t\tcmbAutomation->Append(name);\n\n\t// Add folder groups with separator headers\n\tfor (auto& [folderName, scripts] : folderScripts) {\n\t\tstd::sort(scripts.begin(), scripts.end(),\n\t\t\t[](const wxString& a, const wxString& b) { return a.CmpNoCase(b) < 0; });\n\n\t\t// Separator header\n\t\twxString separator = wxS(\"\\u2500\\u2500\\u2500 \") + folderName + wxS(\" \\u2500\\u2500\\u2500\");\n\t\tcmbAutomation->Append(separator);\n\n\t\tfor (auto& path : scripts)\n\t\t\tcmbAutomation->Append(path);\n\t}\n\n\tif (!currentText.IsEmpty())\n\t\tcmbAutomation->SetValue(currentText);\n}\n\nbool AutomationDialog::IsSeparatorItem(const wxString& text) {\n\treturn text.StartsWith(wxS(\"\\u2500\"));\n}\n\nwxString AutomationDialog::SanitizePath(const wxString& name) {\n\twxString result;\n\tbool lastWasSep = false;\n\tfor (auto ch : name) {\n\t\tif (ch == '/') {\n\t\t\tif (!result.IsEmpty() && !lastWasSep)\n\t\t\t\tresult += '/';\n\t\t\tlastWasSep = true;\n\t\t}\n\t\telse if (ch == '<' || ch == '>' || ch == ':' || ch == '\"' || ch == '\\\\' || ch == '|' || ch == '?' || ch == '*') {\n\t\t\tresult += '_';\n\t\t\tlastWasSep = false;\n\t\t}\n\t\telse {\n\t\t\tresult += ch;\n\t\t\tlastWasSep = false;\n\t\t}\n\t}\n\t// Trim trailing separator\n\tif (result.EndsWith(\"/\"))\n\t\tresult.RemoveLast();\n\treturn result;\n}\n\nvoid AutomationDialog::LoadAutomation(const wxString& name) {\n\tif (name.IsEmpty())\n\t\treturn;\n\n\twxString sanitized = SanitizePath(name);\n\twxString filePath = wxString::FromUTF8(GetAutomationsFolder()) + \"/\" + sanitized + \".xml\";\n\n\tif (!wxFileExists(filePath))\n\t\treturn;\n\n\tint err = script.Load(filePath.ToUTF8().data());\n\tif (err) {\n\t\twxMessageBox(wxString::Format(_(\"Failed to load automation script (error %d).\"), err), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tselectedStep = -1;\n\tShowStepSettings(false);\n\tPopulateStepList();\n\tPopulateVariablesUI();\n\tSyncBatchUIFromScript();\n\n\t// Expand panes based on loaded script content\n\tauto* paneVariables = XRCCTRL(*this, \"paneVariables\", wxCollapsiblePane);\n\tauto* paneBatch = XRCCTRL(*this, \"paneBatch\", wxCollapsiblePane);\n\tif (paneVariables)\n\t\tpaneVariables->Collapse(script.GetVariables().empty());\n\tif (paneBatch)\n\t\tpaneBatch->Collapse(script.GetBatchMode() == AutomationBatchMode::None);\n\n\tUpdateButtonState();\n\tGetSizer()->Layout();\n}\n\nvoid AutomationDialog::UpdateButtonState() {\n\tbool hasSteps = !script.GetSteps().empty();\n\tif (btnSaveScript)\n\t\tbtnSaveScript->Enable(hasSteps && !isExecuting);\n\tif (btnExecuteAll)\n\t\tbtnExecuteAll->Enable(hasSteps && !isExecuting);\n}\n\nvoid AutomationDialog::OnAutomationSelected(wxCommandEvent& WXUNUSED(event)) {\n\twxString name = cmbAutomation->GetValue();\n\n\t// Ignore separator header items\n\tif (IsSeparatorItem(name)) {\n\t\tcmbAutomation->SetValue(wxEmptyString);\n\t\treturn;\n\t}\n\n\tif (name == _(\"<New>\")) {\n\t\tscript = AutomationScript();\n\t\tselectedStep = -1;\n\t\tShowStepSettings(false);\n\t\tPopulateStepList();\n\t\tPopulateVariablesUI();\n\t\tSyncBatchUIFromScript();\n\n\t\tauto* paneVariables = XRCCTRL(*this, \"paneVariables\", wxCollapsiblePane);\n\t\tauto* paneBatch = XRCCTRL(*this, \"paneBatch\", wxCollapsiblePane);\n\t\tif (paneVariables)\n\t\t\tpaneVariables->Collapse(true);\n\t\tif (paneBatch)\n\t\t\tpaneBatch->Collapse(true);\n\n\t\tcmbAutomation->SetValue(wxEmptyString);\n\t\tUpdateButtonState();\n\t\tGetSizer()->Layout();\n\t\treturn;\n\t}\n\tLoadAutomation(name);\n}\n\nvoid AutomationDialog::OnSaveScript(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedStep >= 0)\n\t\tUpdateStepFromUI();\n\n\t// Sync variables and batch settings from UI to script before saving\n\tscript.GetVariables() = CollectVariables();\n\tSyncBatchScriptFromUI();\n\n\twxString name = cmbAutomation ? cmbAutomation->GetValue().Trim().Trim(false) : wxString();\n\tif (name.IsEmpty()) {\n\t\twxMessageBox(_(\"Please enter an automation name.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\twxString sanitized = SanitizePath(name);\n\twxString folder = wxString::FromUTF8(GetAutomationsFolder());\n\n\t// Create folder (including subdirectories) if missing\n\twxFileName fnPath(folder + \"/\" + sanitized + \".xml\");\n\tif (!wxDir::Exists(fnPath.GetPath()))\n\t\twxFileName::Mkdir(fnPath.GetPath(), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\twxString filePath = fnPath.GetFullPath();\n\tint err = script.Save(filePath.ToUTF8().data());\n\tif (err) {\n\t\twxMessageBox(wxString::Format(_(\"Failed to save automation script (error %d).\"), err), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tPopulateAutomationList();\n\tcmbAutomation->SetValue(sanitized);\n}\n\nvoid AutomationDialog::OnDeleteScript(wxCommandEvent& WXUNUSED(event)) {\n\twxString name = cmbAutomation ? cmbAutomation->GetValue().Trim().Trim(false) : wxString();\n\tif (name.IsEmpty()) {\n\t\twxMessageBox(_(\"No automation selected to delete.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\twxString sanitized = SanitizePath(name);\n\twxString filePath = wxString::FromUTF8(GetAutomationsFolder()) + \"/\" + sanitized + \".xml\";\n\n\tif (!wxFileExists(filePath)) {\n\t\twxMessageBox(_(\"Automation file not found.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\tint answer = wxMessageBox(\n\t\twxString::Format(_(\"Delete automation '%s'?\\nThis cannot be undone.\"), name),\n\t\t_(\"Confirm Delete\"), wxYES_NO | wxICON_QUESTION);\n\tif (answer != wxYES)\n\t\treturn;\n\n\twxRemoveFile(filePath);\n\n\t// Clear current script\n\tscript = AutomationScript();\n\tselectedStep = -1;\n\tShowStepSettings(false);\n\tPopulateStepList();\n\tPopulateVariablesUI();\n\tSyncBatchUIFromScript();\n\tPopulateAutomationList();\n\tcmbAutomation->SetValue(wxEmptyString);\n\tUpdateButtonState();\n\tGetSizer()->Layout();\n}\n\nvoid AutomationDialog::OnOpenFolder(wxCommandEvent& WXUNUSED(event)) {\n\twxString folder = MakeAbsoluteToProject(wxString::FromUTF8(GetAutomationsFolder()));\n\tif (!wxDir::Exists(folder))\n\t\twxFileName::Mkdir(folder, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\twxLaunchDefaultApplication(folder);\n}\n\nvoid AutomationDialog::OnAddStep(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedStep >= 0)\n\t\tUpdateStepFromUI();\n\n\tAutomationStep step;\n\tstep.type = AutomationStepType::ClearProject;\n\n\t// Prefill SaveProject fields from current project state\n\tstep.saveName = project->mOutfitName;\n\tstep.saveOutputFileName = project->mGameFile;\n\tstep.saveOutputDataPath = project->mGamePath;\n\tstep.saveSliderSetFile = project->mFileName;\n\tstep.saveShapeDataFolder = project->mDataDir;\n\tstep.saveShapeDataFile = project->mBaseFile;\n\tApplyBatchModeDefaults(step);\n\n\tint newIndex;\n\tif (selectedStep >= 0) {\n\t\tnewIndex = selectedStep + 1;\n\t\tscript.InsertStep(newIndex, step);\n\t}\n\telse {\n\t\tscript.AddStep(step);\n\t\tnewIndex = static_cast<int>(script.GetSteps().size()) - 1;\n\t}\n\n\tPopulateStepList();\n\n\tlistSteps->SetItemState(newIndex, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);\n\tlistSteps->EnsureVisible(newIndex);\n\tSelectStep(newIndex);\n\tUpdateButtonState();\n}\n\nvoid AutomationDialog::OnDuplicateStep(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedStep < 0 || selectedStep >= static_cast<int>(script.GetSteps().size()))\n\t\treturn;\n\n\tUpdateStepFromUI();\n\n\tAutomationStep copy = script.GetSteps()[selectedStep];\n\tint newIndex = selectedStep + 1;\n\tscript.InsertStep(newIndex, copy);\n\n\tPopulateStepList();\n\n\tlistSteps->SetItemState(newIndex, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);\n\tlistSteps->EnsureVisible(newIndex);\n\tSelectStep(newIndex);\n\tUpdateButtonState();\n}\n\nvoid AutomationDialog::OnRemoveStep(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedStep < 0)\n\t\treturn;\n\n\tscript.RemoveStep(selectedStep);\n\tint prevSelected = selectedStep;\n\tselectedStep = -1;\n\tPopulateStepList();\n\n\tif (!script.GetSteps().empty()) {\n\t\tint newSel = std::min(prevSelected, static_cast<int>(script.GetSteps().size()) - 1);\n\t\tlistSteps->SetItemState(newSel, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);\n\t\tSelectStep(newSel);\n\t}\n\telse {\n\t\tShowStepSettings(false);\n\t}\n\tUpdateButtonState();\n}\n\nvoid AutomationDialog::OnMoveUp(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedStep <= 0)\n\t\treturn;\n\n\tUpdateStepFromUI();\n\tscript.MoveStepUp(selectedStep);\n\tint newSel = selectedStep - 1;\n\tselectedStep = -1;\n\tPopulateStepList();\n\tlistSteps->SetItemState(newSel, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);\n\tSelectStep(newSel);\n}\n\nvoid AutomationDialog::OnMoveDown(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedStep < 0 || selectedStep + 1 >= static_cast<int>(script.GetSteps().size()))\n\t\treturn;\n\n\tUpdateStepFromUI();\n\tscript.MoveStepDown(selectedStep);\n\tint newSel = selectedStep + 1;\n\tselectedStep = -1;\n\tPopulateStepList();\n\tlistSteps->SetItemState(newSel, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);\n\tSelectStep(newSel);\n}\n\nvoid AutomationDialog::OnStepListKeyDown(wxKeyEvent& event) {\n\tif (event.ControlDown()) {\n\t\twxCommandEvent evt;\n\t\tif (event.GetKeyCode() == WXK_UP) {\n\t\t\tOnMoveUp(evt);\n\t\t\treturn;\n\t\t}\n\t\telse if (event.GetKeyCode() == WXK_DOWN) {\n\t\t\tOnMoveDown(evt);\n\t\t\treturn;\n\t\t}\n\t}\n\tevent.Skip();\n}\n\nvoid AutomationDialog::OnStepSelected(wxListEvent& event) {\n\tSelectStep(event.GetIndex());\n\n\t// Restore focus to the list so arrow keys continue to work\n\tif (listSteps)\n\t\tlistSteps->SetFocus();\n}\n\nvoid AutomationDialog::OnStepTypeChanged(wxCommandEvent& WXUNUSED(event)) {\n\tint sel = choiceStepType->GetSelection();\n\tif (sel < 0)\n\t\treturn;\n\n\tif (selectedStep < 0 || selectedStep >= static_cast<int>(script.GetSteps().size())) {\n\t\tbookStepPages->SetSelection(sel);\n\t\treturn;\n\t}\n\n\tauto& step = script.GetSteps()[selectedStep];\n\tstep.active = chkActive->GetValue();\n\tstep.note = txtNote->GetValue().ToUTF8().data();\n\tstep.targetMeshes = SplitCommaSeparated(std::string(txtTargetMeshes->GetValue().ToUTF8().data()));\n\tstep.targetRegex = chkTargetRegex ? chkTargetRegex->GetValue() : false;\n\tstep.type = static_cast<AutomationStepType>(sel);\n\tApplyBatchModeDefaults(step);\n\n\tRefreshStepRow(selectedStep);\n\tUpdateUIFromStep(step);\n}\n\nbool AutomationDialog::ShowCheckableListDialog(const wxString& title, const wxString& labelText, const wxArrayString& items, std::vector<size_t>& checkedIndices) {\n\twxDialog dlg(this, wxID_ANY, title, wxDefaultPosition, wxSize(800, 500), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* label = new wxStaticText(&dlg, wxID_ANY, labelText);\n\tsizer->Add(label, 0, wxALL, 10);\n\n\tauto* checkList = new wxCheckListBox(&dlg, wxID_ANY, wxDefaultPosition, wxDefaultSize, items, wxLB_HSCROLL | wxLB_NEEDED_SB);\n\tfor (unsigned int i = 0; i < checkList->GetCount(); i++)\n\t\tcheckList->Check(i);\n\n\tsizer->Add(checkList, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10);\n\n\tauto* btnSizer = new wxBoxSizer(wxHORIZONTAL);\n\tauto* btnAll = new wxButton(&dlg, wxID_ANY, _(\"Select All\"));\n\tauto* btnNone = new wxButton(&dlg, wxID_ANY, _(\"Select None\"));\n\tauto* btnInvert = new wxButton(&dlg, wxID_ANY, _(\"Invert Selection\"));\n\tbtnSizer->Add(btnAll, 0, wxRIGHT, 5);\n\tbtnSizer->Add(btnNone, 0, wxRIGHT, 5);\n\tbtnSizer->Add(btnInvert, 0, wxRIGHT, 5);\n\tbtnSizer->AddStretchSpacer();\n\tauto* btnOK = new wxButton(&dlg, wxID_OK, _(\"Execute\"));\n\tauto* btnCancel = new wxButton(&dlg, wxID_CANCEL, _(\"Cancel\"));\n\tbtnSizer->Add(btnOK, 0, wxRIGHT, 5);\n\tbtnSizer->Add(btnCancel, 0);\n\tsizer->Add(btnSizer, 0, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 10);\n\n\tbtnAll->Bind(wxEVT_BUTTON, [checkList](wxCommandEvent&) {\n\t\tfor (unsigned int i = 0; i < checkList->GetCount(); i++)\n\t\t\tcheckList->Check(i);\n\t});\n\tbtnNone->Bind(wxEVT_BUTTON, [checkList](wxCommandEvent&) {\n\t\tfor (unsigned int i = 0; i < checkList->GetCount(); i++)\n\t\t\tcheckList->Check(i, false);\n\t});\n\tbtnInvert->Bind(wxEVT_BUTTON, [checkList](wxCommandEvent&) {\n\t\tfor (unsigned int i = 0; i < checkList->GetCount(); i++)\n\t\t\tcheckList->Check(i, !checkList->IsChecked(i));\n\t});\n\n\tdlg.SetSizer(sizer);\n\tdlg.CenterOnParent();\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn false;\n\n\tcheckedIndices.clear();\n\tfor (unsigned int i = 0; i < checkList->GetCount(); i++) {\n\t\tif (checkList->IsChecked(i))\n\t\t\tcheckedIndices.push_back(i);\n\t}\n\n\treturn true;\n}\n\nvoid AutomationDialog::OnExecuteAll(wxCommandEvent& WXUNUSED(event)) {\n\tif (isExecuting)\n\t\treturn;\n\n\tif (selectedStep >= 0)\n\t\tUpdateStepFromUI();\n\n\tSyncBatchScriptFromUI();\n\n\tstd::vector<size_t> indices;\n\tfor (size_t i = 0; i < script.GetSteps().size(); i++) {\n\t\tif (script.GetSteps()[i].active)\n\t\t\tindices.push_back(i);\n\t}\n\n\tif (indices.empty()) {\n\t\twxMessageBox(_(\"No active steps to execute.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\tif (script.GetBatchMode() != AutomationBatchMode::None) {\n\t\t// Show confirmation with item count and batch details\n\t\tint itemCount = 0;\n\t\twxString batchDetails;\n\n\t\tif (script.GetBatchMode() == AutomationBatchMode::FolderScan) {\n\t\t\tauto files = GatherBatchFiles();\n\t\t\titemCount = static_cast<int>(files.size());\n\n\t\t\tif (itemCount == 0) {\n\t\t\t\twxMessageBox(_(\"No files found matching the batch folder scan criteria.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (itemCount <= 1000) {\n\t\t\t\twxArrayString displayItems;\n\t\t\t\tfor (const auto& filePath : files)\n\t\t\t\t\tdisplayItems.Add(wxString::FromUTF8(filePath));\n\n\t\t\t\tstd::vector<size_t> checkedIndices;\n\t\t\t\tif (!ShowCheckableListDialog(_(\"Batch Files\"), wxString::Format(_(\"Select files to process (%d found):\"), itemCount), displayItems, checkedIndices))\n\t\t\t\t\treturn;\n\n\t\t\t\tif (checkedIndices.empty()) {\n\t\t\t\t\twxMessageBox(_(\"No files selected.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tstd::vector<std::string> selectedFiles;\n\t\t\t\tfor (size_t idx : checkedIndices)\n\t\t\t\t\tselectedFiles.push_back(files[idx]);\n\n\t\t\t\tExecuteBatch(indices, selectedFiles);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// More than 1000 files: skip list, show confirmation\n\t\t\tbatchDetails = wxString::Format(_(\"Folder: %s\\nExtension: %s\"), wxString::FromUTF8(script.GetBatchFolder()), wxString::FromUTF8(script.GetBatchExtension()));\n\n\t\t\tstd::string filter = script.GetBatchFileFilter();\n\t\t\tif (!filter.empty())\n\t\t\t\tbatchDetails += wxString::Format(_(\"\\nFile filter: %s%s\"), wxString::FromUTF8(filter), script.GetBatchFileFilterRegex() ? \" (regex)\" : \"\");\n\t\t}\n\t\telse if (script.GetBatchMode() == AutomationBatchMode::SliderSets) {\n\t\t\tauto sets = GatherBatchSliderSets();\n\t\t\titemCount = static_cast<int>(sets.size());\n\n\t\t\tif (itemCount == 0) {\n\t\t\t\twxMessageBox(_(\"No slider sets found matching the filter criteria.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twxArrayString displayItems;\n\t\t\tfor (const auto& [filePath, setName] : sets)\n\t\t\t\tdisplayItems.Add(wxString::FromUTF8(setName));\n\n\t\t\tstd::vector<size_t> checkedIndices;\n\t\t\tif (!ShowCheckableListDialog(_(\"Batch Slider Sets\"), wxString::Format(_(\"Select slider sets to process (%d found):\"), itemCount), displayItems, checkedIndices))\n\t\t\t\treturn;\n\n\t\t\tif (checkedIndices.empty()) {\n\t\t\t\twxMessageBox(_(\"No slider sets selected.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstd::vector<std::pair<std::string, std::string>> selectedSets;\n\t\t\tfor (size_t idx : checkedIndices)\n\t\t\t\tselectedSets.push_back(sets[idx]);\n\n\t\t\tExecuteBatch(indices, {}, selectedSets);\n\t\t\treturn;\n\t\t}\n\n\t\tif (itemCount == 0) {\n\t\t\twxMessageBox(_(\"No items found matching the batch criteria.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\treturn;\n\t\t}\n\n\t\twxString confirmMsg = wxString::Format(_(\"Execute %zu active step(s) on %d item(s)?\\n\\n%s\\n\\nThis may take a while.\"), indices.size(), itemCount, batchDetails);\n\n\t\tint answer = wxMessageBox(confirmMsg, _(\"Batch Confirmation\"), wxYES_NO | wxICON_QUESTION);\n\t\tif (answer != wxYES)\n\t\t\treturn;\n\n\t\tExecuteBatch(indices);\n\t}\n\telse {\n\t\tint answer = wxMessageBox(wxString::Format(_(\"Execute %zu active step(s) on the current project?\"), indices.size()), _(\"Confirm Execution\"), wxYES_NO | wxICON_QUESTION);\n\t\tif (answer != wxYES)\n\t\t\treturn;\n\n\t\tExecuteSteps(indices);\n\t}\n}\n\nvoid AutomationDialog::OnExecuteSelected(wxCommandEvent& WXUNUSED(event)) {\n\tif (isExecuting)\n\t\treturn;\n\n\tif (selectedStep < 0) {\n\t\twxMessageBox(_(\"No step selected.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\tUpdateStepFromUI();\n\tExecuteSteps({static_cast<size_t>(selectedStep)});\n}\n\nvoid AutomationDialog::OnClose(wxCommandEvent& WXUNUSED(event)) {\n\tif (isExecuting) {\n\t\tcancelRequested = true;\n\t\tif (statusBar)\n\t\t\tstatusBar->SetStatusText(_(\"Cancelling...\"));\n\t\treturn;\n\t}\n\n\tif (selectedStep >= 0)\n\t\tUpdateStepFromUI();\n\tEndModal(wxID_CLOSE);\n}\n\nstatic bool StepChangesSliderSet(AutomationStepType type) {\n\tswitch (type) {\n\t\tcase AutomationStepType::ClearProject:\n\t\tcase AutomationStepType::LoadReference:\n\t\tcase AutomationStepType::AddProject:\n\t\tcase AutomationStepType::DeleteSlider:\n\t\tcase AutomationStepType::ClearReference:\n\t\tcase AutomationStepType::SetBaseShape:\n\t\tcase AutomationStepType::ImportSliderData:\n\t\t\treturn true;\n\t\tdefault:\n\t\t\treturn false;\n\t}\n}\n\nvoid AutomationDialog::ExecuteSteps(const std::vector<size_t>& stepIndices) {\n\t// Make a copy so placeholder substitution doesn't modify the UI version\n\tAutomationScript execScript;\n\tfor (size_t idx : stepIndices)\n\t\texecScript.AddStep(script.GetSteps()[idx]);\n\n\t// Apply placeholder substitution\n\tauto vars = CollectVariables();\n\tif (!vars.empty())\n\t\texecScript.SubstitutePlaceholders(vars);\n\n\tStartProgress(_(\"Running automation script...\"));\n\n\tint totalSteps = static_cast<int>(execScript.GetSteps().size());\n\tfor (int i = 0; i < totalSteps; i++) {\n\t\tconst auto& step = execScript.GetSteps()[i];\n\t\twxString stepDesc = wxString::Format(_(\"Step %d/%d: %s\"),\n\t\t\ti + 1, totalSteps,\n\t\t\twxString::FromUTF8(AutomationStepTypeToString(step.type)));\n\n\t\tUpdateProgress(i * 100 / totalSteps, stepDesc);\n\n\t\tif (cancelRequested) {\n\t\t\twxLogMessage(\"Automation: Cancelled by user.\");\n\t\t\tEndProgress(_(\"Automation cancelled.\"));\n\t\t\treturn;\n\t\t}\n\n\t\twxLogMessage(\"Automation: %s\", stepDesc);\n\n\t\tint err = ExecuteStep(step);\n\t\tif (err != 0) {\n\t\t\twxString errMsg = wxString::Format(\n\t\t\t\t_(\"Step %d (%s) failed with error %d.\\n\\n%s\\n\\nContinue with remaining steps?\"),\n\t\t\t\ti + 1,\n\t\t\t\twxString::FromUTF8(AutomationStepTypeToString(step.type)),\n\t\t\t\terr,\n\t\t\t\twxString::FromUTF8(step.note));\n\n\t\t\tint result = wxMessageBox(errMsg, _(\"Automation Error\"), wxYES_NO | wxICON_ERROR);\n\t\t\tif (result != wxYES) {\n\t\t\t\tEndProgress(_(\"Automation aborted.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\toutfitStudio->RefreshGUIFromProj();\n\n\t\tif (StepChangesSliderSet(step.type))\n\t\t\toutfitStudio->CreateSetSliders();\n\n\t\toutfitStudio->ApplySliders();\n\t}\n\n\tEndProgress(_(\"Automation complete.\"));\n\n\twxMessageBox(wxString::Format(_(\"Automation completed: %d step(s) executed.\"), totalSteps),\n\t\t\t\t _(\"Automation\"), wxICON_INFORMATION);\n}\n\nvoid AutomationDialog::ResetAndClearProject() {\n\tproject->SetBaseShape(nullptr, false);\n\tproject->GetWorkAnim()->Clear();\n\tproject->GetWorkNif()->Clear();\n\toutfitStudio->ResetProject();\n}\n\nint AutomationDialog::ExecuteStepClearProject(const AutomationStep&) {\n\twxLogMessage(\"Automation: Clearing project...\");\n\tResetAndClearProject();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepLoadReference(const AutomationStep& step) {\n\tif (step.refSourceFile.empty()) {\n\t\twxLogError(\"Automation: LoadReference - no source file specified.\");\n\t\treturn 1;\n\t}\n\n\twxString refSourceFile = MakeAbsoluteToProject(wxString::FromUTF8(step.refSourceFile));\n\twxFileName fn(refSourceFile);\n\twxString ext = fn.GetExt().Lower();\n\tstd::string refSourceFileStd = refSourceFile.ToUTF8().data();\n\n\tint err = 0;\n\tif (ext == \"nif\") {\n\t\terr = project->LoadReferenceNif(refSourceFileStd, step.refShape, step.refMergeSliders, step.refMergeZaps);\n\t}\n\telse {\n\t\tif (!step.refSet.empty()) {\n\t\t\terr = project->LoadReference(refSourceFileStd, step.refSet, step.refShape, step.refMergeSliders, step.refMergeZaps, step.refAppendNewSliders);\n\t\t}\n\t\telse {\n\t\t\terr = project->LoadReferenceTemplate(refSourceFileStd, step.refSet, step.refShape, step.refLoadAll, step.refMergeSliders, step.refMergeZaps, step.refAppendNewSliders);\n\t\t}\n\t}\n\n\tif (err) {\n\t\twxLogError(\"Automation: LoadReference failed with error %d.\", err);\n\t\treturn err;\n\t}\n\n\tproject->SetTextures();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepAddProject(const AutomationStep& step) {\n\tif (step.refSourceFile.empty()) {\n\t\twxLogError(\"Automation: AddProject - no source file specified.\");\n\t\treturn 1;\n\t}\n\n\twxString refSourceFile = MakeAbsoluteToProject(wxString::FromUTF8(step.refSourceFile));\n\tstd::string refSourceFileStd = refSourceFile.ToUTF8().data();\n\twxLogMessage(\"Automation: Adding project from '%s' (set: '%s')...\", refSourceFile, step.refSet);\n\tint err = project->AddFromSliderSet(refSourceFileStd, step.refSet, true, step.refAppendNewSliders);\n\tif (err) {\n\t\twxLogError(\"Automation: AddProject failed with error %d.\", err);\n\t\treturn err;\n\t}\n\n\tproject->SetTextures();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepSetSliderValues(const AutomationStep& step) {\n\tint intVal = static_cast<int>(step.setSliderValue * 100);\n\tif (step.setSliderNames.empty()) {\n\t\twxLogMessage(\"Automation: Setting all slider values to %d%%...\", intVal);\n\t\tfor (size_t i = 0; i < project->SliderCount(); i++)\n\t\t\toutfitStudio->SetSliderValue(i, intVal);\n\t}\n\telse {\n\t\tfor (const auto& name : step.setSliderNames) {\n\t\t\tif (!project->ValidSlider(name)) {\n\t\t\t\twxLogError(\"Automation: SetSliderValues - slider '%s' not found.\", name);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\twxLogMessage(\"Automation: Setting slider '%s' to %d%%...\", name, intVal);\n\t\t\toutfitStudio->SetSliderValue(name, intVal);\n\t\t}\n\t}\n\toutfitStudio->ApplySliders();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepConformSliders(const AutomationStep& step) {\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: ConformSliders - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tif (!project->GetBaseShape()) {\n\t\twxLogError(\"Automation: ConformSliders - no reference shape loaded.\");\n\t\treturn 1;\n\t}\n\n\tConformOptions options;\n\toptions.proximityRadius = step.conformProximityRadius;\n\toptions.maxResults = step.conformMaxResults;\n\toptions.noSqueeze = step.conformNoSqueeze;\n\toptions.solidMode = step.conformSolidMode;\n\toptions.axisX = step.conformAxisX;\n\toptions.axisY = step.conformAxisY;\n\toptions.axisZ = step.conformAxisZ;\n\toptions.sliderNames = step.conformSliderNames;\n\n\tif (options.sliderNames.empty()) {\n\t\twxLogMessage(\"Automation: ConformSliders - conforming all non-zap/non-UV sliders.\");\n\t}\n\telse {\n\t\twxString namesList;\n\t\tfor (const auto& sn : options.sliderNames) {\n\t\t\tif (!namesList.empty())\n\t\t\t\tnamesList += \", \";\n\t\t\tnamesList += wxString::FromUTF8(sn);\n\t\t}\n\t\twxLogMessage(\"Automation: ConformSliders - conforming %zu named slider(s): %s\",\n\t\t\t\t\t options.sliderNames.size(), namesList);\n\t}\n\n\toutfitStudio->ZeroSliders();\n\n\tproject->InitConform();\n\tfor (auto* shape : shapes) {\n\t\twxLogMessage(\"Automation: Conforming '%s'...\", shape->name.get());\n\t\tMesh* m = outfitStudio->glView->GetMesh(shape->name.get());\n\t\tif (m)\n\t\t\tproject->morpher.CopyMeshMask(m, shape->name.get());\n\t\tproject->ConformShape(shape, options);\n\t}\n\tproject->morpher.ClearProximityCache();\n\tproject->morpher.UnlinkRefDiffData();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepCopyBoneWeights(const AutomationStep& step) {\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: CopyBoneWeights - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tif (!project->GetBaseShape()) {\n\t\twxLogError(\"Automation: CopyBoneWeights - no reference shape loaded.\");\n\t\treturn 1;\n\t}\n\n\tAnimInfo& workAnim = *project->GetWorkAnim();\n\tstd::vector<std::string> baseBones = workAnim.shapeBones[project->GetBaseShape()->name.get()];\n\tstd::sort(baseBones.begin(), baseBones.end());\n\n\tint shapeIdx = 0;\n\tfor (auto* shape : shapes) {\n\t\twxLogMessage(\"Automation: Copying bone weights to '%s'...\", shape->name.get());\n\n\t\tstd::unordered_map<uint16_t, float> mask;\n\t\toutfitStudio->glView->GetShapeMask(mask, shape->name.get());\n\t\tUndoStateShape uss;\n\t\tuss.shapeName = shape->name.get();\n\n\t\tstd::vector<std::string> boneList;\n\t\tif (!step.weightBoneList.empty()) {\n\t\t\tboneList = step.weightBoneList;\n\t\t}\n\t\telse {\n\t\t\t// Use all bones from base + shape\n\t\t\tboneList = baseBones;\n\t\t\tauto& shapeBones = workAnim.shapeBones[shape->name.get()];\n\t\t\tfor (const auto& b : shapeBones) {\n\t\t\t\tif (!std::binary_search(baseBones.begin(), baseBones.end(), b))\n\t\t\t\t\tboneList.push_back(b);\n\t\t\t}\n\t\t}\n\n\t\tint nCopyBones = step.weightBoneList.empty() ? static_cast<int>(baseBones.size()) : static_cast<int>(step.weightBoneList.size());\n\t\tstd::vector<std::string> lockedBones;\n\n\t\tproject->CopyBoneWeights(shape, step.weightProximityRadius, step.weightMaxResults,\n\t\t\t\t\t\t\t\t mask, boneList, nCopyBones, lockedBones, uss, false);\n\t\tshapeIdx++;\n\t}\n\tproject->morpher.ClearProximityCache();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepSetBaseShape(const AutomationStep&) {\n\twxLogMessage(\"Automation: Setting base shape (baking slider values)...\");\n\toutfitStudio->SetBaseShape();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepClearReference(const AutomationStep&) {\n\twxLogMessage(\"Automation: Clearing reference...\");\n\tproject->DeleteShape(project->GetBaseShape());\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepTransformShape(const AutomationStep& step) {\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: TransformShape - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tnifly::Vector3 move(step.moveX, step.moveY, step.moveZ);\n\tnifly::Vector3 rotate(step.rotateX, step.rotateY, step.rotateZ);\n\tnifly::Vector3 scale(step.scaleX, step.scaleY, step.scaleZ);\n\n\tfor (auto* shape : shapes) {\n\t\twxLogMessage(\"Automation: Transforming shape '%s'...\", shape->name.get());\n\t\tif (move.x != 0.0f || move.y != 0.0f || move.z != 0.0f)\n\t\t\tproject->OffsetShape(shape, move);\n\t\tif (rotate.x != 0.0f || rotate.y != 0.0f || rotate.z != 0.0f)\n\t\t\tproject->RotateShape(shape, rotate);\n\t\tif (scale.x != 1.0f || scale.y != 1.0f || scale.z != 1.0f)\n\t\t\tproject->ScaleShape(shape, scale);\n\t}\n\n\t// Inflate: move vertices along their normals\n\tnifly::Vector3 inflate(step.inflateX, step.inflateY, step.inflateZ);\n\tif (inflate.x != 0.0f || inflate.y != 0.0f || inflate.z != 0.0f) {\n\t\tfor (auto* shape : shapes) {\n\t\t\twxLogMessage(\"Automation: Inflating shape '%s'...\", shape->name.get());\n\t\t\tconst std::vector<nifly::Vector3>* verts = project->GetWorkNif()->GetVertsForShape(shape);\n\t\t\tconst std::vector<nifly::Vector3>* norms = project->GetWorkNif()->GetNormalsForShape(shape);\n\t\t\tif (!verts || !norms || verts->size() != norms->size())\n\t\t\t\tcontinue;\n\n\t\t\tstd::vector<nifly::Vector3> newVerts = *verts;\n\t\t\tfor (size_t i = 0; i < newVerts.size(); i++) {\n\t\t\t\tnifly::Vector3 diff = (*norms)[i].ComponentMultiply(inflate);\n\t\t\t\tnewVerts[i] += diff;\n\t\t\t}\n\t\t\tproject->GetWorkNif()->SetVertsForShape(shape, newVerts);\n\t\t}\n\t}\n\n\toutfitStudio->ApplySliders();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepInvertUVs(const AutomationStep& step) {\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: InvertUVs - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tif (!step.invertU && !step.invertV) {\n\t\twxLogWarning(\"Automation: InvertUVs - neither U nor V inversion selected.\");\n\t\treturn 0;\n\t}\n\n\tfor (auto* shape : shapes) {\n\t\twxLogMessage(\"Automation: Inverting UVs for '%s' (U=%d, V=%d)...\", shape->name.get(), step.invertU, step.invertV);\n\t\tproject->GetWorkNif()->InvertUVsForShape(shape, step.invertU, step.invertV);\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepDeleteBones(const AutomationStep& step) {\n\tif (step.deleteBoneNames.empty()) {\n\t\twxLogError(\"Automation: DeleteBones - no bone names specified.\");\n\t\treturn 1;\n\t}\n\n\tif (step.deleteBoneFromProject) {\n\t\tfor (const auto& boneName : step.deleteBoneNames) {\n\t\t\twxLogMessage(\"Automation: Deleting bone '%s' from project...\", boneName);\n\t\t\tproject->DeleteBone(boneName);\n\t\t}\n\t}\n\telse {\n\t\tauto shapes = ResolveTargetShapes(step);\n\t\tif (shapes.empty()) {\n\t\t\twxLogWarning(\"Automation: DeleteBones - no target shapes found for weight removal.\");\n\t\t\treturn 0;\n\t\t}\n\t\tfor (const auto& boneName : step.deleteBoneNames) {\n\t\t\tfor (auto* shape : shapes) {\n\t\t\t\twxLogMessage(\"Automation: Removing bone '%s' weights from '%s'...\", boneName, shape->name.get());\n\t\t\t\tproject->GetWorkAnim()->RemoveShapeBone(shape->name.get(), boneName);\n\t\t\t}\n\t\t}\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepAddCustomBone(const AutomationStep& step) {\n\tif (step.addBoneName.empty()) {\n\t\twxLogError(\"Automation: AddCustomBone - no bone name specified.\");\n\t\treturn 1;\n\t}\n\n\tnifly::MatTransform xform;\n\txform.translation = nifly::Vector3(step.addBoneTransX, step.addBoneTransY, step.addBoneTransZ);\n\tnifly::Vector3 rotVec(step.addBoneRotX, step.addBoneRotY, step.addBoneRotZ);\n\txform.rotation = nifly::RotVecToMat(rotVec);\n\n\twxLogMessage(\"Automation: Adding custom bone '%s' (parent: '%s')...\", step.addBoneName, step.addBoneParent);\n\tproject->AddCustomBoneRef(step.addBoneName, step.addBoneParent, xform);\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepEditBone(const AutomationStep& step) {\n\tif (step.editBoneName.empty()) {\n\t\twxLogError(\"Automation: EditBone - no bone name specified.\");\n\t\treturn 1;\n\t}\n\n\tAnimBone* bPtr = AnimSkeleton::getInstance().GetBonePtr(step.editBoneName);\n\tif (!bPtr) {\n\t\twxLogError(\"Automation: EditBone - bone '%s' not found.\", step.editBoneName);\n\t\treturn 1;\n\t}\n\tif (bPtr->isStandardBone) {\n\t\twxLogError(\"Automation: EditBone - bone '%s' is a standard bone, cannot edit.\", step.editBoneName);\n\t\treturn 1;\n\t}\n\n\tnifly::MatTransform xform;\n\txform.translation = nifly::Vector3(step.editBoneTransX, step.editBoneTransY, step.editBoneTransZ);\n\tnifly::Vector3 rotVec(step.editBoneRotX, step.editBoneRotY, step.editBoneRotZ);\n\txform.rotation = nifly::RotVecToMat(rotVec);\n\n\twxLogMessage(\"Automation: Editing custom bone '%s' (parent: '%s')...\", step.editBoneName, step.editBoneParent);\n\tproject->ModifyCustomBone(bPtr, step.editBoneParent, xform);\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepRemoveSkinning(const AutomationStep& step) {\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogMessage(\"Automation: Removing skinning from all shapes...\");\n\t\tproject->RemoveSkinning();\n\t}\n\telse {\n\t\tfor (auto* shape : shapes) {\n\t\t\twxLogMessage(\"Automation: Removing skinning from '%s'...\", shape->name.get());\n\t\t\tproject->RemoveSkinning(shape);\n\t\t}\n\t\tproject->GetWorkNif()->DeleteUnreferencedNodes();\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepApplyPose(const AutomationStep& step) {\n\tif (step.poseName.empty()) {\n\t\twxLogError(\"Automation: ApplyPose - no pose name specified.\");\n\t\treturn 1;\n\t}\n\n\t// Find the pose by name\n\tPoseData* posePtr = nullptr;\n\tfor (auto& pd : outfitStudio->poseDataCollection.poseData) {\n\t\tif (pd.name == step.poseName) {\n\t\t\tposePtr = &pd;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!posePtr) {\n\t\twxLogError(\"Automation: ApplyPose - pose '%s' not found.\", step.poseName);\n\t\treturn 1;\n\t}\n\n\twxLogMessage(\"Automation: Applying pose '%s' to meshes...\", step.poseName);\n\n\t// Set bone poses from PoseData\n\tstd::vector<std::string> boneNames;\n\tAnimSkeleton::getInstance().GetActiveBoneNames(boneNames);\n\tfor (const auto& boneName : boneNames) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (!bone)\n\t\t\tcontinue;\n\n\t\tauto it = std::find_if(posePtr->boneData.begin(), posePtr->boneData.end(),\n\t\t\t[&](const PoseBoneData& pbd) { return pbd.name == boneName; });\n\n\t\tif (it != posePtr->boneData.end()) {\n\t\t\tbone->poseRotVec = it->rotation;\n\t\t\tbone->poseTranVec = it->translation;\n\t\t\tbone->poseScale = it->scale;\n\t\t}\n\t\telse {\n\t\t\tbone->poseRotVec = nifly::Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseTranVec = nifly::Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseScale = 1.0f;\n\t\t}\n\t\tbone->UpdatePoseTransform();\n\t}\n\n\t// Enable pose and apply to mesh geometry\n\tproject->bPose = true;\n\n\tUndoStateProject usp;\n\tproject->ApplyPoseTransformsToAllShapeGeometry(usp);\n\n\t// Reset bone poses after applying\n\tfor (const auto& boneName : boneNames) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (!bone)\n\t\t\tcontinue;\n\t\tbone->poseRotVec = nifly::Vector3(0.0f, 0.0f, 0.0f);\n\t\tbone->poseTranVec = nifly::Vector3(0.0f, 0.0f, 0.0f);\n\t\tbone->poseScale = 1.0f;\n\t\tbone->UpdatePoseTransform();\n\t}\n\n\tproject->bPose = false;\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepImportSliderData(const AutomationStep& step) {\n\tif (step.sliderDataFile.empty()) {\n\t\twxLogError(\"Automation: ImportSliderData - no file/folder specified.\");\n\t\treturn 1;\n\t}\n\n\twxString sliderDataPath = MakeAbsoluteToProject(wxString::FromUTF8(step.sliderDataFile));\n\tstd::string sliderDataPathStd = sliderDataPath.ToUTF8().data();\n\n\tif (step.sliderDataFromFolder) {\n\t\twxLogMessage(\"Automation: Importing slider data from folder '%s'...\", sliderDataPath);\n\t\twxDir dir(sliderDataPath);\n\t\tif (!dir.IsOpened()) {\n\t\t\twxLogError(\"Automation: ImportSliderData - cannot open folder '%s'.\", sliderDataPath);\n\t\t\treturn 1;\n\t\t}\n\n\t\tint importCount = 0;\n\t\tconst auto& shapes = project->GetWorkNif()->GetShapes();\n\t\twxString filename;\n\t\tbool cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES);\n\t\twhile (cont) {\n\t\t\tstd::string fname = filename.ToUTF8().data();\n\t\t\twxFileName wxFn(filename);\n\t\t\tstd::string extLower = wxFn.GetExt().Lower().ToUTF8().data();\n\t\t\tstd::string fullPath = sliderDataPathStd + \"/\" + fname;\n\n\t\t\tif (extLower == \"osd\") {\n\t\t\t\t// OSD: import all sliders, auto-mapping shapes by target name\n\t\t\t\tOSDataFile osd;\n\t\t\t\tif (osd.Read(fullPath)) {\n\t\t\t\t\tauto& diffs = osd.GetDataDiffs();\n\t\t\t\t\tfor (auto& [diffName, diffData] : diffs) {\n\t\t\t\t\t\tstd::string bestTargetName;\n\t\t\t\t\t\tNiShape* bestShape = nullptr;\n\n\t\t\t\t\t\tfor (auto* shape : shapes) {\n\t\t\t\t\t\t\tstd::string targetName = project->ShapeToTarget(shape->name.get());\n\t\t\t\t\t\t\tif (diffName.substr(0, targetName.size()) == targetName) {\n\t\t\t\t\t\t\t\tif (targetName.length() > bestTargetName.length()) {\n\t\t\t\t\t\t\t\t\tbestTargetName = targetName;\n\t\t\t\t\t\t\t\t\tbestShape = shape;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!bestShape || bestTargetName.empty())\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tauto sliderName = project->activeSet.SliderFromDataName(bestTargetName, diffName);\n\t\t\t\t\t\tif (sliderName.empty())\n\t\t\t\t\t\t\tsliderName = diffName.substr(bestTargetName.length());\n\n\t\t\t\t\t\tif (!step.sliderNames.empty()) {\n\t\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\t\tfor (const auto& name : step.sliderNames) {\n\t\t\t\t\t\t\t\tif (name == sliderName) {\n\t\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!found)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!project->ValidSlider(sliderName)) {\n\t\t\t\t\t\t\tif (step.sliderMerge)\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\tproject->AddEmptySlider(sliderName);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (diffData)\n\t\t\t\t\t\t\tproject->SetSliderFromDiff(sliderName, bestShape, *diffData);\n\n\t\t\t\t\t\timportCount++;\n\t\t\t\t\t\twxLogMessage(\"Automation: Imported slider '%s' for shape '%s'.\", sliderName, bestShape->name.get());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twxLogWarning(\"Automation: Failed to read OSD file '%s'.\", fname);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (extLower == \"tri\") {\n\t\t\t\t// TRI: import all morphs, auto-mapping shapes by name\n\t\t\t\tTriFile tri;\n\t\t\t\tif (tri.Read(fullPath)) {\n\t\t\t\t\tauto morphs = tri.GetMorphs();\n\t\t\t\t\tfor (auto& [shapeName, morphList] : morphs) {\n\t\t\t\t\t\tauto* shape = project->GetWorkNif()->FindBlockByName<NiShape>(shapeName);\n\t\t\t\t\t\tif (!shape)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tfor (auto& morphData : morphList) {\n\t\t\t\t\t\t\tif (!step.sliderNames.empty()) {\n\t\t\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\t\t\tfor (const auto& name : step.sliderNames) {\n\t\t\t\t\t\t\t\t\tif (name == morphData->name) {\n\t\t\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (!found)\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (!project->ValidSlider(morphData->name)) {\n\t\t\t\t\t\t\t\tif (step.sliderMerge)\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\tproject->AddEmptySlider(morphData->name);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tstd::unordered_map<uint16_t, Vector3> diff(morphData->offsets.begin(), morphData->offsets.end());\n\t\t\t\t\t\t\tproject->SetSliderFromDiff(morphData->name, shape, diff);\n\n\t\t\t\t\t\t\tif (morphData->type == MORPHTYPE_UV) {\n\t\t\t\t\t\t\t\tsize_t sliderIndex = 0;\n\t\t\t\t\t\t\t\tif (project->SliderIndexFromName(morphData->name, sliderIndex))\n\t\t\t\t\t\t\t\t\tproject->SetSliderUV(sliderIndex, true);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\timportCount++;\n\t\t\t\t\t\t\twxLogMessage(\"Automation: Imported morph '%s' for shape '%s'.\", morphData->name, shapeName);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\twxLogWarning(\"Automation: Failed to read TRI file '%s'.\", fname);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (extLower == \"bsd\" || extLower == \"nif\" || extLower == \"obj\" || extLower == \"fbx\") {\n\t\t\t\t// NIF/OBJ/FBX/BSD: use \"ShapeName#SliderName.ext\" naming pattern\n\t\t\t\tauto hashPos = fname.find('#');\n\t\t\t\tif (hashPos != std::string::npos) {\n\t\t\t\t\tstd::string shapeName = fname.substr(0, hashPos);\n\t\t\t\t\tstd::string rest = fname.substr(hashPos + 1);\n\t\t\t\t\tauto dotPos = rest.rfind('.');\n\t\t\t\t\tstd::string sliderName = (dotPos != std::string::npos) ? rest.substr(0, dotPos) : rest;\n\n\t\t\t\t\tNiShape* shape = FindShapeByName(shapeName);\n\t\t\t\t\tif (shape) {\n\t\t\t\t\t\tif (step.sliderMerge && !project->ValidSlider(sliderName)) {\n\t\t\t\t\t\t\tcont = dir.GetNext(&filename);\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!project->ValidSlider(sliderName))\n\t\t\t\t\t\t\tproject->AddEmptySlider(sliderName);\n\n\t\t\t\t\t\tbool ok = false;\n\t\t\t\t\t\tif (extLower == \"bsd\") {\n\t\t\t\t\t\t\tproject->SetSliderFromBSD(sliderName, shape, fullPath);\n\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (extLower == \"nif\") {\n\t\t\t\t\t\t\tok = project->SetSliderFromNIF(sliderName, shape, fullPath);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (extLower == \"obj\") {\n\t\t\t\t\t\t\tok = project->SetSliderFromOBJ(sliderName, shape, fullPath);\n\t\t\t\t\t\t}\n#ifdef USE_FBXSDK\n\t\t\t\t\t\telse if (extLower == \"fbx\") {\n\t\t\t\t\t\t\tok = project->SetSliderFromFBX(sliderName, shape, fullPath);\n\t\t\t\t\t\t}\n#endif\n\n\t\t\t\t\t\tif (ok) {\n\t\t\t\t\t\t\timportCount++;\n\t\t\t\t\t\t\twxLogMessage(\"Automation: Imported slider '%s' for shape '%s'.\", sliderName, shapeName);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\twxLogWarning(\"Automation: Failed to import slider '%s' for shape '%s' from '%s'.\", sliderName, shapeName, fname);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\twxLogWarning(\"Automation: Shape '%s' not found for file '%s'.\", shapeName, fname);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tcont = dir.GetNext(&filename);\n\t\t}\n\n\t\twxLogMessage(\"Automation: Imported %d slider data file(s) from folder.\", importCount);\n\t}\n\telse {\n\t\t// Single file mode\n\t\twxLogMessage(\"Automation: Importing slider data from '%s'...\", sliderDataPath);\n\t\twxFileName fn(sliderDataPath);\n\t\twxString ext = fn.GetExt().Lower();\n\n\t\tif (ext == \"osd\") {\n\t\t\t// OSD multi-diff import\n\t\t\tOSDataFile osd;\n\t\t\tif (!osd.Read(sliderDataPathStd)) {\n\t\t\t\twxLogError(\"Automation: Failed to read OSD file '%s'.\", sliderDataPath);\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tauto& diffs = osd.GetDataDiffs();\n\t\t\tconst auto& shapes = project->GetWorkNif()->GetShapes();\n\n\t\t\tfor (auto& [diffName, diffData] : diffs) {\n\t\t\t\tstd::string bestTargetName;\n\t\t\t\tNiShape* bestShape = nullptr;\n\n\t\t\t\tfor (auto* shape : shapes) {\n\t\t\t\t\tstd::string shapeName = shape->name.get();\n\t\t\t\t\tstd::string targetName = project->ShapeToTarget(shapeName);\n\t\t\t\t\tif (diffName.substr(0, targetName.size()) == targetName) {\n\t\t\t\t\t\tif (targetName.length() > bestTargetName.length()) {\n\t\t\t\t\t\t\tbestTargetName = targetName;\n\t\t\t\t\t\t\tbestShape = shape;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!bestShape || bestTargetName.empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tauto sliderName = project->activeSet.SliderFromDataName(bestTargetName, diffName);\n\t\t\t\tif (sliderName.empty())\n\t\t\t\t\tsliderName = diffName.substr(bestTargetName.length());\n\n\t\t\t\tif (!step.sliderNames.empty()) {\n\t\t\t\t\tbool found = false;\n\t\t\t\t\tfor (const auto& name : step.sliderNames) {\n\t\t\t\t\t\tif (name == sliderName) {\n\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (!found)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!project->ValidSlider(sliderName)) {\n\t\t\t\t\tif (step.sliderMerge)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tproject->AddEmptySlider(sliderName);\n\t\t\t\t}\n\n\t\t\t\tif (diffData)\n\t\t\t\t\tproject->SetSliderFromDiff(sliderName, bestShape, *diffData);\n\t\t\t\twxLogMessage(\"Automation: Imported slider '%s' for shape '%s'.\", sliderName, bestShape->name.get());\n\t\t\t}\n\t\t}\n\t\telse if (ext == \"tri\") {\n\t\t\t// TRI multi-morph import\n\t\t\tTriFile tri;\n\t\t\tif (!tri.Read(sliderDataPathStd)) {\n\t\t\t\twxLogError(\"Automation: Failed to read TRI file '%s'.\", sliderDataPath);\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tauto morphs = tri.GetMorphs();\n\t\t\tfor (auto& [shapeName, morphList] : morphs) {\n\t\t\t\tauto* shape = project->GetWorkNif()->FindBlockByName<NiShape>(shapeName);\n\t\t\t\tif (!shape)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tfor (auto& morphData : morphList) {\n\t\t\t\t\tif (!step.sliderNames.empty()) {\n\t\t\t\t\t\tbool found = false;\n\t\t\t\t\t\tfor (const auto& name : step.sliderNames) {\n\t\t\t\t\t\t\tif (name == morphData->name) {\n\t\t\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!found)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!project->ValidSlider(morphData->name)) {\n\t\t\t\t\t\tif (step.sliderMerge)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tproject->AddEmptySlider(morphData->name);\n\t\t\t\t\t}\n\n\t\t\t\t\tstd::unordered_map<uint16_t, Vector3> diff(morphData->offsets.begin(), morphData->offsets.end());\n\t\t\t\t\tproject->SetSliderFromDiff(morphData->name, shape, diff);\n\n\t\t\t\t\tif (morphData->type == MORPHTYPE_UV) {\n\t\t\t\t\t\tsize_t sliderIndex = 0;\n\t\t\t\t\t\tif (project->SliderIndexFromName(morphData->name, sliderIndex))\n\t\t\t\t\t\t\tproject->SetSliderUV(sliderIndex, true);\n\t\t\t\t\t}\n\n\t\t\t\t\twxLogMessage(\"Automation: Imported morph '%s' for shape '%s'.\", morphData->name, shapeName);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (ext == \"nif\" || ext == \"obj\" || ext == \"bsd\" || ext == \"fbx\") {\n\t\t\t// Per-shape slider import: compute diff from file mesh vs current shape\n\t\t\tstd::string sliderName;\n\t\t\tif (!step.sliderNames.empty())\n\t\t\t\tsliderName = step.sliderNames[0];\n\t\t\telse\n\t\t\t\tsliderName = fn.GetName().ToUTF8().data();\n\n\t\t\tif (!project->ValidSlider(sliderName)) {\n\t\t\t\tif (step.sliderMerge) {\n\t\t\t\t\twxLogWarning(\"Automation: Slider '%s' does not exist and merge-only is enabled.\", sliderName);\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\tproject->AddEmptySlider(sliderName);\n\t\t\t}\n\n\t\t\tconst auto& shapes = project->GetWorkNif()->GetShapes();\n\t\t\tfor (auto* shape : shapes) {\n\t\t\t\tbool ok = false;\n\t\t\t\tif (ext == \"nif\")\n\t\t\t\t\tok = project->SetSliderFromNIF(sliderName, shape, sliderDataPathStd);\n\t\t\t\telse if (ext == \"obj\")\n\t\t\t\t\tok = project->SetSliderFromOBJ(sliderName, shape, sliderDataPathStd);\n\t\t\t\telse if (ext == \"bsd\") {\n\t\t\t\t\tproject->SetSliderFromBSD(sliderName, shape, sliderDataPathStd);\n\t\t\t\t\tok = true;\n\t\t\t\t}\n#ifdef USE_FBXSDK\n\t\t\t\telse if (ext == \"fbx\")\n\t\t\t\t\tok = project->SetSliderFromFBX(sliderName, shape, sliderDataPathStd);\n#endif\n\n\t\t\t\tif (ok)\n\t\t\t\t\twxLogMessage(\"Automation: Imported slider '%s' for shape '%s'.\", sliderName, shape->name.get());\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\twxLogError(\"Automation: ImportSliderData - unsupported file format '.%s'.\", ext);\n\t\t\treturn 1;\n\t\t}\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepImportFile(const AutomationStep& step) {\n\tif (step.importFilePath.empty()) {\n\t\twxLogError(\"Automation: ImportFile - no file/folder specified.\");\n\t\treturn 1;\n\t}\n\n\twxString importFilePath = MakeAbsoluteToProject(wxString::FromUTF8(step.importFilePath));\n\tstd::string importFilePathStd = importFilePath.ToUTF8().data();\n\n\tif (step.importFromFolder) {\n\t\t// Folder mode: import all NIF/OBJ/FBX files from the folder\n\t\twxLogMessage(\"Automation: Importing all files from folder '%s'...\", importFilePath);\n\t\twxDir dir(importFilePath);\n\t\tif (!dir.IsOpened()) {\n\t\t\twxLogError(\"Automation: ImportFile - cannot open folder '%s'.\", importFilePath);\n\t\t\treturn 1;\n\t\t}\n\n\t\tint importCount = 0;\n\t\twxString filename;\n\t\tbool cont = dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES);\n\t\twhile (cont) {\n\t\t\twxFileName fn(filename);\n\t\t\twxString ext = fn.GetExt().Lower();\n\t\t\tif (ext == \"nif\" || ext == \"obj\" || ext == \"fbx\") {\n\t\t\t\tstd::string fullPath = importFilePathStd + \"/\" + filename.ToUTF8().data();\n\t\t\t\tint err = 0;\n\t\t\t\tif (ext == \"nif\")\n\t\t\t\t\terr = project->ImportNIF(fullPath, false);\n\t\t\t\telse if (ext == \"obj\")\n\t\t\t\t\terr = project->ImportOBJ(fullPath);\n\t\t\t\telse if (ext == \"fbx\")\n#ifdef USE_FBXSDK\n\t\t\t\t\terr = project->ImportFBX(fullPath);\n#else\n\t\t\t\t\twxLogError(\"Automation: FBX import is not available (FBX SDK not compiled in).\");\n#endif\n\n\t\t\t\tif (err)\n\t\t\t\t\twxLogWarning(\"Automation: Failed to import '%s' (error %d).\", fullPath, err);\n\t\t\t\telse\n\t\t\t\t\timportCount++;\n\t\t\t}\n\t\t\tcont = dir.GetNext(&filename);\n\t\t}\n\n\t\twxLogMessage(\"Automation: Imported %d file(s) from folder.\", importCount);\n\t}\n\telse {\n\t\t// Single file mode\n\t\twxFileName fn(importFilePath);\n\t\twxString ext = fn.GetExt().Lower();\n\t\tint err = 0;\n\n\t\tif (ext == \"nif\")\n\t\t\terr = project->ImportNIF(importFilePathStd, false);\n\t\telse if (ext == \"obj\")\n\t\t\terr = project->ImportOBJ(importFilePathStd);\n\t\telse if (ext == \"fbx\")\n#ifdef USE_FBXSDK\n\t\t\terr = project->ImportFBX(importFilePathStd);\n#else\n\t\t\twxLogError(\"Automation: FBX import is not available (FBX SDK not compiled in).\");\n#endif\n\t\telse {\n\t\t\twxLogError(\"Automation: ImportFile - unsupported file extension '%s'.\", ext);\n\t\t\treturn 1;\n\t\t}\n\n\t\tif (err) {\n\t\t\twxLogError(\"Automation: ImportFile '%s' failed with error %d.\", importFilePath, err);\n\t\t\treturn err;\n\t\t}\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepDeleteShape(const AutomationStep& step) {\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: DeleteShape - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tfor (auto* shape : shapes) {\n\t\twxLogMessage(\"Automation: Deleting shape '%s'...\", shape->name.get());\n\t\tproject->DeleteShape(shape);\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepRenameShape(const AutomationStep& step) {\n\tif (step.renameOldName.empty() || step.renameNewName.empty()) {\n\t\twxLogError(\"Automation: RenameShape - old or new name not specified.\");\n\t\treturn 1;\n\t}\n\n\tNiShape* shape = FindShapeByName(step.renameOldName);\n\tif (!shape) {\n\t\twxLogError(\"Automation: RenameShape - shape '%s' not found.\", step.renameOldName);\n\t\treturn 1;\n\t}\n\n\twxLogMessage(\"Automation: Renaming shape '%s' to '%s'...\", step.renameOldName, step.renameNewName);\n\tproject->RenameShape(shape, step.renameNewName);\n\toutfitStudio->glView->RenameShape(step.renameOldName, step.renameNewName);\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepSaveProject(const AutomationStep& step) {\n\tif (step.saveSliderSetFile.empty() || step.saveOutputFileName.empty()) {\n\t\twxLogError(\"Automation: SaveProject - required fields not filled.\");\n\t\treturn 1;\n\t}\n\n\twxLogMessage(\"Automation: Saving project '%s'...\", step.saveName);\n\n\twxFileName sliderSetFile(wxString::FromUTF8(step.saveSliderSetFile));\n\twxString strOutfitName = wxString::FromUTF8(step.saveName);\n\twxString strDataDir = wxString::FromUTF8(step.saveShapeDataFolder);\n\twxString strBaseFile = wxString::FromUTF8(step.saveShapeDataFile);\n\twxString strGamePath = wxString::FromUTF8(step.saveOutputDataPath);\n\twxString strGameFile = wxString::FromUTF8(step.saveOutputFileName);\n\n\tstd::string result = project->Save(sliderSetFile, strOutfitName, strDataDir,\n\t\t\t\t\t\t\t\t\t   strBaseFile, strGamePath, strGameFile,\n\t\t\t\t\t\t\t\t\t   step.saveGenWeights, step.saveAutoCopyRef,\n\t\t\t\t\t\t\t\t\t   false, false);\n\n\tif (!result.empty()) {\n\t\twxLogError(\"Automation: SaveProject error: %s\", result);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepExportFile(const AutomationStep& step) {\n\tif (step.exportFilePath.empty()) {\n\t\twxLogError(\"Automation: ExportFile - no file path specified.\");\n\t\treturn 1;\n\t}\n\n\t// Apply prefix/suffix to filename\n\tstd::string exportPath = step.exportFilePath;\n\tif (!step.exportPrefix.empty() || !step.exportSuffix.empty()) {\n\t\twxFileName fn(wxString::FromUTF8(exportPath));\n\t\twxString name = fn.GetName();\n\t\tif (!step.exportPrefix.empty())\n\t\t\tname = wxString::FromUTF8(step.exportPrefix) + name;\n\t\tif (!step.exportSuffix.empty())\n\t\t\tname = name + wxString::FromUTF8(step.exportSuffix);\n\t\tfn.SetName(name);\n\t\texportPath = fn.GetFullPath().ToUTF8().data();\n\t}\n\n\twxFileName fn(wxString::FromUTF8(exportPath));\n\twxString ext = fn.GetExt().Lower();\n\n\twxLogMessage(\"Automation: Exporting to '%s'...\", exportPath);\n\n\tif (ext == \"nif\") {\n\t\tstd::vector<Mesh*> shapeMeshes;\n\t\tfor (auto* s : project->GetWorkNif()->GetShapes()) {\n\t\t\tif (step.exportWithRef || !project->IsBaseShape(s)) {\n\t\t\t\tMesh* m = outfitStudio->glView->GetMesh(s->name.get());\n\t\t\t\tif (m)\n\t\t\t\t\tshapeMeshes.push_back(m);\n\t\t\t}\n\t\t}\n\t\tint err = project->ExportNIF(exportPath, shapeMeshes, step.exportWithRef);\n\t\tif (err) {\n\t\t\twxLogError(\"Automation: ExportNIF failed with error %d.\", err);\n\t\t\treturn err;\n\t\t}\n\t}\n\telse if (ext == \"obj\") {\n\t\tauto shapes = project->GetWorkNif()->GetShapes();\n\t\tint err = project->ExportOBJ(exportPath, shapes, false);\n\t\tif (err) {\n\t\t\twxLogError(\"Automation: ExportOBJ failed with error %d.\", err);\n\t\t\treturn err;\n\t\t}\n\t}\n\telse if (ext == \"fbx\") {\n#ifdef USE_FBXSDK\n\t\tauto shapes = project->GetWorkNif()->GetShapes();\n\t\tint err = project->ExportFBX(exportPath, shapes, false);\n\t\tif (err) {\n\t\t\twxLogError(\"Automation: ExportFBX failed with error %d.\", err);\n\t\t\treturn err;\n\t\t}\n#else\n\t\twxLogError(\"Automation: FBX export is not available (FBX SDK not compiled in).\");\n\t\treturn 1;\n#endif\n\t}\n\telse if (ext == \"osd\") {\n\t\tbool ok = project->SaveSliderData(exportPath);\n\t\tif (!ok) {\n\t\t\twxLogError(\"Automation: SaveSliderData failed.\");\n\t\t\treturn 1;\n\t\t}\n\t}\n\telse if (ext == \"tri\") {\n\t\tbool ok = project->WriteMorphTRI(exportPath);\n\t\tif (!ok) {\n\t\t\twxLogError(\"Automation: WriteMorphTRI failed.\");\n\t\t\treturn 1;\n\t\t}\n\t}\n\telse {\n\t\twxLogError(\"Automation: ExportFile - unsupported file extension '%s'.\", ext);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepRefineMesh(const AutomationStep&) {\n\twxLogMessage(\"Automation: Refining meshes...\");\n\n\tauto workNif = project->GetWorkNif();\n\tif (!workNif) {\n\t\twxLogError(\"Automation: RefineMesh - no work NIF loaded.\");\n\t\treturn 1;\n\t}\n\n\tconstexpr size_t maxVertIndex = std::numeric_limits<uint16_t>().max();\n\tsize_t maxTriIndex = std::numeric_limits<uint16_t>().max();\n\tif (workNif->GetHeader().GetVersion().IsFO4() || workNif->GetHeader().GetVersion().IsFO76())\n\t\tmaxTriIndex = std::numeric_limits<uint32_t>().max();\n\n\tfor (auto* shape : workNif->GetShapes()) {\n\t\tsize_t nverts = shape->GetNumVertices();\n\n\t\t// Determine unmasked vertices\n\t\tstd::unordered_map<uint16_t, float> mask;\n\t\toutfitStudio->glView->GetShapeUnmasked(mask, shape->name.get());\n\t\tstd::vector<bool> pincs(nverts, false);\n\t\tfor (auto& m : mask)\n\t\t\tpincs[m.first] = true;\n\n\t\tstd::vector<Triangle> tris;\n\t\tshape->GetTriangles(tris);\n\t\tsize_t nedges = 0;\n\t\tfor (Triangle& tri : tris) {\n\t\t\tint ntripts = pincs[tri.p1] + pincs[tri.p2] + pincs[tri.p3];\n\t\t\tif (ntripts == 3)\n\t\t\t\tnedges += 3;\n\t\t\telse if (ntripts == 2)\n\t\t\t\tnedges += 1;\n\t\t}\n\n\t\tif (nverts + nedges > maxVertIndex || shape->GetNumTriangles() + nedges > maxTriIndex) {\n\t\t\twxLogWarning(\"Automation: RefineMesh - shape '%s' would exceed vertex/triangle limits, skipping.\", shape->name.get());\n\t\t\tcontinue;\n\t\t}\n\n\t\tMesh* m = outfitStudio->glView->GetMesh(shape->name.get());\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tUndoStateShape uss;\n\t\tuss.shapeName = shape->name.get();\n\t\tif (!project->PrepareRefineMesh(shape, uss, pincs, m->weldVerts, false)) {\n\t\t\twxLogWarning(\"Automation: RefineMesh - shape '%s' has orientation issues, skipping.\", shape->name.get());\n\t\t\tcontinue;\n\t\t}\n\n\t\tstd::vector<float> emptyMask;\n\t\tproject->ApplyShapeMeshUndo(shape, emptyMask, uss, false);\n\t}\n\n\toutfitStudio->ApplySliders();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepDeleteSlider(const AutomationStep& step) {\n\tif (step.deleteSliderNames.empty()) {\n\t\twxLogError(\"Automation: DeleteSlider - no slider name specified.\");\n\t\treturn 1;\n\t}\n\n\tif (step.deleteSliderRegex) {\n\t\t// In regex mode, use first entry as pattern\n\t\tstd::string pattern = JoinStrings(step.deleteSliderNames, \", \");\n\t\ttry {\n\t\t\tstd::regex re(pattern, std::regex::icase);\n\t\t\tstd::vector<std::string> sliderList;\n\t\t\tproject->GetSliderList(sliderList);\n\t\t\tint deleted = 0;\n\t\t\tfor (const auto& name : sliderList) {\n\t\t\t\tif (std::regex_search(name, re)) {\n\t\t\t\t\twxLogMessage(\"Automation: Deleting slider '%s'...\", name);\n\t\t\t\t\tproject->DeleteSlider(name);\n\t\t\t\t\tdeleted++;\n\t\t\t\t}\n\t\t\t}\n\t\t\twxLogMessage(\"Automation: Deleted %d slider(s) matching '%s'.\", deleted, pattern);\n\t\t}\n\t\tcatch (const std::regex_error&) {\n\t\t\twxLogError(\"Automation: DeleteSlider - invalid regex '%s'.\", pattern);\n\t\t\treturn 1;\n\t\t}\n\t}\n\telse {\n\t\tfor (const auto& sliderName : step.deleteSliderNames) {\n\t\t\twxLogMessage(\"Automation: Deleting slider '%s'...\", sliderName);\n\t\t\tproject->DeleteSlider(sliderName);\n\t\t}\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepSetReferenceShape(const AutomationStep& step) {\n\tif (step.setRefUnset) {\n\t\twxLogMessage(\"Automation: Unsetting reference shape...\");\n\t\tproject->SetBaseShape(nullptr);\n\t\treturn 0;\n\t}\n\n\tif (step.setRefShapeName.empty()) {\n\t\twxLogError(\"Automation: SetReferenceShape - no shape name specified.\");\n\t\treturn 1;\n\t}\n\n\tNiShape* shape = FindShapeByName(step.setRefShapeName);\n\tif (!shape) {\n\t\twxLogError(\"Automation: SetReferenceShape - shape '%s' not found.\", step.setRefShapeName);\n\t\treturn 1;\n\t}\n\n\twxLogMessage(\"Automation: Setting reference shape to '%s'...\", step.setRefShapeName);\n\tproject->SetBaseShape(shape);\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepResetTransforms(const AutomationStep&) {\n\twxLogMessage(\"Automation: Resetting transforms...\");\n\tproject->ResetTransforms();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepDuplicateShape(const AutomationStep& step) {\n\tif (step.dupNewName.empty()) {\n\t\twxLogError(\"Automation: DuplicateShape - no new name specified.\");\n\t\treturn 1;\n\t}\n\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: DuplicateShape - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tfor (auto* shape : shapes) {\n\t\tstd::string newName = step.dupNewName;\n\t\t// If duplicating multiple shapes, append original name to avoid duplicates\n\t\tif (shapes.size() > 1)\n\t\t\tnewName = step.dupNewName + \"_\" + shape->name.get();\n\n\t\tif (project->IsValidShape(newName)) {\n\t\t\twxLogWarning(\"Automation: DuplicateShape - shape '%s' already exists, skipping.\", newName);\n\t\t\tcontinue;\n\t\t}\n\n\t\twxLogMessage(\"Automation: Duplicating shape '%s' as '%s'...\", shape->name.get(), newName);\n\t\tproject->DuplicateShape(shape, newName);\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepMirrorShape(const AutomationStep& step) {\n\tif (!step.mirrorX && !step.mirrorY && !step.mirrorZ) {\n\t\twxLogWarning(\"Automation: MirrorShape - no mirror axis selected.\");\n\t\treturn 0;\n\t}\n\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: MirrorShape - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tfor (auto* shape : shapes) {\n\t\twxLogMessage(\"Automation: Mirroring shape '%s' (X=%d, Y=%d, Z=%d, SwapBones=%d)...\",\n\t\t\tshape->name.get(), step.mirrorX, step.mirrorY, step.mirrorZ, step.mirrorSwapBonesX);\n\t\tproject->GetWorkNif()->MirrorShape(shape, step.mirrorX, step.mirrorY, step.mirrorZ);\n\t\tif (step.mirrorSwapBonesX)\n\t\t\tproject->GetWorkAnim()->SwapBonesLR(shape->name.get());\n\t}\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepClearMask(const AutomationStep& step) {\n\tauto targetShapes = ResolveTargetShapes(step);\n\tif (targetShapes.empty()) {\n\t\twxLogWarning(\"Automation: ClearMask - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tfor (auto* shape : targetShapes) {\n\t\tstd::string shapeName = shape->name.get();\n\t\tMesh* mesh = outfitStudio->glView->GetMesh(shapeName);\n\t\tif (!mesh)\n\t\t\tcontinue;\n\n\t\twxLogMessage(\"Automation: Clearing mask for shape '%s'...\", shapeName);\n\t\tmesh->MaskFill(0.0f);\n\t}\n\n\toutfitStudio->glView->Render();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepLoadMask(const AutomationStep& step) {\n\tif (step.loadMaskFile.empty()) {\n\t\twxLogError(\"Automation: LoadMask - no mask file specified.\");\n\t\treturn 1;\n\t}\n\n\tif (step.loadMaskName.empty()) {\n\t\twxLogError(\"Automation: LoadMask - no mask name specified.\");\n\t\treturn 1;\n\t}\n\n\twxString loadMaskFile = MakeAbsoluteToProject(wxString::FromUTF8(step.loadMaskFile));\n\tstd::string loadMaskFileStd = loadMaskFile.ToUTF8().data();\n\tMaskFile maskFile;\n\tint maskErr = maskFile.Load(loadMaskFileStd);\n\tif (maskErr) {\n\t\twxLogError(\"Automation: LoadMask - failed to load file '%s' (error %d).\", loadMaskFile, maskErr);\n\t\treturn 1;\n\t}\n\n\tconst MaskEntry* entry = maskFile.FindEntry(step.loadMaskName);\n\tif (!entry) {\n\t\twxLogError(\"Automation: LoadMask - mask name '%s' not found in file '%s'.\",\n\t\t\tstep.loadMaskName, loadMaskFile);\n\t\treturn 1;\n\t}\n\n\tauto targetShapes = ResolveTargetShapes(step);\n\tif (targetShapes.empty()) {\n\t\twxLogWarning(\"Automation: LoadMask - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tfor (auto* shape : targetShapes) {\n\t\tstd::string shapeName = shape->name.get();\n\t\tMesh* mesh = outfitStudio->glView->GetMesh(shapeName);\n\t\tif (!mesh)\n\t\t\tcontinue;\n\n\t\tconst MaskShapeData* matched = entry->FindMatchingMask(shapeName, mesh->nVerts);\n\t\tif (!matched) {\n\t\t\twxLogWarning(\"Automation: LoadMask - no matching mask found for shape '%s' (vertex count: %d).\",\n\t\t\t\tshapeName, mesh->nVerts);\n\t\t\tcontinue;\n\t\t}\n\n\t\twxLogMessage(\"Automation: Loading mask '%s' onto shape '%s' (matched from '%s')...\",\n\t\t\tstep.loadMaskName, shapeName, matched->name);\n\t\tauto maskCopy = matched->mask;\n\t\toutfitStudio->glView->SetShapeMask(maskCopy, shapeName);\n\t}\n\n\toutfitStudio->glView->Render();\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepSetSliderProperties(const AutomationStep& step) {\n\twxLogMessage(\"Automation: Setting slider properties...\");\n\n\tfor (size_t i = 0; i < project->SliderCount(); i++) {\n\t\tstd::string name = project->GetSliderName(i);\n\n\t\t// If specific slider names given, check if this one matches\n\t\tif (!step.sliderPropNames.empty()) {\n\t\t\tbool found = false;\n\t\t\tfor (const auto& n : step.sliderPropNames) {\n\t\t\t\tif (n == name) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!found)\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tif (step.sliderPropZap >= 0) {\n\t\t\tproject->SetSliderZap(i, step.sliderPropZap != 0);\n\t\t\twxLogMessage(\"Automation: Slider '%s' zap = %s.\", name, step.sliderPropZap ? \"true\" : \"false\");\n\t\t}\n\t\tif (step.sliderPropHidden >= 0) {\n\t\t\tproject->SetSliderHidden(i, step.sliderPropHidden != 0);\n\t\t\twxLogMessage(\"Automation: Slider '%s' hidden = %s.\", name, step.sliderPropHidden ? \"true\" : \"false\");\n\t\t}\n\t\tif (step.sliderPropDefaultLo >= 0) {\n\t\t\tproject->SetSliderDefault(i, step.sliderPropDefaultLo, false);\n\t\t\twxLogMessage(\"Automation: Slider '%s' default (small) = %d.\", name, step.sliderPropDefaultLo);\n\t\t}\n\t\tif (step.sliderPropDefaultHi >= 0) {\n\t\t\tproject->SetSliderDefault(i, step.sliderPropDefaultHi, true);\n\t\t\twxLogMessage(\"Automation: Slider '%s' default (big) = %d.\", name, step.sliderPropDefaultHi);\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepRemoveUnusedNodes(const AutomationStep&) {\n\twxLogMessage(\"Automation: Removing unused nodes...\");\n\tint deletionCount = 0;\n\tauto workNif = project->GetWorkNif();\n\tif (workNif)\n\t\tworkNif->DeleteUnreferencedNodes(&deletionCount);\n\twxLogMessage(\"Automation: %d unreferenced nodes removed.\", deletionCount);\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepFixClipping(const AutomationStep& step) {\n\tnifly::NiShape* refShape = project->GetBaseShape();\n\tif (!refShape) {\n\t\twxLogError(\"Automation: FixClipping - no reference shape set.\");\n\t\treturn 1;\n\t}\n\n\tClippingFixOptions options;\n\toptions.strength = std::max(0.0f, std::min(1.0f, step.fixClipStrength));\n\tif (options.strength <= 0.0f) {\n\t\twxLogWarning(\"Automation: FixClipping - strength is 0, nothing to do.\");\n\t\treturn 0;\n\t}\n\n\tauto shapes = ResolveTargetShapes(step);\n\tif (shapes.empty()) {\n\t\twxLogWarning(\"Automation: FixClipping - no target shapes found.\");\n\t\treturn 0;\n\t}\n\n\tif (step.fixClipMode == 0) {\n\t\t// Shapes mode: fix base geometry of target shapes with no sliders applied\n\t\twxLogMessage(\"Automation: FixClipping (Shapes mode, strength=%.0f%%)...\", step.fixClipStrength * 100.0f);\n\n\t\tstd::vector<nifly::Vector3> bodyVerts;\n\t\tstd::vector<nifly::Triangle> bodyTris;\n\t\tproject->GetWorkNif()->GetVertsForShape(refShape, bodyVerts);\n\t\trefShape->GetTriangles(bodyTris);\n\n\t\tfor (auto* shape : shapes) {\n\t\t\tif (project->IsBaseShape(shape))\n\t\t\t\tcontinue;\n\n\t\t\tstd::vector<nifly::Vector3> outfitVerts;\n\t\t\tproject->GetWorkNif()->GetVertsForShape(shape, outfitVerts);\n\n\t\t\tstd::vector<nifly::Triangle> outfitTris;\n\t\t\tshape->GetTriangles(outfitTris);\n\n\t\t\tstd::vector<nifly::Vector3> fixedVerts = outfitVerts;\n\t\t\tClippingFixer::FixClipping(bodyVerts, bodyTris, fixedVerts, outfitTris, options);\n\n\t\t\tbool changed = false;\n\t\t\tfor (size_t i = 0; i < outfitVerts.size(); i++) {\n\t\t\t\tnifly::Vector3 diff = fixedVerts[i] - outfitVerts[i];\n\t\t\t\tif (!diff.IsZero(true)) {\n\t\t\t\t\tchanged = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (changed) {\n\t\t\t\twxLogMessage(\"Automation: FixClipping - fixed base geometry for '%s'.\", shape->name.get());\n\t\t\t\tproject->GetWorkNif()->SetVertsForShape(shape, fixedVerts);\n\t\t\t}\n\t\t}\n\n\t\toutfitStudio->ApplySliders();\n\t}\n\telse if (step.fixClipMode == 1) {\n\t\t// Sliders mode: fix clipping for each slider individually\n\t\twxLogMessage(\"Automation: FixClipping (Sliders mode, strength=%.0f%%)...\", step.fixClipStrength * 100.0f);\n\n\t\t// Build list of sliders to process\n\t\tstd::vector<size_t> sliderIndices;\n\t\tif (step.fixClipSliderNames.empty()) {\n\t\t\t// Process all non-zap/non-UV sliders that have morph data\n\t\t\tfor (size_t i = 0; i < project->SliderCount(); i++) {\n\t\t\t\tif (project->activeSet[i].bZap || project->activeSet[i].bUV)\n\t\t\t\t\tcontinue;\n\t\t\t\tsliderIndices.push_back(i);\n\t\t\t}\n\t\t\twxLogMessage(\"Automation: FixClipping - processing all %zu non-zap/non-UV sliders.\", sliderIndices.size());\n\t\t}\n\t\telse {\n\t\t\tfor (const auto& name : step.fixClipSliderNames) {\n\t\t\t\tsize_t idx;\n\t\t\t\tif (!project->SliderIndexFromName(name, idx)) {\n\t\t\t\t\twxLogError(\"Automation: FixClipping - slider '%s' not found.\", name);\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t\tsliderIndices.push_back(idx);\n\t\t\t}\n\t\t}\n\n\t\tif (sliderIndices.empty()) {\n\t\t\twxLogWarning(\"Automation: FixClipping - no sliders to process.\");\n\t\t\treturn 0;\n\t\t}\n\n\t\t// Save current slider values\n\t\tstd::vector<float> savedValues(project->SliderCount());\n\t\tfor (size_t i = 0; i < project->SliderCount(); i++)\n\t\t\tsavedValues[i] = project->SliderValue(i);\n\n\t\tfor (size_t si : sliderIndices) {\n\t\t\tstd::string sliderName = project->GetSliderName(si);\n\t\t\twxLogMessage(\"Automation: FixClipping - processing slider '%s'...\", sliderName);\n\n\t\t\t// Set all sliders to 0%, then this slider to 100%\n\t\t\tfor (size_t i = 0; i < project->SliderCount(); i++)\n\t\t\t\toutfitStudio->SetSliderValue(i, 0);\n\t\t\toutfitStudio->SetSliderValue(si, 100);\n\t\t\toutfitStudio->ApplySliders();\n\n\t\t\t// Get live body verts (base + this slider at 100%)\n\t\t\tstd::vector<nifly::Vector3> bodyVerts;\n\t\t\tstd::vector<nifly::Triangle> bodyTris;\n\t\t\tproject->GetLiveVerts(refShape, bodyVerts);\n\t\t\trefShape->GetTriangles(bodyTris);\n\n\t\t\tfor (auto* shape : shapes) {\n\t\t\t\tif (project->IsBaseShape(shape))\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Check if this shape has morph data for this slider\n\t\t\t\tTargetDataDiffs* diffSet = project->GetDiffSet(project->activeSet[si], shape);\n\t\t\t\tif (!diffSet || diffSet->empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Get live outfit verts (base + this slider morph at 100%)\n\t\t\t\tstd::vector<nifly::Vector3> outfitVerts;\n\t\t\t\tproject->GetLiveVerts(shape, outfitVerts);\n\n\t\t\t\tstd::vector<nifly::Triangle> outfitTris;\n\t\t\t\tshape->GetTriangles(outfitTris);\n\n\t\t\t\tstd::vector<nifly::Vector3> fixedVerts = outfitVerts;\n\t\t\t\tClippingFixer::FixClipping(bodyVerts, bodyTris, fixedVerts, outfitTris, options);\n\n\t\t\t\t// Compute mesh-space morph diffs, only for vertices already in the slider's diff set\n\t\t\t\tTargetDataDiffs morphDiffs;\n\t\t\t\tfor (size_t i = 0; i < outfitVerts.size(); i++) {\n\t\t\t\t\tif (diffSet->find(static_cast<uint16_t>(i)) == diffSet->end())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tnifly::Vector3 nifDiff = fixedVerts[i] - outfitVerts[i];\n\t\t\t\t\tif (nifDiff.IsZero(true))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tmorphDiffs[static_cast<uint16_t>(i)] = Mesh::TransformDiffNifToMesh(nifDiff);\n\t\t\t\t}\n\n\t\t\t\tif (!morphDiffs.empty()) {\n\t\t\t\t\twxLogMessage(\"Automation: FixClipping - updated %zu vertices for '%s' slider '%s'.\",\n\t\t\t\t\t\t\t\t morphDiffs.size(), shape->name.get(), sliderName);\n\t\t\t\t\tproject->UpdateMorphResult(shape, sliderName, morphDiffs);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Restore original slider values\n\t\tfor (size_t i = 0; i < project->SliderCount(); i++)\n\t\t\toutfitStudio->SetSliderValue(i, static_cast<int>(savedValues[i] * 100));\n\t\toutfitStudio->ApplySliders();\n\t}\n\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStepFixBadBones(const AutomationStep& WXUNUSED(step)) {\n\twxLogMessage(\"Automation: Fixing bad bones...\");\n\n\tif (!project->CheckForBadBones(false))\n\t\twxLogMessage(\"Automation: No bad bones found.\");\n\n\treturn 0;\n}\n\nint AutomationDialog::ExecuteStep(const AutomationStep& step) {\n\tswitch (step.type) {\n\t\tcase AutomationStepType::ClearProject: return ExecuteStepClearProject(step);\n\t\tcase AutomationStepType::LoadReference: return ExecuteStepLoadReference(step);\n\t\tcase AutomationStepType::AddProject: return ExecuteStepAddProject(step);\n\t\tcase AutomationStepType::SetSliderValues: return ExecuteStepSetSliderValues(step);\n\t\tcase AutomationStepType::ConformSliders: return ExecuteStepConformSliders(step);\n\t\tcase AutomationStepType::CopyBoneWeights: return ExecuteStepCopyBoneWeights(step);\n\t\tcase AutomationStepType::SetBaseShape: return ExecuteStepSetBaseShape(step);\n\t\tcase AutomationStepType::ClearReference: return ExecuteStepClearReference(step);\n\t\tcase AutomationStepType::TransformShape: return ExecuteStepTransformShape(step);\n\t\tcase AutomationStepType::InvertUVs: return ExecuteStepInvertUVs(step);\n\t\tcase AutomationStepType::DeleteBones: return ExecuteStepDeleteBones(step);\n\t\tcase AutomationStepType::AddCustomBone: return ExecuteStepAddCustomBone(step);\n\t\tcase AutomationStepType::EditBone: return ExecuteStepEditBone(step);\n\t\tcase AutomationStepType::RemoveSkinning: return ExecuteStepRemoveSkinning(step);\n\t\tcase AutomationStepType::ApplyPose: return ExecuteStepApplyPose(step);\n\t\tcase AutomationStepType::ImportSliderData: return ExecuteStepImportSliderData(step);\n\t\tcase AutomationStepType::ImportFile: return ExecuteStepImportFile(step);\n\t\tcase AutomationStepType::DeleteShape: return ExecuteStepDeleteShape(step);\n\t\tcase AutomationStepType::RenameShape: return ExecuteStepRenameShape(step);\n\t\tcase AutomationStepType::SaveProject: return ExecuteStepSaveProject(step);\n\t\tcase AutomationStepType::ExportFile: return ExecuteStepExportFile(step);\n\t\tcase AutomationStepType::RefineMesh: return ExecuteStepRefineMesh(step);\n\t\tcase AutomationStepType::DeleteSlider: return ExecuteStepDeleteSlider(step);\n\t\tcase AutomationStepType::SetReferenceShape: return ExecuteStepSetReferenceShape(step);\n\t\tcase AutomationStepType::ResetTransforms: return ExecuteStepResetTransforms(step);\n\t\tcase AutomationStepType::DuplicateShape: return ExecuteStepDuplicateShape(step);\n\t\tcase AutomationStepType::MirrorShape: return ExecuteStepMirrorShape(step);\n\t\tcase AutomationStepType::ClearMask: return ExecuteStepClearMask(step);\n\t\tcase AutomationStepType::LoadMask: return ExecuteStepLoadMask(step);\n\t\tcase AutomationStepType::SetSliderProperties: return ExecuteStepSetSliderProperties(step);\n\t\tcase AutomationStepType::RemoveUnusedNodes: return ExecuteStepRemoveUnusedNodes(step);\n\t\tcase AutomationStepType::FixClipping: return ExecuteStepFixClipping(step);\n\t\tcase AutomationStepType::FixBadBones: return ExecuteStepFixBadBones(step);\n\t}\n\n\treturn 0;\n}\n\nvoid AutomationDialog::OnAddVariable(wxCommandEvent& WXUNUSED(event)) {\n\tif (varRowCount >= 10)\n\t\treturn;\n\n\tvarRowCount++;\n\n\tauto* pane = XRCCTRL(*this, \"paneVariables\", wxCollapsiblePane);\n\tif (!pane)\n\t\treturn;\n\n\twxWindow* paneWin = pane->GetPane();\n\tif (!paneWin)\n\t\treturn;\n\n\t// The sizer hierarchy: panewindow -> wxBoxSizer -> item[1] -> wxFlexGridSizer\n\twxSizer* boxSizer = paneWin->GetSizer();\n\tif (!boxSizer || boxSizer->GetItemCount() < 2)\n\t\treturn;\n\n\tauto* gridSizer = dynamic_cast<wxFlexGridSizer*>(boxSizer->GetItem(static_cast<size_t>(1))->GetSizer());\n\tif (!gridSizer)\n\t\treturn;\n\n\t// The grid's containing window is the pane window\n\twxWindow* parent = paneWin;\n\n\twxString keyName = wxString::Format(\"txtVarKey%d\", varRowCount);\n\twxString valName = wxString::Format(\"txtVarVal%d\", varRowCount);\n\n\tauto* keyCtrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, keyName);\n\tauto* valCtrl = new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, valName);\n\n\tkeyCtrl->SetName(keyName);\n\tvalCtrl->SetName(valName);\n\n\tgridSizer->Add(keyCtrl, 0, wxEXPAND);\n\tgridSizer->Add(valCtrl, 0, wxEXPAND);\n\n\tpaneWin->Layout();\n\tpane->InvalidateBestSize();\n\tLayout();\n}\n\nvoid AutomationDialog::OnRemoveVariable(wxCommandEvent& WXUNUSED(event)) {\n\tif (varRowCount <= 1)\n\t\treturn;\n\n\tauto* pane = XRCCTRL(*this, \"paneVariables\", wxCollapsiblePane);\n\tif (!pane)\n\t\treturn;\n\n\twxWindow* paneWin = pane->GetPane();\n\tif (!paneWin)\n\t\treturn;\n\n\twxSizer* boxSizer = paneWin->GetSizer();\n\tif (!boxSizer || boxSizer->GetItemCount() < 2)\n\t\treturn;\n\n\tauto* gridSizer = dynamic_cast<wxFlexGridSizer*>(boxSizer->GetItem(static_cast<size_t>(1))->GetSizer());\n\tif (!gridSizer)\n\t\treturn;\n\n\twxString keyName = wxString::Format(\"txtVarKey%d\", varRowCount);\n\twxString valName = wxString::Format(\"txtVarVal%d\", varRowCount);\n\tauto* keyCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(keyName));\n\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(valName));\n\n\tif (keyCtrl) {\n\t\tgridSizer->Detach(keyCtrl);\n\t\tkeyCtrl->Destroy();\n\t}\n\tif (valCtrl) {\n\t\tgridSizer->Detach(valCtrl);\n\t\tvalCtrl->Destroy();\n\t}\n\n\tvarRowCount--;\n\n\tpaneWin->Layout();\n\tpane->InvalidateBestSize();\n\tLayout();\n}\n\nvoid AutomationDialog::PopulateRefTemplates() {\n\tauto* choice = XRCCTRL(*this, \"choiceRefTemplate\", wxChoice);\n\tif (!choice)\n\t\treturn;\n\n\tchoice->Clear();\n\tchoice->Append(\"(None - use file below)\");\n\n\tfor (const auto& tmpl : outfitStudio->GetRefTemplates())\n\t\tchoice->Append(wxString::FromUTF8(tmpl.GetName()));\n\n\tchoice->SetSelection(0);\n}\n\nvoid AutomationDialog::OnRefTemplateChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* choice = XRCCTRL(*this, \"choiceRefTemplate\", wxChoice);\n\tif (!choice)\n\t\treturn;\n\n\tint sel = choice->GetSelection();\n\tif (sel <= 0)\n\t\treturn; // \"(None)\" selected\n\n\tsize_t tmplIdx = static_cast<size_t>(sel - 1);\n\tif (tmplIdx >= outfitStudio->GetRefTemplates().size())\n\t\treturn;\n\n\tconst auto& tmpl = outfitStudio->GetRefTemplates()[tmplIdx];\n\n\t// Fill source file\n\tauto* fp = XRCCTRL(*this, \"fpRefSourceFile\", wxFilePickerCtrl);\n\tif (fp) {\n\t\twxString source = wxString::FromUTF8(tmpl.GetSource());\n\t\tif (!source.IsEmpty()) {\n\t\t\twxFileName fn(source);\n\t\t\tif (fn.IsRelative()) {\n\t\t\t\tstd::string projPath = GetProjectPath();\n\t\t\t\tfn.MakeAbsolute(wxString::FromUTF8(projPath));\n\t\t\t}\n\t\t\tfp->SetPath(fn.GetFullPath());\n\t\t}\n\n\t\t// Populate sets from the source file\n\t\tPopulateSetsFromFile(fp->GetPath(), \"choiceRefSet\", \"choiceRefShape\");\n\t}\n\n\t// Select slider set\n\tauto* choiceSet = XRCCTRL(*this, \"choiceRefSet\", wxChoice);\n\tif (choiceSet) {\n\t\twxString setName = wxString::FromUTF8(tmpl.GetSetName());\n\t\tint idx = choiceSet->FindString(setName);\n\t\tif (idx != wxNOT_FOUND)\n\t\t\tchoiceSet->SetSelection(idx);\n\n\t\t// Populate shapes\n\t\tif (fp)\n\t\t\tPopulateRefShapesForSet(fp->GetPath(), setName);\n\t}\n\n\t// Select shape\n\tauto* choiceShape = XRCCTRL(*this, \"choiceRefShape\", wxChoice);\n\tif (choiceShape) {\n\t\twxString shapeName = wxString::FromUTF8(tmpl.GetShape());\n\t\tint idx = choiceShape->FindString(shapeName);\n\t\tif (idx != wxNOT_FOUND)\n\t\t\tchoiceShape->SetSelection(idx);\n\t}\n\n\t// Set load all checkbox\n\tauto* chk = XRCCTRL(*this, \"chkRefLoadAll\", wxCheckBox);\n\tif (chk)\n\t\tchk->SetValue(tmpl.GetLoadAll());\n}\n\nvoid AutomationDialog::OnRefSourceFileChanged(wxFileDirPickerEvent& event) {\n\twxString filePath = event.GetPath();\n\tPopulateSetsFromFile(filePath, \"choiceRefSet\", \"choiceRefShape\");\n\n\t// Reset template dropdown to \"(None)\" since user chose a file manually\n\tauto* choiceTemplate = XRCCTRL(*this, \"choiceRefTemplate\", wxChoice);\n\tif (choiceTemplate)\n\t\tchoiceTemplate->SetSelection(0);\n}\n\nvoid AutomationDialog::OnRefSetChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* choiceSet = XRCCTRL(*this, \"choiceRefSet\", wxChoice);\n\tauto* fp = XRCCTRL(*this, \"fpRefSourceFile\", wxFilePickerCtrl);\n\tif (!choiceSet || !fp)\n\t\treturn;\n\n\twxString setName = choiceSet->GetStringSelection();\n\tPopulateRefShapesForSet(fp->GetPath(), setName);\n}\n\nvoid AutomationDialog::PopulateSetsFromFile(const wxString& filePath, const char* choiceName, const char* shapesChoiceName) {\n\tauto* choiceSet = XRCCTRL(*this, choiceName, wxChoice);\n\tif (!choiceSet)\n\t\treturn;\n\n\tchoiceSet->Clear();\n\n\twxChoice* choiceShape = nullptr;\n\tif (shapesChoiceName) {\n\t\tchoiceShape = XRCCTRL(*this, shapesChoiceName, wxChoice);\n\t\tif (choiceShape)\n\t\t\tchoiceShape->Clear();\n\t}\n\n\tif (filePath.IsEmpty())\n\t\treturn;\n\n\twxFileName fn(filePath);\n\twxString ext = fn.GetExt().Lower();\n\tif (ext == \"nif\")\n\t\treturn; // NIF files don't have slider sets\n\n\tSliderSetFile ssf(filePath.ToUTF8().data());\n\tif (ssf.fail())\n\t\treturn;\n\n\tstd::vector<std::string> setNames;\n\tssf.GetSetNamesUnsorted(setNames);\n\n\tfor (const auto& name : setNames)\n\t\tchoiceSet->Append(wxString::FromUTF8(name));\n\n\tif (!setNames.empty()) {\n\t\tchoiceSet->SetSelection(0);\n\t\tif (shapesChoiceName)\n\t\t\tPopulateRefShapesForSet(filePath, choiceSet->GetStringSelection());\n\t}\n}\n\nvoid AutomationDialog::PopulateRefShapesForSet(const wxString& filePath, const wxString& setName) {\n\tauto* choiceShape = XRCCTRL(*this, \"choiceRefShape\", wxChoice);\n\tif (!choiceShape)\n\t\treturn;\n\n\tchoiceShape->Clear();\n\n\tif (filePath.IsEmpty() || setName.IsEmpty())\n\t\treturn;\n\n\tSliderSetFile ssf(filePath.ToUTF8().data());\n\tif (ssf.fail())\n\t\treturn;\n\n\tstd::vector<std::string> shapes;\n\tssf.SetShapes(setName.ToUTF8().data(), shapes);\n\n\tfor (const auto& shape : shapes)\n\t\tchoiceShape->Append(wxString::FromUTF8(shape));\n\n\tif (!shapes.empty())\n\t\tchoiceShape->SetSelection(0);\n}\n\nvoid AutomationDialog::OnAddProjSourceFileChanged(wxFileDirPickerEvent& event) {\n\twxString filePath = event.GetPath();\n\tPopulateSetsFromFile(filePath, \"choiceAddProjSet\");\n}\n\nvoid AutomationDialog::OnAddProjSetChanged(wxCommandEvent& WXUNUSED(event)) {\n\t// Nothing to do — AddProject has no shape picker\n}\n\nvoid AutomationDialog::OnImportFolderChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* chk = XRCCTRL(*this, \"chkImportFromFolder\", wxCheckBox);\n\tif (chk)\n\t\tUpdateImportFolderVisibility(chk->GetValue());\n}\n\nvoid AutomationDialog::OnSliderDataFolderChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* chk = XRCCTRL(*this, \"chkSliderDataFromFolder\", wxCheckBox);\n\tif (chk)\n\t\tUpdateSliderDataFolderVisibility(chk->GetValue());\n}\n\nvoid AutomationDialog::OnSaveUseOriginalChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* chk = XRCCTRL(*this, \"chkSaveUseOriginal\", wxCheckBox);\n\tif (chk) {\n\t\tUpdateSaveFieldsEnabled(!chk->GetValue());\n\n\t\t// Default copy-ref-from-project to on when use-original is checked\n\t\tif (chk->GetValue())\n\t\t\tSetCheckboxValue(\"chkSaveCopyRefFromProject\", true);\n\t}\n}\n\nvoid AutomationDialog::OnExportUseOriginalChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* chk = XRCCTRL(*this, \"chkExportUseOriginalPath\", wxCheckBox);\n\tif (chk)\n\t\tUpdateExportFieldsEnabled(!chk->GetValue());\n}\n\nvoid AutomationDialog::OnSetRefUnsetChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto* chk = XRCCTRL(*this, \"chkSetRefUnset\", wxCheckBox);\n\tif (chk)\n\t\tUpdateSetRefFieldsEnabled(!chk->GetValue());\n}\n\nvoid AutomationDialog::UpdateSetRefFieldsEnabled(bool enabled) {\n\tauto* txt = XRCCTRL(*this, \"txtSetRefShapeName\", wxTextCtrl);\n\tif (txt)\n\t\ttxt->Enable(enabled);\n}\n\nvoid AutomationDialog::OnSliderPropZapChanged(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateSliderPropDefaultVisibility();\n}\n\nvoid AutomationDialog::UpdateSliderPropDefaultVisibility() {\n\tauto* choiceZap = XRCCTRL(*this, \"choiceSliderPropZap\", wxChoice);\n\tbool isZap = choiceZap && choiceZap->GetSelection() == 2; // \"Yes\"\n\n\tauto showCtrl = [this](const char* name, bool show) {\n\t\tauto* win = FindWindow(name);\n\t\tif (win)\n\t\t\twin->Show(show);\n\t};\n\n\tshowCtrl(\"lblSliderPropZapped\", isZap);\n\tshowCtrl(\"choiceSliderPropZapped\", isZap);\n\tshowCtrl(\"lblSliderPropDefaultLo\", !isZap);\n\tshowCtrl(\"txtSliderPropDefaultLo\", !isZap);\n\tshowCtrl(\"lblSliderPropDefaultHi\", !isZap);\n\tshowCtrl(\"txtSliderPropDefaultHi\", !isZap);\n\n\tauto* panel = XRCCTRL(*this, \"pageSetSliderProperties\", wxPanel);\n\tif (panel)\n\t\tpanel->Layout();\n}\n\nvoid AutomationDialog::OnLoadMaskFileChanged(wxFileDirPickerEvent& event) {\n\twxString filePath = event.GetPath();\n\tPopulateMaskNamesFromFile(filePath);\n}\n\nvoid AutomationDialog::PopulateMaskNamesFromFile(const wxString& filePath) {\n\tauto* choice = XRCCTRL(*this, \"choiceLoadMaskName\", wxChoice);\n\tif (!choice)\n\t\treturn;\n\n\tchoice->Clear();\n\n\tif (filePath.IsEmpty())\n\t\treturn;\n\n\tMaskFile maskFile;\n\tif (maskFile.Load(filePath.ToUTF8().data()) == 0) {\n\t\tfor (const auto& entry : maskFile.GetEntries())\n\t\t\tchoice->Append(wxString::FromUTF8(entry.name));\n\n\t\tif (choice->GetCount() > 0)\n\t\t\tchoice->SetSelection(0);\n\t}\n}\n\nvoid AutomationDialog::UpdateImportFolderVisibility(bool fromFolder) {\n\tauto setEnabled = [this](const char* name, bool enabled) {\n\t\tauto* win = FindWindow(name);\n\t\tif (win)\n\t\t\twin->Enable(enabled);\n\t};\n\n\tsetEnabled(\"fpImportFile\", !fromFolder);\n\tsetEnabled(\"dpImportFolder\", fromFolder);\n}\n\nvoid AutomationDialog::UpdateSliderDataFolderVisibility(bool fromFolder) {\n\tauto setEnabled = [this](const char* name, bool enabled) {\n\t\tauto* win = FindWindow(name);\n\t\tif (win)\n\t\t\twin->Enable(enabled);\n\t};\n\n\tsetEnabled(\"fpSliderDataFile\", !fromFolder);\n\tsetEnabled(\"dpSliderDataFolder\", fromFolder);\n}\n\nvoid AutomationDialog::UpdateSaveFieldsEnabled(bool enabled) {\n\tbool useOriginal = !enabled;\n\n\tauto* originalFields = FindWindow(\"panelSaveOriginalFields\");\n\tif (originalFields)\n\t\toriginalFields->Show(!useOriginal);\n\n\tauto* batchFields = FindWindow(\"panelSaveBatchFields\");\n\tif (batchFields)\n\t\tbatchFields->Show(useOriginal);\n\n\tauto* page = FindWindow(\"pageSaveProject\");\n\tif (page)\n\t\tpage->Layout();\n}\n\nvoid AutomationDialog::UpdateExportFieldsEnabled(bool enabled) {\n\tauto* fp = XRCCTRL(*this, \"fpExportFile\", wxFilePickerCtrl);\n\tif (fp)\n\t\tfp->Enable(enabled);\n\n\tauto* dp = XRCCTRL(*this, \"dpExportFolder\", wxDirPickerCtrl);\n\tif (dp)\n\t\tdp->Enable(enabled);\n}\n\nvoid AutomationDialog::UpdateExportForBatchMode() {\n\tbool isBatch = radioBatchMode && radioBatchMode->GetSelection() != 0;\n\n\tauto* lbl = XRCCTRL(*this, \"lblExportPath\", wxStaticText);\n\tif (lbl)\n\t\tlbl->SetLabel(isBatch ? _(\"Export Folder:\") : _(\"Export File Path:\"));\n\n\tauto* fp = XRCCTRL(*this, \"fpExportFile\", wxFilePickerCtrl);\n\tif (fp)\n\t\tfp->Show(!isBatch);\n\n\tauto* dp = XRCCTRL(*this, \"dpExportFolder\", wxDirPickerCtrl);\n\tif (dp)\n\t\tdp->Show(isBatch);\n\n\tauto* chk = XRCCTRL(*this, \"chkExportUseOriginalPath\", wxCheckBox);\n\tif (chk) {\n\t\tchk->Show(isBatch);\n\t\tif (!isBatch)\n\t\t\tchk->SetValue(false);\n\t}\n\n\tauto* page = XRCCTRL(*this, \"pageExportFile\", wxPanel);\n\tif (page)\n\t\tpage->Layout();\n}\n\nwxString AutomationDialog::MakeRelativeToProject(const wxString& absolutePath) const {\n\tif (absolutePath.empty())\n\t\treturn absolutePath;\n\n\twxFileName fn(absolutePath);\n\n\tif (fn.IsRelative())\n\t\treturn absolutePath; // Already relative\n\n\tif (fn.MakeRelativeTo(wxString::FromUTF8(GetProjectPath())))\n\t\treturn fn.GetFullPath();\n\n\treturn absolutePath; // Couldn't make relative, return as-is\n}\n\nwxString AutomationDialog::MakeAbsoluteToProject(const wxString& path) const {\n\tif (path.empty())\n\t\treturn path;\n\n\twxFileName fn(path);\n\tif (!fn.IsRelative())\n\t\treturn path;\n\n\tfn.MakeAbsolute(wxString::FromUTF8(GetProjectPath()));\n\treturn fn.GetFullPath();\n}\n\nvoid AutomationDialog::PopulateVariablesUI() {\n\tconst auto& vars = script.GetVariables();\n\n\t// Clear existing rows (set them empty)\n\tfor (int i = 1; i <= 10; i++) {\n\t\twxString keyName = wxString::Format(\"txtVarKey%d\", i);\n\t\twxString valName = wxString::Format(\"txtVarVal%d\", i);\n\t\tauto* keyCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(keyName));\n\t\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(valName));\n\t\tif (keyCtrl)\n\t\t\tkeyCtrl->SetValue(wxEmptyString);\n\t\tif (valCtrl)\n\t\t\tvalCtrl->SetValue(wxEmptyString);\n\t}\n\n\t// Populate from script variables\n\tint row = 1;\n\tfor (const auto& [key, val] : vars) {\n\t\tif (row > 10)\n\t\t\tbreak;\n\n\t\twxString keyName = wxString::Format(\"txtVarKey%d\", row);\n\t\twxString valName = wxString::Format(\"txtVarVal%d\", row);\n\t\tauto* keyCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(keyName));\n\t\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(valName));\n\n\t\tif (!keyCtrl || !valCtrl) {\n\t\t\t// Need to add a row by simulating Add Variable click\n\t\t\twxCommandEvent evt;\n\t\t\tOnAddVariable(evt);\n\t\t\tkeyCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(keyName));\n\t\t\tvalCtrl = dynamic_cast<wxTextCtrl*>(FindWindow(valName));\n\t\t}\n\n\t\tif (keyCtrl)\n\t\t\tkeyCtrl->SetValue(wxString::FromUTF8(key));\n\t\tif (valCtrl)\n\t\t\tvalCtrl->SetValue(wxString::FromUTF8(val));\n\n\t\trow++;\n\t}\n\n\tvarRowCount = std::max(1, row - 1);\n}\n\nvoid AutomationDialog::SyncBatchUIFromScript() {\n\tif (radioBatchMode)\n\t\tradioBatchMode->SetSelection(static_cast<int>(script.GetBatchMode()));\n\n\tauto* dp = XRCCTRL(*this, \"dpBatchFolder\", wxDirPickerCtrl);\n\tif (dp)\n\t\tdp->SetPath(wxString::FromUTF8(script.GetBatchFolder()));\n\n\tauto* txt = XRCCTRL(*this, \"txtBatchExtension\", wxTextCtrl);\n\tif (txt)\n\t\ttxt->SetValue(wxString::FromUTF8(script.GetBatchExtension()));\n\n\tauto* chk = XRCCTRL(*this, \"chkBatchSubdirs\", wxCheckBox);\n\tif (chk)\n\t\tchk->SetValue(script.GetBatchSubdirectories());\n\n\ttxt = XRCCTRL(*this, \"txtBatchFileFilter\", wxTextCtrl);\n\tif (txt)\n\t\ttxt->SetValue(wxString::FromUTF8(script.GetBatchFileFilter()));\n\n\tchk = XRCCTRL(*this, \"chkBatchFileFilterRegex\", wxCheckBox);\n\tif (chk)\n\t\tchk->SetValue(script.GetBatchFileFilterRegex());\n\n\ttxt = XRCCTRL(*this, \"txtBatchSliderSetFilter\", wxTextCtrl);\n\tif (txt)\n\t\ttxt->SetValue(wxString::FromUTF8(script.GetBatchSliderSetFilter()));\n\n\tchk = XRCCTRL(*this, \"chkBatchSliderSetFilterRegex\", wxCheckBox);\n\tif (chk)\n\t\tchk->SetValue(script.GetBatchSliderSetFilterRegex());\n\n\tUpdateBatchPanelVisibility();\n}\n\nvoid AutomationDialog::SyncBatchScriptFromUI() {\n\tif (radioBatchMode)\n\t\tscript.SetBatchMode(static_cast<AutomationBatchMode>(radioBatchMode->GetSelection()));\n\n\tauto* dp = XRCCTRL(*this, \"dpBatchFolder\", wxDirPickerCtrl);\n\tif (dp)\n\t\tscript.SetBatchFolder(dp->GetPath().ToUTF8().data());\n\n\tauto* txt = XRCCTRL(*this, \"txtBatchExtension\", wxTextCtrl);\n\tif (txt)\n\t\tscript.SetBatchExtension(txt->GetValue().ToUTF8().data());\n\n\tauto* chk = XRCCTRL(*this, \"chkBatchSubdirs\", wxCheckBox);\n\tif (chk)\n\t\tscript.SetBatchSubdirectories(chk->GetValue());\n\n\ttxt = XRCCTRL(*this, \"txtBatchFileFilter\", wxTextCtrl);\n\tif (txt)\n\t\tscript.SetBatchFileFilter(txt->GetValue().ToUTF8().data());\n\n\tchk = XRCCTRL(*this, \"chkBatchFileFilterRegex\", wxCheckBox);\n\tif (chk)\n\t\tscript.SetBatchFileFilterRegex(chk->GetValue());\n\n\ttxt = XRCCTRL(*this, \"txtBatchSliderSetFilter\", wxTextCtrl);\n\tif (txt)\n\t\tscript.SetBatchSliderSetFilter(txt->GetValue().ToUTF8().data());\n\n\tchk = XRCCTRL(*this, \"chkBatchSliderSetFilterRegex\", wxCheckBox);\n\tif (chk)\n\t\tscript.SetBatchSliderSetFilterRegex(chk->GetValue());\n}\n\nvoid AutomationDialog::UpdateBatchPanelVisibility() {\n\tint mode = radioBatchMode ? radioBatchMode->GetSelection() : 0;\n\n\tbool folderMode = (mode == 1);\n\tbool sliderSetMode = (mode == 2);\n\n\tauto* panelFolder = XRCCTRL(*this, \"panelBatchFolder\", wxPanel);\n\tauto* panelSliderSets = XRCCTRL(*this, \"panelBatchSliderSets\", wxPanel);\n\n\tif (panelFolder)\n\t\tpanelFolder->Show(folderMode);\n\tif (panelSliderSets)\n\t\tpanelSliderSets->Show(sliderSetMode);\n\n\tauto* paneBatch = XRCCTRL(*this, \"paneBatch\", wxCollapsiblePane);\n\tif (paneBatch) {\n\t\tauto* pane = paneBatch->GetPane();\n\t\tpane->Layout();\n\t\tpane->GetSizer()->SetSizeHints(pane);\n\t\tGetSizer()->Layout();\n\t}\n}\n\nvoid AutomationDialog::OnBatchModeChanged(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateBatchPanelVisibility();\n\n\t// Set batch-specific options on all steps\n\tfor (auto& step : script.GetSteps())\n\t\tApplyBatchModeDefaults(step);\n\n\t// Update currently displayed step\n\tif (selectedStep >= 0 && selectedStep < static_cast<int>(script.GetSteps().size())) {\n\t\tauto& step = script.GetSteps()[selectedStep];\n\t\tif (step.type == AutomationStepType::ExportFile) {\n\t\t\tstep.exportFilePath.clear();\n\t\t\tauto* fp = XRCCTRL(*this, \"fpExportFile\", wxFilePickerCtrl);\n\t\t\tif (fp)\n\t\t\t\tfp->SetPath(wxEmptyString);\n\t\t\tauto* dp = XRCCTRL(*this, \"dpExportFolder\", wxDirPickerCtrl);\n\t\t\tif (dp)\n\t\t\t\tdp->SetPath(wxEmptyString);\n\n\t\t\tSetCheckboxValue(\"chkExportUseOriginalPath\", step.exportUseOriginalPath);\n\t\t\tUpdateExportForBatchMode();\n\t\t\tUpdateExportFileBatchModeUI(step);\n\t\t}\n\t\telse if (step.type == AutomationStepType::SaveProject) {\n\t\t\tSetCheckboxValue(\"chkSaveUseOriginal\", step.saveUseOriginal);\n\t\t\tSetCheckboxValue(\"chkSaveCopyRefFromProject\", step.saveCopyRefFromProject);\n\t\t\tUpdateSaveProjectBatchModeUI(step);\n\t\t}\n\t}\n}\n\nvoid AutomationDialog::AppendFromList(const char* textCtrlName, const wxArrayString& items, const wxString& title) {\n\tif (items.IsEmpty())\n\t\treturn;\n\n\tauto* txt = XRCCTRL(*this, textCtrlName, wxTextCtrl);\n\tif (!txt)\n\t\treturn;\n\n\t// Parse existing entries to exclude from the list\n\tstd::vector<std::string> existing = SplitCommaSeparated(std::string(txt->GetValue().ToUTF8().data()));\n\tstd::set<std::string> existingSet(existing.begin(), existing.end());\n\n\twxArrayString filtered;\n\tfor (const auto& item : items) {\n\t\tif (existingSet.find(std::string(item.ToUTF8().data())) == existingSet.end())\n\t\t\tfiltered.Add(item);\n\t}\n\n\tif (filtered.IsEmpty())\n\t\treturn;\n\n\twxMultiChoiceDialog dlg(this, _(\"Select items to add:\"), title, filtered);\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\twxArrayInt selections = dlg.GetSelections();\n\tif (selections.IsEmpty())\n\t\treturn;\n\n\twxString current = txt->GetValue().Trim().Trim(false);\n\tfor (int sel : selections) {\n\t\twxString item = filtered[sel];\n\t\tif (!current.IsEmpty())\n\t\t\tcurrent += \", \";\n\t\tcurrent += item;\n\t}\n\ttxt->SetValue(current);\n}\n\nvoid AutomationDialog::OnAddShapeToField(wxCommandEvent& WXUNUSED(event)) {\n\twxArrayString items;\n\tauto* workNif = project->GetWorkNif();\n\tif (workNif) {\n\t\tfor (auto* shape : workNif->GetShapes())\n\t\t\titems.Add(wxString::FromUTF8(shape->name.get()));\n\t}\n\n\tAppendFromList(\"txtTargetMeshes\", items, _(\"Add Shapes\"));\n}\n\nvoid AutomationDialog::OnAddSliderToField(wxCommandEvent& event) {\n\t// Determine which text control to append to based on which button was clicked\n\twxWindow* btn = dynamic_cast<wxWindow*>(event.GetEventObject());\n\tconst char* textCtrlName = nullptr;\n\n\tif (btn) {\n\t\twxString name = btn->GetName();\n\t\tif (name == \"btnAddDeleteSlider\")\n\t\t\ttextCtrlName = \"txtDeleteSliderName\";\n\t\telse if (name == \"btnAddSetSlider\")\n\t\t\ttextCtrlName = \"txtSetSliderNames\";\n\t\telse if (name == \"btnAddConformSlider\")\n\t\t\ttextCtrlName = \"txtConformSliderNames\";\n\t\telse if (name == \"btnAddSliderProp\")\n\t\t\ttextCtrlName = \"txtSliderPropNames\";\n\t\telse if (name == \"btnAddFixClipSlider\")\n\t\t\ttextCtrlName = \"txtFixClipSliderNames\";\n\t}\n\n\tif (!textCtrlName)\n\t\treturn;\n\n\twxArrayString items;\n\tstd::vector<std::string> sliderList;\n\tproject->GetSliderList(sliderList);\n\tfor (const auto& s : sliderList)\n\t\titems.Add(wxString::FromUTF8(s));\n\n\tAppendFromList(textCtrlName, items, _(\"Add Sliders\"));\n}\n\nstd::vector<std::string> AutomationDialog::GatherBatchFiles() {\n\tstd::vector<std::string> result;\n\n\twxString folder = MakeAbsoluteToProject(wxString::FromUTF8(script.GetBatchFolder()));\n\tstd::string ext = script.GetBatchExtension();\n\tif (folder.IsEmpty() || ext.empty())\n\t\treturn result;\n\n\t// Ensure extension starts with *\n\twxString wildcard = wxString::FromUTF8(\"*\" + ext);\n\n\twxArrayString wxFiles;\n\tif (script.GetBatchSubdirectories())\n\t\twxDir::GetAllFiles(folder, &wxFiles, wildcard);\n\telse {\n\t\twxDir dir(folder);\n\t\tif (dir.IsOpened()) {\n\t\t\twxString f;\n\t\t\tif (dir.GetFirst(&f, wildcard, wxDIR_FILES)) {\n\t\t\t\tdo {\n\t\t\t\t\twxFiles.Add(folder + wxFileName::GetPathSeparator() + f);\n\t\t\t\t} while (dir.GetNext(&f));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Apply file filter\n\tstd::string filter = script.GetBatchFileFilter();\n\tbool useRegex = script.GetBatchFileFilterRegex();\n\tstd::regex filterRegex;\n\tif (useRegex && !filter.empty()) {\n\t\ttry {\n\t\t\tfilterRegex = std::regex(filter, std::regex::icase);\n\t\t}\n\t\tcatch (const std::regex_error&) {\n\t\t\twxLogWarning(\"Automation: Invalid batch file filter regex '%s'.\", filter);\n\t\t\tuseRegex = false;\n\t\t}\n\t}\n\n\tfor (const auto& filePath : wxFiles) {\n\t\tstd::string path = filePath.ToUTF8().data();\n\n\t\tif (!filter.empty()) {\n\t\t\twxFileName fn(filePath);\n\t\t\tstd::string name = fn.GetFullName().ToUTF8().data();\n\t\t\tif (!MatchesFilter(name, filter, useRegex, filterRegex))\n\t\t\t\tcontinue;\n\t\t}\n\n\t\tresult.push_back(path);\n\t}\n\n\treturn result;\n}\n\nstd::vector<std::pair<std::string, std::string>> AutomationDialog::GatherBatchSliderSets() {\n\tstd::vector<std::pair<std::string, std::string>> result; // (fileName, setName) pairs\n\n\tstd::string projPath = GetProjectPath();\n\twxArrayString files;\n\twxDir::GetAllFiles(wxString::FromUTF8(projPath) + \"/SliderSets\", &files, \"*.osp\");\n\twxDir::GetAllFiles(wxString::FromUTF8(projPath) + \"/SliderSets\", &files, \"*.xml\");\n\n\tstd::string filter = script.GetBatchSliderSetFilter();\n\tbool useRegex = script.GetBatchSliderSetFilterRegex();\n\tstd::regex filterRegex;\n\tif (useRegex && !filter.empty()) {\n\t\ttry {\n\t\t\tfilterRegex = std::regex(filter, std::regex::icase);\n\t\t}\n\t\tcatch (const std::regex_error&) {\n\t\t\twxLogWarning(\"Automation: Invalid slider set filter regex '%s'.\", filter);\n\t\t\tuseRegex = false;\n\t\t}\n\t}\n\n\tfor (const auto& filePath : files) {\n\t\tSliderSetFile ssf(filePath.ToUTF8().data());\n\t\tif (ssf.fail())\n\t\t\tcontinue;\n\n\t\tstd::vector<std::string> setNames;\n\t\tssf.GetSetNamesUnsorted(setNames);\n\n\t\tfor (const auto& setName : setNames) {\n\t\t\tif (!MatchesFilter(setName, filter, useRegex, filterRegex))\n\t\t\t\tcontinue;\n\n\t\t\tresult.push_back({filePath.ToUTF8().data(), setName});\n\t\t}\n\t}\n\n\treturn result;\n}\n\nvoid AutomationDialog::ExecuteBatch(const std::vector<size_t>& stepIndices, const std::vector<std::string>& selectedFiles, const std::vector<std::pair<std::string, std::string>>& selectedSets) {\n\tauto batchMode = script.GetBatchMode();\n\n\t// Pre-set OptimizeForSSE if not already configured.\n\t// ValidateNIF would normally prompt via wxMessageBox parented to OutfitStudioFrame,\n\t// which appears behind this modal dialog and blocks. Default to true (optimize).\n\tConfig.SetDefaultBoolValue(\"OptimizeForSSE\", true);\n\n\t// Clear project before starting batch to prevent current content from leaking into first iteration\n\tResetAndClearProject();\n\n\tStartProgress(_(\"Preparing...\"));\n\n\tif (batchMode == AutomationBatchMode::FolderScan) {\n\t\tauto batchFiles = selectedFiles.empty() ? GatherBatchFiles() : selectedFiles;\n\t\tif (batchFiles.empty()) {\n\t\t\tEndProgress(_(\"No files found.\"));\n\t\t\twxMessageBox(_(\"No files found matching the batch folder scan criteria.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\treturn;\n\t\t}\n\n\t\tint totalItems = static_cast<int>(batchFiles.size());\n\t\tint processedCount = 0;\n\t\tint errorCount = 0;\n\n\t\tfor (int itemIdx = 0; itemIdx < totalItems; itemIdx++) {\n\t\t\tconst auto& filePath = batchFiles[itemIdx];\n\t\t\twxFileName fn(wxString::FromUTF8(filePath));\n\t\t\tstd::string baseName = fn.GetName().ToUTF8().data();\n\n\t\t\tint progress = itemIdx * 100 / totalItems;\n\t\t\twxString msg = wxString::Format(_(\"Processing %d/%d: %s\"), itemIdx + 1, totalItems, fn.GetFullName());\n\t\t\tUpdateProgress(progress, msg);\n\n\t\t\tif (cancelRequested) {\n\t\t\t\twxLogMessage(\"Automation: Batch cancelled by user.\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Set up batch-specific variables\n\t\t\tauto vars = CollectVariables();\n\t\t\tvars[\"BATCH_FILE\"] = filePath;\n\t\t\tvars[\"BATCH_NAME\"] = baseName;\n\t\t\tvars[\"BATCH_DIR\"] = fn.GetPath().ToUTF8().data();\n\t\t\tvars[\"BATCH_FULLNAME\"] = fn.GetFullName().ToUTF8().data();\n\n\t\t\t// Clear project for fresh start\n\t\t\tResetAndClearProject();\n\n\t\t\t// Import the batch file\n\t\t\twxString ext = fn.GetExt().Lower();\n\t\t\tint importErr = 0;\n\t\t\tif (ext == \"nif\")\n\t\t\t\timportErr = project->ImportNIF(filePath, false);\n\t\t\telse if (ext == \"obj\")\n\t\t\t\timportErr = project->ImportOBJ(filePath);\n\t\t\telse if (ext == \"fbx\")\n#ifdef USE_FBXSDK\n\t\t\t\timportErr = project->ImportFBX(filePath);\n#else\n\t\t\t\twxLogError(\"Automation: FBX import is not available (FBX SDK not compiled in).\");\n#endif\n\t\t\telse {\n\t\t\t\twxLogWarning(\"Automation: Batch - unsupported file type '%s', skipping.\", ext);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (importErr) {\n\t\t\t\twxLogError(\"Automation: Batch - failed to import '%s' (error %d), skipping.\", filePath, importErr);\n\t\t\t\terrorCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Build and execute script copy with substituted variables\n\t\t\tAutomationScript execScript;\n\t\t\tfor (size_t idx : stepIndices)\n\t\t\t\texecScript.AddStep(script.GetSteps()[idx]);\n\n\t\t\texecScript.SubstitutePlaceholders(vars);\n\n\t\t\t// Process steps that have exportUseOriginalPath\n\t\t\tfor (auto& step : execScript.GetSteps()) {\n\t\t\t\tif (step.type == AutomationStepType::ExportFile) {\n\t\t\t\t\tif (step.exportUseOriginalPath) {\n\t\t\t\t\t\tstep.exportFilePath = filePath;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!step.exportFilePath.empty()) {\n\t\t\t\t\t\t// In batch mode, exportFilePath is a folder - construct full path\n\t\t\t\t\t\twxFileName exportFn;\n\t\t\t\t\t\texportFn.SetPath(wxString::FromUTF8(step.exportFilePath));\n\t\t\t\t\t\texportFn.SetFullName(fn.GetFullName());\n\t\t\t\t\t\tstep.exportFilePath = exportFn.GetFullPath().ToUTF8().data();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool stepFailed = false;\n\t\t\tfor (size_t i = 0; i < execScript.GetSteps().size(); i++) {\n\t\t\t\tconst auto& batchStep = execScript.GetSteps()[i];\n\t\t\t\tint err = ExecuteStep(batchStep);\n\t\t\t\tif (err != 0) {\n\t\t\t\t\twxLogError(\"Automation: Batch - step %zu failed on '%s'.\", i + 1, filePath);\n\t\t\t\t\tstepFailed = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\toutfitStudio->RefreshGUIFromProj();\n\n\t\t\t\tif (StepChangesSliderSet(batchStep.type))\n\t\t\t\t\toutfitStudio->CreateSetSliders();\n\n\t\t\t\toutfitStudio->ApplySliders();\n\t\t\t}\n\n\t\t\tif (stepFailed)\n\t\t\t\terrorCount++;\n\n\t\t\tprocessedCount++;\n\n\t\t\t// Clear project after processing each entry\n\t\t\tResetAndClearProject();\n\t\t}\n\n\t\tEndProgress(cancelRequested ? _(\"Batch cancelled.\") : _(\"Batch complete.\"));\n\n\t\t// Refresh UI\n\t\toutfitStudio->RefreshGUIFromProj();\n\t\toutfitStudio->CreateSetSliders();\n\n\t\twxMessageBox(wxString::Format(cancelRequested ? _(\"Batch cancelled: %d/%d items processed before cancellation.\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t  : _(\"Batch completed: %d/%d items processed successfully.\"),\n\t\t\t\t\t\t\t\t\t  processedCount - errorCount, processedCount),\n\t\t\t\t\t _(\"Automation\"), wxICON_INFORMATION);\n\t}\n\telse if (batchMode == AutomationBatchMode::SliderSets) {\n\t\tauto batchSets = selectedSets.empty() ? GatherBatchSliderSets() : selectedSets;\n\t\tif (batchSets.empty()) {\n\t\t\tEndProgress(_(\"No slider sets found.\"));\n\t\t\twxMessageBox(_(\"No slider sets found matching the filter criteria.\"), _(\"Automation\"), wxICON_INFORMATION);\n\t\t\treturn;\n\t\t}\n\n\t\tint totalItems = static_cast<int>(batchSets.size());\n\t\tint processedCount = 0;\n\t\tint errorCount = 0;\n\n\t\tfor (int itemIdx = 0; itemIdx < totalItems; itemIdx++) {\n\t\t\tconst auto& [filePath, setName] = batchSets[itemIdx];\n\t\t\twxFileName fn(wxString::FromUTF8(filePath));\n\n\t\t\tint progress = itemIdx * 100 / totalItems;\n\t\t\twxString msg = wxString::Format(_(\"Processing %d/%d: %s\"), itemIdx + 1, totalItems, wxString::FromUTF8(setName));\n\t\t\tUpdateProgress(progress, msg);\n\n\t\t\tif (cancelRequested) {\n\t\t\t\twxLogMessage(\"Automation: Batch cancelled by user.\");\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// Set up batch-specific variables\n\t\t\tauto vars = CollectVariables();\n\t\t\tvars[\"BATCH_FILE\"] = filePath;\n\t\t\tvars[\"BATCH_NAME\"] = setName;\n\t\t\tvars[\"BATCH_SET\"] = setName;\n\t\t\tvars[\"BATCH_DIR\"] = fn.GetPath().ToUTF8().data();\n\n\t\t\t// Clear and load the project\n\t\t\tResetAndClearProject();\n\t\t\tbool loaded = outfitStudio->LoadProject(filePath, setName, true);\n\n\t\t\t// LoadProject with clearProject=true recreates the project object\n\t\t\tproject = outfitStudio->project;\n\n\t\t\tif (!loaded) {\n\t\t\t\twxLogError(\"Automation: Batch - failed to load project '%s' from '%s', skipping.\", setName, filePath);\n\t\t\t\terrorCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Check if loaded project has a reference shape (before any modifications)\n\t\t\tauto* baseShape = project->GetBaseShape();\n\t\t\tbool loadedProjectHadRef = (baseShape != nullptr);\n\n\t\t\t// Build and execute script copy\n\t\t\tAutomationScript execScript;\n\t\t\tfor (size_t idx : stepIndices)\n\t\t\t\texecScript.AddStep(script.GetSteps()[idx]);\n\n\t\t\texecScript.SubstitutePlaceholders(vars);\n\n\t\t\tfor (auto& step : execScript.GetSteps()) {\n\t\t\t\t// Apply copy-ref-from-project: override saveAutoCopyRef based on loaded project\n\t\t\t\tif (step.type == AutomationStepType::SaveProject && step.saveCopyRefFromProject) {\n\t\t\t\t\tbool hadMatchingRef = loadedProjectHadRef;\n\n\t\t\t\t\t// If shape name filter(s) set, check if the reference matches any of them\n\t\t\t\t\tif (hadMatchingRef && !step.saveCopyRefShapeName.empty()) {\n\t\t\t\t\t\tstd::string refName = baseShape->name.get();\n\t\t\t\t\t\thadMatchingRef = false;\n\t\t\t\t\t\tfor (const auto& name : SplitCommaSeparated(step.saveCopyRefShapeName)) {\n\t\t\t\t\t\t\tif (refName == name) {\n\t\t\t\t\t\t\t\thadMatchingRef = true;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tstep.saveAutoCopyRef = hadMatchingRef;\n\t\t\t\t}\n\n\t\t\t\tif (step.type == AutomationStepType::SaveProject && step.saveUseOriginal) {\n\t\t\t\t\t// Use the original project's save settings\n\t\t\t\t\tstep.saveSliderSetFile = filePath;\n\t\t\t\t\tstep.saveName = setName;\n\n\t\t\t\t\tSliderSetFile ssf(filePath);\n\t\t\t\t\tif (!ssf.fail()) {\n\t\t\t\t\t\tSliderSet ss;\n\t\t\t\t\t\tif (ssf.GetSet(setName, ss) == 0) {\n\t\t\t\t\t\t\tstep.saveOutputFileName = ss.GetOutputFile();\n\t\t\t\t\t\t\tstep.saveOutputDataPath = ss.GetOutputPath();\n\t\t\t\t\t\t\tstep.saveShapeDataFolder = ss.GetDefaultDataFolder();\n\t\t\t\t\t\t\tstep.saveShapeDataFile = ss.GetInputFile();\n\t\t\t\t\t\t\tstep.saveGenWeights = ss.GenWeights();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply replace from/to on all string fields\n\t\t\t\t\tif (!step.saveReplaceFrom.empty()) {\n\t\t\t\t\t\tauto replaceAll = [&](std::string& s) {\n\t\t\t\t\t\t\tsize_t pos = 0;\n\t\t\t\t\t\t\twhile ((pos = s.find(step.saveReplaceFrom, pos)) != std::string::npos) {\n\t\t\t\t\t\t\t\ts.replace(pos, step.saveReplaceFrom.size(), step.saveReplaceTo);\n\t\t\t\t\t\t\t\tpos += step.saveReplaceTo.size();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t};\n\t\t\t\t\t\treplaceAll(step.saveName);\n\t\t\t\t\t\treplaceAll(step.saveOutputFileName);\n\t\t\t\t\t\treplaceAll(step.saveOutputDataPath);\n\t\t\t\t\t\treplaceAll(step.saveShapeDataFolder);\n\t\t\t\t\t\treplaceAll(step.saveShapeDataFile);\n\n\t\t\t\t\t\t// Replace only in the filename part of the slider set file path\n\t\t\t\t\t\twxFileName ssfFn(wxString::FromUTF8(step.saveSliderSetFile));\n\t\t\t\t\t\twxString ssfName = ssfFn.GetName();\n\t\t\t\t\t\tstd::string ssfNameStr = ssfName.ToUTF8().data();\n\t\t\t\t\t\treplaceAll(ssfNameStr);\n\t\t\t\t\t\tssfFn.SetName(wxString::FromUTF8(ssfNameStr));\n\t\t\t\t\t\tstep.saveSliderSetFile = ssfFn.GetFullPath().ToUTF8().data();\n\t\t\t\t\t}\n\n\t\t\t\t\t// Apply suffix to display name, shape data folder, shape data file, and slider set file\n\t\t\t\t\tif (!step.saveSuffix.empty()) {\n\t\t\t\t\t\tstep.saveName += step.saveSuffix;\n\t\t\t\t\t\tstep.saveShapeDataFolder += step.saveSuffix;\n\n\t\t\t\t\t\t// Insert suffix before the file extension for slider set file\n\t\t\t\t\t\twxFileName ssfFn(wxString::FromUTF8(step.saveSliderSetFile));\n\t\t\t\t\t\tssfFn.SetName(ssfFn.GetName() + wxString::FromUTF8(step.saveSuffix));\n\t\t\t\t\t\tstep.saveSliderSetFile = ssfFn.GetFullPath().ToUTF8().data();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (step.type == AutomationStepType::ExportFile) {\n\t\t\t\t\tif (step.exportUseOriginalPath) {\n\t\t\t\t\t\t// Overwrite the original file loaded by the batch\n                        step.exportFilePath = filePath;\n\t\t\t\t\t}\n\t\t\t\t\telse if (!step.exportFilePath.empty()) {\n\t\t\t\t\t\t// In batch mode, exportFilePath is a folder - construct full path\n\t\t\t\t\t\twxFileName exportFn;\n\t\t\t\t\t\texportFn.SetPath(wxString::FromUTF8(step.exportFilePath));\n\t\t\t\t\t\texportFn.SetName(wxString::FromUTF8(setName));\n\t\t\t\t\t\texportFn.SetExt(\"nif\");\n\t\t\t\t\t\tstep.exportFilePath = exportFn.GetFullPath().ToUTF8().data();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool stepFailed = false;\n\t\t\tfor (size_t i = 0; i < execScript.GetSteps().size(); i++) {\n\t\t\t\tconst auto& batchStep = execScript.GetSteps()[i];\n\t\t\t\tint err = ExecuteStep(batchStep);\n\t\t\t\tif (err != 0) {\n\t\t\t\t\twxLogError(\"Automation: Batch - step %zu failed on '%s'.\", i + 1, setName);\n\t\t\t\t\tstepFailed = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\toutfitStudio->RefreshGUIFromProj();\n\n\t\t\t\tif (StepChangesSliderSet(batchStep.type))\n\t\t\t\t\toutfitStudio->CreateSetSliders();\n\n\t\t\t\toutfitStudio->ApplySliders();\n\t\t\t}\n\n\t\t\tif (stepFailed)\n\t\t\t\terrorCount++;\n\n\t\t\tprocessedCount++;\n\n\t\t\t// Clear project after processing each entry\n\t\t\tResetAndClearProject();\n\t\t}\n\n\t\tEndProgress(cancelRequested ? _(\"Batch cancelled.\") : _(\"Batch complete.\"));\n\n\t\t// Refresh UI\n\t\toutfitStudio->RefreshGUIFromProj();\n\t\toutfitStudio->CreateSetSliders();\n\n\t\twxMessageBox(wxString::Format(cancelRequested ? _(\"Batch cancelled: %d/%d slider sets processed before cancellation.\")\n\t\t\t\t\t\t\t\t\t\t\t\t\t  : _(\"Batch completed: %d/%d slider sets processed successfully.\"),\n\t\t\t\t\t\t\t\t\t  processedCount - errorCount, processedCount),\n\t\t\t\t\t _(\"Automation\"), wxICON_INFORMATION);\n\t}\n}\n"
  },
  {
    "path": "src/program/AutomationDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../components/Automation.h\"\n\n#include <wx/collpane.h>\n#include <wx/combobox.h>\n#include <wx/filepicker.h>\n#include <wx/gauge.h>\n#include <wx/listctrl.h>\n#include <wx/log.h>\n#include <wx/radiobox.h>\n#include <wx/simplebook.h>\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n\nclass OutfitStudioFrame;\nclass OutfitProject;\n\nnamespace nifly {\nclass NiShape;\n}\n\nclass AutomationDialog : public wxDialog {\npublic:\n\tAutomationDialog(OutfitStudioFrame* outfitStudio, OutfitProject* project);\n\t~AutomationDialog() override;\n\nprivate:\n\tOutfitStudioFrame* outfitStudio = nullptr;\n\tOutfitProject* project = nullptr;\n\tAutomationScript script;\n\tint selectedStep = -1;\n\tint varRowCount = 1;\n\n\twxListCtrl* listSteps = nullptr;\n\twxStaticText* lblStepsPlaceholder = nullptr;\n\twxSimplebook* bookStepPages = nullptr;\n\twxChoice* choiceStepType = nullptr;\n\twxCheckBox* chkActive = nullptr;\n\twxTextCtrl* txtTargetMeshes = nullptr;\n\twxCheckBox* chkTargetRegex = nullptr;\n\twxTextCtrl* txtNote = nullptr;\n\twxRadioBox* radioBatchMode = nullptr;\n\twxPanel* panelStepSettings = nullptr;\n\twxComboBox* cmbAutomation = nullptr;\n\twxButton* btnSaveScript = nullptr;\n\twxButton* btnExecuteAll = nullptr;\n\twxButton* btnClose = nullptr;\n\twxStatusBar* statusBar = nullptr;\n\twxGauge* progressBar = nullptr;\n\twxCollapsiblePane* paneOutput = nullptr;\n\twxTextCtrl* txtOutput = nullptr;\n\twxLog* oldLogTarget = nullptr;\n\tbool cancelRequested = false;\n\tbool isExecuting = false;\n\n\t// UI helper methods\n\tvoid SetCheckboxValue(const char* name, bool value);\n\tbool GetCheckboxValue(const char* name) const;\n\tvoid SetTextValue(const char* name, const std::string& value);\n\tstd::string GetTextValue(const char* name) const;\n\tvoid SetFloatValue(const char* name, float value);\n\tfloat GetFloatValue(const char* name) const;\n\tint GetIntValue(const char* name) const;\n\tvoid SetVectorValue(const char* name, const std::vector<std::string>& values);\n\tstd::vector<std::string> GetVectorValue(const char* name) const;\n\n\t// Progress methods\n\tvoid StartProgress(const wxString& msg = \"\");\n\tvoid UpdateProgress(int val, const wxString& msg = \"\");\n\tvoid EndProgress(const wxString& msg = \"\");\n\tvoid SetExecutionUIState(bool running);\n\n\tvoid PopulateStepList();\n\tvoid SelectStep(int index);\n\tvoid UpdateStepFromUI();\n\tvoid UpdateUIFromStep(const AutomationStep& step);\n\tvoid RefreshStepRow(int index);\n\tvoid ShowStepSettings(bool show);\n\tvoid UpdateButtonState();\n\n\tstd::string GetAutomationsFolder();\n\tvoid PopulateAutomationList();\n\tvoid CollectScripts(const wxString& baseFolder, const wxString& currentFolder, std::vector<std::pair<wxString, wxString>>& entries);\n\tstatic bool IsSeparatorItem(const wxString& text);\n\tvoid LoadAutomation(const wxString& name);\n\tstatic wxString SanitizePath(const wxString& name);\n\n\tvoid PopulateRefTemplates();\n\tvoid PopulateSetsFromFile(const wxString& filePath, const char* choiceName, const char* shapesChoiceName = nullptr);\n\tvoid PopulateRefShapesForSet(const wxString& filePath, const wxString& setName);\n\twxString MakeRelativeToProject(const wxString& absolutePath) const;\n\twxString MakeAbsoluteToProject(const wxString& path) const;\n\tAutomationBatchMode GetSelectedBatchMode() const;\n\tbool IsBatchMode(AutomationBatchMode mode) const;\n\tvoid ApplyBatchModeDefaults(AutomationStep& step) const;\n\tvoid UpdateSaveProjectBatchModeUI(const AutomationStep& step);\n\tvoid UpdateExportFileBatchModeUI(const AutomationStep& step);\n\tvoid UpdateImportFolderVisibility(bool fromFolder);\n\tvoid UpdateSliderDataFolderVisibility(bool fromFolder);\n\tvoid UpdateSaveFieldsEnabled(bool useOriginal);\n\tvoid UpdateExportFieldsEnabled(bool useOriginal);\n\tvoid UpdateSetRefFieldsEnabled(bool enabled);\n\tvoid UpdateExportForBatchMode();\n\n\tstd::map<std::string, std::string> CollectVariables();\n\tvoid PopulateVariablesUI();\n\tvoid SyncBatchUIFromScript();\n\tvoid SyncBatchScriptFromUI();\n\tvoid UpdateBatchPanelVisibility();\n\n\tvoid ResetAndClearProject();\n\n\tvoid ExecuteSteps(const std::vector<size_t>& stepIndices);\n\tvoid ExecuteBatch(const std::vector<size_t>& stepIndices, const std::vector<std::string>& selectedFiles = {}, const std::vector<std::pair<std::string, std::string>>& selectedSets = {});\n\tint ExecuteStep(const AutomationStep& step);\n\n\tint ExecuteStepClearProject(const AutomationStep& step);\n\tint ExecuteStepLoadReference(const AutomationStep& step);\n\tint ExecuteStepAddProject(const AutomationStep& step);\n\tint ExecuteStepSetSliderValues(const AutomationStep& step);\n\tint ExecuteStepConformSliders(const AutomationStep& step);\n\tint ExecuteStepCopyBoneWeights(const AutomationStep& step);\n\tint ExecuteStepSetBaseShape(const AutomationStep& step);\n\tint ExecuteStepClearReference(const AutomationStep& step);\n\tint ExecuteStepTransformShape(const AutomationStep& step);\n\tint ExecuteStepInvertUVs(const AutomationStep& step);\n\tint ExecuteStepDeleteBones(const AutomationStep& step);\n\tint ExecuteStepAddCustomBone(const AutomationStep& step);\n\tint ExecuteStepEditBone(const AutomationStep& step);\n\tint ExecuteStepRemoveSkinning(const AutomationStep& step);\n\tint ExecuteStepApplyPose(const AutomationStep& step);\n\tint ExecuteStepImportSliderData(const AutomationStep& step);\n\tint ExecuteStepImportFile(const AutomationStep& step);\n\tint ExecuteStepDeleteShape(const AutomationStep& step);\n\tint ExecuteStepRenameShape(const AutomationStep& step);\n\tint ExecuteStepSaveProject(const AutomationStep& step);\n\tint ExecuteStepExportFile(const AutomationStep& step);\n\tint ExecuteStepRefineMesh(const AutomationStep& step);\n\tint ExecuteStepDeleteSlider(const AutomationStep& step);\n\tint ExecuteStepSetReferenceShape(const AutomationStep& step);\n\tint ExecuteStepResetTransforms(const AutomationStep& step);\n\tint ExecuteStepDuplicateShape(const AutomationStep& step);\n\tint ExecuteStepMirrorShape(const AutomationStep& step);\n\tint ExecuteStepLoadMask(const AutomationStep& step);\n\tint ExecuteStepClearMask(const AutomationStep& step);\n\tint ExecuteStepSetSliderProperties(const AutomationStep& step);\n\tint ExecuteStepRemoveUnusedNodes(const AutomationStep& step);\n\tint ExecuteStepFixClipping(const AutomationStep& step);\n\tint ExecuteStepFixBadBones(const AutomationStep& step);\n\n\tstd::vector<std::string> GatherBatchFiles();\n\tstd::vector<std::pair<std::string, std::string>> GatherBatchSliderSets();\n\n\tbool ShowCheckableListDialog(const wxString& title, const wxString& labelText, const wxArrayString& items, std::vector<size_t>& checkedIndices);\n\n\tnifly::NiShape* FindShapeByName(const std::string& name);\n\tstd::vector<nifly::NiShape*> ResolveTargetShapes(const AutomationStep& step);\n\n\tvoid OnSaveScript(wxCommandEvent& event);\n\tvoid OnDeleteScript(wxCommandEvent& event);\n\tvoid OnOpenFolder(wxCommandEvent& event);\n\tvoid OnAutomationSelected(wxCommandEvent& event);\n\tvoid OnAddStep(wxCommandEvent& event);\n\tvoid OnDuplicateStep(wxCommandEvent& event);\n\tvoid OnRemoveStep(wxCommandEvent& event);\n\tvoid OnMoveUp(wxCommandEvent& event);\n\tvoid OnMoveDown(wxCommandEvent& event);\n\tvoid OnStepSelected(wxListEvent& event);\n\tvoid OnStepListKeyDown(wxKeyEvent& event);\n\tvoid OnStepListContextMenu(wxContextMenuEvent& event);\n\tvoid OnStepTypeChanged(wxCommandEvent& event);\n\tvoid OnExecuteAll(wxCommandEvent& event);\n\tvoid OnExecuteSelected(wxCommandEvent& event);\n\tvoid OnClose(wxCommandEvent& event);\n\tvoid OnWindowClose(wxCloseEvent& event);\n\tvoid OnAddVariable(wxCommandEvent& event);\n\tvoid OnRemoveVariable(wxCommandEvent& event);\n\tvoid OnRefTemplateChanged(wxCommandEvent& event);\n\tvoid OnRefSourceFileChanged(wxFileDirPickerEvent& event);\n\tvoid OnRefSetChanged(wxCommandEvent& event);\n\tvoid OnAddProjSourceFileChanged(wxFileDirPickerEvent& event);\n\tvoid OnAddProjSetChanged(wxCommandEvent& event);\n\tvoid OnImportFolderChanged(wxCommandEvent& event);\n\tvoid OnSliderDataFolderChanged(wxCommandEvent& event);\n\tvoid OnSaveUseOriginalChanged(wxCommandEvent& event);\n\tvoid OnExportUseOriginalChanged(wxCommandEvent& event);\n\tvoid OnSetRefUnsetChanged(wxCommandEvent& event);\n\tvoid OnLoadMaskFileChanged(wxFileDirPickerEvent& event);\n\tvoid PopulateMaskNamesFromFile(const wxString& filePath);\n\tvoid OnSliderPropZapChanged(wxCommandEvent& event);\n\tvoid UpdateSliderPropDefaultVisibility();\n\tvoid OnBatchModeChanged(wxCommandEvent& event);\n\tvoid OnCharHook(wxKeyEvent& event);\n\tvoid OnAddShapeToField(wxCommandEvent& event);\n\tvoid OnAddSliderToField(wxCommandEvent& event);\n\tvoid AppendFromList(const char* textCtrlName, const wxArrayString& items, const wxString& title);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/BodySlideApp.cpp",
    "content": "/*\nBodySlide and Outfit Studio\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#include \"BodySlideApp.h\"\n#include \"../components/ClippingFixer.h\"\n#include \"../files/wxDDSImage.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"../utils/StringStuff.h\"\n\n#include <atomic>\n#include <regex>\n#include <wx/wrapsizer.h>\n#include <wx/debugrpt.h>\n\n#ifdef WIN64\n#include <concurrent_unordered_map.h>\n#include <ppl.h>\n#include <ppltasks.h>\n#else\n#undef _PPL_H\n#endif\n\nusing namespace nifly;\n\nConfigurationManager Config;\nConfigurationManager BodySlideConfig;\n\nconst std::array<wxString, 10> TargetGames = {\"Fallout3\", \"FalloutNewVegas\", \"Skyrim\", \"Fallout4\", \"SkyrimSpecialEdition\", \"Fallout4VR\", \"SkyrimVR\", \"Fallout76\", \"Oblivion\", \"Starfield\"};\nconst std::array<wxLanguage, 37> SupportedLangs = {wxLANGUAGE_ENGLISH,\t  wxLANGUAGE_AFRIKAANS,\t\t   wxLANGUAGE_ARABIC,  wxLANGUAGE_CATALAN,\t  wxLANGUAGE_CZECH,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_DANISH,\t  wxLANGUAGE_GERMAN,\t\t   wxLANGUAGE_GREEK,   wxLANGUAGE_SPANISH,\t  wxLANGUAGE_BASQUE,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_FINNISH,\t  wxLANGUAGE_FRENCH,\t\t   wxLANGUAGE_HINDI,   wxLANGUAGE_HUNGARIAN,  wxLANGUAGE_INDONESIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_ITALIAN,\t  wxLANGUAGE_JAPANESE,\t\t   wxLANGUAGE_KOREAN,  wxLANGUAGE_LITHUANIAN, wxLANGUAGE_LATVIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_MALAY,\t  wxLANGUAGE_NORWEGIAN_BOKMAL, wxLANGUAGE_NEPALI,  wxLANGUAGE_DUTCH,\t  wxLANGUAGE_POLISH,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_PORTUGUESE, wxLANGUAGE_ROMANIAN,\t\t   wxLANGUAGE_RUSSIAN, wxLANGUAGE_SLOVAK,\t  wxLANGUAGE_SLOVENIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_ALBANIAN,\t  wxLANGUAGE_SWEDISH,\t\t   wxLANGUAGE_TAMIL,   wxLANGUAGE_TURKISH,\t  wxLANGUAGE_UKRAINIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_VIETNAMESE, wxLANGUAGE_CHINESE};\n\nwxBEGIN_EVENT_TABLE(BodySlideFrame, wxFrame)\n\tEVT_MENU(wxID_EXIT, BodySlideFrame::OnExit)\n\tEVT_CLOSE(BodySlideFrame::OnClose)\n\tEVT_ACTIVATE(BodySlideFrame::OnActivateFrame)\n\tEVT_ICONIZE(BodySlideFrame::OnIconizeFrame)\n\tEVT_COMMAND_SCROLL(wxID_ANY, BodySlideFrame::OnSliderChange)\n\tEVT_TEXT_ENTER(wxID_ANY, BodySlideFrame::OnSliderReadoutChange)\n\tEVT_TEXT(XRCID(\"searchHolder\"), BodySlideFrame::OnSearchChange)\n\tEVT_TEXT(XRCID(\"outfitsearchHolder\"), BodySlideFrame::OnOutfitSearchChange)\n\tEVT_TEXT_ENTER(XRCID(\"sliderFilter\"), BodySlideFrame::OnSliderFilterChanged)\n\tEVT_TEXT(XRCID(\"sliderFilter\"), BodySlideFrame::OnSliderFilterChanged)\n\tEVT_TEXT_ENTER(XRCID(\"presetFilter\"), BodySlideFrame::OnPresetFilterChanged)\n\tEVT_TEXT(XRCID(\"presetFilter\"), BodySlideFrame::OnPresetFilterChanged)\n\tEVT_TIMER(DELAYLOAD_TIMER, BodySlideFrame::OnDelayLoad)\n\tEVT_CHOICE(XRCID(\"outfitChoice\"), BodySlideFrame::OnChooseOutfit)\n\tEVT_CHOICE(XRCID(\"presetChoice\"), BodySlideFrame::OnChoosePreset)\n\n\tEVT_BUTTON(XRCID(\"btnDeleteProject\"), BodySlideFrame::OnDeleteProject)\n\tEVT_BUTTON(XRCID(\"btnDeletePreset\"), BodySlideFrame::OnDeletePreset)\n\tEVT_CHECKBOX(XRCID(\"cbIsOutfitChoice\"), BodySlideFrame::OnOutfitChoiceSelect)\n\n\tEVT_BUTTON(XRCID(\"btnPreview\"), BodySlideFrame::OnPreview)\n\tEVT_BUTTON(XRCID(\"btnHighToLow\"), BodySlideFrame::OnHighToLow)\n\tEVT_BUTTON(XRCID(\"btnLowToHigh\"), BodySlideFrame::OnLowToHigh)\n\tEVT_BUTTON(XRCID(\"btnBuildBatch\"), BodySlideFrame::OnBatchBuild)\n\tEVT_BUTTON(XRCID(\"btnBuild\"), BodySlideFrame::OnBuildBodies)\n\tEVT_BUTTON(XRCID(\"btnOutfitStudio\"), BodySlideFrame::OnOutfitStudio)\n\tEVT_BUTTON(XRCID(\"btnSettings\"), BodySlideFrame::OnSettings)\n\tEVT_BUTTON(XRCID(\"btnAbout\"), BodySlideFrame::OnAbout)\n\tEVT_BUTTON(XRCID(\"btnSavePreset\"), BodySlideFrame::OnSavePreset)\n\tEVT_BUTTON(XRCID(\"btnSavePresetAs\"), BodySlideFrame::OnSavePresetAs)\n\tEVT_BUTTON(XRCID(\"btnGroupManager\"), BodySlideFrame::OnGroupManager)\n\tEVT_BUTTON(XRCID(\"btnChooseGroups\"), BodySlideFrame::OnChooseGroups)\n\tEVT_BUTTON(XRCID(\"btnRefreshOutfits\"), BodySlideFrame::OnRefreshOutfits)\n\tEVT_BUTTON(XRCID(\"btnEditProject\"), BodySlideFrame::OnEditProject)\n\n\tEVT_SLIDER(XRCID(\"sliderClippingStrength\"), BodySlideFrame::OnClippingStrengthChanged)\n\n\tEVT_MENU(XRCID(\"menuChooseGroups\"), BodySlideFrame::OnChooseGroups)\n\tEVT_MENU(XRCID(\"menuRefreshGroups\"), BodySlideFrame::OnRefreshGroups)\n\tEVT_MENU(XRCID(\"menuRefreshOutfits\"), BodySlideFrame::OnRefreshOutfits)\n\tEVT_MENU(XRCID(\"menuRegexOutfits\"), BodySlideFrame::OnRegexOutfits)\n\tEVT_MENU(XRCID(\"menuFilterHasZaps\"), BodySlideFrame::OnFilterHasZaps)\n\tEVT_MENU(XRCID(\"menuBrowseOutfitFolder\"), BodySlideFrame::OnBrowseOutfitFolder)\n\tEVT_MENU(XRCID(\"menuSaveGroups\"), BodySlideFrame::OnSaveGroups)\n\n\tEVT_MOVE_END(BodySlideFrame::OnMoveWindow)\n\tEVT_SIZE(BodySlideFrame::OnSetSize)\nwxEND_EVENT_TABLE()\n\nwxIMPLEMENT_APP(BodySlideApp);\n\nBodySlideApp::~BodySlideApp() {\n\t++previewLoadGeneration;\n\tif (previewLoadThread.joinable())\n\t\tpreviewLoadThread.join();\n\n\tdelete locale;\n\tlocale = nullptr;\n\n\tFSManager::del();\n}\n\nbool BodySlideApp::OnInit() {\n\tif (!wxApp::OnInit())\n\t\treturn false;\n\n#ifdef _DEBUG\n\tstd::string dataDir{wxGetCwd().ToUTF8()};\n#else\n\tstd::string dataDir{wxStandardPaths::Get().GetDataDir().ToUTF8()};\n#endif\n\n\tConfig.LoadConfig(dataDir + \"/Config.xml\");\n\tBodySlideConfig.LoadConfig(dataDir + \"/BodySlide.xml\", \"BodySlideConfig\");\n\n\tConfig.SetDefaultValue(\"AppDir\", dataDir);\n\n\tlogger.Initialize(Config.GetIntValue(\"LogLevel\", -1), dataDir + \"/Log_BS.txt\");\n\twxLogMessage(\"Initializing BodySlide...\");\n\n#ifdef NDEBUG\n\twxHandleFatalExceptions();\n#endif\n\n\twxString appDirUri = wxString::FromUTF8(dataDir);\n\tappDirUri.Replace(\"#\", \"%23\");\n\twxSetEnv(\"AppDir\", appDirUri);\n\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->SetFlags(wxXRC_USE_LOCALE | wxXRC_USE_ENVVARS);\n\txrc->InitAllHandlers();\n\twxInitAllImageHandlers();\n\twxImage::AddHandler(new wxDDSHandler);\n\n\tpreview = nullptr;\n\tpreviewWindow = nullptr;\n\tsliderView = nullptr;\n\n\tBind(wxEVT_CHAR_HOOK, &BodySlideApp::CharHook, this);\n\n\twxLogMessage(\"Working directory: %s\", wxGetCwd());\n\twxLogMessage(\"Executable directory: %s\", wxString::FromUTF8(dataDir));\n\tif (!SetDefaultConfig())\n\t\treturn false;\n\n\tInitLanguage();\n\n\twxString gameName = \"Target game: \";\n\tswitch (targetGame) {\n\t\tcase FO3: gameName.Append(\"Fallout 3\"); break;\n\t\tcase FONV: gameName.Append(\"Fallout New Vegas\"); break;\n\t\tcase SKYRIM: gameName.Append(\"Skyrim\"); break;\n\t\tcase FO4: gameName.Append(\"Fallout 4\"); break;\n\t\tcase SKYRIMSE: gameName.Append(\"Skyrim Special Edition\"); break;\n\t\tcase FO4VR: gameName.Append(\"Fallout 4 VR\"); break;\n\t\tcase SKYRIMVR: gameName.Append(\"Skyrim VR\"); break;\n\t\tcase FO76: gameName.Append(\"Fallout 76\"); break;\n\t\tcase OB: gameName.Append(\"Oblivion\"); break;\n\t\tcase SF: gameName.Append(\"Starfield\"); break;\n\t\tdefault: gameName.Append(\"Invalid\");\n\t}\n\twxLogMessage(gameName);\n\n\t// Handle preview mode - open nif files directly without main frame\n\tif (cmdPreviewMode && !cmdPreviewNifs.empty()) {\n\t\twxLogMessage(\"BodySlide preview mode initialized.\");\n\t\tShowPreview();\n\t\tif (preview) {\n\t\t\tpreview->SetReadOnlyMode(true);\n\t\t\tLoadPreviewNifs(cmdPreviewNifs);\n\t\t}\n\t\treturn true;\n\t}\n\n\tint x = BodySlideConfig.GetIntValue(\"BodySlideFrame.x\");\n\tint y = BodySlideConfig.GetIntValue(\"BodySlideFrame.y\");\n\tint w = BodySlideConfig.GetIntValue(\"BodySlideFrame.width\");\n\tint h = BodySlideConfig.GetIntValue(\"BodySlideFrame.height\");\n\tstd::string maximized = BodySlideConfig[\"BodySlideFrame.maximized\"];\n\n\twxLogMessage(\"Loading BodySlide frame at X:%d Y:%d with W:%d H:%d...\", x, y, w, h);\n\tsliderView = new BodySlideFrame(this, wxSize(w, h));\n\tsliderView->SetPosition(wxPoint(x, y));\n\tif (maximized == \"true\")\n\t\tsliderView->Maximize();\n\n\t// Set preview pointer to the embedded panel before any data loading\n\tInitPreviewPanel();\n\n\tsliderView->Show();\n\tSetTopWindow(sliderView);\n\n\tif (!GetOutputDataPath().empty()) {\n\t\tbool dirWritable = wxFileName::IsDirWritable(GetOutputDataPath());\n\t\tbool dirReadable = wxFileName::IsDirReadable(GetOutputDataPath());\n\t\tif (!dirWritable || !dirReadable)\n\t\t\twxMessageBox(\n\t\t\t\t_(\"No read/write permission for game data path!\\n\\nPlease launch the program with admin elevation and make sure the game data path in the settings is correct.\"),\n\t\t\t\t_(\"Warning\"),\n\t\t\t\twxICON_WARNING);\n\t}\n\n\tif (!Config[\"ProjectPath\"].empty()) {\n\t\tbool dirWritable = wxFileName::IsDirWritable(Config[\"ProjectPath\"]);\n\t\tbool dirReadable = wxFileName::IsDirReadable(Config[\"ProjectPath\"]);\n\t\tif (!dirWritable || !dirReadable)\n\t\t\twxMessageBox(\n\t\t\t\t_(\"No read/write permission for project path!\\n\\nPlease launch the program with admin elevation and make sure the project path in the settings is correct.\"),\n\t\t\t\t_(\"Warning\"),\n\t\t\t\twxICON_WARNING);\n\t}\n\n\tLoadAllCategories();\n\tLoadAllGroups();\n\tLoadSliderSets();\n\n\tif (cmdGroupBuild.empty()) {\n\t\tsliderView->delayLoad.Start(100, true);\n\t\twxLogMessage(\"BodySlide initialized.\");\n\t}\n\telse {\n\t\twxLogMessage(\"BodySlide initialized.\");\n\t\tGroupBuild(cmdGroupBuild);\n\t}\n\n\treturn true;\n}\n\nvoid BodySlideApp::OnInitCmdLine(wxCmdLineParser& parser) {\n\tparser.SetDesc(g_cmdLineDesc);\n}\n\nbool BodySlideApp::OnCmdLineParsed(wxCmdLineParser& parser) {\n\twxString gbuild;\n\tparser.Found(\"gbuild\", &gbuild);\n\n\twxStringTokenizer tokenizer(gbuild, \",\");\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString token = tokenizer.GetNextToken().Trim();\n\t\tif (!token.IsEmpty()) {\n\t\t\tstd::string groupName = token.ToUTF8().data();\n\t\t\tcmdGroupBuild.push_back(groupName);\n\t\t}\n\t}\n\n\twxString targetDir;\n\tparser.Found(\"t\", &targetDir);\n\n\tif (!targetDir.IsEmpty() && !targetDir.EndsWith(PathSepChar))\n\t\ttargetDir.Append(PathSepChar);\n\n\tcmdTargetDir = targetDir.ToUTF8().data();\n\n\twxString preset;\n\tparser.Found(\"p\", &preset);\n\tcmdPreset = preset.ToUTF8().data();\n\n\tcmdTri = parser.Found(\"tri\");\n\n\twxString previewFiles;\n\tif (parser.Found(\"preview\", &previewFiles)) {\n\t\tcmdPreviewMode = true;\n\t\twxStringTokenizer previewTokenizer(previewFiles, \",;|\");\n\t\twhile (previewTokenizer.HasMoreTokens()) {\n\t\t\twxString token = previewTokenizer.GetNextToken().Trim();\n\t\t\tif (!token.IsEmpty()) {\n\t\t\t\tstd::string filePath = token.ToUTF8().data();\n\t\t\t\tcmdPreviewNifs.push_back(filePath);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn true;\n}\n\nbool BodySlideApp::OnExceptionInMainLoop() {\n\twxString error;\n\ttry {\n\t\tthrow;\n\t}\n\tcatch (const std::exception& e) {\n\t\terror = e.what();\n\t}\n\tcatch (...) {\n\t\terror = \"unknown error\";\n\t}\n\n\tif (sliderView)\n\t\tsliderView->delayLoad.Stop();\n\n\twxLog::FlushActive();\n\tlogger.SetFormatter(false);\n\n\twxLogError(\"Unexpected exception has occurred: %s, the program will terminate.\", error);\n\twxMessageBox(wxString::Format(_(\"Unexpected exception has occurred: %s, the program will terminate.\"), error), _(\"Unexpected exception\"), wxICON_ERROR);\n\treturn false;\n}\n\nvoid BodySlideApp::OnUnhandledException() {\n\twxString error;\n\ttry {\n\t\tthrow;\n\t}\n\tcatch (const std::exception& e) {\n\t\terror = e.what();\n\t}\n\tcatch (...) {\n\t\terror = \"unknown error\";\n\t}\n\n\tif (sliderView)\n\t\tsliderView->delayLoad.Stop();\n\n\twxLog::FlushActive();\n\tlogger.SetFormatter(false);\n\n\twxLogError(\"Unhandled exception has occurred: %s, the program will terminate.\", error);\n\twxMessageBox(wxString::Format(_(\"Unhandled exception has occurred: %s, the program will terminate.\"), error), _(\"Unhandled exception\"), wxICON_ERROR);\n}\n\nvoid BodySlideApp::OnFatalException() {\n\tif (sliderView)\n\t\tsliderView->delayLoad.Stop();\n\n\twxLog::FlushActive();\n\tlogger.SetFormatter(false);\n\n\twxLogError(\"Fatal exception has occurred, the program will terminate.\");\n\twxMessageBox(_(\"Fatal exception has occurred, the program will terminate.\"), _(\"Fatal exception\"), wxICON_ERROR);\n\n\twxDebugReport report;\n\treport.AddExceptionContext();\n\treport.Process();\n}\n\n\nvoid BodySlideApp::InitArchives() {\n\t// Auto-detect archives\n\tFSManager::del();\n\n\tstd::vector<std::string> fileList;\n\tGetArchiveFiles(fileList);\n\n\tFSManager::addArchives(fileList);\n}\n\nvoid BodySlideApp::GetArchiveFiles(std::vector<std::string>& outList) {\n\tTargetGame targ = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tstd::string cp = \"GameDataFiles/\" + TargetGames[targ].ToStdString();\n\twxString activatedFiles = Config[cp];\n\n\twxStringTokenizer tokenizer(activatedFiles, \";\");\n\tstd::map<wxString, bool> fsearch;\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString val = tokenizer.GetNextToken().Trim(false);\n\t\tval = val.Trim().MakeLower();\n\t\tfsearch[val] = true;\n\t}\n\n\twxString dataDir = Config[\"GameDataPath\"];\n\twxArrayString files;\n\twxDir::GetAllFiles(dataDir, &files, \"*.ba2\", wxDIR_FILES);\n\twxDir::GetAllFiles(dataDir, &files, \"*.bsa\", wxDIR_FILES);\n\tfor (auto& f : files) {\n\t\tf = f.AfterLast('/').AfterLast('\\\\');\n\t\tif (fsearch.find(f.Lower()) == fsearch.end())\n\t\t\toutList.push_back((dataDir + f).ToUTF8().data());\n\t}\n}\n\nvoid BodySlideApp::LoadData() {\n\tif (!sliderView)\n\t\treturn;\n\n\twxLogMessage(\"Loading initial data...\");\n\tInitArchives();\n\n\tstd::string activeOutfit = BodySlideConfig[\"SelectedOutfit\"];\n\tif (!activeOutfit.empty() && !OutfitExists(activeOutfit)) {\n\t\twxLogMessage(\"Previously selected outfit '%s' no longer exists, clearing.\", activeOutfit);\n\t\tactiveOutfit.clear();\n\t\tBodySlideConfig.SetValue(\"SelectedOutfit\", activeOutfit);\n\t}\n\tif (activeOutfit.empty() && !outfitNameOrder.empty()) {\n\t\tactiveOutfit = outfitNameOrder.front();\n\t\tBodySlideConfig.SetValue(\"SelectedOutfit\", activeOutfit);\n\t}\n\n\tsliderView->Freeze();\n\tsliderView->ClearOutfitList();\n\tsliderView->ClearPresetList();\n\tsliderView->ClearSliderGUI();\n\n\tif (preview)\n\t\tCleanupPreview();\n\n\tif (previewWindow)\n\t\tClosePreview();\n\n\tsliderManager.ClearSliders();\n\tsliderManager.ClearPresets();\n\n\tif (!activeOutfit.empty()) {\n\t\twxLogMessage(\"Setting up set '%s'...\", activeOutfit);\n\n\t\tint error = CreateSetSliders(activeOutfit);\n\t\tif (error)\n\t\t\twxLogError(\"Failed to load set '%s' from slider set list (%d).\", activeOutfit, error);\n\n\t\tSetPresetGroups(activeOutfit);\n\t\tLoadPresets(activeOutfit);\n\n\t\tstd::string activePreset = BodySlideConfig[\"SelectedPreset\"];\n\t\tPopulatePresetList(activePreset);\n\t\tActivatePreset(activePreset);\n\n\t\twxLogMessage(\"Finished setting up '%s'.\", activeOutfit);\n\t}\n\n\tPopulateOutfitList(activeOutfit);\n\n\tsliderView->Thaw();\n\tsliderView->Layout();\n\tif (sliderView->leftPanel)\n\t\tsliderView->leftPanel->Layout();\n\n\t// Trigger initial preview load for embedded panel\n\tif (preview && preview->IsGLInitialized() && !previewWindow && !activeOutfit.empty()) {\n\t\tInitPreview();\n\t}\n}\n\nvoid BodySlideApp::CharHook(wxKeyEvent& event) {\n\twxWindow* w = (wxWindow*)event.GetEventObject();\n\tif (!w) {\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\twxString nm = w->GetName();\n\tint keyCode = event.GetKeyCode();\n\n\tif (event.ControlDown()) {\n\t\tif (event.ShiftDown()) {\n\t\t\tif (keyCode == (int)'A') {\n\t\t\t\tif (sliderView) {\n\t\t\t\t\tif (sliderView->outfitsearch)\n\t\t\t\t\t\tsliderView->outfitsearch->Clear();\n\n\t\t\t\t\tif (sliderView->search)\n\t\t\t\t\t\tsliderView->search->Clear();\n\n\t\t\t\t\tif (sliderView->sliderFilter)\n\t\t\t\t\t\tsliderView->sliderFilter->Clear();\n\n\t\t\t\t\tif (sliderView->presetFilter)\n\t\t\t\t\t\tsliderView->presetFilter->Clear();\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (keyCode == wxKeyCode::WXK_PAGEUP) {\n\t\t\tif (sliderView->outfitChoice) {\n\t\t\t\tint curSel = sliderView->outfitChoice->GetSelection();\n\t\t\t\tif (curSel > 0) {\n\t\t\t\t\tsliderView->outfitChoice->SetSelection(curSel - 1);\n\t\t\t\t\tActivateOutfit(sliderView->outfitChoice->GetStringSelection().ToUTF8().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (keyCode == wxKeyCode::WXK_PAGEDOWN) {\n\t\t\tif (sliderView->outfitChoice) {\n\t\t\t\tint curSel = sliderView->outfitChoice->GetSelection();\n\t\t\t\tint curCount = sliderView->outfitChoice->GetCount();\n\t\t\t\tif (curCount > 0 && curSel < curCount - 1) {\n\t\t\t\t\tsliderView->outfitChoice->Select(curSel + 1);\n\t\t\t\t\tActivateOutfit(sliderView->outfitChoice->GetStringSelection().ToUTF8().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\telse {\n\t\tif (keyCode == wxKeyCode::WXK_F5) {\n\t\t\tif (nm == \"outfitChoice\")\n\t\t\t\tRefreshOutfitList();\n\t\t\treturn;\n\t\t}\n\n\t\tif (keyCode == wxKeyCode::WXK_PAGEUP) {\n\t\t\tif (sliderView->presetChoice) {\n\t\t\t\tint curSel = sliderView->presetChoice->GetSelection();\n\t\t\t\tif (curSel > 0) {\n\t\t\t\t\tsliderView->presetChoice->SetSelection(curSel - 1);\n\t\t\t\t\tActivatePreset(sliderView->presetChoice->GetStringSelection().ToUTF8().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (keyCode == wxKeyCode::WXK_PAGEDOWN) {\n\t\t\tif (sliderView->presetChoice) {\n\t\t\t\tint curSel = sliderView->presetChoice->GetSelection();\n\t\t\t\tint curCount = sliderView->presetChoice->GetCount();\n\t\t\t\tif (curCount > 0 && curSel < curCount - 1) {\n\t\t\t\t\tsliderView->presetChoice->Select(curSel + 1);\n\t\t\t\t\tActivatePreset(sliderView->presetChoice->GetStringSelection().ToUTF8().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n#ifdef _WINDOWS\n\tstd::string stupidkeys = \"0123456789-\";\n\tbool stupidHack = false;\n\tif (event.GetKeyCode() < 256 && stupidkeys.find(event.GetKeyCode()) != std::string::npos)\n\t\tstupidHack = true;\n\n\tif (stupidHack && nm.EndsWith(\"|readout\")) {\n\t\twxTextCtrl* e = (wxTextCtrl*)w;\n\t\tHWND hwndEdit = e->GetHandle();\n\t\t::SendMessage(hwndEdit, WM_CHAR, event.GetKeyCode(), event.GetRawKeyFlags());\n\t}\n\telse\n#endif\n\t{\n\t\tevent.Skip();\n\t}\n}\n\nint BodySlideApp::CreateSetSliders(const std::string& outfit) {\n\twxLogMessage(\"Creating sliders...\");\n\tif (outfitNameSource.find(outfit) == outfitNameSource.end())\n\t\treturn 1;\n\n\tSliderSetFile sliderDoc;\n\tsliderDoc.Open(outfitNameSource[outfit]);\n\tif (!sliderDoc.fail()) {\n\t\tprojects.clear();\n\t\tprojects.push_back(std::make_unique<ProjectData>());\n\t\tauto& activeSet = GetActiveSet();\n\t\tactiveSet.Clear();\n\t\tsliderManager.ClearSliders();\n\t\tif (!sliderDoc.GetSet(outfit, activeSet)) {\n\t\t\tactiveSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\t\t\tsliderManager.AddSlidersInSet(activeSet);\n\t\t\tDisplayActiveSet();\n\t\t}\n\t\telse\n\t\t\treturn 3;\n\t}\n\telse\n\t\treturn 2;\n\n\treturn 0;\n}\n\nint BodySlideApp::AddProjectSliders(const std::string& projectFile, const std::string& setName) {\n\twxLogMessage(\"Adding project sliders from '%s' set '%s'...\", projectFile, setName);\n\n\tif (projects.empty()) {\n\t\t// First project: clear shared data managers\n\t\tsliderManager.ClearSliders();\n\t\tsliderManager.ClearPresets();\n\t\tmultiProjectMode = true;\n\t}\n\n\tauto pp = std::make_unique<ProjectData>();\n\n\tSliderSetFile sliderDoc;\n\tsliderDoc.Open(projectFile);\n\tif (sliderDoc.fail())\n\t\treturn 2;\n\n\tif (sliderDoc.GetSet(setName, pp->sliderSet))\n\t\treturn 3;\n\n\tpp->sliderSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\tpp->setName = setName;\n\n\t// Add sliders from this set (additive)\n\tsliderManager.AddSlidersInSet(pp->sliderSet);\n\n\tprojects.push_back(std::move(pp));\n\treturn 0;\n}\n\nstd::string BodySlideApp::GetOutputDataPath() const {\n\tstd::string res = Config[\"OutputDataPath\"];\n\treturn res.empty() ? Config[\"GameDataPath\"] : res;\n}\n\nstd::string BodySlideApp::GetProjectPath() const {\n\tstd::string res = Config[\"ProjectPath\"];\n\treturn res.empty() ? Config[\"AppDir\"] : res;\n}\n\nvoid BodySlideApp::RefreshOutfitList() {\n\tLoadSliderSets();\n\tPopulateOutfitList(\"\");\n}\n\nint BodySlideApp::LoadSliderSets() {\n\twxLogMessage(\"Loading all slider sets...\");\n\toutfitNameSource.clear();\n\toutfitNameOrder.clear();\n\toutfitHasZaps.clear();\n\toutFileCount.clear();\n\n\twxArrayString files;\n\twxDir::GetAllFiles(wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\", &files, \"*.osp\");\n\twxDir::GetAllFiles(wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\", &files, \"*.xml\");\n\n\tbool filterHasZaps = false;\n\n\tauto menuOutfitSrchContext = sliderView->outfitsearch->GetMenu();\n\tif (menuOutfitSrchContext) {\n\t\tauto menuFilterHasZaps = menuOutfitSrchContext->FindItem(XRCID(\"menuFilterHasZaps\"));\n\t\tif (menuFilterHasZaps)\n\t\t\tfilterHasZaps = menuFilterHasZaps->IsChecked();\n\t}\n\n\tfor (auto& file : files) {\n\t\tstd::string fileName{file.ToUTF8()};\n\n\t\tSliderSetFile sliderDoc;\n\t\tsliderDoc.Open(fileName);\n\t\tif (sliderDoc.fail())\n\t\t\tcontinue;\n\n\t\tstd::string outFilePath;\n\t\tstd::vector<std::string> outfitNames;\n\t\tsliderDoc.GetSetNamesUnsorted(outfitNames, false);\n\t\tfor (auto& o : outfitNames) {\n\t\t\tif (outfitNameSource.find(o) != outfitNameSource.end())\n\t\t\t\tcontinue;\n\n\t\t\toutfitNameSource[o] = fileName;\n\t\t\toutfitNameOrder.push_back(o);\n\n\t\t\tif (filterHasZaps) {\n\t\t\t\tbool hasZaps = false;\n\n\t\t\t\tSliderSet sliderSet;\n\t\t\t\tif (sliderDoc.GetSet(o, sliderSet) == 0) {\n\t\t\t\t\tfor (size_t s = 0; s < sliderSet.size(); s++) {\n\t\t\t\t\t\tauto& slider = sliderSet[s];\n\t\t\t\t\t\tif (slider.bZap && !slider.bHidden) {\n\t\t\t\t\t\t\thasZaps = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (hasZaps)\n\t\t\t\t\toutfitHasZaps.push_back(o);\n\t\t\t}\n\n\t\t\tsliderDoc.GetSetOutputFilePath(o, outFilePath);\n\t\t\tif (!outFilePath.empty())\n\t\t\t\toutFileCount[outFilePath].push_back(o);\n\t\t}\n\t}\n\n\tungroupedOutfits.clear();\n\tfor (auto& o : outfitNameSource) {\n\t\tstd::vector<std::string> groups;\n\t\tgCollection.GetOutfitGroups(o.first, groups);\n\t\tif (groups.empty())\n\t\t\tungroupedOutfits.push_back(o.first);\n\t}\n\n\treturn 0;\n}\n\nvoid BodySlideApp::ActivateOutfit(const std::string& outfitName) {\n\twxLogMessage(\"Activating set '%s'...\", outfitName);\n\n\tBodySlideConfig.SetValue(\"SelectedOutfit\", outfitName);\n\tsliderView->Freeze();\n\n\tsliderView->ClearPresetList();\n\tsliderView->ClearSliderGUI();\n\n\tCleanupPreview();\n\n\tstd::string activePreset = BodySlideConfig[\"SelectedPreset\"];\n\n\tsliderManager.ClearPresets();\n\tSetPresetGroups(outfitName);\n\tLoadPresets(outfitName);\n\tPopulatePresetList(activePreset);\n\n\tint error = CreateSetSliders(outfitName);\n\tif (error)\n\t\twxLogError(\"Failed to load set '%s' from slider set list (%d).\", outfitName, error);\n\n\tPopulateOutfitList(outfitName);\n\n\tActivatePreset(activePreset, false);\n\n\tInitPreview();\n\n\tsliderView->Layout();\n\tsliderView->Refresh();\n\tsliderView->Thaw();\n\twxLogMessage(\"Finished activating set '%s'.\", outfitName);\n}\n\nvoid BodySlideApp::ActivatePreset(const std::string& presetName, const bool updatePreview) {\n\twxLogMessage(\"Applying preset '%s' to sliders.\", presetName);\n\n\tBodySlideConfig.SetValue(\"SelectedPreset\", presetName);\n\tsliderManager.InitializeSliders(presetName);\n\n\tbool zapChanged = false;\n\tSlider* sliderSmall = nullptr;\n\tSlider* sliderBig = nullptr;\n\tfor (size_t i = 0; i < sliderManager.slidersBig.size(); i++) {\n\t\tsliderSmall = &sliderManager.slidersSmall[i];\n\t\tsliderBig = &sliderManager.slidersBig[i];\n\n\t\tif (sliderBig->zap && !sliderBig->uv && !zapChanged) {\n\t\t\tauto* sd = sliderView->GetSliderDisplay(sliderBig->name);\n\t\t\tif (sd) {\n\t\t\t\tfloat zapValueUI = sd->zapCheckHi->IsChecked() ? 0.01f : 0.0f;\n\t\t\t\tif (sliderBig->value != zapValueUI)\n\t\t\t\t\tzapChanged = true;\n\t\t\t}\n\t\t}\n\n\t\tsliderView->SetSliderPosition(sliderSmall->name.c_str(), sliderSmall->value, SLIDER_LO);\n\t\tsliderView->SetSliderPosition(sliderBig->name.c_str(), sliderBig->value, SLIDER_HI);\n\t}\n\n\tsliderView->SetPresetChanged(false);\n\n\tif (UpdateZapChoices())\n\t\tzapChanged = true;\n\n\tif (preview && updatePreview)\n\t\tzapChanged ? RebuildPreviewMeshes() : UpdatePreview();\n}\n\nvoid BodySlideApp::DeleteOutfit(const std::string& outfitName) {\n\tauto outfit = outfitNameSource.find(outfitName);\n\tif (outfit == outfitNameSource.end())\n\t\treturn;\n\n\tint select = wxNOT_FOUND;\n\tif (sliderView->outfitChoice)\n\t\tselect = sliderView->outfitChoice->GetSelection();\n\n\twxLogMessage(\"Loading project file '%s'...\", outfit->second);\n\n\tSliderSetFile sliderDoc;\n\tsliderDoc.Open(outfit->second);\n\tif (!sliderDoc.fail()) {\n\t\twxLogMessage(\"Deleting project '%s'...\", outfitName);\n\n\t\tif (!sliderDoc.DeleteSet(outfit->first)) {\n\t\t\tif (sliderDoc.Save()) {\n\t\t\t\tRefreshOutfitList();\n\n\t\t\t\tif (sliderView->outfitChoice) {\n\t\t\t\t\tint count = sliderView->outfitChoice->GetCount();\n\t\t\t\t\tif (count > select)\n\t\t\t\t\t\tsliderView->outfitChoice->Select(select);\n\t\t\t\t\telse if (count > select - 1)\n\t\t\t\t\t\tsliderView->outfitChoice->Select(select - 1);\n\n\t\t\t\t\tActivateOutfit(sliderView->outfitChoice->GetStringSelection().ToUTF8().data());\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\twxLogMessage(\"Failed to delete the slider set!\");\n\t\t}\n\t\telse\n\t\t\twxLogMessage(\"Failed to delete the slider set!\");\n\t}\n\telse\n\t\twxLogMessage(\"Failed to load the project file!\");\n}\n\nvoid BodySlideApp::DeletePreset(const std::string& presetName) {\n\tstd::string outputFile = sliderManager.GetPresetFileNames(presetName);\n\tif (outputFile.empty())\n\t\treturn;\n\n\tint select = wxNOT_FOUND;\n\tif (sliderView->presetChoice)\n\t\tselect = sliderView->presetChoice->GetSelection();\n\n\twxLogMessage(\"Deleting preset '%s'...\", presetName);\n\tif (!sliderManager.DeletePreset(outputFile, presetName)) {\n\t\tLoadPresets(\"\");\n\t\tPopulatePresetList(presetName);\n\n\t\tif (sliderView->presetChoice) {\n\t\t\tint count = sliderView->presetChoice->GetCount();\n\t\t\tif (count > select)\n\t\t\t\tsliderView->presetChoice->Select(select);\n\t\t\telse if (count > select - 1)\n\t\t\t\tsliderView->presetChoice->Select(select - 1);\n\n\t\t\tActivatePreset(sliderView->presetChoice->GetStringSelection().ToUTF8().data());\n\t\t}\n\t}\n\telse\n\t\twxLogMessage(\"Failed to delete preset!\");\n}\n\nvoid BodySlideApp::RefreshSliders() {\n\tSlider* slider = nullptr;\n\tfor (size_t i = 0; i < sliderManager.slidersBig.size(); i++) {\n\t\tslider = &sliderManager.slidersBig[i];\n\t\tsliderView->SetSliderPosition(slider->name.c_str(), slider->value, SLIDER_HI);\n\n\t\tslider = &sliderManager.slidersSmall[i];\n\t\tsliderView->SetSliderPosition(slider->name.c_str(), slider->value, SLIDER_LO);\n\t}\n\n\tif (preview)\n\t\tUpdatePreview();\n}\n\nvoid BodySlideApp::PopulatePresetList(const std::string& select) {\n\tstd::string myselect = BodySlideConfig[\"SelectedPreset\"];\n\tif (!select.empty())\n\t\tmyselect = select;\n\n\tstd::vector<std::string> presets;\n\n\twxArrayString items;\n\tsliderManager.GetPresetNames(presets);\n\n\tstd::vector<std::string> filteredPresets = ApplyPresetFilter(presets);\n\titems.reserve(filteredPresets.size());\n\tfor (size_t i = 0; i < filteredPresets.size(); i++)\n\t\titems.Add(wxString::FromUTF8(filteredPresets[i]));\n\n\tsliderView->PopulatePresetList(items, wxString::FromUTF8(myselect));\n}\n\nvoid BodySlideApp::PopulateOutfitList(const std::string& select) {\n\tstd::string myselect = BodySlideConfig[\"SelectedOutfit\"];\n\tif (!select.empty())\n\t\tmyselect = select;\n\n\twxArrayString items;\n\n\tsize_t n = outfitNameSource.size();\n\tif (n == 0)\n\t\treturn;\n\n\tApplyOutfitFilter();\n\n\titems.reserve(filteredOutfits.size());\n\tfor (auto& fo : filteredOutfits)\n\t\titems.Add(wxString::FromUTF8(fo));\n\n\tsliderView->PopulateOutfitList(items, wxString::FromUTF8(myselect));\n}\n\nvoid BodySlideApp::DisplayActiveSet() {\n\tif (projects.empty())\n\t\treturn;\n\n\tauto& activeSet = GetActiveSet();\n\tif (activeSet.GenWeights())\n\t\tsliderView->ShowLowColumn(true);\n\telse\n\t\tsliderView->ShowLowColumn(false);\n\n\t// Category name, slider names, hidden flag\n\tstd::vector<std::tuple<std::string, std::vector<std::string>, bool>> sliderCategories;\n\tstd::vector<std::string> cats;\n\tcCollection.GetAllCategories(cats);\n\n\t// Populate category data\n\tfor (auto& cat : cats) {\n\t\tstd::vector<std::string> catSliders;\n\t\tcCollection.GetCategorySliders(cat, catSliders);\n\n\t\tif (catSliders.size() > 0) {\n\t\t\tbool catHidden = cCollection.GetCategoryHidden(cat);\n\t\t\tsliderCategories.push_back(make_tuple(cat, catSliders, !catHidden));\n\t\t}\n\t\telse\n\t\t\tcontinue;\n\t}\n\n\t// Loop slider set\n\tstd::vector<std::vector<int>> catSliders;\n\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\tif (activeSet[i].bHidden)\n\t\t\tcontinue;\n\n\t\t// Find the category in the list\n\t\tbool regularSlider = true;\n\t\tint iter = 0;\n\t\tfor (auto& cat : sliderCategories) {\n\t\t\tcatSliders.push_back(std::vector<int>());\n\t\t\tif (std::find(std::get<1>(cat).begin(), std::get<1>(cat).end(), activeSet[i].name) != std::get<1>(cat).end()) {\n\t\t\t\tcatSliders[iter].push_back(i);\n\t\t\t\tregularSlider = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\titer++;\n\t\t}\n\n\t\t// Not in a category\n\t\tif (regularSlider)\n\t\t\tsliderView->AddSliderGUI(activeSet[i].name, activeSet[i].name, \"\", activeSet[i].bZap, !activeSet.GenWeights());\n\t}\n\n\t// Create category UI\n\tsize_t iter = 0;\n\tif (catSliders.size() > 0) {\n\t\tfor (auto& cat : sliderCategories) {\n\t\t\tstd::string categoryName = std::get<0>(cat);\n\t\t\tstd::vector<std::string> sliderNames = std::get<1>(cat);\n\t\t\tbool show = std::get<2>(cat);\n\t\t\tstd::string displayName;\n\n\t\t\tif (catSliders.size() > iter && catSliders[iter].size() > 0) {\n\t\t\t\tsliderView->AddCategorySliderUI(categoryName, sliderNames, show, !activeSet.GenWeights());\n\n\t\t\t\tfor (auto& s : catSliders[iter]) {\n\t\t\t\t\tdisplayName = cCollection.GetSliderDisplayName(categoryName, activeSet[s].name);\n\t\t\t\t\tif (displayName.empty())\n\t\t\t\t\t\tdisplayName = activeSet[s].name;\n\n\t\t\t\t\tsliderView->AddSliderGUI(activeSet[s].name, displayName, categoryName, activeSet[s].bZap, !activeSet.GenWeights());\n\t\t\t\t}\n\t\t\t}\n\t\t\titer++;\n\t\t}\n\t}\n\n\tsliderView->DoFilterSliders();\n\tUpdateConflictManager();\n}\n\nvoid BodySlideApp::GetBuildSelection(BuildSelectionFile& file, BuildSelection& buildSel) {\n\tconst std::string buildSelFileName = Config[\"AppDir\"] + PathSepStr + \"BuildSelection.xml\";\n\n\tfile.Open(buildSelFileName);\n\n\tif (file.GetError())\n\t\tfile.New(buildSelFileName);\n\n\tfile.Get(buildSel);\n}\n\nvoid BodySlideApp::UpdateConflictManager() {\n\tif (projects.empty())\n\t\treturn;\n\n\t// Populate Conflict UI\n\tauto& activeSet = GetActiveSet();\n\tauto conflictCheckBox = (wxCheckBox*)sliderView->FindWindowByName(\"cbIsOutfitChoice\");\n\tauto conflictLabel = (wxStaticText*)sliderView->FindWindowByName(\"conflictLabel\");\n\tauto conflictInfo = (wxStaticText*)sliderView->FindWindowByName(\"conflictInfo\");\n\n\tauto outputFilePath = activeSet.GetOutputFilePath();\n\tauto& col = outFileCount[outputFilePath];\n\n\tbool isOutputChoice = true;\n\tstd::string textColourName = \"#C8C8C8\";\n\n\tif (1 < col.size()) {\n\t\tBuildSelectionFile buildSelFile;\n\t\tBuildSelection buildSelection;\n\t\tGetBuildSelection(buildSelFile, buildSelection);\n\n\t\tstd::string outputChoice = buildSelection.GetOutputChoice(outputFilePath);\n\t\tisOutputChoice = outputChoice == activeSet.GetName();\n\t\ttextColourName = isOutputChoice ? \"#00FFFF\" : \"#FFD769\";\n\t}\n\n\tconflictCheckBox->SetValue(isOutputChoice);\n\tconflictCheckBox->Show();\n\n\tif (activeSet.GenWeights())\n\t\tconflictLabel->SetLabel(wxString::FromUTF8(outputFilePath) + \"_0.nif (and _1.nif)\");\n\telse\n\t\tconflictLabel->SetLabel(wxString::FromUTF8(outputFilePath) + \".nif\");\n\n\tconflictLabel->SetForegroundColour(wxColour(textColourName));\n\tconflictLabel->Show();\n\n\tif (1 < col.size())\n\t\tconflictInfo->Show();\n\telse\n\t\tconflictInfo->Hide();\n}\n\nvoid BodySlideApp::SetDefaultBuildSelection() {\n\tif (projects.empty())\n\t\treturn;\n\n\tauto& activeSet = GetActiveSet();\n\tBuildSelectionFile buildSelFile;\n\tBuildSelection buildSelection;\n\tGetBuildSelection(buildSelFile, buildSelection);\n\n\tauto outputFilePath = activeSet.GetOutputFilePath();\n\tstd::string choiceName = activeSet.GetName();\n\n\tbool willSet = 0 != choiceName.compare(buildSelection.GetOutputChoice(outputFilePath));\n\tif (willSet) {\n\t\tbuildSelection.SetOutputChoice(outputFilePath, activeSet.GetName());\n\t\tbuildSelFile.UpdateOutputChoices(buildSelection);\n\t}\n\telse {\n\t\tbuildSelection.SetOutputChoice(outputFilePath, \"\");\n\t\tbuildSelFile.RemoveOutputChoice(outputFilePath);\n\t}\n\n\tbuildSelFile.Save();\n\n\tUpdateConflictManager();\n\tsliderView->Refresh();\n}\n\nbool BodySlideApp::UpdateZapChoices() {\n\tif (projects.empty())\n\t\treturn false;\n\n\tauto& activeSet = GetActiveSet();\n\tBuildSelectionFile buildSelFile;\n\tBuildSelection buildSelection;\n\tGetBuildSelection(buildSelFile, buildSelection);\n\n\tbool zapChanged = false;\n\n\tfor (size_t s = 0; s < activeSet.size(); s++) {\n\t\tif (!activeSet[s].bZap || activeSet[s].bHidden)\n\t\t\tcontinue;\n\n\t\tstd::string project = activeSet.GetName();\n\t\tstd::string zap = activeSet[s].name;\n\t\tif (buildSelection.HasZapChoice(project, zap)) {\n\t\t\tbool zapChoice = buildSelection.GetZapChoice(project, zap);\n\n\t\t\tSliderDisplay* sd = sliderView->GetSliderDisplay(zap);\n\t\t\tif (sd && sd->isZap) {\n\t\t\t\tif (sd->zapCheckHi->IsChecked() != zapChoice) {\n\t\t\t\t\tsd->zapCheckHi->SetValue(zapChoice);\n\n\t\t\t\t\t// Trigger checkbox event\n\t\t\t\t\twxEvtHandler* handler = sd->zapCheckHi->GetEventHandler();\n\t\t\t\t\twxCommandEvent event(wxEVT_COMMAND_CHECKBOX_CLICKED, sd->zapCheckHi->GetId());\n\t\t\t\t\tevent.SetEventObject(sd->zapCheckHi);\n\t\t\t\t\tevent.SetInt(zapChoice ? 1 : 0);\n\t\t\t\t\thandler->ProcessEvent(event);\n\n\t\t\t\t\tzapChanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn zapChanged;\n}\n\nvoid BodySlideApp::SetZapChoice(const std::string& zap, bool choice) {\n\tif (projects.empty())\n\t\treturn;\n\n\tBuildSelectionFile buildSelFile;\n\tBuildSelection buildSelection;\n\tGetBuildSelection(buildSelFile, buildSelection);\n\n\tstd::string project = GetActiveSet().GetName();\n\n\tbuildSelection.SetZapChoice(project, zap, choice);\n\tbuildSelFile.UpdateZapChoices(buildSelection);\n\n\tbuildSelFile.Save();\n}\n\nvoid BodySlideApp::EditProject(const std::string& projectName) {\n\tauto project = outfitNameSource.find(projectName);\n\tif (project == outfitNameSource.end())\n\t\treturn;\n\n\twxLogMessage(\"Launching Outfit Studio with project file '%s' and project '%s'...\", project->second, project->first);\n\tLaunchOutfitStudio(wxString::Format(\"-proj \\\"%s\\\" \\\"%s\\\"\", wxString::FromUTF8(project->first), wxString::FromUTF8(project->second)));\n}\n\nvoid BodySlideApp::LaunchOutfitStudio(const wxString& args) {\n#ifdef WIN64\n\tconst wxString osExec = \"OutfitStudio x64.exe\";\n#elif _WIN32\n\tconst wxString osExec = \"OutfitStudio.exe\";\n#else\n\tconst wxString osExec = \"OutfitStudio\";\n#endif\n\n\twxString osExecCmd = wxString::Format(\"\\\"%s\\\\%s\\\" %s\", wxString::FromUTF8(Config[\"AppDir\"]), osExec, args);\n\n\tif (!wxExecute(osExecCmd, wxEXEC_ASYNC)) {\n\t\twxLogError(\"Failed to execute '%s' process.\", osExecCmd);\n\t\twxMessageBox(_(\"Failed to launch Outfit Studio executable!\"), _(\"Error\"), wxICON_ERROR);\n\t}\n}\n\nvoid BodySlideApp::ApplySliders(\n\tconst std::string& targetShape, std::vector<Slider>& sliderSet, DiffDataSets& dataSets, std::vector<Vector3>& verts, std::vector<uint16_t>& ZapIdx, std::vector<Vector2>* uvs) {\n\tfor (auto& slider : sliderSet) {\n\t\tfloat val = slider.value;\n\t\tif (slider.zap && !slider.uv) {\n\t\t\tif (val > 0)\n\t\t\t\tfor (size_t j = 0; j < slider.linkedDataSets.size(); j++)\n\t\t\t\t\tdataSets.GetDiffIndices(slider.linkedDataSets[j], targetShape, ZapIdx);\n\t\t}\n\t\telse {\n\t\t\tif (slider.invert)\n\t\t\t\tval = 1.0f - val;\n\n\t\t\tfor (size_t j = 0; j < slider.linkedDataSets.size(); j++) {\n\t\t\t\tif (slider.uv) {\n\t\t\t\t\tif (uvs)\n\t\t\t\t\t\tdataSets.ApplyUVDiff(slider.linkedDataSets[j], targetShape, val, uvs);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tdataSets.ApplyDiff(slider.linkedDataSets[j], targetShape, val, &verts);\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (auto& slider : sliderSet)\n\t\tif (slider.clamp && slider.value > 0)\n\t\t\tfor (size_t j = 0; j < slider.linkedDataSets.size(); j++)\n\t\t\t\tdataSets.ApplyClamp(slider.linkedDataSets[j], targetShape, &verts);\n}\n\nstruct ContinuousRange {\n\tuint16_t index = 0;\n\tsize_t length = 0;\n};\n\nstatic std::vector<ContinuousRange> FindContinuousRanges(const std::vector<uint16_t>& source) {\n\tstd::vector<ContinuousRange> ranges;\n\tif (source.size() == 0) {\n\t\treturn ranges;\n\t}\n\n\tsize_t startIndex = 0;\n\tsize_t endIndex = 1;\n\tint lastValue = (int)source[0]; // Cast to int to avoid potential uint16_t overflow in comparison below\n\n\tfor (; endIndex < source.size(); ++endIndex) {\n\t\tint value = (int)source[endIndex];\n\t\tif (value != lastValue + 1) {\n\t\t\tranges.emplace_back(ContinuousRange{ source[startIndex], endIndex - startIndex });\n\t\t\tstartIndex = endIndex;\n\t\t}\n\t\tlastValue = value;\n\t}\n\n\tranges.emplace_back(ContinuousRange{ source[startIndex], endIndex - startIndex });\n\n\treturn ranges;\n}\n\nbool BodySlideApp::WriteMorphTRI(const std::string& triPath, SliderSet& sliderSet, NifFile& nif, std::unordered_map<std::string, std::vector<uint16_t>>& zapIndices) {\n\tDiffDataSets currentDiffs;\n\tsliderSet.LoadSetDiffData(currentDiffs);\n\n\tTriFile tri;\n\tstd::string triFilePath = triPath + \".tri\";\n\n\tfor (auto targetShape = sliderSet.ShapesBegin(); targetShape != sliderSet.ShapesEnd(); ++targetShape) {\n\t\tauto shape = nif.FindBlockByName<NiShape>(targetShape->first);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\tconst std::vector<uint16_t>& shapeZapIndices = zapIndices[targetShape->first];\n\n\t\tint shapeVertCount = shape->GetNumVertices();\n\t\tshapeVertCount += shapeZapIndices.size();\n\n\t\tif (shapeVertCount <= 0)\n\t\t\tcontinue;\n\n\t\tif (shapeZapIndices.size() > 0 && shapeZapIndices.back() >= shapeVertCount)\n\t\t\tcontinue;\n\n\t\tauto zapRanges = FindContinuousRanges(shapeZapIndices);\n\n\t\tfor (size_t s = 0; s < sliderSet.size(); s++) {\n\t\t\tstd::string dn = sliderSet[s].TargetDataName(targetShape->second.targetShape);\n\t\t\tstd::string target = targetShape->second.targetShape;\n\t\t\tif (dn.empty())\n\t\t\t\tcontinue;\n\n\t\t\tif (!sliderSet[s].bClamp && !sliderSet[s].bZap) {\n\t\t\t\tMorphDataPtr morph = std::make_shared<MorphData>();\n\t\t\t\tmorph->name = sliderSet[s].name;\n\n\t\t\t\tif (sliderSet[s].bUV) {\n\t\t\t\t\tmorph->type = MORPHTYPE_UV;\n\n\t\t\t\t\tstd::vector<Vector2> uvs;\n\t\t\t\t\tuvs.resize(shapeVertCount);\n\n\t\t\t\t\tcurrentDiffs.ApplyUVDiff(dn, target, 1.0f, &uvs);\n\n\t\t\t\t\tfor (auto range = zapRanges.rbegin(); range != zapRanges.rend(); ++range) {\n\t\t\t\t\t\tconst auto start = uvs.cbegin() + range->index;\n\t\t\t\t\t\tuvs.erase(start, start + range->length);\n\t\t\t\t\t}\n\n\t\t\t\t\tint i = 0;\n\t\t\t\t\tfor (auto& uv : uvs) {\n\t\t\t\t\t\tVector3 v(uv.u, uv.v, 0.0f);\n\t\t\t\t\t\tif (!v.IsZero(true))\n\t\t\t\t\t\t\tmorph->offsets.emplace(i, v);\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tmorph->type = MORPHTYPE_POSITION;\n\n\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\tverts.resize(shapeVertCount);\n\n\t\t\t\t\tcurrentDiffs.ApplyDiff(dn, target, 1.0f, &verts);\n\n\t\t\t\t\tfor (auto range = zapRanges.rbegin(); range != zapRanges.rend(); ++range) {\n\t\t\t\t\t\tconst auto start = verts.cbegin() + range->index;\n\t\t\t\t\t\tverts.erase(start, start + range->length);\n\t\t\t\t\t}\n\n\t\t\t\t\tint i = 0;\n\t\t\t\t\tfor (auto& v : verts) {\n\t\t\t\t\t\tif (!v.IsZero(true))\n\t\t\t\t\t\t\tmorph->offsets.emplace(i, v);\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (morph->offsets.size() > 0)\n\t\t\t\t\ttri.AddMorph(targetShape->first, morph);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!tri.Write(triFilePath))\n\t\treturn false;\n\n\treturn true;\n}\n\nvoid BodySlideApp::CopySliderValues(bool toHigh) {\n\twxLogMessage(\"Copying slider values to %s weight.\", toHigh ? \"high\" : \"low\");\n\n\tif (toHigh) {\n\t\tfor (size_t i = 0; i < sliderManager.slidersSmall.size(); i++) {\n\t\t\tSlider* slider = &sliderManager.slidersSmall[i];\n\t\t\tif (slider->zap || slider->clamp)\n\t\t\t\tcontinue;\n\n\t\t\tif (sliderView->GetSliderDisplay(slider->name)) {\n\t\t\t\tsliderView->SetSliderPosition(slider->name.c_str(), slider->value, SLIDER_HI);\n\t\t\t\tSetSliderValue(slider->name, false, slider->value);\n\t\t\t\tSetSliderChanged(slider->name, false);\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor (size_t i = 0; i < sliderManager.slidersBig.size(); i++) {\n\t\t\tSlider* slider = &sliderManager.slidersBig[i];\n\t\t\tif (slider->zap || slider->clamp)\n\t\t\t\tcontinue;\n\n\t\t\tif (sliderView->GetSliderDisplay(slider->name)) {\n\t\t\t\tsliderView->SetSliderPosition(slider->name.c_str(), slider->value, SLIDER_LO);\n\t\t\t\tSetSliderValue(slider->name, true, slider->value);\n\t\t\t\tSetSliderChanged(slider->name, true);\n\t\t\t}\n\t\t}\n\t}\n\n\tsliderView->SetPresetChanged();\n\n\tif (preview)\n\t\tUpdatePreview();\n}\n\nvoid BodySlideApp::CopyPreviewWeightToSliders() {\n\tif (!preview || !sliderView)\n\t\treturn;\n\n\tint weight = preview->GetWeight();\n\twxLogMessage(\"Copying preview shape at weight %d to both high and low sliders.\", weight);\n\n\tfor (size_t i = 0; i < sliderManager.slidersBig.size(); i++) {\n\t\tSlider* sliderBig = &sliderManager.slidersBig[i];\n\t\tSlider* sliderSmall = &sliderManager.slidersSmall[i];\n\n\t\tif (sliderBig->zap || sliderBig->clamp)\n\t\t\tcontinue;\n\n\t\t// Calculate the interpolated slider value at the current weight\n\t\tfloat effectiveValue = (sliderBig->value * weight + sliderSmall->value * (100.0f - weight)) / 100.0f;\n\n\t\tif (sliderView->GetSliderDisplay(sliderBig->name)) {\n\t\t\tsliderView->SetSliderPosition(sliderBig->name.c_str(), effectiveValue, SLIDER_HI);\n\t\t\tSetSliderValue(sliderBig->name, false, effectiveValue);\n\t\t\tSetSliderChanged(sliderBig->name, false);\n\n\t\t\tsliderView->SetSliderPosition(sliderSmall->name.c_str(), effectiveValue, SLIDER_LO);\n\t\t\tSetSliderValue(sliderSmall->name, true, effectiveValue);\n\t\t\tSetSliderChanged(sliderSmall->name, true);\n\t\t}\n\t}\n\n\tsliderView->SetPresetChanged();\n\tUpdatePreview();\n}\n\nvoid BodySlideApp::ShowPreview() {\n\t// For standalone mode (cmd preview, or when no main frame exists)\n\tif (preview)\n\t\treturn;\n\n\tint x = BodySlideConfig.GetIntValue(\"PreviewFrame.x\");\n\tint y = BodySlideConfig.GetIntValue(\"PreviewFrame.y\");\n\tint w = BodySlideConfig.GetIntValue(\"PreviewFrame.width\");\n\tint h = BodySlideConfig.GetIntValue(\"PreviewFrame.height\");\n\tstd::string maximized = BodySlideConfig[\"PreviewFrame.maximized\"];\n\n\tpreviewWindow = new PreviewWindow(wxPoint(x, y), wxSize(w, h), this);\n\tif (maximized == \"true\")\n\t\tpreviewWindow->Maximize();\n\n\tpreview = previewWindow->GetPanel();\n\n\t// Set base data path for texture loading\n\tstd::string baseGamePath = Config[\"GameDataPath\"];\n\tpreview->SetBaseDataPath(baseGamePath);\n}\n\nvoid BodySlideApp::InitPreviewPanel() {\n\t// Set up the embedded preview panel in the main frame\n\tif (sliderView && sliderView->previewPanel) {\n\t\tpreview = sliderView->previewPanel;\n\t\tstd::string baseGamePath = Config[\"GameDataPath\"];\n\t\tpreview->SetBaseDataPath(baseGamePath);\n\t}\n}\n\nvoid BodySlideApp::ClosePreview() {\n\tif (previewWindow) {\n\t\tpreviewWindow->Close();\n\t\t// PreviewClosed() will be called from OnClose\n\t}\n}\n\nvoid BodySlideApp::PreviewClosed() {\n\t// Called when the standalone preview window is closed\n\tpreviewWindow = nullptr;\n\t// If the main frame has an embedded panel, keep using it\n\tif (sliderView && sliderView->previewPanel) {\n\t\tpreview = sliderView->previewPanel;\n\t}\n\telse {\n\t\tpreview = nullptr;\n\t}\n}\n\nvoid BodySlideApp::PopOutPreview() {\n\tif (!sliderView || !sliderView->previewPanel || previewWindow)\n\t\treturn;\n\n\tPreviewPanel* panel = sliderView->previewPanel;\n\n\tint x = BodySlideConfig.GetIntValue(\"PreviewFrame.x\");\n\tint y = BodySlideConfig.GetIntValue(\"PreviewFrame.y\");\n\tint w = BodySlideConfig.GetIntValue(\"PreviewFrame.width\");\n\tint h = BodySlideConfig.GetIntValue(\"PreviewFrame.height\");\n\tstd::string maximized = BodySlideConfig[\"PreviewFrame.maximized\"];\n\n\t// Unsplit: remove panel from splitter and shrink the main frame\n\tsliderView->UnsplitPreview();\n\n\t// Reparent into standalone window\n\tpreviewWindow = new PreviewWindow(wxPoint(x, y), wxSize(w, h), this, panel);\n\tif (maximized == \"true\")\n\t\tpreviewWindow->Maximize();\n\n\tpreview = panel;\n\tpanel->ShowPopoutButton(false);\n\n\tsliderView->previewVisible = false;\n\tsliderView->UpdatePreviewButtonLabel();\n}\n\nvoid BodySlideApp::DockPreview() {\n\tif (!previewWindow || !sliderView)\n\t\treturn;\n\n\tPreviewPanel* panel = previewWindow->ReleasePanel();\n\tif (!panel)\n\t\treturn;\n\n\t// Reparent back into splitter\n\tpanel->Reparent(sliderView->splitter);\n\tsliderView->previewPanel = panel;\n\tpreview = panel;\n\n\tsliderView->SplitPreview(panel);\n\tsliderView->previewVisible = true;\n\tsliderView->UpdatePreviewButtonLabel();\n\tpanel->ShowPopoutButton(true);\n\tpanel->Layout();\n\n\tpreviewWindow->Destroy();\n\tpreviewWindow = nullptr;\n}\n\nvoid BodySlideApp::InitPreview() {\n\tif (!preview)\n\t\treturn;\n\n\tif (projects.empty())\n\t\treturn;\n\n\t// Cancel any in-flight load\n\tuint64_t gen = ++previewLoadGeneration;\n\n\tif (previewLoadThread.joinable())\n\t\tpreviewLoadThread.join();\n\n\tpreview->ShowLoadingIndicator(true);\n\tpreviewLoading = true;\n\n\t// Capture per-project info for the background thread\n\tstruct ProjectInfo {\n\t\tsize_t index;\n\t\tstd::string inputFileName;\n\t\tstd::string setName;\n\t\tSliderSet sliderSetCopy;\n\t\tbool needsReload;\n\t};\n\n\tauto projectInfos = std::make_shared<std::vector<ProjectInfo>>();\n\tfor (size_t i = 0; i < projects.size(); ++i) {\n\t\tauto& pp = projects[i];\n\t\tProjectInfo info;\n\t\tinfo.index = i;\n\t\tinfo.inputFileName = pp->sliderSet.GetInputFileName();\n\t\tinfo.setName = pp->sliderSet.GetName();\n\t\tinfo.sliderSetCopy = pp->sliderSet;\n\n\t\tif (multiProjectMode) {\n\t\t\t// Multi-project always reloads\n\t\t\tinfo.needsReload = true;\n\t\t}\n\t\telse {\n\t\t\t// Single-project: skip if NIF hasn't changed\n\t\t\tinfo.needsReload = !pp->baseNif || pp->inputFileName != info.inputFileName || pp->setName != info.setName || sliderManager.NeedReload();\n\t\t}\n\n\t\tprojectInfos->push_back(std::move(info));\n\t}\n\n\tauto extraNifPaths = multiProjectMode ? preview->GetExtraNifPaths() : std::vector<std::string>{};\n\tbool isMultiProject = multiProjectMode;\n\tPreviewPanel* targetPreview = preview;\n\n\tpreviewLoadThread = std::thread([this, gen, projectInfos, extraNifPaths, isMultiProject, targetPreview]() {\n\t\tstruct ProjectResult {\n\t\t\tsize_t index;\n\t\t\tnifly::NifFile* baseNif = nullptr;\n\t\t\tnifly::NifFile modNif;\n\t\t\tbool loaded = false;\n\t\t};\n\n\t\tstd::vector<ProjectResult> results(projectInfos->size());\n\n\t\tfor (size_t i = 0; i < projectInfos->size(); ++i) {\n\t\t\tif (previewLoadGeneration.load() != gen) {\n\t\t\t\tfor (size_t j = 0; j < i; ++j)\n\t\t\t\t\tdelete results[j].baseNif;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tauto& info = (*projectInfos)[i];\n\t\t\tauto& result = results[i];\n\t\t\tresult.index = info.index;\n\n\t\t\tif (!info.needsReload)\n\t\t\t\tcontinue;\n\n\t\t\tresult.baseNif = new nifly::NifFile();\n\t\t\tstd::fstream file;\n\t\t\tPlatformUtil::OpenFileStream(file, info.inputFileName, std::ios::in | std::ios::binary);\n\t\t\tif (result.baseNif->Load(file)) {\n\t\t\t\tdelete result.baseNif;\n\t\t\t\tresult.baseNif = nullptr;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tresult.modNif.CopyFrom(*result.baseNif);\n\n\t\t\tDiffDataSets dataSets;\n\t\t\tinfo.sliderSetCopy.LoadSetDiffData(dataSets);\n\n\t\t\t// Build preview mesh (apply sliders, zap verts)\n\t\t\tbool keepZappedShapes = info.sliderSetCopy.KeepZappedShapes();\n\t\t\tstd::vector<nifly::Vector3> verts;\n\t\t\tstd::vector<nifly::Vector2> uvs;\n\t\t\tstd::vector<uint16_t> zapIdx;\n\t\t\tfor (auto it = info.sliderSetCopy.ShapesBegin(); it != info.sliderSetCopy.ShapesEnd(); ++it) {\n\t\t\t\tzapIdx.clear();\n\t\t\t\tauto shape = result.baseNif->FindBlockByName<nifly::NiShape>(it->first);\n\t\t\t\tif (!result.baseNif->GetVertsForShape(shape, verts))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tresult.baseNif->GetUvsForShape(shape, uvs);\n\t\t\t\tApplySliders(it->second.targetShape, sliderManager.slidersBig, dataSets, verts, zapIdx, &uvs);\n\n\t\t\t\tshape = result.modNif.FindBlockByName<nifly::NiShape>(it->first);\n\t\t\t\tif (zapIdx.size() > 0) {\n\t\t\t\t\tresult.modNif.SetVertsForShape(shape, verts);\n\t\t\t\t\tresult.modNif.SetUvsForShape(shape, uvs);\n\t\t\t\t\tif (result.modNif.DeleteVertsForShape(shape, zapIdx) && !keepZappedShapes)\n\t\t\t\t\t\tresult.modNif.DeleteShape(shape);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tresult.modNif.SetVertsForShape(shape, verts);\n\t\t\t\t\tresult.modNif.SetUvsForShape(shape, uvs);\n\t\t\t\t}\n\t\t\t}\n\t\t\tresult.loaded = true;\n\t\t}\n\n\t\tif (previewLoadGeneration.load() != gen) {\n\t\t\tfor (auto& r : results)\n\t\t\t\tdelete r.baseNif;\n\t\t\treturn;\n\t\t}\n\n\t\tCallAfter([this, gen, targetPreview, results = std::move(results), projectInfos, extraNifPaths, isMultiProject]() mutable {\n\t\t\tif (previewLoadGeneration.load() != gen) {\n\t\t\t\tfor (auto& r : results)\n\t\t\t\t\tdelete r.baseNif;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Verify the target panel is still the active preview.\n\t\t\t// Prevents stale callbacks from writing to the wrong panel\n\t\t\t// (e.g. conflicts preview closed while async load was in-flight).\n\t\t\tif (!preview || preview != targetPreview) {\n\t\t\t\tfor (auto& r : results)\n\t\t\t\t\tdelete r.baseNif;\n\t\t\t\tpreviewLoading = false;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tbool anyGenWeights = false;\n\t\t\tstd::string baseGamePath = Config[\"GameDataPath\"];\n\t\t\tpreview->SetBaseDataPath(baseGamePath);\n\n\t\t\tfor (size_t i = 0; i < results.size() && i < projects.size(); ++i) {\n\t\t\t\tauto& result = results[i];\n\t\t\t\tauto& pp = projects[result.index];\n\t\t\t\tauto& info = (*projectInfos)[i];\n\n\t\t\t\tif (result.loaded) {\n\t\t\t\t\tdelete pp->baseNif;\n\t\t\t\t\tpp->baseNif = result.baseNif;\n\t\t\t\t\tresult.baseNif = nullptr; // Ownership transferred\n\t\t\t\t\tpp->modNif = std::move(result.modNif);\n\t\t\t\t\tpp->inputFileName = info.inputFileName;\n\t\t\t\t\tpp->setName = info.setName;\n\t\t\t\t}\n\n\t\t\t\tif (pp->sliderSet.GenWeights())\n\t\t\t\t\tanyGenWeights = true;\n\n\t\t\t\tpp->sliderSet.LoadSetDiffData(pp->dataSets);\n\t\t\t\tpreview->AddMeshFromNif(&pp->modNif);\n\n\t\t\t\tfor (auto& s : pp->modNif.GetShapeNames())\n\t\t\t\t\tpreview->AddNifShapeTextures(&pp->modNif, s);\n\n\t\t\t\tUpdateMeshesFromSet(pp->sliderSet);\n\t\t\t}\n\n\t\t\tif (!isMultiProject)\n\t\t\t\tsliderManager.FlagReload(false);\n\n\t\t\tpreview->ShowWeight(anyGenWeights);\n\t\t\tif (sliderView && !preview->IsReadOnlyMode())\n\t\t\t\tpreview->ShowLockShapeButton(anyGenWeights);\n\n\t\t\tif (isMultiProject) {\n\t\t\t\tpreview->LoadNifFiles(extraNifPaths);\n\t\t\t}\n\t\t\telse if (!projects.empty()) {\n\t\t\t\t// Single-project extras: normals gen layers, reference shape\n\t\t\t\tauto* pp = projects[0].get();\n\t\t\t\tpreview->SetNormalsGenerationLayers(pp->sliderSet.GetNormalsGenLayers());\n\n\t\t\t\tif (pp->sliderSet.HasReferenceInfo()) {\n\t\t\t\t\tbool hasBuiltInRef = false;\n\t\t\t\t\tstd::string refInfoShape = pp->sliderSet.GetReferenceShapeName();\n\t\t\t\t\tif (!refInfoShape.empty() && pp->baseNif->FindBlockByName<nifly::NiShape>(refInfoShape))\n\t\t\t\t\t\thasBuiltInRef = true;\n\t\t\t\t\tif (!hasBuiltInRef && ClippingFixer::FindReferenceShape(*pp->baseNif))\n\t\t\t\t\t\thasBuiltInRef = true;\n\n\t\t\t\t\tif (hasBuiltInRef) {\n\t\t\t\t\t\tpreview->ShowReferenceCheckbox(false);\n\t\t\t\t\t\treferenceNif.reset();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (!referenceNif)\n\t\t\t\t\t\t\tLoadExternalReference(pp->sliderSet);\n\n\t\t\t\t\t\tif (referenceNif) {\n\t\t\t\t\t\t\tbool hasClippingFix = clippingFixStrength > 0.0f;\n\t\t\t\t\t\t\tpreview->ShowReferenceCheckbox(true);\n\t\t\t\t\t\t\tif (hasClippingFix)\n\t\t\t\t\t\t\t\tpreview->SetReferenceCheckboxState(true, false);\n\t\t\t\t\t\t\telse\n\t\t\t\t\t\t\t\tpreview->SetReferenceCheckboxState(false, true);\n\n\t\t\t\t\t\t\tpreview->AddMeshFromNif(referenceNif.get(), const_cast<char*>(referenceShapeName.c_str()));\n\t\t\t\t\t\t\tpreview->AddNifShapeTextures(referenceNif.get(), referenceShapeName);\n\t\t\t\t\t\t\tpreview->SetMeshVisibility(referenceShapeName, preview->IsShowReferenceChecked());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tpreview->ShowReferenceCheckbox(false);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpreview->ShowReferenceCheckbox(false);\n\t\t\t\t\treferenceNif.reset();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tUpdatePreview();\n\t\t\tpreview->ShowLoadingIndicator(false);\n\t\t\tpreviewLoading = false;\n\t\t});\n\t});\n}\n\nvoid BodySlideApp::LoadPreviewNifs(const std::vector<std::string>& filePaths) {\n\tif (!preview)\n\t\treturn;\n\n\t// Parse entries: split each by '?' to get file path and optional set names\n\tstruct ParsedEntry {\n\t\tstd::string filePath;\n\t\tstd::vector<std::string> setNames;\n\t\tbool isOsp = false;\n\t};\n\n\tstd::vector<ParsedEntry> entries;\n\tbool hasExplicitSets = false;\n\n\tfor (auto& rawPath : filePaths) {\n\t\tParsedEntry entry;\n\n\t\t// Split by '?'\n\t\tsize_t qPos = rawPath.find('?');\n\t\tif (qPos != std::string::npos) {\n\t\t\tentry.filePath = rawPath.substr(0, qPos);\n\t\t\tstd::string remainder = rawPath.substr(qPos + 1);\n\t\t\t// Split set names by '?'\n\t\t\tsize_t pos = 0;\n\t\t\twhile (pos < remainder.size()) {\n\t\t\t\tsize_t nextQ = remainder.find('?', pos);\n\t\t\t\tstd::string setName;\n\t\t\t\tif (nextQ != std::string::npos) {\n\t\t\t\t\tsetName = remainder.substr(pos, nextQ - pos);\n\t\t\t\t\tpos = nextQ + 1;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tsetName = remainder.substr(pos);\n\t\t\t\t\tpos = remainder.size();\n\t\t\t\t}\n\t\t\t\tif (!setName.empty())\n\t\t\t\t\tentry.setNames.push_back(setName);\n\t\t\t}\n\t\t\thasExplicitSets = true;\n\t\t}\n\t\telse {\n\t\t\tentry.filePath = rawPath;\n\t\t}\n\n\t\t// Detect OSP extension\n\t\tsize_t dotPos = entry.filePath.find_last_of('.');\n\t\tif (dotPos != std::string::npos) {\n\t\t\tstd::string ext = entry.filePath.substr(dotPos + 1);\n\t\t\tstd::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);\n\t\t\tentry.isOsp = (ext == \"osp\");\n\t\t}\n\n\t\tentries.push_back(entry);\n\t}\n\n\t// Collect non-OSP file paths for extra NIF loading alongside projects\n\tstd::vector<std::string> nifPaths;\n\tfor (auto& e : entries) {\n\t\tif (!e.isOsp)\n\t\t\tnifPaths.push_back(e.filePath);\n\t}\n\n\t// Multi-project mode: explicit set names specified with '?'\n\tif (hasExplicitSets) {\n\t\tstd::vector<PreviewProjectEntry> projEntries;\n\n\t\tfor (auto& e : entries) {\n\t\t\tif (e.isOsp) {\n\t\t\t\tif (!e.setNames.empty()) {\n\t\t\t\t\tfor (auto& setName : e.setNames)\n\t\t\t\t\t\tprojEntries.push_back({e.filePath, setName});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// OSP without specific sets: ignore when other files have explicit sets\n\t\t\t\t\twxLogWarning(\"Ignoring OSP file without specified set names: %s\", e.filePath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!projEntries.empty()) {\n\t\t\twxLogMessage(\"Loading %zu combined project(s) in preview mode...\", projEntries.size());\n\t\t\tif (!nifPaths.empty())\n\t\t\t\tpreview->SetExtraNifPaths(nifPaths);\n\t\t\tpreview->SetProjectData(projEntries, true);\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// OSP files without explicit sets: show dropdown with all sets from all OSP files\n\t{\n\t\tstd::vector<PreviewProjectEntry> projEntries;\n\t\tbool anyOsp = false;\n\n\t\tfor (auto& e : entries) {\n\t\t\tif (!e.isOsp)\n\t\t\t\tcontinue;\n\n\t\t\tanyOsp = true;\n\t\t\tSliderSetFile sliderDoc;\n\t\t\tsliderDoc.Open(e.filePath);\n\t\t\tif (sliderDoc.fail()) {\n\t\t\t\twxLogError(\"Failed to load BodySlide project file: %s\", e.filePath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tstd::vector<std::string> setNames;\n\t\t\tsliderDoc.GetSetNamesUnsorted(setNames, false);\n\t\t\tfor (auto& setName : setNames)\n\t\t\t\tprojEntries.push_back({e.filePath, setName});\n\t\t}\n\n\t\tif (!projEntries.empty()) {\n\t\t\twxLogMessage(\"Loading %zu slider set(s) from %zu OSP file(s)\", projEntries.size(), entries.size());\n\t\t\tif (!nifPaths.empty())\n\t\t\t\tpreview->SetExtraNifPaths(nifPaths);\n\t\t\tpreview->SetProjectData(projEntries);\n\t\t\treturn;\n\t\t}\n\n\t\tif (anyOsp)\n\t\t\treturn;\n\t}\n\n\t// Load as regular NIF files\n\tstd::vector<std::string> paths;\n\tfor (auto& e : entries)\n\t\tpaths.push_back(e.filePath);\n\tpreview->SetExtraNifPaths(paths);\n}\n\nvoid BodySlideApp::BuildPreviewMesh(ProjectData* pp, bool freshLoad) {\n\tbool keepZappedShapes = pp->sliderSet.KeepZappedShapes();\n\n\tstd::vector<Vector3> verts;\n\tstd::vector<Vector2> uvs;\n\tstd::vector<uint16_t> zapIdx;\n\tfor (auto it = pp->sliderSet.ShapesBegin(); it != pp->sliderSet.ShapesEnd(); ++it) {\n\t\tzapIdx.clear();\n\n\t\tauto shape = pp->baseNif->FindBlockByName<NiShape>(it->first);\n\t\tif (!pp->baseNif->GetVertsForShape(shape, verts))\n\t\t\tcontinue;\n\n\t\tpp->baseNif->GetUvsForShape(shape, uvs);\n\n\t\tApplySliders(it->second.targetShape, sliderManager.slidersBig, pp->dataSets, verts, zapIdx, &uvs);\n\n\t\t// Zap deleted verts before preview\n\t\tshape = pp->modNif.FindBlockByName<NiShape>(it->first);\n\t\tif (freshLoad && zapIdx.size() > 0) {\n\t\t\t// Freshly loaded, need to actually delete verts and tris in the modified .nif\n\t\t\tpp->modNif.SetVertsForShape(shape, verts);\n\t\t\tpp->modNif.SetUvsForShape(shape, uvs);\n\t\t\tif (pp->modNif.DeleteVertsForShape(shape, zapIdx) && !keepZappedShapes)\n\t\t\t\tpp->modNif.DeleteShape(shape);\n\t\t}\n\t\telse if (zapIdx.size() > 0) {\n\t\t\t// Preview Window has been opened for this shape before, zap the diff verts before applying them to the shape\n\t\t\tfor (int z = zapIdx.size() - 1; z >= 0; z--) {\n\t\t\t\tif (zapIdx[z] >= verts.size())\n\t\t\t\t\tcontinue;\n\t\t\t\tverts.erase(verts.begin() + zapIdx[z]);\n\t\t\t\tuvs.erase(uvs.begin() + zapIdx[z]);\n\t\t\t}\n\t\t\tpp->modNif.SetVertsForShape(shape, verts);\n\t\t\tpp->modNif.SetUvsForShape(shape, uvs);\n\t\t}\n\t\telse {\n\t\t\t// No zapping needed - just show all the verts.\n\t\t\tpp->modNif.SetVertsForShape(shape, verts);\n\t\t\tpp->modNif.SetUvsForShape(shape, uvs);\n\t\t}\n\t}\n}\n\nvoid BodySlideApp::ApplyClippingFix(NifFile& nif,\n\t\t\t\t\t\t\t\t\tconst std::vector<Vector3>& bodyVerts,\n\t\t\t\t\t\t\t\t\tconst std::vector<Triangle>& bodyTris,\n\t\t\t\t\t\t\t\t\tstd::unordered_map<std::string, std::vector<Vector3>*>& shapeVerts) {\n\tClippingFixOptions fixOpts;\n\tfixOpts.strength = clippingFixStrength / 100.0f;\n\n\tfor (auto& [shapeName, vertsPtr] : shapeVerts) {\n\t\tif (!vertsPtr || vertsPtr->empty())\n\t\t\tcontinue;\n\n\t\tauto shape = nif.FindBlockByName<NiShape>(shapeName);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\tstd::vector<Triangle> outfitTris;\n\t\tshape->GetTriangles(outfitTris);\n\t\tif (outfitTris.empty())\n\t\t\tcontinue;\n\n\t\tClippingFixer::FixClipping(bodyVerts, bodyTris, *vertsPtr, outfitTris, fixOpts);\n\t}\n}\n\nbool BodySlideApp::LoadExternalReference(const SliderSet& sliderSet) {\n\tif (!sliderSet.HasReferenceInfo())\n\t\treturn false;\n\n\tstd::string projectFile = sliderSet.GetReferenceProjectFile();\n\tstd::string projectName = sliderSet.GetReferenceProjectName();\n\treferenceShapeName = sliderSet.GetReferenceShapeName();\n\n\t// Resolve project file path relative to project directory\n\twxFileName refProjectFileName(wxString::FromUTF8(projectFile));\n\tif (refProjectFileName.IsRelative())\n\t\trefProjectFileName.MakeAbsolute(wxString::FromUTF8(GetProjectPath()));\n\n\tstd::string projectFilePath = refProjectFileName.GetFullPath().ToUTF8().data();\n\n\t// Load the slider set from the referenced project file\n\tSliderSetFile refSSF(projectFilePath);\n\tif (refSSF.fail()) {\n\t\twxLogWarning(\"Could not load reference project file: %s\", projectFilePath);\n\t\treturn false;\n\t}\n\n\treferenceSliderSet.Clear();\n\tif (refSSF.GetSet(projectName, referenceSliderSet)) {\n\t\twxLogWarning(\"Could not find reference project '%s' in file: %s\", projectName, projectFilePath);\n\t\treturn false;\n\t}\n\n\treferenceSliderSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\n\t// Load diff data for the reference shape\n\treferenceDiffData.Clear();\n\treferenceSliderSet.LoadSetDiffData(referenceDiffData, referenceShapeName);\n\n\t// Load the NIF file from the referenced project\n\tstd::string refInputFile = referenceSliderSet.GetInputFileName();\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, refInputFile, std::ios::in | std::ios::binary);\n\n\treferenceNif = std::make_unique<NifFile>();\n\tif (referenceNif->Load(file)) {\n\t\twxLogWarning(\"Could not load reference NIF file: %s\", refInputFile);\n\t\treferenceNif.reset();\n\t\treturn false;\n\t}\n\n\t// Verify the shape exists\n\tauto refShape = referenceNif->FindBlockByName<NiShape>(referenceShapeName);\n\tif (!refShape) {\n\t\twxLogWarning(\"Reference shape '%s' not found in NIF: %s\", referenceShapeName, refInputFile);\n\t\treferenceNif.reset();\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid BodySlideApp::UpdateReferenceCheckboxState() {\n\tif (!preview || !referenceNif || multiProjectMode)\n\t\treturn;\n\n\tbool hasClippingFix = clippingFixStrength > 0.0f;\n\tif (hasClippingFix) {\n\t\tpreview->SetReferenceCheckboxState(true, false);\n\t}\n\telse {\n\t\tpreview->SetReferenceCheckboxState(false, true);\n\t}\n}\n\nvoid BodySlideApp::UpdatePreview() {\n\tif (!preview)\n\t\treturn;\n\n\tif (projects.empty())\n\t\treturn;\n\n\tint weight = preview->GetWeight();\n\tauto shapeData = ComputeMorphedShapeData(weight);\n\tPostProcessPreview(shapeData, weight);\n}\n\nstd::vector<ShapePreviewData> BodySlideApp::ComputeMorphedShapeData(int weight) {\n\tstd::vector<ShapePreviewData> shapeData;\n\tstd::vector<Vector3> verts, vertsLow, vertsHigh;\n\tstd::vector<Vector2> uvs, uvsLow, uvsHigh;\n\tstd::vector<uint16_t> zapIdx;\n\n\tfor (int pi = 0; pi < static_cast<int>(projects.size()); pi++) {\n\t\tauto& pp = projects[pi];\n\t\tif (!pp->baseNif)\n\t\t\tcontinue;\n\n\t\tfor (auto it = pp->sliderSet.ShapesBegin(); it != pp->sliderSet.ShapesEnd(); ++it) {\n\t\t\tzapIdx.clear();\n\n\t\t\tauto shape = pp->baseNif->FindBlockByName<NiShape>(it->first);\n\t\t\tif (!pp->baseNif->GetVertsForShape(shape, verts))\n\t\t\t\tcontinue;\n\n\t\t\tpp->baseNif->GetUvsForShape(shape, uvs);\n\t\t\tvertsHigh = verts;\n\t\t\tvertsLow = verts;\n\t\t\tuvsHigh = uvs;\n\t\t\tuvsLow = uvs;\n\n\t\t\tApplySliders(it->second.targetShape, sliderManager.slidersBig, pp->dataSets, vertsHigh, zapIdx, &uvsHigh);\n\t\t\tif (pp->sliderSet.GenWeights())\n\t\t\t\tApplySliders(it->second.targetShape, sliderManager.slidersSmall, pp->dataSets, vertsLow, zapIdx, &uvsLow);\n\n\t\t\t// Calculate result of weight\n\t\t\tauto uvsz = uvs.size();\n\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\tverts[i] = (vertsHigh[i] / 100.0f * weight) + (vertsLow[i] / 100.0f * (100.0f - weight));\n\t\t\t\tif (uvsz > i)\n\t\t\t\t\tuvs[i] = (uvsHigh[i] / 100.0f * weight) + (uvsLow[i] / 100.0f * (100.0f - weight));\n\t\t\t}\n\n\t\t\tShapePreviewData spd;\n\t\t\tspd.name = it->first;\n\t\t\tspd.verts = std::move(verts);\n\t\t\tspd.uvs = std::move(uvs);\n\t\t\tspd.zapIdx = zapIdx;\n\t\t\tspd.projectIdx = pi;\n\t\t\tshapeData.push_back(std::move(spd));\n\t\t}\n\t}\n\n\treturn shapeData;\n}\n\nvoid BodySlideApp::PostProcessPreview(std::vector<ShapePreviewData>& shapeData, int weight) {\n\t// Apply clipping fix and handle external reference\n\tbool useExternalReference = !multiProjectMode && referenceNif && preview &&\n\t\t\t\t\t\t\t  (clippingFixStrength > 0.0f || preview->IsShowReferenceChecked());\n\n\tstd::vector<Vector3> extRefVerts;\n\tif (useExternalReference)\n\t\tUpdateExternalReferenceMesh(weight, &extRefVerts);\n\n\t// Hide external reference mesh when not in use\n\tif (!useExternalReference && referenceNif && preview) {\n\t\tpreview->SetMeshVisibility(referenceShapeName, false);\n\t}\n\n\tif (clippingFixStrength > 0.0f) {\n\t\tfor (int pi = 0; pi < static_cast<int>(projects.size()); pi++) {\n\t\t\tauto& pp = projects[pi];\n\t\t\tif (!pp->baseNif)\n\t\t\t\tcontinue;\n\n\t\t\t// Try built-in reference shape first\n\t\t\tauto refShape = ClippingFixer::FindReferenceShape(*pp->baseNif);\n\t\t\tconst std::vector<Vector3>* bodyVerts = nullptr;\n\t\t\tstd::vector<Triangle> bodyTris;\n\n\t\t\tif (refShape) {\n\t\t\t\t// Use built-in reference shape\n\t\t\t\tShapePreviewData* refData = nullptr;\n\t\t\t\tfor (auto& sd : shapeData) {\n\t\t\t\t\tif (sd.projectIdx == pi && sd.name == refShape->name.get()) {\n\t\t\t\t\t\trefData = &sd;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (refData && !refData->verts.empty()) {\n\t\t\t\t\trefShape->GetTriangles(bodyTris);\n\t\t\t\t\tbodyVerts = &refData->verts;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fall back to external reference if no built-in reference\n\t\t\tif (!bodyVerts && useExternalReference && pi == 0 && !extRefVerts.empty()) {\n\t\t\t\tauto extRefShape = referenceNif->FindBlockByName<NiShape>(referenceShapeName);\n\t\t\t\tif (extRefShape) {\n\t\t\t\t\textRefShape->GetTriangles(bodyTris);\n\t\t\t\t\tbodyVerts = &extRefVerts;\n\t\t\t\t\trefShape = extRefShape;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!bodyVerts || bodyTris.empty())\n\t\t\t\tcontinue;\n\n\t\t\tstd::string refShapeName = refShape->name.get();\n\t\t\tstd::unordered_map<std::string, std::vector<Vector3>*> shapeVerts;\n\t\t\tfor (auto& sd : shapeData) {\n\t\t\t\tif (sd.projectIdx == pi && sd.name != refShapeName)\n\t\t\t\t\tshapeVerts[sd.name] = &sd.verts;\n\t\t\t}\n\n\t\t\tApplyClippingFix(*pp->baseNif, *bodyVerts, bodyTris, shapeVerts);\n\t\t}\n\t}\n\n\t// Phase 3: Zap and update meshes\n\tfor (auto& sd : shapeData) {\n\t\tif (sd.zapIdx.size() > 0) {\n\t\t\tfor (int z = sd.zapIdx.size() - 1; z >= 0; z--) {\n\t\t\t\tif (sd.zapIdx[z] >= sd.verts.size())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tsd.verts.erase(sd.verts.begin() + sd.zapIdx[z]);\n\t\t\t\tsd.uvs.erase(sd.uvs.begin() + sd.zapIdx[z]);\n\t\t\t}\n\t\t}\n\t\tpreview->UpdateMeshes(sd.name, &sd.verts, &sd.uvs);\n\t}\n\n\tpreview->Render();\n}\n\nvoid BodySlideApp::CleanupPreview() {\n\tif (!preview)\n\t\treturn;\n\n\t// Cancel async load and wait for it to finish\n\t++previewLoadGeneration;\n\tif (previewLoadThread.joinable())\n\t\tpreviewLoadThread.join();\n\tpreviewLoading = false;\n\n\tpreview->Cleanup();\n\tpreview->ShowLoadingIndicator(false);\n\treferenceNif.reset();\n\n\tif (multiProjectMode) {\n\t\tprojects.clear();\n\t\tmultiProjectMode = false;\n\t}\n\telse if (!projects.empty()) {\n\t\tauto* pp = projects[0].get();\n\t\tdelete pp->baseNif;\n\t\tpp->baseNif = nullptr;\n\t\tpp->inputFileName.clear();\n\t}\n}\n\nvoid BodySlideApp::RebuildPreviewMeshes() {\n\tif (!preview)\n\t\treturn;\n\n\tif (projects.empty())\n\t\treturn;\n\n\tint weight = preview->GetWeight();\n\tauto shapeData = ComputeMorphedShapeData(weight);\n\n\t// Multi-project mode\n\tif (multiProjectMode) {\n\t\tfor (auto& pp : projects) {\n\t\t\tif (!pp->baseNif)\n\t\t\t\tcontinue;\n\n\t\t\tpp->modNif.CopyFrom(*pp->baseNif);\n\n\t\t\tbool keepZappedShapes = pp->sliderSet.KeepZappedShapes();\n\n\t\t\tfor (auto it = pp->sliderSet.ShapesBegin(); it != pp->sliderSet.ShapesEnd(); ++it) {\n\t\t\t\t// Find the matching shape data\n\t\t\t\tShapePreviewData* spd = nullptr;\n\t\t\t\tfor (auto& sd : shapeData) {\n\t\t\t\t\tif (sd.name == it->first) {\n\t\t\t\t\t\tspd = &sd;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!spd)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Zap deleted verts before preview\n\t\t\t\tauto shape = pp->modNif.FindBlockByName<NiShape>(it->first);\n\t\t\t\tif (spd->zapIdx.size() > 0) {\n\t\t\t\t\tpp->modNif.SetVertsForShape(shape, spd->verts);\n\t\t\t\t\tpp->modNif.SetUvsForShape(shape, spd->uvs);\n\t\t\t\t\tif (pp->modNif.DeleteVertsForShape(shape, spd->zapIdx) && !keepZappedShapes)\n\t\t\t\t\t\tpp->modNif.DeleteShape(shape);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpp->modNif.SetVertsForShape(shape, spd->verts);\n\t\t\t\t\tpp->modNif.SetUvsForShape(shape, spd->uvs);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Refresh all meshes from all projects\n\t\tstd::vector<NifFile*> modNifs;\n\t\tfor (auto& pp : projects)\n\t\t\tmodNifs.push_back(&pp->modNif);\n\t\tpreview->RefreshMeshFromNif(modNifs);\n\n\t\t// Update mesh settings from all sets\n\t\tfor (auto& pp : projects) {\n\t\t\tfor (auto it = pp->sliderSet.ShapesBegin(); it != pp->sliderSet.ShapesEnd(); ++it) {\n\t\t\t\tMesh* m = preview->GetMesh(it->first);\n\t\t\t\tif (m) {\n\t\t\t\t\tm->smoothSeamNormals = it->second.smoothSeamNormals;\n\t\t\t\t\tm->lockNormals = it->second.lockNormals;\n\t\t\t\t\tm->SmoothNormals();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tPostProcessPreview(shapeData, weight);\n\t\treturn;\n\t}\n\n\t// Single-project mode\n\tauto* pp = projects[0].get();\n\tif (!pp->baseNif)\n\t\treturn;\n\n\tpp->modNif.CopyFrom(*pp->baseNif);\n\n\tbool keepZappedShapes = pp->sliderSet.KeepZappedShapes();\n\n\tfor (auto& sd : shapeData) {\n\t\tauto shape = pp->modNif.FindBlockByName<NiShape>(sd.name);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\tif (sd.zapIdx.size() > 0) {\n\t\t\tpp->modNif.SetVertsForShape(shape, sd.verts);\n\t\t\tpp->modNif.SetUvsForShape(shape, sd.uvs);\n\t\t\tif (pp->modNif.DeleteVertsForShape(shape, sd.zapIdx) && !keepZappedShapes)\n\t\t\t\tpp->modNif.DeleteShape(shape);\n\t\t}\n\t\telse {\n\t\t\tpp->modNif.SetVertsForShape(shape, sd.verts);\n\t\t\tpp->modNif.SetUvsForShape(shape, sd.uvs);\n\t\t}\n\t}\n\n\tpreview->RefreshMeshFromNif({&pp->modNif});\n\tUpdateMeshesFromSet(pp->sliderSet);\n\n\t// Re-add external reference mesh after refresh (which clears all meshes)\n\tif (referenceNif && !multiProjectMode) {\n\t\tpreview->AddMeshFromNif(referenceNif.get(), const_cast<char*>(referenceShapeName.c_str()));\n\t\tpreview->AddNifShapeTextures(referenceNif.get(), referenceShapeName);\n\t\tpreview->SetMeshVisibility(referenceShapeName, false);\n\t}\n\n\tPostProcessPreview(shapeData, weight);\n}\n\nvoid BodySlideApp::UpdateExternalReferenceMesh(int weight, std::vector<Vector3>* outVerts) {\n\tif (!preview || !referenceNif)\n\t\treturn;\n\n\tstd::vector<Vector3> extRefVerts;\n\tstd::vector<Vector2> extRefUvs;\n\tauto refShape = referenceNif->FindBlockByName<NiShape>(referenceShapeName);\n\tif (!refShape || !referenceNif->GetVertsForShape(refShape, extRefVerts))\n\t\treturn;\n\n\treferenceNif->GetUvsForShape(refShape, extRefUvs);\n\n\tstd::string targetName = referenceSliderSet.ShapeToTarget(referenceShapeName);\n\tif (!targetName.empty()) {\n\t\t// Build slider vectors from the reference project's slider set.\n\t\t// We can't use sliderManager.slidersBig/slidersSmall directly because\n\t\t// their linkedDataSets contain data names from the outfit project,\n\t\t// which don't match the data names in referenceDiffData.\n\t\tstd::vector<Slider> refSlidersBig;\n\t\tstd::vector<Slider> refSlidersSmall;\n\t\tfor (size_t si = 0; si < referenceSliderSet.size(); si++) {\n\t\t\tauto& sd = referenceSliderSet[si];\n\t\t\tSlider s;\n\t\t\ts.name = sd.name;\n\t\t\ts.invert = sd.bInvert;\n\t\t\ts.zap = sd.bZap;\n\t\t\ts.clamp = sd.bClamp;\n\t\t\ts.uv = sd.bUV;\n\t\t\tfor (auto& df : sd.dataFiles)\n\t\t\t\tif (df.targetName == targetName)\n\t\t\t\t\ts.linkedDataSets.push_back(df.dataName);\n\n\t\t\ts.value = sliderManager.GetSlider(sd.name, false);\n\t\t\trefSlidersBig.push_back(s);\n\n\t\t\ts.value = sliderManager.GetSlider(sd.name, true);\n\t\t\trefSlidersSmall.push_back(std::move(s));\n\t\t}\n\n\t\tstd::vector<Vector3> refVertsHigh = extRefVerts;\n\t\tstd::vector<Vector3> refVertsLow = extRefVerts;\n\t\tstd::vector<Vector2> refUvsHigh = extRefUvs;\n\t\tstd::vector<Vector2> refUvsLow = extRefUvs;\n\t\tstd::vector<uint16_t> extZapIdx;\n\n\t\tApplySliders(targetName, refSlidersBig, referenceDiffData, refVertsHigh, extZapIdx, &refUvsHigh);\n\t\tif (referenceSliderSet.GenWeights())\n\t\t\tApplySliders(targetName, refSlidersSmall, referenceDiffData, refVertsLow, extZapIdx, &refUvsLow);\n\n\t\tauto uvsz = extRefUvs.size();\n\t\tfor (size_t i = 0; i < extRefVerts.size(); i++) {\n\t\t\textRefVerts[i] = (refVertsHigh[i] / 100.0f * weight) + (refVertsLow[i] / 100.0f * (100.0f - weight));\n\t\t\tif (uvsz > i)\n\t\t\t\textRefUvs[i] = (refUvsHigh[i] / 100.0f * weight) + (refUvsLow[i] / 100.0f * (100.0f - weight));\n\t\t}\n\t}\n\n\tpreview->UpdateMeshes(referenceShapeName, &extRefVerts, &extRefUvs);\n\tpreview->SetMeshVisibility(referenceShapeName, true);\n\n\tif (outVerts)\n\t\t*outVerts = std::move(extRefVerts);\n}\n\nvoid BodySlideApp::UpdateMeshesFromSet(SliderSet& set) {\n\tfor (auto it = set.ShapesBegin(); it != set.ShapesEnd(); ++it) {\n\t\tMesh* m = preview->GetMesh(it->first);\n\t\tif (m) {\n\t\t\tm->smoothSeamNormals = it->second.smoothSeamNormals;\n\t\t\tm->lockNormals = it->second.lockNormals;\n\n\t\t\tm->SmoothNormals();\n\t\t}\n\t}\n}\n\nvoid BodySlideApp::ApplyReferenceNormals(NifFile& nif) {\n\tfor (auto& s : nif.GetShapes()) {\n\t\tstd::string shapeName = s->name.get();\n\n\t\tif (refNormalsCache.find(shapeName) != refNormalsCache.end()) {\n\t\t\t// Apply normals from file cache\n\t\t\tNifFile& srcNif = refNormalsCache[shapeName];\n\t\t\tnif.ApplyNormalsFromFile(srcNif, shapeName);\n\t\t}\n\t\telse {\n\t\t\t// Check if reference normals file exists\n\t\t\twxString fileName = wxString::Format(\"%s/RefNormals/%s.nif\", wxString::FromUTF8(Config[\"AppDir\"]), wxString::FromUTF8(shapeName));\n\t\t\tif (wxFile::Exists(fileName)) {\n\t\t\t\tstd::fstream file;\n\t\t\t\tPlatformUtil::OpenFileStream(file, fileName.ToUTF8().data(), std::ios::in | std::ios::binary);\n\n\t\t\t\tNifFile srcNif;\n\t\t\t\tif (srcNif.Load(file) != 0)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// Apply normals from file\n\t\t\t\tnif.ApplyNormalsFromFile(srcNif, shapeName);\n\n\t\t\t\t// Move file to cache\n\t\t\t\trefNormalsCache[shapeName] = std::move(srcNif);\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool BodySlideApp::SetDefaultConfig() {\n\tint xborder = wxSystemSettings::GetMetric(wxSYS_FRAMESIZE_X);\n\tif (xborder < 0)\n\t\txborder = 0;\n\tint yborder = wxSystemSettings::GetMetric(wxSYS_FRAMESIZE_Y);\n\tif (yborder < 0)\n\t\tyborder = 0;\n\n\tint currentTarget = -1;\n\tConfig.SetDefaultValue(\"TargetGame\", currentTarget);\n\tcurrentTarget = Config.GetIntValue(\"TargetGame\");\n\n\tConfig.SetDefaultBoolValue(\"WarnMissingGamePath\", true);\n\tConfig.SetDefaultBoolValue(\"WarnBatchBuildOverride\", true);\n\tConfig.SetDefaultBoolValue(\"BSATextureScan\", true);\n\tConfig.SetDefaultValue(\"LogLevel\", \"3\");\n\tConfig.SetDefaultBoolValue(\"UseSystemLanguage\", false);\n\tBodySlideConfig.SetDefaultValue(\"SelectedOutfit\", \"\");\n\tBodySlideConfig.SetDefaultValue(\"SelectedPreset\", \"\");\n\tBodySlideConfig.SetDefaultBoolValue(\"BuildMorphs\", false);\n\tBodySlideConfig.SetDefaultBoolValue(\"RegexFilterOutfits\", false);\n\tConfig.SetDefaultValue(\"Input/SliderMinimum\", 0);\n\tConfig.SetDefaultValue(\"Input/SliderMaximum\", 100);\n\tConfig.SetDefaultBoolValue(\"Input/LeftMousePan\", false);\n\tConfig.SetDefaultBoolValue(\"Input/BrushSettingsNearCursor\", true);\n\tConfig.SetDefaultBoolValue(\"Input/MaskHistory\", true);\n\tConfig.SetDefaultValue(\"Lights/Ambient\", 20);\n\tConfig.SetDefaultValue(\"Lights/Frontal\", 20);\n\tConfig.SetDefaultValue(\"Lights/Directional0\", 60);\n\tConfig.SetDefaultValue(\"Lights/Directional0.x\", -90);\n\tConfig.SetDefaultValue(\"Lights/Directional0.y\", 10);\n\tConfig.SetDefaultValue(\"Lights/Directional0.z\", 100);\n\tConfig.SetDefaultValue(\"Lights/Directional1\", 60);\n\tConfig.SetDefaultValue(\"Lights/Directional1.x\", 70);\n\tConfig.SetDefaultValue(\"Lights/Directional1.y\", 10);\n\tConfig.SetDefaultValue(\"Lights/Directional1.z\", 100);\n\tConfig.SetDefaultValue(\"Lights/Directional2\", 85);\n\tConfig.SetDefaultValue(\"Lights/Directional2.x\", 30);\n\tConfig.SetDefaultValue(\"Lights/Directional2.y\", 20);\n\tConfig.SetDefaultValue(\"Lights/Directional2.z\", -100);\n\tBodySlideConfig.SetDefaultValue(\"BodySlideFrame.width\", 1200);\n\tBodySlideConfig.SetDefaultValue(\"BodySlideFrame.height\", 600);\n\tBodySlideConfig.SetDefaultValue(\"BodySlideFrame.x\", 100);\n\tBodySlideConfig.SetDefaultValue(\"BodySlideFrame.y\", 100);\n\tBodySlideConfig.SetDefaultValue(\"BodySlideFrame.sashpos\", 500);\n\tBodySlideConfig.SetDefaultBoolValue(\"BodySlideFrame.previewVisible\", true);\n\n\twxSize previewSize(720 + xborder * 2, 720 + yborder * 2);\n\tBodySlideConfig.SetDefaultValue(\"PreviewFrame.width\", previewSize.GetWidth());\n\tBodySlideConfig.SetDefaultValue(\"PreviewFrame.height\", previewSize.GetHeight());\n\tBodySlideConfig.SetDefaultValue(\"PreviewFrame.x\", 100);\n\tBodySlideConfig.SetDefaultValue(\"PreviewFrame.y\", 100);\n\n\tConfig.SetDefaultValue(\"GameRegKey/Oblivion\", \"Software\\\\Bethesda Softworks\\\\Oblivion\");\n\tConfig.SetDefaultValue(\"GameRegVal/Oblivion\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Fallout3\", \"Software\\\\Bethesda Softworks\\\\Fallout3\");\n\tConfig.SetDefaultValue(\"GameRegVal/Fallout3\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/FalloutNewVegas\", \"Software\\\\Bethesda Softworks\\\\FalloutNV\");\n\tConfig.SetDefaultValue(\"GameRegVal/FalloutNewVegas\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Skyrim\", \"Software\\\\Bethesda Softworks\\\\Skyrim\");\n\tConfig.SetDefaultValue(\"GameRegVal/Skyrim\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Fallout4\", \"Software\\\\Bethesda Softworks\\\\Fallout4\");\n\tConfig.SetDefaultValue(\"GameRegVal/Fallout4\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/SkyrimSpecialEdition\", \"Software\\\\Bethesda Softworks\\\\Skyrim Special Edition\");\n\tConfig.SetDefaultValue(\"GameRegVal/SkyrimSpecialEdition\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Fallout4VR\", \"Software\\\\Bethesda Softworks\\\\Fallout 4 VR\");\n\tConfig.SetDefaultValue(\"GameRegVal/Fallout4VR\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/SkyrimVR\", \"Software\\\\Bethesda Softworks\\\\Skyrim VR\");\n\tConfig.SetDefaultValue(\"GameRegVal/SkyrimVR\", \"Installed Path\");\n\n\t// Target game not set, show setup dialog\n\tif (currentTarget == -1)\n\t\tif (!ShowSetup())\n\t\t\treturn false;\n\n\ttargetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\n\twxString gameKey = Config[\"GameRegKey/\" + TargetGames[targetGame]];\n\twxString gameValueKey = Config[\"GameRegVal/\" + TargetGames[targetGame]];\n\n#ifdef _WINDOWS\n\tif (Config[\"GameDataPath\"].empty()) {\n\t\twxRegKey key(wxRegKey::HKLM, gameKey, wxRegKey::WOW64ViewMode_32);\n\t\tif (!gameKey.empty() && key.Exists()) {\n\t\t\twxString installPath;\n\t\t\tif (key.HasValues() && key.QueryValue(gameValueKey, installPath)) {\n\t\t\t\tinstallPath.Append(\"Data\").Append(PathSepChar);\n\t\t\t\tConfig.SetDefaultValue(\"GameDataPath\", installPath.ToUTF8().data());\n\t\t\t\twxLogMessage(\"Registry game data path: %s\", installPath);\n\t\t\t}\n\t\t}\n\t}\n#endif\n\n\tif (Config[\"GameDataPath\"].empty()) {\n\t\tif (Config[\"WarnMissingGamePath\"] == \"true\") {\n\t\t\twxLogWarning(\"Failed to find game install path registry key or GameDataPath in the config.\");\n\t\t\twxMessageBox(_(\"Failed to find game install path registry key or GameDataPath in the config.\"), _(\"Warning\"), wxICON_WARNING);\n\t\t}\n\t}\n\telse\n\t\twxLogMessage(\"Game data path in config: %s\", Config[\"GameDataPath\"]);\n\n\tif (!Config[\"OutputDataPath\"].empty()) {\n\t\twxLogMessage(\"Output data path in config: %s\", Config[\"OutputDataPath\"]);\n\t}\n\n\tif (!Config[\"ProjectPath\"].empty()) {\n\t\twxLogMessage(\"Project path in config: %s\", Config[\"ProjectPath\"]);\n\t}\n\n\treturn true;\n}\n\nbool BodySlideApp::ShowSetup() {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\tbool loaded = xrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Setup.xrc\");\n\tif (!loaded) {\n\t\twxMessageBox(\"Failed to load Setup.xrc file!\", _(\"Error\"), wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\twxDialog* setup = xrc->LoadDialog(nullptr, \"dlgSetup\");\n\tif (setup) {\n\t\tsetup->SetSize(setup->FromDIP(wxSize(700, -1)));\n\t\tsetup->CenterOnScreen();\n\n\t\twxButton* btOblivion = XRCCTRL(*setup, \"btOblivion\", wxButton);\n\t\tbtOblivion->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)OB); });\n\n\t\twxButton* btFallout3 = XRCCTRL(*setup, \"btFallout3\", wxButton);\n\t\tbtFallout3->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FO3); });\n\n\t\twxButton* btFalloutNV = XRCCTRL(*setup, \"btFalloutNV\", wxButton);\n\t\tbtFalloutNV->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FONV); });\n\n\t\twxButton* btSkyrim = XRCCTRL(*setup, \"btSkyrim\", wxButton);\n\t\tbtSkyrim->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SKYRIM); });\n\n\t\twxButton* btFallout4 = XRCCTRL(*setup, \"btFallout4\", wxButton);\n\t\tbtFallout4->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FO4); });\n\n\t\twxButton* btSkyrimSE = XRCCTRL(*setup, \"btSkyrimSE\", wxButton);\n\t\tbtSkyrimSE->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SKYRIMSE); });\n\n\t\twxButton* btFallout4VR = XRCCTRL(*setup, \"btFallout4VR\", wxButton);\n\t\tbtFallout4VR->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FO4VR); });\n\n\t\twxButton* btSkyrimVR = XRCCTRL(*setup, \"btSkyrimVR\", wxButton);\n\t\tbtSkyrimVR->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SKYRIMVR); });\n\n\t\twxButton* btStarfield = XRCCTRL(*setup, \"btStarfield\", wxButton);\n\t\tbtStarfield->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SF); });\n\n\t\twxDirPickerCtrl* dirOblivion = XRCCTRL(*setup, \"dirOblivion\", wxDirPickerCtrl);\n\t\tdirOblivion->Bind(wxEVT_DIRPICKER_CHANGED, [&dirOblivion, &btOblivion](wxFileDirPickerEvent&) { btOblivion->Enable(dirOblivion->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFallout3 = XRCCTRL(*setup, \"dirFallout3\", wxDirPickerCtrl);\n\t\tdirFallout3->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFallout3, &btFallout3](wxFileDirPickerEvent&) { btFallout3->Enable(dirFallout3->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFalloutNV = XRCCTRL(*setup, \"dirFalloutNV\", wxDirPickerCtrl);\n\t\tdirFalloutNV->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFalloutNV, &btFalloutNV](wxFileDirPickerEvent&) { btFalloutNV->Enable(dirFalloutNV->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirSkyrim = XRCCTRL(*setup, \"dirSkyrim\", wxDirPickerCtrl);\n\t\tdirSkyrim->Bind(wxEVT_DIRPICKER_CHANGED, [&dirSkyrim, &btSkyrim](wxFileDirPickerEvent&) { btSkyrim->Enable(dirSkyrim->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFallout4 = XRCCTRL(*setup, \"dirFallout4\", wxDirPickerCtrl);\n\t\tdirFallout4->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFallout4, &btFallout4](wxFileDirPickerEvent&) { btFallout4->Enable(dirFallout4->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirSkyrimSE = XRCCTRL(*setup, \"dirSkyrimSE\", wxDirPickerCtrl);\n\t\tdirSkyrimSE->Bind(wxEVT_DIRPICKER_CHANGED, [&dirSkyrimSE, &btSkyrimSE](wxFileDirPickerEvent&) { btSkyrimSE->Enable(dirSkyrimSE->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFallout4VR = XRCCTRL(*setup, \"dirFallout4VR\", wxDirPickerCtrl);\n\t\tdirFallout4VR->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFallout4VR, &btFallout4VR](wxFileDirPickerEvent&) { btFallout4VR->Enable(dirFallout4VR->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirSkyrimVR = XRCCTRL(*setup, \"dirSkyrimVR\", wxDirPickerCtrl);\n\t\tdirSkyrimVR->Bind(wxEVT_DIRPICKER_CHANGED, [&dirSkyrimVR, &btSkyrimVR](wxFileDirPickerEvent&) { btSkyrimVR->Enable(dirSkyrimVR->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirStarfield = XRCCTRL(*setup, \"dirStarfield\", wxDirPickerCtrl);\n\t\tdirStarfield->Bind(wxEVT_DIRPICKER_CHANGED, [&dirStarfield, &btStarfield](wxFileDirPickerEvent&) { btStarfield->Enable(dirStarfield->GetDirName().DirExists()); });\n\n\t\twxFileName dir = GetGameDataPath(OB);\n\t\tif (dir.DirExists()) {\n\t\t\tdirOblivion->SetDirName(dir);\n\t\t\tbtOblivion->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FO3);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFallout3->SetDirName(dir);\n\t\t\tbtFallout3->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FONV);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFalloutNV->SetDirName(dir);\n\t\t\tbtFalloutNV->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SKYRIM);\n\t\tif (dir.DirExists()) {\n\t\t\tdirSkyrim->SetDirName(dir);\n\t\t\tbtSkyrim->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FO4);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFallout4->SetDirName(dir);\n\t\t\tbtFallout4->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SKYRIMSE);\n\t\tif (dir.DirExists()) {\n\t\t\tdirSkyrimSE->SetDirName(dir);\n\t\t\tbtSkyrimSE->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FO4VR);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFallout4VR->SetDirName(dir);\n\t\t\tbtFallout4VR->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SKYRIMVR);\n\t\tif (dir.DirExists()) {\n\t\t\tdirSkyrimVR->SetDirName(dir);\n\t\t\tbtSkyrimVR->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SF);\n\t\tif (dir.DirExists()) {\n\t\t\tdirStarfield->SetDirName(dir);\n\t\t\tbtStarfield->Enable();\n\t\t}\n\n\t\tif (setup->ShowModal() != wxID_CANCEL) {\n\t\t\tint targ = setup->GetReturnCode();\n\t\t\tConfig.SetValue(\"TargetGame\", targ);\n\n\t\t\twxFileName dataDir;\n\t\t\tswitch (targ) {\n\t\t\t\tcase OB:\n\t\t\t\t\tdataDir = dirOblivion->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_ob.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Bip01\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FO3:\n\t\t\t\t\tdataDir = dirFallout3->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo3nv.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Bip01\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FONV:\n\t\t\t\t\tdataDir = dirFalloutNV->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo3nv.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Bip01\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SKYRIM:\n\t\t\t\t\tdataDir = dirSkyrim->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sk.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"NPC Root [Root]\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FO4:\n\t\t\t\t\tdataDir = dirFallout4->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo4.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Root\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SKYRIMSE:\n\t\t\t\t\tdataDir = dirSkyrimSE->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sse.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"NPC Root [Root]\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FO4VR:\n\t\t\t\t\tdataDir = dirFallout4VR->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo4.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Root\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SKYRIMVR:\n\t\t\t\t\tdataDir = dirSkyrimVR->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sse.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"NPC Root [Root]\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SF:\n\t\t\t\t\tdataDir = dirStarfield->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sf.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Root\");\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tConfig.SetValue(\"GameDataPath\", dataDir.GetFullPath().ToUTF8().data());\n\t\t\tConfig.SetValue(\"GameDataPaths/\" + TargetGames[targ].ToStdString(), dataDir.GetFullPath().ToUTF8().data());\n\n\t\t\tConfig.SaveConfig(Config[\"AppDir\"] + \"/Config.xml\");\n\t\t\tdelete setup;\n\t\t}\n\t\telse {\n\t\t\tdelete setup;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nwxString BodySlideApp::GetGameDataPath(TargetGame targ) {\n\twxString dataPath;\n\twxString gamestr = TargetGames[targ];\n\twxString gkey = \"GameRegKey/\" + gamestr;\n\twxString gval = \"GameRegVal/\" + gamestr;\n\twxString cust = \"GameDataPaths/\" + gamestr;\n\n\tif (!Config[cust].IsEmpty()) {\n\t\tdataPath = Config[cust];\n\t}\n#ifdef _WINDOWS\n\telse {\n\t\tstd::string gameKey = Config[gkey];\n\t\twxRegKey key(wxRegKey::HKLM, gameKey, wxRegKey::WOW64ViewMode_32);\n\t\tif (!gameKey.empty() && key.Exists()) {\n\t\t\tif (key.HasValues() && key.QueryValue(Config[gval], dataPath)) {\n\t\t\t\tdataPath.Append(\"Data\").Append(PathSepChar);\n\t\t\t}\n\t\t}\n\t}\n#endif\n\treturn dataPath;\n}\n\nvoid BodySlideApp::InitLanguage() {\n\tif (locale)\n\t\tdelete locale;\n\n\tint lang = Config.GetIntValue(\"Language\");\n\tif (lang < 0)\n\t\tlang = wxLANGUAGE_ENGLISH;\n\n\t// Load language if possible, fall back to English otherwise\n\tif (wxLocale::IsAvailable(lang)) {\n\t\tlocale = new wxLocale(lang);\n\t\tlocale->AddCatalogLookupPathPrefix(wxString::FromUTF8(Config[\"AppDir\"]) + \"/lang\");\n\t\tlocale->AddCatalog(\"BodySlide\");\n\n\t\tif (!locale->IsOk()) {\n\t\t\twxLogError(\"System language '%d' is wrong.\", lang);\n\t\t\twxMessageBox(wxString::Format(_(\"System language '%d' is wrong.\"), lang));\n\n\t\t\tdelete locale;\n\t\t\tlocale = new wxLocale(wxLANGUAGE_ENGLISH);\n\t\t\tlang = wxLANGUAGE_ENGLISH;\n\t\t}\n\t}\n\telse {\n\t\twxLogError(\"The system language '%d' is not supported by your system. Try installing support for this language.\", lang);\n\t\twxMessageBox(wxString::Format(_(\"The system language '%d' is not supported by your system. Try installing support for this language.\"), lang));\n\n\t\tlocale = new wxLocale(wxLANGUAGE_ENGLISH);\n\t\tlang = wxLANGUAGE_ENGLISH;\n\t}\n\n\twxLogMessage(\"Using language '%s'.\", wxLocale::GetLanguageName(lang));\n}\n\nvoid BodySlideApp::LoadAllCategories() {\n\twxLogMessage(\"Loading all slider categories...\");\n\tcCollection.Clear();\n\tcCollection.LoadCategories(GetProjectPath() + \"/SliderCategories\");\n}\n\nvoid BodySlideApp::SetPresetGroups(const std::string& setName) {\n\tpresetGroups.clear();\n\tgCollection.GetOutfitGroups(setName, presetGroups);\n\n\tif (presetGroups.empty()) {\n\t\tConfig.GetValueArray(\"DefaultGroups\", \"GroupName\", presetGroups);\n\t\tif (!presetGroups.empty()) {\n\t\t\twxString defaultGroups;\n\t\t\tfor (auto& group : presetGroups)\n\t\t\t\tdefaultGroups.Append(\"'\" + group + \"' \");\n\n\t\t\twxLogMessage(\"Using default group(s): %s\", defaultGroups);\n\t\t}\n\t\telse\n\t\t\twxLogMessage(\"No group assigned for set '%s'.\", setName);\n\t}\n\telse {\n\t\twxString groups;\n\t\tfor (auto& group : presetGroups)\n\t\t\tgroups.Append(\"'\" + group + \"' \");\n\n\t\twxLogMessage(\"Using group(s): %s\", groups);\n\t}\n}\n\nvoid BodySlideApp::LoadAllGroups() {\n\twxLogMessage(\"Loading all slider groups...\");\n\tgCollection.LoadGroups(GetProjectPath() + \"/SliderGroups\");\n\n\tungroupedOutfits.clear();\n\tfor (auto& o : outfitNameSource) {\n\t\tstd::vector<std::string> groups;\n\t\tgCollection.GetOutfitGroups(o.first, groups);\n\t\tif (groups.empty())\n\t\t\tungroupedOutfits.push_back(o.first);\n\t}\n\n\tstd::vector<std::string> aliases;\n\tConfig.GetValueAttributeArray(\"GroupAliases\", \"GroupAlias\", \"alias\", aliases);\n\tstd::vector<std::string> groups;\n\tConfig.GetValueAttributeArray(\"GroupAliases\", \"GroupAlias\", \"group\", groups);\n\n\tif (aliases.size() == groups.size())\n\t\tfor (size_t i = 0; i < aliases.size(); i++)\n\t\t\tgroupAlias[aliases[i]] = groups[i];\n}\n\nvoid BodySlideApp::GetAllGroupNames(std::vector<std::string>& outGroups) {\n\tstd::set<std::string> gNames;\n\tgCollection.GetAllGroups(gNames);\n\toutGroups.assign(gNames.begin(), gNames.end());\n}\n\nint BodySlideApp::SaveGroupList(const std::string& fileName, const std::string& groupName) {\n\tif (filteredOutfits.empty())\n\t\treturn 1;\n\n\tstd::vector<std::string> existing;\n\tSliderSetGroupFile outfile(fileName);\n\tif (outfile.GetError() != 0) {\n\t\tif (outfile.GetError() == 1)\n\t\t\toutfile.New(fileName);\n\n\t\tif (outfile.GetError() != 0) {\n\t\t\twxMessageBox(_(\"Failed to create group file.\"), _(\"Error\"), wxICON_ERROR);\n\t\t\treturn 5;\n\t\t}\n\t}\n\n\toutfile.GetGroupNames(existing);\n\tbool found = false;\n\tfor (auto& e : existing) {\n\t\tif (StringsEqualInsens(e.c_str(), groupName.c_str())) {\n\t\t\tfound = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (found) {\n\t\tint ret = wxMessageBox(_(\"That group already exists in the specified file, do you wish to overwrite the group?\"), _(\"Group already exists\"), wxYES_NO | wxCANCEL);\n\t\tif (ret == wxNO)\n\t\t\treturn 2;\n\t\telse if (ret == wxCANCEL)\n\t\t\treturn 3;\n\t}\n\n\tSliderSetGroup ssg;\n\tssg.SetName(groupName);\n\tssg.AddMembers(filteredOutfits);\n\n\toutfile.UpdateGroup(ssg);\n\toutfile.Save();\n\treturn 0;\n}\n\nvoid BodySlideApp::PopulateFilterData() {\n\tif (outfitHasZaps.empty())\n\t\tLoadSliderSets();\n}\n\nvoid BodySlideApp::ApplyOutfitFilter() {\n\tfilteredOutfits.clear();\n\n\tstd::unordered_set<std::string> grpFiltOutfits;\n\tstd::vector<std::string> workFilterList;\n\tstatic wxString lastGrps = \"\";\n\tstatic std::set<std::string> grouplist;\n\n\tbool showUngrouped = false;\n\tbool regexFilterOutfits = false;\n\tbool filterHasZaps = false;\n\n\tauto menuOutfitSrchContext = sliderView->outfitsearch->GetMenu();\n\tif (menuOutfitSrchContext) {\n\t\tauto menuRegexOutfits = menuOutfitSrchContext->FindItem(XRCID(\"menuRegexOutfits\"));\n\t\tif (menuRegexOutfits)\n\t\t\tregexFilterOutfits = menuRegexOutfits->IsChecked();\n\n\t\tauto menuFilterHasZaps = menuOutfitSrchContext->FindItem(XRCID(\"menuFilterHasZaps\"));\n\t\tif (menuFilterHasZaps)\n\t\t\tfilterHasZaps = menuFilterHasZaps->IsChecked();\n\t}\n\n\twxString grpSrch = sliderView->search->GetValue();\n\tstd::string outfitSrch{sliderView->outfitsearch->GetValue()};\n\n\tif (lastGrps != grpSrch) {\n\t\tgrouplist.clear();\n\t\tif (grpSrch.empty()) {\n\t\t\tgCollection.GetAllGroups(grouplist);\n\t\t\tshowUngrouped = true;\n\t\t}\n\t\telse {\n\t\t\twxStringTokenizer tokenizer(grpSrch, \",;\");\n\t\t\twhile (tokenizer.HasMoreTokens()) {\n\t\t\t\twxString token = tokenizer.GetNextToken();\n\t\t\t\ttoken.Trim();\n\t\t\t\ttoken.Trim(false);\n\t\t\t\tstd::string group = token.ToStdString();\n\t\t\t\tgrouplist.insert(group);\n\t\t\t}\n\t\t}\n\t\tlastGrps = grpSrch;\n\t}\n\telse if (lastGrps.empty()) {\n\t\tgCollection.GetAllGroups(grouplist);\n\t\tshowUngrouped = true;\n\t}\n\n\tfor (auto& gn : grouplist) {\n\t\tif (gn == \"Unassigned\")\n\t\t\tshowUngrouped = true;\n\t\telse\n\t\t\tgCollection.GetGroupMembers(gn, grpFiltOutfits);\n\t}\n\n\tif (showUngrouped)\n\t\tfor (auto& ug : ungroupedOutfits)\n\t\t\tgrpFiltOutfits.insert(ug);\n\n\tfor (auto& no : outfitNameOrder) {\n\t\tbool filteredOut = false;\n\n\t\tif (grpFiltOutfits.find(no) == grpFiltOutfits.end())\n\t\t\tfilteredOut = true;\n\n\t\tif (!filteredOut && filterHasZaps) {\n\t\t\tif (std::find(outfitHasZaps.cbegin(), outfitHasZaps.cend(), no) == outfitHasZaps.cend())\n\t\t\t\tfilteredOut = true;\n\t\t}\n\n\t\tif (!filteredOut)\n\t\t\tworkFilterList.push_back(no);\n\t}\n\n\n\tif (outfitSrch.empty()) {\n\t\tfor (auto& w : workFilterList)\n\t\t\tfilteredOutfits.push_back(w);\n\t}\n\telse {\n\t\twxString searchStr = wxString::FromUTF8(outfitSrch);\n\t\tsearchStr.MakeLower();\n\n\t\tif (regexFilterOutfits) {\n\t\t\tstd::regex re;\n\n\t\t\tfor (auto& filterEntry : workFilterList) {\n\t\t\t\ttry {\n\t\t\t\t\tre.assign(outfitSrch, std::regex::icase);\n\t\t\t\t\tif (std::regex_search(filterEntry, re))\n\t\t\t\t\t\tfilteredOutfits.push_back(filterEntry);\n\t\t\t\t}\n\t\t\t\tcatch (std::regex_error&) {\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor (auto& filterEntry : workFilterList) {\n\t\t\t\twxString entryStr = wxString::FromUTF8(filterEntry);\n\t\t\t\tif (entryStr.Lower().Contains(searchStr))\n\t\t\t\t\tfilteredOutfits.push_back(entryStr.ToUTF8().data());\n\t\t\t}\n\t\t}\n\t}\n\n\tBodySlideConfig.SetValue(\"LastGroupFilter\", grpSrch.ToUTF8().data());\n\tBodySlideConfig.SetValue(\"LastOutfitFilter\", outfitSrch);\n}\n\nstd::vector<std::string> BodySlideApp::ApplyPresetFilter(const std::vector<std::string>& presetNames) {\n\twxString presetSearchStr = sliderView->presetFilter->GetValue();\n\n\tstd::vector<std::string> filteredPresets;\n\n\tif (presetSearchStr.empty()) {\n\t\tfor (auto& w : presetNames)\n\t\t\tfilteredPresets.push_back(w);\n\t}\n\telse {\n\t\tpresetSearchStr.MakeLower();\n\n\t\tfor (auto& filterEntry : presetNames) {\n\t\t\twxString entryStr = wxString::FromUTF8(filterEntry);\n\t\t\tif (entryStr.Lower().Contains(presetSearchStr))\n\t\t\t\tfilteredPresets.push_back(entryStr.ToUTF8().data());\n\t\t}\n\t}\n\n\tBodySlideConfig.SetValue(\"LastPresetFilter\", presetSearchStr.ToUTF8().data());\n\treturn filteredPresets;\n}\n\nint BodySlideApp::GetOutfits(std::vector<std::string>& outList) {\n\toutList.assign(outfitNameOrder.begin(), outfitNameOrder.end());\n\treturn outList.size();\n}\n\nint BodySlideApp::GetFilteredOutfits(std::vector<std::string>& outList) {\n\toutList.assign(filteredOutfits.begin(), filteredOutfits.end());\n\treturn outList.size();\n}\n\nvoid BodySlideApp::LoadPresets(const std::string& sliderSet) {\n\tstd::string outfit = sliderSet;\n\tif (sliderSet.empty())\n\t\toutfit = BodySlideConfig[\"SelectedOutfit\"];\n\n\twxLogMessage(\"Loading assigned presets...\");\n\n\tstd::vector<std::string> groups_and_aliases;\n\tfor (auto& g : presetGroups) {\n\t\tgroups_and_aliases.push_back(g);\n\t\tfor (auto& ag : this->groupAlias)\n\t\t\tif (ag.second == g)\n\t\t\t\tgroups_and_aliases.push_back(ag.first);\n\t}\n\n\tsliderManager.LoadPresets(GetProjectPath() + \"/SliderPresets\", outfit, groups_and_aliases, groups_and_aliases.empty());\n}\n\nvoid BodySlideApp::GetPresetNames(std::vector<std::string>& outNames) {\n\tsliderManager.GetPresetNames(outNames);\n}\n\nvoid BodySlideApp::InitializeSliders(const std::string& presetName) {\n\tsliderManager.InitializeSliders(presetName);\n}\n\nint BodySlideApp::BuildBodies(bool localPath, bool clean, bool tri, bool forceNormals) {\n\tif (projects.empty())\n\t\treturn 1;\n\n\tauto& activeSet = GetActiveSet();\n\tstd::string inputFileName = activeSet.GetInputFileName();\n\tNifFile nifSmall;\n\tNifFile nifBig;\n\n\tstd::string outFileNameSmall;\n\tstd::string outFileNameBig;\n\n\twxLogMessage(\"Building set '%s' with options: Local Path = %s, Cleaning = %s, TRI = %s, GenWeights = %s\",\n\t\t\t\t activeSet.GetName(),\n\t\t\t\t localPath ? \"True\" : \"False\",\n\t\t\t\t clean ? \"True\" : \"False\",\n\t\t\t\t tri ? \"True\" : \"False\",\n\t\t\t\t activeSet.GenWeights() ? \"True\" : \"False\");\n\n\tif (localPath) {\n\t\toutFileNameSmall = outFileNameBig = activeSet.GetOutputFile();\n\t}\n\telse {\n\t\tif (GetOutputDataPath().empty()) {\n\t\t\tif (Config[\"WarnMissingGamePath\"] == \"true\") {\n\t\t\t\tint ret = wxMessageBox(_(\"WARNING: Game data path not configured. Would you like to show BodySlide where it is?\"),\n\t\t\t\t\t\t\t\t\t   _(\"Game not found\"),\n\t\t\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);\n\t\t\t\tif (ret != wxYES) {\n\t\t\t\t\twxLogMessage(\"Aborted build without data path.\");\n\t\t\t\t\treturn 4;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twxString response = wxDirSelector(_(\"Please choose a directory to set as your Data path\"), wxGetCwd());\n\t\t\tif (response.IsEmpty()) {\n\t\t\t\twxLogMessage(\"Aborted build without data path.\");\n\t\t\t\treturn 4;\n\t\t\t}\n\n\t\t\tresponse.Append(PathSepChar);\n\t\t\tConfig.SetValue(\"GameDataPath\", response.ToUTF8().data());\n\t\t}\n\n\t\toutFileNameSmall = GetOutputDataPath() + activeSet.GetOutputFilePath();\n\t\toutFileNameBig = outFileNameSmall;\n\t\twxString path = wxString::FromUTF8(GetOutputDataPath() + activeSet.GetOutputPath());\n\t\twxFileName::Mkdir(path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\t}\n\n\t// ALT key\n\tif (clean && !localPath) {\n\t\tint ret = wxMessageBox(_(\"WARNING: This will delete the output files from the output folder, potentially causing crashes.\\n\\nDo you want to continue?\"),\n\t\t\t\t\t\t\t   _(\"Clean Build\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);\n\t\tif (ret != wxYES) {\n\t\t\twxLogMessage(\"Aborted cleaning build.\");\n\t\t\treturn 4;\n\t\t}\n\n\t\twxString removeHigh, removeLow;\n\t\twxString msg = _(\"Removed the following files:\\n\");\n\t\tbool genWeights = activeSet.GenWeights();\n\n\t\tif (genWeights)\n\t\t\tremoveHigh = outFileNameSmall + \"_1.nif\";\n\t\telse\n\t\t\tremoveHigh = outFileNameSmall + \".nif\";\n\n\t\tbool remHigh = wxRemoveFile(wxString::FromUTF8(removeHigh));\n\t\tif (remHigh)\n\t\t\tmsg.Append(removeHigh + \"\\n\");\n\t\telse\n\t\t\tmsg.Append(removeHigh + _(\" (no action)\\n\"));\n\n\t\tif (!genWeights) {\n\t\t\twxLogMessage(\"%s\", msg);\n\t\t\twxMessageBox(msg, _(\"Process Successful\"));\n\t\t\treturn 0;\n\t\t}\n\n\t\tremoveLow = outFileNameSmall + \"_0.nif\";\n\t\tbool remLow = wxRemoveFile(wxString::FromUTF8(removeLow));\n\t\tif (remLow)\n\t\t\tmsg.Append(removeLow + \"\\n\");\n\t\telse\n\t\t\tmsg.Append(removeLow + _(\" (no action)\\n\"));\n\n\t\twxLogMessage(\"%s\", msg);\n\t\twxMessageBox(msg, _(\"Process Successful\"));\n\t\treturn 0;\n\t}\n\n\trefNormalsCache.clear();\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, inputFileName, std::ios::in | std::ios::binary);\n\n\tint error = nifBig.Load(file);\n\tif (error) {\n\t\twxLogError(\"Failed to load '%s' (%d)!\", inputFileName, error);\n\t\treturn 1;\n\t}\n\n\tif (activeSet.GenWeights())\n\t\tnifSmall.CopyFrom(nifBig);\n\n\tauto& dataSets = GetActiveDataSets();\n\tdataSets.Clear();\n\tactiveSet.LoadSetDiffData(dataSets);\n\n\tbool keepZappedShapes = activeSet.KeepZappedShapes();\n\n\tstd::vector<Vector3> vertsLow;\n\tstd::vector<Vector3> vertsHigh;\n\tstd::vector<Vector2> uvsLow;\n\tstd::vector<Vector2> uvsHigh;\n\tstd::vector<uint16_t> zapIdx;\n\tstd::unordered_map<std::string, std::vector<uint16_t>> zapIdxAll;\n\n\t// Phase 1: Apply sliders and set vertices for all shapes\n\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it) {\n\t\tauto shape = nifBig.FindBlockByName<NiShape>(it->first);\n\t\tif (!nifBig.GetVertsForShape(shape, vertsHigh))\n\t\t\tcontinue;\n\n\t\tnifBig.GetUvsForShape(shape, uvsHigh);\n\n\t\tif (activeSet.GenWeights()) {\n\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\tif (!nifSmall.GetVertsForShape(shapeSmall, vertsLow))\n\t\t\t\tcontinue;\n\n\t\t\tnifSmall.GetUvsForShape(shapeSmall, uvsLow);\n\t\t}\n\n\t\tzapIdxAll.emplace(it->first, std::vector<uint16_t>());\n\n\t\tApplySliders(it->second.targetShape, sliderManager.slidersBig, dataSets, vertsHigh, zapIdx, &uvsHigh);\n\t\tnifBig.SetVertsForShape(shape, vertsHigh);\n\t\tnifBig.SetUvsForShape(shape, uvsHigh);\n\n\t\tif (activeSet.GenWeights()) {\n\t\t\tzapIdx.clear();\n\t\t\tApplySliders(it->second.targetShape, sliderManager.slidersSmall, dataSets, vertsLow, zapIdx, &uvsLow);\n\n\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\tnifSmall.SetVertsForShape(shapeSmall, vertsLow);\n\t\t\tnifSmall.SetUvsForShape(shapeSmall, uvsLow);\n\t\t}\n\n\t\tzapIdxAll[it->first] = zapIdx;\n\t\tzapIdx.clear();\n\t}\n\n\t// Phase 2: Apply clipping fix when strength is above zero\n\tif (clippingFixStrength > 0.0f) {\n\t\tauto refShape = ClippingFixer::FindReferenceShape(nifBig);\n\t\tif (refShape) {\n\t\t\tstd::vector<Vector3> bodyVerts;\n\t\t\tstd::vector<Triangle> bodyTris;\n\t\t\tnifBig.GetVertsForShape(refShape, bodyVerts);\n\t\t\trefShape->GetTriangles(bodyTris);\n\n\t\t\tif (!bodyVerts.empty() && !bodyTris.empty()) {\n\t\t\t\tClippingFixOptions fixOpts;\n\t\t\t\tfixOpts.strength = clippingFixStrength / 100.0f;\n\n\t\t\t\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it) {\n\t\t\t\t\tauto shape = nifBig.FindBlockByName<NiShape>(it->first);\n\t\t\t\t\tif (!shape || shape == refShape)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tstd::vector<Vector3> outfitVerts;\n\t\t\t\t\tstd::vector<Triangle> outfitTris;\n\t\t\t\t\tif (!nifBig.GetVertsForShape(shape, outfitVerts))\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tshape->GetTriangles(outfitTris);\n\n\t\t\t\t\tClippingFixer::FixClipping(bodyVerts, bodyTris, outfitVerts, outfitTris, fixOpts);\n\t\t\t\t\tnifBig.SetVertsForShape(shape, outfitVerts);\n\t\t\t\t}\n\n\t\t\t\t// Also fix the small/low weight NIF\n\t\t\t\tif (activeSet.GenWeights()) {\n\t\t\t\t\tauto refShapeSmall = nifSmall.FindBlockByName<NiShape>(refShape->name.get());\n\t\t\t\t\tif (refShapeSmall) {\n\t\t\t\t\t\tstd::vector<Vector3> bodyVertsSmall;\n\t\t\t\t\t\tstd::vector<Triangle> bodyTrisSmall;\n\t\t\t\t\t\tnifSmall.GetVertsForShape(refShapeSmall, bodyVertsSmall);\n\t\t\t\t\t\trefShapeSmall->GetTriangles(bodyTrisSmall);\n\n\t\t\t\t\t\tif (!bodyVertsSmall.empty() && !bodyTrisSmall.empty()) {\n\t\t\t\t\t\t\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it) {\n\t\t\t\t\t\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\t\t\t\t\t\tif (!shapeSmall || shapeSmall == refShapeSmall)\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\tstd::vector<Vector3> outfitVerts;\n\t\t\t\t\t\t\t\tstd::vector<Triangle> outfitTris;\n\t\t\t\t\t\t\t\tif (!nifSmall.GetVertsForShape(shapeSmall, outfitVerts))\n\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\tshapeSmall->GetTriangles(outfitTris);\n\n\t\t\t\t\t\t\t\tClippingFixer::FixClipping(bodyVertsSmall, bodyTrisSmall, outfitVerts, outfitTris, fixOpts);\n\t\t\t\t\t\t\t\tnifSmall.SetVertsForShape(shapeSmall, outfitVerts);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Phase 3: Recalculate normals, tangents, and handle zapping\n\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it) {\n\t\tauto shape = nifBig.FindBlockByName<NiShape>(it->first);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\tif (!nifBig.GetVertsForShape(shape, vertsHigh))\n\t\t\tcontinue;\n\n\t\tif (!it->second.lockNormals) {\n\t\t\tnifBig.CalcNormalsForShape(shape, forceNormals, it->second.smoothSeamNormals);\n\n\t\t\tif (forceNormals)\n\t\t\t\tApplyReferenceNormals(nifBig);\n\t\t}\n\n\t\tnifBig.CalcTangentsForShape(shape);\n\n\t\tauto zapIt = zapIdxAll.find(it->first);\n\t\tauto& shapeZapIdx = zapIt != zapIdxAll.end() ? zapIt->second : zapIdx;\n\n\t\tif (keepZappedShapes && shapeZapIdx.size() == vertsHigh.size()) {\n\t\t\tshape->flags |= 1; // Set hidden flag when shape would otherwise be fully zapped\n\t\t}\n\t\telse {\n\t\t\tif (nifBig.DeleteVertsForShape(shape, shapeZapIdx))\n\t\t\t\tnifBig.DeleteShape(shape); // Delete fully zapped shape\n\t\t}\n\n\t\tif (activeSet.GenWeights()) {\n\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\tif (!shapeSmall)\n\t\t\t\tcontinue;\n\n\t\t\tif (!nifSmall.GetVertsForShape(shapeSmall, vertsLow))\n\t\t\t\tcontinue;\n\n\t\t\tif (!it->second.lockNormals) {\n\t\t\t\tnifSmall.CalcNormalsForShape(shapeSmall, forceNormals, it->second.smoothSeamNormals);\n\n\t\t\t\tif (forceNormals)\n\t\t\t\t\tApplyReferenceNormals(nifSmall);\n\t\t\t}\n\n\t\t\tnifSmall.CalcTangentsForShape(shapeSmall);\n\n\t\t\tif (keepZappedShapes && shapeZapIdx.size() == vertsLow.size()) {\n\t\t\t\tshapeSmall->flags |= 1; // Set hidden flag when shape would otherwise be fully zapped\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (nifSmall.DeleteVertsForShape(shapeSmall, shapeZapIdx))\n\t\t\t\t\tnifSmall.DeleteShape(shapeSmall); // Delete fully zapped shape\n\t\t\t}\n\t\t}\n\t}\n\n\tbool triKeep = activeSet.PreventMorphFile();\n\n\tif (tri && !triKeep) {\n\t\tstd::string triFilePath = outFileNameBig + \".tri\";\n\n\t\t// TRI file already exists but isn't a body TRI file, don't overwrite!\n\t\tif (wxFileName::FileExists(wxString::FromUTF8(triFilePath)) && !IsBodyTriFile(triFilePath))\n\t\t\ttriKeep = true;\n\t}\n\n\t/* Add TRI path for in-game morphs */\n\tif (tri && !triKeep) {\n\t\tstd::string triPath = activeSet.GetOutputFilePath() + \".tri\";\n\t\tstd::string triPathTrimmed = triPath;\n\t\t// Replace multiple backslashes or forward slashes with one backslash\n\t\ttriPathTrimmed = std::regex_replace(triPathTrimmed, std::regex(\"/+|\\\\\\\\+\"), \"\\\\\");\n\n\t\t// Remove everything before and including the meshes path\n\t\ttriPathTrimmed = std::regex_replace(triPathTrimmed, std::regex(\".*meshes\\\\\\\\\", std::regex_constants::icase), \"\");\n\n\t\tif (!WriteMorphTRI(outFileNameBig, activeSet, nifBig, zapIdxAll)) {\n\t\t\twxLogError(\"Failed to write TRI file to '%s'!\", triPath);\n\t\t\twxMessageBox(wxString().Format(_(\"Failed to write TRI file to the following location\\n\\n%s\"), triPath), _(\"Unable to process\"), wxOK | wxICON_ERROR);\n\t\t}\n\n\t\tif (targetGame != FO4 && targetGame != FO4VR && targetGame != FO76) {\n\t\t\tfor (auto targetShape = activeSet.ShapesBegin(); targetShape != activeSet.ShapesEnd(); ++targetShape) {\n\t\t\t\tauto shape = nifBig.FindBlockByName<NiShape>(targetShape->first);\n\t\t\t\tif (!shape)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (tri && shape->GetNumVertices() > 0) {\n\t\t\t\t\tAddTriData(nifBig, targetShape->first, triPathTrimmed);\n\t\t\t\t\tif (activeSet.GenWeights())\n\t\t\t\t\t\tAddTriData(nifSmall, targetShape->first, triPathTrimmed);\n\n\t\t\t\t\ttri = false;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tAddTriData(nifBig, \"\", triPathTrimmed, true);\n\t\t\tif (activeSet.GenWeights())\n\t\t\t\tAddTriData(nifSmall, \"\", triPathTrimmed, true);\n\t\t}\n\n\t\t// Set all shapes to dynamic/mutable\n\t\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it) {\n\t\t\tnifBig.SetShapeDynamic(it->first);\n\t\t\tif (activeSet.GenWeights())\n\t\t\t\tnifSmall.SetShapeDynamic(it->first);\n\t\t}\n\t}\n\telse if (!triKeep) {\n\t\twxString triPath = wxString::FromUTF8(outFileNameBig + \".tri\");\n\t\tif (IsBodyTriFile(triPath.ToUTF8().data()))\n\t\t\twxRemoveFile(triPath);\n\t}\n\n\twxString savedLow;\n\twxString savedHigh;\n\twxString custName;\n\tbool useCustName = false;\n\n\tNifSaveOptions nifOptions;\n\tnifOptions.optimize = false;\n\n\tif (activeSet.GenWeights()) {\n\t\toutFileNameSmall += \"_0.nif\";\n\t\toutFileNameBig += \"_1.nif\";\n\t\tcustName = wxString::FromUTF8(outFileNameSmall);\n\t\tsavedLow = custName;\n\n\t\tstd::fstream fileSmall;\n\t\tPlatformUtil::OpenFileStream(fileSmall, custName.ToUTF8().data(), std::ios::out | std::ios::binary);\n\n\t\twhile (nifSmall.Save(fileSmall, nifOptions)) {\n\t\t\twxLogError(\"Failed to build set to '%s'! Asking for new location.\", custName);\n\t\t\twxMessageBox(wxString().Format(_(\"Failed to build set to the following location\\n\\n%s\"), custName), _(\"Unable to process\"), wxOK | wxICON_ERROR);\n\n\t\t\tcustName = wxSaveFileSelector(_(\"Choose alternate file name\"), \"*.nif\", custName);\n\t\t\tif (custName.IsEmpty()) {\n\t\t\t\twxLogMessage(\"Aborted build when choosing alternate file name.\");\n\t\t\t\treturn 4;\n\t\t\t}\n\n\t\t\tuseCustName = true;\n\t\t\tsavedLow = custName;\n\n\t\t\tPlatformUtil::OpenFileStream(fileSmall, custName.ToUTF8().data(), std::ios::out | std::ios::binary);\n\t\t}\n\n\t\twxString custEnd;\n\t\tif (custName.EndsWith(\"_0.nif\", &custEnd))\n\t\t\tcustName = custEnd + \"_1.nif\";\n\t\telse\n\t\t\tcustName.Empty();\n\t}\n\telse {\n\t\toutFileNameBig += \".nif\";\n\t\tcustName = wxString::FromUTF8(outFileNameBig);\n\t}\n\n\tif (!useCustName)\n\t\toutFileNameBig = custName.ToUTF8();\n\n\tsavedHigh = custName;\n\n\tstd::fstream fileBig;\n\tPlatformUtil::OpenFileStream(fileBig, custName.ToUTF8().data(), std::ios::out | std::ios::binary);\n\n\twhile (nifBig.Save(fileBig, nifOptions)) {\n\t\twxLogError(\"Failed to build set to '%s'! Asking for new location.\", custName);\n\t\twxMessageBox(wxString().Format(_(\"Failed to build set to the following location\\n\\n%s\"), custName), _(\"Unable to process\"), wxOK | wxICON_ERROR);\n\n\t\tcustName = wxSaveFileSelector(_(\"Choose alternate file name\"), \"*.nif\", custName);\n\t\tif (custName.IsEmpty()) {\n\t\t\twxLogMessage(\"Aborted build when choosing alternate file name.\");\n\t\t\treturn 4;\n\t\t}\n\n\t\tuseCustName = true;\n\t\tsavedHigh = custName;\n\n\t\tPlatformUtil::OpenFileStream(fileBig, custName.ToUTF8().data(), std::ios::out | std::ios::binary);\n\t}\n\n\twxString msg = _(\"Successfully processed the following files:\\n\");\n\tif (!savedLow.IsEmpty())\n\t\tmsg.Append(savedLow += \"\\n\");\n\n\tif (!savedHigh.IsEmpty())\n\t\tmsg.Append(savedHigh);\n\n\twxLogMessage(\"%s\", msg);\n\twxMessageBox(msg, _(\"Process Successful\"));\n\treturn 0;\n}\n\nint BodySlideApp::ShowBuildOverrideWithPreview(wxDialog* dlg, wxTreeListCtrl* treeListCtrl) {\n\t// Save the main app state so the conflicts preview doesn't corrupt it.\n\t// LoadProjects() -> CleanupPreview() -> AddProjectSliders() all operate on\n\t// shared app members (projects, sliderManager, multiProjectMode).\n\tPreviewPanel* savedPreview = preview;\n\tPreviewWindow* savedPreviewWindow = previewWindow;\n\tauto savedProjects = std::move(projects);\n\tbool savedMultiProjectMode = multiProjectMode;\n\tSliderManager savedSliderManager;\n\tstd::swap(sliderManager, savedSliderManager);\n\tmultiProjectMode = false;\n\tpreview = nullptr;\n\tpreviewWindow = nullptr;\n\n\tPreviewWindow* conflictsPreviewWnd = nullptr;\n\n\tauto closeConflictsPreview = [&]() {\n\t\tif (!conflictsPreviewWnd)\n\t\t\treturn;\n\t\tif (previewWindow == conflictsPreviewWnd)\n\t\t\tCleanupPreview();\n\t\tauto* wnd = conflictsPreviewWnd;\n\t\tconflictsPreviewWnd = nullptr;\n\t\tpreviewWindow = nullptr;\n\t\tpreview = nullptr;\n\t\twnd->Destroy();\n\t};\n\n\twxButton* btnPreviewConflicts = XRCCTRL(*dlg, \"btnPreviewConflicts\", wxButton);\n\tif (btnPreviewConflicts) {\n\t\tbtnPreviewConflicts->Bind(wxEVT_BUTTON, [&](wxCommandEvent& WXUNUSED(event)) {\n\t\t\twxTreeListItem sel = treeListCtrl->GetSelection();\n\t\t\tif (!sel.IsOk())\n\t\t\t\treturn;\n\n\t\t\t// Walk up to the group root (level 1) if a child is selected\n\t\t\twxTreeListItem groupItem = sel;\n\t\t\twxTreeListItem parent = treeListCtrl->GetItemParent(sel);\n\t\t\tif (parent.IsOk() && parent != treeListCtrl->GetRootItem())\n\t\t\t\tgroupItem = parent;\n\n\t\t\t// Build preview entries from all children in this group\n\t\t\tstd::vector<PreviewProjectEntry> entries;\n\t\t\tfor (wxTreeListItem child = treeListCtrl->GetFirstChild(groupItem); child.IsOk(); child = treeListCtrl->GetNextSibling(child)) {\n\t\t\t\tstd::string outfitName = treeListCtrl->GetItemText(child).ToUTF8().data();\n\t\t\t\tauto src = outfitNameSource.find(outfitName);\n\t\t\t\tif (src != outfitNameSource.end())\n\t\t\t\t\tentries.push_back({src->second, outfitName});\n\t\t\t}\n\n\t\t\tif (entries.empty())\n\t\t\t\treturn;\n\n\t\t\tcloseConflictsPreview();\n\n\t\t\t// Open a new standalone preview window\n\t\t\twxSize previewSize = dlg->FromDIP(wxSize(800, 600));\n\t\t\tconflictsPreviewWnd = new PreviewWindow(wxDefaultPosition, previewSize, this);\n\t\t\tpreviewWindow = conflictsPreviewWnd;\n\t\t\tpreview = conflictsPreviewWnd->GetPanel();\n\n\t\t\t// Handle user closing the preview window via X button.\n\t\t\t// Must cancel the async load thread before the panel is destroyed,\n\t\t\t// otherwise the CallAfter callback could target the wrong panel.\n\t\t\tconflictsPreviewWnd->Bind(wxEVT_CLOSE_WINDOW, [&](wxCloseEvent&) {\n\t\t\t\tcloseConflictsPreview();\n\t\t\t});\n\n\t\t\twxString title = wxString::Format(_(\"Preview - %s\"), wxString::FromUTF8(treeListCtrl->GetItemText(groupItem)));\n\t\t\tconflictsPreviewWnd->SetTitle(title);\n\n\t\t\tstd::string baseGamePath = Config[\"GameDataPath\"];\n\t\t\tpreview->SetBaseDataPath(baseGamePath);\n\t\t\tpreview->SetReadOnlyMode(true);\n\t\t\tpreview->SetProjectData(entries, false);\n\t\t});\n\t}\n\n\tint result = dlg->ShowModal();\n\n\tcloseConflictsPreview();\n\n\t// Restore main app state\n\tpreviewWindow = savedPreviewWindow;\n\tpreview = savedPreview;\n\tprojects = std::move(savedProjects);\n\tmultiProjectMode = savedMultiProjectMode;\n\tstd::swap(sliderManager, savedSliderManager);\n\n\treturn result;\n}\n\nint BodySlideApp::BuildListBodies(\n\tstd::vector<std::string>& outfitList, std::map<std::string, std::string>& failedOutfits, bool clean, bool tri, bool forceNormals, const std::string& custPath) {\n\tstd::string datapath = custPath;\n\n\twxLogMessage(\"Started batch build with options: Custom Path = %s, Cleaning = %s, TRI = %s\",\n\t\t\t\t custPath.empty() ? \"False\" : custPath,\n\t\t\t\t clean ? \"True\" : \"False\",\n\t\t\t\t tri ? \"True\" : \"False\");\n\n\tif (clean) {\n\t\tint ret = wxMessageBox(_(\"WARNING: This will delete the output files from the output folders, potentially causing crashes.\\n\\nDo you want to continue?\"),\n\t\t\t\t\t\t\t   _(\"Clean Batch Build\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);\n\t\tif (ret != wxYES) {\n\t\t\twxLogMessage(\"Aborted cleaning batch build.\");\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\tstd::string activePreset = BodySlideConfig[\"SelectedPreset\"];\n\n\tif (datapath.empty()) {\n\t\tif (GetOutputDataPath().empty()) {\n\t\t\tif (clean) {\n\t\t\t\twxLogError(\"Aborted batch clean with unconfigured data path. Files can't be removed that way.\");\n\t\t\t\twxMessageBox(_(\"WARNING: Game data path not configured. Files can't be removed that way.\"), _(\"Game not found\"), wxOK | wxICON_ERROR);\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\tif (Config[\"WarnMissingGamePath\"] == \"true\") {\n\t\t\t\tint ret = wxMessageBox(_(\"WARNING: Game data path not configured. Continue saving files to the working directory?\"),\n\t\t\t\t\t\t\t\t\t   _(\"Game not found\"),\n\t\t\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);\n\t\t\t\tif (ret != wxYES) {\n\t\t\t\t\twxLogError(\"Aborted batch build with unconfigured data path.\");\n\t\t\t\t\treturn 1;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tConfig.SetValue(\"GameDataPath\", Config[\"AppDir\"] + PathSepStr);\n\t\t}\n\n\t\tdatapath = GetOutputDataPath();\n\t}\n\n\tif (Config.MatchValue(\"WarnBatchBuildOverride\", \"true\")) {\n\t\tstd::vector<std::string> outFileList;\n\t\tstd::vector<wxArrayString> choicesList;\n\t\tfor (auto& outFile : outFileCount) {\n\t\t\tif (outFile.second.size() > 1) {\n\t\t\t\twxArrayString selOutfits;\n\t\t\t\tfor (auto& outfit : outFile.second) {\n\t\t\t\t\t// Only if it's going to be batch built\n\t\t\t\t\tif (std::find(outfitList.begin(), outfitList.end(), outfit) != outfitList.end())\n\t\t\t\t\t\tselOutfits.Add(wxString::FromUTF8(outfit));\n\t\t\t\t}\n\n\t\t\t\t// Same file would not be written more than once\n\t\t\t\tif (selOutfits.size() <= 1)\n\t\t\t\t\tcontinue;\n\n\t\t\t\toutFileList.push_back(outFile.first);\n\t\t\t\tchoicesList.push_back(selOutfits);\n\t\t\t}\n\t\t}\n\n\t\tif (!choicesList.empty()) {\n\t\t\t// Load BuildSelection file or create new one\n\t\t\tBuildSelectionFile buildSelFile;\n\t\t\tBuildSelection buildSelection;\n\t\t\tGetBuildSelection(buildSelFile, buildSelection);\n\n\t\t\twxXmlResource* rsrc = wxXmlResource::Get();\n\t\t\twxDialog* dlgBuildOverride = rsrc->LoadDialog(sliderView, \"dlgBuildOverride\");\n\t\t\tdlgBuildOverride->SetSize(dlgBuildOverride->FromDIP(wxSize(800, 400)));\n\t\t\tdlgBuildOverride->SetSizeHints(dlgBuildOverride->FromDIP(wxSize(400, 400)), dlgBuildOverride->FromDIP(wxSize(-1, -1)));\n\t\t\tdlgBuildOverride->CenterOnParent();\n\n\t\t\twxScrolledWindow* scrollOverrides = XRCCTRL(*dlgBuildOverride, \"scrollOverrides\", wxScrolledWindow);\n\t\t\twxBoxSizer* choicesSizer = (wxBoxSizer*)scrollOverrides->GetSizer();\n\n\t\t\t// Create the treelist with checkbox support\n\t\t\tauto treeListCtrl = new wxTreeListCtrl(scrollOverrides, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE | wxTL_CHECKBOX | wxTL_3STATE);\n\t\t\ttreeListCtrl->AppendColumn(_(\"Choice\"), wxCOL_WIDTH_AUTOSIZE, wxALIGN_LEFT);\n\t\t\ttreeListCtrl->AppendColumn(_(\"Source File\"), wxCOL_WIDTH_AUTOSIZE, wxALIGN_LEFT);\n\n\t\t\t// Add root items directly under the (hidden) root\n\t\t\tfor (size_t i = 0; i < choicesList.size(); i++) {\n\t\t\t\tauto& outFile = outFileList[i];\n\t\t\t\tauto& choices = choicesList[i];\n\n\t\t\t\twxTreeListItem rootItem = treeListCtrl->AppendItem(treeListCtrl->GetRootItem(), wxString::FromUTF8(outFile));\n\t\t\t\ttreeListCtrl->CheckItem(rootItem, wxCheckBoxState::wxCHK_UNDETERMINED);\n\n\t\t\t\t// Add children with checkboxes\n\t\t\t\tfor (size_t j = 0; j < choices.size(); j++) {\n\t\t\t\t\twxString choice = choices[j];\n\t\t\t\t\twxString defaultSet;\n\n\t\t\t\t\t// Check previous choices to see if radio button should be checked by default\n\t\t\t\t\tstd::string outputChoice = buildSelection.GetOutputChoice(outFile);\n\t\t\t\t\tif (!outputChoice.empty()) {\n\t\t\t\t\t\twxString c = wxString::FromUTF8(outputChoice);\n\t\t\t\t\t\tif (choices.Index(c) != wxNOT_FOUND)\n\t\t\t\t\t\t\tdefaultSet = c;\n\t\t\t\t\t}\n\n\t\t\t\t\twxTreeListItem child = treeListCtrl->AppendItem(rootItem, choice);\n\n\t\t\t\t\tauto outfitSrc = outfitNameSource.find(choice.ToUTF8().data());\n\t\t\t\t\tif (outfitSrc != outfitNameSource.end()) {\n\t\t\t\t\t\twxFileName outfitFileName(wxString::FromUTF8(outfitSrc->second));\n\t\t\t\t\t\ttreeListCtrl->SetItemText(child, 1, outfitFileName.GetFullName());\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\ttreeListCtrl->SetItemText(child, 1, _(\"<no source>\"));\n\n\t\t\t\t\tif (!defaultSet.IsEmpty() && choice == defaultSet)\n\t\t\t\t\t\ttreeListCtrl->CheckItem(child, wxCheckBoxState::wxCHK_CHECKED);\n\t\t\t\t\telse\n\t\t\t\t\t\ttreeListCtrl->CheckItem(child, wxCheckBoxState::wxCHK_UNCHECKED);\n\t\t\t\t}\n\n\t\t\t\ttreeListCtrl->Expand(rootItem);\n\t\t\t}\n\t\t\t\n\t\t\tbool checkBoxReverting = false;\n\t\t\tauto handler = [&](wxTreeListEvent& e) {\n\t\t\t\tif (checkBoxReverting) {\n\t\t\t\t\te.Skip();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst wxTreeListItem item = e.GetItem();\n\t\t\t\tconst wxTreeListItem parent = treeListCtrl->GetItemParent(item);\n\n\t\t\t\t// Level 1 items are direct children of the (hidden) root: make them non-checkable.\n\t\t\t\tif (parent == treeListCtrl->GetRootItem()) {\n\t\t\t\t\tcheckBoxReverting = true;\n\t\t\t\t\ttreeListCtrl->CheckItem(item, wxCheckBoxState::wxCHK_UNDETERMINED);\n\t\t\t\t\tcheckBoxReverting = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Only enforce the 'radio per level' rule for level-2 items:\n\t\t\t\tcheckBoxReverting = true;\n\n\t\t\t\tauto checkedState = treeListCtrl->GetCheckedState(item);\n\t\t\t\tif (checkedState == wxCheckBoxState::wxCHK_CHECKED) {\n\t\t\t\t\t// Uncheck all siblings\n\t\t\t\t\tfor (wxTreeListItem sib = treeListCtrl->GetFirstChild(parent); sib.IsOk(); sib = treeListCtrl->GetNextSibling(sib)) {\n\t\t\t\t\t\tif (sib != item && treeListCtrl->GetCheckedState(sib) == wxCheckBoxState::wxCHK_CHECKED)\n\t\t\t\t\t\t\ttreeListCtrl->CheckItem(sib, wxCheckBoxState::wxCHK_UNCHECKED);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (checkedState == wxCheckBoxState::wxCHK_UNCHECKED) {\n\t\t\t\t\t// Ensure at least one remains checked in this level\n\t\t\t\t\tbool anyChecked = false;\n\t\t\t\t\tfor (wxTreeListItem sib = treeListCtrl->GetFirstChild(parent); sib.IsOk(); sib = treeListCtrl->GetNextSibling(sib)) {\n\t\t\t\t\t\tif (treeListCtrl->GetCheckedState(sib) == wxCheckBoxState::wxCHK_CHECKED) {\n\t\t\t\t\t\t\tanyChecked = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!anyChecked) {\n\t\t\t\t\t\t// Re-check the one user tried to uncheck\n\t\t\t\t\t\ttreeListCtrl->CheckItem(item, wxCheckBoxState::wxCHK_CHECKED);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcheckBoxReverting = false;\n\t\t\t\te.Skip();\n\t\t\t};\n\n\t\t\ttreeListCtrl->Bind(wxEVT_TREELIST_ITEM_CHECKED, handler);\n\n\t\t\twxTextCtrl* chooseText = XRCCTRL(*dlgBuildOverride, \"chooseText\", wxTextCtrl);\n\t\t\tif (chooseText) {\n\t\t\t\tchooseText->Bind(wxEVT_TEXT_ENTER, [&](wxCommandEvent& WXUNUSED(event)) {\n\t\t\t\t\twxString text = chooseText->GetValue().MakeLower();\n\t\t\t\t\tif (!text.IsEmpty()) {\n\t\t\t\t\t\twxTreeListItem root = treeListCtrl->GetRootItem();\n\n\t\t\t\t\t\tfor (wxTreeListItem level1 = treeListCtrl->GetFirstChild(root); level1.IsOk(); level1 = treeListCtrl->GetNextSibling(level1)) {\n\t\t\t\t\t\t\twxTreeListItem firstMatch;\n\n\t\t\t\t\t\t\t// Find first matching item\n\t\t\t\t\t\t\tfor (wxTreeListItem level2 = treeListCtrl->GetFirstChild(level1); level2.IsOk(); level2 = treeListCtrl->GetNextSibling(level2)) {\n\t\t\t\t\t\t\t\twxString label = treeListCtrl->GetItemText(level2).Lower();\n\n\t\t\t\t\t\t\t\tif (label.Contains(text)) {\n\t\t\t\t\t\t\t\t\tfirstMatch = level2;\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif (firstMatch.IsOk()) {\n\t\t\t\t\t\t\t\t// Check the matched item\n\t\t\t\t\t\t\t\ttreeListCtrl->CheckItem(firstMatch, wxCheckBoxState::wxCHK_CHECKED);\n\n\t\t\t\t\t\t\t\t// Uncheck all siblings except the matched one\n\t\t\t\t\t\t\t\tfor (wxTreeListItem level2 = treeListCtrl->GetFirstChild(level1); level2.IsOk(); level2 = treeListCtrl->GetNextSibling(level2)) {\n\t\t\t\t\t\t\t\t\tif (level2 != firstMatch)\n\t\t\t\t\t\t\t\t\t\ttreeListCtrl->CheckItem(level2, wxCheckBoxState::wxCHK_UNCHECKED);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// else: no match found, do nothing / keep existing checks\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tchoicesSizer->Add(treeListCtrl, 1, wxEXPAND, 0);\n\t\t\tscrollOverrides->FitInside();\n\n\t\t\tif (ShowBuildOverrideWithPreview(dlgBuildOverride, treeListCtrl) == wxID_CANCEL) {\n\t\t\t\twxLogMessage(\"Aborted batch build by not choosing a file override.\");\n\t\t\t\tdelete dlgBuildOverride;\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\twxTreeListItem root = treeListCtrl->GetRootItem();\n\n\t\t\t// Iterate level 1 roots (should correspond to choicesList size)\n\t\t\tsize_t index = 0;\n\t\t\tfor (wxTreeListItem level1 = treeListCtrl->GetFirstChild(root); level1.IsOk() && index < choicesList.size(); level1 = treeListCtrl->GetNextSibling(level1), ++index) {\n\t\t\t\twxString checkedItemText;\n\n\t\t\t\t// Find the checked child (level 2)\n\t\t\t\tfor (wxTreeListItem level2 = treeListCtrl->GetFirstChild(level1); level2.IsOk(); level2 = treeListCtrl->GetNextSibling(level2)) {\n\t\t\t\t\tif (treeListCtrl->GetCheckedState(level2) == wxCheckBoxState::wxCHK_CHECKED) {\n\t\t\t\t\t\tcheckedItemText = treeListCtrl->GetItemText(level2);\n\t\t\t\t\t\tbreak; // assuming only one checked per level 1\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!checkedItemText.IsEmpty()) {\n\t\t\t\t\twxString choiceSel = checkedItemText;\n\n\t\t\t\t\t// Add output choice to file\n\t\t\t\t\tbuildSelection.SetOutputChoice(outFileList[index], choiceSel.ToUTF8().data());\n\n\t\t\t\t\t// Remove the selected choice from choicesList[i]\n\t\t\t\t\tchoicesList[index].Remove(choiceSel);\n\n\t\t\t\t\t// Remove from outfitList all outfits in choicesList[index]\n\t\t\t\t\tfor (auto& outfit : choicesList[index]) {\n\t\t\t\t\t\tauto result = std::find(outfitList.begin(), outfitList.end(), outfit.ToUTF8());\n\t\t\t\t\t\tif (result != outfitList.end())\n\t\t\t\t\t\t\toutfitList.erase(result);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t\tdelete dlgBuildOverride;\n\n\t\t\t// Save output choices to file\n\t\t\tbuildSelFile.UpdateOutputChoices(buildSelection);\n\t\t\tbuildSelFile.Save();\n\t\t}\n\t}\n\n\trefNormalsCache.clear();\n\n\twxProgressDialog progWnd(_(\"Processing Outfits\"), _(\"Starting...\"), 1000, sliderView, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_ELAPSED_TIME);\n\tprogWnd.SetSize(400, 150);\n\tfloat progstep = 1000.0f / outfitList.size();\n\tstd::atomic<int> count = 0;\n\n#ifdef _PPL_H\n\tconcurrency::concurrent_unordered_map<std::string, std::string> failedOutfitsCon;\n#else\n\tstd::unordered_map<std::string, std::string> failedOutfitsCon;\n#endif\n\n\tauto buildOutfit = [&](const std::string& outfit) {\n\t\twxString progMsg = wxString::Format(_(\"Processing '%s' (%d of %d)...\"), wxString::FromUTF8(outfit), ++count, (int)outfitList.size());\n\t\tprogWnd.Update((int)(count * progstep) - 1, progMsg);\n\t\tprogWnd.Fit();\n\n\t\twxLogMessage(progMsg);\n\n\t\t/* Load set */\n\t\tif (outfitNameSource.find(outfit) == outfitNameSource.end()) {\n\t\t\tfailedOutfitsCon[outfit] = _(\"No recorded outfit name source\");\n\t\t\treturn;\n\t\t}\n\n\t\tSliderSet currentSet;\n\t\tDiffDataSets currentDiffs;\n\n\t\tSliderSetFile sliderDoc;\n\t\tsliderDoc.Open(outfitNameSource[outfit]);\n\t\tif (!sliderDoc.fail()) {\n\t\t\tif (sliderDoc.GetSet(outfit, currentSet)) {\n\t\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to get slider set from file: \") + outfitNameSource[outfit];\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to open slider set file: \") + outfitNameSource[outfit];\n\t\t\treturn;\n\t\t}\n\n\t\tcurrentSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\n\t\t// ALT key\n\t\tif (clean && custPath.empty()) {\n\t\t\tbool genWeights = currentSet.GenWeights();\n\n\t\t\twxString removePath = wxString::FromUTF8(datapath + currentSet.GetOutputFilePath());\n\t\t\twxString removeHigh = removePath + \".nif\";\n\t\t\tif (genWeights)\n\t\t\t\tremoveHigh = removePath + \"_1.nif\";\n\n\t\t\tif (wxFileName::FileExists(removeHigh))\n\t\t\t\twxRemoveFile(removeHigh);\n\n\t\t\tif (!genWeights)\n\t\t\t\treturn;\n\n\t\t\twxString removeLow = removePath + \"_0.nif\";\n\t\t\tif (wxFileName::FileExists(removeLow))\n\t\t\t\twxRemoveFile(removeLow);\n\n\t\t\treturn;\n\t\t}\n\n\t\t/* Load input NIFs */\n\t\tstd::fstream file;\n\t\tPlatformUtil::OpenFileStream(file, currentSet.GetInputFileName(), std::ios::in | std::ios::binary);\n\n\t\tNifFile nifBig;\n\t\tNifFile nifSmall;\n\t\tif (nifBig.Load(file)) {\n\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to load input nif: \") + currentSet.GetInputFileName();\n\t\t\treturn;\n\t\t}\n\n\t\tif (currentSet.GenWeights())\n\t\t\tnifSmall.CopyFrom(nifBig);\n\n\t\tcurrentSet.LoadSetDiffData(currentDiffs);\n\n\t\t// Load BuildSelection file for zap choices\n\t\tBuildSelectionFile buildSelFile;\n\t\tBuildSelection buildSelection;\n\t\tGetBuildSelection(buildSelFile, buildSelection);\n\n\t\tbool keepZappedShapes = currentSet.KeepZappedShapes();\n\n\t\t/* Shape the NIF files */\n\t\tstd::vector<Vector3> vertsLow;\n\t\tstd::vector<Vector3> vertsHigh;\n\t\tstd::vector<Vector2> uvsLow;\n\t\tstd::vector<Vector2> uvsHigh;\n\t\tstd::vector<int> clamps;\n\t\tstd::vector<uint16_t> zapIdx;\n\t\tstd::unordered_map<std::string, std::vector<uint16_t>> zapIdxAll;\n\n\t\tfor (size_t s = 0; s < currentSet.size(); s++) {\n\t\t\tstd::string name = currentSet[s].name;\n\n\t\t\tif (currentSet[s].bClamp) {\n\t\t\t\tclamps.push_back(s);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (currentSet[s].bZap && !currentSet[s].bUV) {\n\t\t\t\tfloat vbig = sliderManager.GetBigPresetValue(activePreset, name, currentSet[s].defBigValue / 100.0f);\n\t\t\t\tfor (auto& sliderBig : sliderManager.slidersBig) {\n\t\t\t\t\tif (sliderBig.name == name && sliderBig.changed && !sliderBig.clamp) {\n\t\t\t\t\t\tvbig = sliderBig.value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!currentSet[s].bHidden) {\n\t\t\t\t\t// Apply stored zap choice for zaps visible to the user\n\t\t\t\t\tif (buildSelection.HasZapChoice(currentSet.GetName(), name)) {\n\t\t\t\t\t\tbool zapChoice = buildSelection.GetZapChoice(currentSet.GetName(), name);\n\t\t\t\t\t\tvbig = zapChoice ? 1.0f : 0.0f;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply zap toggles if zap is not in default state\n\t\t\t\tif (vbig != currentSet[s].defBigValue / 100.0f) {\n\t\t\t\t\tfor (auto& zapToggle : currentSet[s].zapToggles) {\n\t\t\t\t\t\t// Toggled zap default values are read in later code if no preset overwrites it\n\t\t\t\t\t\tauto& slider = currentSet[zapToggle];\n\t\t\t\t\t\tslider.defBigValue = 100.0f - slider.defBigValue;\n\t\t\t\t\t\tslider.defSmallValue = 100.0f - slider.defSmallValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Phase 1: Apply sliders and set vertices for all shapes\n\t\tfor (auto it = currentSet.ShapesBegin(); it != currentSet.ShapesEnd(); ++it) {\n\t\t\tauto shape = nifBig.FindBlockByName<NiShape>(it->first);\n\t\t\tif (!nifBig.GetVertsForShape(shape, vertsHigh))\n\t\t\t\tcontinue;\n\n\t\t\tnifBig.GetUvsForShape(shape, uvsHigh);\n\n\t\t\tif (currentSet.GenWeights()) {\n\t\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\t\tif (!nifSmall.GetVertsForShape(shapeSmall, vertsLow))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tnifSmall.GetUvsForShape(shapeSmall, uvsLow);\n\t\t\t}\n\n\t\t\tfloat vbig = 0.0f;\n\t\t\tfloat vsmall = 0.0f;\n\t\t\tzapIdxAll.emplace(it->first, std::vector<uint16_t>());\n\n\t\t\tfor (size_t s = 0; s < currentSet.size(); s++) {\n\t\t\t\tstd::string name = currentSet[s].name;\n\t\t\t\tstd::string target = it->second.targetShape;\n\t\t\t\tstd::string dn = currentSet[s].TargetDataName(target);\n\t\t\t\tif (dn.empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tvbig = sliderManager.GetBigPresetValue(activePreset, name, currentSet[s].defBigValue / 100.0f);\n\t\t\t\tfor (auto& sliderBig : sliderManager.slidersBig) {\n\t\t\t\t\tif (sliderBig.name == name && sliderBig.changed && !sliderBig.clamp) {\n\t\t\t\t\t\tvbig = sliderBig.value;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (currentSet.GenWeights()) {\n\t\t\t\t\tvsmall = sliderManager.GetSmallPresetValue(activePreset, name, currentSet[s].defSmallValue / 100.0f);\n\t\t\t\t\tfor (auto& sliderSmall : sliderManager.slidersSmall) {\n\t\t\t\t\t\tif (sliderSmall.name == name && sliderSmall.changed && !sliderSmall.clamp) {\n\t\t\t\t\t\t\tvsmall = sliderSmall.value;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (currentSet[s].bInvert) {\n\t\t\t\t\tvbig = 1.0f - vbig;\n\t\t\t\t\tif (currentSet.GenWeights())\n\t\t\t\t\t\tvsmall = 1.0f - vsmall;\n\t\t\t\t}\n\n\t\t\t\tif (currentSet[s].bZap && !currentSet[s].bUV) {\n\t\t\t\t\tif (!currentSet[s].bHidden) {\n\t\t\t\t\t\t// Apply stored zap choice for zaps visible to the user\n\t\t\t\t\t\tif (buildSelection.HasZapChoice(currentSet.GetName(), name)) {\n\t\t\t\t\t\t\tbool zapChoice = buildSelection.GetZapChoice(currentSet.GetName(), name);\n\t\t\t\t\t\t\tvbig = zapChoice ? 1.0f : 0.0f;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (vbig > 0.0f) {\n\t\t\t\t\t\tcurrentDiffs.GetDiffIndices(dn, target, zapIdx);\n\t\t\t\t\t\tzapIdxAll[it->first] = zapIdx;\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (currentSet[s].bUV)\n\t\t\t\t\tcurrentDiffs.ApplyUVDiff(dn, target, vbig, &uvsHigh);\n\t\t\t\telse\n\t\t\t\t\tcurrentDiffs.ApplyDiff(dn, target, vbig, &vertsHigh);\n\n\t\t\t\tif (currentSet.GenWeights()) {\n\t\t\t\t\tif (currentSet[s].bUV)\n\t\t\t\t\t\tcurrentDiffs.ApplyUVDiff(dn, target, vsmall, &uvsLow);\n\t\t\t\t\telse\n\t\t\t\t\t\tcurrentDiffs.ApplyDiff(dn, target, vsmall, &vertsLow);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!clamps.empty()) {\n\t\t\t\tfor (auto& c : clamps) {\n\t\t\t\t\tstd::string dn = currentSet[c].TargetDataName(it->second.targetShape);\n\t\t\t\t\tstd::string target = it->second.targetShape;\n\t\t\t\t\tif (currentSet[c].defBigValue > 0)\n\t\t\t\t\t\tcurrentDiffs.ApplyClamp(dn, target, &vertsHigh);\n\n\t\t\t\t\tif (currentSet.GenWeights())\n\t\t\t\t\t\tif (currentSet[c].defSmallValue > 0)\n\t\t\t\t\t\t\tcurrentDiffs.ApplyClamp(dn, target, &vertsLow);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tnifBig.SetVertsForShape(shape, vertsHigh);\n\t\t\tnifBig.SetUvsForShape(shape, uvsHigh);\n\n\t\t\tif (currentSet.GenWeights()) {\n\t\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\t\tnifSmall.SetVertsForShape(shapeSmall, vertsLow);\n\t\t\t\tnifSmall.SetUvsForShape(shapeSmall, uvsLow);\n\t\t\t}\n\n\t\t\tzapIdx.clear();\n\t\t}\n\n\t\t// Phase 2: Apply clipping fix when strength is above zero\n\t\tif (clippingFixStrength > 0.0f) {\n\t\t\tauto refShape = ClippingFixer::FindReferenceShape(nifBig);\n\t\t\tif (refShape) {\n\t\t\t\tstd::vector<Vector3> bodyVerts;\n\t\t\t\tstd::vector<Triangle> bodyTris;\n\t\t\t\tnifBig.GetVertsForShape(refShape, bodyVerts);\n\t\t\t\trefShape->GetTriangles(bodyTris);\n\n\t\t\t\tif (!bodyVerts.empty() && !bodyTris.empty()) {\n\t\t\t\t\tClippingFixOptions fixOpts;\n\t\t\t\t\tfixOpts.strength = clippingFixStrength / 100.0f;\n\n\t\t\t\t\tfor (auto it = currentSet.ShapesBegin(); it != currentSet.ShapesEnd(); ++it) {\n\t\t\t\t\t\tauto shape = nifBig.FindBlockByName<NiShape>(it->first);\n\t\t\t\t\t\tif (!shape || shape == refShape)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tstd::vector<Vector3> outfitVerts;\n\t\t\t\t\t\tstd::vector<Triangle> outfitTris;\n\t\t\t\t\t\tif (!nifBig.GetVertsForShape(shape, outfitVerts))\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tshape->GetTriangles(outfitTris);\n\n\t\t\t\t\t\tClippingFixer::FixClipping(bodyVerts, bodyTris, outfitVerts, outfitTris, fixOpts);\n\t\t\t\t\t\tnifBig.SetVertsForShape(shape, outfitVerts);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (currentSet.GenWeights()) {\n\t\t\t\t\t\tauto refShapeSmall = nifSmall.FindBlockByName<NiShape>(refShape->name.get());\n\t\t\t\t\t\tif (refShapeSmall) {\n\t\t\t\t\t\t\tstd::vector<Vector3> bodyVertsSmall;\n\t\t\t\t\t\t\tstd::vector<Triangle> bodyTrisSmall;\n\t\t\t\t\t\t\tnifSmall.GetVertsForShape(refShapeSmall, bodyVertsSmall);\n\t\t\t\t\t\t\trefShapeSmall->GetTriangles(bodyTrisSmall);\n\n\t\t\t\t\t\t\tif (!bodyVertsSmall.empty() && !bodyTrisSmall.empty()) {\n\t\t\t\t\t\t\t\tfor (auto it = currentSet.ShapesBegin(); it != currentSet.ShapesEnd(); ++it) {\n\t\t\t\t\t\t\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\t\t\t\t\t\t\tif (!shapeSmall || shapeSmall == refShapeSmall)\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\t\tstd::vector<Vector3> outfitVerts;\n\t\t\t\t\t\t\t\t\tstd::vector<Triangle> outfitTris;\n\t\t\t\t\t\t\t\t\tif (!nifSmall.GetVertsForShape(shapeSmall, outfitVerts))\n\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\tshapeSmall->GetTriangles(outfitTris);\n\n\t\t\t\t\t\t\t\t\tClippingFixer::FixClipping(bodyVertsSmall, bodyTrisSmall, outfitVerts, outfitTris, fixOpts);\n\t\t\t\t\t\t\t\t\tnifSmall.SetVertsForShape(shapeSmall, outfitVerts);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Phase 3: Recalculate normals, tangents, and handle zapping\n\t\tfor (auto it = currentSet.ShapesBegin(); it != currentSet.ShapesEnd(); ++it) {\n\t\t\tauto shape = nifBig.FindBlockByName<NiShape>(it->first);\n\t\t\tif (!shape)\n\t\t\t\tcontinue;\n\n\t\t\tif (!nifBig.GetVertsForShape(shape, vertsHigh))\n\t\t\t\tcontinue;\n\n\t\t\tif (!it->second.lockNormals) {\n\t\t\t\tnifBig.CalcNormalsForShape(shape, forceNormals, it->second.smoothSeamNormals);\n\n\t\t\t\tif (forceNormals)\n\t\t\t\t\tApplyReferenceNormals(nifBig);\n\t\t\t}\n\n\t\t\tnifBig.CalcTangentsForShape(shape);\n\n\t\t\tauto zapIt = zapIdxAll.find(it->first);\n\t\t\tauto& shapeZapIdx = zapIt != zapIdxAll.end() ? zapIt->second : zapIdx;\n\n\t\t\tif (keepZappedShapes && shapeZapIdx.size() == vertsHigh.size()) {\n\t\t\t\tshape->flags |= 1; // Set hidden flag when shape would otherwise be fully zapped\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (nifBig.DeleteVertsForShape(shape, shapeZapIdx))\n\t\t\t\t\tnifBig.DeleteShape(shape); // Delete fully zapped shape\n\t\t\t}\n\n\t\t\tif (currentSet.GenWeights()) {\n\t\t\t\tauto shapeSmall = nifSmall.FindBlockByName<NiShape>(it->first);\n\t\t\t\tif (!shapeSmall)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (!nifSmall.GetVertsForShape(shapeSmall, vertsLow))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (!it->second.lockNormals) {\n\t\t\t\t\tnifSmall.CalcNormalsForShape(shapeSmall, forceNormals, it->second.smoothSeamNormals);\n\n\t\t\t\t\tif (forceNormals)\n\t\t\t\t\t\tApplyReferenceNormals(nifSmall);\n\t\t\t\t}\n\n\t\t\t\tnifSmall.CalcTangentsForShape(shapeSmall);\n\n\t\t\t\tif (keepZappedShapes && shapeZapIdx.size() == vertsLow.size()) {\n\t\t\t\t\tshapeSmall->flags |= 1; // Set hidden flag when shape would otherwise be fully zapped\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (nifSmall.DeleteVertsForShape(shapeSmall, shapeZapIdx))\n\t\t\t\t\t\tnifSmall.DeleteShape(shapeSmall); // Delete fully zapped shape\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tcurrentDiffs.Clear();\n\n\t\t/* Create directory for the outfit */\n\t\twxString dir = wxString::FromUTF8(datapath + currentSet.GetOutputPath());\n\t\tbool success = wxFileName::Mkdir(dir, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\t\tif (!success) {\n\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to create destination directory: \") + dir.ToUTF8().data();\n\t\t\treturn;\n\t\t}\n\n\t\tstd::string outFileNameSmall = datapath + currentSet.GetOutputFilePath();\n\t\tstd::string outFileNameBig = outFileNameSmall;\n\n\t\tbool triKeep = currentSet.PreventMorphFile();\n\n\t\tif (tri && !triKeep) {\n\t\t\tstd::string triFilePath = outFileNameBig + \".tri\";\n\n\t\t\t// TRI file already exists but isn't a body TRI file, don't overwrite!\n\t\t\tif (wxFileName::FileExists(wxString::FromUTF8(triFilePath)) && !IsBodyTriFile(triFilePath))\n\t\t\t\ttriKeep = true;\n\t\t}\n\n\t\t/* Add TRI path for in-game morphs */\n\t\tif (tri && !triKeep) {\n\t\t\tbool triEnd = tri;\n\t\t\tstd::string triPath = currentSet.GetOutputFilePath() + \".tri\";\n\t\t\tstd::string triPathTrimmed = triPath;\n\t\t\ttriPathTrimmed = std::regex_replace(triPathTrimmed, std::regex(\"/+|\\\\\\\\+\"),\n\t\t\t\t\t\t\t\t\t\t\t\t\"\\\\\"); // Replace multiple backslashes or forward slashes with one backslash\n\t\t\ttriPathTrimmed = std::regex_replace(triPathTrimmed,\n\t\t\t\t\t\t\t\t\t\t\t\tstd::regex(\".*meshes\\\\\\\\\", std::regex_constants::icase),\n\t\t\t\t\t\t\t\t\t\t\t\t\"\"); // Remove everything before and including the meshes path\n\n\t\t\tif (!WriteMorphTRI(outFileNameBig, currentSet, nifBig, zapIdxAll))\n\t\t\t\twxLogError(\"Failed to create TRI file to '%s'!\", triPath);\n\n\t\t\tif (targetGame != FO4 && targetGame != FO4VR && targetGame != FO76) {\n\t\t\t\tfor (auto targetShape = currentSet.ShapesBegin(); targetShape != currentSet.ShapesEnd(); ++targetShape) {\n\t\t\t\t\tauto shape = nifBig.FindBlockByName<NiShape>(targetShape->first);\n\t\t\t\t\tif (!shape)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (triEnd && shape->GetNumVertices() > 0) {\n\t\t\t\t\t\tAddTriData(nifBig, targetShape->first, triPathTrimmed);\n\t\t\t\t\t\tif (currentSet.GenWeights())\n\t\t\t\t\t\t\tAddTriData(nifSmall, targetShape->first, triPathTrimmed);\n\n\t\t\t\t\t\ttriEnd = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tAddTriData(nifBig, \"\", triPathTrimmed, true);\n\t\t\t\tif (currentSet.GenWeights())\n\t\t\t\t\tAddTriData(nifSmall, \"\", triPathTrimmed, true);\n\t\t\t}\n\n\t\t\t// Set all shapes to dynamic/mutable\n\t\t\tfor (auto it = currentSet.ShapesBegin(); it != currentSet.ShapesEnd(); ++it) {\n\t\t\t\tnifBig.SetShapeDynamic(it->first);\n\t\t\t\tif (currentSet.GenWeights())\n\t\t\t\t\tnifSmall.SetShapeDynamic(it->first);\n\t\t\t}\n\t\t}\n\t\telse if (!triKeep) {\n\t\t\tstd::string triPath = outFileNameBig + \".tri\";\n\t\t\tif (IsBodyTriFile(triPath))\n\t\t\t\twxRemoveFile(triPath);\n\t\t}\n\n\t\tNifSaveOptions nifOptions;\n\t\tnifOptions.optimize = false;\n\n\t\t/* Set filenames for the outfit */\n\t\tif (currentSet.GenWeights()) {\n\t\t\toutFileNameSmall += \"_0.nif\";\n\t\t\toutFileNameBig += \"_1.nif\";\n\n\t\t\tstd::fstream fileBig;\n\t\t\tPlatformUtil::OpenFileStream(fileBig, outFileNameBig, std::ios::out | std::ios::binary);\n\n\t\t\tif (nifBig.Save(fileBig, nifOptions)) {\n\t\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to save nif file: \") + outFileNameBig;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstd::fstream fileSmall;\n\t\t\tPlatformUtil::OpenFileStream(fileSmall, outFileNameSmall, std::ios::out | std::ios::binary);\n\n\t\t\tif (nifSmall.Save(fileSmall, nifOptions)) {\n\t\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to save nif file: \") + outFileNameSmall;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\toutFileNameBig += \".nif\";\n\n\t\t\tstd::fstream fileBig;\n\t\t\tPlatformUtil::OpenFileStream(fileBig, outFileNameBig, std::ios::out | std::ios::binary);\n\n\t\t\tif (nifBig.Save(fileBig, nifOptions)) {\n\t\t\t\tfailedOutfitsCon[outfit] = _(\"Unable to save nif file: \") + outFileNameBig;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\n\t// Multi-threading for 64-bit only due to memory limits of 32-bit builds\n#ifdef _PPL_H\n\t// Parallel loop is run inside a task\n\tauto buildTask = concurrency::create_task([&] { concurrency::parallel_for_each(outfitList.begin(), outfitList.end(), buildOutfit); });\n\n\t// Yield outside of task\n\twhile (!buildTask.is_done()) {\n\t\tYield();\n\t\twxMilliSleep(100);\n\t}\n#else\n\tfor (auto& outfit : outfitList) {\n\t\tbuildOutfit(outfit);\n\t}\n#endif\n\n\tprogWnd.Update(1000);\n\n\tfailedOutfits.insert(failedOutfitsCon.begin(), failedOutfitsCon.end());\n\n\tif (failedOutfits.size() > 0)\n\t\treturn 3;\n\n\treturn 0;\n}\n\nvoid BodySlideApp::GroupBuild(const std::vector<std::string>& groupNames) {\n\tstd::vector<std::string> outfits;\n\tfor (auto& o : outfitNameSource) {\n\t\tstd::vector<std::string> groups;\n\t\tgCollection.GetOutfitGroups(o.first, groups);\n\n\t\tfor (auto& g : groups) {\n\t\t\tif (std::find(groupNames.begin(), groupNames.end(), g) != groupNames.end()) {\n\t\t\t\toutfits.push_back(o.first);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tstd::string preset;\n\tif (!cmdPreset.empty()) {\n\t\tpreset = BodySlideConfig[\"SelectedPreset\"];\n\t\tBodySlideConfig.SetValue(\"SelectedPreset\", cmdPreset);\n\t}\n\n\tstd::vector<std::string> groups;\n\tsliderManager.LoadPresets(GetProjectPath() + \"/SliderPresets\", \"\", groups, true);\n\n\t// Apply saved build selections for CLI group builds before entering batch build conflict handling.\n\tBuildSelectionFile buildSelFile;\n\tBuildSelection buildSelection;\n\tGetBuildSelection(buildSelFile, buildSelection);\n\n\tfor (auto& outFile : outFileCount) {\n\t\tif (outFile.second.size() <= 1)\n\t\t\tcontinue;\n\n\t\tstd::vector<std::string> outfitsInBuild;\n\t\tfor (auto& outfit : outFile.second) {\n\t\t\tif (std::find(outfits.begin(), outfits.end(), outfit) != outfits.end())\n\t\t\t\toutfitsInBuild.push_back(outfit);\n\t\t}\n\n\t\tif (outfitsInBuild.size() <= 1)\n\t\t\tcontinue;\n\n\t\tstd::string outputChoice = buildSelection.GetOutputChoice(outFile.first);\n\t\tif (outputChoice.empty())\n\t\t\tcontinue;\n\n\t\tif (std::find(outfitsInBuild.begin(), outfitsInBuild.end(), outputChoice) == outfitsInBuild.end())\n\t\t\tcontinue;\n\n\t\tint removedChoices = 0;\n\n\t\tfor (auto& outfit : outfitsInBuild) {\n\t\t\tif (outfit == outputChoice)\n\t\t\t\tcontinue;\n\n\t\t\tauto result = std::find(outfits.begin(), outfits.end(), outfit);\n\t\t\tif (result != outfits.end()) {\n\t\t\t\toutfits.erase(result);\n\t\t\t\tremovedChoices++;\n\t\t\t}\n\t\t}\n\n\t\tif (removedChoices > 0) {\n\t\t\twxLogMessage(\"Group build applied saved BuildSelection for output '%s': selected '%s', skipped %d conflicting choice(s).\",\n\t\t\t\t\t\t outFile.first,\n\t\t\t\t\t\t outputChoice,\n\t\t\t\t\t\t removedChoices);\n\t\t}\n\t}\n\n\tstd::map<std::string, std::string> failedOutfits;\n\tint ret = BuildListBodies(outfits, failedOutfits, false, cmdTri, false, cmdTargetDir);\n\n\tif (!cmdPreset.empty())\n\t\tBodySlideConfig.SetValue(\"SelectedPreset\", preset);\n\n\twxLog::FlushActive();\n\n\tif (ret == 0) {\n\t\twxLogMessage(\"All group build sets processed successfully!\");\n\t}\n\telse if (ret == 3) {\n\t\twxArrayString errlist;\n\t\tfor (auto& e : failedOutfits) {\n\t\t\twxString ename = wxString::FromUTF8(e.first);\n\t\t\twxLogError(\"Failed to build '%s': %s\", ename, e.second);\n\t\t\terrlist.Add(ename + \":\" + e.second);\n\t\t}\n\n\t\twxSingleChoiceDialog errdisplay(sliderView, _(\"The following sets failed\"), _(\"Failed\"), errlist, nullptr, wxDEFAULT_DIALOG_STYLE | wxOK | wxRESIZE_BORDER);\n\t\terrdisplay.ShowModal();\n\t}\n\n\tsliderView->Close(true);\n}\n\nvoid BodySlideApp::AddTriData(NifFile& nif, const std::string& shapeName, const std::string& triPath, bool toRoot) {\n\tNiAVObject* target = nullptr;\n\n\tif (toRoot)\n\t\ttarget = nif.GetRootNode();\n\telse\n\t\ttarget = nif.FindBlockByName<NiShape>(shapeName);\n\n\tif (target) {\n\t\tauto triExtraData = std::make_unique<NiStringExtraData>();\n\t\ttriExtraData->name.get() = \"BODYTRI\";\n\t\ttriExtraData->stringData.get() = triPath;\n\t\tnif.AssignExtraData(target, std::move(triExtraData));\n\t}\n}\n\nfloat BodySlideApp::GetSliderValue(const wxString& sliderName, bool isLo) {\n\tstd::string sstr{sliderName.ToUTF8()};\n\treturn sliderManager.GetSlider(sstr, isLo);\n}\n\nbool BodySlideApp::IsUVSlider(const wxString& sliderName) {\n\tif (projects.empty())\n\t\treturn false;\n\n\tstd::string sstr{sliderName.ToUTF8()};\n\treturn GetActiveSet()[sstr].bUV;\n}\n\nstd::vector<std::string> BodySlideApp::GetSliderZapToggles(const wxString& sliderName) {\n\treturn sliderManager.GetSliderZapToggles(sliderName.ToUTF8().data());\n}\n\nvoid BodySlideApp::SetSliderValue(const wxString& sliderName, bool isLo, float val) {\n\tstd::string sstr{sliderName.ToUTF8()};\n\tsliderManager.SetSlider(sstr, isLo, val);\n}\n\nvoid BodySlideApp::SetSliderChanged(const wxString& sliderName, bool isLo) {\n\tstd::string sstr{sliderName.ToUTF8()};\n\tsliderManager.SetChanged(sstr, isLo);\n}\n\nint BodySlideApp::UpdateSliderPositions(const std::string& presetName) {\n\tstd::string outfitName = BodySlideConfig[\"SelectedOutfit\"];\n\tstd::vector<std::string> groups;\n\n\tstd::string outputFile = sliderManager.GetPresetFileNames(presetName);\n\tif (outputFile.empty())\n\t\treturn -2;\n\n\tsliderManager.GetPresetGroups(presetName, groups);\n\n\treturn sliderManager.SavePreset(outputFile, presetName, outfitName, groups);\n}\n\nint BodySlideApp::SaveSliderPositions(const std::string& outputFile, const std::string& presetName, std::vector<std::string>& groups) {\n\tstd::string outfitName = BodySlideConfig[\"SelectedOutfit\"];\n\treturn sliderManager.SavePreset(outputFile, presetName, outfitName, groups);\n}\n\nBodySlideFrame::BodySlideFrame(BodySlideApp* a, const wxSize& size)\n\t: delayLoad(this, DELAYLOAD_TIMER) {\n\tapp = a;\n\n\twxXmlResource* xrc = wxXmlResource::Get();\n\tbool loaded = xrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/BodySlide.xrc\");\n\tif (!loaded) {\n\t\twxMessageBox(_(\"Failed to load BodySlide.xrc file!\"), _(\"Error\"), wxICON_ERROR);\n\t\tClose(true);\n\t\treturn;\n\t}\n\n\tloaded = xrc->LoadFrame(this, GetParent(), \"bodySlideFrame\");\n\tif (!loaded) {\n\t\twxMessageBox(_(\"Failed to load BodySlide frame!\"), _(\"Error\"), wxICON_ERROR);\n\t\tClose(true);\n\t\treturn;\n\t}\n\n\t// --- Embed splitter with preview panel ---\n\t// Capture the XRC-created sizer and all children, then reparent them\n\t// into the left side of a splitter window.\n\twxSizer* originalSizer = GetSizer();\n\n\tsplitter = new wxSplitterWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_LIVE_UPDATE | wxSP_3DSASH);\n\tsplitter->SetMinimumPaneSize(200);\n\n\tleftPanel = new wxPanel(splitter, wxID_ANY);\n\n\t// Reparent all XRC children from frame to leftPanel\n\twxWindowList children = GetChildren();\n\tfor (auto* child : children) {\n\t\tif (child != splitter)\n\t\t\tchild->Reparent(leftPanel);\n\t}\n\n\t// Move the XRC sizer to leftPanel\n\tSetSizer(nullptr, false);\n\tleftPanel->SetSizer(originalSizer);\n\tleftPanel->SetBackgroundColour(GetBackgroundColour());\n\tleftPanel->SetDoubleBuffered(true);\n\n\t// Create embedded preview panel\n\tpreviewPanel = new PreviewPanel(splitter, app);\n\n\t// Read sash position and visibility from config\n\tpreviewVisible = BodySlideConfig.GetBoolValue(\"BodySlideFrame.previewVisible\", true);\n\tsavedSashPosition = BodySlideConfig.GetIntValue(\"BodySlideFrame.sashpos\");\n\n\tif (previewVisible) {\n\t\tsplitter->SplitVertically(leftPanel, previewPanel, savedSashPosition);\n\t}\n\telse {\n\t\tsplitter->Initialize(leftPanel);\n\t\tpreviewPanel->Hide();\n\t}\n\n\t// Set new top-level sizer for the frame\n\twxBoxSizer* frameSizer = new wxBoxSizer(wxVERTICAL);\n\tframeSizer->Add(splitter, 1, wxEXPAND);\n\tSetSizer(frameSizer);\n\n\t// Connect splitter events\n\tsplitter->Bind(wxEVT_SPLITTER_SASH_POS_CHANGED, &BodySlideFrame::OnSashPosChanged, this);\n\n\t// Listen for pop-out events from the preview panel\n\tsplitter->Bind(EVT_PREVIEW_POPOUT, &BodySlideFrame::OnPreviewPopout, this);\n\n\toutfitChoice = (wxChoice*)FindWindowByName(\"outfitChoice\", this);\n\tpresetChoice = (wxChoice*)FindWindowByName(\"presetChoice\", this);\n\tbtnSavePreset = (wxButton*)FindWindowByName(\"btnSavePreset\", this);\n\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/BatchBuild.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Settings.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/About.xrc\");\n\n\tSetIcon(wxIcon(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/BodySlide.png\", wxBITMAP_TYPE_PNG));\n\tSetSize(size);\n\n\tbatchBuildList = nullptr;\n\tauto srchMenu = xrc->LoadMenu(\"menuGroupContext\");\n\tauto outfitsrchMenu = xrc->LoadMenu(\"menuOutfitSrchContext\");\n\n\tif (outfitsrchMenu) {\n\t\tauto menuRegexOutfits = outfitsrchMenu->FindItem(XRCID(\"menuRegexOutfits\"));\n\t\tif (menuRegexOutfits) {\n\t\t\tbool regexFilterOutfits = BodySlideConfig.GetBoolValue(\"RegexFilterOutfits\");\n\t\t\tmenuRegexOutfits->Check(regexFilterOutfits);\n\t\t}\n\t}\n\tfileCollisionMenu = xrc->LoadMenu(\"menuFileCollision\");\n\n\tsearch = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);\n\tsearch->ShowSearchButton(true);\n\tsearch->ShowCancelButton(true);\n\tsearch->SetDescriptiveText(_(\"Filter groups...\"));\n\tsearch->SetMenu(srchMenu);\n\n\toutfitsearch = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);\n\toutfitsearch->ShowSearchButton(true);\n\toutfitsearch->ShowCancelButton(true);\n\toutfitsearch->SetDescriptiveText(_(\"Filter outfits...\"));\n\toutfitsearch->SetMenu(outfitsrchMenu);\n\n\tsliderFilter = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);\n\tsliderFilter->ShowSearchButton(true);\n\tsliderFilter->ShowCancelButton(true);\n\tsliderFilter->SetDescriptiveText(_(\"Filter sliders...\"));\n\n\tpresetFilter = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);\n\tpresetFilter->ShowSearchButton(true);\n\tpresetFilter->ShowCancelButton(true);\n\tpresetFilter->SetDescriptiveText(_(\"Filter presets...\"));\n\n\tint categoryTabSizerID = XRCID(\"categoryTabSizer\");\n\twxSizerItem* si = leftPanel->GetSizer()->GetItemById(categoryTabSizerID, true);\n\n\tcategoryTabSizer = si ? si->GetSizer() : nullptr;\n\n\tauto conflictLabel = (wxStaticText*)FindWindowByName(\"conflictLabel\", this);\n\tif (conflictLabel)\n\t\tconflictLabel->Bind(wxEVT_RIGHT_DOWN, &BodySlideFrame::OnConflictPopup, this);\n\n\tauto conflictInfo = (wxStaticText*)FindWindowByName(\"conflictInfo\", this);\n\tif (conflictInfo)\n\t\tconflictInfo->Bind(wxEVT_RIGHT_DOWN, &BodySlideFrame::OnConflictPopup, this);\n\n\txrc->AttachUnknownControl(\"searchHolder\", search, this);\n\txrc->AttachUnknownControl(\"outfitsearchHolder\", outfitsearch, this);\n\txrc->AttachUnknownControl(\"sliderFilter\", sliderFilter, this);\n\txrc->AttachUnknownControl(\"presetFilter\", presetFilter, this);\n\n\tsliderScroll = (wxScrolledWindow*)FindWindowByName(\"SliderScrollWindow\", this);\n\tif (sliderScroll) {\n\t\tsliderScroll->SetScrollRate(5, 26);\n\t\tsliderScroll->SetFocusIgnoringChildren();\n\t\tsliderScroll->Bind(wxEVT_ENTER_WINDOW, &BodySlideFrame::OnEnterSliderWindow, this);\n\n\t\tsliderLayout = (wxFlexGridSizer*)sliderScroll->GetSizer();\n\t}\n\n\twxString val = BodySlideConfig[\"LastGroupFilter\"];\n\tsearch->ChangeValue(val);\n\tval = BodySlideConfig[\"LastOutfitFilter\"];\n\toutfitsearch->ChangeValue(val);\n\tval = BodySlideConfig[\"LastPresetFilter\"];\n\tpresetFilter->ChangeValue(val);\n\n\tRefreshTargetGameState();\n\n\t// Create initial slider pool\n\tif (sliderScroll && sliderLayout) {\n\t\tconst size_t minSliderPoolSize = 100;\n\t\tsliderPool.CreatePool(minSliderPoolSize, sliderScroll, sliderLayout);\n\t}\n\n\t// Set up accelerator entries\n\twxAcceleratorEntry entries[5];\n\tentries[0].Set(wxACCEL_CTRL, (int)'O', XRCID(\"btnEditProject\"));\n\tentries[1].Set(wxACCEL_CTRL, (int)'S', XRCID(\"btnSavePreset\"));\n\tentries[2].Set(wxACCEL_CTRL | wxACCEL_ALT, (int)'S', XRCID(\"btnSavePresetAs\"));\n\tentries[3].Set(wxACCEL_CTRL, (int)'G', XRCID(\"btnGroupManager\"));\n\tentries[4].Set(wxACCEL_CTRL, (int)'P', XRCID(\"btnPreview\"));\n\n\twxAcceleratorTable accel(5, entries);\n\tSetAcceleratorTable(accel);\n\n\t// Update preview toggle button label\n\tauto btnPreview = (wxButton*)FindWindowByName(\"btnPreview\", this);\n\tif (btnPreview) {\n\t\tif (previewVisible)\n\t\t\tbtnPreview->SetLabel(_(\"Hide Preview\"));\n\t\telse\n\t\t\tbtnPreview->SetLabel(_(\"Show Preview\"));\n\t}\n}\n\nvoid BodySlideFrame::OnLinkClicked(wxHtmlLinkEvent& link) {\n\twxLaunchDefaultBrowser(link.GetLinkInfo().GetHref());\n}\n\nvoid BodySlideFrame::OnEnterClose(wxKeyEvent& event) {\n\tif (event.GetKeyCode() == WXK_RETURN) {\n\t\twxDialog* parent = (wxDialog*)((wxWindow*)event.GetEventObject())->GetParent();\n\t\tif (!parent)\n\t\t\treturn;\n\n\t\tparent->Close();\n\t\tparent->SetReturnCode(wxID_OK);\n\t}\n\tevent.Skip();\n}\n\nvoid BodySlideFrame::OnEnterSliderWindow(wxMouseEvent& event) {\n\tif (this->IsActive()) {\n\t\tif (!this->FindFocus()->IsKindOf(wxClassInfo::FindClass(\"wxTextCtrl\")) &&\n\t\t\t!this->FindFocus()->IsKindOf(wxClassInfo::FindClass(\"wxSearchCtrl\"))) {\n\t\t\twxScrolledWindow* sw = (wxScrolledWindow*)event.GetEventObject();\n\t\t\tsw->SetFocusIgnoringChildren();\n\t\t}\n\t}\n}\n\nvoid BodySlideFrame::HideSlider(SliderDisplay* slider) {\n\tif (!slider)\n\t\treturn;\n\n\tslider->zapCheckLo->Unbind(wxEVT_CHECKBOX, &BodySlideFrame::OnZapCheckChanged, this);\n\tslider->sliderLo->Unbind(wxEVT_ERASE_BACKGROUND, &BodySlideFrame::OnEraseBackground, this);\n\tslider->sliderReadoutLo->Disconnect(wxEVT_KILL_FOCUS, wxCommandEventHandler(BodySlideFrame::OnSliderReadoutChange), nullptr, this);\n\n\tslider->zapCheckHi->Unbind(wxEVT_CHECKBOX, &BodySlideFrame::OnZapCheckChanged, this);\n\tslider->sliderHi->Unbind(wxEVT_ERASE_BACKGROUND, &BodySlideFrame::OnEraseBackground, this);\n\tslider->sliderReadoutHi->Disconnect(wxEVT_KILL_FOCUS, wxCommandEventHandler(BodySlideFrame::OnSliderReadoutChange), nullptr, this);\n\n\tslider->Show(false);\n}\n\nvoid BodySlideFrame::ShowLowColumn(bool show) {\n\tif (show) {\n\t\tXRCCTRL(*this, \"lblLowWt\", wxStaticText)->Show();\n\t\tXRCCTRL(*this, \"lblHighWt\", wxStaticText)->Show();\n\t\tXRCCTRL(*this, \"lblSingleWt\", wxStaticText)->Hide();\n\t\tXRCCTRL(*this, \"btnLowToHigh\", wxButton)->Show();\n\t\tXRCCTRL(*this, \"btnHighToLow\", wxButton)->Show();\n\t\tsliderLayout->SetCols(6);\n\t}\n\telse {\n\t\tXRCCTRL(*this, \"lblLowWt\", wxStaticText)->Hide();\n\t\tXRCCTRL(*this, \"lblHighWt\", wxStaticText)->Hide();\n\t\tXRCCTRL(*this, \"lblSingleWt\", wxStaticText)->Show();\n\t\tXRCCTRL(*this, \"btnLowToHigh\", wxButton)->Hide();\n\t\tXRCCTRL(*this, \"btnHighToLow\", wxButton)->Hide();\n\t\tsliderLayout->SetCols(3);\n\t}\n}\n\nvoid BodySlideFrame::AddCategorySliderUI(const std::string& name, const std::vector<std::string>& sliders, bool enabled, bool oneSize) {\n\tSliderCategoryUI* cat = new SliderCategoryUI();\n\n\tif (!cat->Create(sliderScroll, sliderLayout, categoryTabSizer, name, sliders, enabled, oneSize))\n\t\treturn;\n\n\tcat->check->Bind(wxEVT_CHECKBOX, &BodySlideFrame::OnCategoryCheckChanged, this);\n\n\tif (cat->tabButton)\n\t\tcat->tabButton->Bind(wxEVT_BUTTON, &BodySlideFrame::OnCategoryTabButton, this);\n\n\tif (!cat->isShown)\n\t\tcat->Show();\n\n\tsliderCategories[cat->categoryName] = cat;\n}\n\nvoid BodySlideFrame::AddSliderGUI(const std::string& name, const std::string& display, const std::string& category, bool isZap, bool oneSize) {\n\tSliderDisplay* sd = sliderPool.GetNext();\n\tif (!sd)\n\t\treturn;\n\n\tint minValue = Config.GetIntValue(\"Input/SliderMinimum\");\n\tint maxValue = Config.GetIntValue(\"Input/SliderMaximum\");\n\n\tif (!sd->Create(sliderScroll, sliderLayout, name, display, category, minValue, maxValue, isZap, oneSize))\n\t\treturn;\n\n\tsd->zapCheckLo->Bind(wxEVT_CHECKBOX, &BodySlideFrame::OnZapCheckChanged, this);\n\tsd->sliderLo->Bind(wxEVT_ERASE_BACKGROUND, &BodySlideFrame::OnEraseBackground, this);\n\tsd->sliderReadoutLo->Connect(wxEVT_KILL_FOCUS, wxCommandEventHandler(BodySlideFrame::OnSliderReadoutChange), nullptr, this);\n\n\tsd->zapCheckHi->Bind(wxEVT_CHECKBOX, &BodySlideFrame::OnZapCheckChanged, this);\n\tsd->sliderHi->Bind(wxEVT_ERASE_BACKGROUND, &BodySlideFrame::OnEraseBackground, this);\n\tsd->sliderReadoutHi->Connect(wxEVT_KILL_FOCUS, wxCommandEventHandler(BodySlideFrame::OnSliderReadoutChange), nullptr, this);\n\n\tif (!sd->isShown)\n\t\tsd->Show();\n\n\tsliderDisplays[sd->sliderName] = sd;\n}\n\nvoid BodySlideFrame::ClearPresetList() {\n\tif (presetChoice)\n\t\tpresetChoice->Clear();\n}\n\nvoid BodySlideFrame::ClearOutfitList() {\n\tif (outfitChoice)\n\t\toutfitChoice->Clear();\n}\n\nvoid BodySlideFrame::ClearSliderGUI() {\n\tfor (auto& sd : sliderDisplays)\n\t\tHideSlider(sd.second);\n\n\tsliderScroll->GetSizer()->Clear();\n\n\tfor (auto& cat : sliderCategories) {\n\t\tcat.second->Destroy();\n\t\tdelete cat.second;\n\t}\n\n\tsliderDisplays.clear();\n\tsliderCategories.clear();\n}\n\nvoid BodySlideFrame::SetPresetChanged(bool changed) {\n\tif (btnSavePreset)\n\t\tbtnSavePreset->Enable(changed);\n}\n\nvoid BodySlideFrame::PopulateOutfitList(const wxArrayString& items, const wxString& selectItem) {\n\tif (!outfitChoice)\n\t\treturn;\n\n\toutfitChoice->Clear();\n\toutfitChoice->Append(items);\n\tif (!outfitChoice->SetStringSelection(selectItem)) {\n\t\tint i = wxNOT_FOUND;\n\t\tif (selectItem.empty())\n\t\t\ti = outfitChoice->Append(\"\");\n\t\telse if (selectItem.First('['))\n\t\t\ti = outfitChoice->Append(\"[\" + selectItem + \"]\");\n\t\telse\n\t\t\ti = outfitChoice->Append(selectItem);\n\n\t\toutfitChoice->SetSelection(i);\n\t}\n}\n\nvoid BodySlideFrame::PopulatePresetList(const wxArrayString& items, const wxString& selectItem) {\n\tif (!presetChoice)\n\t\treturn;\n\n\tpresetChoice->Clear();\n\tpresetChoice->Append(items);\n\tif (!presetChoice->SetStringSelection(selectItem)) {\n\t\tint i = wxNOT_FOUND;\n\t\tif (selectItem.empty())\n\t\t\ti = presetChoice->Append(\"\");\n\t\telse if (selectItem.First('['))\n\t\t\ti = presetChoice->Append(\"[\" + selectItem + \"]\");\n\t\telse\n\t\t\ti = presetChoice->Append(selectItem);\n\n\t\tpresetChoice->SetSelection(i);\n\t}\n}\n\nvoid BodySlideFrame::SetSliderPosition(const wxString& name, float newValue, short HiLo) {\n\tint intval = (int)(newValue * 100.0f);\n\n\tSliderDisplay* sd = GetSliderDisplay(name.ToUTF8().data());\n\tif (!sd)\n\t\treturn;\n\n\tif (HiLo == SLIDER_HI) {\n\t\tif (!sd->isZap) {\n\t\t\tsd->sliderReadoutHi->ChangeValue(wxString::Format(\"%d%%\", intval));\n\t\t\tsd->sliderHi->SetValue(intval);\n\t\t}\n\t\telse\n\t\t\tsd->zapCheckHi->SetValue((intval > 0));\n\t}\n\telse if (!sd->oneSize) {\n\t\tif (!sd->isZap) {\n\t\t\tsd->sliderReadoutLo->ChangeValue(wxString::Format(\"%d%%\", intval));\n\t\t\tsd->sliderLo->SetValue(intval);\n\t\t}\n\t\telse\n\t\t\tsd->zapCheckLo->SetValue((intval > 0));\n\t}\n}\n\nvoid BodySlideFrame::OnExit(wxCommandEvent& WXUNUSED(event)) {\n\tClose(true);\n}\n\nvoid BodySlideFrame::OnClose(wxCloseEvent& WXUNUSED(event)) {\n\tapp->CleanupPreview();\n\tapp->ClosePreview();\n\n\tsliderPool.Clear();\n\tsliderDisplays.clear();\n\n\tfor (auto& cat : sliderCategories) {\n\t\tcat.second->Destroy();\n\t\tdelete cat.second;\n\t}\n\n\tsliderCategories.clear();\n\n\tauto cbMorphs = XRCCTRL(*this, \"cbMorphs\", wxCheckBox);\n\tif (cbMorphs && cbMorphs->IsShown())\n\t\tBodySlideConfig.SetBoolValue(\"BuildMorphs\", cbMorphs->GetValue());\n\n\tauto cbForceBodyNormals = XRCCTRL(*this, \"cbForceBodyNormals\", wxCheckBox);\n\tif (cbForceBodyNormals)\n\t\tBodySlideConfig.SetBoolValue(\"ForceBodyNormals\", cbForceBodyNormals->GetValue());\n\n\tauto menuOutfitSrchContext = outfitsearch->GetMenu();\n\tif (menuOutfitSrchContext) {\n\t\tauto menuRegexOutfits = menuOutfitSrchContext->FindItem(XRCID(\"menuRegexOutfits\"));\n\t\tif (menuRegexOutfits)\n\t\t\tBodySlideConfig.SetBoolValue(\"RegexFilterOutfits\", menuRegexOutfits->IsChecked());\n\t}\n\n\tint ret = BodySlideConfig.SaveConfig(Config[\"AppDir\"] + \"/BodySlide.xml\", \"BodySlideConfig\");\n\tif (ret)\n\t\twxLogWarning(\"Failed to save configuration (%d)!\", ret);\n\n\twxLogMessage(\"BodySlide closed.\");\n\tDestroy();\n}\n\nvoid BodySlideFrame::OnActivateFrame(wxActivateEvent& event) {\n\tevent.Skip();\n\tif (event.GetActive()) {\n\t\tsliderScroll->SetFocusIgnoringChildren();\n\t}\n}\n\nvoid BodySlideFrame::OnIconizeFrame(wxIconizeEvent& event) {\n\tevent.Skip();\n\tif (!event.IsIconized()) {\n\t\tlastScroll = sliderScroll->GetScrollPos(wxVERTICAL);\n\t\tCallAfter(&BodySlideFrame::PostIconizeFrame);\n\t}\n}\n\nvoid BodySlideFrame::PostIconizeFrame() {\n\tsliderScroll->SetFocusIgnoringChildren();\n\tsliderScroll->Scroll(0, lastScroll);\n}\n\nvoid BodySlideFrame::OnSliderChange(wxScrollEvent& event) {\n\twxWindow* w = (wxWindow*)event.GetEventObject();\n\tif (!w)\n\t\treturn;\n\n\twxString fullname = w->GetName();\n\twxString name;\n\tbool isLo = fullname.EndsWith(\"|LO\", &name);\n\tif (!isLo) {\n\t\tif (!fullname.EndsWith(\"|HI\", &name))\n\t\t\treturn;\n\t}\n\n\tSliderDisplay* sd = GetSliderDisplay(name.ToUTF8().data());\n\tif (!sd)\n\t\treturn;\n\n\tapp->SetSliderValue(name, isLo, event.GetPosition() / 100.0f);\n\tapp->SetSliderChanged(name, isLo);\n\tif (isLo)\n\t\tsd->sliderReadoutLo->ChangeValue(wxString::Format(\"%d%%\", event.GetPosition()));\n\telse\n\t\tsd->sliderReadoutHi->ChangeValue(wxString::Format(\"%d%%\", event.GetPosition()));\n\n\tSetPresetChanged();\n\tapp->UpdatePreview();\n}\n\nvoid BodySlideFrame::OnSliderReadoutChange(wxCommandEvent& event) {\n\twxTextCtrl* w = (wxTextCtrl*)event.GetEventObject();\n\tevent.Skip();\n\tif (!w)\n\t\treturn;\n\n\twxString fullname = w->GetName();\n\twxString name;\n\tbool isLo = fullname.EndsWith(\"|RLO\", &name);\n\tif (!isLo) {\n\t\tif (!fullname.EndsWith(\"|RHI\", &name))\n\t\t\treturn;\n\t}\n\n\tSliderDisplay* sd = GetSliderDisplay(name.ToUTF8().data());\n\tif (!sd)\n\t\treturn;\n\n\tdouble v;\n\twxString val = w->GetValue();\n\tval.Replace(\"%\", \"\");\n\tif (!val.ToDouble(&v))\n\t\treturn;\n\n\tw->ChangeValue(wxString::Format(\"%0.0f%%\", v));\n\tapp->SetSliderValue(name, isLo, (float)v / 100.0f);\n\tapp->SetSliderChanged(name, isLo);\n\n\tif (isLo)\n\t\tsd->sliderLo->SetValue(v);\n\telse\n\t\tsd->sliderHi->SetValue(v);\n\n\tSetPresetChanged();\n\tapp->UpdatePreview();\n}\n\nvoid BodySlideFrame::OnSearchChange(wxCommandEvent& WXUNUSED(event)) {\n\tapp->PopulateOutfitList(\"\");\n}\n\nvoid BodySlideFrame::OnOutfitSearchChange(wxCommandEvent& WXUNUSED(event)) {\n\tapp->PopulateOutfitList(\"\");\n}\n\nvoid BodySlideFrame::OnSliderFilterChanged(wxCommandEvent& WXUNUSED(event)) {\n\tDoFilterSliders();\n}\n\nvoid BodySlideFrame::OnPresetFilterChanged(wxCommandEvent& WXUNUSED(event)) {\n\tapp->PopulatePresetList(\"\");\n}\n\nvoid BodySlideFrame::DoFilterSliders() {\n\tsliderScroll->Freeze();\n\n\twxString filterStr = sliderFilter->GetValue();\n\tfilterStr.MakeLower();\n\n\twxArrayString filterStrings;\n\n\t// Split string for \"or\" filtering\n\twxStringTokenizer tokenizer(filterStr, \",;\");\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString token = tokenizer.GetNextToken();\n\t\ttoken.Trim().Trim(false);\n\t\tfilterStrings.Add(token);\n\t}\n\n\tstd::set<std::string> matchedSliders;\n\n\tfor (auto& sliderDisplay : sliderDisplays) {\n\t\tif (!sliderDisplay.second)\n\t\t\tcontinue;\n\n\t\t// Filter slider by display name or category\n\t\twxString sliderStr = wxString::FromUTF8(sliderDisplay.first).MakeLower();\n\t\twxString displayStr = wxString::FromUTF8(sliderDisplay.second->displayName).MakeLower();\n\t\twxString categoryStr = wxString::FromUTF8(sliderDisplay.second->categoryName).MakeLower();\n\n\t\t// Check if category is disabled\n\t\tbool disabledCat = false;\n\n\t\tconst std::string& categoryName = sliderDisplay.second->categoryName;\n\t\tif (!categoryName.empty()) {\n\t\t\tSliderCategoryUI* sc = GetSliderCategory(categoryName);\n\t\t\tif (sc && !sc->isEnabled)\n\t\t\t\tdisabledCat = true;\n\t\t}\n\n\t\tbool show = filterStrings.empty();\n\t\tif (!show) {\n\t\t\tfor (auto& fstr : filterStrings) {\n\t\t\t\t// Split string by space for \"and\" filtering\n\t\t\t\tbool matched = false;\n\n\t\t\t\twxStringTokenizer andTokenizer(fstr, \" \");\n\t\t\t\twhile (andTokenizer.HasMoreTokens()) {\n\t\t\t\t\twxString token = andTokenizer.GetNextToken();\n\t\t\t\t\ttoken.Trim().Trim(false);\n\n\t\t\t\t\tif (displayStr.Contains(token) || sliderStr.Contains(token) || (!categoryStr.empty() && categoryStr.Contains(token)))\n\t\t\t\t\t\tmatched = true;\n\t\t\t\t\telse {\n\t\t\t\t\t\tmatched = false;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (matched) {\n\t\t\t\t\tshow = true;\n\t\t\t\t\tmatchedSliders.insert(sliderDisplay.first);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (disabledCat)\n\t\t\tshow = false;\n\n\t\tif (show) {\n\t\t\tif (!sliderDisplay.second->isShown)\n\t\t\t\tsliderDisplay.second->Show();\n\t\t}\n\t\telse {\n\t\t\tif (sliderDisplay.second->isShown)\n\t\t\t\tsliderDisplay.second->Show(false);\n\t\t}\n\t}\n\n\tfor (auto& sliderCategory : sliderCategories) {\n\t\tif (!sliderCategory.second)\n\t\t\tcontinue;\n\n\t\tbool showCat = false;\n\n\t\tif (!filterStrings.empty()) {\n\t\t\tfor (auto& sliderName : sliderCategory.second->sliderNames) {\n\t\t\t\tif (matchedSliders.find(sliderName) != matchedSliders.end())\n\t\t\t\t\tshowCat = true; // Show category if any slider in it was matched\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tshowCat = true; // Without a filter, show all categories\n\n\t\tsliderCategory.second->Show(showCat);\n\t}\n\n\tsliderScroll->Thaw();\n\tsliderScroll->Layout();\n\tsliderScroll->FitInside();\n}\n\nvoid BodySlideFrame::OnCategoryCheckChanged(wxCommandEvent& event) {\n\twxWindow* w = (wxWindow*)event.GetEventObject();\n\tif (!w)\n\t\treturn;\n\n\twxCheckBox* cb = (wxCheckBox*)event.GetEventObject();\n\tif (!cb)\n\t\treturn;\n\n\tstd::string categoryName = cb->GetName().ToUTF8().data();\n\n\tSliderCategoryUI* sc = GetSliderCategory(categoryName);\n\tif (sc) {\n\t\tsc->isEnabled = event.IsChecked();\n\n\t\tDoFilterSliders();\n\n\t\tint scrollPos = sliderScroll->GetScrollPos(wxOrientation::wxVERTICAL);\n\t\tsliderScroll->Scroll(0, scrollPos);\n\t}\n}\n\nvoid BodySlideFrame::OnCategoryTabButton(wxCommandEvent& event) {\n\twxWindow* w = (wxWindow*)event.GetEventObject();\n\tif (!w)\n\t\treturn;\n\n\twxStateButton* tabButton = (wxStateButton*)event.GetEventObject();\n\tif (!tabButton)\n\t\treturn;\n\n\tstd::string categoryName = tabButton->GetName().ToUTF8().data();\n\n\tSliderCategoryUI* sc = GetSliderCategory(categoryName);\n\tif (sc) {\n\t\tif (!sc->isEnabled) {\n\t\t\tsc->check->SetValue(true);\n\t\t\tsc->isEnabled = true;\n\t\t\tDoFilterSliders();\n\t\t}\n\n\t\tint scroll_rate_y = 0;\n\t\tsliderScroll->GetScrollPixelsPerUnit(nullptr, &scroll_rate_y);\n\n\t\twxPoint window_pos = sliderScroll->CalcUnscrolledPosition(sc->check->GetPosition());\n\t\tsliderScroll->Scroll(0, window_pos.y / scroll_rate_y);\n\t}\n}\n\nvoid BodySlideFrame::OnZapCheckChanged(wxCommandEvent& event) {\n\twxWindow* w = (wxWindow*)event.GetEventObject();\n\tif (!w)\n\t\treturn;\n\n\twxString sn;\n\tbool isLo = true;\n\tif (!w->GetName().EndsWith(\"|ZLO\", &sn)) {\n\t\tisLo = false;\n\t\tif (!w->GetName().EndsWith(\"|ZHI\", &sn)) {\n\t\t\tevent.Skip();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tstd::string sliderName{sn.ToUTF8()};\n\twxLogMessage(\"Zap '%s' %s.\", sn, event.IsChecked() ? \"checked\" : \"unchecked\");\n\n\tSliderDisplay* slider = GetSliderDisplay(sliderName);\n\tif (slider) {\n\t\tbool checked = event.IsChecked();\n\t\tif (checked) {\n\t\t\tif (slider->oneSize) {\n\t\t\t\tapp->SetSliderValue(sn, false, 1.0f);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapp->SetSliderValue(sn, true, 1.0f);\n\t\t\t\tapp->SetSliderValue(sn, false, 1.0f);\n\t\t\t\tif (isLo)\n\t\t\t\t\tslider->zapCheckHi->SetValue(true);\n\t\t\t\telse\n\t\t\t\t\tslider->zapCheckLo->SetValue(true);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tif (slider->oneSize) {\n\t\t\t\tapp->SetSliderValue(sn, false, 0.0f);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tapp->SetSliderValue(sn, true, 0.0f);\n\t\t\t\tapp->SetSliderValue(sn, false, 0.0f);\n\t\t\t\tif (isLo)\n\t\t\t\t\tslider->zapCheckHi->SetValue(false);\n\t\t\t\telse\n\t\t\t\t\tslider->zapCheckLo->SetValue(false);\n\t\t\t}\n\t\t}\n\n\t\tapp->SetZapChoice(sliderName, checked);\n\t}\n\n\tapp->SetSliderChanged(sn, isLo);\n\n\tstd::vector<std::string> zapToggles = app->GetSliderZapToggles(sn);\n\tfor (auto& toggle : zapToggles) {\n\t\twxLogMessage(\"Zap '%s' toggled.\", toggle);\n\n\t\tapp->SetSliderValue(toggle, true, 1.0f - app->GetSliderValue(toggle, true));\n\t\tapp->SetSliderValue(toggle, false, 1.0f - app->GetSliderValue(toggle, false));\n\t\tapp->SetSliderChanged(toggle, false);\n\n\t\tslider = GetSliderDisplay(toggle);\n\t\tif (slider) {\n\t\t\tif (slider->zapCheckHi)\n\t\t\t\tslider->zapCheckHi->SetValue(!slider->zapCheckHi->GetValue());\n\t\t\tif (slider->zapCheckLo)\n\t\t\t\tslider->zapCheckLo->SetValue(!slider->zapCheckLo->GetValue());\n\t\t}\n\t}\n\n\tSetPresetChanged();\n\n\twxBeginBusyCursor();\n\tif (app->IsUVSlider(sn))\n\t\tapp->UpdatePreview();\n\telse\n\t\tapp->RebuildPreviewMeshes();\n\twxEndBusyCursor();\n}\n\nvoid BodySlideFrame::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) {\n\tint i = 0;\n\ti++;\n\treturn;\n}\n\nvoid BodySlideFrame::OnDelayLoad(wxTimerEvent& WXUNUSED(event)) {\n\tif (app)\n\t\tapp->LoadData();\n\n\tdelayLoad.Stop();\n}\n\nvoid BodySlideFrame::OnChooseGroups(wxCommandEvent& WXUNUSED(event)) {\n\tstd::vector<std::string> groupNames;\n\tstd::unordered_set<std::string> curGroupNames;\n\tapp->GetAllGroupNames(groupNames);\n\n\twxString srch = search->GetValue();\n\twxStringTokenizer tokenizer(srch, \",;\");\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString token = tokenizer.GetNextToken();\n\t\ttoken.Trim();\n\t\ttoken.Trim(false);\n\t\tcurGroupNames.insert(token.ToUTF8().data());\n\t}\n\n\twxArrayString grpChoices;\n\twxArrayInt grpSelections;\n\tint idx = 0;\n\tfor (auto& g : groupNames) {\n\t\tgrpChoices.Add(wxString::FromUTF8(g));\n\t\tif (curGroupNames.find(g) != curGroupNames.end())\n\t\t\tgrpSelections.Add(idx);\n\n\t\tidx++;\n\t}\n\n\tgrpChoices.Add(\"Unassigned\");\n\n\t// Cast and use wxAnyChoiceDialog \"Create\" function so we can set the wxLB_EXTENDED flag for the internal wxCheckListBox\n\twxMultiChoiceDialog chooser{};\n\twxAnyChoiceDialog* anyChooser = dynamic_cast<wxAnyChoiceDialog*>(&chooser);\n\tanyChooser->Create(this, _(\"Choose groups to filter outfit list\"), _(\"Choose Groups\"), grpChoices, wxCHOICEDLG_STYLE, wxDefaultPosition, wxLB_ALWAYS_SB | wxLB_EXTENDED);\n\tchooser.SetSelections(grpSelections);\n\n\twxString filter;\n\tif (chooser.ShowModal() == wxID_OK) {\n\t\twxArrayInt sel = chooser.GetSelections();\n\t\tfor (size_t i = 0; i < sel.size(); i++) {\n\t\t\tif (i > 0)\n\t\t\t\tfilter += \", \";\n\t\t\tfilter += grpChoices[sel[i]];\n\t\t}\n\t\tsearch->ChangeValue(filter);\n\t\tapp->PopulateOutfitList(\"\");\n\t}\n}\n\nvoid BodySlideFrame::OnBrowseOutfitFolder(wxCommandEvent& WXUNUSED(event)) {\n\tif (!app->HasActiveProject())\n\t\treturn;\n\n\tauto& activeSet = app->GetActiveSet();\n\n\twxFileName folderPath(wxString::FromUTF8(activeSet.GetBaseDataPath()), wxEmptyString);\n\tfolderPath.AppendDir(wxString::FromUTF8(activeSet.GetDefaultDataFolder()));\n\tif (folderPath.IsRelative())\n\t\tfolderPath.MakeAbsolute(wxString::FromUTF8(app->GetProjectPath()));\n\n\tif (!folderPath.FileExists() && folderPath.DirExists())\n\t\twxLaunchDefaultApplication(folderPath.GetPath());\n}\n\nvoid BodySlideFrame::OnSaveGroups(wxCommandEvent& WXUNUSED(event)) {\n\tif (OutfitIsEmpty())\n\t\treturn;\n\n\twxFileDialog saveGroupDialog(this,\n\t\t\t\t\t\t\t\t _(\"Choose or create group file\"),\n\t\t\t\t\t\t\t\t wxString::FromUTF8(app->GetProjectPath()) + \"/SliderGroups\",\n\t\t\t\t\t\t\t\t wxEmptyString,\n\t\t\t\t\t\t\t\t \"Group Files (*.xml)|*.xml\",\n\t\t\t\t\t\t\t\t wxFD_SAVE);\n\tif (saveGroupDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxString fName = saveGroupDialog.GetPath();\n\twxString gName;\n\tint ret = 0;\n\n\tdo {\n\t\tgName = wxGetTextFromUser(_(\"What would you like the new group to be called?\"), _(\"New Group Name\"));\n\t\tif (gName.IsEmpty())\n\t\t\treturn;\n\n\t\tret = app->SaveGroupList(fName.ToUTF8().data(), gName.ToUTF8().data());\n\t} while (ret == 2);\n\n\tif (ret == 0) {\n\t\tapp->LoadAllGroups();\n\t\tsearch->ChangeValue(gName);\n\t\toutfitsearch->ChangeValue(\"\");\n\t\tapp->PopulateOutfitList(\"\");\n\t}\n}\n\nvoid BodySlideFrame::OnRefreshGroups(wxCommandEvent& WXUNUSED(event)) {\n\tapp->LoadAllGroups();\n}\n\nvoid BodySlideFrame::OnRefreshOutfits(wxCommandEvent& WXUNUSED(event)) {\n\tapp->RefreshOutfitList();\n\n\tstd::string outfitName = BodySlideConfig[\"SelectedOutfit\"];\n\tapp->ActivateOutfit(outfitName);\n}\n\nvoid BodySlideFrame::OnRegexOutfits(wxCommandEvent& WXUNUSED(event)) {\n\tapp->PopulateOutfitList(\"\");\n}\n\nvoid BodySlideFrame::OnFilterHasZaps(wxCommandEvent& WXUNUSED(event)) {\n\tapp->PopulateFilterData();\n\tapp->PopulateOutfitList(\"\");\n}\n\nvoid BodySlideFrame::OnChooseOutfit(wxCommandEvent& event) {\n\tstd::string sstr{event.GetString().ToUTF8()};\n\tapp->ActivateOutfit(sstr);\n}\n\nvoid BodySlideFrame::OnChoosePreset(wxCommandEvent& event) {\n\tstd::string sstr{event.GetString().ToUTF8()};\n\tapp->ActivatePreset(sstr);\n}\n\nvoid BodySlideFrame::OnDeleteProject(wxCommandEvent& WXUNUSED(event)) {\n\tint res = wxMessageBox(_(\"Do you really wish to delete the selected project?\"), _(\"Delete Project\"), wxYES_NO | wxICON_WARNING, this);\n\tif (res != wxYES)\n\t\treturn;\n\n\tstd::string outfitName = BodySlideConfig[\"SelectedOutfit\"];\n\tapp->DeleteOutfit(outfitName);\n}\n\nvoid BodySlideFrame::OnDeletePreset(wxCommandEvent& WXUNUSED(event)) {\n\tint res = wxMessageBox(_(\"Do you really wish to delete the selected preset?\"), _(\"Delete Preset\"), wxYES_NO | wxICON_WARNING, this);\n\tif (res != wxYES)\n\t\treturn;\n\n\tstd::string presetName = BodySlideConfig[\"SelectedPreset\"];\n\tapp->DeletePreset(presetName);\n}\n\nvoid BodySlideFrame::OnSavePreset(wxCommandEvent& WXUNUSED(event)) {\n\tif (!btnSavePreset->IsEnabled())\n\t\treturn;\n\n\tif (OutfitIsEmpty())\n\t\treturn;\n\n\tstd::string presetName = BodySlideConfig[\"SelectedPreset\"];\n\tif (presetName.empty())\n\t\treturn;\n\n\tint error = app->UpdateSliderPositions(presetName);\n\tif (error) {\n\t\twxLogError(\"Failed to save preset (%d)!\", error);\n\t\twxMessageBox(wxString::Format(_(\"Failed to save preset (%d)!\"), error), _(\"Error\"));\n\t}\n\n\tSetPresetChanged(false);\n\tapp->LoadPresets(\"\");\n\tapp->PopulatePresetList(presetName);\n}\n\nvoid BodySlideFrame::OnSavePresetAs(wxCommandEvent& WXUNUSED(event)) {\n\tif (OutfitIsEmpty())\n\t\treturn;\n\n\tstd::vector<std::string> groups;\n\tPresetSaveDialog psd(this);\n\n\tapp->GetAllGroupNames(psd.allGroupNames);\n\tpsd.FilterGroups();\n\tpsd.ShowModal();\n\tif (psd.outFileName.empty())\n\t\treturn;\n\n\tstd::string fname = psd.outFileName;\n\tstd::string presetName = psd.outPresetName;\n\tgroups.assign(psd.outGroups.begin(), psd.outGroups.end());\n\n\tint error = app->SaveSliderPositions(fname, presetName, groups);\n\tif (error) {\n\t\twxLogError(\"Failed to save preset as '%s' (%d)!\", fname, error);\n\t\twxMessageBox(wxString::Format(_(\"Failed to save preset as '%s' (%d)!\"), fname, error), \"Error\");\n\t}\n\n\tSetPresetChanged(false);\n\tapp->LoadPresets(\"\");\n\tapp->PopulatePresetList(presetName);\n\tBodySlideConfig.SetValue(\"SelectedPreset\", presetName);\n}\n\nvoid BodySlideFrame::OnGroupManager(wxCommandEvent& WXUNUSED(event)) {\n\tstd::vector<std::string> outfits;\n\tapp->GetOutfits(outfits);\n\n\tGroupManager gm(this, outfits);\n\tgm.ShowModal();\n\tapp->LoadPresets(\"\");\n}\n\nvoid BodySlideFrame::OnConflictPopup(wxMouseEvent& WXUNUSED(event)) {\n\tstd::vector<std::string> conflictingOutfits = app->GetConflictingOutfits();\n\tstd::string currentOutfitName = BodySlideConfig[\"SelectedOutfit\"];\n\n\tint id = fileCollisionMenu->GetMenuItemCount();\n\twhile (id--)\n\t\tfileCollisionMenu->Delete(id);\n\n\tfor (id = 0; id < static_cast<int>(conflictingOutfits.size()); id++) {\n\t\tstd::string& outfitName = conflictingOutfits[id];\n\t\twxMenuItem* outfitItem = fileCollisionMenu->AppendRadioItem(id, wxString::FromUTF8(outfitName));\n\n\t\tif (outfitName == currentOutfitName)\n\t\t\toutfitItem->Check();\n\t}\n\n\tid = GetPopupMenuSelectionFromUser(*fileCollisionMenu, wxDefaultPosition);\n\tif (id < 0)\n\t\treturn;\n\n\tstd::string& selectedOutfitName = conflictingOutfits[id];\n\tif (selectedOutfitName != currentOutfitName)\n\t\tapp->ActivateOutfit(selectedOutfitName);\n}\n\nvoid BodySlideFrame::OnOutfitChoiceSelect(wxCommandEvent& WXUNUSED(event)) {\n\tapp->SetDefaultBuildSelection();\n}\n\nvoid BodySlideFrame::OnHighToLow(wxCommandEvent& WXUNUSED(event)) {\n\tapp->CopySliderValues(false);\n}\n\nvoid BodySlideFrame::OnLowToHigh(wxCommandEvent& WXUNUSED(event)) {\n\tapp->CopySliderValues(true);\n}\n\nvoid BodySlideFrame::OnPreview(wxCommandEvent& WXUNUSED(event)) {\n\tif (previewVisible) {\n\t\t// Hide preview\n\t\tUnsplitPreview();\n\t\tpreviewVisible = false;\n\t\tBodySlideConfig.SetBoolValue(\"BodySlideFrame.previewVisible\", false);\n\t\tUpdatePreviewButtonLabel();\n\t}\n\telse {\n\t\t// If preview is popped out, dock it back instead\n\t\tif (app->IsPreviewPoppedOut()) {\n\t\t\tapp->DockPreview();\n\t\t\treturn;\n\t\t}\n\n\t\t// Show preview\n\t\tSplitPreview();\n\t\tpreviewVisible = true;\n\t\tBodySlideConfig.SetBoolValue(\"BodySlideFrame.previewVisible\", true);\n\t\tUpdatePreviewButtonLabel();\n\n\t\t// Trigger preview load if outfit is selected\n\t\tif (!OutfitIsEmpty()) {\n\t\t\tapp->InitPreviewPanel();\n\t\t\tif (app->HasActiveProject()) {\n\t\t\t\tapp->InitPreview();\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid BodySlideFrame::OnSashPosChanged(wxSplitterEvent& event) {\n\tif (!IsVisible())\n\t\treturn;\n\n\tint pos = event.GetSashPosition();\n\tBodySlideConfig.SetValue(\"BodySlideFrame.sashpos\", pos);\n\tsavedSashPosition = pos;\n\tsavedPreviewWidth = splitter->GetSize().GetWidth() - pos;\n\tif (savedPreviewWidth > 0)\n\t\tBodySlideConfig.SetValue(\"BodySlideFrame.previewWidth\", savedPreviewWidth);\n}\n\nvoid BodySlideFrame::OnPreviewPopout(wxCommandEvent& WXUNUSED(event)) {\n\tapp->PopOutPreview();\n}\n\nvoid BodySlideFrame::OnPreviewWindowClosed() {\n\tapp->DockPreview();\n}\n\nvoid BodySlideFrame::UnsplitPreview() {\n\tif (!splitter || !splitter->IsSplit())\n\t\treturn;\n\n\tsavedSashPosition = splitter->GetSashPosition();\n\tsavedPreviewWidth = splitter->GetSize().GetWidth() - savedSashPosition;\n\tBodySlideConfig.SetValue(\"BodySlideFrame.sashpos\", savedSashPosition);\n\tBodySlideConfig.SetValue(\"BodySlideFrame.previewWidth\", savedPreviewWidth);\n\tsplitter->Unsplit(previewPanel);\n\n\tif (savedPreviewWidth > 0) {\n\t\twxSize sz = GetSize();\n\t\tsz.SetWidth(sz.GetWidth() - savedPreviewWidth);\n\t\tSetSize(sz);\n\t}\n}\n\nvoid BodySlideFrame::SplitPreview(wxPanel* panel) {\n\tif (!splitter || splitter->IsSplit())\n\t\treturn;\n\n\twxPanel* panelToSplit = panel ? panel : previewPanel;\n\tif (!panelToSplit)\n\t\treturn;\n\n\tint previewWidth = savedPreviewWidth;\n\tif (previewWidth <= 0)\n\t\tpreviewWidth = BodySlideConfig.GetIntValue(\"BodySlideFrame.previewWidth\");\n\tif (previewWidth <= 0)\n\t\tpreviewWidth = 400;\n\n\tint sashPos = savedSashPosition;\n\tif (sashPos <= 0)\n\t\tsashPos = BodySlideConfig.GetIntValue(\"BodySlideFrame.sashpos\");\n\tif (sashPos <= 0)\n\t\tsashPos = GetClientSize().GetWidth();\n\n\twxSize sz = GetSize();\n\tsz.SetWidth(sz.GetWidth() + previewWidth);\n\tSetSize(sz);\n\n\tpanelToSplit->Show();\n\tsplitter->SplitVertically(leftPanel, panelToSplit, sashPos);\n}\n\nvoid BodySlideFrame::UpdatePreviewButtonLabel() {\n\tauto btn = (wxButton*)FindWindowByName(\"btnPreview\", this);\n\tif (btn)\n\t\tbtn->SetLabel(previewVisible ? _(\"Hide Preview\") : _(\"Show Preview\"));\n}\n\nvoid BodySlideFrame::OnBuildBodies(wxCommandEvent& WXUNUSED(event)) {\n\tif (OutfitIsEmpty())\n\t\treturn;\n\n\tbool tri = false;\n\tbool forceNormals = false;\n\n\tauto cbMorphs = (wxCheckBox*)FindWindowByName(\"cbMorphs\");\n\tif (cbMorphs)\n\t\ttri = cbMorphs->IsChecked();\n\n\tauto cbForceBodyNormals = (wxCheckBox*)FindWindowByName(\"cbForceBodyNormals\");\n\tif (cbForceBodyNormals)\n\t\tforceNormals = cbForceBodyNormals->IsChecked();\n\n\tif (wxGetKeyState(WXK_CONTROL))\n\t\tapp->BuildBodies(true, false, tri, forceNormals);\n\telse if (wxGetKeyState(WXK_ALT))\n\t\tapp->BuildBodies(false, true, tri, forceNormals);\n\telse\n\t\tapp->BuildBodies(false, false, tri, forceNormals);\n}\n\nvoid BodySlideFrame::OnBatchBuild(wxCommandEvent& WXUNUSED(event)) {\n\tif (OutfitIsEmpty())\n\t\treturn;\n\n\tif (app->clippingFixStrength > 0.0f) {\n\t\tint answer = wxMessageBox(\n\t\t\t_(\"Fix Clipping is enabled for this batch build.\\n\\n\"\n\t\t\t  \"Use this carefully: applying clipping fixes to many outfits at once can create unwelcome side effects on some meshes.\\n\\n\"\n\t\t\t  \"Consider building outfits one-by-one and checking each result in Preview.\\n\\n\"\n\t\t\t  \"Do you want to continue with batch build?\"),\n\t\t\t_(\"Warning\"),\n\t\t\twxYES_NO | wxNO_DEFAULT | wxICON_WARNING,\n\t\t\tthis);\n\n\t\tif (answer != wxYES)\n\t\t\treturn;\n\t}\n\n\twxArrayString oChoices;\n\tstd::vector<std::string> outfitChoices;\n\tstd::vector<std::string> toBuild;\n\n\tbool custpath = false;\n\tbool clean = false;\n\tbool tri = false;\n\tbool forceNormals = false;\n\n\tauto cbMorphs = (wxCheckBox*)FindWindowByName(\"cbMorphs\");\n\tif (cbMorphs)\n\t\ttri = cbMorphs->IsChecked();\n\n\tauto cbForceBodyNormals = (wxCheckBox*)FindWindowByName(\"cbForceBodyNormals\");\n\tif (cbForceBodyNormals)\n\t\tforceNormals = cbForceBodyNormals->IsChecked();\n\n\tif (wxGetKeyState(WXK_CONTROL))\n\t\tcustpath = true;\n\telse if (wxGetKeyState(WXK_ALT))\n\t\tclean = true;\n\n\tapp->GetFilteredOutfits(outfitChoices);\n\n\tstd::map<std::string, uint32_t> outfitIndices;\n\n\tuint32_t idx = 0;\n\tfor (auto& o : outfitChoices) {\n\t\toChoices.Add(wxString::FromUTF8(o));\n\t\toutfitIndices[o] = idx;\n\t\tidx++;\n\t}\n\n\twxXmlResource* rsrc = wxXmlResource::Get();\n\twxDialog* batchBuildChooser = rsrc->LoadDialog(this, \"dlgBatchBuild\");\n\tif (!batchBuildChooser)\n\t\treturn;\n\n\tbatchBuildChooser->SetSize(batchBuildChooser->FromDIP(wxSize(650, 300)));\n\tbatchBuildChooser->SetSizeHints(batchBuildChooser->FromDIP(wxSize(650, 300)), batchBuildChooser->FromDIP(wxSize(650, -1)));\n\tbatchBuildChooser->CenterOnParent();\n\n\t// Load BuildSelection file\n\tBuildSelectionFile buildSelFile;\n\tBuildSelection buildSelection;\n\tapp->GetBuildSelection(buildSelFile, buildSelection);\n\n\tbatchBuildList = XRCCTRL((*batchBuildChooser), \"batchBuildList\", wxCheckListBox);\n\tbatchBuildList->Bind(wxEVT_RIGHT_UP, &BodySlideFrame::OnBatchBuildContext, this);\n\n\tbatchBuildList->Append(oChoices);\n\n\tfor (uint32_t i = 0; i < oChoices.size(); i++)\n\t\tbatchBuildList->Check(i);\n\n\tfor (auto& outFile : app->outFileCount) {\n\t\tif (outFile.second.size() > 1) {\n\t\t\tstd::vector<std::string> outfitsInBuild;\n\t\t\tfor (auto& outfit : outFile.second) {\n\t\t\t\t// Only if it's going to be batch built\n\t\t\t\tif (std::find(outfitChoices.begin(), outfitChoices.end(), outfit) != outfitChoices.end())\n\t\t\t\t\toutfitsInBuild.push_back(outfit);\n\t\t\t}\n\n\t\t\t// Same file would not be written more than once\n\t\t\tif (outfitsInBuild.size() <= 1)\n\t\t\t\tcontinue;\n\n\t\t\tstd::string outputChoice = buildSelection.GetOutputChoice(outFile.first);\n\t\t\tif (!outputChoice.empty()) {\n\t\t\t\tfor (auto& outfit : outfitsInBuild) {\n\t\t\t\t\tif (outfit != outputChoice) {\n\t\t\t\t\t\t// Uncheck choice by default\n\t\t\t\t\t\tbatchBuildList->Check(outfitIndices[outfit], false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (batchBuildChooser->ShowModal() == wxID_OK) {\n\t\twxArrayInt sel;\n\t\tbatchBuildList->GetCheckedItems(sel);\n\t\ttoBuild.clear();\n\t\tfor (size_t i = 0; i < sel.size(); i++)\n\t\t\ttoBuild.push_back(outfitChoices[sel[i]]);\n\n\t\tdelete batchBuildChooser;\n\t}\n\telse {\n\t\tdelete batchBuildChooser;\n\t\treturn;\n\t}\n\n\tstd::map<std::string, std::string> failedOutfits;\n\tint ret;\n\tif (custpath) {\n\t\tstd::string path = wxDirSelector(_(\"Choose a folder to contain the saved files\")).ToStdString();\n\t\tif (path.empty())\n\t\t\treturn;\n\n\t\tret = app->BuildListBodies(toBuild, failedOutfits, false, tri, forceNormals, path + PathSepStr);\n\t}\n\telse if (clean)\n\t\tret = app->BuildListBodies(toBuild, failedOutfits, true, tri, forceNormals);\n\telse\n\t\tret = app->BuildListBodies(toBuild, failedOutfits, false, tri, forceNormals);\n\n\twxLog::FlushActive();\n\n\tif (ret == 0) {\n\t\twxLogMessage(\"All sets processed successfully!\");\n\t\twxMessageBox(_(\"All sets processed successfully!\"), _(\"Complete\"), wxICON_INFORMATION);\n\t}\n\telse if (ret == 3) {\n\t\twxArrayString errlist;\n\t\tfor (auto& e : failedOutfits) {\n\t\t\twxString ename = wxString::FromUTF8(e.first);\n\t\t\twxLogError(\"Failed to build '%s': %s\", ename, e.second);\n\t\t\terrlist.Add(ename + \":\" + e.second);\n\t\t}\n\n\t\twxSingleChoiceDialog errdisplay(this, _(\"The following sets failed\"), _(\"Failed\"), errlist, (void**)0, wxDEFAULT_DIALOG_STYLE | wxOK | wxRESIZE_BORDER);\n\t\terrdisplay.ShowModal();\n\t}\n}\n\nvoid BodySlideFrame::OnBatchBuildContext(wxMouseEvent& WXUNUSED(event)) {\n\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"batchBuildContext\");\n\tif (menu) {\n\t\tmenu->Bind(wxEVT_MENU, &BodySlideFrame::OnBatchBuildSelect, this);\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid BodySlideFrame::OnBatchBuildSelect(wxCommandEvent& event) {\n\tif (event.GetId() == XRCID(\"batchBuildNone\")) {\n\t\tfor (uint32_t i = 0; i < batchBuildList->GetCount(); i++)\n\t\t\tbatchBuildList->Check(i, false);\n\t}\n\telse if (event.GetId() == XRCID(\"batchBuildAll\")) {\n\t\tfor (uint32_t i = 0; i < batchBuildList->GetCount(); i++)\n\t\t\tbatchBuildList->Check(i);\n\t}\n\telse if (event.GetId() == XRCID(\"batchBuildInvert\")) {\n\t\tfor (uint32_t i = 0; i < batchBuildList->GetCount(); i++)\n\t\t\tbatchBuildList->Check(i, !batchBuildList->IsChecked(i));\n\t}\n}\n\nvoid BodySlideFrame::OnOutfitStudio(wxCommandEvent& WXUNUSED(event)) {\n\tapp->LaunchOutfitStudio();\n}\n\nvoid BodySlideFrame::OnChooseTargetGame(wxCommandEvent& event) {\n\twxChoice* choiceTargetGame = (wxChoice*)event.GetEventObject();\n\twxWindow* parent = choiceTargetGame->GetGrandParent();\n\twxFilePickerCtrl* fpSkeletonFile = XRCCTRL(*parent, \"fpSkeletonFile\", wxFilePickerCtrl);\n\twxChoice* choiceSkeletonRoot = XRCCTRL(*parent, \"choiceSkeletonRoot\", wxChoice);\n\n\tTargetGame targ = (TargetGame)choiceTargetGame->GetSelection();\n\tswitch (targ) {\n\t\tcase OB:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_ob.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Bip01\");\n\t\t\tbreak;\n\t\tcase FO3:\n\t\tcase FONV:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_fo3nv.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Bip01\");\n\t\t\tbreak;\n\t\tcase SKYRIM:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_female_sk.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"NPC Root [Root]\");\n\t\t\tbreak;\n\t\tcase SKYRIMSE:\n\t\tcase SKYRIMVR:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_female_sse.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"NPC Root [Root]\");\n\t\t\tbreak;\n\t\tcase SF:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_female_sf.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Root\");\n\t\t\tbreak;\n\t\tcase FO4:\n\t\tcase FO4VR:\n\t\tcase FO76:\n\t\tdefault:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_fo4.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Root\");\n\t\t\tbreak;\n\t}\n\n\twxCheckListBox* dataFileList = XRCCTRL(*parent, \"DataFileList\", wxCheckListBox);\n\twxString dataDir = app->GetGameDataPath(targ);\n\n\twxDirPickerCtrl* dpGameDataPath = XRCCTRL(*parent, \"dpGameDataPath\", wxDirPickerCtrl);\n\tdpGameDataPath->SetPath(dataDir);\n\n\tSettingsFillDataFiles(dataFileList, dataDir, targ);\n}\n\nvoid BodySlideFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxString& dataDir, int targetGame) {\n\tdataFileList->Clear();\n\n\twxString cp = \"GameDataFiles/\" + TargetGames[targetGame];\n\twxString activatedFiles = Config[cp];\n\n\twxStringTokenizer tokenizer(activatedFiles, \";\");\n\tstd::map<wxString, bool> fsearch;\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString val = tokenizer.GetNextToken().Trim(false).Trim();\n\t\tval.MakeLower();\n\t\tfsearch[val] = true;\n\t}\n\n\twxArrayString files;\n\twxDir::GetAllFiles(dataDir, &files, \"*.ba2\", wxDIR_FILES);\n\twxDir::GetAllFiles(dataDir, &files, \"*.bsa\", wxDIR_FILES);\n\tfor (auto& file : files) {\n\t\tfile = file.AfterLast('/').AfterLast('\\\\');\n\t\tdataFileList->Insert(file, dataFileList->GetCount());\n\n\t\tif (fsearch.find(file.Lower()) == fsearch.end())\n\t\t\tdataFileList->Check(dataFileList->GetCount() - 1);\n\t}\n}\n\nvoid BodySlideFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog* settings = wxXmlResource::Get()->LoadDialog(this, \"dlgSettings\");\n\tif (settings) {\n\t\tsettings->SetSize(settings->FromDIP(wxSize(525, -1)));\n\t\tsettings->SetMinSize(settings->FromDIP(wxSize(525, -1)));\n\t\tsettings->CenterOnParent();\n\n\t\twxCollapsiblePane* advancedPane = XRCCTRL(*settings, \"advancedPane\", wxCollapsiblePane);\n\t\tadvancedPane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [&settings](wxCommandEvent&) { settings->Fit(); });\n\n\t\twxChoice* choiceTargetGame = XRCCTRL(*settings, \"choiceTargetGame\", wxChoice);\n\t\tchoiceTargetGame->Select(Config.GetIntValue(\"TargetGame\"));\n\n\t\twxDirPickerCtrl* dpGameDataPath = XRCCTRL(*settings, \"dpGameDataPath\", wxDirPickerCtrl);\n\t\twxString gameDataPath = wxString::FromUTF8(Config[\"GameDataPath\"]);\n\t\tdpGameDataPath->SetPath(gameDataPath);\n\n\t\twxDirPickerCtrl* dpOutputPath = XRCCTRL(*settings, \"dpOutputPath\", wxDirPickerCtrl);\n\t\twxString outputPath = wxString::FromUTF8(Config[\"OutputDataPath\"]);\n\t\tdpOutputPath->SetPath(outputPath);\n\n\t\twxDirPickerCtrl* dpProjectPath = XRCCTRL(*settings, \"dpProjectPath\", wxDirPickerCtrl);\n\t\twxString projectPath = wxString::FromUTF8(Config[\"ProjectPath\"]);\n\t\tdpProjectPath->SetPath(projectPath);\n\n\t\twxCheckBox* cbShowForceBodyNormals = XRCCTRL(*settings, \"cbShowForceBodyNormals\", wxCheckBox);\n\t\tcbShowForceBodyNormals->SetValue(Config.GetBoolValue(\"ShowForceBodyNormals\"));\n\n\t\twxCheckBox* cbBBOverrideWarn = XRCCTRL(*settings, \"cbBBOverrideWarn\", wxCheckBox);\n\t\tcbBBOverrideWarn->SetValue(Config.GetBoolValue(\"WarnBatchBuildOverride\"));\n\n\t\twxCheckBox* cbBSATextures = XRCCTRL(*settings, \"cbBSATextures\", wxCheckBox);\n\t\tcbBSATextures->SetValue(Config.GetBoolValue(\"BSATextureScan\"));\n\n\t\twxCheckBox* cbLeftMousePan = XRCCTRL(*settings, \"cbLeftMousePan\", wxCheckBox);\n\t\tcbLeftMousePan->SetValue(Config.GetBoolValue(\"Input/LeftMousePan\"));\n\n\t\twxCheckBox* cbBrushSettingsNearCursor = XRCCTRL(*settings, \"cbBrushSettingsNearCursor\", wxCheckBox);\n\t\tcbBrushSettingsNearCursor->SetValue(Config.GetBoolValue(\"Input/BrushSettingsNearCursor\"));\n\n\t\twxCheckBox* cbMaskHistory = XRCCTRL(*settings, \"cbMaskHistory\", wxCheckBox);\n\t\tcbMaskHistory->SetValue(Config.GetBoolValue(\"Input/MaskHistory\"));\n\n\t\t// Hide the single instance setting (only relevant for Outfit Studio)\n\t\tXRCCTRL(*settings, \"lbSingleInstanceBehavior\", wxStaticText)->Hide();\n\t\tXRCCTRL(*settings, \"choiceSingleInstanceBehavior\", wxChoice)->Hide();\n\n\t\twxChoice* choiceLanguage = XRCCTRL(*settings, \"choiceLanguage\", wxChoice);\n\t\tfor (size_t i = 0; i < SupportedLangs.size(); i++)\n\t\t\tchoiceLanguage->AppendString(wxLocale::GetLanguageName(SupportedLangs[i]));\n\n\t\tif (!choiceLanguage->SetStringSelection(wxLocale::GetLanguageName(Config.GetIntValue(\"Language\"))))\n\t\t\tchoiceLanguage->SetStringSelection(\"English\");\n\n\t\twxCheckBox* cbPerspectiveView = XRCCTRL(*settings, \"cbPerspectiveView\", wxCheckBox);\n\t\tcbPerspectiveView->SetValue(BodySlideConfig.GetBoolValue(\"Rendering/PerspectiveView\", true));\n\n\t\twxColourPickerCtrl* cpColorBackground = XRCCTRL(*settings, \"cpColorBackground\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorBackground\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorBackground.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorBackground.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorBackground.b\");\n\t\t\tcpColorBackground->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxColourPickerCtrl* cpColorWire = XRCCTRL(*settings, \"cpColorWire\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorWire\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorWire.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorWire.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorWire.b\");\n\t\t\tcpColorWire->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxColourPickerCtrl* cpColorPoints = XRCCTRL(*settings, \"cpColorPoints\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorPoints\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPoints.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPoints.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPoints.b\");\n\t\t\tcpColorPoints->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxColourPickerCtrl* cpColorPointsMasked = XRCCTRL(*settings, \"cpColorPointsMasked\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorPointsMasked\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPointsMasked.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPointsMasked.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPointsMasked.b\");\n\t\t\tcpColorPointsMasked->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxFilePickerCtrl* fpSkeletonFile = XRCCTRL(*settings, \"fpSkeletonFile\", wxFilePickerCtrl);\n\t\tfpSkeletonFile->SetPath(wxString::FromUTF8(Config[\"Anim/DefaultSkeletonReference\"]));\n\n\t\twxChoice* choiceSkeletonRoot = XRCCTRL(*settings, \"choiceSkeletonRoot\", wxChoice);\n\t\tchoiceSkeletonRoot->SetStringSelection(Config[\"Anim/SkeletonRootName\"]);\n\n\t\twxCheckListBox* dataFileList = XRCCTRL(*settings, \"DataFileList\", wxCheckListBox);\n\t\tSettingsFillDataFiles(dataFileList, gameDataPath, Config.GetIntValue(\"TargetGame\"));\n\n\t\tchoiceTargetGame->Bind(wxEVT_CHOICE, &BodySlideFrame::OnChooseTargetGame, this);\n\n\t\tif (settings->ShowModal() == wxID_OK) {\n\t\t\tTargetGame targ = (TargetGame)choiceTargetGame->GetSelection();\n\t\t\tConfig.SetValue(\"TargetGame\", targ);\n\n\t\t\tif (!dpGameDataPath->GetPath().IsEmpty()) {\n\t\t\t\twxFileName gameDataDir = dpGameDataPath->GetDirName();\n\t\t\t\tConfig.SetValue(\"GameDataPath\", gameDataDir.GetFullPath().ToUTF8().data());\n\t\t\t\tConfig.SetValue(\"GameDataPaths/\" + TargetGames[targ].ToStdString(), gameDataDir.GetFullPath().ToUTF8().data());\n\t\t\t}\n\n\t\t\t// set OutputDataPath even if it is empty\n\t\t\twxFileName outputDataDir = dpOutputPath->GetDirName();\n\t\t\tConfig.SetValue(\"OutputDataPath\", outputDataDir.GetFullPath().ToUTF8().data());\n\n\t\t\t// set ProjectPath even if it is empty\n\t\t\twxFileName projectDir = dpProjectPath->GetDirName();\n\t\t\tConfig.SetValue(\"ProjectPath\", projectDir.GetFullPath().ToUTF8().data());\n\n\t\t\twxArrayInt items;\n\t\t\twxString selectedfiles;\n\t\t\tfor (uint32_t i = 0; i < dataFileList->GetCount(); i++)\n\t\t\t\tif (!dataFileList->IsChecked(i))\n\t\t\t\t\tselectedfiles += dataFileList->GetString(i) + \"; \";\n\n\t\t\tselectedfiles = selectedfiles.BeforeLast(';');\n\t\t\tConfig.SetValue(\"GameDataFiles/\" + TargetGames[targ].ToStdString(), selectedfiles.ToUTF8().data());\n\n\t\t\tConfig.SetBoolValue(\"ShowForceBodyNormals\", cbShowForceBodyNormals->IsChecked());\n\t\t\tConfig.SetBoolValue(\"WarnBatchBuildOverride\", cbBBOverrideWarn->IsChecked());\n\t\t\tConfig.SetBoolValue(\"BSATextureScan\", cbBSATextures->IsChecked());\n\t\t\tConfig.SetBoolValue(\"Input/LeftMousePan\", cbLeftMousePan->IsChecked());\n\t\t\tConfig.SetBoolValue(\"Input/BrushSettingsNearCursor\", cbBrushSettingsNearCursor->IsChecked());\n\t\t\tConfig.SetBoolValue(\"Input/MaskHistory\", cbMaskHistory->IsChecked());\n\n\t\t\tint oldLang = Config.GetIntValue(\"Language\");\n\t\t\tint newLang = SupportedLangs[choiceLanguage->GetSelection()];\n\t\t\tif (oldLang != newLang) {\n\t\t\t\tConfig.SetValue(\"Language\", newLang);\n\t\t\t\tapp->InitLanguage();\n\t\t\t}\n\n\t\t\tBodySlideConfig.SetBoolValue(\"Rendering/PerspectiveView\", cbPerspectiveView->IsChecked());\n\n\t\t\twxColour colorBackground = cpColorBackground->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorBackground.r\", colorBackground.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorBackground.g\", colorBackground.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorBackground.b\", colorBackground.Blue());\n\n\t\t\twxColour colorWire = cpColorWire->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorWire.r\", colorWire.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorWire.g\", colorWire.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorWire.b\", colorWire.Blue());\n\n\t\t\twxColour colorPoints = cpColorPoints->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorPoints.r\", colorPoints.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorPoints.g\", colorPoints.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorPoints.b\", colorPoints.Blue());\n\n\t\t\twxColour colorPointsMasked = cpColorPointsMasked->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorPointsMasked.r\", colorPointsMasked.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorPointsMasked.g\", colorPointsMasked.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorPointsMasked.b\", colorPointsMasked.Blue());\n\n\t\t\twxFileName skeletonFile = fpSkeletonFile->GetFileName();\n\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", skeletonFile.GetFullPath().ToUTF8().data());\n\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", choiceSkeletonRoot->GetStringSelection().ToUTF8().data());\n\n\t\t\tConfig.SaveConfig(Config[\"AppDir\"] + \"/Config.xml\");\n\t\t\tapp->targetGame = targ;\n\t\t\tapp->InitArchives();\n\t\t\tapp->LoadAllCategories();\n\t\t\tapp->LoadAllGroups();\n\t\t\tapp->LoadSliderSets();\n\t\t\tapp->LoadData();\n\n\t\t\tRefreshTargetGameState();\n\t\t\tLayout();\n\t\t}\n\n\t\tdelete settings;\n\t}\n}\n\nvoid BodySlideFrame::OnAbout(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog* about = wxXmlResource::Get()->LoadDialog(this, \"dlgAbout\");\n\tif (about) {\n\t\tabout->SetSize(about->FromDIP(wxSize(625, 375)));\n\t\tabout->SetMinSize(about->FromDIP(wxSize(625, 375)));\n\t\tabout->CenterOnParent();\n\t\tabout->Bind(wxEVT_CHAR_HOOK, &BodySlideFrame::OnEnterClose, this);\n\t\tabout->Bind(wxEVT_HTML_LINK_CLICKED, &BodySlideFrame::OnLinkClicked, this);\n\t\tabout->ShowModal();\n\t\tdelete about;\n\t}\n}\n\nvoid BodySlideFrame::OnMoveWindow(wxMoveEvent& event) {\n\twxPoint p = GetPosition();\n\tBodySlideConfig.SetValue(\"BodySlideFrame.x\", p.x);\n\tBodySlideConfig.SetValue(\"BodySlideFrame.y\", p.y);\n\tevent.Skip();\n}\n\nvoid BodySlideFrame::OnSetSize(wxSizeEvent& event) {\n\tbool maximized = IsMaximized();\n\tif (!maximized) {\n\t\twxSize p = event.GetSize();\n\t\tBodySlideConfig.SetValue(\"BodySlideFrame.width\", p.x);\n\t\tBodySlideConfig.SetValue(\"BodySlideFrame.height\", p.y);\n\t}\n\n\tBodySlideConfig.SetBoolValue(\"BodySlideFrame.maximized\", maximized);\n\tevent.Skip();\n}\n\nvoid BodySlideFrame::OnEditProject(wxCommandEvent& WXUNUSED(event)) {\n\tstd::string projectName = BodySlideConfig[\"SelectedOutfit\"];\n\tapp->EditProject(projectName);\n}\n\nvoid BodySlideFrame::OnClippingStrengthChanged(wxCommandEvent& WXUNUSED(event)) {\n\tauto sliderClippingStrength = XRCCTRL(*this, \"sliderClippingStrength\", wxSlider);\n\tif (!sliderClippingStrength)\n\t\treturn;\n\n\tapp->clippingFixStrength = static_cast<float>(sliderClippingStrength->GetValue());\n\tapp->UpdateReferenceCheckboxState();\n\tapp->UpdatePreview();\n}\n\nvoid BodySlideFrame::RefreshTargetGameState() {\n\tauto cbMorphs = XRCCTRL(*this, \"cbMorphs\", wxCheckBox);\n\tif (cbMorphs) {\n\t\tbool buildMorphsDef = BodySlideConfig.GetBoolValue(\"BuildMorphs\");\n\n\t\tswitch (app->targetGame) {\n\t\t\tcase SKYRIM:\n\t\t\tcase FO4:\n\t\t\tcase FO4VR:\n\t\t\tcase SKYRIMSE:\n\t\t\tcase SKYRIMVR:\n\t\t\t\tcbMorphs->SetValue(buildMorphsDef);\n\t\t\t\tcbMorphs->Show();\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tcbMorphs->SetValue(false);\n\t\t\t\tcbMorphs->Hide();\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tauto cbForceBodyNormals = XRCCTRL(*this, \"cbForceBodyNormals\", wxCheckBox);\n\tif (cbForceBodyNormals) {\n\t\tif (Config.GetBoolValue(\"ShowForceBodyNormals\")) {\n\t\t\tbool forceBodyNormalsDef = BodySlideConfig.GetBoolValue(\"ForceBodyNormals\");\n\t\t\tcbForceBodyNormals->SetValue(forceBodyNormalsDef);\n\n\t\t\tswitch (app->targetGame) {\n\t\t\t\tcase SKYRIMSE:\n\t\t\t\tcase SKYRIMVR: cbForceBodyNormals->Show(); break;\n\t\t\t\tdefault: break;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t\tcbForceBodyNormals->Hide();\n\t}\n}\n\nSliderCategoryUI::SliderCategoryUI() {}\n\nbool SliderCategoryUI::Create(wxScrolledWindow* scrollWindow, wxSizer* sliderLayout, wxSizer* categoryTabSizer, const std::string& name, const std::vector<std::string>& sliders, bool pEnabled, bool pOneSize) {\n\tcategoryName = name;\n\tsliderNames = sliders;\n\n\tisEnabled = pEnabled;\n\toneSize = pOneSize;\n\n\tif (isCreated) {\n\t\tcheck->SetValue(isEnabled);\n\t\tlabel->SetLabel(name);\n\n\t\tShow();\n\t\treturn true;\n\t}\n\n\tif (!oneSize) {\n\t\tsliderLayout->AddSpacer(0);\n\n\t\tdummyPanel1 = new wxPanel(scrollWindow);\n\t\tdummyPanel1->SetBackgroundColour(wxColour(90, 90, 90));\n\t\tsliderLayout->Add(dummyPanel1, 0, wxTOP | wxBOTTOM | wxEXPAND, 10);\n\t}\n\n\tcheck = new wxCheckBox(scrollWindow, wxID_ANY, \"\");\n\tcheck->SetName(name);\n\tsliderLayout->Add(check, 0, wxRIGHT | wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL, 5);\n\tcheck->SetValue(isEnabled);\n\n\tlabel = new wxStaticText(scrollWindow, wxID_ANY, name);\n\tlabel->SetFont(wxFont(12, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, \"Andalus\"));\n\tlabel->SetForegroundColour(wxColour(200, 200, 200));\n\tsliderLayout->Add(label, 0, wxLEFT | wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);\n\n\tif (!oneSize) {\n\t\tdummyPanel2 = new wxPanel(scrollWindow);\n\t\tdummyPanel2->SetBackgroundColour(wxColour(90, 90, 90));\n\t\tsliderLayout->Add(dummyPanel2, 0, wxTOP | wxBOTTOM | wxEXPAND, 10);\n\t}\n\n\tsliderLayout->AddSpacer(0);\n\n\tif (categoryTabSizer) {\n\t\ttabButton = new wxStateButton(categoryTabSizer->GetContainingWindow(), wxID_ANY, name, wxDefaultPosition, wxDefaultSize, 0L, wxDefaultValidator, name, true);\n\t\tcategoryTabSizer->Add(tabButton, 0, 0, 0);\n\t}\n\n\tShow(false);\n\tisCreated = true;\n\treturn true;\n}\n\nvoid SliderCategoryUI::Show(bool show) {\n\tif (dummyPanel1)\n\t\tdummyPanel1->Show(show && !oneSize);\n\n\tcheck->Show(show);\n\tlabel->Show(show);\n\n\tif (dummyPanel2)\n\t\tdummyPanel2->Show(show && !oneSize);\n\n\tif (tabButton) {\n\t\tauto wrapSizer = (wxWrapSizer*)tabButton->GetContainingSizer();\n\t\twrapSizer->Show(tabButton, show);\n\n\t\twxSize minSize = wrapSizer->CalcMin();\n\t\twrapSizer->RepositionChildren(minSize);\n\t}\n\n\tisShown = show;\n}\n\nvoid SliderCategoryUI::Destroy() {\n\tif (dummyPanel1) {\n\t\tdummyPanel1->Destroy();\n\t\tdummyPanel1 = nullptr;\n\t}\n\n\tcheck->Destroy();\n\tcheck = nullptr;\n\n\tlabel->Destroy();\n\tlabel = nullptr;\n\n\tif (dummyPanel2) {\n\t\tdummyPanel2->Destroy();\n\t\tdummyPanel2 = nullptr;\n\t}\n\n\tif (tabButton) {\n\t\ttabButton->Destroy();\n\t\ttabButton = nullptr;\n\t}\n\n\tisShown = false;\n}\n\n\nSliderDisplay::SliderDisplay() {}\n\nbool SliderDisplay::Create(wxScrolledWindow* scrollWindow,\n\t\t\t\t\t\t   wxSizer* sliderLayout,\n\t\t\t\t\t\t   const std::string& name,\n\t\t\t\t\t\t   const std::string& display,\n\t\t\t\t\t\t   const std::string& category,\n\t\t\t\t\t\t   int minValue,\n\t\t\t\t\t\t   int maxValue,\n\t\t\t\t\t\t   bool pIsZap,\n\t\t\t\t\t\t   bool pOneSize) {\n\tisZap = pIsZap;\n\toneSize = pOneSize;\n\n\tsliderName = name;\n\tdisplayName = display;\n\tcategoryName = category;\n\n\twxString nameStr = wxString::FromUTF8(name);\n\twxString displayNameStr = wxString::FromUTF8(display);\n\n\tif (isCreated) {\n\t\tif (lblSliderLo->GetLabel() != displayNameStr)\n\t\t\tlblSliderLo->SetLabel(displayNameStr);\n\n\t\tlblSliderLo->Show(!oneSize);\n\n\t\tif (!oneSize)\n\t\t\tsliderLayout->Add(lblSliderLo, 0, wxLEFT | wxALIGN_CENTER, 5);\n\n\t\tzapCheckLo->SetName(nameStr + \"|ZLO\");\n\t\tzapCheckLo->Show(!oneSize && isZap);\n\n\t\tif (!oneSize && isZap) {\n\t\t\tsliderLayout->AddStretchSpacer();\n\t\t\tsliderLayout->Add(zapCheckLo, 0, wxALIGN_LEFT, 0);\n\t\t}\n\n\t\tsliderLo->SetName(nameStr + \"|LO\");\n\t\tsliderLo->SetMin(minValue);\n\t\tsliderLo->SetMax(maxValue);\n\t\tsliderLo->Show(!oneSize && !isZap);\n\n\t\tif (!oneSize && !isZap)\n\t\t\tsliderLayout->Add(sliderLo, 1, wxEXPAND, 0);\n\n\t\tsliderReadoutLo->SetName(nameStr + \"|RLO\");\n\t\tsliderReadoutLo->Show(!oneSize && !isZap);\n\n\t\tif (!oneSize && !isZap)\n\t\t\tsliderLayout->Add(sliderReadoutLo, 0, wxALL | wxALIGN_CENTER, 0);\n\n\t\tif (lblSliderHi->GetLabel() != displayNameStr)\n\t\t\tlblSliderHi->SetLabel(displayNameStr);\n\n\t\tsliderLayout->Add(lblSliderHi, 0, wxLEFT | wxALIGN_CENTER, 5);\n\n\t\tzapCheckHi->SetName(nameStr + \"|ZHI\");\n\t\tzapCheckHi->Show(isZap);\n\n\t\tif (isZap) {\n\t\t\tsliderLayout->AddStretchSpacer();\n\t\t\tsliderLayout->Add(zapCheckHi, 0, wxALIGN_LEFT, 0);\n\t\t}\n\n\t\tsliderHi->SetName(nameStr + \"|HI\");\n\t\tsliderHi->SetMin(minValue);\n\t\tsliderHi->SetMax(maxValue);\n\t\tsliderHi->Show(!isZap);\n\n\t\tif (!isZap)\n\t\t\tsliderLayout->Add(sliderHi, 1, wxEXPAND, 0);\n\n\t\tsliderReadoutHi->SetName(nameStr + \"|RHI\");\n\t\tsliderReadoutHi->Show(!isZap);\n\n\t\tif (!isZap)\n\t\t\tsliderLayout->Add(sliderReadoutHi, 0, wxRIGHT | wxALIGN_CENTER, 10);\n\n\t\tShow();\n\t\treturn true;\n\t}\n\n\tlblSliderLo = new wxStaticText(scrollWindow, wxID_ANY, display, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);\n\tlblSliderLo->SetForegroundColour(wxColour(200, 200, 200));\n\tlblSliderLo->Show(!oneSize);\n\n\tif (!oneSize)\n\t\tsliderLayout->Add(lblSliderLo, 0, wxLEFT | wxALIGN_CENTER, 5);\n\n\tzapCheckLo = new wxCheckBox(scrollWindow, wxID_ANY, \" \", wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, nameStr + \"|ZLO\");\n\tzapCheckLo->Show(!oneSize && isZap);\n\n\tif (!oneSize && isZap) {\n\t\tsliderLayout->AddStretchSpacer();\n\t\tsliderLayout->Add(zapCheckLo, 0, wxALIGN_LEFT, 0);\n\t}\n\n\tsliderLo = new wxSlider(scrollWindow, wxID_ANY, 0, minValue, maxValue, wxDefaultPosition, wxSize(-1, scrollWindow->FromDIP(24)), wxSL_AUTOTICKS | wxSL_BOTTOM | wxSL_HORIZONTAL);\n\tsliderLo->SetTickFreq(5);\n\tsliderLo->SetName(nameStr + \"|LO\");\n\tsliderLo->Show(!oneSize && !isZap);\n\n\tif (!oneSize && !isZap)\n\t\tsliderLayout->Add(sliderLo, 1, wxEXPAND, 0);\n\n\tsliderReadoutLo = new wxTextCtrl(scrollWindow, wxID_ANY, \"0%\", wxDefaultPosition, wxSize(scrollWindow->FromDIP(50), -1), wxTE_CENTRE | wxNO_BORDER | wxTE_PROCESS_ENTER);\n\tsliderReadoutLo->Show(!oneSize && !isZap);\n\tsliderReadoutLo->SetName(nameStr + \"|RLO\");\n\n\tif (!oneSize && !isZap)\n\t\tsliderLayout->Add(sliderReadoutLo, 0, wxALL | wxALIGN_CENTER, 0);\n\n\tlblSliderHi = new wxStaticText(scrollWindow, wxID_ANY, display, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER_HORIZONTAL);\n\tlblSliderHi->SetForegroundColour(wxColour(200, 200, 200));\n\tsliderLayout->Add(lblSliderHi, 0, wxLEFT | wxALIGN_CENTER, 5);\n\n\tzapCheckHi = new wxCheckBox(scrollWindow, wxID_ANY, \" \", wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, nameStr + \"|ZHI\");\n\tzapCheckHi->Show(isZap);\n\n\tif (isZap) {\n\t\tsliderLayout->AddStretchSpacer();\n\t\tsliderLayout->Add(zapCheckHi, 0, wxALIGN_LEFT, 0);\n\t}\n\n\tsliderHi = new wxSlider(scrollWindow, wxID_ANY, 0, minValue, maxValue, wxDefaultPosition, wxSize(-1, scrollWindow->FromDIP(24)), wxSL_AUTOTICKS | wxSL_HORIZONTAL);\n\tsliderHi->SetTickFreq(5);\n\tsliderHi->SetName(nameStr + \"|HI\");\n\tsliderHi->Show(!isZap);\n\n\tif (!isZap)\n\t\tsliderLayout->Add(sliderHi, 1, wxEXPAND, 0);\n\n\tsliderReadoutHi = new wxTextCtrl(scrollWindow, wxID_ANY, \"0%\", wxDefaultPosition, wxSize(scrollWindow->FromDIP(50), -1), wxTE_CENTRE | wxNO_BORDER | wxTE_PROCESS_ENTER);\n\tsliderReadoutHi->Show(!isZap);\n\tsliderReadoutHi->SetName(nameStr + \"|RHI\");\n\n\tif (!isZap)\n\t\tsliderLayout->Add(sliderReadoutHi, 0, wxRIGHT | wxALIGN_CENTER, 10);\n\n\tShow(false);\n\tisCreated = true;\n\treturn true;\n}\n\nvoid SliderDisplay::Show(bool show) {\n\tlblSliderLo->Show(show && !oneSize);\n\tzapCheckLo->Show(show && !oneSize && isZap);\n\tsliderLo->Show(show && !oneSize && !isZap);\n\tsliderReadoutLo->Show(show && !oneSize && !isZap);\n\tlblSliderHi->Show(show);\n\tzapCheckHi->Show(show && isZap);\n\tsliderHi->Show(show && !isZap);\n\tsliderReadoutHi->Show(show && !isZap);\n\tisShown = show;\n}\n\n\nSliderDisplay* SliderDisplayPool::Push() {\n\tif (pool.size() < MaxPoolSize) {\n\t\tauto entry = new SliderDisplay();\n\t\tpool.push_back(entry);\n\t\treturn entry;\n\t}\n\n\treturn nullptr;\n}\n\nvoid SliderDisplayPool::CreatePool(size_t poolSize, wxScrolledWindow* scrollWindow, wxSizer* sliderLayout) {\n\tif (poolSize > MaxPoolSize)\n\t\tpoolSize = MaxPoolSize;\n\n\tpool.resize(poolSize, nullptr);\n\n\tfor (auto& p : pool) {\n\t\tif (!p)\n\t\t\tp = new SliderDisplay();\n\n\t\tif (!p->IsCreated())\n\t\t\tp->Create(scrollWindow, sliderLayout, \"sliderPoolDummy\", \"\", \"\", 0, 100, false);\n\t}\n}\n\nSliderDisplay* SliderDisplayPool::Get(size_t index) {\n\tif (pool.size() > index)\n\t\treturn pool[index];\n\n\treturn nullptr;\n}\n\nSliderDisplay* SliderDisplayPool::GetNext() {\n\tfor (size_t i = 0; i < pool.size(); ++i) {\n\t\tSliderDisplay* entry = pool[i];\n\n\t\t// Index of a slider that is invisible can be reused\n\t\tif (entry && !entry->isShown)\n\t\t\treturn entry;\n\t}\n\n\treturn Push();\n}\n\nvoid SliderDisplayPool::Clear() {\n\tfor (auto& p : pool)\n\t\tdelete p;\n\n\tpool.clear();\n}\n"
  },
  {
    "path": "src/program/BodySlideApp.h",
    "content": "/*\nBodySlide and Outfit Studio\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#pragma once\n\n#include \"../components/BuildSelection.h\"\n#include \"../components/ClippingFixer.h\"\n#include \"../components/SliderCategories.h\"\n#include \"../components/SliderData.h\"\n#include \"../components/SliderGroup.h\"\n#include \"../components/SliderManager.h\"\n#include \"../files/TriFile.h\"\n#include \"../utils/ConfigurationManager.h\"\n#include \"../utils/Log.h\"\n#include \"GroupManager.h\"\n#include \"PresetSaveDialog.h\"\n#include \"PreviewWindow.h\"\n#include \"../ui/PreviewPanel.h\"\n#include \"../ui/wxStateButton.h\"\n\n#include \"../FSEngine/FSEngine.h\"\n#include \"../FSEngine/FSManager.h\"\n\n#include <wx/clrpicker.h>\n#include <wx/cmdline.h>\n#include <wx/collpane.h>\n#include <wx/dcbuffer.h>\n#include <wx/dir.h>\n#include <wx/html/htmlwin.h>\n#include <wx/imagpng.h>\n#include <wx/intl.h>\n#include <wx/listctrl.h>\n#include <wx/treelist.h>\n#include <wx/progdlg.h>\n#include <wx/splitter.h>\n#include <wx/srchctrl.h>\n#include <wx/statline.h>\n#include <wx/stdpaths.h>\n#include <wx/tokenzr.h>\n#include <wx/wxprec.h>\n#include <wx/xrc/xmlres.h>\n\n#include <atomic>\n#include <thread>\n\n\nenum TargetGame { FO3, FONV, SKYRIM, FO4, SKYRIMSE, FO4VR, SKYRIMVR, FO76, OB, SF };\n\nstruct ShapePreviewData {\n\tstd::string name;\n\tstd::vector<nifly::Vector3> verts;\n\tstd::vector<nifly::Vector2> uvs;\n\tstd::vector<uint16_t> zapIdx;\n\tint projectIdx = 0;\n};\n\nclass BodySlideFrame;\n\nclass BodySlideApp : public wxApp {\n\t/* UI Managers */\n\tBodySlideFrame* sliderView = nullptr;\n\tPreviewPanel* preview = nullptr;\n\tPreviewWindow* previewWindow = nullptr;\n\n\t/* Command-Line Arguments */\n\tstd::vector<std::string> cmdGroupBuild;\n\tstd::string cmdTargetDir;\n\tstd::string cmdPreset;\n\tbool cmdTri = false;\n\tstd::vector<std::string> cmdPreviewNifs;\n\tbool cmdPreviewMode = false;\n\npublic:\n\t/* Clipping Fix */\n\tfloat clippingFixStrength = 0.0f; // 0-100 scale, 0 disables clipping fix\nprivate:\n\n\t/* Reference shape loaded from external project for clipping fix */\n\tstd::unique_ptr<nifly::NifFile> referenceNif;\n\tSliderSet referenceSliderSet;\n\tDiffDataSets referenceDiffData;\n\tstd::string referenceShapeName;\n\n\t/* Localization */\n\twxLocale* locale = nullptr;\n\tint language = 0;\n\n\t/* Data Managers */\n\tSliderManager sliderManager;\n\tLog logger;\n\n\t/* Data Items */\n\tstd::map<std::string, std::string, case_insensitive_compare> outfitNameSource; // All currently defined outfits.\n\tstd::vector<std::string> outfitNameOrder;\t\t\t\t\t\t\t\t\t   // All currently defined outfits, in their order of appearance.\n\tstd::vector<std::string> outfitHasZaps;\t\t\t\t\t\t\t\t\t\t   // All currently defined outfits that have visible zaps.\n\tstd::map<std::string, std::vector<std::string>> groupMembers;\t\t\t\t   // All currently defined groups.\n\tstd::map<std::string, std::string> groupAlias;\t\t\t\t\t\t\t\t   // Group name aliases.\n\tstd::vector<std::string> ungroupedOutfits;\t\t\t\t\t\t\t\t\t   // Outfits without a group.\n\tstd::vector<std::string> filteredOutfits;\t\t\t\t\t\t\t\t\t   // Filtered outfit names.\n\tstd::vector<std::string> presetGroups;\n\tstd::vector<std::string> allGroups;\n\tSliderSetGroupCollection gCollection;\n\n\t/* Cache */\n\tstd::map<std::string, nifly::NifFile, case_insensitive_compare> refNormalsCache; // Cache for reference normals files\n\n\tstruct ProjectData {\n\t\tSliderSet sliderSet;\n\t\tDiffDataSets dataSets;\n\t\tnifly::NifFile* baseNif = nullptr;\n\t\tnifly::NifFile modNif;\n\t\tstd::string setName;\n\t\tstd::string inputFileName;\n\n\t\t~ProjectData() { delete baseNif; }\n\t\tProjectData() = default;\n\t\tProjectData(const ProjectData&) = delete;\n\t\tProjectData& operator=(const ProjectData&) = delete;\n\t};\n\tstd::vector<std::unique_ptr<ProjectData>> projects;\n\tbool multiProjectMode = false;\n\n\tint CreateSetSliders(const std::string& outfit);\n\npublic:\n\tvirtual ~BodySlideApp();\n\tvirtual bool OnInit();\n\tvirtual void OnInitCmdLine(wxCmdLineParser& parser);\n\tvirtual bool OnCmdLineParsed(wxCmdLineParser& parser);\n\n\tvirtual bool OnExceptionInMainLoop();\n\tvirtual void OnUnhandledException();\n\tvirtual void OnFatalException();\n\n\tSliderCategoryCollection cCollection;\n\tTargetGame targetGame = TargetGame::FO3;\n\tstd::map<std::string, std::vector<std::string>, case_insensitive_compare> outFileCount; // Counts how many sets write to the same output file\n\n\tbool SetDefaultConfig();\n\tbool ShowSetup();\n\twxString GetGameDataPath(TargetGame targ);\n\n\tstd::string GetOutputDataPath() const;\n\tstd::string GetProjectPath() const;\n\tSliderSet& GetActiveSet() { return projects[0]->sliderSet; }\n\tDiffDataSets& GetActiveDataSets() { return projects[0]->dataSets; }\n\tbool HasActiveProject() const { return !projects.empty(); }\n\n\tint AddProjectSliders(const std::string& projectFile, const std::string& setName);\n\n\tvoid InitLanguage();\n\n\tvoid InitArchives();\n\tvoid GetArchiveFiles(std::vector<std::string>& outList);\n\n\tvoid LoadData();\n\tvoid CharHook(wxKeyEvent& event);\n\n\tbool OutfitExists(const std::string& name) const { return outfitNameSource.find(name) != outfitNameSource.end(); }\n\n\tvoid LoadAllCategories();\n\n\tvoid SetPresetGroups(const std::string& setName);\n\tvoid LoadAllGroups();\n\tvoid GetAllGroupNames(std::vector<std::string>& outGroups);\n\tint SaveGroupList(const std::string& filename, const std::string& groupname);\n\n\tvoid PopulateFilterData();\n\tvoid ApplyOutfitFilter();\n\tstd::vector<std::string> ApplyPresetFilter(const std::vector<std::string>& presetNames);\n\tint GetOutfits(std::vector<std::string>& outList);\n\tint GetFilteredOutfits(std::vector<std::string>& outList);\n\n\tvoid LoadPresets(const std::string& sliderSet);\n\tvoid GetPresetNames(std::vector<std::string>& outNames);\n\tvoid InitializeSliders(const std::string& presetName = \"\");\n\tvoid PopulatePresetList(const std::string& select);\n\tvoid PopulateOutfitList(const std::string& select);\n\tvoid DisplayActiveSet();\n\n\tvoid GetBuildSelection(BuildSelectionFile& file, BuildSelection& buildSel);\n\n\tvoid UpdateConflictManager();\n\tvoid SetDefaultBuildSelection();\n\n\tbool UpdateZapChoices();\n\tvoid SetZapChoice(const std::string& zap, bool choice);\n\n\tint LoadSliderSets();\n\tvoid RefreshOutfitList();\n\n\tvoid RefreshSliders();\n\n\tvoid ActivateOutfit(const std::string& outfitName);\n\tvoid ActivatePreset(const std::string& presetName, const bool updatePreview = true);\n\n\tstd::vector<std::string> GetConflictingOutfits() {\n\t\tif (projects.empty())\n\t\t\treturn {};\n\t\treturn outFileCount.find(GetActiveSet().GetOutputFilePath())->second;\n\t}\n\n\tvoid DeleteOutfit(const std::string& outfitName);\n\tvoid DeletePreset(const std::string& presetName);\n\n\tvoid EditProject(const std::string& projectName);\n\tvoid LaunchOutfitStudio(const wxString& args = \"\");\n\n\tvoid ApplySliders(const std::string& targetShape,\n\t\t\t\t\t  std::vector<Slider>& sliderSet,\n\t\t\t\t\t  DiffDataSets& dataSets,\n\t\t\t\t\t  std::vector<nifly::Vector3>& verts,\n\t\t\t\t\t  std::vector<uint16_t>& zapidx,\n\t\t\t\t\t  std::vector<nifly::Vector2>* uvs = nullptr);\n\tbool WriteMorphTRI(const std::string& triPath, SliderSet& sliderSet, nifly::NifFile& nif, std::unordered_map<std::string, std::vector<uint16_t>>& zapIndices);\n\n\tvoid CopySliderValues(bool toHigh);\n\tvoid CopyPreviewWeightToSliders();\n\tvoid ShowPreview();\n\tvoid InitPreviewPanel();\n\tvoid BuildPreviewMesh(ProjectData* pp, bool freshLoad);\n\tvoid InitPreview();\n\tvoid CleanupPreview();\n\tvoid LoadPreviewNifs(const std::vector<std::string>& nifFilePaths);\n\tvoid ClosePreview();\n\tvoid PreviewClosed();\n\tvoid PopOutPreview();\n\tvoid DockPreview();\n\tbool IsPreviewPoppedOut() const { return previewWindow != nullptr; }\n\n\t/* Async preview loading */\n\tstd::atomic<uint64_t> previewLoadGeneration{0};\n\tstd::thread previewLoadThread;\n\tbool previewLoading = false;\n\n\tvoid ApplyClippingFix(nifly::NifFile& nif,\n\t\t\t\t\t\tconst std::vector<nifly::Vector3>& bodyVerts,\n\t\t\t\t\t\tconst std::vector<nifly::Triangle>& bodyTris,\n\t\t\t\t\t\tstd::unordered_map<std::string, std::vector<nifly::Vector3>*>& shapeVerts);\n\tbool LoadExternalReference(const SliderSet& sliderSet);\n\tvoid UpdateReferenceCheckboxState();\n\tvoid UpdatePreview();\n\tvoid RebuildPreviewMeshes();\n\tstd::vector<ShapePreviewData> ComputeMorphedShapeData(int weight);\n\tvoid PostProcessPreview(std::vector<ShapePreviewData>& shapeData, int weight);\n\tvoid UpdateExternalReferenceMesh(int weight, std::vector<nifly::Vector3>* outVerts = nullptr);\n\tvoid UpdateMeshesFromSet(SliderSet& set);\n\tvoid ApplyReferenceNormals(nifly::NifFile& nif);\n\n\tint BuildBodies(bool localPath = false, bool clean = false, bool tri = false, bool forceNormals = false);\n\tint BuildListBodies(std::vector<std::string>& outfitList,\n\t\t\t\t\t\tstd::map<std::string, std::string>& failedOutfits,\n\t\t\t\t\t\tbool remove = false,\n\t\t\t\t\t\tbool tri = false,\n\t\t\t\t\t\tbool forceNormals = false,\n\t\t\t\t\t\tconst std::string& custPath = \"\");\n\tint ShowBuildOverrideWithPreview(wxDialog* dlg, wxTreeListCtrl* treeListCtrl);\n\tvoid GroupBuild(const std::vector<std::string>& groupNames);\n\n\tvoid AddTriData(nifly::NifFile& nif, const std::string& shapeName, const std::string& triPath, bool toRoot = false);\n\n\tfloat GetSliderValue(const wxString& sliderName, bool isLo);\n\tbool IsUVSlider(const wxString& sliderName);\n\tstd::vector<std::string> GetSliderZapToggles(const wxString& sliderName);\n\tvoid SetSliderValue(const wxString& sliderName, bool isLo, float val);\n\tvoid SetSliderChanged(const wxString& sliderName, bool isLo);\n\n\tint UpdateSliderPositions(const std::string& presetName);\n\tint SaveSliderPositions(const std::string& outputFile, const std::string& presetName, std::vector<std::string>& groups);\n};\n\nstatic const wxCmdLineEntryDesc g_cmdLineDesc[] = {{wxCMD_LINE_OPTION, \"gbuild\", \"groupbuild\", \"builds the specified group on launch\", wxCMD_LINE_VAL_STRING},\n\t\t\t\t\t\t\t\t\t\t\t\t   {wxCMD_LINE_OPTION, \"t\", \"targetdir\", \"build target directory, defaults to game data path\", wxCMD_LINE_VAL_STRING},\n\t\t\t\t\t\t\t\t\t\t\t\t   {wxCMD_LINE_OPTION, \"p\", \"preset\", \"preset used for the build, defaults to last used preset\", wxCMD_LINE_VAL_STRING},\n\t\t\t\t\t\t\t\t\t\t\t\t   {wxCMD_LINE_SWITCH, \"tri\", \"trimorphs\", \"enables tri morph output for the specified build\"},\n\t\t\t\t\t\t\t\t\t\t\t\t   {wxCMD_LINE_OPTION, \"preview\", \"preview\", \"open the specified nif files in preview mode\", wxCMD_LINE_VAL_STRING},\n\t\t\t\t\t\t\t\t\t\t\t\t   wxCMD_LINE_DESC_END};\n\n#define DELAYLOAD_TIMER 299\n#define SLIDER_LO 1\n#define SLIDER_HI 2\n\nclass SliderCategoryUI {\n\tbool isCreated = false;\n\npublic:\n\tbool isShown = false;\n\tbool isEnabled = false;\n\tbool oneSize = false;\n\n\tstd::string categoryName;\n\tstd::vector<std::string> sliderNames;\n\n\twxPanel* dummyPanel1 = nullptr;\n\twxCheckBox* check = nullptr;\n\twxStaticText* label = nullptr;\n\twxPanel* dummyPanel2 = nullptr;\n\twxStateButton* tabButton = nullptr;\n\n\tSliderCategoryUI();\n\n\tbool IsCreated() { return isCreated; }\n\n\tbool Create(wxScrolledWindow* scrollWindow,\n\t\t\t\twxSizer* sliderLayout,\n\t\t\t\twxSizer* categoryTabSizer,\n\t\t\t\tconst std::string& name,\n\t\t\t\tconst std::vector<std::string>& sliders,\n\t\t\t\tbool pEnabled = true,\n\t\t\t\tbool pOneSize = false);\n\tvoid Show(bool show = true);\n\tvoid Destroy();\n};\n\nclass SliderDisplay {\n\tbool isCreated = false;\n\npublic:\n\tbool isShown = false;\n\tbool isZap = false;\n\tbool oneSize = false;\n\n\tstd::string sliderName;\n\tstd::string displayName;\n\tstd::string categoryName;\n\n\twxStaticText* lblSliderLo = nullptr;\n\twxSlider* sliderLo = nullptr;\n\twxTextCtrl* sliderReadoutLo = nullptr;\n\twxStaticText* lblSliderHi = nullptr;\n\twxSlider* sliderHi = nullptr;\n\twxTextCtrl* sliderReadoutHi = nullptr;\n\twxCheckBox* zapCheckHi = nullptr;\n\twxCheckBox* zapCheckLo = nullptr;\n\n\tSliderDisplay();\n\n\tbool IsCreated() { return isCreated; }\n\n\tbool Create(\n\t\twxScrolledWindow* scrollWindow, wxSizer* sliderLayout, const std::string& name, const std::string& category, const std::string& display, int minValue, int maxValue, bool pIsZap, bool pOneSize = false);\n\tvoid Show(bool show = true);\n};\n\nclass SliderDisplayPool {\n\tstd::vector<SliderDisplay*> pool;\n\n\tconst size_t MaxPoolSize = 500;\n\npublic:\n\tSliderDisplay* Push();\n\tvoid CreatePool(size_t poolSize, wxScrolledWindow* scrollWindow, wxSizer* sliderLayout);\n\tSliderDisplay* Get(size_t index);\n\tSliderDisplay* GetNext();\n\tvoid Clear();\n};\n\nclass BodySlideFrame : public wxFrame {\npublic:\n\tSliderDisplayPool sliderPool;\n\tstd::unordered_map<std::string, SliderDisplay*> sliderDisplays;\n\tstd::unordered_map<std::string, SliderCategoryUI*> sliderCategories;\n\n\twxTimer delayLoad;\n\n\twxChoice* outfitChoice = nullptr;\n\twxChoice* presetChoice = nullptr;\n\twxButton* btnSavePreset = nullptr;\n\twxSearchCtrl* search = nullptr;\n\twxSearchCtrl* outfitsearch = nullptr;\n\twxSearchCtrl* sliderFilter = nullptr;\n\twxSearchCtrl* presetFilter = nullptr;\n\twxSizer* categoryTabSizer = nullptr;\n\n\twxScrolledWindow* sliderScroll = nullptr;\n\twxFlexGridSizer* sliderLayout = nullptr;\n\n\twxCheckListBox* batchBuildList = nullptr;\n\twxMenu* fileCollisionMenu = nullptr;\n\n\t// Splitter and embedded preview\n\twxSplitterWindow* splitter = nullptr;\n\twxPanel* leftPanel = nullptr;\n\tPreviewPanel* previewPanel = nullptr;\n\tbool previewVisible = true;\n\tint savedSashPosition = -1;\n\tint savedPreviewWidth = 0;\n\n\t// Helpers for preview docking/undocking\n\tvoid UnsplitPreview();\n\tvoid SplitPreview(wxPanel* panel = nullptr);\n\tvoid UpdatePreviewButtonLabel();\n\n\tBodySlideFrame(BodySlideApp* app, const wxSize& size);\n\t~BodySlideFrame() { delete fileCollisionMenu; }\n\n\tvoid HideSlider(SliderDisplay* slider);\n\tvoid ShowLowColumn(bool show);\n\tvoid AddCategorySliderUI(const std::string& name, const std::vector<std::string>& sliders, bool enabled, bool oneSize);\n\tvoid AddSliderGUI(const std::string& name, const std::string& display, const std::string& categoryName, bool isZap, bool oneSize = false);\n\n\tSliderDisplay* GetSliderDisplay(const std::string& name) {\n\t\tif (sliderDisplays.find(name) != sliderDisplays.end())\n\t\t\treturn sliderDisplays[name];\n\n\t\treturn nullptr;\n\t}\n\n\tSliderCategoryUI* GetSliderCategory(const std::string& name) {\n\t\tif (sliderCategories.find(name) != sliderCategories.end())\n\t\t\treturn sliderCategories[name];\n\n\t\treturn nullptr;\n\t}\n\n\tvoid ClearPresetList();\n\tvoid ClearOutfitList();\n\tvoid ClearSliderGUI();\n\tvoid SetPresetChanged(bool changed = true);\n\n\tvoid PopulateOutfitList(const wxArrayString& items, const wxString& selectItem);\n\tvoid PopulatePresetList(const wxArrayString& items, const wxString& selectItem);\n\n\tvoid SetSliderPosition(const wxString& name, float newValue, short HiLo);\n\tvoid DoFilterSliders();\n\n\tint lastScroll = 0;\n\nprivate:\n\tvoid OnExit(wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnActivateFrame(wxActivateEvent& event);\n\tvoid OnIconizeFrame(wxIconizeEvent& event);\n\tvoid PostIconizeFrame();\n\n\tvoid OnLinkClicked(wxHtmlLinkEvent& link);\n\tvoid OnEnterClose(wxKeyEvent& event);\n\n\tvoid OnEnterSliderWindow(wxMouseEvent& event);\n\tvoid OnSliderChange(wxScrollEvent& event);\n\tvoid OnSliderReadoutChange(wxCommandEvent& event);\n\tvoid OnSearchChange(wxCommandEvent& event);\n\tvoid OnOutfitSearchChange(wxCommandEvent& event);\n\n\tvoid OnSliderFilterChanged(wxCommandEvent&);\n\tvoid OnPresetFilterChanged(wxCommandEvent&);\n\n\tvoid OnZapCheckChanged(wxCommandEvent& event);\n\tvoid OnCategoryCheckChanged(wxCommandEvent& event);\n\tvoid OnCategoryTabButton(wxCommandEvent& event);\n\n\tvoid OnEraseBackground(wxEraseEvent& event);\n\n\tvoid OnDelayLoad(wxTimerEvent& event);\n\n\tvoid OnChooseGroups(wxCommandEvent& event);\n\tvoid OnRefreshGroups(wxCommandEvent& event);\n\tvoid OnBrowseOutfitFolder(wxCommandEvent& event);\n\tvoid OnSaveGroups(wxCommandEvent& event);\n\tvoid OnRefreshOutfits(wxCommandEvent& event);\n\tvoid OnRegexOutfits(wxCommandEvent& event);\n\tvoid OnFilterHasZaps(wxCommandEvent& event);\n\n\tvoid OnChooseOutfit(wxCommandEvent& event);\n\tvoid OnChoosePreset(wxCommandEvent& event);\n\n\tvoid OnDeleteProject(wxCommandEvent& event);\n\tvoid OnDeletePreset(wxCommandEvent& event);\n\n\tvoid OnSavePreset(wxCommandEvent& event);\n\tvoid OnSavePresetAs(wxCommandEvent& event);\n\tvoid OnGroupManager(wxCommandEvent& event);\n\tvoid OnConflictPopup(wxMouseEvent& event);\n\tvoid OnOutfitChoiceSelect(wxCommandEvent& event);\n\n\tvoid OnPreview(wxCommandEvent& event);\n\tvoid OnSashPosChanged(wxSplitterEvent& event);\n\tvoid OnPreviewPopout(wxCommandEvent& event);\n\tvoid OnPreviewWindowClosed();\n\n\tvoid OnHighToLow(wxCommandEvent& event);\n\tvoid OnLowToHigh(wxCommandEvent& event);\n\tvoid OnBuildBodies(wxCommandEvent& event);\n\tvoid OnBatchBuild(wxCommandEvent& event);\n\tvoid OnBatchBuildContext(wxMouseEvent& event);\n\tvoid OnBatchBuildSelect(wxCommandEvent& event);\n\tvoid OnOutfitStudio(wxCommandEvent& event);\n\tvoid SettingsFillDataFiles(wxCheckListBox* dataFileList, wxString& dataDir, int targetGame);\n\tvoid OnSettings(wxCommandEvent& event);\n\tvoid OnChooseTargetGame(wxCommandEvent& event);\n\tvoid OnAbout(wxCommandEvent& event);\n\tvoid OnMoveWindow(wxMoveEvent& event);\n\tvoid OnSetSize(wxSizeEvent& event);\n\n\tvoid OnEditProject(wxCommandEvent& event);\n\n\tvoid OnClippingStrengthChanged(wxCommandEvent& event);\n\n\tbool OutfitIsEmpty() {\n\t\tif (outfitChoice && !outfitChoice->GetStringSelection().empty())\n\t\t\treturn false;\n\n\t\treturn true;\n\t}\n\n\tvoid RefreshTargetGameState();\n\n\tBodySlideApp* app;\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/ConvertBodyReferenceDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"ConvertBodyReferenceDialog.h\"\n\n#include <NifUtil.hpp>\n\n#include \"../utils/ConfigDialogUtil.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <regex>\n\n#include \"OutfitStudio.h\"\n\nusing namespace std;\nclass RefTemplate;\nextern ConfigurationManager Config;\n\nwxBEGIN_EVENT_TABLE(ConvertBodyReferenceDialog, wxWizard)\n\nwxEND_EVENT_TABLE()\n\nconst char* CONVERT_SLIDER_PREFIX = \"Convert\";\nconst char* SLIDER_SET_PREFIX = \"Sliders\";\n\n\nConvertBodyReferenceDialog::ConvertBodyReferenceDialog(OutfitStudioFrame* outfitStudio,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   OutfitProject* project,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   ConfigurationManager& config,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   const std::vector<RefTemplate>& refTemplates)\n\t: outfitStudio(outfitStudio)\n\t, project(project)\n\t, config(config)\n\t, refTemplates(refTemplates)\n\t, pg1(nullptr)\n\t, pg2(nullptr) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ConvertBodyReference.xrc\");\n\txrc->LoadObject(this, outfitStudio, \"wizConvertBodyRef\", \"wxWizard\");\n\n\tpg1 = (wxWizardPage*)XRCCTRL(*this, \"wizpgConvertBodyRef1\", wxWizardPageSimple);\n\tpg2 = (wxWizardPage*)XRCCTRL(*this, \"wizpgConvertBodyRef2\", wxWizardPageSimple);\n\n\tnpConvRefChoice = XRCCTRL((*this), \"npConvRefChoice\", wxChoice);\n\tnpConvRefChoice->Append(\"None\");\n\n\tchkConformSliders = XRCCTRL((*this), \"chkConformSliders\", wxCheckBox);\n\tchkSkipConformPopup = XRCCTRL((*this), \"chkSkipConformPopup\", wxCheckBox);\n\tchkCopyBoneWeights = XRCCTRL((*this), \"chkCopyBoneWeights\", wxCheckBox);\n\tchkSkipCopyBonesPopup = XRCCTRL((*this), \"chkSkipCopyBonesPopup\", wxCheckBox);\n\n\tstd::vector<RefTemplate> converters = refTemplates;\n\tstd::vector<RefTemplate> bodies = refTemplates;\n\n\tauto sortTemplates = [&](const RefTemplate& first, const RefTemplate& second, vector<string> prioritizeNames, bool ascendingPriority) {\n\t\tconst bool firstHasPriorityName = std::any_of(prioritizeNames.begin(), prioritizeNames.end(), [first](const string& name) {\n\t\t\treturn strstr(first.GetName().c_str(), name.c_str());\n\t\t});\n\t\tconst bool secondHasPriorityName = std::any_of(prioritizeNames.begin(), prioritizeNames.end(), [second](const string& name) {\n\t\t\treturn strstr(second.GetName().c_str(), name.c_str());\n\t\t});\n\t\tif (firstHasPriorityName == secondHasPriorityName)\n\t\t\treturn first.GetName().compare(second.GetName()) <= 0;\n\t\treturn static_cast<bool>((!firstHasPriorityName && secondHasPriorityName) ^ ascendingPriority);\n\t};\n\n\n\tstd::sort(converters.begin(), converters.end(), [&](const RefTemplate& first, const RefTemplate& second) {\n\t\treturn sortTemplates(first, second, {CONVERT_SLIDER_PREFIX}, true);\n\t});\n\tstd::sort(bodies.begin(), bodies.end(), [&](const RefTemplate& first, const RefTemplate& second) {\n\t\treturn sortTemplates(first, second, {CONVERT_SLIDER_PREFIX, SLIDER_SET_PREFIX}, false);\n\t});\n\n\tConfigDialogUtil::LoadDialogChoices(config, (*this), \"ConvertBodyReference\", \"npConvRefChoice\", converters);\n\tConfigDialogUtil::LoadDialogChoices(config, (*this), \"ConvertBodyReference\", \"npNewRefChoice\", bodies);\n\tConfigDialogUtil::LoadDialogText(config, (*this), \"ConvertBodyReference\", \"npRemoveText\");\n\tConfigDialogUtil::LoadDialogText(config, (*this), \"ConvertBodyReference\", \"npAppendText\");\n\tConfigDialogUtil::LoadDialogText(config, (*this), \"ConvertBodyReference\", \"npDeleteShapesText\");\n\tConfigDialogUtil::LoadDialogText(config, (*this), \"ConvertBodyReference\", \"npAddBonesText\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkConvertMergeSliders\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkConvertMergeZaps\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkConformSliders\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkSkipConformPopup\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkCopyBoneWeights\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkSkipCopyBonesPopup\");\n\tConfigDialogUtil::LoadDialogCheckBox(config, (*this), \"ConvertBodyReference\", \"chkDeleteReferenceOnComplete\");\n\n\tif (!chkConformSliders->IsChecked())\n\t\tchkSkipConformPopup->Disable();\n\n\tif (!chkCopyBoneWeights->IsChecked())\n\t\tchkSkipCopyBonesPopup->Disable();\n\n\tchkConformSliders->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& event) {\n\t\tbool checked = event.IsChecked();\n\t\tchkSkipConformPopup->Enable(checked);\n\t});\n\n\tchkCopyBoneWeights->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& event) {\n\t\tbool checked = event.IsChecked();\n\t\tchkSkipCopyBonesPopup->Enable(checked);\n\t});\n\n\tSetDoubleBuffered(true);\n\tCenterOnParent();\n}\n\nConvertBodyReferenceDialog::~ConvertBodyReferenceDialog() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ConvertBodyReferenceDialog.xrc\");\n}\n\nbool ConvertBodyReferenceDialog::Load() {\n\tFitToPage(pg1);\n\treturn RunWizard(pg1);\n}\n\nvoid ConvertBodyReferenceDialog::ConvertBodyReference() const {\n\toutfitStudio->StartProgress(_(\"Starting conversion...\"));\n\n\tbool mergeSliders = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkConvertMergeSliders\");\n\tbool mergeZaps = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkConvertMergeZaps\");\n\tbool conformSliders = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkConformSliders\");\n\tbool skipConformPopup = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkSkipConformPopup\");\n\tbool copyBoneWeights = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkCopyBoneWeights\");\n\tbool skipCopyBonesPopup = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkSkipCopyBonesPopup\");\n\tbool deleteReferenceOnCompleted = ConfigDialogUtil::SetBoolFromDialogCheckbox(config, (*this), \"ConvertBodyReference\", \"chkDeleteReferenceOnComplete\");\n\tauto conversionRefTemplate = ConfigDialogUtil::SetStringFromDialogChoice(config, (*this), \"ConvertBodyReference\", \"npConvRefChoice\");\n\tauto newRefTemplate = ConfigDialogUtil::SetStringFromDialogChoice(config, (*this), \"ConvertBodyReference\", \"npNewRefChoice\");\n\tauto removeFromProjectText = ConfigDialogUtil::SetStringFromDialogTextControl(config, (*this), \"ConvertBodyReference\", \"npRemoveText\");\n\tauto appendToProjectText = ConfigDialogUtil::SetStringFromDialogTextControl(config, (*this), \"ConvertBodyReference\", \"npAppendText\");\n\tauto deleteShapesText = ConfigDialogUtil::SetStringFromDialogTextControl(config, (*this), \"ConvertBodyReference\", \"npDeleteShapesText\");\n\tauto addBonesText = ConfigDialogUtil::SetStringFromDialogTextControl(config, (*this), \"ConvertBodyReference\", \"npAddBonesText\");\n\n\tConfig.SaveConfig(Config[\"AppDir\"] + \"/Config.xml\");\n\n\toutfitStudio->UpdateProgress(1, _(\"Updating Project Output Settings\"));\n\n\tif (!removeFromProjectText.IsEmpty()) {\n\t\twxStringTokenizer tkz(removeFromProjectText, wxT(\",\"));\n\t\tbool modifiedName = false;\n\t\twhile (tkz.HasMoreTokens()) {\n\t\t\twxString token = tkz.GetNextToken();\n\t\t\tif (!modifiedName && !appendToProjectText.IsEmpty() && project->mFileName.Contains(token)) {\n\t\t\t\tproject->mFileName.Replace(token, appendToProjectText);\n\t\t\t\tmodifiedName = true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tproject->mFileName.Replace(token, \"\");\n\t\t\t}\n\t\t\tproject->mOutfitName.Replace(token, \"\");\n\t\t\tproject->mDataDir.Replace(token, \"\");\n\t\t\tproject->mBaseFile.Replace(token, \"\");\n\t\t}\n\t}\n\tif (!appendToProjectText.IsEmpty()) {\n\t\tif (project->mOutfitName[0] != ' ')\n\t\t\tproject->mOutfitName.Prepend(' ');\n\t\tif (project->mDataDir[0] != ' ')\n\t\t\tproject->mDataDir.Prepend(' ');\n\t\tif (project->mBaseFile[0] != ' ')\n\t\t\tproject->mBaseFile.Prepend(' ');\n\t\tproject->mOutfitName.Prepend(appendToProjectText);\n\t\tproject->mDataDir.Prepend(appendToProjectText);\n\t\tproject->mBaseFile.Prepend(appendToProjectText);\n\n\t\tproject->outfitName = project->mOutfitName.ToStdString();\n\t\toutfitStudio->UpdateTitle();\n\t}\n\n\toutfitStudio->DeleteSliders(mergeSliders, mergeZaps); // we need to do this first so we can clear any broken sliders\n\tproject->ResetTransforms();\n\n\tauto originalShapes = project->GetWorkNif()->GetShapes(); // get outfit shapes\n\tif (!deleteShapesText.IsEmpty()) {\n\t\toutfitStudio->UpdateProgress(5, _(\"Deleting Shapes...\"));\n\t\twxStringTokenizer tkz(deleteShapesText, wxT(\",\"));\n\n\t\twhile (tkz.HasMoreTokens()) {\n\t\t\twxString token = tkz.GetNextToken();\n\t\t\tfor (auto& shape : originalShapes) {\n\t\t\t\tif (shape == nullptr)\n\t\t\t\t\tcontinue;\n\t\t\t\tauto shapeName = wxString(shape->name.get().c_str());\n\t\t\t\tif (shapeName.Contains(token)) {\n\t\t\t\t\tproject->DeleteShape(shape);\n\t\t\t\t\tshape = nullptr;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tproject->DeleteShape(project->GetBaseShape());\n\tauto remainingOutfitShapes = project->GetWorkNif()->GetShapes(); // get outfit shapes\n\n\tif (conversionRefTemplate != \"None\") {\n\t\toutfitStudio->UpdateProgress(5, _(\"Loading conversion reference...\"));\n\t\toutfitStudio->StartSubProgress(5, 10);\n\t\tif (AlertProgressError(LoadReferenceTemplate(conversionRefTemplate, mergeSliders, mergeZaps), _(\"Load Error\"), \"Failed to load conversion reference\"))\n\t\t\treturn;\n\t\toutfitStudio->EndProgress();\n\n\t\toutfitStudio->StartSubProgress(10, 20);\n\t\toutfitStudio->CreateSetSliders();\n\t\toutfitStudio->RefreshGUIFromProj();\n\n\t\toutfitStudio->UpdateProgress(20, _(\"Conforming outfit parts...\"));\n\t\toutfitStudio->StartSubProgress(20, 35);\n\n\t\t// We shouldn't ever need to skip using default for this case as a correct conversion reference should always conform accurately\n\t\tif (AlertProgressError(outfitStudio->ConformShapes(remainingOutfitShapes, true), _(\"Conform Error\"), \"Failed to conform shapes\"))\n\t\t\treturn;\n\n\t\toutfitStudio->UpdateProgress(35, _(\"Updating conversion Slider...\"));\n\t\toutfitStudio->SetSliderValue(project->activeSet.size() - 1, 100);\n\t\toutfitStudio->ApplySliders();\n\n\t\toutfitStudio->UpdateProgress(40, _(\"Setting the base shape and removing the conversion reference\"));\n\t\toutfitStudio->SetBaseShape();\n\t\tproject->DeleteShape(project->GetBaseShape());\n\t\toutfitStudio->DeleteSliders(mergeSliders, mergeZaps);\n\t\tproject->GetWorkAnim()->Clear();\n\t}\n\telse {\n\t\toutfitStudio->UpdateProgress(5, _(\"Skipping conversion reference...\"));\n\t}\n\n\toutfitStudio->RefreshGUIFromProj();\n\n\toutfitStudio->UpdateProgress(50, _(\"Loading new reference...\"));\n\toutfitStudio->StartSubProgress(50, 55);\n\tif (AlertProgressError(LoadReferenceTemplate(newRefTemplate, mergeSliders, mergeZaps), _(\"Load Error\"), \"Failed to load new reference\"))\n\t\treturn;\n\toutfitStudio->EndProgress();\n\n\toutfitStudio->StartSubProgress(55, 65);\n\toutfitStudio->CreateSetSliders();\n\toutfitStudio->RefreshGUIFromProj();\n\n\tif (AlertProgressError(project->GetBaseShape() == nullptr, _(\"Missing Base Shape\"), \"The loaded reference does not contain a base shape\"))\n\t\treturn;\n\n\tif (copyBoneWeights) {\n\t\toutfitStudio->UpdateProgress(65, _(\"Copying bones...\"));\n\t\toutfitStudio->StartSubProgress(65, 85);\n\t\tif (AlertProgressError(outfitStudio->CopyBoneWeightForShapes(remainingOutfitShapes, skipCopyBonesPopup), _(\"Copy Bone Weights Error\"), \"Failed to copy bone weights\"))\n\t\t\treturn;\n\t}\n\n\tif (conformSliders) {\n\t\toutfitStudio->UpdateProgress(85, _(\"Conforming outfit parts...\"));\n\t\toutfitStudio->StartSubProgress(85, 100);\n\t\tif (AlertProgressError(outfitStudio->ConformShapes(remainingOutfitShapes, skipConformPopup), _(\"Conform Error\"), \"Failed to conform shapes\"))\n\t\t\treturn;\n\t}\n\n\tif (!addBonesText.IsEmpty()) {\n\t\toutfitStudio->UpdateProgress(100, _(\"Adding Bones...\"));\n\t\twxStringTokenizer tkz(addBonesText, wxT(\",\"));\n\t\twhile (tkz.HasMoreTokens()) {\n\t\t\twxString token = tkz.GetNextToken();\n\t\t\tproject->AddBoneRef(token.ToStdString());\n\t\t}\n\t}\n\n\tif (deleteReferenceOnCompleted) {\n\t\tauto allShapes = project->GetWorkNif()->GetShapes();\n\t\tfor (auto& s : allShapes) {\n\t\t\tif (std::find(remainingOutfitShapes.begin(), remainingOutfitShapes.end(), s) == remainingOutfitShapes.end())\n\t\t\t\tproject->DeleteShape(s);\n\t\t}\n\t}\n\n\tint deletionCount = 0;\n\tauto workNif = project->GetWorkNif();\n\tif (workNif)\n\t\tworkNif->DeleteUnreferencedNodes(&deletionCount);\n\n\tauto allShapes = project->GetWorkNif()->GetShapes();\n\tfor (auto& s : allShapes)\n\t\toutfitStudio->glView->RecalcNormals(s->name.get());\n\n\toutfitStudio->RefreshGUIFromProj();\n\toutfitStudio->ApplySliders();\n\n\twxLogMessage(\"Conversion finished.\");\n\toutfitStudio->EndProgress(_(\"Conversion finished.\"));\n}\n\nint ConvertBodyReferenceDialog::LoadReferenceTemplate(const wxString& refTemplate, bool mergeSliders, bool mergeZaps) const {\n\tnifly::NiShape* baseShape = project->GetBaseShape();\n\tif (baseShape)\n\t\toutfitStudio->glView->DeleteMesh(baseShape->name.get());\n\n\tint error;\n\twxLogMessage(\"Loading reference template '%s'...\", refTemplate);\n\tstd::string tmplName{refTemplate.ToUTF8()};\n\tauto tmpl = find_if(refTemplates.begin(), refTemplates.end(), [&tmplName](const RefTemplate& rt) { return rt.GetName() == tmplName; });\n\tif (tmpl != refTemplates.end()) {\n\t\tif (wxFileName(wxString::FromUTF8(tmpl->GetSource())).IsRelative())\n\t\t\terror = project->LoadReferenceTemplate(GetProjectPath() + PathSepStr + tmpl->GetSource(),\n\t\t\t\t\t\t\t\t\t\t\t\t   tmpl->GetSetName(),\n\t\t\t\t\t\t\t\t\t\t\t\t   tmpl->GetShape(),\n\t\t\t\t\t\t\t\t\t\t\t\t   tmpl->GetLoadAll(),\n\t\t\t\t\t\t\t\t\t\t\t\t   mergeSliders,\n\t\t\t\t\t\t\t\t\t\t\t\t   mergeZaps);\n\t\telse\n\t\t\terror = project->LoadReferenceTemplate(tmpl->GetSource(), tmpl->GetSetName(), tmpl->GetShape(), tmpl->GetLoadAll(), mergeSliders, mergeZaps);\n\t}\n\telse\n\t\terror = 1;\n\n\tif (!error) {\n\t\t// since some reference files have multiple shapes, just update all textures\n\t\tfor (auto& s : project->GetWorkNif()->GetShapes())\n\t\t\tproject->SetTextures(s);\n\t}\n\n\treturn error;\n}\n\nbool ConvertBodyReferenceDialog::AlertProgressError(int error, const wxString& title, const wxString& message) const {\n\tif (error == 0)\n\t\treturn false;\n\n\twxLogError(message);\n\twxMessageBox(message, title, wxICON_ERROR);\n\toutfitStudio->EndProgress(\"\", true);\n\toutfitStudio->RefreshGUIFromProj();\n\treturn true;\n}\n"
  },
  {
    "path": "src/program/ConvertBodyReferenceDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n\n#include \"OutfitProject.h\"\n\nclass OutfitStudioFrame;\nclass ConfigurationManager;\nclass RefTemplate;\n\nclass ConvertBodyReferenceDialog : public wxWizard {\npublic:\n\tConvertBodyReferenceDialog(OutfitStudioFrame* outfitStudio, OutfitProject* project, ConfigurationManager& config, const std::vector<RefTemplate>& refTemplates);\n\t~ConvertBodyReferenceDialog() override;\n\n\tbool Load();\n\tvoid ConvertBodyReference() const;\n\nprivate:\n\tOutfitStudioFrame* outfitStudio = nullptr;\n\tOutfitProject* project = nullptr;\n\tConfigurationManager& config;\n\tconst std::vector<RefTemplate>& refTemplates;\n\twxWizardPage* pg1 = nullptr;\n\twxWizardPage* pg2 = nullptr;\n\n\twxChoice* npConvRefChoice = nullptr;\n\twxCheckBox* chkConformSliders = nullptr;\n\twxCheckBox* chkSkipConformPopup = nullptr;\n\twxCheckBox* chkCopyBoneWeights = nullptr;\n\twxCheckBox* chkSkipCopyBonesPopup = nullptr;\n\n\tint LoadReferenceTemplate(const wxString& refTemplate, bool mergeSliders, bool mergeZaps) const;\n\tbool AlertProgressError(int error, const wxString& title, const wxString& message) const;\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/EditUV.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"EditUV.h\"\n#include \"../render/GLOffscreenBuffer.h\"\n\n#include <regex>\n\nextern ConfigurationManager Config;\n\nusing namespace nifly;\n\nstd::unordered_map<int, Vector2>& EditUVAction::GetStartState() {\n\treturn startState;\n}\n\nstd::unordered_map<int, Vector2>& EditUVAction::GetEndState() {\n\treturn endState;\n}\n\nvoid EditUVAction::SetStartState(std::unordered_map<int, Vector2>& state) {\n\tstartState = std::move(state);\n}\n\nvoid EditUVAction::SetEndState(std::unordered_map<int, Vector2>& state) {\n\tendState = std::move(state);\n}\n\nvoid EditUVAction::RestoreStartState() {\n\tfor (auto& stateIt : startState) {\n\t\tactionMesh->verts[stateIt.first].x = stateIt.second.u;\n\t\tactionMesh->verts[stateIt.first].y = stateIt.second.v;\n\t}\n\n\tactionMesh->QueueUpdate(Mesh::UpdateType::Position);\n}\n\nvoid EditUVAction::RestoreEndState() {\n\tfor (auto& stateIt : endState) {\n\t\tactionMesh->verts[stateIt.first].x = stateIt.second.u;\n\t\tactionMesh->verts[stateIt.first].y = stateIt.second.v;\n\t}\n\n\tactionMesh->QueueUpdate(Mesh::UpdateType::Position);\n}\n\n\nEditUVHistory::EditUVHistory() {}\n\nEditUVHistory::~EditUVHistory() {\n\tClear();\n}\n\nvoid EditUVHistory::Clear() {\n\tfor (unsigned int i = 0; i < actions.size(); i++)\n\t\tdelete actions[i];\n\n\tactions.clear();\n\tcurState = -1;\n}\n\nvoid EditUVHistory::Add(EditUVAction* action) {\n\tint maxState = actions.size() - 1;\n\tif (curState < maxState) {\n\t\tfor (auto strokeIt = actions.begin() + (curState + 1); strokeIt != actions.end(); ++strokeIt)\n\t\t\tdelete (*strokeIt);\n\n\t\tactions.erase(actions.begin() + (curState + 1), actions.end());\n\t}\n\telse if (actions.size() == EDITUV_MAX_UNDO) {\n\t\tdelete actions[0];\n\t\tactions.erase(actions.begin());\n\t}\n\n\tactions.push_back(action);\n\tcurState = actions.size() - 1;\n}\n\nbool EditUVHistory::Back() {\n\tif (curState > -1) {\n\t\tactions[curState]->RestoreStartState();\n\t\tcurState--;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool EditUVHistory::Forward() {\n\tint maxState = actions.size() - 1;\n\tif (curState < maxState) {\n\t\tactions[curState + 1]->RestoreEndState();\n\t\tcurState++;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n\nwxBEGIN_EVENT_TABLE(EditUV, wxFrame)\n\tEVT_MENU(XRCID(\"btnBoxSelection\"), EditUV::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnVertexSelection\"), EditUV::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnMove\"), EditUV::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnScale\"), EditUV::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnRotate\"), EditUV::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnSeamEdges\"), EditUV::OnSeamEdges)\n\tEVT_MENU(XRCID(\"fileExportUVTemplate\"), EditUV::OnExportUVTemplate)\n\tEVT_MENU(XRCID(\"editUndo\"), EditUV::OnUndo)\n\tEVT_MENU(XRCID(\"editRedo\"), EditUV::OnRedo)\n\tEVT_MENU(XRCID(\"editSelectAll\"), EditUV::OnSelectAll)\n\tEVT_MENU(XRCID(\"editSelectInvert\"), EditUV::OnSelectInvert)\n\tEVT_MENU(XRCID(\"editSelectLess\"), EditUV::OnSelectLess)\n\tEVT_MENU(XRCID(\"editSelectMore\"), EditUV::OnSelectMore)\n\tEVT_MENU(XRCID(\"maskSelection\"), EditUV::OnMaskSelection)\n\tEVT_MENU(XRCID(\"editTranslate\"), EditUV::OnTranslate)\n\tEVT_MENU(XRCID(\"editRotate\"), EditUV::OnRotate)\n\tEVT_MENU(XRCID(\"editScale\"), EditUV::OnScale)\n\tEVT_BUTTON(wxID_OK, EditUV::OnApply)\n\tEVT_BUTTON(wxID_CANCEL, EditUV::OnCancel)\n\tEVT_CLOSE(EditUV::OnClose)\nwxEND_EVENT_TABLE()\n\nEditUV::EditUV(wxWindow* parent, NifFile* srcNif, NiShape* srcShape, Mesh* srcMesh, const std::string& srcSliderName) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\tbool loaded = xrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/EditUV.xrc\");\n\tif (!loaded) {\n\t\twxMessageBox(\"Failed to load EditUV.xrc file!\", \"Error\", wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tloaded = xrc->LoadFrame(this, parent, \"dlgEditUV\");\n\tif (!loaded) {\n\t\twxMessageBox(\"Failed to load EditUV frame!\", \"Error\", wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tos = (OutfitStudioFrame*)parent;\n\tnif = srcNif;\n\tshape = srcShape;\n\tshapeMesh = srcMesh;\n\tsliderName = srcSliderName;\n\n\tuvToolBar = xrc->LoadToolBar(this, \"uvToolBar\");\n\tuvMenuBar = xrc->LoadMenuBar(this, \"uvMenuBar\");\n\n\tcanvas = new EditUVCanvas(this, wxDefaultSize, GLSurface::GetGLAttribs());\n\tcanvas->SetNotifyWindow(this);\n\tcanvas->SetCursor(wxStockCursor::wxCURSOR_CROSS);\n\n\txrc->AttachUnknownControl(\"uvGLView\", canvas, this);\n#ifdef _WINDOWS\n\tcanvas->MSWDisableComposited(); // Fix stuttering from composited flag?\n#endif\n}\n\nEditUV::~EditUV() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/EditUV.xrc\");\n}\n\nvoid EditUV::OnSelectTool(wxCommandEvent& event) {\n\tint id = event.GetId();\n\tif (id == XRCID(\"btnBoxSelection\"))\n\t\tSelectTool(EditUVTool::BoxSelection);\n\telse if (id == XRCID(\"btnVertexSelection\"))\n\t\tSelectTool(EditUVTool::VertexSelection);\n\telse if (id == XRCID(\"btnMove\"))\n\t\tSelectTool(EditUVTool::Move);\n\telse if (id == XRCID(\"btnScale\"))\n\t\tSelectTool(EditUVTool::Scale);\n\telse if (id == XRCID(\"btnRotate\"))\n\t\tSelectTool(EditUVTool::Rotate);\n}\n\nvoid EditUV::OnSeamEdges(wxCommandEvent& event) {\n\tif (canvas->seamEdgesMesh) {\n\t\tcanvas->seamEdgesMesh->bVisible = event.IsChecked();\n\t\tos->glView->Render();\n\t}\n}\n\nvoid EditUV::OnUndo(wxCommandEvent& WXUNUSED(event)) {\n\tUndo();\n}\n\nvoid EditUV::OnRedo(wxCommandEvent& WXUNUSED(event)) {\n\tRedo();\n}\n\nvoid EditUV::OnSelectAll(wxCommandEvent& WXUNUSED(event)) {\n\tcanvas->SelectAll();\n}\n\nvoid EditUV::OnSelectInvert(wxCommandEvent& WXUNUSED(event)) {\n\tcanvas->SelectInvert();\n}\n\nvoid EditUV::OnSelectLess(wxCommandEvent& WXUNUSED(event)) {\n\tcanvas->SelectLess();\n}\n\nvoid EditUV::OnSelectMore(wxCommandEvent& WXUNUSED(event)) {\n\tcanvas->SelectMore();\n}\n\nvoid EditUV::OnMaskSelection(wxCommandEvent& WXUNUSED(event)) {\n\tif (!shapeMesh->mask)\n\t\treturn;\n\n\tif (shapeMesh->nVerts != canvas->uvGridMesh->nVerts)\n\t\treturn;\n\n\tfor (int i = 0; i < canvas->uvGridMesh->nVerts; i++) {\n\t\tif (canvas->uvGridMesh->vcolors[i] == Vector3(1.0f, 1.0f, 0.0f))\n\t\t\tshapeMesh->mask[i] = 1.0f;\n\t\telse\n\t\t\tshapeMesh->mask[i] = 0.0f;\n\t}\n\n\tshapeMesh->QueueUpdate(Mesh::UpdateType::Mask);\n\tos->glView->Render();\n}\n\nvoid EditUV::OnExportUVTemplate(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tif (!wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgExportUV\"))\n\t\treturn;\n\n\twxChoice* choiceResolution = XRCCTRL(dlg, \"choiceResolution\", wxChoice);\n\twxColourPickerCtrl* cpWireColor = XRCCTRL(dlg, \"cpWireColor\", wxColourPickerCtrl);\n\twxColourPickerCtrl* cpBackgroundColor = XRCCTRL(dlg, \"cpBackgroundColor\", wxColourPickerCtrl);\n\twxCheckBox* cbTransparentBG = XRCCTRL(dlg, \"cbTransparentBG\", wxCheckBox);\n\twxCheckBox* cbIncludeTexture = XRCCTRL(dlg, \"cbIncludeTexture\", wxCheckBox);\n\n\tauto onTransparentToggle = [&](wxCommandEvent&) {\n\t\tcpBackgroundColor->Enable(!cbTransparentBG->IsChecked());\n\t};\n\n\tcbTransparentBG->Bind(wxEVT_CHECKBOX, onTransparentToggle);\n\tcpBackgroundColor->Enable(!cbTransparentBG->IsChecked());\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\tint resolutions[] = {512, 1024, 2048, 4096};\n\tint resIndex = choiceResolution->GetSelection();\n\tif (resIndex < 0 || resIndex > 3)\n\t\tresIndex = 2;\n\tint resolution = resolutions[resIndex];\n\n\twxColour wireColor = cpWireColor->GetColour();\n\twxColour bgColor = cpBackgroundColor->GetColour();\n\tbool transparentBG = cbTransparentBG->IsChecked();\n\tbool includeTexture = cbIncludeTexture->IsChecked();\n\n\twxChoice* choiceWrapMode = XRCCTRL(dlg, \"choiceWrapMode\", wxChoice);\n\twxCheckBox* cbAntiAliasing = XRCCTRL(dlg, \"cbAntiAliasing\", wxCheckBox);\n\tbool clampUVs = choiceWrapMode->GetSelection() == 1;\n\tbool antiAliasing = cbAntiAliasing->IsChecked();\n\n\twxFileDialog saveDialog(this,\n\t\t_(\"Save UV template image\"),\n\t\twxEmptyString,\n\t\twxEmptyString,\n\t\t\"PNG Files (*.png)|*.png|TGA Files (*.tga)|*.tga|BMP Files (*.bmp)|*.bmp|JPG Files (*.jpg)|*.jpg|DDS Files (*.dds)|*.dds\",\n\t\twxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\n\tif (saveDialog.ShowModal() != wxID_OK)\n\t\treturn;\n\n\tstd::string filename = saveDialog.GetPath().ToUTF8().data();\n\n\tif (!canvas->ExportUVTemplate(filename, resolution, wireColor, bgColor, transparentBG, includeTexture, clampUVs, antiAliasing))\n\t\twxMessageBox(_(\"Failed to export UV template.\"), _(\"Error\"), wxICON_ERROR, this);\n}\n\nvoid EditUV::OnTranslate(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgTranslate\")) {\n\t\twxSlider* sliderU = XRCCTRL(dlg, \"sliderU\", wxSlider);\n\t\twxSlider* sliderV = XRCCTRL(dlg, \"sliderV\", wxSlider);\n\t\twxTextCtrl* textU = XRCCTRL(dlg, \"textU\", wxTextCtrl);\n\t\twxTextCtrl* textV = XRCCTRL(dlg, \"textV\", wxTextCtrl);\n\n\t\tauto sliderMoved = [&](wxCommandEvent&) {\n\t\t\tfloat u = sliderU->GetValue() / 1000.0f;\n\t\t\tfloat v = sliderV->GetValue() / 1000.0f;\n\n\t\t\ttextU->ChangeValue(wxString::Format(\"%0.5f\", u));\n\t\t\ttextV->ChangeValue(wxString::Format(\"%0.5f\", v));\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent&) {\n\t\t\tfloat u = atof(textU->GetValue().c_str());\n\t\t\tfloat v = atof(textV->GetValue().c_str());\n\n\t\t\tsliderU->SetValue(u * 1000);\n\t\t\tsliderV->SetValue(v * 1000);\n\t\t};\n\n\t\tsliderU->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tsliderV->Bind(wxEVT_SLIDER, sliderMoved);\n\n\t\ttextU->Bind(wxEVT_TEXT, textChanged);\n\t\ttextV->Bind(wxEVT_TEXT, textChanged);\n\n\t\tif (dlg.ShowModal() != wxID_OK)\n\t\t\treturn;\n\n\t\tcanvas->StartMeshAction();\n\n\t\tVector3 translation;\n\t\ttranslation.x = atof(textU->GetValue().c_str());\n\t\ttranslation.y = atof(textV->GetValue().c_str());\n\n\t\tMatrix4 mat;\n\t\tmat.PushTranslate(translation);\n\n\t\tcanvas->ApplyMeshTransform(mat);\n\t\tcanvas->EndMeshAction();\n\t}\n}\n\nvoid EditUV::OnRotate(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgRotate\")) {\n\t\twxSlider* slider = XRCCTRL(dlg, \"slider\", wxSlider);\n\t\twxTextCtrl* text = XRCCTRL(dlg, \"text\", wxTextCtrl);\n\n\t\tauto sliderMoved = [&](wxCommandEvent&) {\n\t\t\tfloat sliderValue = slider->GetValue() / 100.0f;\n\t\t\ttext->ChangeValue(wxString::Format(\"%0.4f\", sliderValue));\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent&) {\n\t\t\tfloat changedValue = atof(text->GetValue().c_str());\n\t\t\tslider->SetValue(changedValue * 100);\n\t\t};\n\n\t\tslider->Bind(wxEVT_SLIDER, sliderMoved);\n\t\ttext->Bind(wxEVT_TEXT, textChanged);\n\n\t\tif (dlg.ShowModal() != wxID_OK)\n\t\t\treturn;\n\n\t\tVector3 currentCenter = canvas->CalcSelectionCenter();\n\t\tcanvas->StartMeshAction();\n\n\t\tfloat rotation = atof(text->GetValue().c_str());\n\n\t\tMatrix4 mat;\n\t\tmat.PushTranslate(currentCenter);\n\t\tmat.PushRotate(rotation * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\t\tmat.PushTranslate(currentCenter * -1.0f);\n\n\t\tcanvas->ApplyMeshTransform(mat);\n\t\tcanvas->EndMeshAction();\n\t}\n}\n\nvoid EditUV::OnScale(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgScale\")) {\n\t\twxSlider* sliderU = XRCCTRL(dlg, \"sliderU\", wxSlider);\n\t\twxSlider* sliderV = XRCCTRL(dlg, \"sliderV\", wxSlider);\n\t\twxTextCtrl* textU = XRCCTRL(dlg, \"textU\", wxTextCtrl);\n\t\twxTextCtrl* textV = XRCCTRL(dlg, \"textV\", wxTextCtrl);\n\n\t\tauto sliderMoved = [&](wxCommandEvent& event) {\n\t\t\tVector3 scale(1.0f, 1.0f, 1.0f);\n\n\t\t\tbool uniform = XRCCTRL(dlg, \"cbUniform\", wxCheckBox)->IsChecked();\n\t\t\tif (uniform) {\n\t\t\t\tfloat uniformValue = ((wxSlider*)event.GetEventObject())->GetValue() / 1000.0f;\n\t\t\t\tscale = Vector3(uniformValue, uniformValue, uniformValue);\n\n\t\t\t\tXRCCTRL(dlg, \"sliderU\", wxSlider)->SetValue(scale.x * 1000);\n\t\t\t\tXRCCTRL(dlg, \"sliderV\", wxSlider)->SetValue(scale.y * 1000);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tscale.x = XRCCTRL(dlg, \"sliderU\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t\tscale.y = XRCCTRL(dlg, \"sliderV\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t}\n\n\t\t\tXRCCTRL(dlg, \"textU\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.x));\n\t\t\tXRCCTRL(dlg, \"textV\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.y));\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent& event) {\n\t\t\tVector3 scale(1.0f, 1.0f, 1.0f);\n\n\t\t\tbool uniform = XRCCTRL(dlg, \"cbUniform\", wxCheckBox)->IsChecked();\n\t\t\tif (uniform) {\n\t\t\t\tfloat uniformValue = atof(((wxTextCtrl*)event.GetEventObject())->GetValue().c_str());\n\t\t\t\tscale = Vector3(uniformValue, uniformValue, uniformValue);\n\n\t\t\t\tXRCCTRL(dlg, \"textU\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.x));\n\t\t\t\tXRCCTRL(dlg, \"textV\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.y));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tscale.x = atof(XRCCTRL(dlg, \"textU\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tscale.y = atof(XRCCTRL(dlg, \"textV\", wxTextCtrl)->GetValue().c_str());\n\t\t\t}\n\n\t\t\tif (scale.x < 0.01f) {\n\t\t\t\tscale.x = 0.01f;\n\t\t\t\tXRCCTRL(dlg, \"textU\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.x));\n\t\t\t}\n\n\t\t\tif (scale.y < 0.01f) {\n\t\t\t\tscale.y = 0.01f;\n\t\t\t\tXRCCTRL(dlg, \"textV\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.y));\n\t\t\t}\n\n\t\t\tXRCCTRL(dlg, \"sliderU\", wxSlider)->SetValue(scale.x * 1000);\n\t\t\tXRCCTRL(dlg, \"sliderV\", wxSlider)->SetValue(scale.y * 1000);\n\t\t};\n\n\t\tsliderU->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tsliderV->Bind(wxEVT_SLIDER, sliderMoved);\n\n\t\ttextU->Bind(wxEVT_TEXT, textChanged);\n\t\ttextV->Bind(wxEVT_TEXT, textChanged);\n\n\t\tif (dlg.ShowModal() != wxID_OK)\n\t\t\treturn;\n\n\t\tVector3 currentCenter = canvas->CalcSelectionCenter();\n\t\tcanvas->StartMeshAction();\n\n\t\tfloat scaleU = atof(textU->GetValue().c_str());\n\t\tfloat scaleV = atof(textV->GetValue().c_str());\n\n\t\tMatrix4 mat;\n\t\tmat.PushTranslate(currentCenter);\n\t\tmat.PushScale(scaleU, scaleV, 1.0f);\n\t\tmat.PushTranslate(currentCenter * -1.0f);\n\n\t\tcanvas->ApplyMeshTransform(mat);\n\t\tcanvas->EndMeshAction();\n\t}\n}\n\nvoid EditUV::SelectTool(EditUVTool tool) {\n\tcanvas->SetCursorType(GLSurface::None);\n\ttoolSelected = tool;\n\n\tswitch (toolSelected) {\n\t\tcase EditUVTool::BoxSelection:\n\t\t\tcanvas->SetCursor(wxStockCursor::wxCURSOR_CROSS);\n\t\t\tuvToolBar->ToggleTool(XRCID(\"btnBoxSelection\"), true);\n\t\t\tbreak;\n\t\tcase EditUVTool::VertexSelection:\n\t\t\tcanvas->SetCursor(wxStockCursor::wxCURSOR_DEFAULT);\n\t\t\tcanvas->SetCursorType(GLSurface::PointCursor);\n\t\t\tuvToolBar->ToggleTool(XRCID(\"btnVertexSelection\"), true);\n\t\t\tbreak;\n\t\tcase EditUVTool::Move:\n\t\t\tcanvas->SetCursor(wxStockCursor::wxCURSOR_SIZING);\n\t\t\tuvToolBar->ToggleTool(XRCID(\"btnMove\"), true);\n\t\t\tbreak;\n\t\tcase EditUVTool::Scale:\n\t\t\tcanvas->SetCursor(wxStockCursor::wxCURSOR_SIZING);\n\t\t\tuvToolBar->ToggleTool(XRCID(\"btnScale\"), true);\n\t\t\tbreak;\n\t\tcase EditUVTool::Rotate:\n\t\t\tcanvas->SetCursor(wxStockCursor::wxCURSOR_HAND);\n\t\t\tuvToolBar->ToggleTool(XRCID(\"btnRotate\"), true);\n\t\t\tbreak;\n\t}\n}\n\nvoid EditUV::Undo() {\n\thistory.Back();\n\tcanvas->Render();\n\n\tUpdateShapeMesh(false);\n}\n\nvoid EditUV::Redo() {\n\thistory.Forward();\n\tcanvas->Render();\n\n\tUpdateShapeMesh(false);\n}\n\nvoid EditUV::UpdateShapeMesh(bool apply) {\n\tstd::vector<Vector2> uvs;\n\tnif->GetUvsForShape(shape, uvs);\n\n\tif (!sliderName.empty()) {\n\t\tstd::unordered_map<uint16_t, Vector3> morphDiff;\n\t\tos->project->GetSliderDiffUV(shape, sliderName, uvs);\n\n\t\tfor (int i = 0; i < canvas->uvGridMesh->nVerts; i++) {\n\t\t\tVector3 diff = Vector3((canvas->uvGridMesh->verts[i].x - uvs[i].u) / -10.0f, 0.0f, ((canvas->uvGridMesh->verts[i].y * -1.0f) - uvs[i].v) / 10.0f);\n\t\t\tif (!diff.IsZero(true))\n\t\t\t\tmorphDiff[i] = std::move(diff);\n\n\t\t\tshapeMesh->texcoord[i].u = canvas->uvGridMesh->verts[i].x;\n\t\t\tshapeMesh->texcoord[i].v = canvas->uvGridMesh->verts[i].y * -1.0f;\n\t\t}\n\n\t\tif (apply)\n\t\t\tos->project->UpdateMorphResult(shape, sliderName, morphDiff);\n\t}\n\telse {\n\t\tfor (int i = 0; i < canvas->uvGridMesh->nVerts; i++) {\n\t\t\tuvs[i].u = canvas->uvGridMesh->verts[i].x;\n\t\t\tuvs[i].v = canvas->uvGridMesh->verts[i].y * -1.0f;\n\t\t\tshapeMesh->texcoord[i].u = uvs[i].u;\n\t\t\tshapeMesh->texcoord[i].v = uvs[i].v;\n\t\t}\n\n\t\tif (apply)\n\t\t\tnif->SetUvsForShape(shape, uvs);\n\t}\n\n\tshapeMesh->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\tos->glView->Render();\n}\n\nvoid EditUV::OnApply(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateShapeMesh();\n\tos->SetPendingChanges();\n\tClose();\n}\n\nvoid EditUV::OnCancel(wxCommandEvent& WXUNUSED(event)) {\n\tos->ApplySliders(false);\n\tClose();\n}\n\nvoid EditUV::OnClose(wxCloseEvent& WXUNUSED(event)) {\n\tif (canvas)\n\t\tdelete canvas;\n\n\tDestroy();\n}\n\n\nwxBEGIN_EVENT_TABLE(EditUVCanvas, wxGLCanvas)\n\tEVT_PAINT(EditUVCanvas::OnPaint)\n\tEVT_SIZE(EditUVCanvas::OnSize)\n\tEVT_MOUSEWHEEL(EditUVCanvas::OnMouseWheel)\n\tEVT_MOTION(EditUVCanvas::OnMouseMove)\n\tEVT_LEFT_DOWN(EditUVCanvas::OnLeftDown)\n\tEVT_LEFT_DCLICK(EditUVCanvas::OnLeftDown)\n\tEVT_LEFT_UP(EditUVCanvas::OnLeftUp)\n\tEVT_MIDDLE_DOWN(EditUVCanvas::OnMiddleDown)\n\tEVT_MIDDLE_UP(EditUVCanvas::OnMiddleUp)\n\tEVT_RIGHT_DOWN(EditUVCanvas::OnRightDown)\n\tEVT_RIGHT_UP(EditUVCanvas::OnRightUp)\n\tEVT_KEY_DOWN(EditUVCanvas::OnKeyDown)\nwxEND_EVENT_TABLE()\n\nEditUVCanvas::EditUVCanvas(wxWindow* parent, const wxSize& size, const wxGLAttributes& attribs)\n\t: wxGLCanvas(parent, attribs, wxID_ANY, wxDefaultPosition, size, wxFULL_REPAINT_ON_RESIZE) {\n\tcontext = std::make_unique<wxGLContext>(this, nullptr, &GLSurface::GetGLContextAttribs());\n}\n\nEditUVCanvas::~EditUVCanvas() {\n\teditUV->os->glView->gls.DeleteMesh(seamEdgesMesh);\n\teditUV->os->glView->Render();\n\n\tuvSurface.Cleanup();\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::OnShown() {\n\tif (!context->IsOK()) {\n\t\twxLogError(\"Outfit Studio: OpenGL context is not OK.\");\n\t\twxMessageBox(_(\"Outfit Studio: OpenGL context is not OK.\"), _(\"OpenGL Error\"), wxICON_ERROR, editUV);\n\t}\n\n\tuvSurface.Initialize(this, context.get());\n\n\tauto size = GetSize();\n\tuvSurface.SetStartingView(Vector3(-0.5f, 0.5f, -1.0f), Vector3(), size.GetWidth(), size.GetHeight());\n\tuvSurface.SetPerspective(false);\n\n\tuvSurface.ToggleLighting();\n\tuvSurface.SetVertexColors();\n\n\tInitMeshes();\n\tRender();\n}\n\nvoid EditUVCanvas::OnPaint(wxPaintEvent& event) {\n\t// Initialize OpenGL the first time the window is painted.\n\t// We unfortunately can't initialize it before the window is shown.\n\t// We could register for the EVT_SHOW event, but unfortunately it\n\t// appears to only be called after the first few EVT_PAINT events.\n\t// It also isn't supported on all platforms.\n\tif (firstPaint) {\n\t\tfirstPaint = false;\n\t\tOnShown();\n\t}\n\n\tuvSurface.RenderOneFrame();\n\tevent.Skip();\n}\n\nvoid EditUVCanvas::OnSize(wxSizeEvent& event) {\n\twxSize sz = event.GetSize();\n\tuvSurface.SetSize(sz.GetX(), sz.GetY());\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::OnMouseWheel(wxMouseEvent& event) {\n\tint delt = event.GetWheelRotation() / 10;\n\tuvSurface.DollyCamera(delt);\n\tuvSurface.ClampCameraPosition('Z', -10.0f, -0.1f);\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::OnMouseMove(wxMouseEvent& event) {\n\tif (editUV->IsActive())\n\t\tSetFocus();\n\n\tint x = 0;\n\tint y = 0;\n\tevent.GetPosition(&x, &y);\n\twxPoint p(x, y);\n\n\tEditUVTool activeTool = editUV->GetActiveTool();\n\n\tif (mbuttonDown) {\n\t\tisMDragging = true;\n\t\tif (wxGetKeyState(wxKeyCode::WXK_SHIFT)) {\n\t\t\tuvSurface.DollyCamera(y - lastY);\n\t\t\tuvSurface.ClampCameraPosition('Z', -10.0f, -0.1f);\n\t\t}\n\t\telse\n\t\t\tuvSurface.PanCamera(x - lastX, y - lastY);\n\n\t\tuvSurface.RenderOneFrame();\n\t}\n\n\tif (rbuttonDown) {\n\t\tisRDragging = true;\n\t\t//uvSurface.RenderOneFrame();\n\t}\n\n\tif (lbuttonDown) {\n\t\tisLDragging = true;\n\n\t\tVector3 start;\n\t\tVector3 current;\n\t\tVector3 last;\n\t\tVector3 d;\n\t\tuvSurface.GetPickRay(clickX, clickY, nullptr, d, start);\n\t\tuvSurface.GetPickRay(x, y, nullptr, d, current);\n\t\tuvSurface.GetPickRay(lastX, lastY, nullptr, d, last);\n\n\t\tRect rect;\n\t\tMesh* m = editUV->shapeMesh;\n\n\t\tif (activeTool == EditUVTool::BoxSelection) {\n\t\t\t// Draw normalized rectangle from start to current\n\t\t\trect.SetTopLeft(Vector2(start.x, start.y));\n\t\t\trect.SetBottomRight(Vector2(current.x, current.y));\n\t\t\trect = rect.Normalized();\n\n\t\t\tboxSelectMesh->verts[0].x = rect.GetTopLeft().u;\n\t\t\tboxSelectMesh->verts[0].y = rect.GetTopLeft().v;\n\n\t\t\tboxSelectMesh->verts[1].x = rect.GetTopRight().u;\n\t\t\tboxSelectMesh->verts[1].y = rect.GetTopRight().v;\n\n\t\t\tboxSelectMesh->verts[2].x = rect.GetBottomRight().u;\n\t\t\tboxSelectMesh->verts[2].y = rect.GetBottomRight().v;\n\n\t\t\tboxSelectMesh->verts[3].x = rect.GetBottomLeft().u;\n\t\t\tboxSelectMesh->verts[3].y = rect.GetBottomLeft().v;\n\n\t\t\tif (!wxGetKeyState(wxKeyCode::WXK_ALT)) {\n\t\t\t\tboxSelectMesh->color.x = 1.0f;\n\t\t\t\tboxSelectMesh->color.y = 1.0f;\n\t\t\t\tboxSelectMesh->color.z = 0.0f;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tboxSelectMesh->color.x = 0.0f;\n\t\t\t\tboxSelectMesh->color.y = 1.0f;\n\t\t\t\tboxSelectMesh->color.z = 0.0f;\n\t\t\t}\n\n\t\t\tboxSelectMesh->QueueUpdate(Mesh::UpdateType::Position);\n\t\t}\n\t\telse if (activeTool == EditUVTool::VertexSelection) {\n\t\t\tSelectVertex(p, wxGetKeyState(wxKeyCode::WXK_ALT));\n\t\t}\n\t\telse if (activeTool == EditUVTool::Move) {\n\t\t\t// Move alongside cursor\n\t\t\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\t\t\tif (uvGridMesh->vcolors[i] == Vector3(1.0f, 1.0f, 0.0f)) {\n\t\t\t\t\tuvGridMesh->verts[i].x += current.x - last.x;\n\t\t\t\t\tuvGridMesh->verts[i].y += current.y - last.y;\n\n\t\t\t\t\tm->texcoord[i].u = uvGridMesh->verts[i].x;\n\t\t\t\t\tm->texcoord[i].v = uvGridMesh->verts[i].y * -1.0f;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuvGridMesh->QueueUpdate(Mesh::UpdateType::Position);\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\t\t\teditUV->os->glView->Render();\n\t\t}\n\t\telse if (activeTool == EditUVTool::Scale) {\n\t\t\t// Store the initial direction\n\t\t\tif (lastDirection == EDITUV_DIRECTION_NONE) {\n\t\t\t\tif (current.x > currentCenter.x)\n\t\t\t\t\tlastDirection |= EDITUV_DIRECTION_RIGHT;\n\t\t\t\telse\n\t\t\t\t\tlastDirection |= EDITUV_DIRECTION_LEFT;\n\n\t\t\t\tif (current.y > currentCenter.y)\n\t\t\t\t\tlastDirection |= EDITUV_DIRECTION_DOWN;\n\t\t\t\telse\n\t\t\t\t\tlastDirection |= EDITUV_DIRECTION_UP;\n\t\t\t}\n\n\t\t\tfloat angle = std::atan2(currentCenter.y - current.y, currentCenter.x - current.x) * 180.0f / PI;\n\t\t\tfloat angleAbs = std::fabs(angle);\n\n\t\t\t// Set cursor depending on the angle to the center\n\t\t\tif ((angle >= -22.5f && angle < 22.5f) || (angleAbs >= 157.5f && angleAbs <= 180.0f))\n\t\t\t\tSetCursor(wxStockCursor::wxCURSOR_SIZEWE);\n\t\t\telse if ((angle >= 22.5f && angle < 67.5f) || (angle >= -157.5f && angle < -112.5))\n\t\t\t\tSetCursor(wxStockCursor::wxCURSOR_SIZENESW);\n\t\t\telse if (angleAbs >= 67.5f && angleAbs < 112.5f)\n\t\t\t\tSetCursor(wxStockCursor::wxCURSOR_SIZENS);\n\t\t\telse if ((angle >= 112.5f && angle < 157.5f) || (angle >= -67.5f && angle < -22.5f))\n\t\t\t\tSetCursor(wxStockCursor::wxCURSOR_SIZENWSE);\n\n\t\t\t// Scale up or down depending on the initial direction\n\t\t\tVector3 scale(1.0f, 1.0f, 0.0f);\n\n\t\t\tif (lastDirection & EDITUV_DIRECTION_RIGHT)\n\t\t\t\tscale.x += current.x - start.x;\n\t\t\telse\n\t\t\t\tscale.x += start.x - current.x;\n\n\t\t\tif (lastDirection & EDITUV_DIRECTION_DOWN)\n\t\t\t\tscale.y += current.y - start.y;\n\t\t\telse\n\t\t\t\tscale.y += start.y - current.y;\n\n\t\t\t// Shift enables uniform scaling\n\t\t\tif (wxGetKeyState(wxKeyCode::WXK_SHIFT)) {\n\t\t\t\tif (scale.x > scale.y)\n\t\t\t\t\tscale.y = scale.x;\n\t\t\t\telse\n\t\t\t\t\tscale.x = scale.y;\n\t\t\t}\n\n\t\t\tauto curState = editUV->history.GetCurState();\n\t\t\tif (curState) {\n\t\t\t\tauto& startState = curState->GetStartState();\n\n\t\t\t\t// Scale around the selection center\n\t\t\t\tfor (auto& s : startState) {\n\t\t\t\t\tif (uvGridMesh->vcolors[s.first] == Vector3(1.0f, 1.0f, 0.0f)) {\n\t\t\t\t\t\tVector3 startPos(s.second.u, s.second.v, 0.0f);\n\t\t\t\t\t\tuvGridMesh->verts[s.first] = (startPos - currentCenter).ComponentMultiply(scale) + currentCenter;\n\n\t\t\t\t\t\tm->texcoord[s.first].u = uvGridMesh->verts[s.first].x;\n\t\t\t\t\t\tm->texcoord[s.first].v = uvGridMesh->verts[s.first].y * -1.0f;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tuvGridMesh->QueueUpdate(Mesh::UpdateType::Position);\n\n\t\t\t\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\t\t\t\teditUV->os->glView->Render();\n\t\t\t}\n\t\t}\n\t\telse if (activeTool == EditUVTool::Rotate) {\n\t\t\tfloat angle = std::atan2(currentCenter.y - current.y, currentCenter.x - current.x);\n\t\t\tfloat angleDiff = angle - lastAngle;\n\t\t\tfloat angleSin = std::sin(angleDiff);\n\t\t\tfloat angleCos = std::cos(angleDiff);\n\n\t\t\tauto curState = editUV->history.GetCurState();\n\t\t\tif (curState) {\n\t\t\t\tauto& startState = curState->GetStartState();\n\n\t\t\t\t// Rotate around the selection center\n\t\t\t\tfor (auto& s : startState) {\n\t\t\t\t\tif (uvGridMesh->vcolors[s.first] == Vector3(1.0f, 1.0f, 0.0f)) {\n\t\t\t\t\t\tauto& vert = uvGridMesh->verts[s.first];\n\t\t\t\t\t\tVector3 pos(s.second.u, s.second.v, 0.0f);\n\t\t\t\t\t\tpos -= currentCenter;\n\n\t\t\t\t\t\tvert.x = pos.x * angleCos - pos.y * angleSin + currentCenter.x;\n\t\t\t\t\t\tvert.y = pos.x * angleSin + pos.y * angleCos + currentCenter.y;\n\n\t\t\t\t\t\tm->texcoord[s.first].u = vert.x;\n\t\t\t\t\t\tm->texcoord[s.first].v = vert.y * -1.0f;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tuvGridMesh->QueueUpdate(Mesh::UpdateType::Position);\n\n\t\t\t\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\t\t\t\teditUV->os->glView->Render();\n\t\t\t}\n\t\t}\n\n\t\tuvSurface.RenderOneFrame();\n\t}\n\n\tif ((!lbuttonDown && !rbuttonDown && !mbuttonDown) || activeTool == EditUVTool::VertexSelection) {\n\t\tUpdateCursor(x, y, \"UVGrid\");\n\t\tuvSurface.RenderOneFrame();\n\t}\n\n\tlastX = x;\n\tlastY = y;\n}\n\nvoid EditUVCanvas::OnLeftDown(wxMouseEvent& event) {\n\tif (!HasCapture())\n\t\tCaptureMouse();\n\n\tcurrentCenter.Zero();\n\tlastDirection = EDITUV_DIRECTION_NONE;\n\n\tevent.GetPosition(&clickX, &clickY);\n\n\tVector3 click;\n\tVector3 d;\n\tuvSurface.GetPickRay(clickX, clickY, nullptr, d, click);\n\n\teditUV->StartTool();\n\n\tswitch (editUV->GetActiveTool()) {\n\t\tcase EditUVTool::VertexSelection: break;\n\n\t\tcase EditUVTool::BoxSelection:\n\t\t\tboxSelectMesh->verts[0] = Vector3(click.x, click.y, 0.0f);\n\t\t\tboxSelectMesh->verts[1] = Vector3(click.x, click.y, 0.0f);\n\t\t\tboxSelectMesh->verts[2] = Vector3(click.x, click.y, 0.0f);\n\t\t\tboxSelectMesh->verts[3] = Vector3(click.x, click.y, 0.0f);\n\t\t\tboxSelectMesh->color = Vector3(1.0f, 1.0f, 0.0f);\n\t\t\tboxSelectMesh->QueueUpdate(Mesh::UpdateType::Position);\n\t\t\tboxSelectMesh->bVisible = true;\n\t\t\tbreak;\n\n\t\tcase EditUVTool::Move:\n\t\tcase EditUVTool::Scale:\n\t\tcase EditUVTool::Rotate:\n\t\t\tStartMeshAction();\n\t\t\tCalcSelectionCenter();\n\t\t\tlastAngle = std::atan2(currentCenter.y - click.y, currentCenter.x - click.x);\n\t\t\tbreak;\n\t}\n\n\tlbuttonDown = true;\n}\n\nvoid EditUVCanvas::OnLeftUp(wxMouseEvent& event) {\n\tif (HasCapture())\n\t\tReleaseMouse();\n\n\tevent.GetPosition(&upX, &upY);\n\twxPoint p(upX, upY);\n\n\tRect rect;\n\n\tswitch (editUV->GetActiveTool()) {\n\t\tcase EditUVTool::BoxSelection:\n\t\t\trect.SetTopLeft(Vector2(boxSelectMesh->verts[0].x, boxSelectMesh->verts[0].y));\n\t\t\trect.SetBottomRight(Vector2(boxSelectMesh->verts[2].x, boxSelectMesh->verts[2].y));\n\n\t\t\tif (!wxGetKeyState(wxKeyCode::WXK_ALT)) {\n\t\t\t\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\t\t\t\tif (rect.Contains(Vector2(uvGridMesh->verts[i].x, uvGridMesh->verts[i].y))) {\n\t\t\t\t\t\tuvGridMesh->vcolors[i].x = 1.0f;\n\t\t\t\t\t\tuvGridMesh->vcolors[i].y = 1.0f;\n\t\t\t\t\t\tuvGridMesh->vcolors[i].z = 0.0f;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (!wxGetKeyState(wxKeyCode::WXK_SHIFT)) {\n\t\t\t\t\t\t\tuvGridMesh->vcolors[i].x = 0.0f;\n\t\t\t\t\t\t\tuvGridMesh->vcolors[i].y = 1.0f;\n\t\t\t\t\t\t\tuvGridMesh->vcolors[i].z = 0.0f;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\t\t\t\tif (rect.Contains(Vector2(uvGridMesh->verts[i].x, uvGridMesh->verts[i].y))) {\n\t\t\t\t\t\tuvGridMesh->vcolors[i].x = 0.0f;\n\t\t\t\t\t\tuvGridMesh->vcolors[i].y = 1.0f;\n\t\t\t\t\t\tuvGridMesh->vcolors[i].z = 0.0f;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuvGridMesh->QueueUpdate(Mesh::UpdateType::VertexColors);\n\t\t\tboxSelectMesh->bVisible = false;\n\t\t\tbreak;\n\n\t\tcase EditUVTool::VertexSelection: SelectVertex(p, wxGetKeyState(wxKeyCode::WXK_ALT)); break;\n\n\t\tcase EditUVTool::Move:\n\t\tcase EditUVTool::Scale:\n\t\tcase EditUVTool::Rotate: EndMeshAction(); break;\n\t}\n\n\tisLDragging = false;\n\tlbuttonDown = false;\n\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::OnMiddleDown(wxMouseEvent& WXUNUSED(event)) {\n\tif (!HasCapture())\n\t\tCaptureMouse();\n\n\tmbuttonDown = true;\n}\n\nvoid EditUVCanvas::OnMiddleUp(wxMouseEvent& WXUNUSED(event)) {\n\tif (HasCapture())\n\t\tReleaseMouse();\n\n\tisMDragging = false;\n\tmbuttonDown = false;\n}\n\nvoid EditUVCanvas::OnRightDown(wxMouseEvent& WXUNUSED(event)) {\n\tif (!HasCapture())\n\t\tCaptureMouse();\n\n\trbuttonDown = true;\n}\n\nvoid EditUVCanvas::OnRightUp(wxMouseEvent& WXUNUSED(event)) {\n\tif (HasCapture())\n\t\tReleaseMouse();\n\n\trbuttonDown = false;\n}\n\nvoid EditUVCanvas::OnKeyDown(wxKeyEvent& event) {\n\tif (!lbuttonDown && !rbuttonDown && !mbuttonDown) {\n\t\tswitch (event.GetKeyCode()) {\n\t\t\tcase '1': editUV->SelectTool(EditUVTool::BoxSelection); break;\n\t\t\tcase '2': editUV->SelectTool(EditUVTool::VertexSelection); break;\n\t\t\tcase '3': editUV->SelectTool(EditUVTool::Move); break;\n\t\t\tcase '4': editUV->SelectTool(EditUVTool::Scale); break;\n\t\t\tcase '5': editUV->SelectTool(EditUVTool::Rotate); break;\n\t\t}\n\t}\n}\n\nvoid EditUVCanvas::SetNotifyWindow(wxWindow* win) {\n\teditUV = dynamic_cast<EditUV*>(win);\n}\n\nvoid EditUVCanvas::SelectAll() {\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\tuvGridMesh->vcolors[i].x = 1.0f;\n\t\tuvGridMesh->vcolors[i].y = 1.0f;\n\t\tuvGridMesh->vcolors[i].z = 0.0f;\n\t}\n\n\tuvGridMesh->QueueUpdate(Mesh::UpdateType::VertexColors);\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::SelectInvert() {\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++)\n\t\tuvGridMesh->vcolors[i].x = uvGridMesh->vcolors[i].x == 1.0f ? 0.0f : 1.0f;\n\n\tuvGridMesh->QueueUpdate(Mesh::UpdateType::VertexColors);\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::SelectLess() {\n\tstd::set<int> unselectPoints;\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\tif (uvGridMesh->vcolors[i].x > 0.0f) {\n\t\t\tstd::unordered_set<int> adjacentPoints;\n\t\t\tuvGridMesh->GetAdjacentPoints(i, adjacentPoints);\n\n\t\t\tfor (auto& adj : adjacentPoints) {\n\t\t\t\tif (uvGridMesh->vcolors[adj].x == 0.0f) {\n\t\t\t\t\tunselectPoints.insert(i);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (auto& up : unselectPoints)\n\t\tuvGridMesh->vcolors[up].x = 0.0f;\n\n\tuvGridMesh->QueueUpdate(Mesh::UpdateType::VertexColors);\n\tuvSurface.RenderOneFrame();\n}\n\nvoid EditUVCanvas::SelectMore() {\n\tstd::unordered_set<int> adjacentPoints;\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++)\n\t\tif (uvGridMesh->vcolors[i].x > 0.0f)\n\t\t\tuvGridMesh->GetAdjacentPoints(i, adjacentPoints);\n\n\tfor (auto& adj : adjacentPoints)\n\t\tuvGridMesh->vcolors[adj].x = 1.0f;\n\n\tuvGridMesh->QueueUpdate(Mesh::UpdateType::VertexColors);\n\tuvSurface.RenderOneFrame();\n}\n\nVector3 EditUVCanvas::CalcSelectionCenter() {\n\tint count = 0;\n\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\tif (uvGridMesh->vcolors[i] == Vector3(1.0f, 1.0f, 0.0f)) {\n\t\t\tcurrentCenter = currentCenter + uvGridMesh->verts[i];\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tif (count > 0)\n\t\tcurrentCenter = currentCenter / count;\n\telse\n\t\tcurrentCenter.Zero();\n\n\treturn currentCenter;\n}\n\nvoid EditUVCanvas::StartMeshAction() {\n\tstd::unordered_map<int, Vector2> state;\n\tstate.reserve(uvGridMesh->nVerts);\n\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++)\n\t\tstate[i] = Vector2(uvGridMesh->verts[i].x, uvGridMesh->verts[i].y);\n\n\tauto action = new EditUVAction();\n\taction->SetActionMesh(uvGridMesh);\n\taction->SetStartState(state);\n\teditUV->history.Add(action);\n}\n\nvoid EditUVCanvas::EndMeshAction() {\n\tstd::unordered_map<int, Vector2> state;\n\tstate.reserve(uvGridMesh->nVerts);\n\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++)\n\t\tstate[i] = Vector2(uvGridMesh->verts[i].x, uvGridMesh->verts[i].y);\n\n\tauto action = editUV->history.GetCurState();\n\tif (action)\n\t\taction->SetEndState(state);\n\n\tif (editUV->GetActiveTool() == EditUVTool::Rotate)\n\t\tSetCursor(wxStockCursor::wxCURSOR_HAND);\n\telse\n\t\tSetCursor(wxStockCursor::wxCURSOR_SIZING);\n}\n\nvoid EditUVCanvas::ApplyMeshTransform(const Matrix4& mat) {\n\tMesh* m = editUV->shapeMesh;\n\n\tfor (int i = 0; i < uvGridMesh->nVerts; i++) {\n\t\tif (uvGridMesh->vcolors[i] == Vector3(1.0f, 1.0f, 0.0f)) {\n\t\t\tuvGridMesh->verts[i] = mat * uvGridMesh->verts[i];\n\n\t\t\tm->texcoord[i].u = uvGridMesh->verts[i].x;\n\t\t\tm->texcoord[i].v = uvGridMesh->verts[i].y * -1.0f;\n\t\t}\n\t}\n\n\tuvGridMesh->QueueUpdate(Mesh::UpdateType::Position);\n\n\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\teditUV->os->glView->Render();\n}\n\nvoid EditUVCanvas::InitMeshes() {\n\tauto project = editUV->os->project;\n\tauto glView = editUV->os->glView;\n\n\tauto seamEdgesRefMesh = glView->GetMesh(editUV->shape->name.get());\n\tif (seamEdgesRefMesh) {\n\t\tseamEdgesMesh = glView->gls.AddVisSeamEdges(seamEdgesRefMesh, true);\n\t\tglView->Render();\n\t}\n\n\tplaneMesh = uvSurface.AddVisPlane(Matrix4(), Vector2(64.0f, 64.0f), 64.0f);\n\tif (planeMesh) {\n\t\tstd::string texFile;\n\t\teditUV->nif->GetTextureSlot(editUV->shape, texFile, 0);\n\n\t\t// Replace all backward slashes with one forward slash\n\t\ttexFile = std::regex_replace(texFile, std::regex(\"\\\\\\\\+\"), \"/\");\n\n\t\t// Remove everything before the first occurence of \"/textures/\"\n\t\ttexFile = std::regex_replace(texFile, std::regex(\"^(.*?)/textures/\", std::regex_constants::icase), \"\");\n\n\t\t// Remove all slashes from the front\n\t\ttexFile = std::regex_replace(texFile, std::regex(\"^/+\"), \"\");\n\n\t\t// If the path doesn't start with \"textures/\", add it to the front\n\t\ttexFile = std::regex_replace(texFile, std::regex(\"^(?!^textures/)\", std::regex_constants::icase), \"textures/\");\n\n\t\tstd::string texturesDir = Config[\"GameDataPath\"];\n\t\ttexFile = texturesDir + texFile;\n\n\t\tstd::vector<std::string> textures(1, texFile);\n\t\tstd::string vShader = Config[\"AppDir\"] + \"/res/shaders/default.vert\";\n\t\tstd::string fShader = Config[\"AppDir\"] + \"/res/shaders/default.frag\";\n\t\tplaneMesh->material = uvSurface.GetResourceLoader()->AddMaterial(textures, vShader, fShader);\n\t\tuvSurface.UpdateShaders(planeMesh);\n\t}\n\n\tstd::vector<Vector3> verts(editUV->shape->GetNumVertices());\n\tstd::vector<Vector2> uvs(editUV->shape->GetNumVertices());\n\teditUV->nif->GetUvsForShape(editUV->shape, uvs);\n\n\tif (uvs.size() != verts.size()) {\n\t\teditUV->Close();\n\t\treturn;\n\t}\n\n\tif (!editUV->sliderName.empty())\n\t\tproject->GetSliderDiffUV(editUV->shape, editUV->sliderName, uvs);\n\n\tstd::vector<Triangle> tris;\n\teditUV->shape->GetTriangles(tris);\n\n\tuvGridMesh = new Mesh();\n\tuvGridMesh->nVerts = verts.size();\n\tuvGridMesh->nTris = tris.size();\n\n\tif (uvGridMesh->nVerts > 0) {\n\t\tuvGridMesh->verts = std::make_unique<Vector3[]>(uvGridMesh->nVerts);\n\t\tuvGridMesh->vcolors = std::make_unique<Vector3[]>(uvGridMesh->nVerts);\n\t}\n\n\tif (uvGridMesh->nTris > 0)\n\t\tuvGridMesh->tris = std::make_unique<Triangle[]>(uvGridMesh->nTris);\n\n\tfor (int v = 0; v < uvGridMesh->nVerts; v++) {\n\t\tuvGridMesh->verts[v].x = uvs[v].u;\n\t\tuvGridMesh->verts[v].y = uvs[v].v * -1.0f;\n\t\tuvGridMesh->vcolors[v] = Vector3(0.0f, 1.0f, 0.0f);\n\t}\n\n\tfor (int t = 0; t < uvGridMesh->nTris; t++)\n\t\tuvGridMesh->tris[t] = tris[t];\n\n\tuvGridMesh->rendermode = Mesh::RenderMode::LitWire;\n\tuvGridMesh->color = Vector3(1.0f, 0.0f, 0.0f);\n\tuvGridMesh->vertexColors = true;\n\n\tuvGridMaterial = GLMaterial(Config[\"AppDir\"] + \"/res/shaders/primitive.vert\", Config[\"AppDir\"] + \"/res/shaders/primitive.frag\");\n\tuvGridMesh->material = &uvGridMaterial;\n\tuvGridMesh->shapeName = \"UVGrid\";\n\n\tuvGridMesh->BuildVertexAdjacency();\n\tuvGridMesh->BuildEdgeList();\n\tuvGridMesh->CreateBVH();\n\tuvGridMesh->CreateBuffers();\n\tuvSurface.AddOverlay(uvGridMesh);\n\tuvSurface.UpdateShaders(uvGridMesh);\n\n\tboxSelectMesh = new Mesh();\n\tboxSelectMesh->nVerts = 4;\n\tboxSelectMesh->nTris = 2;\n\n\tboxSelectMesh->verts = std::make_unique<Vector3[]>(boxSelectMesh->nVerts);\n\tboxSelectMesh->tris = std::make_unique<Triangle[]>(boxSelectMesh->nTris);\n\n\tboxSelectMesh->color = Vector3(1.0f, 1.0f, 0.0f);\n\tboxSelectMesh->prop.alpha = 0.25f;\n\tboxSelectMesh->alphaFlags = 4333;\n\n\tboxSelectMesh->tris[0] = Triangle(0, 1, 2);\n\tboxSelectMesh->tris[1] = Triangle(2, 3, 0);\n\n\tboxSelectMaterial = GLMaterial(Config[\"AppDir\"] + \"/res/shaders/primitive.vert\", Config[\"AppDir\"] + \"/res/shaders/primitive.frag\");\n\tboxSelectMesh->material = &boxSelectMaterial;\n\n\tboxSelectMesh->shapeName = \"BoxSelect\";\n\tboxSelectMesh->doublesided = true;\n\tboxSelectMesh->bVisible = false;\n\n\tboxSelectMesh->CreateBuffers();\n\tuvSurface.AddOverlay(boxSelectMesh);\n\tuvSurface.UpdateShaders(boxSelectMesh);\n}\n\nbool EditUVCanvas::ExportUVTemplate(const std::string& filename, int resolution, const wxColour& wireColor, const wxColour& bgColor, bool transparentBG, bool includeTexture, bool clampUVs, bool antiAliasing) {\n\tif (!uvGridMesh)\n\t\treturn false;\n\n\tuvSurface.SetContext();\n\n\t// Determine save format from file extension\n\tint saveType = SOIL_SAVE_TYPE_PNG;\n\tstd::string ext = filename.substr(filename.find_last_of('.') + 1);\n\tif (ext == \"tga\" || ext == \"TGA\")\n\t\tsaveType = SOIL_SAVE_TYPE_TGA;\n\telse if (ext == \"bmp\" || ext == \"BMP\")\n\t\tsaveType = SOIL_SAVE_TYPE_BMP;\n\telse if (ext == \"jpg\" || ext == \"JPG\" || ext == \"jpeg\" || ext == \"JPEG\")\n\t\tsaveType = SOIL_SAVE_TYPE_JPG;\n\telse if (ext == \"dds\" || ext == \"DDS\")\n\t\tsaveType = SOIL_SAVE_TYPE_DDS;\n\n\t// Formats without alpha support: pick a contrasting background based on wire color brightness\n\tbool formatSupportsAlpha = (saveType == SOIL_SAVE_TYPE_PNG || saveType == SOIL_SAVE_TYPE_TGA || saveType == SOIL_SAVE_TYPE_DDS);\n\tbool useTransparency = transparentBG && formatSupportsAlpha;\n\n\t// MSAA: use 4x multisampling when anti-aliasing is enabled\n\tint samples = antiAliasing ? 4 : 0;\n\n\t// Save current state\n\tVector3 savedCamPos = uvSurface.camPos;\n\tVector3 savedCamOffset = uvSurface.camOffset;\n\tVector3 savedCamRot = uvSurface.camRot;\n\tVector3 savedCamRotOffset = uvSurface.camRotOffset;\n\tVector3 savedBgColor = uvSurface.GetBackgroundColor();\n\tVector3 savedGridColor = uvGridMesh->color;\n\tbool savedVertexColors = uvGridMesh->vertexColors;\n\n\t// Reset camera to default UV view (shows full 0-1 UV space)\n\tuvSurface.camPos = Vector3(-0.5f, 0.5f, -1.0f);\n\tuvSurface.camOffset = Vector3();\n\tuvSurface.camRot = Vector3();\n\tuvSurface.camRotOffset = Vector3();\n\n\t// Set up the projection for a square 1:1 viewport\n\tuint32_t savedW, savedH;\n\tuvSurface.GetSize(savedW, savedH);\n\tuvSurface.SetSize(resolution, resolution);\n\tuvSurface.UpdateProjection();\n\n\t// Create offscreen buffer (with optional MSAA)\n\tGLOffScreenBuffer offscreen(&uvSurface, resolution, resolution, 1, {}, samples);\n\toffscreen.Start();\n\n\t// Clear with background color\n\tif (useTransparency) {\n\t\tglClearColor(0.0f, 0.0f, 0.0f, 0.0f);\n\t}\n\telse if (transparentBG && !formatSupportsAlpha) {\n\t\tfloat luminance = wireColor.Red() / 255.0f * 0.299f + wireColor.Green() / 255.0f * 0.587f + wireColor.Blue() / 255.0f * 0.114f;\n\t\tfloat bg = luminance > 0.5f ? 0.0f : 1.0f;\n\t\tglClearColor(bg, bg, bg, 1.0f);\n\t}\n\telse {\n\t\tglClearColor(bgColor.Red() / 255.0f, bgColor.Green() / 255.0f, bgColor.Blue() / 255.0f, 1.0f);\n\t}\n\tglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n\t// Clamp: use scissor test to restrict rendering to 0-1 UV range\n\tif (clampUVs) {\n\t\tglEnable(GL_SCISSOR_TEST);\n\t\tglScissor(0, 0, resolution, resolution);\n\t}\n\n\t// Render texture plane if requested\n\tif (includeTexture && planeMesh && planeMesh->material) {\n\t\tuvSurface.RenderMesh(planeMesh);\n\t}\n\n\t// Render UV wireframe with custom color (disable vertex colors, override mesh color)\n\tuvGridMesh->color = Vector3(wireColor.Red() / 255.0f, wireColor.Green() / 255.0f, wireColor.Blue() / 255.0f);\n\tuvGridMesh->vertexColors = false;\n\tuvSurface.UpdateShaders(uvGridMesh);\n\tuvSurface.RenderMesh(uvGridMesh);\n\n\tif (clampUVs) {\n\t\tglDisable(GL_SCISSOR_TEST);\n\t}\n\n\t// Resolve MSAA (no-op if samples == 0) and read pixels\n\toffscreen.Resolve();\n\n\tstd::unique_ptr<GLubyte[]> pixels(new GLubyte[resolution * resolution * 4]);\n\tglReadPixels(0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());\n\n\toffscreen.End();\n\n\t// Restore mesh state\n\tuvGridMesh->color = savedGridColor;\n\tuvGridMesh->vertexColors = savedVertexColors;\n\tuvSurface.UpdateShaders(uvGridMesh);\n\n\t// Restore camera and viewport\n\tuvSurface.camPos = savedCamPos;\n\tuvSurface.camOffset = savedCamOffset;\n\tuvSurface.camRot = savedCamRot;\n\tuvSurface.camRotOffset = savedCamRotOffset;\n\tuvSurface.SetBackgroundColor(savedBgColor);\n\tuvSurface.SetSize(savedW, savedH);\n\n\t// Flip vertically (glReadPixels reads bottom-to-top, all save formats expect top-to-bottom)\n\t{\n\t\tint rowBytes = resolution * 4;\n\t\tstd::unique_ptr<GLubyte[]> rowBuf(new GLubyte[rowBytes]);\n\t\tfor (int y = 0; y < resolution / 2; y++) {\n\t\t\tGLubyte* topRow = pixels.get() + y * rowBytes;\n\t\t\tGLubyte* botRow = pixels.get() + (resolution - 1 - y) * rowBytes;\n\t\t\tmemcpy(rowBuf.get(), topRow, rowBytes);\n\t\t\tmemcpy(topRow, botRow, rowBytes);\n\t\t\tmemcpy(botRow, rowBuf.get(), rowBytes);\n\t\t}\n\t}\n\n\tint result = SOIL_save_image(filename.c_str(), saveType, resolution, resolution, 4, pixels.get());\n\n\t// Re-render the canvas\n\tRender();\n\n\treturn result != 0;\n}\n\nvoid EditUVCanvas::UpdateCursor(int ScreenX, int ScreenY, const std::string& meshName) {\n\thoverPoint = -1;\n\n\tauto m = uvSurface.GetOverlay(meshName);\n\tif (!m)\n\t\treturn;\n\n\tVector3 o;\n\tVector3 d;\n\tuvSurface.GetPickRay(ScreenX, ScreenY, m, d, o);\n\n\to.z = 0.0f;\n\t//d = d * -1.0f;\n\n\tstd::vector<IntersectResult> results;\n\tif (m->bvh && m->bvh->IntersectRay(o, d, &results)) {\n\t\tif (results.size() > 0) {\n\t\t\tsize_t min_i = 0;\n\t\t\tfloat minDist = results[0].HitDistance;\n\t\t\tfor (size_t i = 1; i < results.size(); i++) {\n\t\t\t\tif (results[i].HitDistance < minDist) {\n\t\t\t\t\tminDist = results[i].HitDistance;\n\t\t\t\t\tmin_i = i;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tVector3 origin = results[min_i].HitCoord;\n\n\t\t\tTriangle t = m->tris[results[min_i].HitFacet];\n\n\t\t\tVector3 hilitepoint = m->verts[t.p1];\n\t\t\tfloat closestdist = fabs(m->verts[t.p1].DistanceTo(origin));\n\t\t\tfloat nextdist = fabs(m->verts[t.p2].DistanceTo(origin));\n\t\t\tint pointid = t.p1;\n\n\t\t\tif (nextdist < closestdist) {\n\t\t\t\tclosestdist = nextdist;\n\t\t\t\thilitepoint = m->verts[t.p2];\n\t\t\t\tpointid = t.p2;\n\t\t\t}\n\t\t\tnextdist = fabs(m->verts[t.p3].DistanceTo(origin));\n\t\t\tif (nextdist < closestdist) {\n\t\t\t\thilitepoint = m->verts[t.p3];\n\t\t\t\tpointid = t.p3;\n\t\t\t}\n\n\t\t\thoverPoint = pointid;\n\n\t\t\tVector3 visPoint = m->TransformPosMeshToModel(hilitepoint);\n\t\t\tauto visPointMesh = uvSurface.AddVisPoint(visPoint, \"pointhilite\");\n\t\t\tif (visPointMesh)\n\t\t\t\tvisPointMesh->color = Vector3(1.0f, 0.0f, 0.0f);\n\t\t}\n\t}\n\n\tuvSurface.ShowCursor(hoverPoint >= 0 ? true : false);\n}\n\nbool EditUVCanvas::SelectVertex(const wxPoint& screenPos, bool unselect) {\n\tint vertIndex;\n\tif (!uvSurface.GetCursorVertex(screenPos.x, screenPos.y, &vertIndex, uvGridMesh))\n\t\treturn false;\n\n\tif (unselect)\n\t\tuvGridMesh->vcolors[vertIndex].x = 0.0f;\n\telse\n\t\tuvGridMesh->vcolors[vertIndex].x = 1.0f;\n\n\tuvGridMesh->QueueUpdate(Mesh::UpdateType::VertexColors);\n\treturn true;\n}\n"
  },
  {
    "path": "src/program/EditUV.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"OutfitStudio.h\"\n\nconst int EDITUV_MAX_UNDO = 200;\n\nconst int EDITUV_DIRECTION_NONE = 0x0;\nconst int EDITUV_DIRECTION_RIGHT = 0x1;\nconst int EDITUV_DIRECTION_LEFT = 0x2;\nconst int EDITUV_DIRECTION_UP = 0x4;\nconst int EDITUV_DIRECTION_DOWN = 0x8;\n\nenum class EditUVTool { BoxSelection, VertexSelection, Move, Scale, Rotate };\n\nclass EditUVAction {\n\tMesh* actionMesh = nullptr;\n\tstd::unordered_map<int, nifly::Vector2> startState;\n\tstd::unordered_map<int, nifly::Vector2> endState;\n\npublic:\n\tvoid SetActionMesh(Mesh* m) { actionMesh = m; }\n\n\tstd::unordered_map<int, nifly::Vector2>& GetStartState();\n\tstd::unordered_map<int, nifly::Vector2>& GetEndState();\n\tvoid SetStartState(std::unordered_map<int, nifly::Vector2>& state);\n\tvoid SetEndState(std::unordered_map<int, nifly::Vector2>& state);\n\tvoid RestoreStartState();\n\tvoid RestoreEndState();\n};\n\nclass EditUVHistory {\n\tint curState = -1;\n\tstd::vector<EditUVAction*> actions;\n\npublic:\n\tEditUVHistory();\n\t~EditUVHistory();\n\n\tvoid Add(EditUVAction* action);\n\tbool Back();\n\tbool Forward();\n\tvoid Clear();\n\n\tEditUVAction* GetCurState() {\n\t\tif (curState == -1)\n\t\t\treturn nullptr;\n\n\t\treturn actions[curState];\n\t}\n};\n\nclass EditUVCanvas;\n\nclass EditUV : public wxFrame {\npublic:\n\tOutfitStudioFrame* os = nullptr;\n\tEditUVCanvas* canvas = nullptr;\n\tnifly::NifFile* nif = nullptr;\n\tnifly::NiShape* shape = nullptr;\n\tMesh* shapeMesh = nullptr;\n\tstd::string sliderName;\n\n\tEditUVAction currentAction;\n\tEditUVHistory history;\n\n\twxToolBar* uvToolBar = nullptr;\n\twxMenuBar* uvMenuBar = nullptr;\n\n\tEditUV(wxWindow*, nifly::NifFile*, nifly::NiShape*, Mesh*, const std::string&);\n\t~EditUV();\n\n\tvoid StartTool() { toolActive = toolSelected; }\n\n\tEditUVTool GetSelectedTool() { return toolSelected; }\n\n\tEditUVTool GetActiveTool() { return toolActive; }\n\n\tvoid SelectTool(EditUVTool tool);\n\tvoid Undo();\n\tvoid Redo();\n\nprivate:\n\tEditUVTool toolSelected = EditUVTool::BoxSelection;\n\tEditUVTool toolActive = EditUVTool::BoxSelection;\n\n\tvoid UpdateShapeMesh(bool apply = true);\n\n\tvoid OnSelectTool(wxCommandEvent& event);\n\tvoid OnSeamEdges(wxCommandEvent& event);\n\tvoid OnUndo(wxCommandEvent& event);\n\tvoid OnRedo(wxCommandEvent& event);\n\tvoid OnSelectAll(wxCommandEvent& event);\n\tvoid OnSelectInvert(wxCommandEvent& event);\n\tvoid OnSelectLess(wxCommandEvent& event);\n\tvoid OnSelectMore(wxCommandEvent& event);\n\tvoid OnMaskSelection(wxCommandEvent& event);\n\tvoid OnExportUVTemplate(wxCommandEvent& event);\n\tvoid OnTranslate(wxCommandEvent& event);\n\tvoid OnRotate(wxCommandEvent& event);\n\tvoid OnScale(wxCommandEvent& event);\n\tvoid OnApply(wxCommandEvent& event);\n\tvoid OnCancel(wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\n\twxDECLARE_EVENT_TABLE();\n};\n\nclass EditUVCanvas : public wxGLCanvas {\npublic:\n\tMesh* seamEdgesMesh = nullptr;\n\tMesh* planeMesh = nullptr;\n\tMesh* uvGridMesh = nullptr;\n\tMesh* boxSelectMesh = nullptr;\n\n\tEditUVCanvas(wxWindow* parent, const wxSize& size, const wxGLAttributes& attribs);\n\t~EditUVCanvas();\n\npublic:\n\tvoid SetNotifyWindow(wxWindow*);\n\tvoid SelectAll();\n\tvoid SelectInvert();\n\tvoid SelectLess();\n\tvoid SelectMore();\n\n\tnifly::Vector3 CalcSelectionCenter();\n\tvoid StartMeshAction();\n\tvoid EndMeshAction();\n\tvoid ApplyMeshTransform(const nifly::Matrix4&);\n\n\tvoid SetCursorType(GLSurface::CursorType cursorType) { uvSurface.SetCursorType(cursorType); }\n\n\tvoid Render() { uvSurface.RenderOneFrame(); }\n\n\tbool ExportUVTemplate(const std::string& filename, int resolution, const wxColour& wireColor, const wxColour& bgColor, bool transparentBG, bool includeTexture, bool clampUVs, bool antiAliasing);\n\nprivate:\n\tEditUV* editUV = nullptr;\n\n\tGLSurface uvSurface;\n\tstd::unique_ptr<wxGLContext> context;\n\n\tbool firstPaint = true;\n\n\tbool rbuttonDown = false;\n\tbool lbuttonDown = false;\n\tbool mbuttonDown = false;\n\tbool isLDragging = false;\n\tbool isMDragging = false;\n\tbool isRDragging = false;\n\n\tint clickX = 0;\n\tint clickY = 0;\n\tint upX = 0;\n\tint upY = 0;\n\tint lastX = 0;\n\tint lastY = 0;\n\n\tnifly::Vector3 currentCenter;\n\tint lastDirection;\n\tfloat lastAngle;\n\n\tint hoverPoint = -1;\n\n\tGLMaterial uvGridMaterial;\n\tGLMaterial boxSelectMaterial;\n\n\tvoid OnShown();\n\tvoid OnPaint(wxPaintEvent& event);\n\tvoid OnSize(wxSizeEvent& event);\n\n\tvoid OnMouseWheel(wxMouseEvent& event);\n\tvoid OnMouseMove(wxMouseEvent& event);\n\n\tvoid OnLeftDown(wxMouseEvent& event);\n\tvoid OnLeftUp(wxMouseEvent& event);\n\tvoid OnMiddleDown(wxMouseEvent& event);\n\tvoid OnMiddleUp(wxMouseEvent& event);\n\tvoid OnRightDown(wxMouseEvent& event);\n\tvoid OnRightUp(wxMouseEvent& event);\n\tvoid OnKeyDown(wxKeyEvent& event);\n\n\tvoid InitMeshes();\n\tvoid UpdateCursor(int ScreenX, int ScreenY, const std::string& meshName);\n\tbool SelectVertex(const wxPoint& screenPos, bool unselect = false);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/FBXImportDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#ifdef USE_FBXSDK\n\n#include \"FBXImportDialog.h\"\n#include \"../utils/ConfigDialogUtil.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <wx/valnum.h>\n\nusing namespace nifly;\n\nextern ConfigurationManager Config;\nextern ConfigurationManager OutfitStudioConfig;\n\n\nwxBEGIN_EVENT_TABLE(FBXImportDialog, GLDialog)\n\tEVT_CHECKBOX(XRCID(\"cbInvertU\"), FBXImportDialog::OnInvertU)\n\tEVT_CHECKBOX(XRCID(\"cbInvertV\"), FBXImportDialog::OnInvertV)\n\tEVT_TEXT(XRCID(\"scale\"), FBXImportDialog::OnScale)\n\tEVT_CHOICE(XRCID(\"rotateX\"), FBXImportDialog::OnRotateX)\n\tEVT_CHOICE(XRCID(\"rotateY\"), FBXImportDialog::OnRotateY)\n\tEVT_CHOICE(XRCID(\"rotateZ\"), FBXImportDialog::OnRotateZ)\n\tEVT_LIST_ITEM_SELECTED(XRCID(\"meshesList\"), FBXImportDialog::OnItemSelected)\n\tEVT_LIST_ITEM_DESELECTED(XRCID(\"meshesList\"), FBXImportDialog::OnItemDeselected)\n\tEVT_LIST_KEY_DOWN(XRCID(\"meshesList\"), FBXImportDialog::OnListKeyDown)\n\tEVT_BUTTON(wxID_OK, FBXImportDialog::OnImport)\nwxEND_EVENT_TABLE()\n\nFBXImportDialog::FBXImportDialog(wxWindow* parent, const std::string& fileName, size_t vertexLimit, size_t triangleLimit, const wxString& warningLabel)\n\t: GLDialog()\n\t, fileName(fileName)\n\t, vertexLimit(vertexLimit)\n\t, triangleLimit(triangleLimit) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ImportDialog.xrc\");\n\txrc->LoadDialog(this, parent, \"importDialog\");\n\n\tlbWarning = XRCCTRL((*this), \"lbWarning\", wxStaticText);\n\n\tif (!warningLabel.IsEmpty()) {\n\t\tlbWarning->SetLabel(warningLabel);\n\t\tlbWarning->Wrap(GetClientSize().x - 25);\n\t\tlbWarning->Show();\n\t}\n\n\tcbInvertU = XRCCTRL((*this), \"cbInvertU\", wxCheckBox);\n\tcbInvertV = XRCCTRL((*this), \"cbInvertV\", wxCheckBox);\n\n\twxFloatingPointValidator<float> floatValidator(5);\n\tfloatValidator.SetRange(0.00001f, 10000.0f);\n\n\tscale = XRCCTRL((*this), \"scale\", wxTextCtrl);\n\tscale->SetValidator(floatValidator);\n\n\trotateX = XRCCTRL((*this), \"rotateX\", wxChoice);\n\trotateY = XRCCTRL((*this), \"rotateY\", wxChoice);\n\trotateZ = XRCCTRL((*this), \"rotateZ\", wxChoice);\n\n\tmeshesList = XRCCTRL((*this), \"meshesList\", wxListCtrl);\n\n\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, (*this), \"FBXImport\", \"cbInvertU\");\n\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, (*this), \"FBXImport\", \"cbInvertV\");\n\tConfigDialogUtil::LoadDialogTextFloat(OutfitStudioConfig, (*this), \"FBXImport\", \"scale\");\n\tConfigDialogUtil::LoadDialogChoiceIndex(OutfitStudioConfig, (*this), \"FBXImport\", \"rotateX\");\n\tConfigDialogUtil::LoadDialogChoiceIndex(OutfitStudioConfig, (*this), \"FBXImport\", \"rotateY\");\n\tConfigDialogUtil::LoadDialogChoiceIndex(OutfitStudioConfig, (*this), \"FBXImport\", \"rotateZ\");\n\n\txrc->AttachUnknownControl(\"glView\", CreateCanvas(), this);\n#ifdef _WINDOWS\n\tcanvas->MSWDisableComposited(); // Fix stuttering from composited flag?\n#endif\n}\n\nFBXImportDialog::~FBXImportDialog() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ImportDialog.xrc\");\n}\n\nvoid FBXImportDialog::OnShown() {\n\tGLDialog::OnShown();\n\n\tbool result = fbxw.ImportScene(fileName);\n\tif (result) {\n\t\tstd::vector<std::string> shapes;\n\t\tfbxw.GetShapeNames(shapes);\n\n\t\tfor (auto& s : shapes) {\n\t\t\tFBXShape* fbxShape = fbxw.GetShape(s);\n\n\t\t\tsize_t vertCount = fbxShape->verts.size();\n\t\t\tsize_t triCount = fbxShape->tris.size();\n\n\t\t\tauto m = new Mesh();\n\t\t\tm->nVerts = static_cast<int>(vertCount);\n\t\t\tm->nTris = static_cast<int>(triCount);\n\n\t\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->norms = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->tangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->bitangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->texcoord = std::make_unique<Vector2[]>(m->nVerts);\n\t\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->verts[v] = Mesh::TransformPosNifToMesh(fbxShape->verts[v]);\n\n\t\t\tfor (int t = 0; t < m->nTris; t++)\n\t\t\t\tm->tris[t] = fbxShape->tris[t];\n\n\t\t\tif (vertCount == fbxShape->uvs.size())\n\t\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\t\tm->texcoord[v] = fbxShape->uvs[v];\n\n\t\t\tif (vertCount == fbxShape->normals.size()) {\n\t\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\t\tm->norms[v] = Mesh::TransformDirNifToMesh(fbxShape->normals[v]);\n\t\t\t}\n\t\t\telse\n\t\t\t\tm->SmoothNormals();\n\n\t\t\tm->shapeName = fbxShape->name;\n\t\t\tm->rendermode = Mesh::RenderMode::Normal;\n\t\t\tm->doublesided = true;\n\t\t\tm->color = Vector3(0.25f, 0.25f, 0.25f);\n\t\t\tm->textured = true;\n\n\t\t\tstd::vector<std::string> textureFiles{Config[\"AppDir\"] + \"/res/images/NoImg.png\"};\n\t\t\tm->material = GetSurface().AddMaterial(textureFiles, Config[\"AppDir\"] + \"/res/shaders/default.vert\", Config[\"AppDir\"] + \"/res/shaders/default.frag\");\n\n\t\t\tm->CalcTangentSpace();\n\t\t\tm->CreateBuffers();\n\t\t\tGetSurface().UpdateShaders(m);\n\t\t\tGetSurface().AddMesh(m);\n\n\t\t\tlong itemId = meshesList->InsertItem(meshesList->GetItemCount(), wxString::FromUTF8(m->shapeName));\n\n\t\t\twxListItem colName{};\n\t\t\tcolName.SetId(itemId);\n\t\t\tcolName.SetColumn(0);\n\t\t\tcolName.SetText(wxString::FromUTF8(m->shapeName));\n\t\t\tmeshesList->SetItem(colName);\n\n\t\t\twxListItem colVertCount{};\n\t\t\tcolVertCount.SetId(itemId);\n\t\t\tcolVertCount.SetColumn(1);\n\t\t\tcolVertCount.SetText(wxString::Format(\"%zu\", vertCount));\n\t\t\tmeshesList->SetItem(colVertCount);\n\n\t\t\twxListItem colTriCount{};\n\t\t\tcolTriCount.SetId(itemId);\n\t\t\tcolTriCount.SetColumn(2);\n\t\t\tcolTriCount.SetText(wxString::Format(\"%zu\", triCount));\n\t\t\tmeshesList->SetItem(colTriCount);\n\n\t\t\twxListItem colInfo{};\n\t\t\tcolInfo.SetId(itemId);\n\t\t\tcolInfo.SetColumn(3);\n\n\t\t\tif (vertexLimit > 0 && static_cast<size_t>(m->nVerts) > vertexLimit) {\n\t\t\t\tcolInfo.SetText(_(\"The shape has reached the vertex count limit.\"));\n\t\t\t\tmeshesList->SetItemTextColour(itemId, wxColour(\"red\"));\n\t\t\t}\n\t\t\telse if (triangleLimit > 0 && static_cast<size_t>(m->nTris) > triangleLimit) {\n\t\t\t\tcolInfo.SetText(_(\"The shape has reached the triangle count limit.\"));\n\t\t\t\tmeshesList->SetItemTextColour(itemId, wxColour(\"red\"));\n\t\t\t}\n\t\t}\n\n\t\tUpdateVertexPositions();\n\t\tUpdateTextureCoords();\n\t}\n}\n\nvoid FBXImportDialog::UpdateVertexPositions() {\n\tif (!scale || !rotateX || !rotateY || !rotateZ)\n\t\treturn;\n\n\tMatrix4 mat;\n\n\tfloat scaleValue = std::atof(scale->GetValue().c_str());\n\tmat.PushScale(scaleValue, scaleValue, scaleValue);\n\n\tint rotateXSel = rotateX->GetSelection();\n\tint rotateYSel = rotateY->GetSelection();\n\tint rotateZSel = rotateZ->GetSelection();\n\n\tfloat rotateXDeg = 0.0f;\n\tfloat rotateYDeg = 0.0f;\n\tfloat rotateZDeg = 0.0f;\n\n\tswitch (rotateXSel) {\n\t\tcase 1: rotateXDeg = 90.0f; break;\n\t\tcase 2: rotateXDeg = 180.0f; break;\n\t\tcase 3: rotateXDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateYSel) {\n\t\tcase 1: rotateYDeg = 90.0f; break;\n\t\tcase 2: rotateYDeg = 180.0f; break;\n\t\tcase 3: rotateYDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateZSel) {\n\t\tcase 1: rotateZDeg = 90.0f; break;\n\t\tcase 2: rotateZDeg = 180.0f; break;\n\t\tcase 3: rotateZDeg = 270.0f; break;\n\t}\n\n\tmat.PushRotate(rotateXDeg * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmat.PushRotate(rotateYDeg * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmat.PushRotate(rotateZDeg * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tMatrix4 matRot;\n\tmatRot.PushRotate(rotateXDeg * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmatRot.PushRotate(rotateYDeg * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmatRot.PushRotate(rotateZDeg * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tstd::vector<std::string> shapes;\n\tfbxw.GetShapeNames(shapes);\n\n\tfor (auto& s : shapes) {\n\t\tFBXShape* fbxShape = fbxw.GetShape(s);\n\n\t\tauto m = GetSurface().GetMesh(fbxShape->name);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tint vertCount = static_cast<int>(fbxShape->verts.size());\n\t\tif (vertCount != m->nVerts)\n\t\t\tcontinue;\n\n\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\tm->verts[v] = Mesh::TransformPosNifToMesh(mat * fbxShape->verts[v]);\n\n\t\tm->QueueUpdate(Mesh::UpdateType::Position);\n\n\t\tint normCount = static_cast<int>(fbxShape->normals.size());\n\t\tif (normCount == m->nVerts) {\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->norms[v] = Mesh::TransformDirNifToMesh(matRot * fbxShape->normals[v]);\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Normals);\n\t\t\tm->CalcTangentSpace();\n\t\t}\n\t}\n\n\tRender();\n}\n\nvoid FBXImportDialog::UpdateTextureCoords() {\n\tif (!cbInvertU || !cbInvertV)\n\t\treturn;\n\n\tstd::vector<std::string> shapes;\n\tfbxw.GetShapeNames(shapes);\n\n\tfor (auto& s : shapes) {\n\t\tFBXShape* fbxShape = fbxw.GetShape(s);\n\n\t\tauto m = GetSurface().GetMesh(fbxShape->name);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tint uvCount = static_cast<int>(fbxShape->uvs.size());\n\t\tif (uvCount != m->nVerts)\n\t\t\tcontinue;\n\n\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\tm->texcoord[v] = fbxShape->uvs[v];\n\n\t\tif (cbInvertU->IsChecked())\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->texcoord[v].u = 1.0f - m->texcoord[v].u;\n\n\t\tif (cbInvertV->IsChecked())\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->texcoord[v].v = 1.0f - m->texcoord[v].v;\n\n\t\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\t}\n\n\tRender();\n}\n\nvoid FBXImportDialog::UpdateItemSelection() {\n\tif (!meshesList)\n\t\treturn;\n\n\tfor (int item = 0; item < meshesList->GetItemCount(); item++) {\n\t\tstd::string name{meshesList->GetItemText(item).ToUTF8()};\n\n\t\tauto m = GetSurface().GetMesh(name);\n\t\tif (m) {\n\t\t\tif (meshesList->GetItemState(item, wxLIST_STATE_SELECTED) == wxLIST_STATE_SELECTED)\n\t\t\t\tm->color = Vector3(0.1f, 0.25f, 0.1f);\n\t\t\telse\n\t\t\t\tm->color = Vector3(0.25f, 0.25f, 0.25f);\n\t\t}\n\t}\n\n\tRender();\n}\n\nvoid FBXImportDialog::DeleteItemSelection() {\n\tif (!meshesList)\n\t\treturn;\n\n\tfor (int item = meshesList->GetItemCount() - 1; item >= 0; item--) {\n\t\tif (meshesList->GetItemState(item, wxLIST_STATE_SELECTED) == wxLIST_STATE_SELECTED) {\n\t\t\tstd::string name{meshesList->GetItemText(item).ToUTF8()};\n\t\t\tGetSurface().DeleteMesh(name);\n\t\t\tmeshesList->DeleteItem(item);\n\t\t}\n\t}\n\n\tRender();\n}\n\nvoid FBXImportDialog::OnInvertU(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateTextureCoords();\n}\n\nvoid FBXImportDialog::OnInvertV(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateTextureCoords();\n}\n\nvoid FBXImportDialog::OnScale(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid FBXImportDialog::OnRotateX(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid FBXImportDialog::OnRotateY(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid FBXImportDialog::OnRotateZ(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid FBXImportDialog::OnItemSelected(wxListEvent& WXUNUSED(event)) {\n\tUpdateItemSelection();\n}\n\nvoid FBXImportDialog::OnItemDeselected(wxListEvent& WXUNUSED(event)) {\n\tUpdateItemSelection();\n}\n\nvoid FBXImportDialog::OnListKeyDown(wxListEvent& event) {\n\tif (event.GetKeyCode() == wxKeyCode::WXK_DELETE)\n\t\tDeleteItemSelection();\n}\n\nvoid FBXImportDialog::OnImport(wxCommandEvent& WXUNUSED(event)) {\n\toptions.InvertU = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, (*this), \"FBXImport\", \"cbInvertU\");\n\toptions.InvertV = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, (*this), \"FBXImport\", \"cbInvertV\");\n\toptions.Scale = ConfigDialogUtil::SetFloatFromDialogTextControl(OutfitStudioConfig, (*this), \"FBXImport\", \"scale\");\n\n\tint rotateXSel = ConfigDialogUtil::SetIntegerFromDialogChoice(OutfitStudioConfig, (*this), \"FBXImport\", \"rotateX\");\n\tint rotateYSel = ConfigDialogUtil::SetIntegerFromDialogChoice(OutfitStudioConfig, (*this), \"FBXImport\", \"rotateY\");\n\tint rotateZSel = ConfigDialogUtil::SetIntegerFromDialogChoice(OutfitStudioConfig, (*this), \"FBXImport\", \"rotateZ\");\n\n\tfloat rotateXDeg = 0.0f;\n\tfloat rotateYDeg = 0.0f;\n\tfloat rotateZDeg = 0.0f;\n\n\tswitch (rotateXSel) {\n\t\tcase 1: rotateXDeg = 90.0f; break;\n\t\tcase 2: rotateXDeg = 180.0f; break;\n\t\tcase 3: rotateXDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateYSel) {\n\t\tcase 1: rotateYDeg = 90.0f; break;\n\t\tcase 2: rotateYDeg = 180.0f; break;\n\t\tcase 3: rotateYDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateZSel) {\n\t\tcase 1: rotateZDeg = 90.0f; break;\n\t\tcase 2: rotateZDeg = 180.0f; break;\n\t\tcase 3: rotateZDeg = 270.0f; break;\n\t}\n\n\toptions.RotateX = rotateXDeg;\n\toptions.RotateY = rotateYDeg;\n\toptions.RotateZ = rotateZDeg;\n\toptions.ImportAll = false;\n\n\tfor (int item = 0; item < meshesList->GetItemCount(); item++) {\n\t\tstd::string name{meshesList->GetItemText(item).ToUTF8()};\n\t\toptions.ImportShapes.insert(name);\n\t}\n\n\tEndModal(wxID_OK);\n}\n\n#endif\n"
  },
  {
    "path": "src/program/FBXImportDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#ifdef USE_FBXSDK\n\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n#include <wx/listctrl.h>\n\n#include \"../render/GLDialog.h\"\n#include \"../render/GLSurface.h\"\n#include \"../files/FBXWrangler.h\"\n\nclass FBXImportDialog : public GLDialog {\npublic:\n\tFBXImportDialog(wxWindow* parent, const std::string& fileName, size_t vertexLimit = 0, size_t triangleLimit = 0, const wxString& warningLabel = wxString());\n\t~FBXImportDialog();\n\n\tvirtual void OnShown() override;\n\tvoid OnImport(wxCommandEvent& event);\n\n\tFBXImportOptions GetOptions() { return options; }\n\n\twxDECLARE_EVENT_TABLE();\n\nprivate:\n\tstd::string fileName;\n\tsize_t vertexLimit = 0;\n\tsize_t triangleLimit = 0;\n\n\tFBXWrangler fbxw;\n\n\tFBXImportOptions options;\n\twxStaticText* lbWarning;\n\twxCheckBox* cbInvertU = nullptr;\n\twxCheckBox* cbInvertV = nullptr;\n\twxTextCtrl* scale = nullptr;\n\twxChoice* rotateX = nullptr;\n\twxChoice* rotateY = nullptr;\n\twxChoice* rotateZ = nullptr;\n\twxListCtrl* meshesList = nullptr;\n\n\tvoid UpdateVertexPositions();\n\tvoid UpdateTextureCoords();\n\tvoid UpdateItemSelection();\n\tvoid DeleteItemSelection();\n\tvoid OnInvertU(wxCommandEvent& event);\n\tvoid OnInvertV(wxCommandEvent& event);\n\tvoid OnScale(wxCommandEvent& event);\n\tvoid OnRotateX(wxCommandEvent& event);\n\tvoid OnRotateY(wxCommandEvent& event);\n\tvoid OnRotateZ(wxCommandEvent& event);\n\tvoid OnItemSelected(wxListEvent& event);\n\tvoid OnItemDeselected(wxListEvent& event);\n\tvoid OnListKeyDown(wxListEvent& event);\n};\n\n#endif\n"
  },
  {
    "path": "src/program/FBXImportOptions.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <set>\n\n"
  },
  {
    "path": "src/program/GroupManager.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GroupManager.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <wx/srchctrl.h>\n\nextern ConfigurationManager Config;\n\nwxBEGIN_EVENT_TABLE(GroupManager, wxDialog)\n\tEVT_FILEPICKER_CHANGED(XRCID(\"fpGroupXML\"), GroupManager::OnLoadGroup)\n\tEVT_LISTBOX(XRCID(\"listGroups\"), GroupManager::OnSelectGroup)\n\tEVT_LISTBOX_DCLICK(XRCID(\"listGroups\"), GroupManager::OnDblClickGroup)\n\tEVT_LISTBOX_DCLICK(XRCID(\"listMembers\"), GroupManager::OnDblClickMember)\n\tEVT_LISTBOX_DCLICK(XRCID(\"listOutfits\"), GroupManager::OnDblClickOutfit)\n\tEVT_BUTTON(XRCID(\"btAddGroup\"), GroupManager::OnAddGroup)\n\tEVT_BUTTON(XRCID(\"btRemoveGroup\"), GroupManager::OnRemoveGroup)\n\tEVT_BUTTON(XRCID(\"btSave\"), GroupManager::OnSaveGroup)\n\tEVT_BUTTON(XRCID(\"btSaveAs\"), GroupManager::OnSaveGroupAs)\n\tEVT_BUTTON(XRCID(\"btRemoveMember\"), GroupManager::OnRemoveMember)\n\tEVT_BUTTON(XRCID(\"btAddMember\"), GroupManager::OnAddMember)\n\tEVT_TEXT_ENTER(XRCID(\"outfitFilter\"), GroupManager::OnFilterChanged)\n\tEVT_TEXT(XRCID(\"outfitFilter\"), GroupManager::OnFilterChanged)\n\tEVT_BUTTON(wxID_OK, GroupManager::OnCloseButton)\n\tEVT_CLOSE(GroupManager::OnClose)\nwxEND_EVENT_TABLE()\n\nGroupManager::GroupManager(wxWindow* parent, std::vector<std::string> outfits)\n\t: allOutfits(std::move(outfits)) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/GroupManager.xrc\");\n\txrc->LoadDialog(this, parent, \"dlgGroupManager\");\n\n\tSetSize(800, 500);\n\tSetDoubleBuffered(true);\n\tCenterOnParent();\n\n\tXRCCTRL(*this, \"fpGroupXML\", wxFilePickerCtrl)->SetInitialDirectory(wxString::FromUTF8(GetProjectPath()) + \"/SliderGroups\");\n\tlistGroups = XRCCTRL(*this, \"listGroups\", wxListBox);\n\tgroupName = XRCCTRL(*this, \"groupName\", wxTextCtrl);\n\tbtAddGroup = XRCCTRL(*this, \"btAddGroup\", wxButton);\n\tbtRemoveGroup = XRCCTRL(*this, \"btRemoveGroup\", wxButton);\n\tbtSave = XRCCTRL(*this, \"btSave\", wxButton);\n\tbtSaveAs = XRCCTRL(*this, \"btSaveAs\", wxButton);\n\tbtRemoveMember = XRCCTRL(*this, \"btRemoveMember\", wxButton);\n\tbtAddMember = XRCCTRL(*this, \"btAddMember\", wxButton);\n\tlistMembers = XRCCTRL(*this, \"listMembers\", wxListBox);\n\tlistOutfits = XRCCTRL(*this, \"listOutfits\", wxListBox);\n\n\tauto search = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, FromDIP(wxSize(200, -1)), wxTE_PROCESS_ENTER);\n\tsearch->ShowSearchButton(true);\n\tsearch->SetDescriptiveText(\"Outfit Filter\");\n\tsearch->SetToolTip(\"Filter outfit list by name\");\n\n\txrc->AttachUnknownControl(\"outfitFilter\", search, this);\n\n\tRefreshUI();\n}\n\nGroupManager::~GroupManager() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/GroupManager.xrc\");\n}\n\nstd::string GroupManager::GetProjectPath() const {\n\tstd::string res = Config[\"ProjectPath\"];\n\treturn res.empty() ? Config[\"AppDir\"] : res;\n}\n\nvoid GroupManager::RefreshUI(const bool clearGroups) {\n\tlistMembers->Clear();\n\n\tbtSave->Enable(dirty & !fileName.empty());\n\n\tstd::string selectedGroup;\n\tif (clearGroups) {\n\t\t// Add groups to list\n\t\tlistGroups->Clear();\n\t\tfor (auto& group : groupMembers)\n\t\t\tlistGroups->Append(wxString::FromUTF8(group.first));\n\t}\n\telse {\n\t\t// Get group selection if existing\n\t\tselectedGroup = listGroups->GetStringSelection().ToUTF8();\n\t}\n\n\t// Add members of selected group to list\n\tbool groupSelected = !selectedGroup.empty();\n\tif (groupSelected)\n\t\tfor (auto& member : groupMembers[selectedGroup])\n\t\t\tlistMembers->Append(wxString::FromUTF8(member));\n\n\tauto outfitFilter = XRCCTRL(*this, \"outfitFilter\", wxSearchCtrl);\n\tstd::string filter{outfitFilter->GetValue().ToUTF8()};\n\tDoFilterOutfits(filter);\n\n\tlistMembers->Enable(groupSelected);\n\tlistOutfits->Enable(groupSelected);\n\toutfitFilter->Enable(groupSelected);\n\n\tbtRemoveMember->Enable(groupSelected);\n\tbtAddMember->Enable(groupSelected);\n}\n\nbool GroupManager::ChooseFile() {\n\twxFileDialog file(this,\n\t\t\t\t\t  \"Saving group XML file...\",\n\t\t\t\t\t  wxString::FromUTF8(GetProjectPath()) + \"/SliderGroups\",\n\t\t\t\t\t  fileName,\n\t\t\t\t\t  \"Group Files (*.xml)|*.xml\",\n\t\t\t\t\t  wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\tif (file.ShowModal() != wxID_OK)\n\t\treturn false;\n\n\tfileName = file.GetPath();\n\treturn true;\n}\n\nvoid GroupManager::SaveGroup() {\n\tSliderSetGroupFile groupFile;\n\tgroupFile.New(fileName.ToUTF8().data());\n\tfor (auto& grp : groupMembers) {\n\t\tSliderSetGroup group;\n\t\tgroup.SetName(grp.first);\n\t\tgroup.AddMembers(grp.second);\n\t\tgroupFile.UpdateGroup(group);\n\t}\n\tgroupFile.Save();\n\n\tdirty = false;\n\tbtSave->Enable(dirty & !fileName.empty());\n}\n\nvoid GroupManager::DoRenameGroup() {\n\t// Rename the selected group\n\tstd::string selectedGroup{listGroups->GetStringSelection().ToUTF8()};\n\tif (!selectedGroup.empty()) {\n\t\tstd::string newGroupName;\n\n\t\tdo {\n\t\t\tstd::string result{wxGetTextFromUser(_(\"Please enter a new unique name for the group.\"), _(\"Rename Group\")).ToUTF8()};\n\t\t\tif (result.empty())\n\t\t\t\treturn;\n\n\t\t\tnewGroupName = std::move(result);\n\t\t} while (groupMembers.find(newGroupName) != groupMembers.end());\n\n\t\tauto it = groupMembers.find(selectedGroup);\n\t\tif (it != groupMembers.end()) {\n\t\t\tstd::swap(groupMembers[newGroupName], it->second);\n\t\t\tgroupMembers.erase(it);\n\t\t}\n\n\t\tlistGroups->SetString(listGroups->GetSelection(), wxString::FromUTF8(newGroupName));\n\n\t\tdirty = true;\n\t\tRefreshUI();\n\t}\n}\n\nvoid GroupManager::DoRemoveMembers() {\n\twxArrayInt selections;\n\tlistMembers->GetSelections(selections);\n\n\t// Find and remove member from selected group\n\tstd::string selectedGroup{listGroups->GetStringSelection().ToUTF8()};\n\tif (!selectedGroup.empty()) {\n\t\tfor (auto& sel : selections) {\n\t\t\tstd::string member{listMembers->GetString(sel).ToUTF8()};\n\t\t\tauto it = find(groupMembers[selectedGroup].begin(), groupMembers[selectedGroup].end(), member);\n\t\t\tif (it != groupMembers[selectedGroup].end())\n\t\t\t\tgroupMembers[selectedGroup].erase(it);\n\t\t}\n\t}\n\n\tdirty = true;\n\tselections.Clear();\n\tRefreshUI();\n}\n\nvoid GroupManager::DoAddMembers() {\n\twxArrayInt selections;\n\tlistOutfits->GetSelections(selections);\n\n\t// Add member to selected group\n\tstd::string selectedGroup{listGroups->GetStringSelection().ToUTF8()};\n\tif (!selectedGroup.empty()) {\n\t\tfor (auto& sel : selections) {\n\t\t\tstd::string member{listOutfits->GetString(sel).ToUTF8()};\n\t\t\tgroupMembers[selectedGroup].push_back(member);\n\t\t}\n\t}\n\n\tdirty = true;\n\tselections.Clear();\n\tRefreshUI();\n}\n\nvoid GroupManager::DoFilterOutfits(const std::string& filter) {\n\twxString filterString = wxString::FromUTF8(filter);\n\tfilterString.MakeLower();\n\n\tlistOutfits->Clear();\n\n\t// Add outfits that are no members to list\n\tfor (auto& outfit : allOutfits) {\n\t\tif (listMembers->FindString(outfit) == wxNOT_FOUND) {\n\t\t\twxString outfitName = wxString::FromUTF8(outfit);\n\n\t\t\t// Filter outfit by name\n\t\t\tif (outfitName.Lower().Contains(filterString))\n\t\t\t\tlistOutfits->Append(outfitName);\n\t\t}\n\t}\n}\n\nvoid GroupManager::OnLoadGroup(wxFileDirPickerEvent& event) {\n\t// Load group file\n\tSliderSetGroupFile groupFile(event.GetPath().ToUTF8().data());\n\tif (groupFile.fail())\n\t\treturn;\n\n\tgroupMembers.clear();\n\tbtRemoveGroup->Enable();\n\n\t// Fill group member map\n\tstd::vector<std::string> groupNames;\n\tgroupFile.GetGroupNames(groupNames, true, true);\n\tfor (auto& grp : groupNames) {\n\t\tSliderSetGroup group;\n\t\tif (groupFile.GetGroup(grp, group))\n\t\t\treturn;\n\n\t\tstd::vector<std::string> members;\n\t\tgroup.GetMembers(members);\n\t\tgroupMembers[grp] = members;\n\t}\n\n\twxFileName fileInfo(event.GetPath());\n\tfileName = fileInfo.GetFullPath();\n\tRefreshUI(true);\n}\n\nvoid GroupManager::OnSaveGroup(wxCommandEvent& WXUNUSED(event)) {\n\tSaveGroup();\n}\n\nvoid GroupManager::OnSaveGroupAs(wxCommandEvent& WXUNUSED(event)) {\n\tif (ChooseFile())\n\t\tSaveGroup();\n}\n\nvoid GroupManager::OnSelectGroup(wxCommandEvent& WXUNUSED(event)) {\n\tRefreshUI();\n}\n\nvoid GroupManager::OnDblClickGroup(wxCommandEvent& WXUNUSED(event)) {\n\tDoRenameGroup();\n}\n\nvoid GroupManager::OnDblClickMember(wxCommandEvent& WXUNUSED(event)) {\n\tDoRemoveMembers();\n}\n\nvoid GroupManager::OnDblClickOutfit(wxCommandEvent& WXUNUSED(event)) {\n\tDoAddMembers();\n}\n\nvoid GroupManager::OnAddGroup(wxCommandEvent& WXUNUSED(event)) {\n\twxString name = groupName->GetValue().Trim();\n\tif (name.empty())\n\t\treturn;\n\n\tgroupName->Clear();\n\n\t// Already exists\n\tauto it = groupMembers.find(name.ToUTF8().data());\n\tif (it != groupMembers.end())\n\t\treturn;\n\n\t// Create empty group entry\n\tgroupMembers[name.ToUTF8().data()] = std::vector<std::string>();\n\tlistGroups->Append(name);\n\n\tdirty = true;\n\tbtSave->Enable(dirty & !fileName.empty());\n}\n\nvoid GroupManager::OnRemoveGroup(wxCommandEvent& WXUNUSED(event)) {\n\tint id = listGroups->GetSelection();\n\tif (id == wxNOT_FOUND)\n\t\treturn;\n\n\t// Remove empty group entry\n\twxString group = listGroups->GetString(id);\n\tgroupMembers.erase(group.ToUTF8().data());\n\n\tdirty = true;\n\tRefreshUI(true);\n}\n\nvoid GroupManager::OnRemoveMember(wxCommandEvent& WXUNUSED(event)) {\n\tDoRemoveMembers();\n}\n\nvoid GroupManager::OnAddMember(wxCommandEvent& WXUNUSED(event)) {\n\tDoAddMembers();\n}\n\nvoid GroupManager::OnFilterChanged(wxCommandEvent& event) {\n\tstd::string filter{event.GetString().ToUTF8()};\n\tDoFilterOutfits(filter);\n}\n\nvoid GroupManager::OnCloseButton(wxCommandEvent& WXUNUSED(event)) {\n\tClose();\n}\n\nvoid GroupManager::OnClose(wxCloseEvent& event) {\n\tif (dirty) {\n\t\tint ret = wxMessageBox(_(\"Save changes to group file?\"), _(\"Save Changes\"), wxYES_NO | wxCANCEL | wxICON_WARNING, this);\n\t\tif (ret == wxCANCEL) {\n\t\t\tevent.Veto();\n\t\t\treturn;\n\t\t}\n\t\telse if (ret == wxYES) {\n\t\t\tif (fileName.empty()) {\n\t\t\t\tif (!ChooseFile()) {\n\t\t\t\t\tevent.Veto();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tSaveGroup();\n\t\t}\n\t}\n\n\tEndModal(wxID_OK);\n}\n"
  },
  {
    "path": "src/program/GroupManager.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../components/SliderGroup.h\"\n\n#include <wx/filepicker.h>\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n\nclass GroupManager : public wxDialog {\npublic:\n\tGroupManager(wxWindow*, std::vector<std::string>);\n\t~GroupManager();\n\nprivate:\n\twxListBox* listGroups;\n\twxTextCtrl* groupName;\n\twxButton* btAddGroup;\n\twxButton* btRemoveGroup;\n\twxButton* btSave;\n\twxButton* btSaveAs;\n\twxButton* btRemoveMember;\n\twxButton* btAddMember;\n\twxListBox* listMembers;\n\twxListBox* listOutfits;\n\n\tbool dirty = false;\n\twxString fileName;\n\tstd::map<std::string, std::vector<std::string>> groupMembers;\n\tstd::vector<std::string> allOutfits;\n\n\tstd::string GetProjectPath() const;\n\n\tvoid RefreshUI(const bool = false);\n\tbool ChooseFile();\n\tvoid SaveGroup();\n\n\tvoid DoRenameGroup();\n\tvoid DoRemoveMembers();\n\tvoid DoAddMembers();\n\tvoid DoFilterOutfits(const std::string& filter = \"\");\n\n\tvoid OnLoadGroup(wxFileDirPickerEvent&);\n\tvoid OnSaveGroup(wxCommandEvent&);\n\tvoid OnSaveGroupAs(wxCommandEvent&);\n\tvoid OnSelectGroup(wxCommandEvent&);\n\tvoid OnDblClickGroup(wxCommandEvent&);\n\tvoid OnDblClickMember(wxCommandEvent&);\n\tvoid OnDblClickOutfit(wxCommandEvent&);\n\tvoid OnAddGroup(wxCommandEvent&);\n\tvoid OnRemoveGroup(wxCommandEvent&);\n\tvoid OnRemoveMember(wxCommandEvent&);\n\tvoid OnAddMember(wxCommandEvent&);\n\tvoid OnFilterChanged(wxCommandEvent&);\n\tvoid OnCloseButton(wxCommandEvent&);\n\tvoid OnClose(wxCloseEvent&);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/NormalsGenDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"NormalsGenDialog.h\"\n#include \"../ui/PreviewPanel.h\"\n\nNormalsGenDialog::NormalsGenDialog(wxWindow* parent, std::vector<NormalGenLayer>& inLayersRef)\n\t: wxNormalsGenDlg(parent)\n\t, refNormalGenLayers(inLayersRef) {\n\tpgLayers->Bind(wxEVT_PG_SELECTED, &NormalsGenDialog::doPropSelected, this);\n\n\tpgLayers->SetSortFunction([](wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* p1, wxPGProperty* p2) -> int {\n\t\tif (p1->GetClientData() >= p2->GetClientData())\n\t\t\treturn 1;\n\t\treturn 0;\n\t});\n\n\tPopulateLayers();\n\n\tbtnDeleteLayer->Disable();\n\tbtnMoveUp->Disable();\n}\n\nvoid NormalsGenDialog::doShowPresetContext(wxCommandEvent& WXUNUSED(event)) {\n\tPopupMenu(presetContext);\n}\n\nvoid NormalsGenDialog::doPropertyChanged(wxPropertyGridEvent& WXUNUSED(event)) {\n\t// Just clear out the whole layers list and rebuild it based on current property grid values.\n\trefNormalGenLayers.clear();\n\n\tNormalGenLayer ngl;\n\twxColour clr;\n\tint propindex = 0;\n\tfor (wxPropertyGridIterator it = pgLayers->GetIterator(wxPG_ITERATE_ALL); !it.AtEnd(); ++it) {\n\t\tif (it.GetProperty()->IsCategory()) {\n\t\t\tif (!ngl.layerName.empty()) {\n\t\t\t\t// layer name not being empty means we've got layer info already, so push the layer onto the list.\n\t\t\t\trefNormalGenLayers.push_back(ngl);\n\t\t\t}\n\t\t\tngl.layerName = it.GetProperty()->GetLabel();\n\t\t\tpropindex = 0;\n\t\t}\n\t\telse {\n\t\t\t// pull values based on position in the list.\n\t\t\tswitch (propindex) {\n\t\t\t\tcase 0:\n\t\t\t\t\tngl.sourceFileName = it.GetProperty()->GetValueAsString();\n\t\t\t\t\tif (ngl.sourceFileName == \"0\")\n\t\t\t\t\t\tngl.sourceFileName.clear();\n\n\t\t\t\t\tbreak;\n\t\t\t\tcase 1:\n\t\t\t\t\tif (ngl.layerName == \"Background\") {\n\t\t\t\t\t\t//background layer has fillcolor here.\n\t\t\t\t\t\tclr << it.GetProperty()->GetValue();\n\t\t\t\t\t\tngl.fillColor[0] = clr.Red();\n\t\t\t\t\t\tngl.fillColor[1] = clr.Green();\n\t\t\t\t\t\tngl.fillColor[2] = clr.Blue();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tngl.isTangentSpace = it.GetProperty()->GetValue().GetBool();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tif (ngl.layerName == \"Background\") {\n\t\t\t\t\t\t//background layer has resolution here\n\t\t\t\t\t\tngl.resolution = std::stol(it.GetProperty()->GetValueAsString().ToStdString());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tngl.maskFileName = it.GetProperty()->GetValueAsString();\n\t\t\t\t\t\tif (ngl.maskFileName == \"0\")\n\t\t\t\t\t\t\tngl.maskFileName.clear();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 3: ngl.xOffset = it.GetProperty()->GetValue().GetInteger(); break;\n\t\t\t\tcase 4: ngl.yOffset = it.GetProperty()->GetValue().GetInteger(); break;\n\t\t\t\tcase 5: ngl.scaleToResolution = it.GetProperty()->GetValue().GetBool(); break;\n\t\t\t}\n\t\t\tpropindex++;\n\t\t}\n\t}\n}\n\nvoid NormalsGenDialog::doAddLayer(wxCommandEvent& WXUNUSED(event)) {\n\tNormalGenLayer blankLayer;\n\n\twxTextEntryDialog entry(this, _(\"Enter a name for the new layer.\"), _(\"Name new layer\"), nextLayerName());\n\tif (entry.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tblankLayer.layerName = entry.GetValue();\n\n\twxPGProperty* p = pgLayers->GetSelectedProperty();\n\tif (!p) {\n\t\taddLayer(blankLayer);\n\t\treturn;\n\t}\n\n\twxPropertyGridIterator it;\n\tfor (it = pgLayers->GetIterator(wxPG_ITERATE_CATEGORIES, p); !it.AtEnd(); ++it) {\n\t\tif (*it == p)\n\t\t\tcontinue;\n\t\tif ((*it)->GetName() != \"Background\") {\n\t\t\taddLayer(blankLayer, *it);\n\t\t\treturn;\n\t\t}\n\t}\n\n\taddLayer(blankLayer);\n}\n\nvoid NormalsGenDialog::doMoveUpLayer(wxCommandEvent& WXUNUSED(event)) {\n\twxPGProperty* prev = nullptr;\n\twxPGProperty* me = nullptr;\n\n\twxPGProperty* s = pgLayers->GetSelectedProperty();\n\tif (!s || !s->IsCategory() || s->GetName() == \"Background\")\n\t\treturn;\n\n\tintptr_t n = 1;\n\tfor (auto it = pgLayers->GetIterator(wxPG_ITERATE_CATEGORIES); !it.AtEnd(); ++it) {\n\t\twxPGProperty* p = it.GetProperty();\n\t\tp->SetClientData(reinterpret_cast<void*>(n++));\n\t\tif (p == s) {\n\t\t\tme = p;\n\t\t}\n\t\telse if (!me && p && p->GetName() != \"Background\") {\n\t\t\tprev = p;\n\t\t}\n\t}\n\n\tif (!me || !prev)\n\t\treturn;\n\n\tintptr_t t = reinterpret_cast<intptr_t>(me->GetClientData());\n\tme->SetClientData(prev->GetClientData());\n\tprev->SetClientData(reinterpret_cast<void*>(t));\n\n\tpgLayers->Sort();\n\tpgLayers->Refresh();\n}\n\nvoid NormalsGenDialog::doDeleteLayer(wxCommandEvent& WXUNUSED(event)) {\n\twxPGProperty* p = pgLayers->GetSelectedProperty();\n\tif (p && p->IsCategory() && p->GetName() != \"Background\") {\n\t\tp->DeleteChildren();\n\t\tpgLayers->DeleteProperty(p);\n\t}\n}\n\nvoid NormalsGenDialog::OnUseBackgroundLayerCheck(wxCommandEvent& event) {\n\tif (event.IsChecked())\n\t\tfpOutputFile->Disable();\n\telse\n\t\tfpOutputFile->Enable();\n}\n\nvoid NormalsGenDialog::doSetOutputFileName(wxFileDirPickerEvent& WXUNUSED(event)) {\n\t// TODO: Implement doSetOutputFileName\n}\n\nvoid NormalsGenDialog::doPreviewNormalMap(wxCommandEvent& WXUNUSED(event)) {\n\tPreviewPanel* preview = dynamic_cast<PreviewPanel*>(GetParent());\n\tif (!preview)\n\t\treturn;\n\n\t// no file name specified so it only renders a preview.\n\tpreview->RenderNormalMap();\n}\n\nvoid NormalsGenDialog::doGenerateNormalMap(wxCommandEvent& WXUNUSED(event)) {\n\tPreviewPanel* preview = dynamic_cast<PreviewPanel*>(GetParent());\n\tif (!preview)\n\t\treturn;\n\n\twxFileName outfile;\n\tif (cbSaveToBGLayerFile->IsChecked())\n\t\toutfile = refNormalGenLayers[0].sourceFileName;\n\telse\n\t\toutfile = fpOutputFile->GetPath();\n\n\t// forcing dds extension for final output.\n\toutfile.SetExt(\"dds\");\n\n\tif (cbBackup->IsChecked() && wxFileExists(outfile.GetFullPath())) {\n\t\twxFileName bak(outfile);\n\t\tbak.SetExt(\"bak\");\n\t\twxCopyFile(outfile.GetFullPath(), bak.GetFullPath(), true);\n\t}\n\n\t// rendering to lossless png (SOIL2 wants to run dxt1 compression on dds which loses lots of quality).\n\tpreview->RenderNormalMap(\"ngtemp.png\");\n\n\tif (cbCompress->IsChecked()) {\n\t\t// compression using texconv .. pretty slow, but uses direct compute to make it a bit faster.\n\t\twxBusyCursor compressWait;\n\t\twxExecute(\"texconv.exe -f BC7_UNORM ngtemp.png -o \" + outfile.GetFullPath(), wxEXEC_SYNC);\n\t}\n\telse {\n\t\t// uncompressed 8bpp using texconv just because.\n\t\twxExecute(\"texconv.exe -f R8G8B8A8_UNORM ngtemp.png -o \" + outfile.GetFullPath());\n\t}\n}\n\nvoid NormalsGenDialog::doLoadPreset(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog fl(this, _(\"Choose a normals generator preset file...\"), \"NormalGen\", wxEmptyString, \"XML Files (*.xml)|*.xml\", wxFD_OPEN);\n\tif (fl.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxFileName fn(fl.GetPath());\n\n\ttinyxml2::XMLDocument doc;\n\tdoc.LoadFile(fn.GetFullPath().ToUTF8());\n\n\ttinyxml2::XMLElement* root = doc.FirstChildElement(\"NormalsGeneration\");\n\tif (root)\n\t\tNormalGenLayer::LoadFromXML(root, refNormalGenLayers);\n\n\tPopulateLayers();\n}\n\nvoid NormalsGenDialog::doSavePreset(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog fs(this, _(\"Save normals generator preset to...\"), \"NormalGen\", wxEmptyString, \"XML Files (*.xml)|*.xml\", wxFD_SAVE);\n\tif (fs.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\ttinyxml2::XMLDocument doc;\n\ttinyxml2::XMLElement* root = doc.NewElement(\"NormalsGeneration\");\n\n\twxFileName fn(fs.GetPath());\n\troot->SetAttribute(\"name\", fn.GetName().ToUTF8());\n\n\tdoc.InsertFirstChild(root);\n\n\tNormalGenLayer::SaveToXML(root, refNormalGenLayers);\n\n\tdoc.SaveFile(fn.GetFullPath().ToUTF8());\n}\n\nwxString NormalsGenDialog::nextLayerName() {\n\twxString nameStr = _(\"Layer\") + wxString::Format(\" %d\", layerCount);\n\treturn nameStr;\n}\n\nvoid NormalsGenDialog::addBGLayer(NormalGenLayer& newLayer) {\n\twxPGProperty* newProp;\n\twxArrayString resolutions;\n\tresolutions.Add(\"256\");\n\tresolutions.Add(\"512\");\n\tresolutions.Add(\"1024\");\n\tresolutions.Add(\"2048\");\n\tresolutions.Add(\"4096\");\n\n\tint selectedRes = 0;\n\tfor (int i = 0; i < static_cast<int>(resolutions.size()); i++) {\n\t\tif (resolutions[i] == std::to_string(newLayer.resolution)) {\n\t\t\tselectedRes = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tpgLayers->Append(new wxPropertyCategory(newLayer.layerName, \"Background\"));\n\n\tnewProp = pgLayers->Append(new wxImageFileProperty(_(\"Background File\"), _(\"Background File\"), newLayer.sourceFileName));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"File source for this layer.\"));\n\tnewProp = pgLayers->Append(new wxColourProperty(_(\"Color\"), _(\"Color\"), wxColour(newLayer.fillColor[0], newLayer.fillColor[1], newLayer.fillColor[2])));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"Solid background color (if file is not set).\"));\n\tnewProp = pgLayers->Append(new wxEnumProperty(_(\"Resolution\"), _(\"Resolution\"), resolutions));\n\tnewProp->SetChoiceSelection(selectedRes);\n\tpgLayers->SetPropertyHelpString(newProp, _(\"Output texture dimensions. By default all images will be scaled to fit this size.\"));\n}\n\nvoid NormalsGenDialog::addLayer(NormalGenLayer& newLayer, wxPGProperty* before) {\n\twxString internalName = nextLayerName();\n\tlayerCount++;\n\n\twxPGProperty* newCat;\n\twxPGProperty* newProp;\n\n\tif (before)\n\t\tnewCat = pgLayers->Insert(before, new wxPropertyCategory(newLayer.layerName, internalName));\n\telse\n\t\tnewCat = pgLayers->Append(new wxPropertyCategory(newLayer.layerName, internalName));\n\n\tnewProp = newCat->AppendChild(new wxImageFileProperty(_(\"File\"), internalName + \"File\", newLayer.sourceFileName));\n\tnewProp->SetAttribute(\"Wildcard\", \"PNG files (*.png)|*.png\");\n\tpgLayers->SetPropertyHelpString(newProp, _(\"File containing normals data to combine. Note this file should fit the mesh UVs.\"));\n\n\tnewProp = newCat->AppendChild(new wxBoolProperty(_(\"Is Tangent Space?\"), internalName + \"IsTangent\", newLayer.isTangentSpace));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"True if the normals data in the layer file is in tangent space, false if they are in model space (msn).\"));\n\n\tnewProp = newCat->AppendChild(new wxImageFileProperty(_(\"Mask\"), internalName + \"Mask\", newLayer.maskFileName));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"A greyscale image used to mask updates to destination image.\"));\n\n\tnewProp = newCat->AppendChild(new wxUIntProperty(_(\"X Offset\"), internalName + \"XOffset\", newLayer.xOffset));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"Offset to apply to image position.\"));\n\n\tnewProp = newCat->AppendChild(new wxUIntProperty(_(\"Y Offset\"), internalName + \"YOffset\", newLayer.yOffset));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"Offset to apply to image position.\"));\n\n\tnewProp = newCat->AppendChild(new wxBoolProperty(_(\"Scale\"), internalName + \"Scale\", newLayer.scaleToResolution));\n\tpgLayers->SetPropertyHelpString(newProp, _(\"If true, scale image to match background resolution.\"));\n}\n\nvoid NormalsGenDialog::PopulateLayers() {\n\tpgLayers->Clear();\n\tlayerCount = 1;\n\tfor (auto l : refNormalGenLayers) {\n\t\tif (l.layerName == \"Background\")\n\t\t\taddBGLayer(l);\n\t\telse\n\t\t\taddLayer(l);\n\t}\n}\n\nvoid NormalsGenDialog::SetLayersRef(std::vector<NormalGenLayer>& inLayersRef) {\n\trefNormalGenLayers = inLayersRef;\n\tPopulateLayers();\n}\n\nvoid NormalsGenDialog::doPropSelected(wxPropertyGridEvent& WXUNUSED(event)) {\n\twxPGProperty* p = pgLayers->GetSelectedProperty();\n\tif (p && p->IsCategory() && p->GetName() != \"Background\") {\n\t\tbtnDeleteLayer->Enable();\n\t\tbtnMoveUp->Enable();\n\t}\n\telse {\n\t\tbtnDeleteLayer->Disable();\n\t\tbtnMoveUp->Disable();\n\t}\n}\n"
  },
  {
    "path": "src/program/NormalsGenDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../components/NormalGenLayers.h\"\n#include \"../ui/wxNormalsGenDlg.h\"\n\nclass NormalsGenDialog : public wxNormalsGenDlg {\nprotected:\n\tvoid doShowPresetContext(wxCommandEvent& event);\n\tvoid doPropertyChanged(wxPropertyGridEvent& event);\n\tvoid doAddLayer(wxCommandEvent& event);\n\tvoid doMoveUpLayer(wxCommandEvent& event);\n\tvoid doDeleteLayer(wxCommandEvent& event);\n\tvoid OnUseBackgroundLayerCheck(wxCommandEvent& event);\n\tvoid doSetOutputFileName(wxFileDirPickerEvent& event);\n\tvoid doPreviewNormalMap(wxCommandEvent& event);\n\tvoid doGenerateNormalMap(wxCommandEvent& event);\n\tvoid doLoadPreset(wxCommandEvent& event);\n\tvoid doSavePreset(wxCommandEvent& event);\n\npublic:\n\tNormalsGenDialog(wxWindow* parent, std::vector<NormalGenLayer>& inLayersRef);\n\n\tvoid SetLayersRef(std::vector<NormalGenLayer>& inLayersRef);\n\nprotected:\n\tint layerCount = 1;\n\tstd::vector<NormalGenLayer>& refNormalGenLayers;\n\n\tvoid doPropSelected(wxPropertyGridEvent& event);\n\n\twxString nextLayerName();\n\tvoid addBGLayer(NormalGenLayer& newLayer);\n\tvoid addLayer(NormalGenLayer& newLayer, wxPGProperty* before = nullptr);\n\n\tvoid PopulateLayers();\n};\n"
  },
  {
    "path": "src/program/OBJImportOptions.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <set>\n\nstruct OBJImportOptions {\n\tbool InvertU = false;\n\tbool InvertV = false;\n\tfloat Scale = 1.0f;\n\tfloat RotateX = 0.0f;\n\tfloat RotateY = 0.0f;\n\tfloat RotateZ = 0.0f;\n\n\tbool ImportAll = true;\n\tstd::set<std::string> ImportShapes;\n};\n"
  },
  {
    "path": "src/program/ObjImportDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"ObjImportDialog.h\"\n#include \"../utils/ConfigDialogUtil.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <wx/valnum.h>\n\nusing namespace nifly;\n\nextern ConfigurationManager Config;\nextern ConfigurationManager OutfitStudioConfig;\n\n\nwxBEGIN_EVENT_TABLE(ObjImportDialog, GLDialog)\n\tEVT_CHECKBOX(XRCID(\"cbInvertU\"), ObjImportDialog::OnInvertU)\n\tEVT_CHECKBOX(XRCID(\"cbInvertV\"), ObjImportDialog::OnInvertV)\n\tEVT_TEXT(XRCID(\"scale\"), ObjImportDialog::OnScale)\n\tEVT_CHOICE(XRCID(\"rotateX\"), ObjImportDialog::OnRotateX)\n\tEVT_CHOICE(XRCID(\"rotateY\"), ObjImportDialog::OnRotateY)\n\tEVT_CHOICE(XRCID(\"rotateZ\"), ObjImportDialog::OnRotateZ)\n\tEVT_LIST_ITEM_SELECTED(XRCID(\"meshesList\"), ObjImportDialog::OnItemSelected)\n\tEVT_LIST_ITEM_DESELECTED(XRCID(\"meshesList\"), ObjImportDialog::OnItemDeselected)\n\tEVT_LIST_KEY_DOWN(XRCID(\"meshesList\"), ObjImportDialog::OnListKeyDown)\n\tEVT_BUTTON(wxID_OK, ObjImportDialog::OnImport)\nwxEND_EVENT_TABLE()\n\nObjImportDialog::ObjImportDialog(wxWindow* parent, const std::string& fileName, size_t vertexLimit, size_t triangleLimit, const wxString& warningLabel)\n\t: GLDialog()\n\t, fileName(fileName)\n\t, vertexLimit(vertexLimit)\n\t, triangleLimit(triangleLimit) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ImportDialog.xrc\");\n\txrc->LoadDialog(this, parent, \"importDialog\");\n\n\tlbWarning = XRCCTRL((*this), \"lbWarning\", wxStaticText);\n\n\tif (!warningLabel.IsEmpty()) {\n\t\tlbWarning->SetLabel(warningLabel);\n\t\tlbWarning->Wrap(GetClientSize().x - 25);\n\t\tlbWarning->Show();\n\t}\n\n\tcbInvertU = XRCCTRL((*this), \"cbInvertU\", wxCheckBox);\n\tcbInvertV = XRCCTRL((*this), \"cbInvertV\", wxCheckBox);\n\n\twxFloatingPointValidator<float> floatValidator(5);\n\tfloatValidator.SetRange(0.00001f, 10000.0f);\n\n\tscale = XRCCTRL((*this), \"scale\", wxTextCtrl);\n\tscale->SetValidator(floatValidator);\n\n\trotateX = XRCCTRL((*this), \"rotateX\", wxChoice);\n\trotateY = XRCCTRL((*this), \"rotateY\", wxChoice);\n\trotateZ = XRCCTRL((*this), \"rotateZ\", wxChoice);\n\n\tmeshesList = XRCCTRL((*this), \"meshesList\", wxListCtrl);\n\n\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, (*this), \"OBJImport\", \"cbInvertU\");\n\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, (*this), \"OBJImport\", \"cbInvertV\");\n\tConfigDialogUtil::LoadDialogTextFloat(OutfitStudioConfig, (*this), \"OBJImport\", \"scale\");\n\tConfigDialogUtil::LoadDialogChoiceIndex(OutfitStudioConfig, (*this), \"OBJImport\", \"rotateX\");\n\tConfigDialogUtil::LoadDialogChoiceIndex(OutfitStudioConfig, (*this), \"OBJImport\", \"rotateY\");\n\tConfigDialogUtil::LoadDialogChoiceIndex(OutfitStudioConfig, (*this), \"OBJImport\", \"rotateZ\");\n\n\txrc->AttachUnknownControl(\"glView\", CreateCanvas(), this);\n#ifdef _WINDOWS\n\tcanvas->MSWDisableComposited(); // Fix stuttering from composited flag?\n#endif\n}\n\nObjImportDialog::~ObjImportDialog() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ImportDialog.xrc\");\n}\n\nvoid ObjImportDialog::OnShown() {\n\tGLDialog::OnShown();\n\n\tobj.SetScale(Vector3(10.0f, 10.0f, 10.0f));\n\n\tint result = obj.LoadForNif(fileName);\n\tif (result == 0) {\n\t\tauto shapes = obj.GetGroupList();\n\n\t\tfor (auto& s : shapes) {\n\t\t\tstd::vector<Vector3> verts;\n\t\t\tstd::vector<Triangle> tris;\n\t\t\tstd::vector<Vector2> uvs;\n\t\t\tstd::vector<Vector3> norms;\n\n\t\t\tif (!obj.CopyDataForGroup(s, &verts, &tris, &uvs, &norms))\n\t\t\t\tcontinue;\n\n\t\t\tsize_t vertCount = verts.size();\n\t\t\tsize_t triCount = tris.size();\n\n\t\t\tauto m = new Mesh();\n\t\t\tm->nVerts = static_cast<int>(vertCount);\n\t\t\tm->nTris = static_cast<int>(triCount);\n\n\t\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->norms = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->tangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->bitangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\t\tm->texcoord = std::make_unique<Vector2[]>(m->nVerts);\n\t\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->verts[v] = Mesh::TransformPosNifToMesh(verts[v]);\n\n\t\t\tfor (int t = 0; t < m->nTris; t++)\n\t\t\t\tm->tris[t] = tris[t];\n\n\t\t\tif (vertCount == uvs.size())\n\t\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\t\tm->texcoord[v] = uvs[v];\n\n\t\t\tif (vertCount == norms.size()) {\n\t\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\t\tm->norms[v] = Mesh::TransformDirNifToMesh(norms[v]);\n\t\t\t}\n\t\t\telse\n\t\t\t\tm->SmoothNormals();\n\n\t\t\tm->shapeName = s;\n\t\t\tm->rendermode = Mesh::RenderMode::Normal;\n\t\t\tm->doublesided = true;\n\t\t\tm->color = Vector3(0.25f, 0.25f, 0.25f);\n\t\t\tm->textured = true;\n\n\t\t\tstd::vector<std::string> textureFiles{Config[\"AppDir\"] + \"/res/images/NoImg.png\"};\n\t\t\tm->material = GetSurface().AddMaterial(textureFiles, Config[\"AppDir\"] + \"/res/shaders/default.vert\", Config[\"AppDir\"] + \"/res/shaders/default.frag\");\n\n\t\t\tm->CalcTangentSpace();\n\t\t\tm->CreateBuffers();\n\t\t\tGetSurface().UpdateShaders(m);\n\t\t\tGetSurface().AddMesh(m);\n\n\t\t\tlong itemId = meshesList->InsertItem(meshesList->GetItemCount(), wxString::FromUTF8(m->shapeName));\n\n\t\t\twxListItem colName{};\n\t\t\tcolName.SetId(itemId);\n\t\t\tcolName.SetColumn(0);\n\t\t\tcolName.SetText(wxString::FromUTF8(m->shapeName));\n\t\t\tmeshesList->SetItem(colName);\n\n\t\t\twxListItem colVertCount{};\n\t\t\tcolVertCount.SetId(itemId);\n\t\t\tcolVertCount.SetColumn(1);\n\t\t\tcolVertCount.SetText(wxString::Format(\"%zu\", vertCount));\n\t\t\tmeshesList->SetItem(colVertCount);\n\n\t\t\twxListItem colTriCount{};\n\t\t\tcolTriCount.SetId(itemId);\n\t\t\tcolTriCount.SetColumn(2);\n\t\t\tcolTriCount.SetText(wxString::Format(\"%zu\", triCount));\n\t\t\tmeshesList->SetItem(colTriCount);\n\n\t\t\twxListItem colInfo{};\n\t\t\tcolInfo.SetId(itemId);\n\t\t\tcolInfo.SetColumn(3);\n\n\t\t\tif (vertexLimit > 0 && static_cast<size_t>(m->nVerts) > vertexLimit) {\n\t\t\t\tcolInfo.SetText(_(\"The shape has reached the vertex count limit.\"));\n\t\t\t\tmeshesList->SetItemTextColour(itemId, wxColour(\"red\"));\n\t\t\t}\n\t\t\telse if (triangleLimit > 0 && static_cast<size_t>(m->nTris) > triangleLimit) {\n\t\t\t\tcolInfo.SetText(_(\"The shape has reached the triangle count limit.\"));\n\t\t\t\tmeshesList->SetItemTextColour(itemId, wxColour(\"red\"));\n\t\t\t}\n\n\t\t\tmeshesList->SetItem(colInfo);\n\t\t}\n\n\t\tUpdateVertexPositions();\n\t\tUpdateTextureCoords();\n\t}\n}\n\nvoid ObjImportDialog::UpdateVertexPositions() {\n\tif (!scale || !rotateX || !rotateY || !rotateZ)\n\t\treturn;\n\n\tMatrix4 mat;\n\n\tfloat scaleValue = std::atof(scale->GetValue().c_str());\n\tmat.PushScale(scaleValue, scaleValue, scaleValue);\n\n\tint rotateXSel = rotateX->GetSelection();\n\tint rotateYSel = rotateY->GetSelection();\n\tint rotateZSel = rotateZ->GetSelection();\n\n\tfloat rotateXDeg = 0.0f;\n\tfloat rotateYDeg = 0.0f;\n\tfloat rotateZDeg = 0.0f;\n\n\tswitch (rotateXSel) {\n\t\tcase 1: rotateXDeg = 90.0f; break;\n\t\tcase 2: rotateXDeg = 180.0f; break;\n\t\tcase 3: rotateXDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateYSel) {\n\t\tcase 1: rotateYDeg = 90.0f; break;\n\t\tcase 2: rotateYDeg = 180.0f; break;\n\t\tcase 3: rotateYDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateZSel) {\n\t\tcase 1: rotateZDeg = 90.0f; break;\n\t\tcase 2: rotateZDeg = 180.0f; break;\n\t\tcase 3: rotateZDeg = 270.0f; break;\n\t}\n\n\tmat.PushRotate(rotateXDeg * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmat.PushRotate(rotateYDeg * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmat.PushRotate(rotateZDeg * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tMatrix4 matRot;\n\tmatRot.PushRotate(rotateXDeg * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\tmatRot.PushRotate(rotateYDeg * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\tmatRot.PushRotate(rotateZDeg * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\n\tauto shapes = obj.GetGroupList();\n\n\tfor (auto& s : shapes) {\n\t\tauto m = GetSurface().GetMesh(s);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tstd::vector<Vector3> verts;\n\t\tstd::vector<Vector3> norms;\n\n\t\tif (!obj.CopyDataForGroup(s, &verts, nullptr, nullptr, &norms))\n\t\t\tcontinue;\n\n\t\tint vertCount = static_cast<int>(verts.size());\n\t\tif (vertCount != m->nVerts)\n\t\t\tcontinue;\n\t\t\n\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\tm->verts[v] = Mesh::TransformPosNifToMesh(mat * verts[v]);\n\n\t\tm->QueueUpdate(Mesh::UpdateType::Position);\n\n\t\tint normCount = static_cast<int>(norms.size());\n\t\tif (normCount == m->nVerts) {\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->norms[v] = Mesh::TransformDirNifToMesh(matRot * norms[v]);\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Normals);\n\t\t\tm->CalcTangentSpace();\n\t\t}\n\t}\n\n\tRender();\n}\n\nvoid ObjImportDialog::UpdateTextureCoords() {\n\tif (!cbInvertU || !cbInvertV)\n\t\treturn;\n\n\tauto shapes = obj.GetGroupList();\n\n\tfor (auto& s : shapes) {\n\t\tauto m = GetSurface().GetMesh(s);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tstd::vector<Vector2> uvs;\n\n\t\tif (!obj.CopyDataForGroup(s, nullptr, nullptr, &uvs, nullptr))\n\t\t\tcontinue;\n\n\t\tint uvCount = static_cast<int>(uvs.size());\n\t\tif (uvCount != m->nVerts)\n\t\t\tcontinue;\n\n\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\tm->texcoord[v] = uvs[v];\n\n\t\tif (cbInvertU->IsChecked())\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->texcoord[v].u = 1.0f - m->texcoord[v].u;\n\n\t\tif (cbInvertV->IsChecked())\n\t\t\tfor (int v = 0; v < m->nVerts; v++)\n\t\t\t\tm->texcoord[v].v = 1.0f - m->texcoord[v].v;\n\n\t\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n\t}\n\n\tRender();\n}\n\nvoid ObjImportDialog::UpdateItemSelection() {\n\tif (!meshesList)\n\t\treturn;\n\n\tfor (int item = 0; item < meshesList->GetItemCount(); item++) {\n\t\tstd::string name{meshesList->GetItemText(item).ToUTF8()};\n\n\t\tauto m = GetSurface().GetMesh(name);\n\t\tif (m) {\n\t\t\tif (meshesList->GetItemState(item, wxLIST_STATE_SELECTED) == wxLIST_STATE_SELECTED)\n\t\t\t\tm->color = Vector3(0.1f, 0.25f, 0.1f);\n\t\t\telse\n\t\t\t\tm->color = Vector3(0.25f, 0.25f, 0.25f);\n\t\t}\n\t}\n\n\tRender();\n}\n\nvoid ObjImportDialog::DeleteItemSelection() {\n\tif (!meshesList)\n\t\treturn;\n\n\tfor (int item = meshesList->GetItemCount() - 1; item >= 0; item--) {\n\t\tif (meshesList->GetItemState(item, wxLIST_STATE_SELECTED) == wxLIST_STATE_SELECTED) {\n\t\t\tstd::string name{meshesList->GetItemText(item).ToUTF8()};\n\t\t\tGetSurface().DeleteMesh(name);\n\t\t\tmeshesList->DeleteItem(item);\n\t\t}\n\t}\n\n\tRender();\n}\n\nvoid ObjImportDialog::OnInvertU(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateTextureCoords();\n}\n\nvoid ObjImportDialog::OnInvertV(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateTextureCoords();\n}\n\nvoid ObjImportDialog::OnScale(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid ObjImportDialog::OnRotateX(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid ObjImportDialog::OnRotateY(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid ObjImportDialog::OnRotateZ(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateVertexPositions();\n}\n\nvoid ObjImportDialog::OnItemSelected(wxListEvent& WXUNUSED(event)) {\n\tUpdateItemSelection();\n}\n\nvoid ObjImportDialog::OnItemDeselected(wxListEvent& WXUNUSED(event)) {\n\tUpdateItemSelection();\n}\n\nvoid ObjImportDialog::OnListKeyDown(wxListEvent& event) {\n\tif (event.GetKeyCode() == wxKeyCode::WXK_DELETE)\n\t\tDeleteItemSelection();\n}\n\nvoid ObjImportDialog::OnImport(wxCommandEvent& WXUNUSED(event)) {\n\toptions.InvertU = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, (*this), \"OBJImport\", \"cbInvertU\");\n\toptions.InvertV = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, (*this), \"OBJImport\", \"cbInvertV\");\n\toptions.Scale = ConfigDialogUtil::SetFloatFromDialogTextControl(OutfitStudioConfig, (*this), \"OBJImport\", \"scale\");\n\n\tint rotateXSel = ConfigDialogUtil::SetIntegerFromDialogChoice(OutfitStudioConfig, (*this), \"OBJImport\", \"rotateX\");\n\tint rotateYSel = ConfigDialogUtil::SetIntegerFromDialogChoice(OutfitStudioConfig, (*this), \"OBJImport\", \"rotateY\");\n\tint rotateZSel = ConfigDialogUtil::SetIntegerFromDialogChoice(OutfitStudioConfig, (*this), \"OBJImport\", \"rotateZ\");\n\n\tfloat rotateXDeg = 0.0f;\n\tfloat rotateYDeg = 0.0f;\n\tfloat rotateZDeg = 0.0f;\n\n\tswitch (rotateXSel) {\n\t\tcase 1: rotateXDeg = 90.0f; break;\n\t\tcase 2: rotateXDeg = 180.0f; break;\n\t\tcase 3: rotateXDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateYSel) {\n\t\tcase 1: rotateYDeg = 90.0f; break;\n\t\tcase 2: rotateYDeg = 180.0f; break;\n\t\tcase 3: rotateYDeg = 270.0f; break;\n\t}\n\n\tswitch (rotateZSel) {\n\t\tcase 1: rotateZDeg = 90.0f; break;\n\t\tcase 2: rotateZDeg = 180.0f; break;\n\t\tcase 3: rotateZDeg = 270.0f; break;\n\t}\n\n\toptions.RotateX = rotateXDeg;\n\toptions.RotateY = rotateYDeg;\n\toptions.RotateZ = rotateZDeg;\n\toptions.ImportAll = false;\n\n\tfor (int item = 0; item < meshesList->GetItemCount(); item++) {\n\t\tstd::string name{meshesList->GetItemText(item).ToUTF8()};\n\t\toptions.ImportShapes.insert(name);\n\t}\n\n\tEndModal(wxID_OK);\n}\n"
  },
  {
    "path": "src/program/ObjImportDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n#include <wx/listctrl.h>\n\n#include \"../render/GLDialog.h\"\n#include \"../render/GLSurface.h\"\n#include \"../files/ObjFile.h\"\n\nclass ObjImportDialog : public GLDialog {\npublic:\n\tObjImportDialog(wxWindow* parent, const std::string& fileName, size_t vertexLimit = 0, size_t triangleLimit = 0, const wxString& warningLabel = wxString());\n\t~ObjImportDialog();\n\n\tvirtual void OnShown() override;\n\tvoid OnImport(wxCommandEvent& event);\n\n\tObjImportOptions GetOptions() { return options; }\n\n\twxDECLARE_EVENT_TABLE();\n\nprivate:\n\tstd::string fileName;\n\tsize_t vertexLimit = 0;\n\tsize_t triangleLimit = 0;\n\n\tObjFile obj;\n\n\tObjImportOptions options;\n\twxStaticText* lbWarning;\n\twxCheckBox* cbInvertU = nullptr;\n\twxCheckBox* cbInvertV = nullptr;\n\twxTextCtrl* scale = nullptr;\n\twxChoice* rotateX = nullptr;\n\twxChoice* rotateY = nullptr;\n\twxChoice* rotateZ = nullptr;\n\twxListCtrl* meshesList = nullptr;\n\n\tvoid UpdateVertexPositions();\n\tvoid UpdateTextureCoords();\n\tvoid UpdateItemSelection();\n\tvoid DeleteItemSelection();\n\tvoid OnInvertU(wxCommandEvent& event);\n\tvoid OnInvertV(wxCommandEvent& event);\n\tvoid OnScale(wxCommandEvent& event);\n\tvoid OnRotateX(wxCommandEvent& event);\n\tvoid OnRotateY(wxCommandEvent& event);\n\tvoid OnRotateZ(wxCommandEvent& event);\n\tvoid OnItemSelected(wxListEvent& event);\n\tvoid OnItemDeselected(wxListEvent& event);\n\tvoid OnListKeyDown(wxListEvent& event);\n};\n"
  },
  {
    "path": "src/program/OutfitProject.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"OutfitProject.h\"\n#include \"../components/WeightNorm.h\"\n#include \"../files/FBXWrangler.h\"\n#include \"../files/ObjFile.h\"\n#include \"../files/TriFile.h\"\n#include \"../files/SFMorphFile.h\"\n#include \"../program/FBXImportDialog.h\"\n#include \"../program/ObjImportDialog.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"NifUtil.hpp\"\n\n#include \"../FSEngine/FSEngine.h\"\n#include \"../FSEngine/FSManager.h\"\n\n#include <algorithm>\n#include <regex>\n#include <sstream>\n\nextern ConfigurationManager Config;\n\nusing namespace nifly;\n\nOutfitProject::OutfitProject(OutfitStudioFrame* inOwner) {\n\towner = inOwner;\n\tworkAnim.SetRefNif(&workNif);\n\n\tstd::string defSkelFile = Config[\"Anim/DefaultSkeletonReference\"];\n\tif (wxFileName(wxString::FromUTF8(defSkelFile)).IsRelative())\n\t\tLoadSkeletonReference(Config[\"AppDir\"] + PathSepStr + defSkelFile);\n\telse\n\t\tLoadSkeletonReference(defSkelFile);\n\n\tauto targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tif (targetGame == SKYRIM || targetGame == SKYRIMSE || targetGame == SKYRIMVR)\n\t\tmGenWeights = true;\n}\n\nvoid OutfitProject::UpdateProgress(int val, const wxString& msg) {\n\tif (owner)\n\t\towner->UpdateProgress(val, msg);\n}\n\nOutfitProject::~OutfitProject() {}\n\nstd::string OutfitProject::Save(const wxFileName& sliderSetFile,\n\t\t\t\t\t\t\t\tconst wxString& strOutfitName,\n\t\t\t\t\t\t\t\tconst wxString& strDataDir,\n\t\t\t\t\t\t\t\tconst wxString& strBaseFile,\n\t\t\t\t\t\t\t\tconst wxString& strGamePath,\n\t\t\t\t\t\t\t\tconst wxString& strGameFile,\n\t\t\t\t\t\t\t\tbool genWeights,\n\t\t\t\t\t\t\t\tbool copyRef,\n\t\t\t\t\t\t\t\tbool preventMorphFile,\n\t\t\t\t\t\t\t\tbool keepZappedShapes) {\n\tUpdateProgress(1, _(\"Checking destination...\"));\n\tstd::string errmsg = \"\";\n\tstd::string outfit{strOutfitName.ToUTF8()};\n\tstd::string baseFile{strBaseFile.ToUTF8()};\n\tstd::string gameFile{strGameFile.ToUTF8()};\n\n\tReplaceForbidden(outfit);\n\tReplaceForbidden(baseFile);\n\tReplaceForbidden(gameFile);\n\n\tSliderSet outSet;\n\toutSet.SetName(outfit);\n\toutSet.SetDataFolder(strDataDir.ToUTF8().data());\n\toutSet.SetInputFile(baseFile);\n\toutSet.SetOutputPath(strGamePath.ToUTF8().data());\n\toutSet.SetOutputFile(gameFile);\n\toutSet.SetGenWeights(genWeights);\n\toutSet.SetPreventMorphFile(preventMorphFile);\n\toutSet.SetKeepZappedShapes(keepZappedShapes);\n\toutSet.SetNotes(activeSet.GetNotes());\n\n\tconst wxString sliderSetsStr = \"SliderSets\";\n\n\twxFileName ssFileName(sliderSetFile);\n\tint sliderSetsStrIndex = ssFileName.GetDirs().Index(sliderSetsStr);\n\tif (sliderSetsStrIndex == wxNOT_FOUND) {\n\t\t// Make path relative to \"SliderSets\\\", only use file name\n\t\tssFileName = wxFileName(sliderSetsStr + PathSepStr + sliderSetFile.GetFullName());\n\t}\n\n\tif (ssFileName.IsRelative())\n\t\tssFileName.MakeAbsolute(wxString::FromUTF8(GetProjectPath()));\n\n\tmFileName = ssFileName.GetFullPath();\n\tmOutfitName = wxString::FromUTF8(outfit);\n\tmDataDir = strDataDir;\n\tmBaseFile = wxString::FromUTF8(baseFile);\n\tmGamePath = strGamePath;\n\tmGameFile = wxString::FromUTF8(gameFile);\n\tmCopyRef = copyRef;\n\tmGenWeights = genWeights;\n\tbPreventMorphFile = preventMorphFile;\n\tbKeepZappedShapes = keepZappedShapes;\n\n\tauto shapes = workNif.GetShapes();\n\n\twxString folder(wxString::Format(\"%s/%s/%s\", wxString::FromUTF8(GetProjectPath()), \"ShapeData\", strDataDir));\n\twxFileName::Mkdir(folder, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\tint prog = 5;\n\tint step = 10 / shapes.size();\n\tUpdateProgress(prog);\n\n\tif (copyRef && baseShape) {\n\t\t// Add all the reference shapes to the target list.\n\t\tstd::string baseShapeName = baseShape->name.get();\n\t\toutSet.AddShapeTarget(baseShapeName, ShapeToTarget(baseShapeName));\n\t\toutSet.SetTargetDataFolders(ShapeToTarget(baseShapeName), activeSet.GetShapeDataFolders(baseShapeName));\n\t\toutSet.SetSmoothSeamNormals(baseShapeName, activeSet.GetSmoothSeamNormals(baseShapeName));\n\t\toutSet.SetSmoothSeamNormalsAngle(baseShapeName, activeSet.GetSmoothSeamNormalsAngle(baseShapeName));\n\t\toutSet.SetLockNormals(baseShapeName, activeSet.GetLockNormals(baseShapeName));\n\t\tUpdateProgress(prog += step, _(\"Adding reference shapes...\"));\n\t}\n\n\tif (!mRefProjectFile.empty() && !mRefProjectName.empty() && !mRefShapeName.empty()) {\n\t\toutSet.SetReferenceInfo(mRefProjectFile, mRefProjectName, mRefShapeName);\n\t}\n\n\t// Add all the outfit shapes to the target list.\n\tfor (auto& s : shapes) {\n\t\tif (IsBaseShape(s))\n\t\t\tcontinue;\n\n\t\tstd::string shapeName = s->name.get();\n\t\toutSet.AddShapeTarget(shapeName, ShapeToTarget(shapeName));\n\n\t\t// Reference only if not local folder\n\t\tstd::vector<std::string> shapeDataFolders = activeSet.GetShapeDataFolders(shapeName);\n\t\tfor (auto& df : shapeDataFolders) {\n\t\t\tif (df != activeSet.GetDefaultDataFolder())\n\t\t\t\toutSet.AddTargetDataFolder(ShapeToTarget(shapeName), df);\n\t\t}\n\n\t\toutSet.SetSmoothSeamNormals(shapeName, activeSet.GetSmoothSeamNormals(shapeName));\n\t\toutSet.SetSmoothSeamNormalsAngle(shapeName, activeSet.GetSmoothSeamNormalsAngle(shapeName));\n\t\toutSet.SetLockNormals(shapeName, activeSet.GetLockNormals(shapeName));\n\t\tUpdateProgress(prog += step, _(\"Adding outfit shapes...\"));\n\t}\n\n\tstd::string osdFileName = baseFile.substr(0, baseFile.find_last_of('.')) + \".osd\";\n\n\tif (activeSet.size() > 0) {\n\t\t// Copy the reference slider info and add the outfit data to them.\n\t\tstd::string targ;\n\t\tstd::string targSlider;\n\t\tstd::string targSliderData;\n\n\t\tprog = 10;\n\t\tstep = 20 / activeSet.size();\n\t\tUpdateProgress(prog);\n\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tsize_t id = outSet.CopySlider(&activeSet[i]);\n\t\t\toutSet[id].Clear();\n\n\t\t\tif (copyRef && baseShape) {\n\t\t\t\tstd::string baseShapeName = baseShape->name.get();\n\t\t\t\ttarg = ShapeToTarget(baseShapeName);\n\t\t\t\ttargSlider = activeSet[i].TargetDataName(targ);\n\t\t\t\tif (baseDiffData.GetDiffSet(targSlider) && baseDiffData.GetDiffSet(targSlider)->size() > 0) {\n\t\t\t\t\tif (activeSet[i].IsLocalData(targSlider)) {\n\t\t\t\t\t\ttargSliderData = osdFileName + PathSepStr + targSlider;\n\t\t\t\t\t\toutSet[id].AddDataFile(targ, targSlider, targSliderData);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ttargSliderData = activeSet[i].DataFileName(targSlider);\n\t\t\t\t\t\toutSet[id].AddDataFile(targ, targSlider, targSliderData, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto& s : shapes) {\n\t\t\t\tif (IsBaseShape(s))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::string shapeName = s->name.get();\n\t\t\t\ttarg = ShapeToTarget(shapeName);\n\t\t\t\ttargSlider = activeSet[i].TargetDataName(targ);\n\t\t\t\tif (targSlider.empty())\n\t\t\t\t\ttargSlider = targ + outSet[i].name;\n\n\t\t\t\tif (morpher.GetResultDiffSize(shapeName, activeSet[i].name) > 0) {\n\t\t\t\t\tstd::vector<std::string> shapeDataFolders = activeSet.GetShapeDataFolders(shapeName);\n\t\t\t\t\tbool isDefaultDataFolder = shapeDataFolders.size() == 1 && shapeDataFolders.front() == activeSet.GetDefaultDataFolder();\n\n\t\t\t\t\tif (isDefaultDataFolder || activeSet[i].IsLocalData(targSlider)) {\n\t\t\t\t\t\ttargSliderData = osdFileName + PathSepStr + targSlider;\n\t\t\t\t\t\toutSet[i].AddDataFile(targ, targSlider, targSliderData);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ttargSliderData = activeSet[i].DataFileName(targSlider);\n\t\t\t\t\t\toutSet[i].AddDataFile(targ, targSlider, targSliderData, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tUpdateProgress(prog += step, _(\"Calculating slider data...\"));\n\t\t}\n\t}\n\n\tstd::string saveDataPath = GetProjectPath() + PathSepStr + \"ShapeData\" + PathSepStr + mDataDir.ToUTF8().data();\n\tSaveSliderData(saveDataPath + PathSepStr + osdFileName, copyRef);\n\n\tprog = 60;\n\tUpdateProgress(prog, _(\"Creating slider set file...\"));\n\n\tstd::string ssUFileName{mFileName.ToUTF8()};\n\tSliderSetFile ssf(ssUFileName);\n\tif (ssf.fail()) {\n\t\tssf.New(ssUFileName);\n\t\tif (ssf.fail()) {\n\t\t\terrmsg = _(\"Failed to open or create slider set file: \") + ssUFileName;\n\t\t\treturn errmsg;\n\t\t}\n\t}\n\n\tssFileName.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\tUpdateProgress(61, _(\"Saving slider set file...\"));\n\tssf.UpdateSet(outSet);\n\tif (!ssf.Save()) {\n\t\terrmsg = _(\"Failed to write to slider set file: \") + ssUFileName;\n\t\treturn errmsg;\n\t}\n\n\tUpdateProgress(70, _(\"Saving NIF file...\"));\n\n\tstd::string saveFileName = saveDataPath + PathSepStr + baseFile;\n\n\tif (workNif.IsValid()) {\n\t\tworkAnim.CleanupBones();\n\t\towner->UpdateAnimationGUI();\n\n\t\tNifFile clone(workNif);\n\t\tChooseClothData(clone);\n\n\t\tif (!copyRef && baseShape) {\n\t\t\tstd::string baseShapeName = baseShape->name.get();\n\t\t\tauto shape = clone.FindBlockByName<NiShape>(baseShapeName);\n\t\t\tclone.DeleteShape(shape);\n\t\t\tworkAnim.WriteToNif(&clone, baseShapeName);\n\t\t}\n\t\telse\n\t\t\tworkAnim.WriteToNif(&clone);\n\n\t\tfor (auto& s : clone.GetShapes())\n\t\t\tclone.UpdateSkinPartitions(s);\n\n\t\tclone.SetShapeOrder(owner->GetShapeList());\n\t\tclone.GetHeader().SetExportInfo(\"Exported using Outfit Studio.\");\n\n\t\t// Project ShapeData NIFs always use internal geometry for simplicity\n\t\tForceInternalGeometry(clone);\n\n\t\tstd::fstream file;\n\t\tPlatformUtil::OpenFileStream(file, saveFileName, std::ios::out | std::ios::binary);\n\n\t\tif (clone.Save(file)) {\n\t\t\terrmsg = _(\"Failed to write base .nif file: \") + saveFileName;\n\t\t\treturn errmsg;\n\t\t}\n\t}\n\n\towner->ShowPartition();\n\tUpdateProgress(100, _(\"Finished\"));\n\treturn errmsg;\n}\n\nbool OutfitProject::SaveSliderData(const std::string& fileName, bool copyRef) {\n\tauto shapes = workNif.GetShapes();\n\n\tif (activeSet.size() > 0) {\n\t\tstd::string targ;\n\t\tstd::string targSlider;\n\n\t\tDiffDataSets osdDiffs;\n\t\tstd::map<std::string, std::map<std::string, std::string>> osdNames;\n\n\t\t// Copy the changed reference slider data and add the outfit data to them.\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tif (copyRef && baseShape) {\n\t\t\t\tstd::string baseShapeName = baseShape->name.get();\n\t\t\t\ttarg = ShapeToTarget(baseShapeName);\n\t\t\t\ttargSlider = activeSet[i].TargetDataName(targ);\n\t\t\t\tif (baseDiffData.GetDiffSet(targSlider) && baseDiffData.GetDiffSet(targSlider)->size() > 0) {\n\t\t\t\t\tif (activeSet[i].IsLocalData(targSlider)) {\n\t\t\t\t\t\tstd::unordered_map<uint16_t, Vector3>* diff = baseDiffData.GetDiffSet(targSlider);\n\t\t\t\t\t\tosdDiffs.LoadSet(targSlider, targ, *diff);\n\t\t\t\t\t\tosdNames[fileName][targSlider] = targ;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto& s : shapes) {\n\t\t\t\tif (IsBaseShape(s))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::string shapeName = s->name.get();\n\t\t\t\ttarg = ShapeToTarget(shapeName);\n\t\t\t\ttargSlider = activeSet[i].TargetDataName(targ);\n\t\t\t\tif (targSlider.empty())\n\t\t\t\t\ttargSlider = targ + activeSet[i].name;\n\n\t\t\t\tif (morpher.GetResultDiffSize(shapeName, activeSet[i].name) > 0) {\n\t\t\t\t\tstd::vector<std::string> shapeDataFolders = activeSet.GetShapeDataFolders(shapeName);\n\t\t\t\t\tbool isDefaultDataFolder = shapeDataFolders.size() == 1 && shapeDataFolders.front() == activeSet.GetDefaultDataFolder();\n\n\t\t\t\t\tif (isDefaultDataFolder || activeSet[i].IsLocalData(targSlider)) {\n\t\t\t\t\t\tstd::unordered_map<uint16_t, Vector3> diff;\n\t\t\t\t\t\tmorpher.GetRawResultDiff(shapeName, activeSet[i].name, diff);\n\t\t\t\t\t\tosdDiffs.LoadSet(targSlider, targ, diff);\n\t\t\t\t\t\tosdNames[fileName][targSlider] = targ;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (!osdDiffs.SaveData(osdNames))\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid OutfitProject::SetBaseShape(NiShape* shape, const bool moveData) {\n\tif (moveData) {\n\t\tif (baseShape != shape) {\n\t\t\t// Copy data from base shape to regular shape\n\t\t\tif (baseShape) {\n\t\t\t\tstd::string shapeName = baseShape->name.get();\n\t\t\t\tstd::string srcTarget = ShapeToTarget(shapeName);\n\n\t\t\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\t\t\tauto& sd = activeSet[i];\n\t\t\t\t\tstd::string srcTargetData = sd.TargetDataName(srcTarget);\n\n\t\t\t\t\tauto diff = baseDiffData.GetDiffSet(srcTargetData);\n\t\t\t\t\tif (diff)\n\t\t\t\t\t\tmorpher.SetResultDiff(shapeName, sd.name, *diff);\n\n\t\t\t\t\tactiveSet[i].RenameTarget(srcTarget, shapeName, sd.name);\n\t\t\t\t\tbaseDiffData.ClearSet(srcTargetData);\n\t\t\t\t}\n\n\t\t\t\tactiveSet.AddShapeTarget(shapeName, shapeName);\n\t\t\t\tactiveSet.Retarget(srcTarget, shapeName);\n\t\t\t}\n\n\t\t\t// Copy data from regular shape to base shape\n\t\t\tif (shape) {\n\t\t\t\tstd::string shapeName = shape->name.get();\n\t\t\t\tstd::string target = ShapeToTarget(shapeName);\n\n\t\t\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\t\t\tstd::string sliderName = activeSet[i].name;\n\t\t\t\t\tstd::string targetData = activeSet[i].TargetDataName(target);\n\t\t\t\t\tif (targetData.empty()) {\n\t\t\t\t\t\ttargetData = target + sliderName;\n\t\t\t\t\t\tactiveSet[i].AddDataFile(target, target + sliderName, target + sliderName);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tactiveSet[i].SetLocalData(targetData);\n\n\t\t\t\t\tstd::unordered_map<uint16_t, Vector3> diff;\n\t\t\t\t\tmorpher.GetRawResultDiff(shapeName, sliderName, diff);\n\t\t\t\t\tmorpher.ClearResultSet(targetData);\n\n\t\t\t\t\tbaseDiffData.LoadSet(targetData, shapeName, diff);\n\t\t\t\t}\n\n\t\t\t\tactiveSet.AddShapeTarget(shapeName, shapeName);\n\t\t\t}\n\t\t}\n\t}\n\n\tbaseShape = shape;\n}\n\n\nstd::string OutfitProject::SliderSetName() {\n\treturn activeSet.GetName();\n}\n\nstd::string OutfitProject::SliderSetFileName() {\n\treturn activeSet.GetInputFileName();\n}\n\nstd::string OutfitProject::OutfitName() {\n\treturn outfitName;\n}\n\nvoid OutfitProject::ReplaceForbidden(std::string& str, const char& replacer) {\n\tconst std::string forbiddenChars = \"\\\\/:*?\\\"<>|\";\n\n\tstd::transform(str.begin(), str.end(), str.begin(), [&forbiddenChars, &replacer](char c) { return forbiddenChars.find(c) != std::string::npos ? replacer : c; });\n}\n\nbool OutfitProject::ValidSlider(const size_t index) {\n\tif (index < activeSet.size())\n\t\treturn true;\n\n\treturn false;\n}\n\nbool OutfitProject::ValidSlider(const std::string& sliderName) {\n\treturn activeSet.SliderExists(sliderName);\n}\n\nbool OutfitProject::AllSlidersZero() {\n\tfor (size_t i = 0; i < activeSet.size(); i++)\n\t\tif (activeSet[i].curValue != 0.0f)\n\t\t\treturn false;\n\treturn true;\n}\n\nsize_t OutfitProject::SliderCount() {\n\treturn activeSet.size();\n}\n\nvoid OutfitProject::GetSliderList(std::vector<std::string>& sliderNames) {\n\tfor (size_t i = 0; i < activeSet.size(); i++)\n\t\tsliderNames.push_back(activeSet[i].name);\n}\n\nstd::string OutfitProject::GetSliderName(const size_t index) {\n\tif (!ValidSlider(index))\n\t\treturn std::string();\n\n\treturn activeSet[index].name;\n}\n\nvoid OutfitProject::AddEmptySlider(const std::string& newName) {\n\tsize_t sliderID = activeSet.CreateSlider(newName);\n\n\tif (baseShape) {\n\t\tstd::string baseShapeName = baseShape->name.get();\n\t\tstd::string target = ShapeToTarget(baseShapeName);\n\t\tstd::string shapeSlider = target + newName;\n\t\tactiveSet[sliderID].AddDataFile(target, shapeSlider, shapeSlider);\n\t\tactiveSet.AddShapeTarget(baseShapeName, target);\n\t\tbaseDiffData.AddEmptySet(shapeSlider, target);\n\t}\n}\n\nvoid OutfitProject::AddZapSlider(const std::string& newName, std::unordered_map<uint16_t, float>& verts, NiShape* shape) {\n\tstd::unordered_map<uint16_t, Vector3> diffData;\n\tVector3 moveVec(0.0f, 1.0f, 0.0f);\n\tfor (auto& v : verts)\n\t\tdiffData[v.first] = moveVec;\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tstd::string shapeSlider = target + newName;\n\n\tsize_t sliderID = 0;\n\tif (!SliderIndexFromName(newName, sliderID))\n\t\tsliderID = activeSet.CreateSlider(newName);\n\n\tactiveSet[sliderID].bZap = true;\n\tactiveSet[sliderID].defBigValue = 0.0f;\n\tactiveSet[sliderID].defSmallValue = 0.0f;\n\n\tif (IsBaseShape(shape)) {\n\t\tactiveSet[sliderID].AddDataFile(target, shapeSlider, shapeSlider);\n\t\tactiveSet.AddShapeTarget(shape->name.get(), target);\n\t\tbaseDiffData.AddEmptySet(shapeSlider, target);\n\t\tfor (auto& i : diffData)\n\t\t\tbaseDiffData.SumDiff(shapeSlider, target, i.first, i.second);\n\t}\n\telse\n\t\tmorpher.SetResultDiff(shape->name.get(), newName, diffData);\n}\n\nvoid OutfitProject::AddCombinedSlider(const std::string& newName) {\n\tstd::vector<Vector3> verts;\n\tstd::unordered_map<uint16_t, Vector3> diffData;\n\n\tfor (auto& s : workNif.GetShapes()) {\n\t\tif (IsBaseShape(s))\n\t\t\tcontinue;\n\n\t\tdiffData.clear();\n\t\tGetLiveVerts(s, verts);\n\t\tworkNif.CalcShapeDiff(s, &verts, diffData);\n\t\tmorpher.SetResultDiff(s->name.get(), newName, diffData);\n\t}\n\n\tsize_t sliderID = activeSet.CreateSlider(newName);\n\tif (baseShape) {\n\t\tstd::string baseShapeName = baseShape->name.get();\n\t\tstd::string target = ShapeToTarget(baseShapeName);\n\t\tstd::string shapeSlider = target + newName;\n\t\tactiveSet[sliderID].AddDataFile(target, shapeSlider, shapeSlider);\n\t\tbaseDiffData.AddEmptySet(shapeSlider, target);\n\n\t\tGetLiveVerts(baseShape, verts);\n\t\tworkNif.CalcShapeDiff(baseShape, &verts, diffData);\n\n\t\tfor (auto& i : diffData)\n\t\t\tbaseDiffData.SumDiff(shapeSlider, target, i.first, i.second);\n\t}\n}\n\nNiShape* OutfitProject::CreateNifShapeFromData(\n\tconst std::string& shapeName, const std::vector<Vector3>* v, const std::vector<Triangle>* t, const std::vector<Vector2>* uv, const std::vector<Vector3>* norms) {\n\tauto targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\n\tif (!workNif.IsValid()) {\n\t\tNiVersion version;\n\n\t\tswitch (targetGame) {\n\t\t\tcase OB: version = NiVersion::getOB(); break;\n\t\t\tcase FO3:\n\t\t\tcase FONV: version = NiVersion::getFO3(); break;\n\t\t\tcase SKYRIM: version = NiVersion::getSK(); break;\n\t\t\tcase FO4:\n\t\t\tcase FO4VR: version = NiVersion::getFO4(); break;\n\t\t\tcase SKYRIMSE:\n\t\t\tcase SKYRIMVR: version = NiVersion::getSSE(); break;\n\t\t\tcase FO76: version = NiVersion::getFO76(); break;\n\t\t\tcase SF: version = NiVersion::getSF(); break;\n\t\t}\n\n\t\tworkNif.Create(version);\n\t}\n\n\tauto shapeResult = workNif.CreateShapeFromData(shapeName, v, t, uv, norms);\n\tif (shapeResult)\n\t\tSetTextures(shapeResult);\n\n\treturn shapeResult;\n}\n\nstd::string OutfitProject::SliderShapeDataName(const size_t index, const std::string& shapeName) {\n\tif (!ValidSlider(index))\n\t\treturn \"\";\n\n\treturn activeSet.ShapeToDataName(index, shapeName);\n}\n\nbool OutfitProject::SliderClamp(const size_t index) {\n\tif (!ValidSlider(index))\n\t\treturn false;\n\n\treturn activeSet[index].bClamp;\n}\n\nbool OutfitProject::SliderZap(const size_t index) {\n\tif (!ValidSlider(index))\n\t\treturn false;\n\n\treturn activeSet[index].bZap;\n}\n\nbool OutfitProject::SliderUV(const size_t index) {\n\tif (!ValidSlider(index))\n\t\treturn false;\n\n\treturn activeSet[index].bUV;\n}\n\nwxArrayString OutfitProject::SliderZapToggles(const size_t index) {\n\twxArrayString toggles;\n\tif (ValidSlider(index))\n\t\tfor (auto& toggle : activeSet[index].zapToggles)\n\t\t\ttoggles.Add(wxString::FromUTF8(toggle));\n\n\treturn toggles;\n}\n\nbool OutfitProject::SliderInvert(const size_t index) {\n\tif (!ValidSlider(index))\n\t\treturn false;\n\n\treturn activeSet[index].bInvert;\n}\n\nbool OutfitProject::SliderHidden(const size_t index) {\n\tif (!ValidSlider(index))\n\t\treturn false;\n\n\treturn activeSet[index].bHidden;\n}\n\nvoid OutfitProject::SetSliderZap(const size_t index, const bool zap) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tactiveSet[index].bZap = zap;\n}\n\nvoid OutfitProject::SetSliderZapToggles(const size_t index, const wxArrayString& toggles) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tstd::vector<std::string> zapToggles;\n\tfor (auto& s : toggles)\n\t\tzapToggles.push_back(s.ToUTF8().data());\n\n\tactiveSet[index].zapToggles = zapToggles;\n}\n\nvoid OutfitProject::SetSliderInvert(const size_t index, const bool inv) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tactiveSet[index].bInvert = inv;\n}\n\nvoid OutfitProject::SetSliderUV(const size_t index, const bool uv) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tactiveSet[index].bUV = uv;\n}\n\nvoid OutfitProject::SetSliderHidden(const size_t index, const bool hidden) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tactiveSet[index].bHidden = hidden;\n}\n\nvoid OutfitProject::SetSliderDefault(const size_t index, const int val, const bool isHi) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tif (!isHi)\n\t\tactiveSet[index].defSmallValue = val;\n\telse\n\t\tactiveSet[index].defBigValue = val;\n}\n\nvoid OutfitProject::SetSliderName(const size_t index, const std::string& newName) {\n\tif (!ValidSlider(index))\n\t\treturn;\n\n\tstd::string oldName = activeSet[index].name;\n\tfor (auto& s : workNif.GetShapes()) {\n\t\tstd::string shapeName = s->name.get();\n\t\tstd::string oldDT = shapeName + oldName;\n\t\tstd::string newDT = shapeName + newName;\n\n\t\tif (IsBaseShape(s))\n\t\t\tbaseDiffData.RenameSet(oldDT, newDT);\n\t\telse\n\t\t\tmorpher.RenameResultDiffData(shapeName, oldName, newName);\n\n\t\tactiveSet[index].RenameData(oldDT, newDT);\n\t\tactiveSet[index].SetLocalData(newDT);\n\t}\n\n\tactiveSet[index].name = newName;\n}\n\nfloat& OutfitProject::SliderValue(const size_t index) {\n\treturn activeSet[index].curValue;\n}\n\nfloat& OutfitProject::SliderValue(const std::string& name) {\n\treturn activeSet[name].curValue;\n}\n\nfloat OutfitProject::SliderDefault(const size_t index, const bool hi) {\n\tif (hi)\n\t\treturn activeSet[index].defBigValue;\n\n\treturn activeSet[index].defSmallValue;\n}\n\nbool& OutfitProject::SliderShow(const size_t index) {\n\treturn activeSet[index].bShow;\n}\n\nbool& OutfitProject::SliderShow(const std::string& sliderName) {\n\treturn activeSet[sliderName].bShow;\n}\n\nbool OutfitProject::SliderIndexFromName(const std::string& sliderName, size_t& index) {\n\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\tif (activeSet[i].name == sliderName) {\n\t\t\tindex = i;\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nvoid OutfitProject::CloneSlider(const std::string& sliderName, const std::string& cloneName) {\n\tsize_t cloneIndex = activeSet.CloneSlider(sliderName, cloneName);\n\tif (cloneIndex == -1)\n\t\treturn;\n\n\tfor (auto& shape : workNif.GetShapes()) {\n\t\tstd::string shapeName = shape->name.get();\n\t\tstd::string target = ShapeToTarget(shape->name.get());\n\t\tstd::string oldDT = target + sliderName;\n\t\tstd::string newDT = target + cloneName;\n\n\t\t// Adjust all data names to cloned slider name and make it local\n\t\tactiveSet[cloneIndex].RenameData(oldDT, newDT);\n\t\tactiveSet[cloneIndex].SetLocalData(newDT);\n\n\t\tstd::string data = activeSet[sliderName].TargetDataName(target);\n\n\t\tif (IsBaseShape(shape)) {\n\t\t\tactiveSet[cloneIndex].AddDataFile(target, newDT, newDT);\n\t\t\tactiveSet.AddShapeTarget(shape->name.get(), target);\n\t\t\tbaseDiffData.AddEmptySet(newDT, target);\n\n\t\t\tauto diffData = baseDiffData.GetDiffSet(oldDT);\n\t\t\tif (diffData) {\n\t\t\t\tfor (auto& i : *diffData)\n\t\t\t\t\tbaseDiffData.SumDiff(newDT, target, i.first, i.second);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tauto diffData = morpher.GetDiffSet(oldDT);\n\t\t\tif (diffData)\n\t\t\t\tmorpher.SetResultDiff(shape->name.get(), cloneName, *diffData);\n\t\t}\n\t}\n}\n\nvoid OutfitProject::NegateSlider(const std::string& sliderName, NiShape* shape) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.ScaleDiff(sliderData, target, -1.0f);\n\t}\n\telse\n\t\tmorpher.ScaleResultDiff(target, sliderName, -1.0f);\n}\n\nvoid OutfitProject::MaskAffected(const std::string& sliderName, NiShape* shape) {\n\tMesh* m = owner->glView->GetMesh(shape->name.get());\n\tif (!m)\n\t\treturn;\n\n\tm->MaskFill(0.0f);\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::vector<uint16_t> outIndices;\n\t\tstd::string target = ShapeToTarget(shape->name.get());\n\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.GetDiffIndices(sliderData, target, outIndices);\n\n\t\tfor (auto& i : outIndices) {\n\t\t\tif (m->nVerts > i)\n\t\t\t\tm->mask[i] = 1.0f;\n\t\t}\n\t}\n\telse {\n\t\tstd::unordered_map<uint16_t, Vector3> outDiff;\n\t\tmorpher.GetRawResultDiff(shape->name.get(), sliderName, outDiff);\n\n\t\tfor (auto& i : outDiff) {\n\t\t\tif (m->nVerts > i.first)\n\t\t\t\tm->mask[i.first] = 1.0f;\n\t\t}\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Mask);\n}\n\nbool OutfitProject::WriteMorphTRI(const std::string& triPath) {\n\tTriFile tri;\n\tstd::string triFilePath = triPath;\n\n\tfor (auto& shape : workNif.GetShapes()) {\n\t\tint shapeVertCount = GetVertexCount(shape);\n\t\tif (shapeVertCount <= 0)\n\t\t\tcontinue;\n\n\t\tstd::string shapeName = shape->name.get();\n\t\tbool bIsOutfit = true;\n\t\tif (IsBaseShape(shape))\n\t\t\tbIsOutfit = false;\n\n\t\tfor (size_t s = 0; s < activeSet.size(); s++) {\n\t\t\tif (!activeSet[s].bClamp && !activeSet[s].bZap) {\n\t\t\t\tMorphDataPtr morph = std::make_shared<MorphData>();\n\t\t\t\tmorph->name = activeSet[s].name;\n\n\t\t\t\tif (activeSet[s].bUV) {\n\t\t\t\t\tmorph->type = MORPHTYPE_UV;\n\n\t\t\t\t\tstd::vector<Vector2> uvs;\n\t\t\t\t\tuvs.resize(shapeVertCount);\n\n\t\t\t\t\tstd::string target = ShapeToTarget(shapeName);\n\t\t\t\t\tif (!bIsOutfit) {\n\t\t\t\t\t\tstd::string dn = activeSet[s].TargetDataName(target);\n\t\t\t\t\t\tif (dn.empty())\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tbaseDiffData.ApplyUVDiff(dn, target, 1.0f, &uvs);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tmorpher.ApplyResultToUVs(morph->name, target, &uvs);\n\n\t\t\t\t\tint i = 0;\n\t\t\t\t\tfor (auto& uv : uvs) {\n\t\t\t\t\t\tVector3 v(uv.u, uv.v, 0.0f);\n\t\t\t\t\t\tif (!v.IsZero(true))\n\t\t\t\t\t\t\tmorph->offsets.emplace(i, v);\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tmorph->type = MORPHTYPE_POSITION;\n\n\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\tverts.resize(shapeVertCount);\n\n\t\t\t\t\tstd::string target = ShapeToTarget(shapeName);\n\t\t\t\t\tif (!bIsOutfit) {\n\t\t\t\t\t\tstd::string dn = activeSet[s].TargetDataName(target);\n\t\t\t\t\t\tif (dn.empty())\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tbaseDiffData.ApplyDiff(dn, target, 1.0f, &verts);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tmorpher.ApplyResultToVerts(morph->name, target, &verts);\n\n\t\t\t\t\tint i = 0;\n\t\t\t\t\tfor (auto& v : verts) {\n\t\t\t\t\t\tif (!v.IsZero(true))\n\t\t\t\t\t\t\tmorph->offsets.emplace(i, v);\n\t\t\t\t\t\ti++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (morph->offsets.size() > 0)\n\t\t\t\t\ttri.AddMorph(shapeName, morph);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!tri.Write(triFilePath))\n\t\treturn false;\n\n\treturn true;\n}\n\nbool OutfitProject::WriteHeadTRI(NiShape* shape, const std::string& triPath) {\n\tif (!shape)\n\t\treturn false;\n\n\tTriHeadFile tri;\n\tstd::string triFilePath = triPath;\n\n\tint shapeVertCount = GetVertexCount(shape);\n\tif (shapeVertCount <= 0)\n\t\treturn false;\n\n\tstd::string shapeName = shape->name.get();\n\tbool bIsOutfit = true;\n\tif (IsBaseShape(shape))\n\t\tbIsOutfit = false;\n\n\tstd::vector<Triangle> tris;\n\tif (!shape->GetTriangles(tris))\n\t\treturn false;\n\n\tconst std::vector<Vector3>* verts = workNif.GetVertsForShape(shape);\n\tif (!verts)\n\t\treturn false;\n\n\ttri.SetVertices(*verts);\n\ttri.SetTriangles(tris);\n\n\tconst std::vector<Vector2>* uvs = workNif.GetUvsForShape(shape);\n\tif (uvs)\n\t\ttri.SetUV(*uvs);\n\n\tfor (size_t s = 0; s < activeSet.size(); s++) {\n\t\tif (!activeSet[s].bClamp && !activeSet[s].bZap && !activeSet[s].bUV) {\n\t\t\tTriHeadMorph morph;\n\t\t\tmorph.morphName = activeSet[s].name;\n\n\t\t\tstd::vector<Vector3> morphVerts;\n\t\t\tmorphVerts.resize(shapeVertCount);\n\n\t\t\tstd::string target = ShapeToTarget(shapeName);\n\t\t\tif (!bIsOutfit) {\n\t\t\t\tstd::string dn = activeSet[s].TargetDataName(target);\n\t\t\t\tif (dn.empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tbaseDiffData.ApplyDiff(dn, target, 1.0f, &morphVerts);\n\t\t\t}\n\t\t\telse\n\t\t\t\tmorpher.ApplyResultToVerts(morph.morphName, target, &morphVerts);\n\n\t\t\tmorph.vertices = morphVerts;\n\t\t\ttri.AddMorph(morph);\n\t\t}\n\t}\n\n\tif (!tri.Write(triFilePath))\n\t\treturn false;\n\n\treturn true;\n}\n\nbool OutfitProject::WriteSFMorphs(nifly::NiShape* shape, const std::string& morphPath) {\n\tSFMorphFile morphFile;\n\tstd::string morphPathFilePath = morphPath;\n\n\tint shapeVertCount = GetVertexCount(shape);\n\tif (shapeVertCount <= 0)\n\t\treturn false;\n\n\tstd::string shapeName = shape->name.get();\n\tbool bIsOutfit = true;\n\tif (IsBaseShape(shape))\n\t\tbIsOutfit = false;\n\n\tmorphFile.SetVertexCount(shapeVertCount);\n\n\tfor (size_t s = 0; s < activeSet.size(); s++) {\n\t\tif (!activeSet[s].bClamp && !activeSet[s].bZap) {\n\t\t\tstd::string morphName = activeSet[s].name;\n\t\t\tstd::unordered_map<uint16_t, Vector3> morphOffsets;\n\n\t\t\tstd::vector<Vector3> diffs;\n\t\t\tdiffs.resize(shapeVertCount);\n\n\t\t\tstd::string target = ShapeToTarget(shapeName);\n\t\t\tif (!bIsOutfit) {\n\t\t\t\tstd::string dn = activeSet[s].TargetDataName(target);\n\t\t\t\tif (dn.empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tbaseDiffData.ApplyDiff(dn, target, 1.0f, &diffs);\n\t\t\t}\n\t\t\telse\n\t\t\t\tmorpher.ApplyResultToVerts(morphName, target, &diffs);\n\n\t\t\tint i = 0;\n\t\t\tfor (auto& d : diffs) {\n\t\t\t\tif (!d.IsZero(true))\n\t\t\t\t\tmorphOffsets.emplace(i, d);\n\t\t\t\ti++;\n\t\t\t}\n\n\t\t\tif (morphOffsets.size() > 0) {\n\t\t\t\tstd::unordered_map<uint16_t, nifly::Vector3> morphNormals;\n\t\t\t\tstd::unordered_map<uint16_t, nifly::Vector3> morphTangents;\n\n\t\t\t\tstd::vector<Vector3> shapeVerts;\n\t\t\t\tstd::vector<Vector2> shapeUVs;\n\t\t\t\tstd::vector<Triangle> shapeTris;\n\t\t\t\tif (workNif.GetVertsForShape(shape, shapeVerts) && workNif.GetUvsForShape(shape, shapeUVs) && shape->GetTriangles(shapeTris)) {\n\t\t\t\t\t// Apply diff to base positions\n\t\t\t\t\tif (shapeVerts.size() == diffs.size()) {\n\t\t\t\t\t\tfor (int v = 0; v < shapeVertCount; v++)\n\t\t\t\t\t\t\tshapeVerts[v] += diffs[v];\n\t\t\t\t\t}\n\n\t\t\t\t\t// Use temporary mesh to calculate normals and tangents for the morph\n\t\t\t\t\t// TODO: Allow storing these normals and importing custom normals for a slider?\n\t\t\t\t\tMesh tmpMesh{};\n\t\t\t\t\ttmpMesh.nVerts = static_cast<int>(shapeVerts.size());\n\t\t\t\t\ttmpMesh.nTris = static_cast<int>(shapeTris.size());\n\n\t\t\t\t\tif (tmpMesh.nVerts > 0) {\n\t\t\t\t\t\ttmpMesh.verts = std::make_unique<Vector3[]>(tmpMesh.nVerts);\n\t\t\t\t\t\ttmpMesh.norms = std::make_unique<Vector3[]>(tmpMesh.nVerts);\n\t\t\t\t\t\ttmpMesh.tangents = std::make_unique<Vector3[]>(tmpMesh.nVerts);\n\t\t\t\t\t\ttmpMesh.bitangents = std::make_unique<Vector3[]>(tmpMesh.nVerts);\n\t\t\t\t\t\ttmpMesh.texcoord = std::make_unique<Vector2[]>(tmpMesh.nVerts);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (tmpMesh.nTris > 0)\n\t\t\t\t\t\ttmpMesh.tris = std::make_unique<Triangle[]>(tmpMesh.nTris);\n\n\t\t\t\t\tfor (int v = 0; v < tmpMesh.nVerts; v++)\n\t\t\t\t\t\ttmpMesh.verts[v] = Mesh::TransformPosNifToMesh(shapeVerts[v]);\n\n\t\t\t\t\tif (!shapeUVs.empty()) {\n\t\t\t\t\t\tfor (int v = 0; v < tmpMesh.nVerts; v++) {\n\t\t\t\t\t\t\ttmpMesh.texcoord[v].u = shapeUVs[v].u;\n\t\t\t\t\t\t\ttmpMesh.texcoord[v].v = shapeUVs[v].v;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (int t = 0; t < tmpMesh.nTris; t++)\n\t\t\t\t\t\ttmpMesh.tris[t] = shapeTris[t];\n\n\t\t\t\t\ttmpMesh.SmoothNormals();\n\n\t\t\t\t\tfor (int v = 0; v < tmpMesh.nVerts; v++) {\n\t\t\t\t\t\tmorphNormals[v] = Mesh::TransformDirMeshToNif(tmpMesh.norms[v]);\n\t\t\t\t\t\tmorphTangents[v] = Mesh::TransformDirMeshToNif(tmpMesh.tangents[v]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// TODO: Store and pass target vertex colors?\n\t\t\t\tmorphFile.AddMorph(morphName, morphOffsets, {}, morphNormals, morphTangents);\n\t\t\t}\n\t\t}\n\t}\n\n\tmorphFile.CacheToFileData();\n\n\tif (!morphFile.Write(morphPathFilePath))\n\t\treturn false;\n\n\treturn true;\n}\n\nint OutfitProject::SaveSliderNIF(const std::string& sliderName, NiShape* shape, const std::string& fileName) {\n\tif (!shape)\n\t\treturn 1;\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tstd::vector<Vector3> outVerts;\n\tstd::vector<Vector2> outUVs;\n\n\tif (!workNif.GetVertsForShape(shape, outVerts))\n\t\treturn 2;\n\n\tworkNif.GetUvsForShape(shape, outUVs);\n\n\tGetSliderDiff(shape, sliderName, outVerts);\n\tGetSliderDiffUV(shape, sliderName, outUVs);\n\n\tNifFile nif;\n\tnif.CopyFrom(workNif);\n\n\tauto sliderShape = nif.FindBlockByName<NiShape>(shape->name.get());\n\tif (sliderShape) {\n\t\tfor (auto& s : nif.GetShapes()) {\n\t\t\tif (s != sliderShape)\n\t\t\t\tnif.DeleteShape(s);\n\t\t}\n\n\t\tnif.SetVertsForShape(sliderShape, outVerts);\n\t\tnif.SetUvsForShape(sliderShape, outUVs);\n\n\t\tnif.DeleteUnreferencedNodes();\n\t}\n\n\t// Slider NIFs in ShapeData always use internal geometry\n\tForceInternalGeometry(nif);\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::out | std::ios::binary);\n\n\tif (nif.Save(file) != 0)\n\t\treturn 3;\n\n\treturn 0;\n}\n\nint OutfitProject::SaveSliderBSD(const std::string& sliderName, NiShape* shape, const std::string& fileName) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.SaveSet(sliderData, target, fileName);\n\t}\n\telse\n\t\tmorpher.SaveResultDiff(target, sliderName, fileName);\n\n\treturn 0;\n}\n\nint OutfitProject::SaveSliderOBJ(const std::string& sliderName, NiShape* shape, const std::string& fileName, const bool onlyDiff) {\n\tif (!shape)\n\t\treturn 1;\n\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tconst std::vector<Vector3>* verts = workNif.GetVertsForShape(shape);\n\tif (!verts)\n\t\treturn 2;\n\n\tconst std::vector<Vector2>* uvs = workNif.GetUvsForShape(shape);\n\tconst std::vector<Vector3> norms;\n\n\tstd::vector<Vector3> outVerts = *verts;\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbool foundDiff = baseDiffData.ApplyDiff(sliderData, target, 1.0f, &outVerts);\n\t\tif (onlyDiff && !foundDiff)\n\t\t\treturn 0;\n\t}\n\telse {\n\t\tbool foundDiff = morpher.ApplyResultToVerts(sliderName, target, &outVerts);\n\t\tif (onlyDiff && !foundDiff)\n\t\t\treturn 0;\n\t}\n\n\tObjFile obj;\n\tobj.SetScale(Vector3(0.1f, 0.1f, 0.1f));\n\tobj.AddGroup(shape->name.get(), outVerts, tris, uvs ? *uvs : std::vector<Vector2>(), norms);\n\tif (obj.Save(fileName))\n\t\treturn 3;\n\n\treturn 0;\n}\n\nbool OutfitProject::SetSliderFromNIF(const std::string& sliderName, NiShape* shape, const std::string& fileName) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);\n\n\tNifFile nif;\n\tif (nif.Load(file) != 0)\n\t\treturn false;\n\n\t// File needs at least one shape\n\tauto shapeNames = nif.GetShapeNames();\n\tif (shapeNames.empty())\n\t\treturn false;\n\n\t// Use first shape or shape with matching name\n\tstd::string srcShapeName = shapeNames.front();\n\tif (std::find(shapeNames.begin(), shapeNames.end(), shape->name.get()) != shapeNames.end())\n\t\tsrcShapeName = shape->name.get();\n\n\tstd::vector<Vector3> verts;\n\tstd::vector<Vector2> uvs;\n\n\tauto srcShape = nif.FindBlockByName<NiShape>(srcShapeName);\n\tif (!srcShape)\n\t\treturn false;\n\n\tif (!nif.GetVertsForShape(srcShape, verts))\n\t\treturn false;\n\n\tnif.GetUvsForShape(srcShape, uvs);\n\n\tstd::unordered_map<uint16_t, Vector3> diff;\n\tif (activeSet[sliderName].bUV) {\n\t\tif (workNif.CalcUVDiff(shape, &uvs, diff))\n\t\t\treturn false;\n\t}\n\telse {\n\t\tif (workNif.CalcShapeDiff(shape, &verts, diff))\n\t\t\treturn false;\n\t}\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.LoadSet(sliderData, target, diff);\n\t}\n\telse\n\t\tmorpher.SetResultDiff(target, sliderName, diff);\n\n\treturn true;\n}\n\nvoid OutfitProject::SetSliderFromBSD(const std::string& sliderName, NiShape* shape, const std::string& fileName) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.LoadSet(sliderData, target, fileName);\n\t}\n\telse {\n\t\tDiffDataSets tmpSet;\n\t\ttmpSet.LoadSet(sliderName, target, fileName);\n\t\tstd::unordered_map<uint16_t, Vector3>* diff = tmpSet.GetDiffSet(sliderName);\n\t\tmorpher.SetResultDiff(target, sliderName, (*diff));\n\t}\n}\n\nbool OutfitProject::SetSliderFromOBJ(const std::string& sliderName, NiShape* shape, const std::string& fileName) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tObjImportOptions options;\n\toptions.NoFaces = true;\n\n\tObjFile obj;\n\tobj.LoadForNif(fileName, options);\n\n\t// File needs at least one group\n\tstd::vector<std::string> groupNames = obj.GetGroupList();\n\tif (groupNames.empty())\n\t\treturn false;\n\n\t// Use first shape or shape with matching name\n\tstd::string sourceShape = groupNames.front();\n\tif (std::find(groupNames.begin(), groupNames.end(), shape->name.get()) != groupNames.end())\n\t\tsourceShape = shape->name.get();\n\n\tstd::vector<Vector3> objVerts;\n\tstd::vector<Vector2> objUVs;\n\tif (!obj.CopyDataForGroup(sourceShape, &objVerts, nullptr, &objUVs, nullptr))\n\t\treturn false;\n\n\tstd::unordered_map<uint16_t, Vector3> diff;\n\tif (activeSet[sliderName].bUV) {\n\t\tif (workNif.CalcUVDiff(shape, &objUVs, diff))\n\t\t\treturn false;\n\t}\n\telse {\n\t\tif (workNif.CalcShapeDiff(shape, &objVerts, diff, 10.0f))\n\t\t\treturn false;\n\t}\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.LoadSet(sliderData, target, diff);\n\t}\n\telse\n\t\tmorpher.SetResultDiff(target, sliderName, diff);\n\n\treturn true;\n}\n\n#ifdef USE_FBXSDK\nbool OutfitProject::SetSliderFromFBX(const std::string& sliderName, NiShape* shape, const std::string& fileName) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tFBXWrangler fbxw;\n\tbool result = fbxw.ImportScene(fileName);\n\tif (!result)\n\t\treturn 1;\n\n\tstd::vector<std::string> shapes;\n\tfbxw.GetShapeNames(shapes);\n\tbool found = false;\n\tfor (auto& s : shapes)\n\t\tif (s == shape->name.get())\n\t\t\tfound = true;\n\n\tif (!found)\n\t\treturn false;\n\n\tFBXShape* fbxShape = fbxw.GetShape(shape->name.get());\n\n\tstd::unordered_map<uint16_t, Vector3> diff;\n\tif (IsBaseShape(shape)) {\n\t\tif (workNif.CalcShapeDiff(shape, &fbxShape->verts, diff, 1.0f))\n\t\t\treturn false;\n\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.LoadSet(sliderData, target, diff);\n\t}\n\telse {\n\t\tif (workNif.CalcShapeDiff(shape, &fbxShape->verts, diff, 1.0f))\n\t\t\treturn false;\n\n\t\tmorpher.SetResultDiff(target, sliderName, diff);\n\t}\n\n\treturn true;\n}\n#endif\n\nvoid OutfitProject::SetSliderFromDiff(const std::string& sliderName, NiShape* shape, const TargetDataDiffs& diff) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tif (IsBaseShape(shape)) {\n\t\tstd::string sliderData = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.LoadSet(sliderData, target, diff);\n\t}\n\telse {\n\t\tmorpher.EmptyResultDiff(target, sliderName);\n\t\tmorpher.SetResultDiff(target, sliderName, diff);\n\t}\n}\n\nint OutfitProject::GetVertexCount(NiShape* shape) {\n\tif (workNif.IsValid()) {\n\t\tif (shape)\n\t\t\treturn shape->GetNumVertices();\n\t}\n\n\treturn 0;\n}\n\nvoid OutfitProject::GetLiveVerts(NiShape* shape, std::vector<Vector3>& outVerts, std::vector<Vector2>* outUVs) {\n\tworkNif.GetVertsForShape(shape, outVerts);\n\tif (outUVs)\n\t\tworkNif.GetUvsForShape(shape, *outUVs);\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tif (IsBaseShape(shape)) {\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tif (activeSet[i].bShow && activeSet[i].curValue != 0.0f) {\n\t\t\t\tstd::string targetData = activeSet.ShapeToDataName(i, shape->name.get());\n\t\t\t\tif (targetData.empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tif (activeSet[i].bUV) {\n\t\t\t\t\tif (outUVs)\n\t\t\t\t\t\tbaseDiffData.ApplyUVDiff(targetData, target, activeSet[i].curValue, outUVs);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tbaseDiffData.ApplyDiff(targetData, target, activeSet[i].curValue, &outVerts);\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tif (activeSet[i].bShow && activeSet[i].curValue != 0.0f) {\n\t\t\t\tif (activeSet[i].bUV) {\n\t\t\t\t\tif (outUVs)\n\t\t\t\t\t\tmorpher.ApplyResultToUVs(activeSet[i].name, target, outUVs, activeSet[i].curValue);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tmorpher.ApplyResultToVerts(activeSet[i].name, target, &outVerts, activeSet[i].curValue);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (bPose) {\n\t\tint nv = outVerts.size();\n\t\tstd::vector<Vector3> pv(nv);\n\t\tstd::vector<float> wv(nv, 0.0f);\n\t\tAnimSkin& animSkin = workAnim.shapeSkinning[shape->name.get()];\n\t\tMatTransform globalToSkin = workAnim.GetTransformGlobalToShape(shape);\n\n\t\tfor (auto& boneNamesIt : animSkin.boneNames) {\n\t\t\tAnimBone* animB = AnimSkeleton::getInstance().GetBonePtr(boneNamesIt.first);\n\t\t\tif (animB) {\n\t\t\t\tAnimWeight& animW = animSkin.boneWeights[boneNamesIt.second];\n\n\t\t\t\t// Compose transform: skin -> (posed) bone -> global -> skin\n\t\t\t\tMatTransform transform = globalToSkin.ComposeTransforms(animB->xformPoseToGlobal.ComposeTransforms(animW.xformSkinToBone));\n\t\t\t\tif (transform.IsNearlyEqualTo(MatTransform()))\n\t\t\t\t\ttransform.Clear();\n\n\t\t\t\t// Add weighted contributions to vertex for this bone\n\t\t\t\tfor (auto& wIt : animW.weights) {\n\t\t\t\t\tint ind = wIt.first;\n\t\t\t\t\tfloat w = wIt.second;\n\t\t\t\t\tpv[ind] += w * transform.ApplyTransform(outVerts[ind]);\n\t\t\t\t\twv[ind] += w;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Check if total weight for each vertex was 1\n\t\tfor (int ind = 0; ind < nv; ++ind) {\n\t\t\tif (wv[ind] < EPSILON) // If weights are missing for this vertex\n\t\t\t\tpv[ind] = outVerts[ind];\n\t\t\telse if (std::fabs(wv[ind] - 1.0f) >= EPSILON) // If weights are bad for this vertex\n\t\t\t\tpv[ind] /= wv[ind];\n\t\t\t// else do nothing because weights totaled 1.\n\n\t\t\t// New position is nearly equal to old position (reduce noise)\n\t\t\tif (pv[ind].IsNearlyEqualTo(outVerts[ind]))\n\t\t\t\tpv[ind] = outVerts[ind];\n\t\t}\n\n\t\toutVerts.swap(pv);\n\t}\n}\n\nvoid OutfitProject::GetSliderDiff(NiShape* shape, const std::string& sliderName, std::vector<Vector3>& outVerts) {\n\tsize_t sliderIndex = 0;\n\tif (!SliderIndexFromName(sliderName, sliderIndex))\n\t\treturn;\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tif (IsBaseShape(shape)) {\n\t\tstd::string targetData = activeSet.ShapeToDataName(sliderIndex, shape->name.get());\n\t\tif (targetData.empty())\n\t\t\treturn;\n\n\t\tif (!activeSet[sliderIndex].bUV)\n\t\t\tbaseDiffData.ApplyDiff(targetData, target, 1.0f, &outVerts);\n\t}\n\telse {\n\t\tif (!activeSet[sliderIndex].bUV)\n\t\t\tmorpher.ApplyResultToVerts(activeSet[sliderIndex].name, target, &outVerts);\n\t}\n}\n\nvoid OutfitProject::GetSliderDiffUV(NiShape* shape, const std::string& sliderName, std::vector<Vector2>& outUVs) {\n\tsize_t sliderIndex = 0;\n\tif (!SliderIndexFromName(sliderName, sliderIndex))\n\t\treturn;\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tif (IsBaseShape(shape)) {\n\t\tstd::string targetData = activeSet.ShapeToDataName(sliderIndex, shape->name.get());\n\t\tif (targetData.empty())\n\t\t\treturn;\n\n\t\tif (activeSet[sliderIndex].bUV)\n\t\t\tbaseDiffData.ApplyUVDiff(targetData, target, 1.0f, &outUVs);\n\t}\n\telse {\n\t\tif (activeSet[sliderIndex].bUV)\n\t\t\tmorpher.ApplyResultToUVs(activeSet[sliderIndex].name, target, &outUVs);\n\t}\n}\n\nconst std::string& OutfitProject::ShapeToTarget(const std::string& shapeName) {\n\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it)\n\t\tif (it->first == shapeName)\n\t\t\treturn it->second.targetShape;\n\n\treturn shapeName;\n}\n\nconst std::string& OutfitProject::TargetToShape(const std::string& targetName) {\n\tfor (auto it = activeSet.ShapesBegin(); it != activeSet.ShapesEnd(); ++it)\n\t\tif (it->second.targetShape == targetName)\n\t\t\treturn it->first;\n\n\treturn targetName;\n}\n\nsize_t OutfitProject::GetActiveBoneCount() {\n\treturn AnimSkeleton::getInstance().GetActiveBoneCount();\n}\n\nvoid OutfitProject::GetActiveBones(std::vector<std::string>& outBoneNames) {\n\tAnimSkeleton::getInstance().GetActiveBoneNames(outBoneNames);\n}\n\nstd::vector<std::string> OutfitProject::GetShapeTextures(NiShape* shape) {\n\tstd::string shapeName = shape->name.get();\n\n\tif (shapeTextures.find(shapeName) != shapeTextures.end())\n\t\treturn shapeTextures[shapeName];\n\n\treturn std::vector<std::string>();\n}\n\nbool OutfitProject::GetShapeMaterialFile(NiShape* shape, MaterialFile& outMatFile) {\n\tstd::string shapeName = shape->name.get();\n\n\tif (shapeMaterialFiles.find(shapeName) != shapeMaterialFiles.end()) {\n\t\toutMatFile = shapeMaterialFiles[shapeName];\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid OutfitProject::SetTextures() {\n\tfor (auto& s : workNif.GetShapes())\n\t\tSetTextures(s);\n}\n\nvoid OutfitProject::SetTextures(const std::vector<std::string>& textureFiles) {\n\tfor (auto& s : workNif.GetShapes())\n\t\tSetTextures(s, textureFiles);\n}\n\nvoid OutfitProject::SetTextures(NiShape* shape, const std::vector<std::string>& textureFiles) {\n\tif (!shape)\n\t\treturn;\n\n\tstd::string shapeName = shape->name.get();\n\tif (shapeName.empty())\n\t\treturn;\n\n\tif (textureFiles.empty()) {\n\t\tstd::string texturesDir = Config[\"GameDataPath\"];\n\t\tbool hasMat = false;\n\t\tstd::string matFile;\n\n\t\tconst uint8_t MAX_TEXTURE_PATHS = 10;\n\t\tstd::vector<std::string> texFiles(MAX_TEXTURE_PATHS);\n\n\t\tNiShader* shader = workNif.GetShader(shape);\n\t\tif (shader) {\n\t\t\t// Find material file\n\t\t\tif (workNif.GetHeader().GetVersion().IsFO4() || workNif.GetHeader().GetVersion().IsFO76()) {\n\t\t\t\tmatFile = shader->name.get();\n\t\t\t\tif (!matFile.empty())\n\t\t\t\t\thasMat = true;\n\t\t\t}\n\t\t}\n\n\t\tshapeMaterialFiles.erase(shapeName);\n\n\t\tMaterialFile mat(MaterialFile::BGSM);\n\t\tif (hasMat) {\n\t\t\t// Replace all backward slashes with one forward slash\n\t\t\tmatFile = std::regex_replace(matFile, std::regex(\"\\\\\\\\+\"), \"/\");\n\n\t\t\t// Remove everything before the first occurence of \"/materials/\"\n\t\t\tmatFile = std::regex_replace(matFile, std::regex(\"^(.*?)/materials/\", std::regex_constants::icase), \"\");\n\n\t\t\t// Remove all slashes from the front\n\t\t\tmatFile = std::regex_replace(matFile, std::regex(\"^/+\"), \"\");\n\n\t\t\t// If the path doesn't start with \"materials/\", add it to the front\n\t\t\tmatFile = std::regex_replace(matFile, std::regex(\"^(?!^materials/)\", std::regex_constants::icase), \"materials/\");\n\n\t\t\t// Attempt to read loose material file\n\t\t\tmat = MaterialFile(texturesDir + matFile);\n\n\t\t\tif (mat.Failed()) {\n\t\t\t\t// Search for material file in archives\n\t\t\t\twxMemoryBuffer data;\n\t\t\t\tfor (FSArchiveFile* archive : FSManager::archiveList()) {\n\t\t\t\t\tif (archive) {\n\t\t\t\t\t\tif (archive->hasFile(matFile)) {\n\t\t\t\t\t\t\twxMemoryBuffer outData;\n\t\t\t\t\t\t\tarchive->fileContents(matFile, outData);\n\n\t\t\t\t\t\t\tif (!outData.IsEmpty()) {\n\t\t\t\t\t\t\t\tdata = std::move(outData);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!data.IsEmpty()) {\n\t\t\t\t\tstd::string content((char*)data.GetData(), data.GetDataLen());\n\t\t\t\t\tstd::istringstream contentStream(content, std::istringstream::binary);\n\n\t\t\t\t\tmat = MaterialFile(contentStream);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!mat.Failed()) {\n\t\t\t\tif (mat.signature == MaterialFile::BGSM) {\n\t\t\t\t\ttexFiles[0] = mat.diffuseTexture.c_str();\n\t\t\t\t\ttexFiles[1] = mat.normalTexture.c_str();\n\t\t\t\t\ttexFiles[2] = mat.glowTexture.c_str();\n\t\t\t\t\ttexFiles[3] = mat.greyscaleTexture.c_str();\n\t\t\t\t\ttexFiles[4] = mat.envmapTexture.c_str();\n\t\t\t\t\ttexFiles[7] = mat.smoothSpecTexture.c_str();\n\t\t\t\t}\n\t\t\t\telse if (mat.signature == MaterialFile::BGEM) {\n\t\t\t\t\ttexFiles[0] = mat.baseTexture.c_str();\n\t\t\t\t\ttexFiles[1] = mat.fxNormalTexture.c_str();\n\t\t\t\t\ttexFiles[3] = mat.grayscaleTexture.c_str();\n\t\t\t\t\ttexFiles[4] = mat.fxEnvmapTexture.c_str();\n\t\t\t\t\ttexFiles[5] = mat.envmapMaskTexture.c_str();\n\t\t\t\t}\n\n\t\t\t\tshapeMaterialFiles[shapeName] = std::move(mat);\n\t\t\t}\n\t\t\telse if (shader) {\n\t\t\t\tfor (int i = 0; i < MAX_TEXTURE_PATHS; i++)\n\t\t\t\t\tworkNif.GetTextureSlot(shape, texFiles[i], i);\n\t\t\t}\n\t\t}\n\t\telse if (shader) {\n\t\t\tfor (int i = 0; i < MAX_TEXTURE_PATHS; i++)\n\t\t\t\tworkNif.GetTextureSlot(shape, texFiles[i], i);\n\t\t}\n\n\t\tfor (int i = 0; i < MAX_TEXTURE_PATHS; i++) {\n\t\t\tif (!texFiles[i].empty()) {\n\t\t\t\ttexFiles[i] = std::regex_replace(texFiles[i], std::regex(\"\\\\\\\\+\"), \"/\"); // Replace all backward slashes with one forward slash\n\t\t\t\ttexFiles[i] = std::regex_replace(texFiles[i],\n\t\t\t\t\t\t\t\t\t\t\t\t std::regex(\"^(.*?)/textures/\", std::regex_constants::icase),\n\t\t\t\t\t\t\t\t\t\t\t\t \"\");\t\t\t\t\t\t\t\t  // Remove everything before the first occurence of \"/textures/\"\n\t\t\t\ttexFiles[i] = std::regex_replace(texFiles[i], std::regex(\"^/+\"), \"\"); // Remove all slashes from the front\n\t\t\t\ttexFiles[i] = std::regex_replace(texFiles[i],\n\t\t\t\t\t\t\t\t\t\t\t\t std::regex(\"^(?!^textures/)\", std::regex_constants::icase),\n\t\t\t\t\t\t\t\t\t\t\t\t \"textures/\"); // If the path doesn't start with \"textures/\", add it to the front\n\n\t\t\t\ttexFiles[i] = texturesDir + texFiles[i];\n\t\t\t}\n\t\t}\n\n\t\tshapeTextures[shapeName] = texFiles;\n\t}\n\telse\n\t\tshapeTextures[shapeName] = textureFiles;\n}\n\nbool OutfitProject::IsValidShape(const std::string& shapeName) {\n\tfor (auto& s : workNif.GetShapeNames())\n\t\tif (s == shapeName)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nvoid OutfitProject::RefreshMorphShape(NiShape* shape) {\n\tmorpher.UpdateMeshFromNif(workNif, shape->name.get());\n}\n\nVector3 OutfitProject::InversePoseDiff(int vertIndex, const Vector3& diffNif, AnimSkin& animSkin, const MatTransform& globalToSkin) {\n\tMatrix3 blendedMat(0, 0, 0, 0, 0, 0, 0, 0, 0);\n\tfloat totalWeight = 0;\n\n\tfor (auto& boneNameIt : animSkin.boneNames) {\n\t\tAnimBone* animB = AnimSkeleton::getInstance().GetBonePtr(boneNameIt.first);\n\t\tif (!animB)\n\t\t\tcontinue;\n\n\t\tAnimWeight& animW = animSkin.boneWeights[boneNameIt.second];\n\t\tauto wIt = animW.weights.find(vertIndex);\n\t\tif (wIt == animW.weights.end())\n\t\t\tcontinue;\n\n\t\tfloat w = wIt->second;\n\t\tMatTransform xform = globalToSkin.ComposeTransforms(animB->xformPoseToGlobal.ComposeTransforms(animW.xformSkinToBone));\n\n\t\tfor (int r = 0; r < 3; r++)\n\t\t\tfor (int c = 0; c < 3; c++)\n\t\t\t\tblendedMat[r][c] += w * xform.rotation[r][c] * xform.scale;\n\n\t\ttotalWeight += w;\n\t}\n\n\tif (totalWeight >= EPSILON) {\n\t\tMatrix3 invMat;\n\t\tif (blendedMat.Invert(&invMat))\n\t\t\treturn invMat * diffNif;\n\t}\n\n\treturn diffNif;\n}\n\nvoid OutfitProject::UpdateShapeFromMesh(NiShape* shape, const Mesh* m) {\n\tif (bPose) {\n\t\t// When posed, m->verts are in posed mesh space. We need to compute\n\t\t// the delta between current posed verts and original posed positions,\n\t\t// then un-pose those deltas and apply them to the NIF rest positions.\n\t\tstd::vector<Vector3> restVerts;\n\t\tworkNif.GetVertsForShape(shape, restVerts);\n\n\t\tstd::vector<Vector3> posedVerts;\n\t\tGetLiveVerts(shape, posedVerts);\n\n\t\tAnimSkin& animSkin = workAnim.shapeSkinning[shape->name.get()];\n\t\tMatTransform globalToSkin = workAnim.GetTransformGlobalToShape(shape);\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tVector3 meshVertNif = Mesh::TransformPosMeshToNif(m->verts[i]);\n\t\t\tVector3 deltaPosed = meshVertNif - posedVerts[i];\n\n\t\t\tif (deltaPosed.IsZero())\n\t\t\t\tcontinue;\n\n\t\t\trestVerts[i] += InversePoseDiff(i, deltaPosed, animSkin, globalToSkin);\n\t\t}\n\n\t\tworkNif.SetVertsForShape(shape, restVerts);\n\t}\n\telse {\n\t\tstd::vector<Vector3> liveVerts(m->nVerts);\n\n\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\tliveVerts[i] = Mesh::TransformPosMeshToNif(m->verts[i]);\n\n\t\tworkNif.SetVertsForShape(shape, liveVerts);\n\t}\n}\n\nvoid OutfitProject::UndoPoseDiffs(NiShape* shape, std::unordered_map<uint16_t, Vector3>& diffs) {\n\tif (!bPose)\n\t\treturn;\n\n\tAnimSkin& animSkin = workAnim.shapeSkinning[shape->name.get()];\n\tMatTransform globalToSkin = workAnim.GetTransformGlobalToShape(shape);\n\n\tfor (auto& d : diffs) {\n\t\tVector3 diffNif = Mesh::TransformDiffMeshToNif(d.second);\n\t\tdiffNif = InversePoseDiff(d.first, diffNif, animSkin, globalToSkin);\n\t\td.second = Mesh::TransformDiffNifToMesh(diffNif);\n\t}\n}\n\nvoid OutfitProject::ComputeUndoRestDiffs(NiShape* shape, UndoStateShape& uss) {\n\tif (!uss.restDiffs.empty())\n\t\treturn;\n\n\tAnimSkin& animSkin = workAnim.shapeSkinning[shape->name.get()];\n\tMatTransform globalToSkin = workAnim.GetTransformGlobalToShape(shape);\n\n\tfor (auto& ps : uss.pointStartState) {\n\t\tauto pe = uss.pointEndState.find(ps.first);\n\t\tif (pe == uss.pointEndState.end())\n\t\t\tcontinue;\n\n\t\tVector3 diffMesh = pe->second - ps.second;\n\t\tVector3 diffNif = Mesh::TransformDiffMeshToNif(diffMesh);\n\t\tif (bPose)\n\t\t\tdiffNif = InversePoseDiff(ps.first, diffNif, animSkin, globalToSkin);\n\t\tuss.restDiffs[ps.first] = diffNif;\n\t}\n}\n\nvoid OutfitProject::UpdateMorphResult(NiShape* shape, const std::string& sliderName, const TargetDataDiffs& vertUpdates) {\n\t// Morph results are stored in two different places depending on whether it's an outfit or the base shape.\n\t// The outfit morphs are stored in the automorpher, whereas the base shape diff info is stored in directly in basediffdata.\n\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tstd::string dataName = activeSet[sliderName].TargetDataName(target);\n\tif (!vertUpdates.empty()) {\n\t\tif (dataName.empty())\n\t\t\tactiveSet[sliderName].AddDataFile(target, target + sliderName, target + sliderName);\n\t\telse\n\t\t\tactiveSet[sliderName].SetLocalData(dataName);\n\t}\n\n\tif (IsBaseShape(shape)) {\n\t\tfor (auto& i : vertUpdates) {\n\t\t\tVector3 diffscale = Mesh::TransformDiffMeshToNif(i.second);\n\t\t\tbaseDiffData.SumDiff(dataName, target, i.first, diffscale);\n\t\t}\n\t}\n\telse\n\t\tmorpher.UpdateResultDiff(shape->name.get(), sliderName, vertUpdates);\n}\n\nvoid OutfitProject::ScaleMorphResult(NiShape* shape, const std::string& sliderName, float scaleValue) {\n\tif (IsBaseShape(shape)) {\n\t\tstd::string target = ShapeToTarget(shape->name.get());\n\t\tstd::string dataName = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.ScaleDiff(dataName, target, scaleValue);\n\t}\n\telse\n\t\tmorpher.ScaleResultDiff(shape->name.get(), sliderName, scaleValue);\n}\n\nvoid OutfitProject::MoveVertex(NiShape* shape, const Vector3& pos, const int& id) {\n\tworkNif.MoveVertex(shape, pos, id);\n}\n\nvoid OutfitProject::OffsetShape(NiShape* shape, const Vector3& xlate, std::unordered_map<uint16_t, float>* mask) {\n\tworkNif.OffsetShape(shape, xlate, mask);\n}\n\nvoid OutfitProject::ScaleShape(NiShape* shape, const Vector3& scale, std::unordered_map<uint16_t, float>* mask) {\n\tworkNif.ScaleShape(shape, scale, mask);\n}\n\nvoid OutfitProject::RotateShape(NiShape* shape, const Vector3& angle, std::unordered_map<uint16_t, float>* mask) {\n\tworkNif.RotateShape(shape, angle, mask);\n}\n\nvoid OutfitProject::ApplyTransformToShapeGeometry(NiShape* shape, const MatTransform& t) {\n\tif (!shape)\n\t\treturn;\n\n\t// Vertices\n\tconst std::vector<Vector3>* oldVerts = workNif.GetVertsForShape(shape);\n\tif (!oldVerts || oldVerts->empty())\n\t\treturn;\n\n\tsize_t nVerts = oldVerts->size();\n\tstd::vector<Vector3> verts(nVerts);\n\tfor (size_t i = 0; i < nVerts; ++i)\n\t\tverts[i] = t.ApplyTransform((*oldVerts)[i]);\n\n\tworkNif.SetVertsForShape(shape, verts);\n\n\t// Position diffs\n\tfor (size_t si = 0; si < activeSet.size(); ++si) {\n\t\tSliderData& sd = activeSet[si];\n\t\tif (sd.bUV || sd.bClamp || sd.bZap)\n\t\t\tcontinue;\n\n\t\tstd::unordered_map<uint16_t, Vector3>* diffSet = GetDiffSet(sd,  shape);\n\t\tif (!diffSet)\n\t\t\tcontinue;\n\n\t\tfor (auto& diffp : *diffSet)\n\t\t\tdiffp.second = t.ApplyTransformToDiff(diffp.second);\n\t}\n\n\t// Normals\n\tif (t.rotation.IsNearlyEqualTo(Matrix3()))\n\t\treturn;\n\n\tconst std::vector<Vector3>* oldNorms = workNif.GetNormalsForShape(shape);\n\tif (!oldNorms || oldNorms->size() != nVerts)\n\t\treturn;\n\n\tstd::vector<Vector3> norms(nVerts);\n\tfor (size_t i = 0; i < nVerts; ++i)\n\t\tnorms[i] = t.ApplyTransformToDir((*oldNorms)[i]);\n\n\tworkNif.SetNormalsForShape(shape, norms);\n}\n\nvoid OutfitProject::CopyBoneWeights(NiShape* shape,\n\t\t\t\t\t\t\t\t\tconst float proximityRadius,\n\t\t\t\t\t\t\t\t\tconst int maxResults,\n\t\t\t\t\t\t\t\t\tstd::unordered_map<uint16_t, float>& mask,\n\t\t\t\t\t\t\t\t\tconst std::vector<std::string>& boneList,\n\t\t\t\t\t\t\t\t\tint nCopyBones,\n\t\t\t\t\t\t\t\t\tconst std::vector<std::string>& lockedBones,\n\t\t\t\t\t\t\t\t\tUndoStateShape& uss,\n\t\t\t\t\t\t\t\t\tbool bSpreadWeight) {\n\tif (!shape || !baseShape)\n\t\treturn;\n\n\tstd::string shapeName = shape->name.get();\n\tstd::string baseShapeName = baseShape->name.get();\n\n\tUpdateProgress(1, _(\"Gathering bones...\"));\n\n\tint nBones = boneList.size();\n\tif (nBones <= 0 || nCopyBones <= 0) {\n\t\tUpdateProgress(90);\n\t\treturn;\n\t}\n\n\tDiffDataSets dds;\n\tfor (int bi = 0; bi < nCopyBones; ++bi) {\n\t\tconst std::string& bone = boneList[bi];\n\t\tstd::string wtSet = bone + \"_WT_\";\n\t\tdds.AddEmptySet(wtSet, \"Weight\");\n\n\t\tauto weights = workAnim.GetWeightsPtr(baseShapeName, bone);\n\t\tif (weights) {\n\t\t\tfor (auto& w : *weights) {\n\t\t\t\tVector3 tmp;\n\t\t\t\ttmp.y = w.second;\n\t\t\t\tdds.UpdateDiff(wtSet, \"Weight\", w.first, tmp);\n\t\t\t}\n\t\t}\n\t}\n\n\tBoneWeightAutoNormalizer nzer;\n\tnzer.SetUp(&uss, &workAnim, shapeName, boneList, lockedBones, nCopyBones, bSpreadWeight);\n\tstd::unordered_set<int> vertList;\n\n\tUpdateProgress(10, _(\"Initializing proximity data...\"));\n\n\tInitConform();\n\tmorpher.LinkRefDiffData(&dds);\n\tmorpher.BuildProximityCache(shapeName, proximityRadius);\n\tCreateSkinning(shape);\n\n\tint step = 40 / nCopyBones;\n\tint prog = 40;\n\tUpdateProgress(prog);\n\n\tfor (int bi = 0; bi < nCopyBones; ++bi) {\n\t\tconst std::string& boneName = boneList[bi];\n\t\tauto& ubw = uss.boneWeights[bi].weights;\n\t\t// Zero out unmasked weights\n\t\tauto weights = workAnim.GetWeightsPtr(shapeName, boneName);\n\t\tif (weights) {\n\t\t\tfor (auto& pi : *weights) {\n\t\t\t\tif (mask[pi.first] > 0.0f)\n\t\t\t\t\tcontinue;\n\t\t\t\tif (vertList.find(pi.first) == vertList.end()) {\n\t\t\t\t\tvertList.insert(pi.first);\n\t\t\t\t\tnzer.GrabOneVertexStartingWeights(pi.first);\n\t\t\t\t}\n\t\t\t\tubw[pi.first].endVal = 0.0;\n\t\t\t}\n\t\t}\n\n\t\t// Calculate new values for bone's weights\n\t\tstd::string wtSet = boneName + \"_WT_\";\n\t\tmorpher.GenerateResultDiff(shapeName, wtSet, wtSet, false, maxResults);\n\n\t\tstd::unordered_map<uint16_t, Vector3> diffResult;\n\t\tmorpher.GetRawResultDiff(shapeName, wtSet, diffResult);\n\n\t\t// Copy unmasked weights from diffResult into uss\n\t\tfor (auto& dr : diffResult) {\n\t\t\tif (mask[dr.first] > 0.0f)\n\t\t\t\tcontinue;\n\t\t\tif (vertList.find(dr.first) == vertList.end()) {\n\t\t\t\tvertList.insert(dr.first);\n\t\t\t\tnzer.GrabOneVertexStartingWeights(dr.first);\n\t\t\t}\n\t\t\tubw[dr.first].endVal = dr.second.y;\n\t\t}\n\n\t\tUpdateProgress(prog += step, _(\"Copying bone weights...\"));\n\t}\n\tmorpher.UnlinkRefDiffData();\n\n\t// Normalize\n\tfor (auto vInd : vertList)\n\t\tnzer.AdjustWeights(vInd);\n\n\tUpdateProgress(90);\n}\n\nvoid OutfitProject::TransferSelectedWeights(NiShape* shape, std::unordered_map<uint16_t, float>* mask, std::vector<std::string>* inBoneList) {\n\tif (!shape || !baseShape)\n\t\treturn;\n\n\tstd::string shapeName = shape->name.get();\n\tstd::string baseShapeName = baseShape->name.get();\n\n\tUpdateProgress(10, _(\"Gathering bones...\"));\n\n\tstd::vector<std::string>* boneList;\n\tstd::vector<std::string> allBoneList;\n\tif (!inBoneList) {\n\t\tfor (auto& boneName : workAnim.shapeBones[baseShapeName])\n\t\t\tallBoneList.push_back(boneName);\n\n\t\tboneList = &allBoneList;\n\t}\n\telse\n\t\tboneList = inBoneList;\n\n\tif (boneList->size() <= 0) {\n\t\tUpdateProgress(100, _(\"Finished\"));\n\t\treturn;\n\t}\n\n\tint step = 50 / boneList->size();\n\tint prog = 40;\n\tUpdateProgress(prog, _(\"Transferring bone weights...\"));\n\n\tfor (auto& boneName : *boneList) {\n\t\tstd::unordered_map<uint16_t, float> weights;\n\t\tstd::unordered_map<uint16_t, float> oldWeights;\n\t\tworkAnim.GetWeights(baseShapeName, boneName, weights);\n\t\tworkAnim.GetWeights(shapeName, boneName, oldWeights);\n\n\t\tfor (auto& w : weights) {\n\t\t\tif (mask) {\n\t\t\t\tif (1.0f - (*mask)[w.first] > 0.0f)\n\t\t\t\t\tweights[w.first] = w.second * (1.0f - (*mask)[w.first]);\n\t\t\t\telse\n\t\t\t\t\tweights[w.first] = oldWeights[w.first];\n\t\t\t}\n\t\t\telse\n\t\t\t\tweights[w.first] = w.second;\n\t\t}\n\n\t\tworkAnim.AddShapeBone(shapeName, boneName);\n\t\tworkAnim.SetWeights(shapeName, boneName, weights);\n\t\tUpdateProgress(prog += step, \"\");\n\t}\n\n\tUpdateProgress(100, _(\"Finished\"));\n}\n\nbool OutfitProject::HasUnweighted(std::vector<std::string>* shapeNames) {\n\tbool hasUnweighted = false;\n\n\tfor (auto& shape : workNif.GetShapes()) {\n\t\tif (!shape || !shape->IsSkinned())\n\t\t\tcontinue;\n\n\t\tstd::string shapeName = shape->name.get();\n\t\tstd::vector<Vector3> verts;\n\t\tworkNif.GetVertsForShape(shape, verts);\n\n\t\tstd::unordered_map<int, int> influences;\n\t\tfor (size_t i = 0; i < verts.size(); i++)\n\t\t\tinfluences.emplace(i, 0);\n\n\t\tif (workAnim.shapeBones.find(shapeName) != workAnim.shapeBones.end()) {\n\t\t\tfor (auto& b : workAnim.shapeBones[shapeName]) {\n\t\t\t\tauto weights = workAnim.GetWeightsPtr(shapeName, b);\n\t\t\t\tif (weights) {\n\t\t\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\t\t\tauto id = weights->find(i);\n\t\t\t\t\t\tif (id != weights->end() && id->second > 0.0f)\n\t\t\t\t\t\t\tinfluences.at(i)++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbool shapeUnweighted = false;\n\t\tMesh* m = owner->glView->GetMesh(shapeName);\n\t\tif (m) {\n\t\t\tfor (auto& i : influences) {\n\t\t\t\tif (i.second == 0) {\n\t\t\t\t\tif (!shapeUnweighted)\n\t\t\t\t\t\tm->MaskFill(0.0f);\n\n\t\t\t\t\tm->mask[i.first] = 1.0f;\n\t\t\t\t\tshapeUnweighted = true;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (shapeUnweighted) {\n\t\t\t\thasUnweighted = true;\n\n\t\t\t\tif (shapeNames)\n\t\t\t\t\tshapeNames->push_back(shapeName);\n\t\t\t}\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Mask);\n\t\t}\n\t}\n\n\treturn hasUnweighted;\n}\n\nvoid OutfitProject::AddBoneRef(const std::string& boneName) {\n\tfor (auto& s : workNif.GetShapeNames())\n\t\tworkAnim.AddShapeBone(s, boneName);\n}\n\nvoid OutfitProject::AddCustomBoneRef(const std::string& boneName, const std::string& parentBone, const MatTransform& xformToParent) {\n\tAnimBone& customBone = AnimSkeleton::getInstance().AddCustomBone(boneName);\n\tcustomBone.SetTransformBoneToParent(xformToParent);\n\tcustomBone.SetParentBone(AnimSkeleton::getInstance().GetBonePtr(parentBone));\n\n\tfor (auto& s : workNif.GetShapeNames())\n\t\tworkAnim.AddShapeBone(s, boneName);\n}\n\nvoid OutfitProject::ModifyCustomBone(AnimBone* bPtr, const std::string& parentBone, const MatTransform& xformToParent) {\n\tbPtr->SetTransformBoneToParent(xformToParent);\n\tbPtr->SetParentBone(AnimSkeleton::getInstance().GetBonePtr(parentBone));\n\n\tfor (auto& s : workNif.GetShapeNames())\n\t\tworkAnim.RecursiveRecalcXFormSkinToBone(s, bPtr);\n}\n\nint OutfitProject::CopySegPart(NiShape* shape) {\n\t// Gather baseShape's triangles and vertices\n\tstd::vector<Triangle> tris;\n\tbaseShape->GetTriangles(tris);\n\tstd::vector<Vector3> verts;\n\tworkNif.GetVertsForShape(baseShape, verts);\n\n\t// Transform baseShape vertices to nif global coordinates\n\tMatTransform xformToGlobal = workAnim.GetTransformShapeToGlobal(baseShape);\n\tfor (Vector3& v : verts)\n\t\tv = xformToGlobal.ApplyTransform(v);\n\n\t// Calculate center of each triangle (times 3)\n\tstd::vector<Vector3> tricenters(tris.size());\n\tfor (size_t ti = 0; ti < tris.size(); ++ti)\n\t\ttricenters[ti] = verts[tris[ti].p1] + verts[tris[ti].p2] + verts[tris[ti].p3];\n\n\t// Build proximity cache for triangle centers of baseShape.\n\t// Note that kd_tree keeps pointers into tricenters.\n\tkd_tree<uint32_t> refTree(&tricenters[0], tricenters.size());\n\n\t// Get baseShape's segment/partition data\n\tstd::vector<int> bstriParts;\n\tNifSegmentationInfo inf;\n\tbool gotsegs = workNif.GetShapeSegments(baseShape, inf, bstriParts);\n\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\tbool gotparts = false;\n\tif (!gotsegs)\n\t\tgotparts = workNif.GetShapePartitions(baseShape, partitionInfo, bstriParts);\n\n\t// Gather shape's triangles and vertices\n\tshape->GetTriangles(tris);\n\tworkNif.GetVertsForShape(shape, verts);\n\n\t// Transform shape's vertices to nif global coordinates\n\txformToGlobal = workAnim.GetTransformShapeToGlobal(shape);\n\tfor (Vector3& v : verts)\n\t\tv = xformToGlobal.ApplyTransform(v);\n\n\t// Calculate new partition/segment for each triangle\n\tstd::vector<int> triParts(tris.size());\n\tint failcount = 0;\n\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\t// Calculate center of triangle (times 3)\n\t\tVector3 tricenter = verts[tris[ti].p1] + verts[tris[ti].p2] + verts[tris[ti].p3];\n\n\t\t// Find closest triangle center in proximity cache.\n\t\tuint32_t resultcount = refTree.kd_nn(&tricenter, 0);\n\t\tif (resultcount < 1) {\n\t\t\t++failcount;\n\t\t\ttriParts[ti] = -1;\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Look up closest triangle and copy its partition/segment ID.\n\t\tsize_t bti = refTree.queryResult[0].vertex_index;\n\t\ttriParts[ti] = bstriParts[bti];\n\t\tif (triParts[ti] == -1)\n\t\t\t++failcount;\n\t}\n\n\t// Refuse to continue if we have any triangles without segments/partitions.\n\tif (failcount)\n\t\treturn failcount;\n\n\t// Store new information in NIF.\n\tif (gotsegs)\n\t\tworkNif.SetShapeSegments(shape, inf, triParts);\n\n\tif (gotparts) {\n\t\tworkNif.SetShapePartitions(shape, partitionInfo, triParts);\n\t\tworkNif.RemoveEmptyPartitions(shape);\n\t}\n\n\treturn 0;\n}\n\nvoid OutfitProject::ClearWorkSliders() {\n\tmorpher.ClearResultDiff();\n}\n\nvoid OutfitProject::ClearReference() {\n\tDeleteShape(baseShape);\n\n\tif (activeSet.size() > 0)\n\t\tactiveSet.Clear();\n}\n\nvoid OutfitProject::ClearOutfit() {\n\tfor (auto& s : workNif.GetShapes()) {\n\t\tif (IsBaseShape(s))\n\t\t\tcontinue;\n\n\t\tDeleteShape(s);\n\t}\n\tClearWorkSliders();\n}\n\nvoid OutfitProject::ClearSlider(NiShape* shape, const std::string& sliderName) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string data = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.EmptySet(data, target);\n\t}\n\telse\n\t\tmorpher.EmptyResultDiff(target, sliderName);\n}\n\nvoid OutfitProject::ClearUnmaskedDiff(NiShape* shape, const std::string& sliderName, std::unordered_map<uint16_t, float>* mask) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tif (IsBaseShape(shape)) {\n\t\tstd::string data = activeSet[sliderName].TargetDataName(target);\n\t\tbaseDiffData.ZeroVertDiff(data, target, nullptr, mask);\n\t}\n\telse\n\t\tmorpher.ZeroVertDiff(target, sliderName, nullptr, mask);\n}\n\nvoid OutfitProject::DeleteSlider(const std::string& sliderName) {\n\tfor (auto& s : workNif.GetShapes()) {\n\t\tstd::string target = ShapeToTarget(s->name.get());\n\t\tstd::string data = activeSet[sliderName].TargetDataName(target);\n\n\t\tif (IsBaseShape(s))\n\t\t\tbaseDiffData.ClearSet(data);\n\t\telse\n\t\t\tmorpher.ClearResultSet(data);\n\t}\n\n\tactiveSet.DeleteSlider(sliderName);\n}\n\nint OutfitProject::LoadSkeletonReference(const std::string& skeletonFileName) {\n\treturn AnimSkeleton::getInstance().LoadFromNif(skeletonFileName);\n}\n\nint OutfitProject::LoadReferenceTemplate(\n\tconst std::string& sourceFile, const std::string& set, const std::string& shape, bool loadAll, bool mergeSliders, bool mergeZaps, bool appendNewSliders) {\n\tif (sourceFile.empty() || set.empty()) {\n\t\twxLogError(\"Template source entries are invalid.\");\n\t\twxMessageBox(_(\"Template source entries are invalid.\"), _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\treturn 1;\n\t}\n\n\tif (loadAll) {\n\t\towner->StartSubProgress(10, 20);\n\t\treturn AddFromSliderSet(sourceFile, set, false, appendNewSliders);\n\t}\n\telse\n\t\treturn LoadReference(sourceFile, set, shape, mergeSliders, mergeZaps, appendNewSliders);\n}\n\nint OutfitProject::LoadReferenceNif(const std::string& fileName, const std::string& shapeName, bool mergeSliders, bool mergeZaps) {\n\tif (mergeZaps || mergeSliders) {\n\t\towner->DeleteSliders(mergeSliders, mergeZaps);\n\t\tDeleteShape(baseShape);\n\t}\n\telse\n\t\tClearReference();\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);\n\n\tNifFile refNif;\n\tint error = refNif.Load(file);\n\tif (error) {\n\t\tif (error == 2) {\n\t\t\twxString errorText = wxString::Format(_(\"NIF version not supported!\\n\\nFile: %s\\n%s\"), fileName, refNif.GetHeader().GetVersion().GetVersionInfo());\n\n\t\t\twxLogError(errorText);\n\t\t\twxMessageBox(errorText, _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\t\treturn 3;\n\t\t}\n\n\t\twxLogError(\"Could not load reference NIF file '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Could not load reference NIF file '%s'!\"), fileName), _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\treturn 2;\n\t}\n\n\tValidateNIF(refNif, fileName);\n\n\tstd::vector<std::string> deletedShapes;\n\n\tauto refShapeDup = workNif.FindBlockByName<NiShape>(shapeName);\n\tauto refShape = refNif.FindBlockByName<NiShape>(shapeName);\n\tif (refShapeDup && refShape) {\n\t\t// Delete shape with identical name\n\t\tDeleteShape(refShapeDup);\n\t\tdeletedShapes.push_back(shapeName);\n\t}\n\n\tif (workNif.IsValid()) {\n\t\t// Copy only reference shape\n\t\tauto clonedShape = workNif.CloneShape(refShape, shapeName, &refNif);\n\t\tworkAnim.LoadFromNif(&workNif, clonedShape);\n\t}\n\telse {\n\t\t// Copy the full file\n\t\tworkNif.CopyFrom(refNif);\n\t\tworkAnim.LoadFromNif(&workNif);\n\n\t\t// Delete all except for reference\n\t\tfor (auto& s : workNif.GetShapes())\n\t\t\tif (s->name != shapeName)\n\t\t\t\tDeleteShape(s);\n\t}\n\n\tbaseShape = workNif.FindBlockByName<NiShape>(shapeName);\n\tactiveSet.LoadSetDiffData(baseDiffData);\n\n\t// Clear reference source info (NIF-only reference, no OSP available)\n\tmRefProjectFile.clear();\n\tmRefProjectName.clear();\n\tmRefShapeName.clear();\n\n\tif (!deletedShapes.empty()) {\n\t\tstd::string shapesJoin = JoinStrings(deletedShapes, \"; \");\n\t\twxMessageBox(wxString::Format(\"%s\\n \\n%s\", _(\"The following shapes were deleted. Rename the duplicates yourself beforehand if you wish to keep them.\"), shapesJoin),\n\t\t\t\t\t _(\"Deleted Shapes\"),\n\t\t\t\t\t wxOK | wxICON_WARNING,\n\t\t\t\t\t owner);\n\t}\n\n\treturn 0;\n}\n\nint OutfitProject::LoadReference(const std::string& fileName, const std::string& setName, const std::string& shapeName, bool mergeSliders, bool mergeZaps, bool appendNewSliders) {\n\tif (mergeZaps || mergeSliders) {\n\t\towner->DeleteSliders(mergeSliders, mergeZaps);\n\t\tDeleteShape(baseShape);\n\t}\n\telse\n\t\tClearReference();\n\n\tSliderSetFile sset(fileName);\n\tif (sset.fail()) {\n\t\twxLogError(\"Could not load slider set file '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Could not load slider set file '%s'!\"), fileName), _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\treturn 1;\n\t}\n\n\tstd::string dataFolder = activeSet.GetDefaultDataFolder();\n\tstd::vector<std::string> dataNames = activeSet.GetLocalData(shapeName);\n\n\tsset.GetSet(setName, activeSet, appendNewSliders);\n\n\tactiveSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\tstd::string refFile = activeSet.GetInputFileName();\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, refFile, std::ios::in | std::ios::binary);\n\n\tNifFile refNif;\n\tint error = refNif.Load(file);\n\tif (error) {\n\t\tif (error == 2) {\n\t\t\twxString errorText = wxString::Format(_(\"NIF version not supported!\\n\\nFile: %s\\n%s\"), refFile, refNif.GetHeader().GetVersion().GetVersionInfo());\n\n\t\t\twxLogError(errorText);\n\t\t\twxMessageBox(errorText, _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\t\tClearReference();\n\t\t\treturn 5;\n\t\t}\n\n\t\tClearReference();\n\t\twxLogError(\"Could not load reference NIF file '%s'!\", refFile);\n\t\twxMessageBox(wxString::Format(_(\"Could not load reference NIF file '%s'!\"), refFile), _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\treturn 2;\n\t}\n\n\tValidateNIF(refNif, refFile);\n\n\tstd::vector<std::string> shapes = refNif.GetShapeNames();\n\tif (shapes.empty()) {\n\t\tClearReference();\n\t\twxLogError(\"Reference NIF file '%s' does not contain any shapes.\", refFile);\n\t\twxMessageBox(wxString::Format(_(\"Reference NIF file '%s' does not contain any shapes.\"), refFile), _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\treturn 3;\n\t}\n\n\tstd::string shape = shapeName;\n\tif (shape.empty())\n\t\tshape = shapes[0];\n\n\tauto refShape = refNif.FindBlockByName<NiShape>(shape);\n\tif (!refShape) {\n\t\tClearReference();\n\t\twxLogError(\"Shape '%s' not found in reference NIF file '%s'!\", shape, refFile);\n\t\twxMessageBox(wxString::Format(_(\"Shape '%s' not found in reference NIF file '%s'!\"), shape, refFile), _(\"Reference Error\"), wxICON_ERROR, owner);\n\t\treturn 4;\n\t}\n\n\tstd::vector<std::string> deletedShapes;\n\n\tauto refShapeDup = workNif.FindBlockByName<NiShape>(shape);\n\tif (refShapeDup) {\n\t\t// Delete shape with identical name\n\t\tDeleteShape(refShapeDup);\n\t\tdeletedShapes.push_back(shape);\n\t}\n\n\t// Add cloth data block of NIF to the list\n\tstd::vector<BSClothExtraData*> clothDataBlocks = refNif.GetChildren<BSClothExtraData>(nullptr, true);\n\tfor (auto& cloth : clothDataBlocks)\n\t\tclothData[refFile] = cloth->Clone();\n\n\trefNif.GetHeader().DeleteBlockByType(\"BSClothExtraData\");\n\n\tif (workNif.IsValid()) {\n\t\t// Copy only reference shape\n\t\tauto clonedShape = workNif.CloneShape(refShape, shape, &refNif);\n\t\tworkAnim.LoadFromNif(&workNif, clonedShape);\n\t}\n\telse {\n\t\t// Copy the full file\n\t\tworkNif.CopyFrom(refNif);\n\t\tworkAnim.LoadFromNif(&workNif);\n\n\t\t// Delete all except for reference\n\t\tfor (auto& s : workNif.GetShapes())\n\t\t\tif (s->name != shape)\n\t\t\t\tDeleteShape(s);\n\t}\n\n\tbaseShape = workNif.FindBlockByName<NiShape>(shape);\n\n\tif (mergeSliders)\n\t\tactiveSet.LoadSetDiffData(baseDiffData, shape);\n\telse\n\t\tactiveSet.LoadSetDiffData(baseDiffData);\n\n\tbool hadLocalData = false;\n\tactiveSet.SetReferencedData(shape, false, &hadLocalData);\n\tfor (auto& dn : dataNames)\n\t\tactiveSet.SetReferencedDataByName(shape, dn, true);\n\n\tstd::string refDataFolder = activeSet.GetDefaultDataFolder();\n\tif (hadLocalData && !refDataFolder.empty() && refDataFolder != dataFolder) {\n\t\t// Add data folder of reference to list of data folders of new reference target\n\t\tstd::string targetName = ShapeToTarget(shapeName);\n\t\tactiveSet.AddTargetDataFolder(targetName, refDataFolder);\n\t}\n\n\t// Keep default data folder from current project if existing\n\tif (!dataFolder.empty())\n\t\tactiveSet.SetDataFolder(dataFolder);\n\n\t// Remember reference source info for saved projects\n\t{\n\t\twxFileName refFileName(wxString::FromUTF8(fileName));\n\t\tif (refFileName.IsRelative())\n\t\t\trefFileName.MakeAbsolute(wxString::FromUTF8(GetProjectPath()));\n\n\t\tif (refFileName.MakeRelativeTo(wxString::FromUTF8(GetProjectPath())))\n\t\t\tmRefProjectFile = refFileName.GetFullPath().ToUTF8().data();\n\t\telse\n\t\t\tmRefProjectFile = fileName;\n\n\t\tmRefProjectName = setName;\n\t\tmRefShapeName = shape;\n\t}\n\n\tif (!deletedShapes.empty()) {\n\t\tstd::string shapesJoin = JoinStrings(deletedShapes, \"; \");\n\t\twxMessageBox(wxString::Format(\"%s\\n \\n%s\",\n\t\t\t\t\t\t\t\t\t  _(\"The following shapes were deleted. Rename the duplicates yourself beforehand if you wish to keep them.\"),\n\t\t\t\t\t\t\t\t\t  shapesJoin),\n\t\t\t\t\t _(\"Deleted Shapes\"),\n\t\t\t\t\t wxOK | wxICON_WARNING,\n\t\t\t\t\t owner);\n\t}\n\n\treturn 0;\n}\n\nint OutfitProject::LoadFromSliderSet(const std::string& fileName, const std::string& sliderSetName, std::vector<std::string>* origShapeOrder) {\n\towner->StartProgress(_(\"Loading slider set...\"));\n\tSliderSetFile InSS(fileName);\n\tif (InSS.fail()) {\n\t\towner->EndProgress();\n\t\treturn 1;\n\t}\n\n\tUpdateProgress(20, _(\"Retrieving sliders...\"));\n\tif (InSS.GetSet(sliderSetName, activeSet)) {\n\t\towner->EndProgress();\n\t\treturn 3;\n\t}\n\n\tactiveSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\n\tstd::string inputNif = activeSet.GetInputFileName();\n\n\tUpdateProgress(30, _(\"Loading outfit shapes...\"));\n\tif (ImportNIF(inputNif, true, sliderSetName)) {\n\t\towner->EndProgress();\n\t\treturn 4;\n\t}\n\n\tif (origShapeOrder)\n\t\t*origShapeOrder = workNif.GetShapeNames();\n\n\tNiShape* newBaseShape = nullptr;\n\n\t// First external target with skin shader becomes reference\n\tstd::vector<std::string> refTargets;\n\tactiveSet.GetReferencedTargets(refTargets);\n\tfor (auto& target : refTargets) {\n\t\tstd::string shapeName = activeSet.TargetToShape(target);\n\t\tauto shape = workNif.FindBlockByName<NiShape>(shapeName);\n\t\tif (shape) {\n\t\t\tNiShader* shader = workNif.GetShader(shape);\n\t\t\tif (shader && shader->IsSkinTinted()) {\n\t\t\t\tnewBaseShape = shape;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// No external target found, first skin shaded shape becomes reference\n\tif (refTargets.empty()) {\n\t\tfor (auto shapeTarget = activeSet.ShapesBegin(); shapeTarget != activeSet.ShapesEnd(); ++shapeTarget) {\n\t\t\tauto shape = workNif.FindBlockByName<NiShape>(shapeTarget->first);\n\t\t\tif (shape) {\n\t\t\t\tNiShader* shader = workNif.GetShader(shape);\n\t\t\t\tif (shader && shader->IsSkinTinted()) {\n\t\t\t\t\tnewBaseShape = shape;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Store base shape for later deletion\n\tbaseShape = newBaseShape;\n\n\tUpdateProgress(90, _(\"Updating slider data...\"));\n\tmorpher.LoadResultDiffs(activeSet);\n\n\twxString rest;\n\tmFileName = wxString::FromUTF8(fileName);\n\tif (mFileName.EndsWith(\".xml\", &rest))\n\t\tmFileName = rest.Append(\".osp\");\n\n\tmOutfitName = wxString::FromUTF8(sliderSetName);\n\tmDataDir = wxString::FromUTF8(activeSet.GetDefaultDataFolder());\n\tmBaseFile = wxString::FromUTF8(activeSet.GetInputFileName());\n\tmBaseFile = mBaseFile.AfterLast('/').AfterLast('\\\\');\n\n\tmGamePath = wxString::FromUTF8(activeSet.GetOutputPath());\n\tmGameFile = wxString::FromUTF8(activeSet.GetOutputFile());\n\tmCopyRef = true;\n\tmGenWeights = activeSet.GenWeights();\n\tbPreventMorphFile = activeSet.PreventMorphFile();\n\tbKeepZappedShapes = activeSet.KeepZappedShapes();\n\n\t// Preserve reference info from the loaded project so it gets saved again\n\tif (activeSet.HasReferenceInfo()) {\n\t\tmRefProjectFile = activeSet.GetReferenceProjectFile();\n\t\tmRefProjectName = activeSet.GetReferenceProjectName();\n\t\tmRefShapeName = activeSet.GetReferenceShapeName();\n\t}\n\n\towner->EndProgress();\n\treturn 0;\n}\n\nint OutfitProject::AddFromSliderSet(const std::string& fileName, const std::string& sliderSetName, const bool newDataLocal, const bool appendNewSliders) {\n\towner->StartProgress(_(\"Adding slider set...\"));\n\tSliderSetFile InSS(fileName);\n\tif (InSS.fail()) {\n\t\towner->EndProgress();\n\t\treturn 1;\n\t}\n\n\tSliderSet addSet;\n\tUpdateProgress(20, _(\"Retrieving sliders...\"));\n\tif (InSS.GetSet(sliderSetName, addSet)) {\n\t\towner->EndProgress();\n\t\treturn 2;\n\t}\n\n\taddSet.SetBaseDataPath(GetProjectPath() + PathSepStr + \"ShapeData\");\n\tstd::string inputNif = addSet.GetInputFileName();\n\n\tstd::map<std::string, std::string> renamedShapes;\n\tUpdateProgress(30, _(\"Adding outfit shapes...\"));\n\tif (ImportNIF(inputNif, false, \"\", &renamedShapes)) {\n\t\towner->EndProgress();\n\t\treturn 3;\n\t}\n\n\tif (!baseShape) {\n\t\tNiShape* newBaseShape = nullptr;\n\n\t\t// First external target with skin shader becomes reference\n\t\tstd::vector<std::string> refTargets;\n\t\taddSet.GetReferencedTargets(refTargets);\n\t\tfor (auto& target : refTargets) {\n\t\t\tstd::string shapeName = addSet.TargetToShape(target);\n\t\t\tauto shape = workNif.FindBlockByName<NiShape>(shapeName);\n\t\t\tif (shape) {\n\t\t\t\tNiShader* shader = workNif.GetShader(shape);\n\t\t\t\tif (shader && shader->IsSkinTinted()) {\n\t\t\t\t\tnewBaseShape = shape;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// No external target found, first skin shaded shape becomes reference\n\t\tif (refTargets.empty()) {\n\t\t\tfor (auto shapeTarget = addSet.ShapesBegin(); shapeTarget != addSet.ShapesEnd(); ++shapeTarget) {\n\t\t\t\tauto shape = workNif.FindBlockByName<NiShape>(shapeTarget->first);\n\t\t\t\tif (shape) {\n\t\t\t\t\tNiShader* shader = workNif.GetShader(shape);\n\t\t\t\t\tif (shader && shader->IsSkinTinted()) {\n\t\t\t\t\t\tnewBaseShape = shape;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbaseShape = newBaseShape;\n\t}\n\n\tif (!renamedShapes.empty()) {\n\t\tstd::vector<std::string> renamedShapesOrig;\n\t\trenamedShapesOrig.reserve(renamedShapes.size());\n\t\tfor (auto& rs : renamedShapes)\n\t\t\trenamedShapesOrig.push_back(rs.first);\n\n\t\tstd::string shapesJoin = JoinStrings(renamedShapesOrig, \"; \");\n\t\twxMessageBox(wxString::Format(\"%s\\n \\n%s\",\n\t\t\t\t\t\t\t\t\t  _(\"The following shapes were renamed and won't have slider data attached. Rename the duplicates yourself beforehand.\"),\n\t\t\t\t\t\t\t\t\t  shapesJoin),\n\t\t\t\t\t _(\"Renamed Shapes\"),\n\t\t\t\t\t wxOK | wxICON_WARNING,\n\t\t\t\t\t owner);\n\t}\n\n\tUpdateProgress(70, _(\"Updating slider data...\"));\n\tmorpher.MergeResultDiffs(activeSet, addSet, baseDiffData, baseShape ? baseShape->name.get() : \"\", newDataLocal, appendNewSliders);\n\n\towner->EndProgress();\n\treturn 0;\n}\n\nvoid OutfitProject::InitConform() {\n\tif (baseShape) {\n\t\tmorpher.SetRef(workNif, baseShape, &workAnim);\n\t\tmorpher.LinkRefDiffData(&baseDiffData);\n\t\tmorpher.SourceShapesFromNif(workNif, &workAnim);\n\t}\n}\n\nvoid OutfitProject::ConformShape(NiShape* shape, const ConformOptions& options) {\n\tif (!workNif.IsValid() || !baseShape)\n\t\treturn;\n\n\tstd::unordered_map<uint16_t, float> mask;\n\towner->glView->GetShapeMask(mask, baseShape->name.get());\n\n\tstd::set<uint16_t> maskIndices;\n\tfor (auto& m : mask)\n\t\tmaskIndices.insert(m.first);\n\n\tmorpher.BuildProximityCache(shape->name.get(), options.proximityRadius, &maskIndices);\n\n\tstd::string refTarget = ShapeToTarget(baseShape->name.get());\n\tint conformedCount = 0;\n\tint skippedByFilter = 0;\n\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\tif (SliderZap(i) || SliderUV(i))\n\t\t\tcontinue;\n\t\tif (!options.sliderNames.empty()) {\n\t\t\tbool found = false;\n\t\t\tfor (const auto& sn : options.sliderNames) {\n\t\t\t\tif (sn == activeSet[i].name) {\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!found) {\n\t\t\t\tskippedByFilter++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tconformedCount++;\n\t\tmorpher.GenerateResultDiff(shape->name.get(),\n\t\t\t\t\t\t\t\t\t   activeSet[i].name,\n\t\t\t\t\t\t\t\t\t   activeSet[i].TargetDataName(refTarget),\n\t\t\t\t\t\t\t\t\t   true,\n\t\t\t\t\t\t\t\t\t   options.maxResults,\n\t\t\t\t\t\t\t\t\t   options.noSqueeze,\n\t\t\t\t\t\t\t\t\t   options.solidMode,\n\t\t\t\t\t\t\t\t\t   options.axisX,\n\t\t\t\t\t\t\t\t\t   options.axisY,\n\t\t\t\t\t\t\t\t\t   options.axisZ);\n\t}\n\n\tif (!options.sliderNames.empty())\n\t\twxLogMessage(\"ConformShape '%s': conformed %d slider(s), skipped %d by name filter (of %zu total).\",\n\t\t\t\t\t shape->name.get(), conformedCount, skippedByFilter, activeSet.size());\n}\nTargetDataDiffs* OutfitProject::GetDiffSet(SliderData& sliderData, NiShape* shape) {\n\tstd::string target = ShapeToTarget(shape->name.get());\n\tstd::string targetDataName = sliderData.TargetDataName(target);\n\tif (targetDataName.empty())\n\t\ttargetDataName = target + sliderData.name;\n\n\tif (IsBaseShape(shape))\n\t\treturn baseDiffData.GetDiffSet(targetDataName);\n\telse\n\t\treturn morpher.GetDiffSet(targetDataName);\n}\n\nvoid OutfitProject::CollectVertexData(NiShape* shape, UndoStateShape& uss, const std::vector<uint16_t>& indices) {\n\tuss.delVerts.resize(indices.size());\n\n\tconst std::vector<Vector3>* verts = workNif.GetVertsForShape(shape);\n\tconst std::vector<Vector2>* uvs = workNif.GetUvsForShape(shape);\n\tconst std::vector<Color4>* colors = workNif.GetColorsForShape(shape->name.get());\n\tconst std::vector<Vector3>* normals = workNif.GetNormalsForShape(shape);\n\tconst std::vector<Vector3>* tangents = workNif.GetTangentsForShape(shape);\n\tconst std::vector<Vector3>* bitangents = workNif.GetBitangentsForShape(shape);\n\tconst std::vector<float>* eyeData = workNif.GetEyeDataForShape(shape);\n\tAnimSkin& skin = workAnim.shapeSkinning[shape->name.get()];\n\tMesh* m = owner->glView->GetMesh(shape->name.get());\n\tconst float* mask = m ? m->mask.get() : nullptr;\n\n\tuss.hadVertexColors = colors && !colors->empty();\n\n\tfor (uint16_t di = 0; di < static_cast<uint16_t>(indices.size()); ++di) {\n\t\tUndoStateVertex& usv = uss.delVerts[di];\n\t\tuint16_t vi = indices[di];\n\t\tusv.index = vi;\n\n\t\tif (verts && verts->size() > vi)\n\t\t\tusv.pos = (*verts)[vi];\n\t\tif (uvs && uvs->size() > vi)\n\t\t\tusv.uv = (*uvs)[vi];\n\t\tif (colors && colors->size() > vi)\n\t\t\tusv.color = (*colors)[vi];\n\t\tif (normals && normals->size() > vi)\n\t\t\tusv.normal = (*normals)[vi];\n\t\tif (tangents && tangents->size() > vi)\n\t\t\tusv.tangent = (*tangents)[vi];\n\t\tif (bitangents && bitangents->size() > vi)\n\t\t\tusv.bitangent = (*bitangents)[vi];\n\t\tif (eyeData && eyeData->size() > vi)\n\t\t\tusv.eyeData = (*eyeData)[vi];\n\t\tif (mask)\n\t\t\tusv.mask = mask[vi];\n\n\t\tfor (auto bnp : skin.boneNames) {\n\t\t\tAnimWeight& aw = skin.boneWeights[bnp.second];\n\t\t\tauto wit = aw.weights.find(vi);\n\t\t\tif (wit != aw.weights.end())\n\t\t\t\tusv.weights.emplace_back(UndoStateVertexBoneWeight{bnp.first, wit->second});\n\t\t}\n\t}\n\n\t// For diffs, it's more efficient to reverse the loop nesting.\n\tfor (size_t si = 0; si < activeSet.size(); ++si) {\n\t\tstd::unordered_map<uint16_t, Vector3>* diffSet = GetDiffSet(activeSet[si], shape);\n\n\t\tif (!diffSet)\n\t\t\tcontinue;\n\n\t\tfor (UndoStateVertex& usv : uss.delVerts) {\n\t\t\tauto dit = diffSet->find(usv.index);\n\t\t\tif (dit == diffSet->end())\n\t\t\t\tcontinue;\n\n\t\t\tusv.diffs.push_back(UndoStateVertexSliderDiff{activeSet[si].name, dit->second});\n\t\t}\n\t}\n}\n\nvoid OutfitProject::CollectTriangleData(NiShape* shape, UndoStateShape& uss, const std::vector<uint32_t>& indices) {\n\tuss.delTris.resize(indices.size());\n\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\tif (!workNif.GetShapeSegments(shape, inf, triParts)) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\t\tworkNif.GetShapePartitions(shape, partitionInfo, triParts);\n\t}\n\n\tfor (uint32_t di = 0; di < static_cast<uint32_t>(indices.size()); ++di) {\n\t\tUndoStateTriangle& ust = uss.delTris[di];\n\t\tuint32_t ti = indices[di];\n\t\tust.index = ti;\n\t\tust.t = tris[ti];\n\t\tif (ti < triParts.size())\n\t\t\tust.partID = triParts[ti];\n\t\telse\n\t\t\tust.partID = -1;\n\t}\n}\n\nbool OutfitProject::PrepareDeleteVerts(NiShape* shape, const std::unordered_map<uint16_t, float>& mask, UndoStateShape& uss) {\n\tuint16_t numVerts = shape->GetNumVertices();\n\n\t// Set flag for every vertex index in mask\n\tstd::vector<bool> delVertFlags(numVerts, false);\n\tfor (auto& m : mask)\n\t\tdelVertFlags[m.first] = true;\n\n\t// Generate list of triangles to delete.  Also count how many\n\t// non-deleted triangles each vertex belongs to.\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<uint32_t> delTriInds;\n\tstd::vector<uint32_t> vertTriCounts(numVerts, 0);\n\n\tfor (uint32_t ti = 0; ti < static_cast<uint32_t>(tris.size()); ++ti) {\n\t\tif (delVertFlags[tris[ti].p1] || delVertFlags[tris[ti].p2] || delVertFlags[tris[ti].p3])\n\t\t\tdelTriInds.push_back(ti);\n\t\telse {\n\t\t\t++vertTriCounts[tris[ti].p1];\n\t\t\t++vertTriCounts[tris[ti].p2];\n\t\t\t++vertTriCounts[tris[ti].p3];\n\t\t}\n\t}\n\n\t// If all triangles are deleted, then delete the whole shape.\n\tif (delTriInds.size() >= tris.size())\n\t\treturn true;\n\n\t// Generate new list of vertices to delete: vertices that are not\n\t// used by any non-deleted triangle.\n\tstd::vector<uint16_t> delVertInds;\n\tfor (uint16_t vi = 0; vi < numVerts; ++vi)\n\t\tif (vertTriCounts[vi] <= 0)\n\t\t\tdelVertInds.push_back(vi);\n\n\t// If all vertices are deleted, then delete the whole shape.\n\tif (delVertInds.size() >= numVerts)\n\t\treturn true;\n\n\t// Now collect the vertex and triangle data.\n\tCollectVertexData(shape, uss, delVertInds);\n\tCollectTriangleData(shape, uss, delTriInds);\n\n\treturn false;\n}\n\nvoid OutfitProject::ApplyShapeMeshUndo(NiShape* shape, std::vector<float>& mask, const UndoStateShape& uss, bool bUndo) {\n\tconst std::vector<UndoStateVertex>& delVerts = bUndo ? uss.addVerts : uss.delVerts;\n\tconst std::vector<UndoStateVertex>& addVerts = bUndo ? uss.delVerts : uss.addVerts;\n\tconst std::vector<UndoStateTriangle>& delTris = bUndo ? uss.addTris : uss.delTris;\n\tconst std::vector<UndoStateTriangle>& addTris = bUndo ? uss.delTris : uss.addTris;\n\n\t// Gather data\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\tbool gotsegs = workNif.GetShapeSegments(shape, inf, triParts);\n\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\tbool gotparts = false;\n\tif (!gotsegs)\n\t\tgotparts = workNif.GetShapePartitions(shape, partitionInfo, triParts);\n\n\tstd::vector<Vector3> verts;\n\tworkNif.GetVertsForShape(shape, verts);\n\n\tconst std::vector<Vector2>* uvsp = workNif.GetUvsForShape(shape);\n\tconst std::vector<Color4>* colorsp = workNif.GetColorsForShape(shape->name.get());\n\tconst std::vector<Vector3>* normalsp = workNif.GetNormalsForShape(shape);\n\tconst std::vector<Vector3>* tangentsp = workNif.GetTangentsForShape(shape);\n\tconst std::vector<Vector3>* bitangentsp = workNif.GetBitangentsForShape(shape);\n\tconst std::vector<float>* eyeDatap = workNif.GetEyeDataForShape(shape);\n\n\tif (uvsp && uvsp->empty())\n\t\tuvsp = nullptr;\n\tif (colorsp && colorsp->empty())\n\t\tcolorsp = nullptr;\n\tif (normalsp && normalsp->empty())\n\t\tnormalsp = nullptr;\n\tif (tangentsp && tangentsp->empty())\n\t\ttangentsp = nullptr;\n\tif (bitangentsp && bitangentsp->empty())\n\t\tbitangentsp = nullptr;\n\tif (eyeDatap && eyeDatap->empty())\n\t\teyeDatap = nullptr;\n\n\tstd::vector<Vector2> uvs;\n\tstd::vector<Color4> colors;\n\tstd::vector<Vector3> normals;\n\tstd::vector<Vector3> tangents;\n\tstd::vector<Vector3> bitangents;\n\tstd::vector<float> eyeData;\n\tif (uvsp)\n\t\tuvs = *uvsp;\n\tif (colorsp)\n\t\tcolors = *colorsp;\n\tif (normalsp)\n\t\tnormals = *normalsp;\n\tif (tangentsp)\n\t\ttangents = *tangentsp;\n\tif (bitangentsp)\n\t\tbitangents = *bitangentsp;\n\tif (eyeDatap)\n\t\teyeData = *eyeDatap;\n\tif (mask.size() != verts.size())\n\t\tmask.resize(verts.size());\n\n\tAnimSkin& skin = workAnim.shapeSkinning[shape->name.get()];\n\tstd::string target = ShapeToTarget(shape->name.get());\n\n\tif (!delTris.empty()) {\n\t\t// Delete triangles\n\t\tstd::vector<uint32_t> delTriInds(delTris.size());\n\t\tfor (uint32_t di = 0; di < static_cast<uint32_t>(delTris.size()); ++di)\n\t\t\tdelTriInds[di] = delTris[di].index;\n\n\t\tEraseVectorIndices(tris, delTriInds);\n\n\t\tif (gotsegs || gotparts)\n\t\t\tEraseVectorIndices(triParts, delTriInds);\n\t}\n\n\tbool makeLocal = false;\n\n\tif (!delVerts.empty()) {\n\t\t// Delete vertices...\n\t\tstd::vector<uint16_t> delVertInds(delVerts.size());\n\t\tfor (uint16_t di = 0; di < static_cast<uint16_t>(delVerts.size()); ++di)\n\t\t\tdelVertInds[di] = delVerts[di].index;\n\n\t\tstd::vector<int> vertCollapseMap = GenerateIndexCollapseMap(delVertInds, verts.size());\n\n\t\t// ...from triangles\n\t\tApplyMapToTriangles(tris, vertCollapseMap);\n\n\t\t// ...from workAnim\n\t\tworkAnim.DeleteVertsForShape(shape->name.get(), delVertInds);\n\n\t\t// ...from diff data\n\t\tif (IsBaseShape(shape))\n\t\t\tbaseDiffData.DeleteVerts(target, delVertInds);\n\t\telse\n\t\t\tmorpher.DeleteVerts(target, delVertInds);\n\n\t\t// ...from nif arrays\n\t\tEraseVectorIndices(verts, delVertInds);\n\t\tEraseVectorIndices(mask, delVertInds);\n\t\tif (uvsp)\n\t\t\tEraseVectorIndices(uvs, delVertInds);\n\t\tif (colorsp)\n\t\t\tEraseVectorIndices(colors, delVertInds);\n\t\tif (normalsp)\n\t\t\tEraseVectorIndices(normals, delVertInds);\n\t\tif (tangentsp)\n\t\t\tEraseVectorIndices(tangents, delVertInds);\n\t\tif (bitangentsp)\n\t\t\tEraseVectorIndices(bitangents, delVertInds);\n\t\tif (eyeDatap)\n\t\t\tEraseVectorIndices(eyeData, delVertInds);\n\n\t\tmakeLocal = true;\n\t}\n\n\tif (!addVerts.empty()) {\n\t\t// Insert new vertex indices...\n\t\tstd::vector<uint16_t> insVertInds(addVerts.size());\n\t\tfor (uint16_t di = 0; di < static_cast<uint16_t>(addVerts.size()); ++di)\n\t\t\tinsVertInds[di] = addVerts[di].index;\n\n\t\tstd::vector<int> vertExpandMap = GenerateIndexExpandMap(insVertInds, verts.size());\n\n\t\t// ...into triangles\n\t\tApplyMapToTriangles(tris, vertExpandMap);\n\n\t\t// ...into workAnim\n\t\tskin.InsertVertexIndices(insVertInds);\n\n\t\t// ...into diff data\n\t\tif (IsBaseShape(shape))\n\t\t\tbaseDiffData.InsertVertexIndices(target, insVertInds);\n\t\telse\n\t\t\tmorpher.InsertVertexIndices(target, insVertInds);\n\n\t\t// ...into nif arrays\n\t\tInsertVectorIndices(verts, insVertInds);\n\t\tInsertVectorIndices(mask, insVertInds);\n\t\tif (uvsp)\n\t\t\tInsertVectorIndices(uvs, insVertInds);\n\t\tif (colorsp)\n\t\t\tInsertVectorIndices(colors, insVertInds);\n\t\tif (normalsp)\n\t\t\tInsertVectorIndices(normals, insVertInds);\n\t\tif (tangentsp)\n\t\t\tInsertVectorIndices(tangents, insVertInds);\n\t\tif (bitangentsp)\n\t\t\tInsertVectorIndices(bitangents, insVertInds);\n\t\tif (eyeDatap)\n\t\t\tInsertVectorIndices(eyeData, insVertInds);\n\n\t\t// Store vertex data...\n\t\tfor (const UndoStateVertex& usv : addVerts) {\n\t\t\t// ...in nif arrays\n\t\t\tverts[usv.index] = usv.pos;\n\t\t\tmask[usv.index] = usv.mask;\n\n\t\t\t// UV\n\t\t\tif (uvsp && uvs.size() > usv.index)\n\t\t\t\tuvs[usv.index] = usv.uv;\n\n\t\t\t// Vertex Color\n\t\t\tif (colorsp && colors.size() > usv.index) {\n\t\t\t\tif (uss.hadVertexColors) {\n\t\t\t\t\tcolors[usv.index] = usv.color;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tcolors[usv.index].r = 1.0f;\n\t\t\t\t\tcolors[usv.index].g = 1.0f;\n\t\t\t\t\tcolors[usv.index].b = 1.0f;\n\t\t\t\t\tcolors[usv.index].a = 1.0f;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Normal\n\t\t\tif (normalsp && normals.size() > usv.index)\n\t\t\t\tnormals[usv.index] = usv.normal;\n\n\t\t\t// Tangent\n\t\t\tif (tangentsp && tangents.size() > usv.index)\n\t\t\t\ttangents[usv.index] = usv.tangent;\n\n\t\t\t// Bitangent\n\t\t\tif (bitangentsp && bitangents.size() > usv.index)\n\t\t\t\tbitangents[usv.index] = usv.bitangent;\n\n\t\t\t// Eye Data\n\t\t\tif (eyeDatap && eyeData.size() > usv.index)\n\t\t\t\teyeData[usv.index] = usv.eyeData;\n\n\t\t\t// ...in workAnim\n\t\t\tfor (const auto& usvbw : usv.weights) {\n\t\t\t\tauto bnit = skin.boneNames.find(usvbw.boneName);\n\t\t\t\tif (bnit == skin.boneNames.end()) {\n\t\t\t\t\tworkAnim.AddShapeBone(shape->name.get(), usvbw.boneName);\n\t\t\t\t\tbnit = skin.boneNames.find(usvbw.boneName);\n\t\t\t\t}\n\t\t\t\tskin.boneWeights[bnit->second].weights[usv.index] = usvbw.w;\n\t\t\t}\n\n\t\t\t// ...in diff data\n\t\t\tfor (const UndoStateVertexSliderDiff& diff : usv.diffs) {\n\t\t\t\tstd::string targetDataName = activeSet[diff.sliderName].TargetDataName(target);\n\t\t\t\tif (targetDataName.empty()) {\n\t\t\t\t\ttargetDataName = target + diff.sliderName;\n\n\t\t\t\t\tif (IsBaseShape(shape))\n\t\t\t\t\t\tbaseDiffData.AddEmptySet(targetDataName, target);\n\t\t\t\t\telse\n\t\t\t\t\t\tmorpher.AddEmptySet(shape->name.get(), diff.sliderName);\n\t\t\t\t}\n\n\t\t\t\tstd::unordered_map<uint16_t, Vector3>* diffSet;\n\t\t\t\tif (IsBaseShape(shape))\n\t\t\t\t\tdiffSet = baseDiffData.GetDiffSet(targetDataName);\n\t\t\t\telse\n\t\t\t\t\tdiffSet = morpher.GetDiffSet(targetDataName);\n\n\t\t\t\tif (!diffSet) // should be impossible\n\t\t\t\t\tcontinue;\n\n\t\t\t\t(*diffSet)[usv.index] = diff.diff;\n\t\t\t}\n\t\t}\n\n\t\tmakeLocal = true;\n\t}\n\n\tif (makeLocal) {\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tstd::string targetData = activeSet[i].TargetDataName(target);\n\n\t\t\tif (!targetData.empty())\n\t\t\t\tactiveSet[i].SetLocalData(targetData);\n\t\t}\n\t}\n\n\tif (!addTris.empty()) {\n\t\t// Insert new triangle indices\n\t\tstd::vector<uint32_t> insTriInds(addTris.size());\n\t\tfor (uint32_t di = 0; di < static_cast<uint32_t>(addTris.size()); ++di)\n\t\t\tinsTriInds[di] = addTris[di].index;\n\n\t\tInsertVectorIndices(tris, insTriInds);\n\n\t\tif (gotsegs || gotparts)\n\t\t\tInsertVectorIndices(triParts, insTriInds);\n\n\t\t// Store triangle data\n\t\tfor (const UndoStateTriangle& ust : addTris) {\n\t\t\ttris[ust.index] = ust.t;\n\t\t\tif (gotsegs || gotparts)\n\t\t\t\ttriParts[ust.index] = ust.partID;\n\t\t}\n\t}\n\n\t// Put data back in nif\n\tworkNif.SetVertsForShape(shape, verts);\n\tif (uvsp)\n\t\tworkNif.SetUvsForShape(shape, uvs);\n\tif (colorsp)\n\t\tworkNif.SetColorsForShape(shape, colors);\n\tif (normalsp)\n\t\tworkNif.SetNormalsForShape(shape, normals);\n\tif (tangentsp)\n\t\tworkNif.SetTangentsForShape(shape, tangents);\n\tif (bitangentsp)\n\t\tworkNif.SetBitangentsForShape(shape, bitangents);\n\tif (eyeDatap)\n\t\tworkNif.SetEyeDataForShape(shape, eyeData);\n\n\tshape->SetTriangles(tris);\n\n\tif (gotsegs)\n\t\tworkNif.SetShapeSegments(shape, inf, triParts);\n\n\tif (gotparts) {\n\t\tworkNif.SetShapePartitions(shape, partitionInfo, triParts);\n\t\tworkNif.RemoveEmptyPartitions(shape);\n\t}\n\n\t// Note that we do not restore the nif's vertex bone weights.\n\t// That should happen when the file is saved.\n}\n\nbool OutfitProject::PrepareCollapseVertex(NiShape* shape, UndoStateShape& uss, const std::vector<uint16_t>& indices) {\n\t// Get triangle data\n\tuint16_t numVerts = shape->GetNumVertices();\n\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\n\tif (!workNif.GetShapeSegments(shape, inf, triParts)) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\t\tworkNif.GetShapePartitions(shape, partitionInfo, triParts);\n\t}\n\n\t// Note that indices is already in sorted order.\n\tstd::vector<uint16_t> nverts;\n\tstd::vector<uint32_t> ntris;\n\tauto addneighbor = [&nverts](const uint16_t vi) {\n\t\tfor (const auto evi : nverts)\n\t\t\tif (vi == evi)\n\t\t\t\treturn;\n\n\t\tnverts.push_back(vi);\n\t};\n\n\tstd::vector<uint32_t> nrtris; // non-replaced triangles\n\n\tfor (const auto vi : indices) {\n\t\tntris.clear();\n\t\tnverts.clear();\n\n\t\t// Collect lists of neighboring triangles and vertices.\n\t\tfor (uint32_t ti = 0; ti < static_cast<uint32_t>(tris.size()); ++ti) {\n\t\t\tconst Triangle& t = tris[ti];\n\t\t\tif (!t.HasVertex(vi))\n\t\t\t\tcontinue;\n\n\t\t\tif (ntris.size() >= 3)\n\t\t\t\treturn false;\n\n\t\t\tntris.push_back(ti);\n\n\t\t\t// Order of vertex collection is important, or we'll end up\n\t\t\t// with a backwards triangle.\n\t\t\tif (t.p1 == vi) {\n\t\t\t\taddneighbor(t.p2);\n\t\t\t\taddneighbor(t.p3);\n\t\t\t}\n\t\t\telse if (t.p2 == vi) {\n\t\t\t\taddneighbor(t.p3);\n\t\t\t\taddneighbor(t.p1);\n\t\t\t}\n\t\t\telse {\n\t\t\t\taddneighbor(t.p1);\n\t\t\t\taddneighbor(t.p2);\n\t\t\t}\n\n\t\t\tif (nverts.size() > 3)\n\t\t\t\treturn false;\n\t\t}\n\n\t\t// Make sure no neighboring vertices are welded to this vertex.\n\t\tfor (uint16_t nvi = 0; nvi < static_cast<uint16_t>(nverts.size()); ++nvi)\n\t\t\tfor (uint16_t ii = 0; ii < static_cast<uint16_t>(indices.size()); ++ii)\n\t\t\t\tif (indices[ii] == nverts[nvi])\n\t\t\t\t\treturn false;\n\n\t\t// Put triangles to delete in uss.delTris.\n\t\tfor (uint32_t vti = 0; vti < static_cast<uint32_t>(ntris.size()); ++vti) {\n\t\t\tuint32_t ti = ntris[vti];\n\t\t\tuss.delTris.push_back(UndoStateTriangle{ti, tris[ti], ti < triParts.size() ? triParts[ti] : -1});\n\t\t}\n\n\t\tuint32_t pti = NIF_NPOS;\n\t\tif (nverts.size() == 3) {\n\t\t\t// Determine preferred triangle to replace.\n\t\t\tpti = 0;\n\n\t\t\tif (!triParts.empty() && ntris.size() == 3 && triParts[ntris[0]] != triParts[ntris[1]] && triParts[ntris[1]] == triParts[ntris[2]]) {\n\t\t\t\tpti = 1;\n\t\t\t}\n\n\t\t\t// Put new triangle in uss.\n\t\t\tuint32_t ti = ntris[pti];\n\t\t\tuss.addTris.push_back(UndoStateTriangle{ti, Triangle(nverts[0], nverts[1], nverts[2]), ti < triParts.size() ? triParts[ti] : -1});\n\t\t}\n\n\t\t// Collect list of non-replaced triangles for triangle renumbering.\n\t\tfor (uint32_t vti = 0; vti < static_cast<uint32_t>(ntris.size()); ++vti)\n\t\t\tif (vti != pti)\n\t\t\t\tnrtris.push_back(ntris[vti]);\n\t}\n\n\t// We've loaded all the triangle data; now load the vertex data.\n\tCollectVertexData(shape, uss, indices);\n\n\t// Renumber vertex and triangle indices in uss.addTris.\n\tstd::vector<int> vCollapse = GenerateIndexCollapseMap(indices, numVerts);\n\n\tstd::sort(nrtris.begin(), nrtris.end());\n\tstd::vector<int> tCollapse = GenerateIndexCollapseMap(nrtris, tris.size());\n\n\tfor (UndoStateTriangle& ust : uss.addTris) {\n\t\tust.t.p1 = vCollapse[ust.t.p1];\n\t\tust.t.p2 = vCollapse[ust.t.p2];\n\t\tust.t.p3 = vCollapse[ust.t.p3];\n\t\tust.index = tCollapse[ust.index];\n\t}\n\n\t// Sort uss.addTris and uss.delTris, since they weren't added in any\n\t// particular order.\n\tstd::sort(uss.addTris.begin(), uss.addTris.end());\n\tstd::sort(uss.delTris.begin(), uss.delTris.end());\n\n\treturn true;\n}\n\nstatic uint16_t TriangleOppositeVertex(const Triangle& t, const uint16_t p1) {\n\tif (t.p1 == p1)\n\t\treturn t.p3;\n\telse if (t.p2 == p1)\n\t\treturn t.p1;\n\telse\n\t\treturn t.p2;\n}\n\nbool OutfitProject::PrepareFlipEdge(NiShape* shape, UndoStateShape& uss, const Edge& edge) {\n\t// Get triangle data\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\tif (!workNif.GetShapeSegments(shape, inf, triParts)) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\t\tworkNif.GetShapePartitions(shape, partitionInfo, triParts);\n\t}\n\n\t// Find the two neighboring triangles\n\tbool t1found = false;\n\tbool t2found = false;\n\tuint32_t t1 = 0;\n\tuint32_t t2 = 0;\n\tconst Edge redge(edge.p2, edge.p1);\n\n\tfor (uint32_t ti = 0; ti < static_cast<uint32_t>(tris.size()); ++ti) {\n\t\tif (tris[ti].HasOrientedEdge(edge)) {\n\t\t\tif (t1found)\n\t\t\t\treturn false;\n\n\t\t\tt1 = ti;\n\t\t\tt1found = true;\n\t\t}\n\n\t\tif (tris[ti].HasOrientedEdge(redge)) {\n\t\t\tif (t2found)\n\t\t\t\treturn false;\n\n\t\t\tt2 = ti;\n\t\t\tt2found = true;\n\t\t}\n\t}\n\n\tif (!t1found || !t2found)\n\t\treturn false;\n\n\t// Find the non-edge vertex for each neighboring triangle.\n\tuint16_t nev1 = TriangleOppositeVertex(tris[t1], edge.p1);\n\tuint16_t nev2 = TriangleOppositeVertex(tris[t2], edge.p2);\n\n\t// Put data into uss.\n\tint tp1 = t1 < triParts.size() ? triParts[t1] : -1;\n\tint tp2 = t2 < triParts.size() ? triParts[t2] : -1;\n\tuss.delTris.push_back(UndoStateTriangle{t1, tris[t1], tp1});\n\tuss.delTris.push_back(UndoStateTriangle{t2, tris[t2], tp2});\n\tuss.addTris.push_back(UndoStateTriangle{t1, Triangle(edge.p1, nev2, nev1), tp1});\n\tuss.addTris.push_back(UndoStateTriangle{t2, Triangle(edge.p2, nev1, nev2), tp2});\n\n\t// Sort delTris and addTris by index.\n\tif (t2 < t1) {\n\t\tstd::swap(uss.delTris[0], uss.delTris[1]);\n\t\tstd::swap(uss.addTris[0], uss.addTris[1]);\n\t}\n\n\treturn true;\n}\n\n/*\nIdeally, PrepareRefineMesh would take a list of edges, not a list of\nvertices.  But OutfitStudio doesn't yet have an edge-mask tool.\nParameter \"noCurveOffset\" disables the smoothing/curving of the new vertex position within split edges.\n*/\nbool OutfitProject::PrepareRefineMesh(NiShape* shape, UndoStateShape& uss, std::vector<bool>& pincs, const Mesh::WeldVertsType& weldVerts, const bool noCurveOffset, std::vector<Edge>* badEdges) {\n\t// Get vertex coordinates and triangle data\n\tsize_t nverts = pincs.size();\n\tconst std::vector<Vector3>* verts = workNif.GetVertsForShape(shape);\n\tif (!verts || verts->size() != nverts)\n\t\treturn false;\t// Shouldn't be possible\n\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\tif (!workNif.GetShapeSegments(shape, inf, triParts)) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\t\tworkNif.GetShapePartitions(shape, partitionInfo, triParts);\n\t}\n\n\t// Ensure welded vertices are included in pincs\n\tfor (size_t vi = 0; vi < nverts; ++vi) {\n\t\tif (!pincs[vi])\n\t\t\tcontinue;\n\t\tMesh::DoForEachWeldedVertex(weldVerts, vi, [&](int p){pincs[p] = true;});\n\t}\n\n\t// Get data for all the vertices (in a secondary data-collection\n\t// UndoStateShape).\n\tUndoStateShape duss;\n\tstd::vector<uint16_t> vertexInds, dussInds(nverts);\n\tfor (size_t vi = 0; vi < nverts; ++vi)\n\t\tif (pincs[vi]) {\n\t\t\tdussInds[vi] = vertexInds.size();\n\t\t\tvertexInds.push_back(vi);\n\t\t}\n\n\tCollectVertexData(shape, duss, vertexInds);\n\n\t// Calculate the normal at each point by averaging triangle normals.\n\tstd::vector<Vector3> nsums(nverts);\n\tfor (uint16_t vi : vertexInds) {\n\t\tVector3 nsum;\n\t\tfor (const Triangle& t : tris)\n\t\t\tif (t.HasVertex(vi)) {\n\t\t\t\tVector3 tn = t.trinormal(*verts);\n\t\t\t\ttn.Normalize();\n\t\t\t\tnsum += tn;\n\t\t\t}\n\n\t\tnsums[vi] = nsum;\n\t}\n\tstd::vector<Vector3> normals(nverts);\n\tfor (uint16_t vi : vertexInds) {\n\t\tVector3 normal(nsums[vi]);\n\t\tMesh::DoForEachWeldedVertex(weldVerts, vi, [&](int p){normal += nsums[p];});\n\t\tnormal.Normalize();\n\t\tnormals[vi] = normal;\n\t}\n\n\t// Search through the list of triangles for edges to include.\n\t// The boolean in singleEdges indicates whether the edge has been\n\t// split yet (in the following big loop).\n\tstd::unordered_map<Edge, bool> singleEdges;\n\tbool hasBadEdges = false;\n\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\tif (tris[ti].p1 >= nverts || tris[ti].p2 >= nverts ||\n\t\t\ttris[ti].p3 >= nverts)\n\t\t\treturn false;\t// Out-of-range indices; shouldn't be possible.\n\t\tfor (int tei = 0; tei < 3; ++tei) {\n\t\t\tEdge e = tris[ti].GetEdge(tei);\n\t\t\tif (!pincs[e.p1] || !pincs[e.p2])\n\t\t\t\tcontinue;\n\t\t\tif (singleEdges.find(e) != singleEdges.end()) {\n\t\t\t\t// Multiple triangles for this edge\n\t\t\t\tif (badEdges)\n\t\t\t\t\tbadEdges->push_back(e);\n\t\t\t\thasBadEdges = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsingleEdges[e] = false;\n\t\t}\n\t}\n\n\tif (hasBadEdges)\n\t\treturn false;\n\n\tuint16_t newvi = nverts;\n\n\t// emls contains the data that will be needed for updating the\n\t// triangulation.  We fill it in in the big edge loop, sort it, and\n\t// then update the triangles (far below).\n\tstruct EdgeWithMidAndLen: public Edge {\n\t\tuint16_t mid;\n\t\tfloat len;\n\n\t\tbool operator<(const EdgeWithMidAndLen &e2) {\n\t\t\treturn e2.len < len;\n\t\t}\n\t};\n\tstd::vector<EdgeWithMidAndLen> emls;\n\n\t// begin big loop through the edges\n\tstd::vector<uint16_t> p1s, p2s;\n\tfor (auto& e : singleEdges) {\n\t\tif (e.second) continue;\n\t\te.second = true;\n\n\t\tEdge edge(e.first), redge;\n\t\tbool hasre = false;\n\n\t\t// Collect lists of welded vertices for the edge's two points.\n\t\tMesh::GetWeldSet(weldVerts, edge.p1, p1s);\n\t\tMesh::GetWeldSet(weldVerts, edge.p2, p2s);\n\n\t\t// Search for edge and reverse-edge matches in singleEdges\n\t\tbool edgeError = false;\n\t\tfor (const auto p1 : p1s) {\n\t\t\tfor (const auto p2 : p2s) {\n\t\t\t\tauto seit = singleEdges.find(Edge(p1, p2));\n\t\t\t\tif (seit != singleEdges.end() && !seit->second) {\n\t\t\t\t\tif (badEdges) {\n\t\t\t\t\t\tbadEdges->push_back(Edge(p1, p2));\n\t\t\t\t\t\thasBadEdges = true;\n\t\t\t\t\t\tedgeError = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\t// Multiple triangles for this edge\n\t\t\t\t}\n\t\t\t\tseit = singleEdges.find(Edge(p2, p1));\n\t\t\t\tif (seit == singleEdges.end())\n\t\t\t\t\tcontinue;\n\t\t\t\tif (seit->second) {\n\t\t\t\t\tif (badEdges) {\n\t\t\t\t\t\tbadEdges->push_back(Edge(p2, p1));\n\t\t\t\t\t\thasBadEdges = true;\n\t\t\t\t\t\tedgeError = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\t// Shouldn't be possible\n\t\t\t\t}\n\t\t\t\tseit->second = true;\n\t\t\t\tif (hasre) {\n\t\t\t\t\tif (badEdges) {\n\t\t\t\t\t\tbadEdges->push_back(Edge(p2, p1));\n\t\t\t\t\t\thasBadEdges = true;\n\t\t\t\t\t\tedgeError = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\treturn false;\t// Multiple reverse edges for this edge\n\t\t\t\t}\n\t\t\t\thasre = true;\n\t\t\t\tredge = Edge(p2, p1);\n\t\t\t}\n\t\t}\n\n\t\tif (edgeError)\n\t\t\tcontinue;\n\n\t\t// Find the edge and redge vertex data\n\t\tconst UndoStateVertex& p1d = duss.delVerts[dussInds[edge.p1]];\n\t\tconst UndoStateVertex& p2d = duss.delVerts[dussInds[edge.p2]];\n\t\tconst UndoStateVertex& rp1d = duss.delVerts[dussInds[redge.p1]];\n\t\tconst UndoStateVertex& rp2d = duss.delVerts[dussInds[redge.p2]];\n\t\tconst Vector3& p1 = p1d.pos;\n\t\tconst Vector3& p2 = p2d.pos;\n\t\tconst Vector3& np1 = normals[edge.p1];\n\t\tconst Vector3& np2 = normals[edge.p2];\n\n\t\tbool welded = hasre && (redge.p1 != edge.p2 || redge.p2 != edge.p1);\n\n\t\t// Create entry for new vertex and (if welded) new welded vertex\n\t\tuss.addVerts.emplace_back();\n\t\tuss.addVerts.back().index = newvi++;\n\t\tif (welded) {\n\t\t\tuss.addVerts.emplace_back();\n\t\t\tuss.addVerts.back().index = newvi++;\n\t\t}\n\t\tUndoStateVertex& usv = uss.addVerts[uss.addVerts.size() - (welded ? 2 : 1)];\n\t\tUndoStateVertex& rusv = uss.addVerts.back();\n\n\t\t/* Now comes the hard part: determining a good location for the\n\t\tnew vertex.  Clearly it should lie somewhere on the plane bisecting\n\t\tthe segment between p1 and p2.  If we wanted to be lazy, we could\n\t\tjust pick the midpoint.  But that would require the user to adjust\n\t\tthe position every time.  Better would be if we could fit a circle\n\t\tthrough p1, p2, and the new point so that all three have normals\n\t\tperpendicular to the circle.  But there's no guarantee that that's\n\t\tpossible: the old normals could have different angles to the edge;\n\t\tand they could even be non-coplanar.  So we need to average the\n\t\tangles for the two normals somehow.  There are several stages\n\t\twhere this could be done; I choose to do it early. */\n\n\t\t// Starting position of new point: midpoint between p1 and p2\n\t\tusv.pos = (p1 + p2) * 0.5f;\n\n\t\tVector3 u12 = p2 - p1;\t   // unit vector from p1 to p2 (along the edge)\n\t\tfloat elen = u12.length(); // edge length\n\t\tu12.Normalize();\n\n\t\tusv.normal = np1 + np2;\n\n\t\tif (!noCurveOffset) {\n\t\t\t// Working normal for new point: average of np1 and np2, made\n\t\t\t// perpendicular to u12.  (If you want something fancy for usv.normal,\n\t\t\t// calculate it later.  This calculation needs to be done this\n\t\t\t// way for the circle fitter.)\n\t\t\tusv.normal -= u12 * u12.dot(usv.normal);\n\t\t}\n\n\t\tusv.normal.Normalize();\n\n\t\tfloat curveOffsetFactor = 1.0f;\n\t\tif (!noCurveOffset) {\n\t\t\t// Now, the angle between npi and usv.normal, in the plane of\n\t\t\t// npi and u12 (since usv.normal isn't necessarily in that plane)\n\t\t\t// would be asin(u12.dot(npi)).  We want to average this for np1\n\t\t\t// and np2 and carefully preserve the sign.\n\t\t\tfloat angle = asin(u12.dot(np2 - np1) * 0.5);\n\n\t\t\t// Now, \"angle\" is the desired circle angle between the new point and\n\t\t\t// either p1 or p2.  It's positive for convex, negative for concave.\n\t\t\t// To figure out how far off of the edge we need to go, we need to\n\t\t\t// take the trigonometric tangent of the correct angle.  It turns out\n\t\t\t// the correct angle is the angle we just calculated divided by 2.\n\t\t\tcurveOffsetFactor = tan(angle * 0.5);\n\n\t\t\t// Now apply the offset to the new point.  (curveOffsetFactor is\n\t\t\t// positive for convex, negative for concave, and will be no larger\n\t\t\t// than 1.)\n\t\t\tusv.pos += usv.normal * (curveOffsetFactor * elen * 0.5f);\n\t\t}\n\n\t\t// Calculate uv, color, tangent, bitangent, and eyeData by averaging.\n\t\t// We need to make sure normal, tangent, and bitangent are\n\t\t// perpendicular.\n\t\tusv.uv = (p1d.uv + p2d.uv) * 0.5;\n\t\tusv.color.r = (p1d.color.r + p2d.color.r) * 0.5f;\n\t\tusv.color.g = (p1d.color.g + p2d.color.g) * 0.5f;\n\t\tusv.color.b = (p1d.color.b + p2d.color.b) * 0.5f;\n\t\tusv.color.a = (p1d.color.a + p2d.color.a) * 0.5f;\n\t\tusv.eyeData = (p1d.eyeData + p2d.eyeData) * 0.5f;\n\t\tusv.mask = std::min(p1d.mask, p2d.mask);\n\t\tusv.tangent = (p1d.tangent + p2d.tangent) * 0.5f;\n\t\tusv.bitangent = (p1d.bitangent + p2d.bitangent) * 0.5f;\n\t\tusv.tangent -= usv.normal * usv.normal.dot(usv.tangent);\n\t\tusv.tangent.Normalize();\n\t\tusv.bitangent -= usv.normal * usv.normal.dot(usv.bitangent);\n\t\tusv.bitangent -= usv.tangent * usv.tangent.dot(usv.bitangent);\n\t\tusv.bitangent.Normalize();\n\n\t\t// Calculate weights by averaging.  Note that the resulting weights\n\t\t// will add up to 1 if each source's weights do.\n\t\tfor (int si = 0; si < 2; ++si) {\n\t\t\tconst std::vector<UndoStateVertexBoneWeight>& swts = si ? p2d.weights : p1d.weights;\n\t\t\tfor (const UndoStateVertexBoneWeight& sw : swts) {\n\t\t\t\tbool found = false;\n\t\t\t\tfor (size_t dwi = 0; dwi < usv.weights.size() && !found; ++dwi) {\n\t\t\t\t\tif (usv.weights[dwi].boneName == sw.boneName) {\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tusv.weights[dwi].w += sw.w;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (!found)\n\t\t\t\t\tusv.weights.push_back(sw);\n\t\t\t}\n\t\t}\n\n\t\tfor (auto& dw : usv.weights)\n\t\t\tdw.w *= 0.5;\n\n\t\tif (welded) {\n\t\t\t// Welded vertex gets exactly the same data except uv and uv-diffs.\n\t\t\tuint16_t rvi = rusv.index;\n\t\t\trusv = usv;\n\t\t\trusv.index = rvi;\n\t\t\trusv.uv = (rp1d.uv + rp2d.uv) * 0.5;\n\t\t}\n\n\t\t// Unfortunately, we can't just calculate diffs by averaging.  p1\n\t\t// and p2 may have moved farther apart, which would require greater\n\t\t// curve offset.\n\n\t\t// diffpairs: key is sliderName.\n\t\tstd::unordered_map<std::string, std::pair<Vector3, Vector3>> diffpairs;\n\t\tfor (auto& sd : p1d.diffs)\n\t\t\tdiffpairs[sd.sliderName].first = sd.diff;\n\t\tfor (auto& sd : p2d.diffs)\n\t\t\tdiffpairs[sd.sliderName].second = sd.diff;\n\n\t\tfor (auto& dp : diffpairs) {\n\t\t\t// First, just average the diffs.\n\t\t\tVector3 diff = (dp.second.first + dp.second.second) * 0.5f;\n\t\t\tconst SliderData& sd = activeSet[dp.first];\n\t\t\tif (!noCurveOffset && !sd.bUV && !sd.bClamp && !sd.bZap) {\n\t\t\t\t// Calculate the distance between the moved p1 and p2.\n\t\t\t\tfloat delen = (dp.second.second + p2 - dp.second.first - p1).length();\n\t\t\t\t// Apply more curve offset (for delen > elen)\n\t\t\t\t// or less (for delen < elen).\n\t\t\t\tdiff += usv.normal * (curveOffsetFactor * (delen - elen) * 0.5f);\n\t\t\t}\n\n\t\t\tusv.diffs.push_back(UndoStateVertexSliderDiff{dp.first, diff});\n\t\t\tif (welded && !sd.bUV)\n\t\t\t\trusv.diffs.push_back(UndoStateVertexSliderDiff{dp.first, diff});\n\t\t}\n\n\t\tif (welded) {\n\t\t\t// Repeat the diff calculation, but only for UV diffs.\n\t\t\tstd::unordered_map<std::string, std::pair<Vector3, Vector3>> rdiffpairs;\n\t\t\tfor (auto& sd : rp1d.diffs)\n\t\t\t\trdiffpairs[sd.sliderName].first = sd.diff;\n\t\t\tfor (auto& sd : rp2d.diffs)\n\t\t\t\trdiffpairs[sd.sliderName].second = sd.diff;\n\n\t\t\tfor (auto& dp : rdiffpairs) {\n\t\t\t\tconst SliderData& sd = activeSet[dp.first];\n\t\t\t\tif (!sd.bUV)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tVector3 diff = (dp.second.first + dp.second.second) * 0.5f;\n\t\t\t\trusv.diffs.push_back(UndoStateVertexSliderDiff{dp.first, diff});\n\t\t\t}\n\t\t}\n\n\t\t// Now usv and rusv are finished.  Add the edge and reverse edge to\n\t\t// the list of edges that need triangle updates.\n\t\temls.emplace_back(EdgeWithMidAndLen{edge, usv.index, elen});\n\t\tif (hasre)\n\t\t\temls.emplace_back(EdgeWithMidAndLen{redge, rusv.index, elen});\n\t}\n\t// end big loop through the edges\n\n\tif (hasBadEdges)\n\t\treturn false;\n\n\t// Sort the edges from longest to shortest so that we'll split the\n\t// triangles for the longest edges first.\n\tstd::sort(emls.begin(), emls.end());\n\n\tfor (auto& eml : emls) {\n\t\t/* We know (because we've already checked) that there is\n\t\texactly one triangle in the old triangle list with the oriented\n\t\tedge eml.  However, it might have already been split into two\n\t\tor more triangles.  So we have to look in the new triangle\n\t\tlist and then the old.  We also don't know ahead of time\n\t\thow many times an original triangle will be split in two,\n\t\tso we can't know the new triangle numbering until the end.\n\t\tSo we assign each triangle of the pair created the same index\n\t\tas the original, for now, and we'll update those indices later,\n\t\tafter the new-triangle list has been sorted. */\n\t\tbool found = false;\n\n\t\t// Loop through the new triangles\n\t\tfor (auto& ust : uss.addTris) {\n\t\t\tif (!ust.t.HasOrientedEdge(eml))\n\t\t\t\tcontinue;\n\t\t\tfound = true;\n\t\t\tuint16_t ovi = TriangleOppositeVertex(ust.t, eml.p1);\n\t\t\tust.t.p1 = eml.p1;\n\t\t\tust.t.p2 = eml.mid;\n\t\t\tust.t.p3 = ovi;\n\t\t\tUndoStateTriangle newust = ust; // copies index and partID too\n\t\t\tnewust.t.p1 = eml.mid;\n\t\t\tnewust.t.p2 = eml.p2;\n\t\t\tuss.addTris.push_back(newust);\n\t\t\tbreak;\n\t\t}\n\t\tif (found)\n\t\t\tcontinue;\n\n\t\t// Loop through the old triangles\n\t\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\t\tif (!tris[ti].HasOrientedEdge(eml))\n\t\t\t\tcontinue;\n\t\t\tfound = true;\n\t\t\tuint16_t ovi = TriangleOppositeVertex(tris[ti], eml.p1);\n\t\t\tint tp = ti < triParts.size() ? triParts[ti] : -1;\n\t\t\tuint32_t sti = static_cast<uint32_t>(ti);\n\t\t\tuss.delTris.push_back(UndoStateTriangle{sti, tris[ti], tp});\n\t\t\tuss.addTris.push_back(UndoStateTriangle{sti, Triangle(eml.p1, eml.mid, ovi), tp});\n\t\t\tuss.addTris.push_back(UndoStateTriangle{sti, Triangle(eml.mid, eml.p2, ovi), tp});\n\t\t\tbreak;\n\t\t}\n\t\t// assert(found)\n\t}\n\n\t// Sort delTris and addTris by index.\n\tstd::sort(uss.delTris.begin(), uss.delTris.end());\n\tstd::sort(uss.addTris.begin(), uss.addTris.end());\n\n\t// Update the triangle indices in addTris so indices are not duplicated\n\tuint32_t tioffset = 0, lastindex = 0;\n\tfor (size_t ati = 0; ati < uss.addTris.size(); ++ati) {\n\t\tuint32_t& ti = uss.addTris[ati].index;\n\t\tif (ati != 0 && ti == lastindex)\n\t\t\t++tioffset;\n\t\tlastindex = ti;\n\t\tti += tioffset;\n\t}\n\n\treturn true;\n}\n\nbool OutfitProject::IsVertexOnBoundary(NiShape* shape, int vi) {\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\t// Count how many times each neighboring vertex is in a triangle with\n\t// this vertex\n\tstd::unordered_map<uint16_t, int> vcounts;\n\tfor (const Triangle &t : tris) {\n\t\tif (!t.HasVertex(vi))\n\t\t\tcontinue;\n\n\t\tif (t.p1 != vi) vcounts[t.p1]++;\n\t\tif (t.p2 != vi) vcounts[t.p2]++;\n\t\tif (t.p3 != vi) vcounts[t.p3]++;\n\t}\n\n\t// If any vertex count is not even, the corresponding edge is on the\n\t// boundary.  (Note that if any vc is greater than 2, the surface is\n\t// messed up.)\n\tfor (auto& vc : vcounts)\n\t\tif (vc.second % 2 != 0)\n\t\t\treturn true;\n\n\treturn false;\n}\n\nbool OutfitProject::PointsHaveDifferingWeightsOrDiffs(NiShape* shape1, int p1, NiShape* shape2, int p2) {\n\t// Check for position differences\n\tconst AnimSkin& skin1 = shape1->IsSkinned() ? workAnim.shapeSkinning[shape1->name.get()] : AnimSkin();\n\tconst AnimSkin& skin2 = shape2->IsSkinned() ? workAnim.shapeSkinning[shape2->name.get()] : AnimSkin();\n\tMatTransform skin1ToGlobal = workAnim.GetTransformShapeToGlobal(shape1);\n\tMatTransform skin2ToGlobal = workAnim.GetTransformShapeToGlobal(shape2);\n\tconst std::vector<Vector3>* verts1 = workNif.GetVertsForShape(shape1);\n\tconst std::vector<Vector3>* verts2 = workNif.GetVertsForShape(shape2);\n\tif (verts1 && verts2 && (*verts1)[p1] != (*verts2)[p2])\n\t\treturn true;\n\n\t// Check for bone weight differences\n\tfor (auto bnp : skin1.boneNames) {\n\t\tconst AnimWeight& aw1 = skin1.boneWeights.at(bnp.second);\n\t\tauto wit1 = aw1.weights.find(p1);\n\t\tif (wit1 == aw1.weights.end() || wit1->second == 0.0f)\n\t\t\tcontinue;\n\t\tauto bnit = skin2.boneNames.find(bnp.first);\n\t\tif (bnit == skin2.boneNames.end())\n\t\t\treturn true;\n\t\tconst AnimWeight& aw2 = skin2.boneWeights.at(bnit->second);\n\t\tauto wit2 = aw2.weights.find(p2);\n\t\tif (wit2 == aw2.weights.end() || wit2->second != wit1->second)\n\t\t\treturn true;\n\t}\n\tfor (auto bnp : skin2.boneNames) {\n\t\tconst AnimWeight& aw2 = skin2.boneWeights.at(bnp.second);\n\t\tauto wit2 = aw2.weights.find(p2);\n\t\tif (wit2 == aw2.weights.end() || wit2->second == 0.0f)\n\t\t\tcontinue;\n\t\tauto bnit = skin1.boneNames.find(bnp.first);\n\t\tif (bnit == skin1.boneNames.end())\n\t\t\treturn true;\n\t\tconst AnimWeight& aw1 = skin1.boneWeights.at(bnit->second);\n\t\tauto wit1 = aw1.weights.find(p1);\n\t\tif (wit1 == aw1.weights.end() || wit1->second != wit2->second)\n\t\t\treturn true;\n\t}\n\n\t// Check for position slider differences.  We skip uv, clamp, and zap.\n\tfor (size_t si = 0; si < activeSet.size(); ++si) {\n\t\tif (activeSet[si].bUV || activeSet[si].bClamp || activeSet[si].bZap)\n\t\t\tcontinue;\n\n\t\tstd::unordered_map<uint16_t, Vector3>* diffSet1 = GetDiffSet(activeSet[si], shape1);\n\t\tstd::unordered_map<uint16_t, Vector3>* diffSet2 = GetDiffSet(activeSet[si], shape2);\n\n\t\tif (!diffSet1 && !diffSet2)\n\t\t\tcontinue;\n\n\t\tVector3 diff1, diff2;\n\t\tif (diffSet1) {\n\t\t\tauto dit1 = diffSet1->find(p1);\n\t\t\tif (dit1 != diffSet1->end())\n\t\t\t\tdiff1 = skin1ToGlobal.ApplyTransformToDiff(dit1->second);\n\t\t}\n\t\tif (diffSet2) {\n\t\t\tauto dit2 = diffSet2->find(p2);\n\t\t\tif (dit2 != diffSet2->end())\n\t\t\t\tdiff2 = skin2ToGlobal.ApplyTransformToDiff(dit2->second);\n\t\t}\n\t\tif (diff1 != diff2)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid OutfitProject::PrepareMergeVertex(NiShape* shape, UndoStateShape& uss, int selVert, int targVert) {\n\t// Get triangle data\n\tuint16_t numVerts = shape->GetNumVertices();\n\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\n\tif (!workNif.GetShapeSegments(shape, inf, triParts)) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\t\tworkNif.GetShapePartitions(shape, partitionInfo, triParts);\n\t}\n\n\t// Delete vertex\n\tstd::vector<uint16_t> indices(1, selVert);\n\tCollectVertexData(shape, uss, indices);\n\tstd::vector<int> vCollapse = GenerateIndexCollapseMap(indices, numVerts);\n\n\t// Replace triangles\n\tfor (uint32_t ti = 0; ti < tris.size(); ++ti) {\n\t\tconst Triangle& t = tris[ti];\n\t\tif (!t.HasVertex(selVert))\n\t\t\tcontinue;\n\n\t\t// Replace selVert with targVert\n\t\tTriangle newt = t;\n\t\tif (newt.p1 == selVert)\n\t\t\tnewt.p1 = targVert;\n\t\tif (newt.p2 == selVert)\n\t\t\tnewt.p2 = targVert;\n\t\tif (newt.p3 == selVert)\n\t\t\tnewt.p3 = targVert;\n\n\t\t// Get partition number\n\t\tint part = -1;\n\t\tif (ti < triParts.size())\n\t\t\tpart = triParts[ti];\n\n\t\t// Collapse vertex indices\n\t\tnewt.p1 = vCollapse[newt.p1];\n\t\tnewt.p2 = vCollapse[newt.p2];\n\t\tnewt.p3 = vCollapse[newt.p3];\n\n\t\tuss.delTris.push_back(UndoStateTriangle{ti, t, part});\n\t\tuss.addTris.push_back(UndoStateTriangle{ti, newt, part});\n\t}\n}\n\nvoid OutfitProject::PrepareWeldVertex(NiShape* shape, UndoStateShape& uss, int selVert, int targVert, NiShape* targShape) {\n\t// Get triangle data\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo inf;\n\n\tif (!workNif.GetShapeSegments(shape, inf, triParts)) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\t\tworkNif.GetShapePartitions(shape, partitionInfo, triParts);\n\t}\n\n\t// Delete and restore all triangles that use selVert\n\tfor (uint32_t ti = 0; ti < tris.size(); ++ti) {\n\t\tconst Triangle& t = tris[ti];\n\t\tif (!t.HasVertex(selVert))\n\t\t\tcontinue;\n\n\t\t// Get partition number\n\t\tint part = -1;\n\t\tif (ti < triParts.size())\n\t\t\tpart = triParts[ti];\n\n\t\tuss.delTris.push_back(UndoStateTriangle{ti, t, part});\n\t\tuss.addTris.push_back(UndoStateTriangle{ti, t, part});\n\t}\n\n\t// Get data for the target vertex (in a secondary data-collection\n\t// UndoStateShape).\n\tUndoStateShape duss;\n\tstd::vector<uint16_t> targInds(1, targVert);\n\tCollectVertexData(targShape, duss, targInds);\n\tUndoStateVertex &tusv = duss.delVerts[0];\n\n\t// Calculate transform from target's skin coordinates to selected's.\n\tMatTransform skx = workAnim.GetTransformGlobalToShape(shape).ComposeTransforms(workAnim.GetTransformShapeToGlobal(targShape));\n\n\t// Delete vertex\n\tstd::vector<uint16_t> selInds(1, selVert);\n\tCollectVertexData(shape, uss, selInds);\n\tUndoStateVertex &susv = uss.delVerts.back();\n\n\t// Build replacement vertex from a mix of selected and target vertex data\n\tuss.addVerts.emplace_back();\n\tUndoStateVertex& usv = uss.addVerts.back();\n\tusv.index = selVert;\n\tusv.pos = skx.ApplyTransform(tusv.pos);\n\tusv.uv = susv.uv;\n\tusv.color = tusv.color;\n\tusv.normal = skx.ApplyTransformToDir(tusv.normal);\n\tusv.tangent = skx.ApplyTransformToDir(tusv.tangent);\n\tusv.bitangent = skx.ApplyTransformToDir(tusv.bitangent);\n\tusv.eyeData = tusv.eyeData;\n\tusv.mask = tusv.mask;\n\tusv.weights = std::move(tusv.weights);\n\n\t// UV, clamp, and zap diffs come from selected vertex; position diffs\n\t// come from target\n\tfor (const auto& diff : susv.diffs) {\n\t\tconst SliderData& sd = activeSet[diff.sliderName];\n\t\tif (sd.bUV || sd.bClamp || sd.bZap)\n\t\t\tusv.diffs.push_back(diff);\n\t}\n\tfor (const auto& diff : tusv.diffs) {\n\t\tconst SliderData& sd = activeSet[diff.sliderName];\n\t\tif (!sd.bUV && !sd.bClamp && !sd.bZap) {\n\t\t\tVector3 d = skx.ApplyTransformToDiff(diff.diff);\n\t\t\tusv.diffs.push_back(UndoStateVertexSliderDiff{diff.sliderName, d});\n\t\t}\n\t}\n}\n\nvoid OutfitProject::CheckMerge(const std::string& sourceName, const std::string& targetName, MergeCheckErrors& e) {\n\tif (sourceName == targetName) {\n\t\te.shapesSame = true;\n\t\treturn;\n\t}\n\n\tNiShape* source = workNif.FindBlockByName<NiShape>(sourceName);\n\tif (!source)\n\t\treturn;\n\tNiShape* target = workNif.FindBlockByName<NiShape>(targetName);\n\tif (!target)\n\t\treturn;\n\n\tconstexpr size_t maxVertIndex = std::numeric_limits<uint16_t>().max();\n\tsize_t maxTriIndex = std::numeric_limits<uint16_t>().max();\n\tif (workNif.GetHeader().GetVersion().IsFO4() || workNif.GetHeader().GetVersion().IsFO76())\n\t\tmaxTriIndex = std::numeric_limits<uint32_t>().max();\n\n\tsize_t snVerts = source->GetNumVertices();\n\tsize_t tnVerts = target->GetNumVertices();\n\tif (snVerts + tnVerts > maxVertIndex)\n\t\te.tooManyVertices = true;\n\n\tsize_t snTris = source->GetNumTriangles();\n\tsize_t tnTris = target->GetNumTriangles();\n\tif (snTris + tnTris > maxTriIndex)\n\t\te.tooManyTriangles = true;\n\n\tstd::vector<int> triParts;\n\tNifSegmentationInfo sinf, tinf;\n\tbool gotssegs = workNif.GetShapeSegments(source, sinf, triParts);\n\tbool gottsegs = workNif.GetShapeSegments(target, tinf, triParts);\n\tif (gotssegs != gottsegs) {\n\t\t// Shape with segments and the other without\n\t\te.segmentsMismatch = true;\n\t}\n\telse if (gotssegs) {\n\t\t// Both shapes have segments\n\t\tif (sinf.ssfFile != tinf.ssfFile) {\n\t\t\t// Segment definition file path differs\n\t\t\te.segmentsMismatch = true;\n\t\t}\n\n\t\tif (sinf.segs.size() != tinf.segs.size()) {\n\t\t\t// Shapes have different amount of segments\n\t\t\te.segmentsMismatch = true;\n\t\t}\n\n\t\tfor (size_t si = 0; !e.segmentsMismatch && si < sinf.segs.size(); ++si) {\n\t\t\tif (sinf.segs[si].subs.size() != tinf.segs[si].subs.size()) {\n\t\t\t\t// Shapes have different amount of sub segments\n\t\t\t\te.segmentsMismatch = true;\n\t\t\t}\n\n\t\t\tfor (size_t ssi = 0; !e.segmentsMismatch && ssi < sinf.segs[si].subs.size(); ++ssi) {\n\t\t\t\tconst NifSubSegmentInfo& sssinf = sinf.segs[si].subs[ssi];\n\t\t\t\tconst NifSubSegmentInfo& tssinf = tinf.segs[si].subs[ssi];\n\t\t\t\tif (sssinf.userSlotID != tssinf.userSlotID || sssinf.material != tssinf.material) {\n\t\t\t\t\t// Sub segment information differs\n\t\t\t\t\te.segmentsMismatch = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (workNif.GetHeader().GetVersion().File() == NiFileVersion::V20_2_0_7) {\n\t\tNiVector<BSDismemberSkinInstance::PartitionInfo> spinf, tpinf;\n\t\tbool gotspar = workNif.GetShapePartitions(source, spinf, triParts);\n\t\tbool gottpar = workNif.GetShapePartitions(target, tpinf, triParts);\n\t\tif (gotspar != gottpar) {\n\t\t\t// Shape with partitions and the other without\n\t\t\te.partitionsMismatch = true;\n\t\t}\n\t\telse if (gotspar) {\n\t\t\t// Both shapes have partitions\n\t\t\tif (spinf.size() != tpinf.size()) {\n\t\t\t\t// Shapes have different amount of partitions\n\t\t\t\te.partitionsMismatch = true;\n\t\t\t}\n\n\t\t\tfor (uint32_t pi = 0; !e.partitionsMismatch && pi < spinf.size(); ++pi) {\n\t\t\t\tif (spinf[pi].partID != tpinf[pi].partID) {\n\t\t\t\t\t// Partition slot differs\n\t\t\t\t\te.partitionsMismatch = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tauto sShader = workNif.GetShader(source);\n\tauto tShader = workNif.GetShader(target);\n\tif ((sShader != nullptr) != (tShader != nullptr)) {\n\t\t// Shape with shader and the other without\n\t\te.shaderMismatch = true;\n\t}\n\telse if (sShader) {\n\t\t// Both shapes have a shader\n\t\tif (sShader->GetShaderType() != tShader->GetShaderType()) {\n\t\t\t// Shader type differs\n\t\t\te.shaderMismatch = true;\n\t\t}\n\t\telse if (workNif.GetHeader().GetVersion().IsFO4() || workNif.GetHeader().GetVersion().IsFO76()) {\n\t\t\tif (!StringsEqualInsens(sShader->name.get().c_str(), tShader->name.get().c_str())\n\t\t\t\t|| !StringsEqualInsens(sShader->GetWetMaterialName().c_str(), tShader->GetWetMaterialName().c_str())) {\n\t\t\t\t// Material file paths differ\n\t\t\t\te.shaderMismatch = true;\n\t\t\t}\n\t\t}\n\n\t\tstd::string sTexBase, tTexBase;\n\t\tworkNif.GetTextureSlot(source, sTexBase);\n\t\tworkNif.GetTextureSlot(target, tTexBase);\n\n\t\tif (!StringsEqualInsens(sTexBase.c_str(), tTexBase.c_str())) {\n\t\t\t// Base texture path differs (and possibly UV layout)\n\t\t\te.textureMismatch = true;\n\t\t}\n\t}\n\n\tauto sAlphaProp = workNif.GetAlphaProperty(source);\n\tauto tAlphaProp = workNif.GetAlphaProperty(target);\n\tif ((sAlphaProp != nullptr) != (tAlphaProp != nullptr)) {\n\t\t// Shape with alpha property and the other without\n\t\te.alphaPropMismatch = true;\n\t}\n\telse if (sAlphaProp) {\n\t\t// Both shapes have an alpha property\n\t\tif (sAlphaProp->flags != tAlphaProp->flags || sAlphaProp->threshold != tAlphaProp->threshold) {\n\t\t\t// Flags or threshold differs\n\t\t\te.alphaPropMismatch = true;\n\t\t}\n\t}\n\n\te.canMerge = !e.partitionsMismatch && !e.segmentsMismatch && !e.tooManyVertices && !e.tooManyTriangles && !e.shaderMismatch && !e.textureMismatch && !e.alphaPropMismatch;\n}\n\nvoid OutfitProject::PrepareCopyGeo(NiShape* source, NiShape* target, UndoStateShape& uss) {\n\tif (!source || !target)\n\t\treturn;\n\n\tuint16_t snVerts = source->GetNumVertices();\n\tuint16_t tnVerts = target->GetNumVertices();\n\tuint32_t snTris = source->GetNumTriangles();\n\tuint32_t tnTris = target->GetNumTriangles();\n\n\tstd::vector<uint16_t> vinds(snVerts);\n\tstd::vector<uint32_t> tinds(snTris);\n\tfor (uint16_t i = 0; i < snVerts; ++i)\n\t\tvinds[i] = i;\n\tfor (uint32_t i = 0; i < snTris; ++i)\n\t\ttinds[i] = i;\n\n\tCollectVertexData(source, uss, vinds);\n\tCollectTriangleData(source, uss, tinds);\n\n\tfor (uint16_t vi = 0; vi < snVerts; ++vi)\n\t\tuss.delVerts[vi].index += tnVerts;\n\n\tfor (uint32_t ti = 0; ti < snTris; ++ti) {\n\t\tuss.delTris[ti].index += tnTris;\n\t\tuss.delTris[ti].t.p1 += tnVerts;\n\t\tuss.delTris[ti].t.p2 += tnVerts;\n\t\tuss.delTris[ti].t.p3 += tnVerts;\n\t}\n\n\tuss.delVerts.swap(uss.addVerts);\n\tuss.delTris.swap(uss.addTris);\n}\n\nNiShape* OutfitProject::DuplicateShape(NiShape* sourceShape, const std::string& destShapeName) {\n\tif (!sourceShape)\n\t\treturn nullptr;\n\n\tworkAnim.CloneShape(&workNif, sourceShape, destShapeName);\n\n\tauto newShape = workNif.CloneShape(sourceShape, destShapeName);\n\n\tstd::string shapeName = sourceShape->name.get();\n\tstd::string srcTarget = ShapeToTarget(shapeName);\n\n\tif (IsBaseShape(sourceShape)) {\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tauto& sd = activeSet[i];\n\t\t\tstd::string srcTargetData = sd.TargetDataName(srcTarget);\n\t\t\tif (srcTargetData.empty())\n\t\t\t\tsrcTargetData = baseDiffData.GetDataTargetName(srcTarget, sd.name);\n\n\t\t\tauto diff = baseDiffData.GetDiffSet(srcTargetData);\n\t\t\tif (diff)\n\t\t\t\tmorpher.SetResultDiff(destShapeName, sd.name, *diff);\n\t\t}\n\t}\n\telse {\n\t\tmorpher.CopyShape(shapeName, destShapeName);\n\n\t\tfor (size_t i = 0; i < activeSet.size(); i++) {\n\t\t\tauto& sd = activeSet[i];\n\t\t\tstd::string oldDataName = sd.TargetDataName(srcTarget);\n\t\t\tif (oldDataName.empty())\n\t\t\t\toldDataName = morpher.GetDataTargetName(srcTarget, sd.name);\n\n\t\t\tif (!oldDataName.empty()) {\n\t\t\t\tstd::string newDataName = \"\";\n\n\t\t\t\tif (oldDataName == srcTarget + sd.name)\n\t\t\t\t\tnewDataName = destShapeName + sd.name;\n\t\t\t\telse if (StringStartsWith(oldDataName, srcTarget))\n\t\t\t\t\tnewDataName = destShapeName + oldDataName.substr(srcTarget.length());\n\t\t\t\telse if (StringEndsWith(oldDataName, sd.name))\n\t\t\t\t\tnewDataName = destShapeName + sd.name;\n\n\t\t\t\tif (!newDataName.empty())\n\t\t\t\t\tmorpher.CopySet(oldDataName, newDataName, destShapeName);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn newShape;\n}\n\nvoid OutfitProject::DeleteShape(NiShape* shape) {\n\tif (!shape)\n\t\treturn;\n\n\tstd::string shapeName = shape->name.get();\n\tworkAnim.ClearShape(shapeName);\n\towner->glView->DeleteMesh(shapeName);\n\tshapeTextures.erase(shapeName);\n\tshapeMaterialFiles.erase(shapeName);\n\n\tif (IsBaseShape(shape)) {\n\t\tmorpher.UnlinkRefDiffData();\n\t\tbaseShape = nullptr;\n\t}\n\n\towner->ClearSelected(shape);\n\tworkNif.DeleteShape(shape);\n}\n\nvoid OutfitProject::CaptureShapeDeleteState(NiShape* shape, UndoStateShapeDelete& state) {\n\tif (!shape)\n\t\treturn;\n\n\tstate.shapeName = shape->name.get();\n\tstate.wasBaseShape = IsBaseShape(shape);\n\n\t// Clone shape and all child blocks into a temporary NIF\n\tstate.nifBackup.Create(workNif.GetHeader().GetVersion());\n\tstate.nifBackup.CloneShape(shape, state.shapeName, &workNif);\n\n\t// Capture slider diffs\n\tstd::string target = ShapeToTarget(state.shapeName);\n\tfor (size_t si = 0; si < activeSet.size(); si++) {\n\t\tSliderData& sd = activeSet[si];\n\t\tstd::string targetDataName = sd.TargetDataName(target);\n\t\tif (targetDataName.empty())\n\t\t\ttargetDataName = target + sd.name;\n\n\t\tTargetDataDiffs* diffSet = nullptr;\n\t\tif (state.wasBaseShape)\n\t\t\tdiffSet = baseDiffData.GetDiffSet(targetDataName);\n\t\telse\n\t\t\tdiffSet = morpher.GetDiffSet(targetDataName);\n\n\t\tif (diffSet && !diffSet->empty()) {\n\t\t\tUndoStateShapeSliderDiff ssd;\n\t\t\tssd.sliderName = sd.name;\n\t\t\tssd.targetDataName = targetDataName;\n\t\t\tssd.diffs = *diffSet;\n\t\t\tstate.sliderDiffs.push_back(std::move(ssd));\n\t\t}\n\t}\n\n\t// Capture texture and material references\n\tauto tex = shapeTextures.find(state.shapeName);\n\tif (tex != shapeTextures.end())\n\t\tstate.textures = tex->second;\n\n\tauto mat = shapeMaterialFiles.find(state.shapeName);\n\tif (mat != shapeMaterialFiles.end())\n\t\tstate.materialFile = mat->second;\n}\n\nNiShape* OutfitProject::RestoreDeletedShape(UndoStateShapeDelete& state) {\n\t// Find the backup shape in the temp NIF\n\tauto backupShapes = state.nifBackup.GetShapes();\n\tif (backupShapes.empty())\n\t\treturn nullptr;\n\n\tNiShape* backupShape = backupShapes.front();\n\n\t// Rename if a shape with the same name already exists\n\tstd::string restoreName = state.shapeName;\n\tif (workNif.FindBlockByName<NiShape>(restoreName)) {\n\t\tint suffix = 2;\n\t\tstd::string candidate;\n\t\tdo {\n\t\t\tcandidate = restoreName + \"_\" + std::to_string(suffix++);\n\t\t} while (workNif.FindBlockByName<NiShape>(candidate));\n\n\t\twxLogMessage(\"Restoring shape '%s' as '%s' (name conflict).\", restoreName, candidate);\n\t\trestoreName = candidate;\n\t}\n\n\tstate.shapeName = restoreName;\n\n\t// Clone shape back into working NIF\n\tauto restoredShape = workNif.CloneShape(backupShape, restoreName, &state.nifBackup);\n\tif (!restoredShape)\n\t\treturn nullptr;\n\n\t// Reload bone weights from the cloned NIF blocks\n\tworkAnim.LoadFromNif(&workNif, restoredShape);\n\n\t// Restore slider diffs\n\tstd::string target = ShapeToTarget(state.shapeName);\n\tbool restoreAsBase = state.wasBaseShape && baseShape == nullptr;\n\n\tfor (auto& ssd : state.sliderDiffs) {\n\t\tif (restoreAsBase)\n\t\t\tbaseDiffData.LoadSet(ssd.targetDataName, target, ssd.diffs);\n\t\telse\n\t\t\tmorpher.SetResultDiff(state.shapeName, ssd.sliderName, ssd.diffs);\n\t}\n\n\t// Restore texture and material references\n\tif (!state.textures.empty())\n\t\tshapeTextures[state.shapeName] = state.textures;\n\n\tif (state.materialFile.has_value())\n\t\tshapeMaterialFiles[state.shapeName] = state.materialFile.value();\n\n\t// Restore base shape status if appropriate\n\tif (restoreAsBase) {\n\t\tbaseShape = restoredShape;\n\t\tmorpher.LinkRefDiffData(&baseDiffData);\n\t}\n\n\treturn restoredShape;\n}\n\nvoid OutfitProject::RenameShape(NiShape* shape, const std::string& newShapeName) {\n\tstd::string shapeName = shape->name.get();\n\tstd::string oldTarget = ShapeToTarget(shapeName);\n\n\tworkNif.RenameShape(shape, newShapeName);\n\tworkAnim.RenameShape(shapeName, newShapeName);\n\n\tbool isBaseShape = IsBaseShape(shape);\n\tfor (size_t si = 0; si < activeSet.size(); ++si) {\n\t\tSliderData& sd = activeSet[si];\n\t\tstd::string oldDataName = sd.TargetDataName(oldTarget);\n\t\tif (oldDataName.empty()) {\n\t\t\tif (isBaseShape)\n\t\t\t\toldDataName = baseDiffData.GetDataTargetName(oldTarget, sd.name);\n\t\t\telse\n\t\t\t\toldDataName = morpher.GetDataTargetName(oldTarget, sd.name);\n\t\t}\n\n\t\tif (!oldDataName.empty()) {\n\t\t\tstd::string newDataName = \"\";\n\n\t\t\tif (oldDataName == oldTarget + sd.name)\n\t\t\t\tnewDataName = newShapeName + sd.name;\n\t\t\telse if (StringStartsWith(oldDataName, oldTarget))\n\t\t\t\tnewDataName = newShapeName + oldDataName.substr(oldTarget.length());\n\t\t\telse if (StringEndsWith(oldDataName, sd.name))\n\t\t\t\tnewDataName = newShapeName + sd.name;\n\n\t\t\tif (!newDataName.empty()) {\n\t\t\t\tif (isBaseShape)\n\t\t\t\t\tbaseDiffData.RenameSet(oldDataName, newDataName);\n\t\t\t\telse\n\t\t\t\t\tmorpher.RenameSet(oldDataName, newDataName);\n\t\t\t}\n\t\t}\n\t}\n\n\tactiveSet.RenameShape(shapeName, newShapeName);\n\n\tauto tex = shapeTextures.find(shapeName);\n\tif (tex != shapeTextures.end()) {\n\t\tauto value = tex->second;\n\t\tshapeTextures.erase(tex);\n\t\tshapeTextures[newShapeName] = value;\n\t}\n\n\tauto mat = shapeMaterialFiles.find(shapeName);\n\tif (mat != shapeMaterialFiles.end()) {\n\t\tauto value = mat->second;\n\t\tshapeMaterialFiles.erase(mat);\n\t\tshapeMaterialFiles[newShapeName] = value;\n\t}\n\n\tif (isBaseShape) {\n\t\tbaseDiffData.RenameDataTarget(oldTarget, newShapeName);\n\t\tactiveSet.SetReferencedData(newShapeName, true);\n\t}\n\telse {\n\t\tmorpher.RenameDataTarget(oldTarget, newShapeName);\n\t\tmorpher.RenameShape(shapeName, newShapeName);\n\t}\n\n\twxLogMessage(\"Renamed shape '%s' to '%s'.\", shapeName, newShapeName);\n}\n\nvoid OutfitProject::UpdateNifNormals(NifFile* nif, const std::vector<Mesh*>& shapeMeshes) {\n\tstd::vector<Vector3> liveNorms;\n\tfor (auto& m : shapeMeshes) {\n\t\tauto shape = nif->FindBlockByName<NiShape>(m->shapeName);\n\t\tif (shape) {\n\t\t\tif (nif->GetHeader().GetVersion().IsSK() || nif->GetHeader().GetVersion().IsSSE()) {\n\t\t\t\tNiShader* shader = nif->GetShader(shape);\n\t\t\t\tif (shader && shader->IsModelSpace())\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tliveNorms.clear();\n\t\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\t\tliveNorms.push_back(Mesh::TransformDirMeshToNif(m->norms[i]));\n\n\t\t\tnif->SetNormalsForShape(shape, liveNorms);\n\t\t\tnif->CalcTangentsForShape(shape);\n\t\t}\n\t}\n}\n\nvoid OutfitProject::MatchSymmetricVertices(NiShape* shape, const Mesh::WeldVertsType& weldVerts, SymmetricVertices& r) {\n\t// Gather shape's vertices\n\tstd::vector<Vector3> verts;\n\tworkNif.GetVertsForShape(shape, verts);\n\tint origNVerts = static_cast<int>(verts.size());\n\n\t// Dealing with welded vertices is potentially very messy.  So we\n\t// remove all but one vertex of each welded set from the vertex list,\n\t// producing a reduced vertex list.  The surviving vertex of each\n\t// welded set is the one with the lowest index.\n\tstd::vector<int> indRedToOrig(origNVerts);\n\tint redNVerts = 0;\n\tfor (int vi = 0; vi < origNVerts; ++vi) {\n\t\tif (Mesh::LeastWeldedVertexIndex(weldVerts, vi) == vi)\n\t\t\tindRedToOrig[redNVerts++] = vi;\n\t}\n\n\t// Delete welded vertices from our copy of the vertex list.\n\tfor (int vi = 0; vi < redNVerts; ++vi)\n\t\tverts[vi] = verts[indRedToOrig[vi]];\n\n\t// Build proximity cache for vertices.\n\t// Note that kd_tree keeps pointers into verts.\n\tkd_tree<uint16_t> vertTree(&verts[0], redNVerts);\n\n\tstruct VertData {\n\t\t// bad: no match or a bad match\n\t\tbool bad = false;\n\t\t// mi: matched vertex's index.  The value of -1 is not meaningful,\n\t\t// except it's not a valid vertex index.\n\t\tint mi = -1;\n\t\tint matchcount = 0;\n\t};\n\tstd::vector<VertData> vdata(redNVerts);\n\n\t// Main loop through the reduced vertex set.\n\tfor (int vi = 0; vi < redNVerts; ++vi) {\n\t\t// Construct mirror coordinates\n\t\tVector3 mc = verts[vi];\n\t\tmc.x = -mc.x;\n\n\t\t// Match\n\t\tvertTree.kd_nn(&mc, 0);\n\n\t\t// mi: matched vertex's index\n\t\tint mi = vertTree.queryResult[0].vertex_index;\n\t\tvdata[vi].mi = mi;\n\t\t++vdata[mi].matchcount;\n\t}\n\n\t// Mark a vertex bad if two vertices matched to it, if its matched\n\t// vertex didn't match to it, or if its match is bad.\n\tfor (int vi = 0; vi < redNVerts; ++vi)\n\t\tif (vdata[vi].matchcount != 1 || vdata[vdata[vi].mi].mi != vi) {\n\t\t\tvdata[vi].bad = true;\n\t\t\tvdata[vdata[vi].mi].bad = true;\n\t\t}\n\n\t// Put results in r.\n\tfor (int vi = 0; vi < redNVerts; ++vi) {\n\t\tconst VertData& vd = vdata[vi];\n\t\tif (vd.bad)\n\t\t\tr.unmatched.push_back(indRedToOrig[vi]);\n\t\telse if (vi <= vd.mi)\n\t\t\tr.matches.emplace_back(indRedToOrig[vi], indRedToOrig[vd.mi]);\n\t}\n}\n\nvoid OutfitProject::MatchSymmetricBoneNames(std::vector<std::pair<std::string, std::string>>& pairs, std::vector<std::string>& singles) {\n\t// Note that there is very similar code to this in OutfitStudioFrame::CalcAutoXMirrorBone.\n\tstd::vector<std::string> bones;\n\tGetActiveBones(bones);\n\n\tAnimInfo::MatchSymmetricBoneNames(bones, pairs, singles);\n}\n\nvoid OutfitProject::FindVertexAsymmetries(NiShape* shape, const SymmetricVertices& symverts, const Mesh::WeldVertsType& weldVerts, VertexAsymmetries& r) {\n\t// Get shape's vertices\n\tstd::vector<Vector3> verts;\n\tworkNif.GetVertsForShape(shape, verts);\n\tint nVerts = static_cast<int>(shape->GetNumVertices());\n\n\t// Create welded-vertex set for every vertex\n\tstd::vector<std::vector<int>> weldSets(nVerts);\n\tfor (int vi = 0; vi < nVerts; ++vi)\n\t\tMesh::GetWeldSet(weldVerts, vi, weldSets[vi]);\n\n\t// Initialize global result arrays\n\tint nMatches = static_cast<int>(symverts.matches.size());\n\tr.positions.resize(nMatches, false);\n\tr.anyslider.resize(nMatches, false);\n\tr.anybone.resize(nMatches, false);\n\tr.poserr.resize(nMatches, 0.0f);\n\n\t// Find position asymmetries\n\tfor (int mpi = 0; mpi < nMatches; ++mpi) {\n\t\tbool asym = false;\n\t\tfloat err = 0.0f;\n\t\tint errCount = 0;\n\t\tfor (int p1 : weldSets[symverts.matches[mpi].first]) {\n\t\t\tVector3 v1 = verts[p1];\n\t\t\tv1.x = -v1.x;\n\t\t\tfor (int p2 : weldSets[symverts.matches[mpi].second])\n\t\t\t\tif (v1 != verts[p2]) {\n\t\t\t\t\tasym = true;\n\t\t\t\t\terr += (v1 - verts[p2]).length();\n\t\t\t\t\t++errCount;\n\t\t\t\t}\n\t\t}\n\t\tif (asym) {\n\t\t\tr.positions[mpi] = true;\n\t\t\tr.poserr[mpi] = err / errCount;\n\t\t}\n\t}\n\n\t// Find position slider asymmetries\n\tfor (size_t si = 0; si < activeSet.size(); ++si) {\n\t\tSliderData& sd = activeSet[si];\n\t\tif (sd.bUV || sd.bClamp || sd.bZap)\n\t\t\tcontinue;\n\n\t\t// Get the diffs for this slider\n\t\tconst std::unordered_map<uint16_t, Vector3>* diffSet = GetDiffSet(sd, shape);\n\t\tif (!diffSet)\n\t\t\tcontinue;\n\n\t\t// Initialize all the data we'll be collecting for this slider\n\t\tstd::vector<bool> aflags(nMatches, false);\n\t\tstd::vector<float> differr(nMatches, 0.0f);\n\t\tbool sliderasym = false;\n\n\t\t// Main loop through matches (for sliders).\n\t\tfor (int mpi = 0; mpi < nMatches; ++mpi) {\n\t\t\tbool asym = false;\n\t\t\tfloat err = 0.0f;\n\t\t\tint errCount = 0;\n\n\t\t\t// Loop through weld set of match's first point\n\t\t\tfor (int p1 : weldSets[symverts.matches[mpi].first]) {\n\t\t\t\t// Get p1's diff\n\t\t\t\tVector3 p1diff;\n\t\t\t\tauto dit1 = diffSet->find(p1);\n\t\t\t\tif (dit1 != diffSet->end())\n\t\t\t\t\tp1diff = dit1->second;\n\t\t\t\tp1diff.x = -p1diff.x;\n\n\t\t\t\t// Loop through weld set of match's second point\n\t\t\t\tfor (int p2 : weldSets[symverts.matches[mpi].second]) {\n\t\t\t\t\t// Get p2's diff\n\t\t\t\t\tVector3 p2diff;\n\t\t\t\t\tauto dit2 = diffSet->find(p2);\n\t\t\t\t\tif (dit2 != diffSet->end())\n\t\t\t\t\t\tp2diff = dit2->second;\n\n\t\t\t\t\t// Check for asymmetry\n\t\t\t\t\tif (p1diff != p2diff) {\n\t\t\t\t\t\tasym = true;\n\t\t\t\t\t\terr += (p1diff - p2diff).length();\n\t\t\t\t\t\t++errCount;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If this match had an asymmetry, record it\n\t\t\tif (asym) {\n\t\t\t\taflags[mpi] = true;\n\t\t\t\tdifferr[mpi] = err / errCount;\n\t\t\t\tsliderasym = true;\n\t\t\t\tr.anyslider[mpi] = true;\n\t\t\t}\n\t\t}\n\n\t\t// If this slider had an asymmetry, store the results\n\t\tif (sliderasym) {\n\t\t\tr.sliders.emplace_back();\n\t\t\tr.sliders.back().sliderName = sd.name;\n\t\t\tr.sliders.back().aflags = std::move(aflags);\n\t\t\tr.sliders.back().differr = std::move(differr);\n\t\t}\n\t}\n\n\t// Get list of symmetric bone pairings and unpaired bones\n\tstd::vector<std::pair<std::string, std::string>> bPairs;\n\tstd::vector<std::string> bSingles;\n\tMatchSymmetricBoneNames(bPairs, bSingles);\n\tint nbPairs = static_cast<int>(bPairs.size());\n\tint nbSingles = static_cast<int>(bSingles.size());\n\tAnimSkin& skin = workAnim.shapeSkinning[shape->name.get()];\n\n\t// Find bone weight asymmetries\n\tstd::unordered_map<uint16_t, float> dummyWeights;\n\tfor (int bpi = 0; bpi < nbPairs + nbSingles; ++bpi) {\n\t\t// Get the names of our one or two bones\n\t\tstd::string b1name, b2name;\n\t\tbool isBonePair = bpi < nbPairs;\n\t\tif (isBonePair) {\n\t\t\tb1name = bPairs[bpi].first;\n\t\t\tb2name = bPairs[bpi].second;\n\t\t}\n\t\telse {\n\t\t\tb1name = bSingles[bpi - nbPairs];\n\t\t\tb2name = b1name;\n\t\t}\n\n\t\t// Look up the weights for both bones\n\t\tauto bnit = skin.boneNames.find(b1name);\n\t\tconst std::unordered_map<uint16_t, float>& b1w = bnit != skin.boneNames.end() ? skin.boneWeights[bnit->second].weights : dummyWeights;\n\t\tbnit = skin.boneNames.find(b2name);\n\t\tconst std::unordered_map<uint16_t, float>& b2w = bnit != skin.boneNames.end() ? skin.boneWeights[bnit->second].weights : dummyWeights;\n\n\t\t// Initialize all the data we'll be calculating for this bone/bones.\n\t\tstd::vector<bool> aflags1(nMatches, false);\n\t\tstd::vector<bool> aflags2(nMatches, false);\n\t\tstd::vector<float> weighterr1(nMatches, 0.0f);\n\t\tstd::vector<float> weighterr2(nMatches, 0.0f);\n\t\tbool boneasym = false;\n\n\t\t// Main loop through matches for a bone or bone pair.\n\t\tfor (int mpi = 0; mpi < nMatches; ++mpi) {\n\t\t\tbool asym1 = false, asym2 = false;\n\t\t\tfloat werr1 = 0.0f, werr2 = 0.0f;\n\t\t\tint werr1count = 0, werr2count = 0;\n\n\t\t\t// Loop through weld set for match's first point\n\t\t\tfor (int p1 : weldSets[symverts.matches[mpi].first]) {\n\t\t\t\t// Find weights of p1 for bone 1 and bone 2\n\t\t\t\tfloat p1b1w = 0.0f, p1b2w = 0.0f;\n\t\t\t\tauto wit = b1w.find(p1);\n\t\t\t\tif (wit != b1w.end())\n\t\t\t\t\tp1b1w = wit->second;\n\t\t\t\twit = b2w.find(p1);\n\t\t\t\tif (wit != b2w.end())\n\t\t\t\t\tp1b2w = wit->second;\n\n\t\t\t\t// Loop through weld set for match's second point\n\t\t\t\tfor (int p2 : weldSets[symverts.matches[mpi].second]) {\n\t\t\t\t\t// Find weights of p2 for bone 1 and bone 2\n\t\t\t\t\tfloat p2b1w = 0.0f, p2b2w = 0.0f;\n\t\t\t\t\twit = b1w.find(p2);\n\t\t\t\t\tif (wit != b1w.end())\n\t\t\t\t\t\tp2b1w = wit->second;\n\t\t\t\t\twit = b2w.find(p2);\n\t\t\t\t\tif (wit != b2w.end())\n\t\t\t\t\t\tp2b2w = wit->second;\n\n\t\t\t\t\t// Check for asymmetry between p1's bone 1 weight and\n\t\t\t\t\t// p2's bone 2 weight.\n\t\t\t\t\tif (p1b1w != p2b2w) {\n\t\t\t\t\t\tasym1 = true;\n\t\t\t\t\t\twerr1 += std::fabs(p1b1w - p2b2w);\n\t\t\t\t\t\t++werr1count;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check for asymmetry between p1's bone 2 weight and\n\t\t\t\t\t// p2's bone 1 weight.\n\t\t\t\t\tif (p1b2w != p2b1w) {\n\t\t\t\t\t\tasym2 = true;\n\t\t\t\t\t\twerr2 += std::fabs(p1b2w - p2b1w);\n\t\t\t\t\t\t++werr2count;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// end loops through weld sets of the match's two points\n\n\t\t\t// Record results for this match for this bone or bone pair\n\t\t\tif (asym1) {\n\t\t\t\taflags1[mpi] = true;\n\t\t\t\tweighterr1[mpi] = werr1 / werr1count;\n\t\t\t}\n\t\t\tif (asym2) {\n\t\t\t\taflags2[mpi] = true;\n\t\t\t\tweighterr2[mpi] = werr2 / werr2count;\n\t\t\t}\n\t\t\tif (asym1 || asym2) {\n\t\t\t\tr.anybone[mpi] = true;\n\t\t\t\tboneasym = true;\n\t\t\t}\n\t\t}\n\t\t// end main loop through matches for a bone or bone pair\n\n\t\t// If we have any weight asymmetries for this bone or bone pair,\n\t\t// store the results.\n\t\tif (boneasym) {\n\t\t\tr.bones.emplace_back();\n\t\t\tr.bones.back().boneName = b1name;\n\t\t\tr.bones.back().mirroroffset = isBonePair ? 1 : 0;\n\t\t\tr.bones.back().aflags = std::move(aflags1);\n\t\t\tr.bones.back().weighterr = std::move(weighterr1);\n\t\t\tif (isBonePair) {\n\t\t\t\tr.bones.emplace_back();\n\t\t\t\tr.bones.back().boneName = b2name;\n\t\t\t\tr.bones.back().mirroroffset = -1;\n\t\t\t\tr.bones.back().aflags = std::move(aflags2);\n\t\t\t\tr.bones.back().weighterr = std::move(weighterr2);\n\t\t\t}\n\t\t}\n\t}\n}\n\nstd::vector<bool> CalcVertexListForAsymmetryTasks(const SymmetricVertices& symverts, const VertexAsymmetries& asyms, const VertexAsymmetryTasks& tasks, int nVerts) {\n\tint nSliders = static_cast<int>(asyms.sliders.size());\n\tint nBones = static_cast<int>(asyms.bones.size());\n\tint nMatches = static_cast<int>(asyms.positions.size());\n\n\tstd::vector<bool> doVert(nVerts, false);\n\tfor (int mi = 0; mi < nMatches; ++mi) {\n\t\tint p1 = symverts.matches[mi].first;\n\t\tint p2 = symverts.matches[mi].second;\n\n\t\t// Positions\n\t\tif (tasks.doPos && asyms.positions[mi])\n\t\t\tdoVert[p1] = doVert[p2] = true;\n\n\t\t// Sliders\n\t\tfor (int sai = 0; sai < nSliders; ++sai)\n\t\t\tif (tasks.doSliders[sai] && asyms.sliders[sai].aflags[mi])\n\t\t\t\tdoVert[p1] = doVert[p2] = true;\n\n\t\t// Bones\n\t\tfor (int bi = 0; bi < nBones; ++bi) {\n\t\t\tif (!asyms.bones[bi].aflags[mi])\n\t\t\t\tcontinue;\n\t\t\tif (tasks.doBones[bi])\n\t\t\t\tdoVert[p1] = true;\n\t\t\tif (tasks.doBones[bi + asyms.bones[bi].mirroroffset])\n\t\t\t\tdoVert[p2] = true;\n\t\t}\n\t}\n\n\tif (tasks.doUnmatched)\n\t\tfor (int vi : symverts.unmatched)\n\t\t\tdoVert[vi] = true;\n\n\treturn doVert;\n}\n\nvoid AddWeldedToVertexList(const Mesh::WeldVertsType& weldVerts, std::vector<bool>& verts) {\n\tfor (size_t i = 0; i < verts.size(); ++i) {\n\t\tif (!verts[i])\n\t\t\tcontinue;\n\t\tMesh::DoForEachWeldedVertex(weldVerts, i, [&](int p){verts[p] = true;});\n\t}\n}\n\nstatic int SelCount(const std::vector<bool>& sel) {\n\tint c = 0;\n\tfor (size_t i = 0; i < sel.size(); ++i)\n\t\tc += sel[i];\n\treturn c;\n}\n\nstatic int SelCount(const std::vector<bool>& sel, const std::vector<bool>& osel) {\n\tint c = 0;\n\tfor (size_t i = 0; i < sel.size(); ++i)\n\t\tif (sel[i] && osel[i])\n\t\t\t++c;\n\treturn c;\n}\n\nstatic float SelAvg(const std::vector<bool>& sel, const std::vector<float>& vals) {\n\tfloat sum = 0.0f;\n\tint c = 0;\n\tfor (size_t i = 0; i < sel.size(); ++i)\n\t\tif (sel[i]) {\n\t\t\tsum += vals[i];\n\t\t\t++c;\n\t\t}\n\treturn c ? sum / c : 0.0f;\n}\n\nvoid CalcVertexAsymmetryStats(const SymmetricVertices& symverts, const VertexAsymmetries& asyms, const std::vector<bool>& selVerts, VertexAsymmetryStats& stats) {\n\tint nSliders = static_cast<int>(asyms.sliders.size());\n\tint nBones = static_cast<int>(asyms.bones.size());\n\tint nMatches = static_cast<int>(asyms.positions.size());\n\n\t// Calculate which matches are not masked\n\tstd::vector<bool> selMatches(nMatches);\n\tfor (int mi = 0; mi < nMatches; ++mi)\n\t\tselMatches[mi] = selVerts[symverts.matches[mi].first] || selVerts[symverts.matches[mi].second];\n\n\tstats.boneCounts.resize(nBones, 0);\n\tstats.boneAvgs.resize(nBones, 0.0f);\n\tstats.sliderCounts.resize(nSliders, 0);\n\tstats.sliderAvgs.resize(nSliders, 0.0f);\n\tstats.unmaskedCount = SelCount(selVerts);\n\tstats.posCount = SelCount(selMatches, asyms.positions);\n\tstats.posAvg = SelAvg(selMatches, asyms.poserr);\n\tstats.anySliderCount = SelCount(selMatches, asyms.anyslider);\n\tstats.anyBoneCount = SelCount(selMatches, asyms.anybone);\n\n\tfor (int si = 0; si < nSliders; ++si) {\n\t\tstats.sliderCounts[si] = SelCount(selMatches, asyms.sliders[si].aflags);\n\t\tstats.sliderAvgs[si] = SelAvg(selMatches, asyms.sliders[si].differr);\n\t}\n\n\tfor (int bi = 0; bi < nBones; ++bi) {\n\t\tint bi2 = bi + asyms.bones[bi].mirroroffset;\n\t\tfloat sum = 0.0f;\n\t\tint count = 0;\n\n\t\tfor (int mi = 0; mi < nMatches; ++mi) {\n\t\t\tint p1 = symverts.matches[mi].first;\n\t\t\tint p2 = symverts.matches[mi].second;\n\t\t\tif (!selVerts[p1] && !selVerts[p2])\n\t\t\t\tcontinue;\n\n\t\t\t// b1 aflags says: p1 b1 mismatches p2 b2\n\t\t\t// b2 aflags says: p1 b2 mismatches p2 b1\n\t\t\t// We need to sum the data for b1; that is, the first and fourth\n\t\t\t// cases.\n\t\t\tif (selVerts[p1] && asyms.bones[bi].aflags[mi]) {\n\t\t\t\tsum += asyms.bones[bi].weighterr[mi];\n\t\t\t\t++count;\n\t\t\t}\n\t\t\tif (p1 != p2 && selVerts[p2] && asyms.bones[bi2].aflags[mi]) {\n\t\t\t\tsum += asyms.bones[bi2].weighterr[mi];\n\t\t\t\t++count;\n\t\t\t}\n\t\t}\n\n\t\tstats.boneCounts[bi] = count;\n\t\tif (count)\n\t\t\tstats.boneAvgs[bi] = sum / count;\n\t}\n}\n\nstatic Vector3 GetUSliderDiff(const UndoStateVertex& usv, const std::string& name) {\n\tfor (const auto& sd : usv.diffs)\n\t\tif (sd.sliderName == name)\n\t\t\treturn sd.diff;\n\treturn Vector3();\n}\n\nstatic void SetUSliderDiff(UndoStateVertex& usv, const std::string& name, const Vector3& diff) {\n\tfor (auto& sd : usv.diffs)\n\t\tif (sd.sliderName == name) {\n\t\t\tsd.diff = diff;\n\t\t\treturn;\n\t\t}\n\tusv.diffs.push_back(UndoStateVertexSliderDiff{name, diff});\n}\n\nstatic float GetUWeight(const UndoStateVertex& usv, const std::string& name) {\n\tfor (const auto& bw : usv.weights)\n\t\tif (bw.boneName == name)\n\t\t\treturn bw.w;\n\treturn 0.0f;\n}\n\n// The two versions of SetUWeight are for storing it in uss.boneWeights\n// (first version) or usv.weights (second version).  The first is needed\n// by the normalizer; the second is the final location.\nstatic void SetUWeight(UndoStateShape& uss, int p, const std::string& bn, float w) {\n\tfor (auto& bw : uss.boneWeights)\n\t\tif (bw.boneName == bn) {\n\t\t\tbw.weights[p].endVal = w;\n\t\t\treturn;\n\t\t}\n}\n\nstatic void SetUWeight(UndoStateVertex& usv, const std::string& bn, float w) {\n\tfor (auto& bw : usv.weights)\n\t\tif (bw.boneName == bn) {\n\t\t\tbw.w = w;\n\t\t\treturn;\n\t\t}\n\tusv.weights.push_back(UndoStateVertexBoneWeight{bn, w});\n}\n\nvoid OutfitProject::PrepareSymmetrizeVertices(NiShape* shape, UndoStateShape& uss, const SymmetricVertices& symverts, const VertexAsymmetries& asyms, const VertexAsymmetryTasks& tasks, const Mesh::WeldVertsType& weldVerts, const std::vector<bool>& selVerts, const std::vector<std::string>& userNormBones, const std::vector<std::string>& userNotNormBones) {\n\tint nMatches = static_cast<int>(symverts.matches.size());\n\tint nVerts = static_cast<int>(shape->GetNumVertices());\n\tint nSliders = static_cast<int>(asyms.sliders.size());\n\tint nBones = static_cast<int>(asyms.bones.size());\n\n\t// To simplify the handling of vertex data, we collect the data for\n\t// all vertices.  We will keep track of which vertices we actually\n\t// modify and put just the modified data in uss at the end.  The new\n\t// vertex data (tuss.addVerts) is initially a copy of the old vertex\n\t// data (tuss.delVerts).\n\tstd::vector<uint16_t> allvinds(nVerts);\n\tfor (uint16_t i = 0; i < nVerts; ++i)\n\t\tallvinds[i] = i;\n\tUndoStateShape tuss;\n\tCollectVertexData(shape, tuss, allvinds);\n\ttuss.addVerts = tuss.delVerts;\n\tstd::vector<bool> vChanged(nVerts, false);\n\n\t// Prepare bone list for bone weight normalizer.  First, we add the\n\t// bones that are being symmetrized to normBones.\n\tstd::vector<std::string> normBones;\t// order is important: sel before unsel\n\tstd::unordered_set<std::string> normBonesSet;\n\tfor (int bai = 0; bai < nBones; ++bai)\n\t\tif (tasks.doBones[bai]) {\n\t\t\tnormBones.push_back(asyms.bones[bai].boneName);\n\t\t\tnormBonesSet.insert(asyms.bones[bai].boneName);\n\t\t}\n\tint nMBones = static_cast<int>(normBones.size());\n\n\t// Next, we add the norm-bones from the user to normBones, if they\n\t// aren't already there.\n\tbool hasNormBones = false;\n\tfor (const std::string& bone : userNormBones)\n\t\tif (!normBonesSet.count(bone)) {\n\t\t\tnormBones.push_back(bone);\n\t\t\tnormBonesSet.insert(bone);\n\t\t\thasNormBones = true;\n\t\t}\n\n\t// Finally, we add the not-norm-bones from the user.  If the user has\n\t// picked some norm bones that aren't being symmetrized, then we can\n\t// lock all the not-norm-bones.  Otherwise, they become norm bones.\n\tstd::vector<std::string> lockedBones;\n\tfor (const std::string& bone : userNotNormBones)\n\t\tif (!normBonesSet.count(bone)) {\n\t\t\tif (hasNormBones)\n\t\t\t\tlockedBones.push_back(bone);\n\t\t\telse\n\t\t\t\tnormBones.push_back(bone);\n\t\t}\n\n\t// Initialize the bone weight normalizer\n\tBoneWeightAutoNormalizer nzer;\n\tnzer.SetUp(&tuss, &workAnim, shape->name.get(), normBones, lockedBones, nMBones, hasNormBones);\n\n\t// Because we might be adjusting the weights for several different bones\n\t// for a given point, we have to delay normalization until after the\n\t// main loop.  Only the first point in each weld set is normalized;\n\t// the result is copied to the other points in the weld set.\n\tstd::vector<bool> weightAdjustPoint(nVerts, false);\n\n\t// Main loop through matches\n\tstd::vector<int> p1s, p2s;\n\tfor (int mi = 0; mi < nMatches; ++mi) {\n\t\tint p1 = symverts.matches[mi].first;\n\t\tint p2 = symverts.matches[mi].second;\n\t\tif (!selVerts[p1] && !selVerts[p2])\n\t\t\tcontinue;\n\n\t\tMesh::GetWeldSet(weldVerts, p1, p1s);\n\t\tMesh::GetWeldSet(weldVerts, p2, p2s);\n\n\t\t// Symmetrize position\n\t\tif (tasks.doPos && asyms.positions[mi]) {\n\t\t\t// Calculate average\n\t\t\tVector3 avg;\n\t\t\tint avgcount = 0;\n\t\t\tif (selVerts[p1]) {\n\t\t\t\tVector3 sum;\n\t\t\t\tfor (int p : p2s)\n\t\t\t\t\tsum += tuss.addVerts[p].pos;\n\t\t\t\tavg += sum / p2s.size();\n\t\t\t\t++avgcount;\n\t\t\t}\n\t\t\tif (p1 == p2)\n\t\t\t\tavg.x = 0;\n\t\t\telse {\n\t\t\t\tavg.x = -avg.x;\n\t\t\t\tif (selVerts[p2]) {\n\t\t\t\t\tVector3 sum;\n\t\t\t\t\tfor (int p : p1s)\n\t\t\t\t\t\tsum += tuss.addVerts[p].pos;\n\t\t\t\t\tavg += sum / p1s.size();\n\t\t\t\t\t++avgcount;\n\t\t\t\t}\n\t\t\t\tavg /= avgcount;\n\t\t\t}\n\n\t\t\t// Store average\n\t\t\tif (selVerts[p1]) {\n\t\t\t\tfor (int p : p1s) {\n\t\t\t\t\ttuss.addVerts[p].pos = avg;\n\t\t\t\t\tvChanged[p] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (selVerts[p2]) {\n\t\t\t\tavg.x = -avg.x;\n\t\t\t\tfor (int p : p2s) {\n\t\t\t\t\ttuss.addVerts[p].pos = avg;\n\t\t\t\t\tvChanged[p] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Symmetrize position slider diffs\n\t\tfor (int si = 0; si < nSliders; ++si) {\n\t\t\tif (!tasks.doSliders[si])\n\t\t\t\tcontinue;\n\t\t\tconst auto& sd = asyms.sliders[si];\n\t\t\tif (!sd.aflags[mi])\n\t\t\t\tcontinue;\n\n\t\t\t// Calculate average\n\t\t\tVector3 avg;\n\t\t\tint avgcount = 0;\n\t\t\tif (selVerts[p1]) {\n\t\t\t\tVector3 sum;\n\t\t\t\tfor (int p : p2s)\n\t\t\t\t\tsum += GetUSliderDiff(tuss.addVerts[p], sd.sliderName);\n\t\t\t\tavg = sum / p2s.size();\n\t\t\t\t++avgcount;\n\t\t\t}\n\t\t\tif (p1 == p2)\n\t\t\t\tavg.x = 0;\n\t\t\telse {\n\t\t\t\tavg.x = -avg.x;\n\t\t\t\tif (selVerts[p2]) {\n\t\t\t\t\tVector3 sum;\n\t\t\t\t\tfor (int p : p1s)\n\t\t\t\t\t\tsum += GetUSliderDiff(tuss.addVerts[p], sd.sliderName);\n\t\t\t\t\tavg += sum / p1s.size();\n\t\t\t\t\t++avgcount;\n\t\t\t\t}\n\t\t\t\tavg /= avgcount;\n\t\t\t}\n\n\t\t\t// Store average\n\t\t\tif (selVerts[p1]) {\n\t\t\t\tfor (int p : p1s) {\n\t\t\t\t\tSetUSliderDiff(tuss.addVerts[p], sd.sliderName, avg);\n\t\t\t\t\tvChanged[p] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (selVerts[p2]) {\n\t\t\t\tavg.x = -avg.x;\n\t\t\t\tfor (int p : p2s) {\n\t\t\t\t\tSetUSliderDiff(tuss.addVerts[p], sd.sliderName, avg);\n\t\t\t\t\tvChanged[p] = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Symmetrize bone weights\n\t\tfor (int bi = 0; bi < nBones; ++bi) {\n\t\t\t// Figure out exactly what we need to do for this match, given\n\t\t\t// all our flags.  Note that there are cases (such as with\n\t\t\t// self-matches) where we update a weight twice or sum some\n\t\t\t// values twice, but the result is always the same.  Trying to\n\t\t\t// make this code update things just once or sum things just\n\t\t\t// once would make it much more complex.\n\t\t\tconst auto& bd1 = asyms.bones[bi];\n\t\t\tconst auto& bd2 = asyms.bones[bi + bd1.mirroroffset];\n\t\t\tif (!bd1.aflags[mi])\n\t\t\t\tcontinue;\n\t\t\tbool doThisBone = selVerts[p1] && tasks.doBones[bi];\n\t\t\tbool doMirrorBone = selVerts[p2] && tasks.doBones[bi + bd1.mirroroffset];\n\t\t\tif (!doThisBone && !doMirrorBone)\n\t\t\t\tcontinue;\n\n\t\t\t// Calculate average\n\t\t\tfloat avg = 0.0f;\n\t\t\tint avgcount = 0;\n\t\t\tif (doThisBone) {\n\t\t\t\tfloat sum = 0.0f;\n\t\t\t\tfor (int p : p2s)\n\t\t\t\t\tsum += GetUWeight(tuss.addVerts[p], bd2.boneName);\n\t\t\t\tavg += sum / p2s.size();\n\t\t\t\t++avgcount;\n\t\t\t}\n\t\t\tif (doMirrorBone) {\n\t\t\t\tfloat sum = 0.0f;\n\t\t\t\tfor (int p : p1s)\n\t\t\t\t\tsum += GetUWeight(tuss.addVerts[p], bd1.boneName);\n\t\t\t\tavg += sum / p1s.size();\n\t\t\t\t++avgcount;\n\t\t\t}\n\t\t\tavg /= avgcount;\n\n\t\t\t// Store average\n\t\t\tif (doThisBone) {\n\t\t\t\tif (!weightAdjustPoint[p1s[0]]) {\n\t\t\t\t\tweightAdjustPoint[p1s[0]] = true;\n\t\t\t\t\tnzer.GrabOneVertexStartingWeights(p1s[0]);\n\t\t\t\t}\n\t\t\t\tSetUWeight(tuss, p1s[0], bd1.boneName, avg);\n\t\t\t}\n\t\t\tif (doMirrorBone) {\n\t\t\t\tif (!weightAdjustPoint[p2s[0]]) {\n\t\t\t\t\tweightAdjustPoint[p2s[0]] = true;\n\t\t\t\t\tnzer.GrabOneVertexStartingWeights(p2s[0]);\n\t\t\t\t}\n\t\t\t\tSetUWeight(tuss, p2s[0], bd2.boneName, avg);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize weights and transfer them from tuss.boneWeights to\n\t// tuss.addVerts.\n\tfor (int p = 0; p < nVerts; ++p) {\n\t\tif (!weightAdjustPoint[p])\n\t\t\tcontinue;\n\n\t\tMesh::GetWeldSet(weldVerts, p, p1s);\n\t\tfor (int p1 : p1s)\n\t\t\tvChanged[p1] = true;\n\n\t\t// Normalize weights\n\t\tnzer.AdjustWeights(p);\n\n\t\t// Transfer results\n\t\tfor (const auto& bw : tuss.boneWeights) {\n\t\t\tauto wit = bw.weights.find(p);\n\t\t\tif (wit == bw.weights.end())\n\t\t\t\tcontinue;\n\t\t\tfloat w = wit->second.endVal;\n\t\t\tfor (int p1 : p1s)\n\t\t\t\tSetUWeight(tuss.addVerts[p1], bw.boneName, w);\n\t\t}\n\t}\n\n\t// Transfer the data for just the changed vertices from tuss to uss.\n\tfor (int vi = 0; vi < nVerts; ++vi) {\n\t\tif (!vChanged[vi])\n\t\t\tcontinue;\n\t\tuss.delVerts.push_back(std::move(tuss.delVerts[vi]));\n\t\tuss.addVerts.push_back(std::move(tuss.addVerts[vi]));\n\t}\n\n\t// Collect triangle data.  Every triangle that uses any changed vertex\n\t// must be deleted and restored.\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\tint nTris = static_cast<int>(tris.size());\n\tstd::vector<uint32_t> triInds;\n\tfor (int ti = 0; ti < nTris; ++ti)\n\t\tif (vChanged[tris[ti].p1] || vChanged[tris[ti].p2] || vChanged[tris[ti].p3])\n\t\t\ttriInds.push_back(ti);\n\tCollectTriangleData(shape, uss, triInds);\n\tuss.addTris = uss.delTris;\n}\n\nstd::vector<bool> OutfitProject::CalculateAsymmetricTriangleVertexMask(NiShape* shape, const Mesh::WeldVertsType& weldVerts) {\n\t// Ideally, this function would return a triangle mask.  But triangle\n\t// masks aren't implemented in Outfit Studio yet.  So we have to\n\t// convert the information to a vertex mask.\n\n\t// Gather shape's vertices and triangles\n\tstd::vector<Vector3> verts;\n\tworkNif.GetVertsForShape(shape, verts);\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\n\t// Find vertex symmetries\n\tSymmetricVertices symverts;\n\tMatchSymmetricVertices(shape, weldVerts, symverts);\n\n\t// Create welded-vertex set for every vertex\n\tstd::vector<std::vector<int>> weldSets(verts.size());\n\tfor (int i = 0; i < static_cast<int>(verts.size()); ++i)\n\t\tMesh::GetWeldSet(weldVerts, i, weldSets[i]);\n\n\t// Create mirror vertex map\n\tstd::vector<int> mVerts(verts.size(), -1);\n\tfor (const auto& mp : symverts.matches) {\n\t\tfor (int vi : weldSets[mp.first])\n\t\t\tmVerts[vi] = mp.second;\n\t\tfor (int vi : weldSets[mp.second])\n\t\t\tmVerts[vi] = mp.first;\n\t}\n\n\t// Create set of Triangles so we can quickly check if a triangle exists\n\tstd::unordered_set<Triangle> triSet;\n\tfor (Triangle t : tris) {\n\t\tt.rot();\n\t\ttriSet.insert(t);\n\t}\n\n\t// Main loop through triangles\n\tstd::vector<bool> mask(verts.size(), false);\n\tfor (const Triangle& t : tris) {\n\t\t// m1, m2, m3: mirror of each of the triangle's points.  Note that\n\t\t// p2 and p3 are swapped, as we flip orientation when mirroring.\n\t\tint m1 = mVerts[t.p1];\n\t\tint m2 = mVerts[t.p3];\n\t\tint m3 = mVerts[t.p2];\n\t\tbool bad = false;\n\t\t// If any of m1, m2, or m3 is negative, that means the point does\n\t\t// not have a mirror match.\n\t\tif (m1 < 0 || m2 < 0 || m3 < 0)\n\t\t\tbad = true;\n\t\tif (!bad) {\n\t\t\t// Search through the weld sets for our three mirror points,\n\t\t\t// looking for a mirror triangle.\n\t\t\tbool gotmatch = false;\n\t\t\tfor (int wm1 : weldSets[m1])\n\t\t\tfor (int wm2 : weldSets[m2])\n\t\t\tfor (int wm3 : weldSets[m3]) {\n\t\t\t\tTriangle mt(wm1, wm2, wm3);\n\t\t\t\tmt.rot();\n\t\t\t\tif (triSet.count(mt))\n\t\t\t\t\tgotmatch = true;\n\t\t\t}\n\t\t\tbad = !gotmatch;\n\t\t}\n\t\tif (bad) {\n\t\t\t// We've found a triangle that does not have a mirror.\n\t\t\tfor (int i : weldSets[t.p1])\n\t\t\t\tmask[i] = true;\n\t\t\tfor (int i : weldSets[t.p2])\n\t\t\t\tmask[i] = true;\n\t\t\tfor (int i : weldSets[t.p3])\n\t\t\t\tmask[i] = true;\n\t\t}\n\t}\n\treturn mask;\n}\n\nint OutfitProject::ImportNIF(const std::string& fileName, bool clear, const std::string& inOutfitName, std::map<std::string, std::string>* renamedShapes) {\n\tif (clear)\n\t\tClearOutfit();\n\n\tif (fileName.empty()) {\n\t\twxLogMessage(\"No outfit selected.\");\n\t\treturn 0;\n\t}\n\n\tauto targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\n\tif (!inOutfitName.empty())\n\t\toutfitName = inOutfitName;\n\telse if (outfitName.empty())\n\t\toutfitName = \"New Outfit\";\n\n\twxFileName file(fileName);\n\tif (mBaseFile.empty())\n\t\tmBaseFile = file.GetFullName();\n\n\tif (clear) {\n\t\tmGameFile = file.GetName();\n\t\tmGamePath = file.GetPath();\n\n\t\tint pos = mGamePath.Lower().Find(\"meshes\");\n\t\tif (pos != wxNOT_FOUND)\n\t\t\tmGamePath = mGamePath.Mid(pos);\n\t\telse\n\t\t\tmGamePath.Clear();\n\n\t\tif (targetGame == SKYRIM || targetGame == SKYRIMSE || targetGame == SKYRIMVR) {\n\t\t\twxString fileRest;\n\t\t\tif (mGameFile.EndsWith(\"_0\", &fileRest) || mGameFile.EndsWith(\"_1\", &fileRest))\n\t\t\t\tmGameFile = fileRest;\n\t\t}\n\t}\n\n\tstd::fstream fileStream;\n\tPlatformUtil::OpenFileStream(fileStream, fileName, std::ios::in | std::ios::binary);\n\n\tNifFile nif;\n\tint error = nif.Load(fileStream);\n\tif (error) {\n\t\tif (error == 2) {\n\t\t\twxString errorText = wxString::Format(_(\"NIF version not supported!\\n\\nFile: %s\\n%s\"), fileName, nif.GetHeader().GetVersion().GetVersionInfo());\n\n\t\t\twxLogError(errorText);\n\t\t\twxMessageBox(errorText, _(\"NIF Error\"), wxICON_ERROR, owner);\n\t\t\treturn 4;\n\t\t}\n\n\t\twxLogError(\"Could not load NIF file '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Could not load NIF file '%s'!\"), fileName), _(\"NIF Error\"), wxICON_ERROR, owner);\n\t\treturn 1;\n\t}\n\n\tValidateNIF(nif, fileName);\n\n\tnif.SetNodeName(0, \"Scene Root\");\n\tnif.RenameDuplicateShapes();\n\n\tif (baseShape) {\n\t\tstd::string baseShapeName = baseShape->name.get();\n\t\tauto bshape = nif.FindBlockByName<NiShape>(baseShapeName);\n\t\tif (nif.RenameShape(bshape, baseShapeName + \"_outfit\")) {\n\t\t\tif (renamedShapes)\n\t\t\t\t(*renamedShapes)[baseShapeName] = baseShapeName + \"_outfit\";\n\t\t}\n\t}\n\n\tstd::vector<std::string> shapes = workNif.GetShapeNames();\n\tauto nifShapes = nif.GetShapes();\n\n\tfor (auto& s : nifShapes) {\n\t\tstd::vector<std::string> uniqueShapes = nif.GetShapeNames();\n\t\tuniqueShapes.insert(uniqueShapes.end(), shapes.begin(), shapes.end());\n\n\t\tstd::string shapeName = s->name.get();\n\t\tstd::string newName = shapeName;\n\t\tint uniqueCount = 0;\n\t\tfor (;;) {\n\t\t\tauto foundShape = find(uniqueShapes.begin(), uniqueShapes.end(), newName);\n\t\t\tif (foundShape != uniqueShapes.end()) {\n\t\t\t\tuniqueShapes.erase(foundShape);\n\t\t\t\tuniqueCount++;\n\t\t\t\tif (uniqueCount > 1)\n\t\t\t\t\tnewName = shapeName + wxString::Format(\"_%d\", uniqueCount).ToStdString();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (uniqueCount > 1) {\n\t\t\t\t\tif (nif.RenameShape(s, newName)) {\n\t\t\t\t\t\tif (renamedShapes)\n\t\t\t\t\t\t\t(*renamedShapes)[shapeName] = newName;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add cloth data block of NIF to the list\n\tstd::vector<BSClothExtraData*> clothDataBlocks = nif.GetChildren<BSClothExtraData>(nullptr, true);\n\tfor (auto& cloth : clothDataBlocks)\n\t\tclothData[fileName] = cloth->Clone();\n\n\tnif.GetHeader().DeleteBlockByType(\"BSClothExtraData\");\n\n\tif (workNif.IsValid()) {\n\t\tfor (auto& s : nif.GetShapes()) {\n\t\t\tstd::string shapeName = s->name.get();\n\t\t\tauto clonedShape = workNif.CloneShape(s, shapeName, &nif);\n\t\t\tworkAnim.LoadFromNif(&workNif, clonedShape);\n\t\t}\n\t}\n\telse {\n\t\tworkNif.CopyFrom(nif);\n\t\tworkAnim.LoadFromNif(&workNif);\n\t}\n\n\treturn 0;\n}\n\nint OutfitProject::ExportNIF(const std::string& fileName, const std::vector<Mesh*>& modMeshes, bool withRef, std::optional<bool> useInternalGeom) {\n\tworkAnim.CleanupBones();\n\towner->UpdateAnimationGUI();\n\n\tNifFile clone(workNif);\n\tChooseClothData(clone);\n\n\tstd::vector<Vector3> liveVerts;\n\tstd::vector<Vector3> liveNorms;\n\tfor (auto& m : modMeshes) {\n\t\tauto shape = clone.FindBlockByName<NiShape>(m->shapeName);\n\t\tif (shape) {\n\t\t\tliveVerts.clear();\n\t\t\tliveNorms.clear();\n\n\t\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\t\tliveVerts.push_back(Mesh::TransformPosMeshToNif(m->verts[i]));\n\t\t\t\tliveNorms.push_back(Mesh::TransformDirMeshToNif(m->norms[i]));\n\t\t\t}\n\n\t\t\tclone.SetVertsForShape(shape, liveVerts);\n\n\t\t\tif (clone.GetHeader().GetVersion().IsSK() || clone.GetHeader().GetVersion().IsSSE()) {\n\t\t\t\tNiShader* shader = clone.GetShader(shape);\n\t\t\t\tif (shader && shader->IsModelSpace())\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tclone.SetNormalsForShape(shape, liveNorms);\n\t\t\tclone.CalcTangentsForShape(shape);\n\t\t}\n\t}\n\n\tif (!withRef && baseShape) {\n\t\tstd::string baseShapeName = baseShape->name.get();\n\t\tauto bshape = clone.FindBlockByName<NiShape>(baseShapeName);\n\t\tclone.DeleteShape(bshape);\n\t\tworkAnim.WriteToNif(&clone, baseShapeName);\n\t}\n\telse\n\t\tworkAnim.WriteToNif(&clone);\n\n\tfor (auto& s : clone.GetShapes())\n\t\tclone.UpdateSkinPartitions(s);\n\n\tclone.SetShapeOrder(owner->GetShapeList());\n\tclone.GetHeader().SetExportInfo(\"Exported using Outfit Studio.\");\n\n\tConfigureInternalGeometry(clone, fileName, useInternalGeom);\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::out | std::ios::binary);\n\n\tint result = clone.Save(file);\n\tif (result == 0)\n\t\tSaveExternalMeshes(clone, fileName);\n\n\treturn result;\n}\n\n\nvoid OutfitProject::ChooseClothData(NifFile& nif) {\n\tif (!clothData.empty()) {\n\t\twxArrayString clothFileNames;\n\t\tfor (auto& cloth : clothData)\n\t\t\tclothFileNames.Add(wxString::FromUTF8(cloth.first));\n\n\t\twxMultiChoiceDialog clothDataChoice(owner,\n\t\t\t\t\t\t\t\t\t\t\t_(\"There was cloth physics data loaded at some point (BSClothExtraData). Please choose all the origins to use in the output.\"),\n\t\t\t\t\t\t\t\t\t\t\t_(\"Choose cloth data\"),\n\t\t\t\t\t\t\t\t\t\t\tclothFileNames);\n\t\tif (clothDataChoice.ShowModal() == wxID_CANCEL)\n\t\t\treturn;\n\n\t\twxArrayInt sel = clothDataChoice.GetSelections();\n\t\tfor (size_t i = 0; i < sel.Count(); i++) {\n\t\t\tstd::string selString{clothFileNames[sel[i]].ToUTF8()};\n\t\t\tif (!selString.empty()) {\n\t\t\t\tauto clothBlock = clothData[selString]->Clone();\n\t\t\t\tuint32_t id = nif.GetHeader().AddBlock(std::move(clothBlock));\n\t\t\t\tif (id != 0xFFFFFFFF) {\n\t\t\t\t\tauto root = nif.GetRootNode();\n\t\t\t\t\tif (root)\n\t\t\t\t\t\troot->extraDataRefs.AddBlockRef(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nint OutfitProject::ExportShapeNIF(const std::string& fileName, const std::vector<std::string>& exportShapes, std::optional<bool> useInternalGeom) {\n\tif (exportShapes.empty())\n\t\treturn 1;\n\n\tif (!workNif.IsValid())\n\t\treturn 2;\n\n\tworkAnim.CleanupBones();\n\n\tNifFile clone(workNif);\n\tChooseClothData(clone);\n\n\tclone.SetShapeOrder(owner->GetShapeList());\n\n\tfor (auto& s : clone.GetShapes())\n\t\tif (find(exportShapes.begin(), exportShapes.end(), s->name.get()) == exportShapes.end())\n\t\t\tclone.DeleteShape(s);\n\n\tworkAnim.WriteToNif(&clone);\n\n\tfor (auto& s : clone.GetShapes())\n\t\tclone.UpdateSkinPartitions(s);\n\n\tclone.GetHeader().SetExportInfo(\"Exported using Outfit Studio.\");\n\n\tConfigureInternalGeometry(clone, fileName, useInternalGeom);\n\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::out | std::ios::binary);\n\n\tint result = clone.Save(file);\n\tif (result == 0)\n\t\tSaveExternalMeshes(clone, fileName);\n\n\treturn result;\n}\n\nvoid OutfitProject::ForceInternalGeometry(NifFile& nif) {\n\tif (!nif.GetHeader().GetVersion().IsSF())\n\t\treturn;\n\n\tfor (auto& s : nif.GetShapes()) {\n\t\tauto bsgeo = dynamic_cast<BSGeometry*>(s);\n\t\tif (bsgeo)\n\t\t\tbsgeo->SetInternalGeomData(true);\n\t}\n}\n\nvoid OutfitProject::ConfigureInternalGeometry(NifFile& nif, const std::string& nifFileName, std::optional<bool> useInternalGeom) {\n\tif (!nif.GetHeader().GetVersion().IsSF())\n\t\treturn;\n\n\tbool hasBSGeo = false;\n\tfor (auto& s : nif.GetShapes()) {\n\t\tif (s->HasType<BSGeometry>()) {\n\t\t\thasBSGeo = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!hasBSGeo)\n\t\treturn;\n\n\t// Derive geometry folder name from the NIF filename (without extension)\n\twxFileName nifPath(wxString::FromUTF8(nifFileName));\n\tstd::string folderName = nifPath.GetName().ToUTF8().data();\n\n\tfor (auto& s : nif.GetShapes()) {\n\t\tauto bsgeo = dynamic_cast<BSGeometry*>(s);\n\t\tif (!bsgeo)\n\t\t\tcontinue;\n\n\t\t// Use provided choice, or keep the shape's current state\n\t\tbool useInternal = useInternalGeom.value_or(bsgeo->HasInternalGeomData());\n\n\t\tbsgeo->SetInternalGeomData(useInternal);\n\n\t\tif (!useInternal) {\n\t\t\t// Ensure external mesh paths are set\n\t\t\tfor (uint8_t i = 0; i < bsgeo->MeshCount(); i++) {\n\t\t\t\tauto mesh = bsgeo->SelectMesh(i);\n\t\t\t\tif (mesh && mesh->meshName.get().empty()) {\n\t\t\t\t\t// Generate mesh path: NifName\\ShapeName_Index\n\t\t\t\t\tstd::string shapeName = s->name.get();\n\t\t\t\t\tauto sanitize = [](std::string& str) {\n\t\t\t\t\t\tfor (char& c : str) {\n\t\t\t\t\t\t\tif (c == ' ' || c == '/' || c == ':' || c == '*' || c == '?' || c == '\"' || c == '<' || c == '>' || c == '|')\n\t\t\t\t\t\t\t\tc = '_';\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t\tstd::string folder = folderName;\n\t\t\t\t\tsanitize(folder);\n\t\t\t\t\tsanitize(shapeName);\n\t\t\t\t\tmesh->meshName.get() = folder + \"\\\\\" + shapeName + \"_\" + std::to_string(i);\n\t\t\t\t}\n\t\t\t\tbsgeo->ReleaseMesh();\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool OutfitProject::SaveExternalMeshes(NifFile& nif, const std::string& nifFileName) {\n\tif (!nif.GetHeader().GetVersion().IsSF())\n\t\treturn true;\n\n\twxFileName nifPath(wxString::FromUTF8(nifFileName));\n\twxString nifDir = nifPath.GetPath();\n\n\tfor (auto& s : nif.GetShapes()) {\n\t\tauto meshPaths = nif.GetExternalGeometryPathRefs(s);\n\t\tuint8_t meshIndex = 0;\n\n\t\tfor (auto& meshPathRef : meshPaths) {\n\t\t\tstd::string meshPath = meshPathRef.get();\n\t\t\tif (meshPath.empty()) {\n\t\t\t\tmeshIndex++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Build full output path: geometries/{meshPath}.mesh in the Data root (sibling to Meshes/)\n\t\t\t// Walk up to the directory that contains \"meshes\" (case-insensitive)\n\t\t\twxFileName walker(nifDir + wxFileName::GetPathSeparator());\n\t\t\tbool foundMeshes = false;\n\t\t\twhile (walker.GetDirCount() > 0) {\n\t\t\t\twxString lastDir = walker.GetDirs().Last();\n\t\t\t\tif (lastDir.CmpNoCase(\"meshes\") == 0) {\n\t\t\t\t\twalker.RemoveLastDir();\n\t\t\t\t\tfoundMeshes = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\twalker.RemoveLastDir();\n\t\t\t}\n\t\t\t// If not inside a game data layout, place geometries/ next to the NIF\n\t\t\twxString rootDir = foundMeshes ? walker.GetPath() : nifDir;\n\t\t\twxString normalizedMeshPath = wxString::FromUTF8(meshPath);\n\t\t\tnormalizedMeshPath.Replace(\"\\\\\", wxString(wxFileName::GetPathSeparator()));\n\t\t\tnormalizedMeshPath.Replace(\"/\", wxString(wxFileName::GetPathSeparator()));\n\t\t\tif (normalizedMeshPath.Length() < 5 || normalizedMeshPath.Right(5).CmpNoCase(\".mesh\") != 0)\n\t\t\t\tnormalizedMeshPath += \".mesh\";\n\t\t\twxFileName meshFullPath(rootDir + wxFileName::GetPathSeparator() + \"geometries\"\n\t\t\t\t+ wxFileName::GetPathSeparator() + normalizedMeshPath);\n\n\t\t\t// Ensure the directory exists\n\t\t\twxFileName::Mkdir(meshFullPath.GetPath(), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\t\t\tstd::string meshFileStr = meshFullPath.GetFullPath().ToUTF8().data();\n\n\t\t\tstd::fstream meshFile;\n\t\t\tPlatformUtil::OpenFileStream(meshFile, meshFileStr, std::ios::out | std::ios::binary);\n\t\t\tif (meshFile.fail()) {\n\t\t\t\twxLogError(\"Failed to save external mesh file '%s'.\", meshFileStr.c_str());\n\t\t\t\tmeshIndex++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnif.SaveExternalShapeData(s, meshFile, meshIndex);\n\t\t\tmeshIndex++;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nint OutfitProject::ImportOBJ(const std::string& fileName, const std::string& shapeName, NiShape* mergeShape) {\n\t// Set reference NIF in case nothing was loaded yet\n\tif (!workAnim.GetRefNif())\n\t\tworkAnim.SetRefNif(&workNif);\n\n\tObjFile obj;\n\tobj.SetScale(Vector3(10.0f, 10.0f, 10.0f));\n\n\tif (!shapeName.empty())\n\t\toutfitName = shapeName;\n\telse if (outfitName.empty())\n\t\toutfitName = \"New Outfit\";\n\n\tsize_t vertexLimit = workNif.GetVertexLimit();\n\tsize_t triLimit = workNif.GetTriangleLimit();\n\n\twxString warningLabel;\n\tif (!baseShape)\n\t\twarningLabel = _(\"No reference has been loaded.  For correct bone transforms, you might need to load a reference before importing OBJ files.\");\n\n\tObjImportDialog import(owner, fileName, vertexLimit, triLimit, warningLabel);\n\tif (import.ShowModal() != wxID_OK)\n\t\treturn 1;\n\n\tif (obj.LoadForNif(fileName, import.GetOptions())) {\n\t\twxLogError(\"Could not load OBJ file '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Could not load OBJ file '%s'!\"), fileName), _(\"OBJ Error\"), wxICON_ERROR, owner);\n\t\treturn 1;\n\t}\n\n\tbool copyBaseSkinTrans = false;\n\tif (baseShape && !workAnim.GetTransformGlobalToShape(baseShape).IsNearlyEqualTo(MatTransform())) {\n\t\tint res = wxMessageBox(_(\"The reference shape has a skin coordinate system that is different from the global coordinate system.  Would you like to copy the reference's \"\n\t\t\t\t\t\t\t\t \"global-to-skin transform to the imported shapes?\"),\n\t\t\t\t\t\t\t   _(\"Copy skin coordinates\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL);\n\t\tif (res == wxCANCEL)\n\t\t\treturn 1;\n\t\tif (res == wxYES)\n\t\t\tcopyBaseSkinTrans = true;\n\t}\n\n\tstd::vector<std::string> groupNames = obj.GetGroupList();\n\tfor (const auto& group : groupNames) {\n\t\tstd::vector<Vector3> v;\n\t\tstd::vector<Triangle> t;\n\t\tstd::vector<Vector2> uv;\n\t\tstd::vector<Vector3> n;\n\t\tif (!obj.CopyDataForGroup(group, &v, &t, &uv, &n)) {\n\t\t\twxLogError(\"Could not copy data from OBJ file '%s'!\", fileName);\n\t\t\twxMessageBox(wxString::Format(_(\"Could not copy data from OBJ file '%s'!\"), fileName), _(\"OBJ Error\"), wxICON_ERROR, owner);\n\t\t\treturn 3;\n\t\t}\n\n\t\tsize_t vertCount = v.size();\n\t\tsize_t triCount = t.size();\n\n\t\t// Skip zero size groups.\n\t\tif (vertCount == 0)\n\t\t\tcontinue;\n\n\t\tstd::string useShapeName = group;\n\n\t\tif (mergeShape) {\n\t\t\tstd::vector<Vector3> shapeVerts;\n\t\t\tworkNif.GetVertsForShape(mergeShape, shapeVerts);\n\t\t\tif (shapeVerts.size() == vertCount) {\n\t\t\t\tint ret = wxMessageBox(_(\"The vertex count of the selected .obj file matches the currently selected outfit shape.  Do you wish to update the current shape?  \"\n\t\t\t\t\t\t\t\t\t\t \"(click No to create a new shape)\"),\n\t\t\t\t\t\t\t\t\t   _(\"Merge or New\"),\n\t\t\t\t\t\t\t\t\t   wxYES_NO | wxICON_QUESTION,\n\t\t\t\t\t\t\t\t\t   owner);\n\t\t\t\tif (ret == wxYES) {\n\t\t\t\t\tret = wxMessageBox(_(\"Update Vertex Positions?\"), _(\"Vertex Position Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\tif (ret == wxYES)\n\t\t\t\t\t\tworkNif.SetVertsForShape(mergeShape, v);\n\n\t\t\t\t\tif (uv.size() == vertCount) {\n\t\t\t\t\t\tret = wxMessageBox(_(\"Update Texture Coordinates?\"), _(\"UV Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\t\tif (ret == wxYES)\n\t\t\t\t\t\t\tworkNif.SetUvsForShape(mergeShape, uv);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (n.size() == vertCount) {\n\t\t\t\t\t\tret = wxMessageBox(_(\"Update Normals?\"), _(\"Normals Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\t\tif (ret == wxYES) {\n\t\t\t\t\t\t\tworkNif.SetNormalsForShape(mergeShape, n);\n\t\t\t\t\t\t\tworkNif.CalcTangentsForShape(mergeShape);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn 101;\n\t\t\t\t}\n\t\t\t}\n\t\t\tuseShapeName = wxGetTextFromUser(_(\"Please specify a name for the new shape\"), _(\"New Shape Name\"), useShapeName, owner).ToUTF8();\n\t\t\tif (useShapeName.empty())\n\t\t\t\treturn 100;\n\t\t}\n\n\t\tauto newShape = CreateNifShapeFromData(useShapeName, &v, &t, &uv, &n);\n\t\tif (newShape) {\n\t\t\tuint16_t vertCountNew = newShape->GetNumVertices();\n\t\t\tuint32_t triCountNew = newShape->GetNumTriangles();\n\n\t\t\tif (vertCountNew < vertCount || triCountNew < triCount) {\n\t\t\t\twxMessageBox(wxString::Format(_(\"The vertex or triangle limit for '%s' was exceeded.\\nRemaining data was dropped.\\n\\nVertices (current/max): %zu/%zu\\nTriangles \"\n\t\t\t\t\t\t\t\t\t\t\t\t\"(current/max): %zu/%zu\"),\n\t\t\t\t\t\t\t\t\t\t\t  useShapeName,\n\t\t\t\t\t\t\t\t\t\t\t  vertCount,\n\t\t\t\t\t\t\t\t\t\t\t  vertexLimit,\n\t\t\t\t\t\t\t\t\t\t\t  triCount,\n\t\t\t\t\t\t\t\t\t\t\t  triLimit),\n\t\t\t\t\t\t\t _(\"OBJ Error\"),\n\t\t\t\t\t\t\t wxICON_WARNING,\n\t\t\t\t\t\t\t owner);\n\t\t\t}\n\n\t\t\tif (copyBaseSkinTrans)\n\t\t\t\tworkAnim.SetTransformGlobalToShape(newShape, workAnim.GetTransformGlobalToShape(baseShape));\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nint OutfitProject::ExportOBJ(const std::string& fileName, const std::vector<NiShape*>& shapes, bool transToGlobal, const Vector3& scale, const Vector3& offset) {\n\tObjFile obj;\n\tobj.SetScale(scale);\n\tobj.SetOffset(offset);\n\n\tfor (auto& shape : shapes) {\n\t\tif (!shape)\n\t\t\treturn 1;\n\n\t\tstd::vector<Triangle> tris;\n\t\tif (!shape->GetTriangles(tris))\n\t\t\treturn 2;\n\n\t\tconst std::vector<Vector3>* verts = workNif.GetVertsForShape(shape);\n\t\tif (!verts)\n\t\t\treturn 3;\n\n\t\tconst std::vector<Vector2>* uvs = workNif.GetUvsForShape(shape);\n\t\tconst std::vector<Vector3>* norms = workNif.GetNormalsForShape(shape);\n\n\t\tstd::vector<Vector3> gVerts, gNorms;\n\t\tif (transToGlobal) {\n\t\t\tMatTransform toGlobal = workAnim.GetTransformShapeToGlobal(shape);\n\t\t\tgVerts.resize(verts->size());\n\n\t\t\tfor (size_t i = 0; i < gVerts.size(); ++i)\n\t\t\t\tgVerts[i] = toGlobal.ApplyTransform((*verts)[i]);\n\n\t\t\tverts = &gVerts;\n\t\t\tif (norms) {\n\t\t\t\tgNorms.resize(norms->size());\n\n\t\t\t\tfor (size_t i = 0; i < gNorms.size(); ++i)\n\t\t\t\t\tgNorms[i] = toGlobal.ApplyTransformToDir((*norms)[i]);\n\n\t\t\t\tnorms = &gNorms;\n\t\t\t}\n\t\t}\n\n\t\tobj.AddGroup(shape->name.get(), *verts, tris, uvs ? *uvs : std::vector<Vector2>(), norms ? *norms : std::vector<Vector3>());\n\t}\n\n\tif (obj.Save(fileName))\n\t\treturn 4;\n\n\treturn 0;\n}\n\n#ifdef USE_FBXSDK\nint OutfitProject::ImportFBX(const std::string& fileName, const std::string& shapeName, NiShape* mergeShape) {\n\t// Set reference NIF in case nothing was loaded yet\n\tif (!workAnim.GetRefNif())\n\t\tworkAnim.SetRefNif(&workNif);\n\n\tFBXWrangler fbxw;\n\tstd::string nonRefBones;\n\tsize_t vertexLimit = workNif.GetVertexLimit();\n\tsize_t triLimit = workNif.GetTriangleLimit();\n\n\twxString warningLabel;\n\tif (!baseShape)\n\t\twarningLabel = _(\"No reference has been loaded.  For correct bone transforms, you might need to load a reference before importing FBX files.\");\n\n\tFBXImportDialog import(owner, fileName, vertexLimit, triLimit, warningLabel);\n\tif (import.ShowModal() != wxID_OK)\n\t\treturn 1;\n\n\tbool result = fbxw.ImportScene(fileName, import.GetOptions());\n\tif (!result)\n\t\treturn 2;\n\n\tbool copyBaseSkinTrans = false;\n\tif (baseShape && !workAnim.GetTransformGlobalToShape(baseShape).IsNearlyEqualTo(MatTransform())) {\n\t\tint res = wxMessageBox(_(\"The reference shape has a skin coordinate system that is different from the global coordinate system.  Would you like to copy the reference's \"\n\t\t\t\t\t\t\t\t \"global-to-skin transform to the imported shapes?\"),\n\t\t\t\t\t\t\t   _(\"Copy skin coordinates\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL);\n\t\tif (res == wxCANCEL)\n\t\t\treturn 1;\n\t\tif (res == wxYES)\n\t\t\tcopyBaseSkinTrans = true;\n\t}\n\n\tif (!shapeName.empty())\n\t\toutfitName = shapeName;\n\telse if (outfitName.empty())\n\t\toutfitName = \"New Outfit\";\n\n\tstd::vector<std::string> shapes;\n\tfbxw.GetShapeNames(shapes);\n\tfor (auto& s : shapes) {\n\t\tFBXShape* fbxShape = fbxw.GetShape(s);\n\t\tstd::string useShapeName = s;\n\n\t\tsize_t vertCount = fbxShape->verts.size();\n\t\tsize_t triCount = fbxShape->tris.size();\n\n\t\tif (mergeShape) {\n\t\t\tif (mergeShape->GetNumVertices() == vertCount) {\n\t\t\t\tint ret = wxMessageBox(_(\"The vertex count of the selected .fbx file matches the currently selected outfit shape.  Do you wish to update the current shape?  \"\n\t\t\t\t\t\t\t\t\t\t \"(click No to create a new shape)\"),\n\t\t\t\t\t\t\t\t\t   _(\"Merge or New\"),\n\t\t\t\t\t\t\t\t\t   wxYES_NO | wxICON_QUESTION,\n\t\t\t\t\t\t\t\t\t   owner);\n\t\t\t\tif (ret == wxYES) {\n\t\t\t\t\tret = wxMessageBox(_(\"Update Vertex Positions?\"), _(\"Vertex Position Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\tif (ret == wxYES)\n\t\t\t\t\t\tworkNif.SetVertsForShape(mergeShape, fbxShape->verts);\n\n\t\t\t\t\tif (fbxShape->uvs.size() == vertCount) {\n\t\t\t\t\t\tret = wxMessageBox(_(\"Update Texture Coordinates?\"), _(\"UV Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\t\tif (ret == wxYES)\n\t\t\t\t\t\t\tworkNif.SetUvsForShape(mergeShape, fbxShape->uvs);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (fbxShape->normals.size() == vertCount) {\n\t\t\t\t\t\tret = wxMessageBox(_(\"Update Normals?\"), _(\"Normals Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\t\tif (ret == wxYES) {\n\t\t\t\t\t\t\tworkNif.SetNormalsForShape(mergeShape, fbxShape->normals);\n\t\t\t\t\t\t\tworkNif.CalcTangentsForShape(mergeShape);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tret = wxMessageBox(_(\"Update Animation Weighting?\"), _(\"Animation Weight Update\"), wxYES_NO | wxICON_QUESTION, owner);\n\t\t\t\t\tif (ret == wxYES)\n\t\t\t\t\t\tfor (auto& bn : fbxShape->boneNames)\n\t\t\t\t\t\t\tworkAnim.SetWeights(mergeShape->name.get(), bn, fbxShape->boneSkin[bn].GetWeights());\n\n\t\t\t\t\treturn 101;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tuseShapeName = wxGetTextFromUser(_(\"Please specify a name for the new shape\"), _(\"New Shape Name\"), useShapeName, owner).ToUTF8();\n\t\t\tif (useShapeName.empty())\n\t\t\t\treturn 100;\n\t\t}\n\n\t\tauto newShape = CreateNifShapeFromData(useShapeName, &fbxShape->verts, &fbxShape->tris, &fbxShape->uvs, &fbxShape->normals);\n\t\tif (!newShape)\n\t\t\tcontinue;\n\n\t\tCreateSkinning(newShape);\n\n\t\tuint16_t vertCountNew = newShape->GetNumVertices();\n\t\tuint32_t triCountNew = newShape->GetNumTriangles();\n\n\t\tif (vertCountNew < vertCount || triCountNew < triCount) {\n\t\t\twxMessageBox(wxString::Format(_(\"The vertex or triangle limit for '%s' was exceeded.\\nRemaining data was dropped.\\n\\nVertices (current/max): %zu/%zu\\nTriangles \"\n\t\t\t\t\t\t\t\t\t\t\t\"(current/max): %zu/%zu\"),\n\t\t\t\t\t\t\t\t\t\t  useShapeName,\n\t\t\t\t\t\t\t\t\t\t  vertCount,\n\t\t\t\t\t\t\t\t\t\t  vertexLimit,\n\t\t\t\t\t\t\t\t\t\t  triCount,\n\t\t\t\t\t\t\t\t\t\t  triLimit),\n\t\t\t\t\t\t _(\"OBJ Error\"),\n\t\t\t\t\t\t wxICON_WARNING,\n\t\t\t\t\t\t owner);\n\t\t}\n\n\t\tif (copyBaseSkinTrans)\n\t\t\tworkAnim.SetTransformGlobalToShape(newShape, workAnim.GetTransformGlobalToShape(baseShape));\n\n\t\tfor (auto& bn : fbxShape->boneNames) {\n\t\t\tif (!AnimSkeleton::getInstance().GetBonePtr(bn)) {\n\t\t\t\t// Not found in reference skeleton, use default values\n\t\t\t\tAnimSkeleton::getInstance().AddCustomBone(bn);\n\t\t\t\t//AnimBone& cstm = AnimSkeleton::getInstance().AddCustomBone(bn);\n\t\t\t\t// TODO: call SetParentBone (FbxNode::GetParent?)\n\t\t\t\t// TODO: call SetTransformBoneToParent (FbxNode::LclTranslation and LclRotation?)\n\t\t\t\tnonRefBones += bn + \"\\n\";\n\t\t\t}\n\n\t\t\tworkAnim.AddShapeBone(useShapeName, bn);\n\t\t\tworkAnim.SetWeights(useShapeName, bn, fbxShape->boneSkin[bn].GetWeights());\n\t\t}\n\n\t\tif (!nonRefBones.empty())\n\t\t\twxLogMessage(\"Bones in shape '%s' not found in reference skeleton:\\n%s\", useShapeName, nonRefBones);\n\t}\n\n\treturn 0;\n}\n\nint OutfitProject::ExportFBX(const std::string& fileName, const std::vector<NiShape*>& shapes, bool transToGlobal) {\n\tFBXWrangler fbxw;\n\tfbxw.AddSkeleton(&AnimSkeleton::getInstance().refSkeletonNif);\n\n\tfor (auto& s : shapes) {\n\t\tfbxw.AddNif(&workNif, &workAnim, transToGlobal, s);\n\t\tfbxw.AddSkinning(&workAnim, s);\n\t}\n\n\treturn fbxw.ExportScene(fileName);\n}\n#endif\n\nstd::unique_ptr<std::istream> OutfitProject::GetExternalGeometryStream(const std::string& dir, const std::string& path, const std::string& nifFilePath) const {\n\t// Normalize path: replace backslashes, extract relative geometries path, ensure prefix and suffix\n\tstd::string meshPath = std::regex_replace(path, std::regex(\"\\\\\\\\+\"), \"/\");\n\tmeshPath = std::regex_replace(meshPath, std::regex(\"^(.*?)/geometries/\", std::regex_constants::icase), \"\");\n\tmeshPath = std::regex_replace(meshPath, std::regex(\"^/+\"), \"\");\n\tmeshPath = std::regex_replace(meshPath, std::regex(\"^(?!^geometries/)\", std::regex_constants::icase), \"geometries/\");\n\n\tif (meshPath.size() < 5 || meshPath.compare(meshPath.size() - 5, 5, \".mesh\") != 0)\n\t\tmeshPath += \".mesh\";\n\n\t// Try opening a loose file at the given path\n\tauto tryOpenLoose = [](const std::string& fullPath) -> std::unique_ptr<std::istream> {\n\t\tif (!PlatformUtil::FileExists(fullPath))\n\t\t\treturn nullptr;\n\n\t\tauto fs = std::make_unique<std::fstream>();\n\t\tPlatformUtil::OpenFileStream(*fs, fullPath, std::ios::in | std::ios::binary);\n\t\tif (!fs->fail())\n\t\t\treturn fs;\n\n\t\treturn nullptr;\n\t};\n\n\t// 1) Loose file in GameDataPath\n\tif (auto stream = tryOpenLoose(dir + meshPath))\n\t\treturn stream;\n\n\t// 2) Beside the meshes folder (or NIF directory) of the loading NIF\n\tif (!nifFilePath.empty()) {\n\t\tstd::string nifDir = std::regex_replace(nifFilePath, std::regex(\"\\\\\\\\+\"), \"/\");\n\t\tstd::string nifDirLower = nifDir;\n\t\tstd::transform(nifDirLower.begin(), nifDirLower.end(), nifDirLower.begin(), ::tolower);\n\n\t\tauto meshesPos = nifDirLower.rfind(\"/meshes/\");\n\t\tif (meshesPos != std::string::npos) {\n\t\t\tif (auto stream = tryOpenLoose(nifDir.substr(0, meshesPos + 1) + meshPath))\n\t\t\t\treturn stream;\n\t\t}\n\t\telse {\n\t\t\tauto lastSlash = nifDir.rfind('/');\n\t\t\tif (lastSlash != std::string::npos) {\n\t\t\t\tif (auto stream = tryOpenLoose(nifDir.substr(0, lastSlash + 1) + meshPath))\n\t\t\t\t\treturn stream;\n\t\t\t}\n\t\t}\n\t}\n\n\t// 3) Search in archives\n\tfor (FSArchiveFile* archive : FSManager::archiveList()) {\n\t\tif (archive && archive->hasFile(meshPath)) {\n\t\t\twxMemoryBuffer outData;\n\t\t\tarchive->fileContents(meshPath, outData);\n\n\t\t\tif (!outData.IsEmpty()) {\n\t\t\t\tauto contentStream = std::make_unique<std::istringstream>(\n\t\t\t\t\tstd::string(static_cast<char*>(outData.GetData()), outData.GetDataLen()), std::istringstream::binary);\n\t\t\t\tif (!contentStream->fail())\n\t\t\t\t\treturn contentStream;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nullptr;\n}\n\nvoid OutfitProject::ValidateNIF(NifFile& nif, const std::string& nifFilePath) {\n\tauto targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tbool match = false;\n\n\tswitch (targetGame) {\n\t\tcase OB: match = nif.GetHeader().GetVersion().IsOB(); break;\n\t\tcase FO3:\n\t\tcase FONV: match = nif.GetHeader().GetVersion().IsFO3(); break;\n\t\tcase SKYRIM: match = nif.GetHeader().GetVersion().IsSK(); break;\n\t\tcase FO4:\n\t\tcase FO4VR: match = nif.GetHeader().GetVersion().IsFO4(); break;\n\t\tcase SKYRIMSE:\n\t\tcase SKYRIMVR: match = nif.GetHeader().GetVersion().IsSSE(); break;\n\t\tcase FO76: match = nif.GetHeader().GetVersion().IsFO76(); break;\n\t\tcase SF: match = nif.GetHeader().GetVersion().IsSF(); break;\n\t}\n\n\tif (!match) {\n\t\tif ((targetGame == SKYRIMSE || targetGame == SKYRIMVR) && nif.GetHeader().GetVersion().IsSK()) {\n\t\t\tif (!Config.Exists(\"OptimizeForSSE\")) {\n\t\t\t\tint res = wxMessageBox(_(\"Would you like Skyrim NIFs to be optimized for SSE during this session?\"), _(\"Target Game\"), wxYES_NO | wxICON_INFORMATION, owner);\n\t\t\t\tif (res == wxYES)\n\t\t\t\t\tConfig.SetDefaultBoolValue(\"OptimizeForSSE\", true);\n\t\t\t\telse\n\t\t\t\t\tConfig.SetDefaultBoolValue(\"OptimizeForSSE\", false);\n\t\t\t}\n\n\t\t\tif (Config[\"OptimizeForSSE\"] == \"true\") {\n\t\t\t\tOptOptions options;\n\t\t\t\toptions.targetVersion.SetFile(V20_2_0_7);\n\t\t\t\toptions.targetVersion.SetUser(12);\n\t\t\t\toptions.targetVersion.SetStream(100);\n\t\t\t\tnif.OptimizeFor(options);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\twxLogWarning(\"Version of NIF file doesn't match current target game.\");\n\t\t\twxMessageBox(wxString::Format(_(\"File format doesn't match the current game. Use FBX export, then start a new project and import the FBX file there.\")),\n\t\t\t\t\t\t _(\"Version\"),\n\t\t\t\t\t\t wxICON_WARNING,\n\t\t\t\t\t\t owner);\n\t\t}\n\t}\n\n\tfor (auto& s : nif.GetShapes()) {\n\t\tuint8_t meshIndex = 0;\n\t\tfor (auto meshPath : nif.GetExternalGeometryPathRefs(s)) {\n\t\t\tauto dataPath = Config[\"GameDataPath\"];\n\n\t\t\tauto meshStream = GetExternalGeometryStream(dataPath, meshPath.get(), nifFilePath);\n\t\t\tif (!meshStream) {\n\t\t\t\twxMessageBox(wxString::Format(_(\"Unable to locate external mesh data for shape. Expected path: %s\"), meshPath.get()),\n\t\t\t\t\t\t\t _(\"External Mesh Data Load Failure\"),\n\t\t\t\t\t\t\t wxICON_WARNING,\n\t\t\t\t\t\t\t owner);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tnif.LoadExternalShapeData(s, *meshStream, meshIndex);\n\t\t\tmeshIndex++;\n\t\t}\n\n\t\tnif.TriangulateShape(s);\n\t}\n}\n\nvoid OutfitProject::ResetTransforms() {\n\tbool clearRoot = false;\n\tbool unskinnedFound = false;\n\n\tfor (auto& s : workNif.GetShapes()) {\n\t\tif (s->IsSkinned()) {\n\t\t\t/*\n\t\t\t * Root node, shape and global-to-skin transform aren't rendered directly for skinned meshes.\n\t\t\t * They only affect different things, e.g. bounds and the global-to-parent transforms.\n\t\t\t *\n\t\t\t * By clearing these and recalculating bounds on export we make sure that\n\t\t\t * nothing but the individual bone transforms affect visuals.\n\t\t\t */\n\n\t\t\tif (!unskinnedFound)\n\t\t\t\tclearRoot = true;\n\n\t\t\tMatTransform oldXformGlobalToSkin = workAnim.shapeSkinning[s->name.get()].xformGlobalToSkin;\n\t\t\tMatTransform newXformGlobalToSkin;\n\n\t\t\t// Apply global-to-skin transform to vertices\n\t\t\tif (!newXformGlobalToSkin.IsNearlyEqualTo(oldXformGlobalToSkin)) {\n\t\t\t\tApplyTransformToShapeGeometry(s, newXformGlobalToSkin.ComposeTransforms(oldXformGlobalToSkin.InverseTransform()));\n\n\t\t\t\tworkAnim.ChangeGlobalToSkinTransform(s->name.get(), newXformGlobalToSkin);\n\t\t\t\tworkNif.SetShapeTransformGlobalToSkin(s, newXformGlobalToSkin);\n\t\t\t}\n\n\t\t\t// Clear shape transform\n\t\t\ts->SetTransformToParent(MatTransform());\n\n\t\t\t// Clear global-to-skin transform\n\t\t\tworkAnim.shapeSkinning[s->name.get()].xformGlobalToSkin.Clear();\n\t\t\tworkNif.SetShapeTransformGlobalToSkin(s, MatTransform());\n\t\t}\n\t\telse {\n\t\t\tclearRoot = false;\n\t\t\tunskinnedFound = true;\n\t\t}\n\t}\n \n\tif (clearRoot) {\n\t\t// Clear root node transform\n\t\tauto rootNode = workNif.GetRootNode();\n\t\tif (rootNode)\n\t\t\trootNode->SetTransformToParent(MatTransform());\n\t}\n}\n\nvoid OutfitProject::CreateSkinning(NiShape* s) {\n\tif (s->IsSkinned())\n\t\treturn;\n\tMatTransform globalToShape = workAnim.GetTransformGlobalToShape(s);\n\tworkNif.CreateSkinning(s);\n\tworkAnim.SetTransformGlobalToShape(s, globalToShape);\n}\n\nvoid OutfitProject::RemoveSkinning(NiShape* s) {\n\tif (!s->IsSkinned())\n\t\treturn;\n\tMatTransform shapeToGlobal = workAnim.GetTransformShapeToGlobal(s);\n\tworkNif.DeleteSkinning(s);\n\tworkAnim.ClearShape(s->name.get());\n\tworkAnim.SetTransformShapeToGlobal(s, shapeToGlobal);\n}\n\nvoid OutfitProject::RemoveSkinning() {\n\tfor (auto& s : workNif.GetShapes()) {\n\t\tRemoveSkinning(s);\n\t}\n\n\tworkNif.DeleteUnreferencedNodes();\n}\n\nbool OutfitProject::CheckForBadBones(bool interactive) {\n\tstruct ShapeBadBones {\n\t\tstd::unordered_map<std::string, MatTransform> badStandard, badCustom;\n\t\tbool fixStanSkin = false;\n\t};\n\tstd::unordered_map<std::string, ShapeBadBones> shapeBBs;\n\tbool gotAnyBad = false;\n\n\t// Find bad bones for every skinned shape, initializing shapeBBs.\n\tfor (NiShape* s : workNif.GetShapes()) {\n\t\tif (!s->IsSkinned())\n\t\t\tcontinue;\n\n\t\tstd::string shapeName = s->name.get();\n\t\tShapeBadBones& sbb = shapeBBs[shapeName];\n\t\tworkAnim.FindBonesWithInconsistentTransforms(shapeName, sbb.badStandard, sbb.badCustom);\n\t\tif (!sbb.badStandard.empty() || !sbb.badCustom.empty())\n\t\t\tgotAnyBad = true;\n\t\tif (!sbb.badStandard.empty())\n\t\t\tsbb.fixStanSkin = true;\n\t}\n\tif (!gotAnyBad) {\n\t\tif (interactive)\n\t\t\twxMessageBox(_(\"No Bad Bones Found.\"), _(\"No Bad Bones\"), wxOK, owner);\n\t\treturn false;\n\t}\n\n\t// For bad custom bones, we need to rearrange the data so it's keyed\n\t// on bone name rather than shape name.\n\tstruct BadCustomBone {\n\t\tstd::unordered_set<std::string> badShapes, goodShapes;\n\t\tenum FixType {DoNothing, TrustNode, TrustSkin};\n\t\tint fixtype = DoNothing;\n\t\tstd::string trustShape;\n\t};\n\tstd::unordered_map<std::string, BadCustomBone> badCBs;\n\tfor (auto& sbbp : shapeBBs) {\n\t\tconst std::string& shapeName = sbbp.first;\n\t\tShapeBadBones& sbb = sbbp.second;\n\t\tfor (auto& brp : sbb.badCustom)\n\t\t\tbadCBs[brp.first].badShapes.insert(shapeName);\n\t}\n\n\t// For each bad custom bone...\n\tfor (auto& bcbp : badCBs) {\n\t\tconst std::string& bone = bcbp.first;\n\t\tBadCustomBone& bcb = bcbp.second;\n\n\t\t// ...fill in goodShapes\n\t\tfor (auto& sbbp : shapeBBs) {\n\t\t\tconst std::string& shapeName = sbbp.first;\n\t\t\tif (bcb.badShapes.count(shapeName) == 0 && workAnim.GetShapeBoneIndex(shapeName, bone) >= 0)\n\t\t\t\tbcb.goodShapes.insert(shapeName);\n\t\t}\n\n\t\t// ...and calculate a recommendation:\n\t\t// If a skin matches the node, trust them.\n\t\tif (!bcb.goodShapes.empty())\n\t\t\tbcb.fixtype = BadCustomBone::TrustNode;\n\t\t// Otherwise, if there's only one skin, trust it.\n\t\tif (bcb.fixtype == BadCustomBone::DoNothing && bcb.badShapes.size() == 1) {\n\t\t\tbcb.fixtype = BadCustomBone::TrustSkin;\n\t\t\tbcb.trustShape = *bcb.badShapes.begin();\n\t\t}\n\t\t// Otherwise, if one of the skins is the reference, trust it.\n\t\tif (bcb.fixtype == BadCustomBone::DoNothing && baseShape) {\n\t\t\tstd::string baseShapeName = baseShape->name.get();\n\t\t\tfor (const std::string& shapeName : bcb.badShapes)\n\t\t\t\tif (shapeName == baseShapeName) {\n\t\t\t\t\tbcb.fixtype = BadCustomBone::TrustSkin;\n\t\t\t\t\tbcb.trustShape = baseShapeName;\n\t\t\t\t}\n\t\t}\n\t\t// Otherwise, pick the skin with the lowest residual error.\n\t\t// This is pretty arbitrary.  It's only marginally better than\n\t\t// picking randomly.\n\t\tif (bcb.fixtype == BadCustomBone::DoNothing) {\n\t\t\t// Calculate smallest rotation residual error\n\t\t\tfloat minRotErr = 10.0f;\n\t\t\tfor (const std::string& shapeName : bcb.badShapes) {\n\t\t\t\tfloat rotErr = RotMatToVec(shapeBBs[shapeName].badCustom[bone].rotation).length();\n\t\t\t\tif (rotErr < minRotErr)\n\t\t\t\t\tminRotErr = rotErr;\n\t\t\t}\n\n\t\t\t// Winnow shapes that have a significantly larger rotation error\n\t\t\t// than the smallest.\n\t\t\tstd::unordered_set<std::string> shapesLeft;\n\t\t\tfor (const std::string& shapeName : bcb.badShapes) {\n\t\t\t\tfloat rotErr = RotMatToVec(shapeBBs[shapeName].badCustom[bone].rotation).length();\n\t\t\t\tif (FloatsAreNearlyEqual(rotErr, minRotErr))\n\t\t\t\t\tshapesLeft.insert(shapeName);\n\t\t\t}\n\n\t\t\t// Calculate smallest translation residual error\n\t\t\tfloat minTrErr = FLT_MAX;\n\t\t\tfor (const std::string& shapeName : shapesLeft) {\n\t\t\t\tfloat trErr = shapeBBs[shapeName].badCustom[bone].translation.length();\n\t\t\t\tif (trErr < minTrErr)\n\t\t\t\t\tminTrErr = trErr;\n\t\t\t}\n\n\t\t\t// Winnow shapes that have a significantly larger translation error\n\t\t\t// than the smallest.\n\t\t\tstd::unordered_set<std::string> shapesLeft2;\n\t\t\tfor (const std::string& shapeName : shapesLeft) {\n\t\t\t\tfloat trErr = shapeBBs[shapeName].badCustom[bone].translation.length();\n\t\t\t\tif (FloatsAreNearlyEqual(trErr, minTrErr))\n\t\t\t\t\tshapesLeft2.insert(shapeName);\n\t\t\t}\n\t\t\tshapesLeft = std::move(shapesLeft2);\n\t\t\tshapesLeft2.clear();\n\n\t\t\t// Calculate smallest scale residual error\n\t\t\tfloat minScErr = FLT_MAX;\n\t\t\tfor (const std::string& shapeName : shapesLeft) {\n\t\t\t\tfloat scErr = std::fabs(shapeBBs[shapeName].badCustom[bone].scale - 1.0f);\n\t\t\t\tif (scErr < minScErr)\n\t\t\t\t\tminScErr = scErr;\n\t\t\t}\n\n\t\t\t// Winnow shapes that have a significantly larger scale error\n\t\t\t// than the smallest.\n\t\t\tfor (const std::string& shapeName : shapesLeft) {\n\t\t\t\tfloat scErr = std::fabs(shapeBBs[shapeName].badCustom[bone].scale - 1.0f);\n\t\t\t\tif (FloatsAreNearlyEqual(scErr, minScErr))\n\t\t\t\t\tshapesLeft2.insert(shapeName);\n\t\t\t}\n\t\t\tshapesLeft = std::move(shapesLeft2);\n\n\t\t\t// We might have more than one shape left, but it's highly unlikely.\n\t\t\t// Pick the first of the remaining shapes.\n\t\t\tbcb.fixtype = BadCustomBone::TrustSkin;\n\t\t\tbcb.trustShape = *shapesLeft.begin();\n\t\t}\n\t}\n\n\tif (interactive) {\n\t\t// Create dialog window\n\t\twxDialog dlg(owner, -1, _(\"Bad Bones\"), wxDefaultPosition, wxSize(800,600), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);\n\t\twxBoxSizer* topBox = new wxBoxSizer(wxVERTICAL);\n\t\twxSizerFlags sizerFlags = wxSizerFlags().Expand().Border(wxALL, 5);\n\t\tconstexpr int wrapPixels = 800;\n\t\twxScrolledWindow* wnd = new wxScrolledWindow(&dlg);\n\t\ttopBox->Add(wnd, wxSizerFlags().Expand().Proportion(1));\n\t\twxBoxSizer* scrollBox = new wxBoxSizer(wxVERTICAL);\n\t\twnd->SetScrollRate(30, 50);\n\n\t\t// A helper class for creating the collapsible panes\n\t\tstruct CollapsePane {\n\t\t\twxScrolledWindow* wnd;\n\t\t\twxCollapsiblePane* collapse;\n\t\t\twxFlexGridSizer* collPaneBox;\n\t\t\tCollapsePane(wxScrolledWindow* wi, wxSizer* boxSizer, const wxString& label, const wxString& col1Label):\n\t\t\t\twnd(wi) {\n\t\t\t\twxSizerFlags sizerFlags = wxSizerFlags().Expand().Border(wxALL, 5);\n\t\t\t\tcollapse = new wxCollapsiblePane(wnd, wxID_ANY, label, wxDefaultPosition, wxDefaultSize, wxCP_DEFAULT_STYLE | wxCP_NO_TLW_RESIZE);\n\t\t\t\tboxSizer->Add(collapse, sizerFlags);\n\t\t\t\tcollPaneBox = new wxFlexGridSizer(4);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, col1Label), sizerFlags);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, _(\"Error in rotation\")), sizerFlags);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, _(\"Error in translation\")), sizerFlags);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, _(\"Error in scale\")), sizerFlags);\n\t\t\t}\n\t\t\tvoid AddRow(const wxString& label, const MatTransform& t) {\n\t\t\t\twxSizerFlags sizerFlags = wxSizerFlags().Expand().Border(wxALL, 5);\n\t\t\t\tfloat rotErr = RotMatToVec(t.rotation).length();\n\t\t\t\tfloat trErr = t.translation.length();\n\t\t\t\tfloat scErr = std::fabs(t.scale - 1.0f);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, label), sizerFlags);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, wxString() << rotErr), sizerFlags);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, wxString() << trErr), sizerFlags);\n\t\t\t\tcollPaneBox->Add(new wxStaticText(collapse->GetPane(), wxID_ANY, wxString() << scErr), sizerFlags);\n\t\t\t}\n\t\t\tvoid Finish() {\n\t\t\t\tcollapse->GetPane()->SetSizerAndFit(collPaneBox);\n\t\t\t\twxScrolledWindow* wndl = wnd;\n\t\t\t\tcollapse->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [wndl](wxCollapsiblePaneEvent&) { wndl->FitInside(); });\n\t\t\t}\n\t\t};\n\n\t\t// Add a frame for each shape with bad standard bones\n\t\tfor (auto& sbbp : shapeBBs) {\n\t\t\tconst std::string &shapeName = sbbp.first;\n\t\t\tShapeBadBones& sbb = sbbp.second;\n\t\t\tauto& bb = sbb.badStandard;\n\t\t\tif (bb.empty())\n\t\t\t\tcontinue;\n\n\t\t\twxStaticBoxSizer* boxSizer = new wxStaticBoxSizer(wxVERTICAL, wnd, wxString::Format(_(\"Bad standard bones for shape \\\"%s\\\"\"), shapeName));\n\t\t\tscrollBox->Add(boxSizer, sizerFlags);\n\n\t\t\twxString label = wxString::Format(_(\"%zu bones in shape \\\"%s\\\" had inconsistencies between their NIF skin transforms and the standard skeleton:\\n\"), bb.size(), shapeName);\n\n\t\t\tauto brit = bb.begin();\n\t\t\tlabel << brit->first;\n\t\t\t++brit;\n\n\t\t\twhile (brit != bb.end()) {\n\t\t\t\tlabel << \", \" << brit->first;\n\t\t\t\t++brit;\n\t\t\t}\n\n\t\t\twxStaticText* ctrl = new wxStaticText(wnd, -1, label);\n\t\t\tctrl->Wrap(wrapPixels);\n\t\t\tboxSizer->Add(ctrl, sizerFlags);\n\n\t\t\twxRadioButton* rb = new wxRadioButton(wnd, wxID_ANY, _(\"Update skin (recommended)\"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);\n\t\t\trb->SetValue(1);\n\t\t\trb->Bind(wxEVT_RADIOBUTTON, [&](wxCommandEvent&) {\n\t\t\t\tsbb.fixStanSkin = true;\n\t\t\t});\n\t\t\tboxSizer->Add(rb, sizerFlags);\n\t\t\tsbb.fixStanSkin = true;\n\n\t\t\tCollapsePane bcp(wnd, boxSizer, _(\"Details\"), _(\"Bone\"));\n\t\t\tfor (auto& brp : bb)\n\t\t\t\tbcp.AddRow(brp.first, brp.second);\n\t\t\tbcp.Finish();\n\n\t\t\trb = new wxRadioButton(wnd, wxID_ANY, _(\"Do nothing\"));\n\t\t\trb->Bind(wxEVT_RADIOBUTTON, [&](wxCommandEvent&) {\n\t\t\t\tsbb.fixStanSkin = false;\n\t\t\t});\n\t\t\tboxSizer->Add(rb, sizerFlags);\n\t\t}\n\n\t\t// Add a frame for each bad custom bone\n\t\tfor (auto& bcbp : badCBs) {\n\t\t\tconst std::string& bone = bcbp.first;\n\t\t\tBadCustomBone& bcb = bcbp.second;\n\n\t\t\twxStaticBoxSizer* boxSizer = new wxStaticBoxSizer(wxVERTICAL, wnd, wxString::Format(_(\"Bad Custom Bone \\\"%s\\\"\"), bone));\n\t\t\tscrollBox->Add(boxSizer, sizerFlags);\n\n\t\t\twxString label = wxString::Format(_(\"Custom bone \\\"%s\\\" had inconsistent NIF node and skin transforms for the following shapes:\\n\\\"\"), bone);\n\n\t\t\tauto bsit = bcb.badShapes.begin();\n\t\t\tlabel << *bsit;\n\t\t\t++bsit;\n\n\t\t\twhile (bsit != bcb.badShapes.end()) {\n\t\t\t\tlabel << \"\\\", \\\"\" << *bsit;\n\t\t\t\t++bsit;\n\t\t\t}\n\t\t\tlabel << \"\\\"\";\n\n\t\t\twxStaticText* ctrl = new wxStaticText(wnd, -1, label);\n\t\t\tctrl->Wrap(wrapPixels);\n\t\t\tboxSizer->Add(ctrl, sizerFlags);\n\n\t\t\twxString tnLabel;\n\t\t\tif (bcb.fixtype == BadCustomBone::TrustNode) {\n\t\t\t\ttnLabel = \"\";\n\t\t\t\tif (bcb.goodShapes.size() > 1)\n\t\t\t\t\ttnLabel << _(\"Trust node and skins \\\"\");\n\t\t\t\telse\n\t\t\t\t\ttnLabel << _(\"Trust node and skin \\\"\");\n\t\t\t\tauto gsit = bcb.goodShapes.begin();\n\t\t\t\ttnLabel << *gsit;\n\t\t\t\t++gsit;\n\t\t\t\twhile (gsit != bcb.goodShapes.end()) {\n\t\t\t\t\ttnLabel << \"\\\", \\\"\" << *gsit;\n\t\t\t\t\t++gsit;\n\t\t\t\t}\n\t\t\t\ttnLabel << _(\"\\\", and update other skins (recommended)\");\n\t\t\t}\n\t\t\telse if (bcb.badShapes.size() > 1)\n\t\t\t\ttnLabel = _(\"Trust node, and update skins\");\n\t\t\telse\n\t\t\t\ttnLabel = _(\"Trust node, and update skin\");\n\t\t\twxRadioButton* rb = new wxRadioButton(wnd, wxID_ANY, tnLabel, wxDefaultPosition, wxDefaultSize, wxRB_GROUP);\n\t\t\tif (bcb.fixtype == BadCustomBone::TrustNode)\n\t\t\t\trb->SetValue(1);\n\t\t\trb->Bind(wxEVT_RADIOBUTTON, [&](wxCommandEvent&) {\n\t\t\t\tbcb.fixtype = BadCustomBone::TrustNode;\n\t\t\t});\n\t\t\tboxSizer->Add(rb, sizerFlags);\n\n\t\t\tCollapsePane ncp(wnd, boxSizer, _(\"Details\"), _(\"Skin\"));\n\t\t\tfor (const std::string& shapeName : bcb.badShapes) {\n\t\t\t\tMatTransform t = shapeBBs[shapeName].badCustom[bone];\n\t\t\t\tncp.AddRow(shapeName, t);\n\t\t\t}\n\t\t\tncp.Finish();\n\n\t\t\tfor (const std::string& shapeName : bcb.badShapes) {\n\t\t\t\twxString sLabel;\n\t\t\t\tsLabel << _(\"Trust skin \\\"\") << shapeName;\n\t\t\t\tif (bcb.badShapes.size() == 1 && bcb.goodShapes.empty())\n\t\t\t\t\tsLabel << _(\"\\\", and update node\");\n\t\t\t\telse\n\t\t\t\t\tsLabel << _(\"\\\", and update node and other skins\");\n\t\t\t\trb = new wxRadioButton(wnd, wxID_ANY, sLabel);\n\t\t\t\trb->Bind(wxEVT_RADIOBUTTON, [&](wxCommandEvent&) {\n\t\t\t\t\tbcb.fixtype = BadCustomBone::TrustSkin;\n\t\t\t\t\tbcb.trustShape = shapeName;\n\t\t\t\t});\n\t\t\t\tif (bcb.fixtype == BadCustomBone::TrustSkin && bcb.trustShape == shapeName)\n\t\t\t\t\trb->SetValue(1);\n\t\t\t\tboxSizer->Add(rb, sizerFlags);\n\n\t\t\t\tCollapsePane scp(wnd, boxSizer, _(\"Details\"), _(\"With\"));\n\t\t\t\tscp.AddRow(_(\"Node\"), shapeBBs[shapeName].badCustom[bone]);\n\t\t\t\tfor (const std::string& shapeName2 : bcb.badShapes) {\n\t\t\t\t\tif (shapeName == shapeName2)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tMatTransform skinToBone1, skinToBone2;\n\t\t\t\t\tworkAnim.GetXFormSkinToBone(shapeName, bone, skinToBone1);\n\t\t\t\t\tworkAnim.GetXFormSkinToBone(shapeName, bone, skinToBone2);\n\t\t\t\t\tMatTransform residual = skinToBone1.ComposeTransforms(skinToBone2.InverseTransform());\n\t\t\t\t\tscp.AddRow(shapeName2, residual);\n\t\t\t\t}\n\t\t\t\tscp.Finish();\n\t\t\t}\n\n\t\t\trb = new wxRadioButton(wnd, wxID_ANY, _(\"Do nothing\"));\n\t\t\trb->Bind(wxEVT_RADIOBUTTON, [&](wxCommandEvent&) {\n\t\t\t\tbcb.fixtype = BadCustomBone::DoNothing;\n\t\t\t});\n\t\t\tif (bcb.fixtype == BadCustomBone::DoNothing)\n\t\t\t\trb->SetValue(1);\n\t\t\tboxSizer->Add(rb, sizerFlags);\n\t\t}\n\n\t\t// Finish building the dialog window\n\t\twnd->SetSizer(scrollBox);\n\t\twxStdDialogButtonSizer* buttonSizer = new wxStdDialogButtonSizer;\n\t\tbuttonSizer->AddButton(new wxButton(&dlg, wxID_OK));\n\t\tbuttonSizer->AddButton(new wxButton(&dlg, wxID_CANCEL, _(\"Fix nothing\")));\n\t\tbuttonSizer->Realize();\n\t\ttopBox->Add(buttonSizer, sizerFlags);\n\t\tdlg.SetSizer(topBox);\n\n\t\tif (dlg.ShowModal() == wxID_CANCEL)\n\t\t\treturn false;\n\t}\n\n\t// Execute the fixes (recommended defaults, or user's choices if interactive)\n\tfor (auto& sbbp : shapeBBs) {\n\t\tconst std::string &shapeName = sbbp.first;\n\t\tShapeBadBones& sbb = sbbp.second;\n\n\t\tif (sbb.fixStanSkin)\n\t\t\tfor (auto& brp : sbb.badStandard)\n\t\t\t\tworkAnim.RecalcXFormSkinToBone(shapeName, brp.first);\n\t}\n\tfor (auto& bcbp : badCBs) {\n\t\tconst std::string& bone = bcbp.first;\n\t\tBadCustomBone& bcb = bcbp.second;\n\t\tif (bcb.fixtype == BadCustomBone::TrustSkin) {\n\t\t\tworkAnim.RecalcCustomBoneXFormsFromSkin(bcb.trustShape, bone);\n\t\t\t// After updating the node's bone-to-global transform, any shapes\n\t\t\t// that had good skin-to-bone transforms now have bad ones and\n\t\t\t// have to be updated.\n\t\t\tfor (const std::string& shapeName : bcb.goodShapes)\n\t\t\t\tworkAnim.RecalcXFormSkinToBone(shapeName, bone);\n\t\t}\n\t\tif (bcb.fixtype != BadCustomBone::DoNothing)\n\t\t\tfor (const std::string& shapeName : bcb.badShapes)\n\t\t\t\tworkAnim.RecalcXFormSkinToBone(shapeName, bone);\n\t}\n\treturn true;\n}\n\nbool OutfitProject::ShapeHasBadBones(NiShape* s) {\n\tif (!s->IsSkinned())\n\t\treturn false;\n\tstd::unordered_map<std::string, MatTransform> badStandard, badCustom;\n\tstd::string shapeName = s->name.get();\n\tworkAnim.FindBonesWithInconsistentTransforms(shapeName, badStandard, badCustom);\n\tif (!badStandard.empty() || !badCustom.empty())\n\t\treturn true;\n\treturn false;\n}\n\n// GetAllPoseTransforms: this function calculates the pose transform (in\n// shape coordinates) for every vertex.  Note that the resulting transforms\n// do not follow the rules: the \"rotation\" is not necessarily a rotation;\n// it might contain a scale, and it'll almost certainly contain rule violations\n// because of linear interpolation.\nvoid OutfitProject::GetAllPoseTransforms(NiShape* s, std::vector<MatTransform>& ts) {\n\tint nVerts = static_cast<int>(s->GetNumVertices());\n\tts.resize(nVerts);\n\n\t// We're going to _sum_ rotations, so we have to start with zero matrices.\n\tfor (int i = 0; i < nVerts; ++i)\n\t\tts[i].rotation[0][0] = ts[i].rotation[1][1] = ts[i].rotation[2][2] = 0.0f;\n\tstd::vector<float> tws(nVerts, 0.0f); // Total weight for each vertex\n\n\tAnimSkin& animSkin = workAnim.shapeSkinning[s->name.get()];\n\tMatTransform globalToSkin = workAnim.GetTransformGlobalToShape(s);\n\n\tfor (auto& boneNamesIt : animSkin.boneNames) {\n\t\tAnimBone* animB = AnimSkeleton::getInstance().GetBonePtr(boneNamesIt.first);\n\t\tif (!animB)\n\t\t\tcontinue;\n\t\tAnimWeight& animW = animSkin.boneWeights[boneNamesIt.second];\n\t\t// Compose transform: skin -> (posed) bone -> global -> skin\n\t\tMatTransform t = globalToSkin.ComposeTransforms(animB->xformPoseToGlobal.ComposeTransforms(animW.xformSkinToBone));\n\t\t// Add weighted contributions to vertex transforms for this bone\n\t\tfor (auto& wIt : animW.weights) {\n\t\t\tint vi = wIt.first;\n\t\t\tfloat w = wIt.second;\n\t\t\tts[vi].rotation += t.rotation * (w * t.scale);\n\t\t\tts[vi].translation += t.translation * w;\n\t\t\ttws[vi] += w;\n\t\t}\n\t}\n\n\t// Check if total weight for each vertex was 1\n\tfor (int vi = 0; vi < nVerts; ++vi) {\n\t\tif (tws[vi] < EPSILON) { // If weights are missing for this vertex\n\t\t\tts[vi] = MatTransform();\n\t\t}\n\t\telse if (std::fabs(tws[vi] - 1.0f) >= EPSILON) { // If weights are not normalized for this vertex\n\t\t\tfloat normAdjust = 1.0f / tws[vi];\n\t\t\tts[vi].rotation *= normAdjust;\n\t\t\tts[vi].translation *= normAdjust;\n\t\t}\n\t\t// else do nothing because weights totaled 1.\n\t}\n\n\t// Note that the rotations still contain scale and interpolation\n\t// artifacts that make them not rotations!\n}\n\n// Note that ApplyTransformToOneVertexGeometry does not assume that t.rotation\n// is a proper rotation, so it can be used with GetAllPoseTransforms.\nvoid OutfitProject::ApplyTransformToOneVertexGeometry(UndoStateVertex& usv, const MatTransform& transform) {\n\tVector3 newPos = transform.ApplyTransform(usv.pos);\n\tif (newPos.IsNearlyEqualTo(usv.pos)) {\n\t\t// New position is nearly equal to old position (reduce noise)\n\t\treturn;\n\t}\n\n\tusv.pos = newPos;\n\tusv.normal = transform.ApplyTransformToDir(usv.normal);\n\tusv.normal.Normalize();\n\tusv.tangent = transform.ApplyTransformToDir(usv.tangent);\n\tusv.tangent.Normalize();\n\tusv.bitangent = transform.ApplyTransformToDir(usv.bitangent);\n\tusv.bitangent.Normalize();\n\n\tfor (auto& usvsd : usv.diffs) {\n\t\tSliderData& sd = activeSet[usvsd.sliderName];\n\t\tif (sd.bUV || sd.bClamp || sd.bZap)\n\t\t\tcontinue;\n\n\t\tusvsd.diff = transform.ApplyTransformToDiff(usvsd.diff);\n\t}\n}\n\nvoid OutfitProject::ApplyPoseTransformsToShapeGeometry(NiShape* s, UndoStateShape& uss) {\n\tint nVerts = static_cast<int>(s->GetNumVertices());\n\tint nTris = static_cast<int>(s->GetNumTriangles());\n\n\t// Get all the shape's vertices\n\tstd::vector<uint16_t> vinds(nVerts);\n\tfor (int i = 0; i < nVerts; ++i)\n\t\tvinds[i] = i;\n\tCollectVertexData(s, uss, vinds);\n\tuss.addVerts = uss.delVerts;\n\n\t// Get all the shape's triangles\n\tstd::vector<uint32_t> tinds(nTris);\n\tfor (int i = 0; i < nTris; ++i)\n\t\ttinds[i] = i;\n\tCollectTriangleData(s, uss, tinds);\n\tuss.addTris = uss.delTris;\n\n\t// Get all the pose transforms\n\tstd::vector<MatTransform> ts;\n\tGetAllPoseTransforms(s, ts);\n\n\t// Apply all the pose transforms\n\tfor (int i = 0; i < nVerts; ++i)\n\t\tApplyTransformToOneVertexGeometry(uss.addVerts[i], ts[i]);\n}\n\nvoid OutfitProject::ApplyPoseTransformsToAllShapeGeometry(UndoStateProject& usp) {\n\tusp.undoType = UndoType::Mesh;\n\tstd::vector<NiShape*> shapes = workNif.GetShapes();\n\tusp.usss.resize(shapes.size());\n\tfor (size_t si = 0; si < shapes.size(); ++si) {\n\t\tUndoStateShape& uss = usp.usss[si];\n\t\tuss.shapeName = shapes[si]->name.get();\n\t\tApplyPoseTransformsToShapeGeometry(shapes[si], uss);\n\t}\n}\n"
  },
  {
    "path": "src/program/OutfitProject.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../components/Anim.h\"\n#include \"../components/Automorph.h\"\n#include \"../components/Mesh.h\"\n#include \"OutfitStudio.h\"\n\n#include <optional>\n#include <wx/arrstr.h>\n#include <wx/filename.h>\n\nstruct ConformOptions {\n\tfloat proximityRadius = 10.0f;\n\tint maxResults = 10;\n\tbool noSqueeze = false;\n\tbool solidMode = false;\n\tbool axisX = true;\n\tbool axisY = true;\n\tbool axisZ = true;\n\tstd::vector<std::string> sliderNames; // If empty, conform all non-zap/non-UV sliders\n};\n\nclass OutfitStudioFrame;\nstruct UndoStateShape;\nstruct UndoStateShapeDelete;\n\nstruct MergeCheckErrors {\n\tbool canMerge = false;\n\tbool shapesSame = false;\n\tbool partitionsMismatch = false;\n\tbool segmentsMismatch = false;\n\tbool tooManyVertices = false;\n\tbool tooManyTriangles = false;\n\tbool shaderMismatch = false;\n\tbool textureMismatch = false;\n\tbool alphaPropMismatch = false;\n};\n\n// SymmetricVertices: result from the function MatchSymmetricVertices\nstruct SymmetricVertices {\n\t// matches has all matched pairs of vertices, including self-matches,\n\t// in no particular order.  The first vertex index is always less than\n\t// or equal to the second.  Only one vertex in each weld set is listed:\n\t// the one with the lowest index.\n\tstd::vector<std::pair<int, int>> matches;\n\tstd::vector<int> unmatched;\n};\n\n// VertexAsymmetries: result from the function FindVertexAsymmetries\nstruct VertexAsymmetries {\n\t// Indexing of each vector<bool> and vector<float> is the same as\n\t// SymmetricVertices::matches.\n\tstd::vector<bool> positions;\n\tstd::vector<float> poserr;\n\tstruct Slider {\n\t\tstd::string sliderName;\n\t\tstd::vector<bool> aflags;\n\t\tstd::vector<float> differr;\n\t};\n\tstd::vector<Slider> sliders;\n\tstd::vector<bool> anyslider;\n\tstruct Bone {\n\t\tstd::string boneName;\n\t\t// We call this bone \"bone 1\" and its mirror \"bone 2\".\n\t\t// mirroroffset gives the offset in bones of bone 2.\n\t\tint mirroroffset = 0;\t// -1, 0, or 1\n\t\t// aflags[i] will be true if p1's bone 1 weight doesn't match p2's\n\t\t// bone 2 weight.  That means not all asymmetries for bone 1 will\n\t\t// be listed here: if bone 1 != bone 2 and (p1,p2) is a dual\n\t\t// match, bone 2's aflags will indicate whether p2's bone 1 weight\n\t\t// doesn't match p1's bone 2 weight, which is also an asymmetry for\n\t\t// bone 1.\n\t\tstd::vector<bool> aflags;\n\t\tstd::vector<float> weighterr;\n\t};\n\tstd::vector<Bone> bones;\n\tstd::vector<bool> anybone;\n};\n\nstruct VertexAsymmetryStats {\n\tint unmaskedCount = 0;\n\tint posCount = 0;\n\tfloat posAvg = 0.0f;\n\tint anySliderCount = 0;\n\tint anyBoneCount = 0;\n\tstd::vector<int> sliderCounts;\n\tstd::vector<float> sliderAvgs;\n\tstd::vector<int> boneCounts;\n\tstd::vector<float> boneAvgs;\n};\n\nstruct VertexAsymmetryTasks {\n\tbool doUnmatched = false;\n\tbool doPos = false;\n\tstd::vector<bool> doSliders;\t// Same size as VertexAsymmetries::sliders\n\tstd::vector<bool> doBones;\t// Same size as VertexAsymmetries::bones\n};\n\nvoid CalcVertexAsymmetryStats(const SymmetricVertices& symverts, const VertexAsymmetries& asyms, const std::vector<bool>& selVerts, VertexAsymmetryStats& stats);\nstd::vector<bool> CalcVertexListForAsymmetryTasks(const SymmetricVertices& symverts, const VertexAsymmetries& asyms, const VertexAsymmetryTasks& tasks, int nVerts);\nvoid AddWeldedToVertexList(const Mesh::WeldVertsType& welcVerts, std::vector<bool>& selVerts);\n\nclass OutfitProject {\n\tOutfitStudioFrame* owner = nullptr;\n\n\tvoid UpdateProgress(int val, const wxString& msg = \"\");\n\n\tnifly::NifFile workNif;\n\tAnimInfo workAnim;\n\tnifly::NiShape* baseShape = nullptr;\n\n\t// All cloth data blocks that have been loaded during work\n\tstd::unordered_map<std::string, std::unique_ptr<nifly::BSClothExtraData>> clothData;\n\n\tstd::unique_ptr<std::istream> GetExternalGeometryStream(const std::string& dir, const std::string& path, const std::string& nifFilePath = std::string()) const;\n\tvoid ValidateNIF(nifly::NifFile& nif, const std::string& nifFilePath = std::string());\n\n\t// Applies the inverse of the blended pose transform to a NIF-space diff\n\t// vector for a single vertex, converting it from posed space to rest space.\n\tnifly::Vector3 InversePoseDiff(int vertIndex, const nifly::Vector3& diffNif, AnimSkin& animSkin, const nifly::MatTransform& globalToSkin);\n\npublic:\n\tstd::string outfitName = \"New Outfit\";\n\tDiffDataSets baseDiffData;\n\tSliderSet activeSet;\n\tAutomorph morpher;\n\tbool morpherInitialized = false;\n\n\tstd::unordered_map<std::string, std::vector<std::string>> shapeTextures;\n\tstd::unordered_map<std::string, MaterialFile> shapeMaterialFiles;\n\n\t// inOwner is meant to provide access to OutfitStudio for the purposes of reporting process status only.\n\tOutfitProject(OutfitStudioFrame* inOwner = nullptr);\n\t~OutfitProject();\n\n\twxString mFileName;\n\twxString mOutfitName;\n\twxString mDataDir;\n\twxString mBaseFile;\n\twxString mGamePath;\n\twxString mGameFile;\n\tbool mCopyRef = true;\n\tbool mGenWeights = false;\n\tbool bPreventMorphFile = false;\n\tbool bKeepZappedShapes = false;\n\tbool bPose = false;\n\n\t// Reference source info (remembered when reference is loaded from an OSP)\n\tstd::string mRefProjectFile;    // OSP file path relative to project dir\n\tstd::string mRefProjectName;    // Slider set name in the OSP file\n\tstd::string mRefShapeName;      // Shape name in the project\n\n\t// Returns a string error message or empty string on success.\n\tstd::string Save(const wxFileName& sliderSetFile,\n\t\t\t\t\t const wxString& strOutfitName,\n\t\t\t\t\t const wxString& strDataDir,\n\t\t\t\t\t const wxString& strBaseFile,\n\t\t\t\t\t const wxString& strGamePath,\n\t\t\t\t\t const wxString& strGameFile,\n\t\t\t\t\t bool genWeights,\n\t\t\t\t\t bool copyRef,\n\t\t\t\t\t bool preventMorphFile,\n\t\t\t\t\t bool keepZappedShapes);\n\n\tbool SaveSliderData(const std::string& fileName, bool copyRef = true);\n\n\tnifly::NifFile* GetWorkNif() { return &workNif; }\n\tAnimInfo* GetWorkAnim() { return &workAnim; }\n\tstd::unordered_map<std::string, std::unique_ptr<nifly::BSClothExtraData>>& GetClothData() { return clothData; }\n\n\tnifly::NiShape* GetBaseShape() { return baseShape; }\n\tvoid SetBaseShape(nifly::NiShape* shape, const bool moveData = true);\n\n\tbool IsBaseShape(nifly::NiShape* shape) { return (shape && shape == baseShape); }\n\n\tstd::string SliderSetName();\n\tstd::string SliderSetFileName();\n\tstd::string OutfitName();\n\n\tvoid ReplaceForbidden(std::string& str, const char& replacer = ' ');\n\n\tbool ValidSlider(const size_t index);\n\tbool ValidSlider(const std::string& sliderName);\n\tbool AllSlidersZero();\n\tsize_t SliderCount();\n\tstd::string GetSliderName(const size_t index);\n\tvoid GetSliderList(std::vector<std::string>& sliderNames);\n\tvoid AddEmptySlider(const std::string& newName);\n\tvoid AddZapSlider(const std::string& newName, std::unordered_map<uint16_t, float>& verts, nifly::NiShape* shape);\n\tvoid AddCombinedSlider(const std::string& newName);\n\n\tnifly::NiShape* CreateNifShapeFromData(const std::string& shapeName,\n\t\t\t\t\t\t\t\t\t\t   const std::vector<nifly::Vector3>* v,\n\t\t\t\t\t\t\t\t\t\t   const std::vector<nifly::Triangle>* t = nullptr,\n\t\t\t\t\t\t\t\t\t\t   const std::vector<nifly::Vector2>* uv = nullptr,\n\t\t\t\t\t\t\t\t\t\t   const std::vector<nifly::Vector3>* norms = nullptr);\n\n\t// Slider data can have a separate name from the shape target.\n\tstd::string SliderShapeDataName(const size_t index, const std::string& shapeName);\n\tbool SliderClamp(const size_t index);\n\tbool SliderZap(const size_t index);\n\tbool SliderUV(const size_t index);\n\twxArrayString SliderZapToggles(const size_t index);\n\tbool SliderInvert(const size_t index);\n\tbool SliderHidden(const size_t index);\n\tbool SliderIndexFromName(const std::string& sliderName, size_t& index);\n\n\tvoid SetSliderZap(const size_t index, const bool zap);\n\tvoid SetSliderZapToggles(const size_t index, const wxArrayString& toggles);\n\tvoid SetSliderInvert(const size_t index, const bool inv);\n\tvoid SetSliderUV(const size_t index, const bool uv);\n\tvoid SetSliderHidden(const size_t index, const bool hidden);\n\tvoid SetSliderDefault(const size_t index, const int val, const bool isHi);\n\tvoid SetSliderName(const size_t index, const std::string& newName);\n\n\tvoid CloneSlider(const std::string& sliderName, const std::string& cloneName);\n\tvoid NegateSlider(const std::string& sliderName, nifly::NiShape* shape);\n\tvoid MaskAffected(const std::string& sliderName, nifly::NiShape* shape);\n\n\tbool SetSliderFromNIF(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName);\n\tvoid SetSliderFromBSD(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName);\n\tbool SetSliderFromOBJ(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName);\n#ifdef USE_FBXSDK\n\tbool SetSliderFromFBX(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName);\n#endif\n\tvoid SetSliderFromDiff(const std::string& sliderName, nifly::NiShape* shape, const TargetDataDiffs& diff);\n\tint SaveSliderNIF(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName);\n\tint SaveSliderBSD(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName);\n\tint SaveSliderOBJ(const std::string& sliderName, nifly::NiShape* shape, const std::string& fileName, const bool onlyDiff = false);\n\tbool WriteMorphTRI(const std::string& triPath);\n\tbool WriteHeadTRI(nifly::NiShape* shape, const std::string& triPath);\n\tbool WriteSFMorphs(nifly::NiShape* shape, const std::string& morphPath);\n\n\tfloat& SliderValue(const size_t index);\n\tfloat& SliderValue(const std::string& name);\n\tfloat SliderDefault(const size_t index, const bool hi);\n\n\tvoid InitConform();\n\tvoid ConformShape(nifly::NiShape* shape, const ConformOptions& options = ConformOptions());\n\n\tconst std::string& ShapeToTarget(const std::string& shapeName);\n\tconst std::string& TargetToShape(const std::string& targetName);\n\tint GetVertexCount(nifly::NiShape* shape);\n\tvoid GetLiveVerts(nifly::NiShape* shape, std::vector<nifly::Vector3>& outVerts, std::vector<nifly::Vector2>* outUVs = nullptr);\n\tvoid GetSliderDiff(nifly::NiShape* shape, const std::string& sliderName, std::vector<nifly::Vector3>& outVerts);\n\tvoid GetSliderDiffUV(nifly::NiShape* shape, const std::string& sliderName, std::vector<nifly::Vector2>& outUVs);\n\tsize_t GetActiveBoneCount();\n\tvoid GetActiveBones(std::vector<std::string>& outBoneNames);\n\n\tstd::vector<std::string> GetShapeTextures(nifly::NiShape* shape);\n\tbool GetShapeMaterialFile(nifly::NiShape* shape, MaterialFile& outMatFile);\n\n\tvoid SetTextures();\n\tvoid SetTextures(const std::vector<std::string>& textureFiles);\n\tvoid SetTextures(nifly::NiShape* shape, const std::vector<std::string>& textureFiles = std::vector<std::string>());\n\n\tbool IsValidShape(const std::string& shapeName);\n\n\tbool& SliderShow(const size_t index);\n\tbool& SliderShow(const std::string& sliderName);\n\n\tvoid RefreshMorphShape(nifly::NiShape* shape);\n\tvoid UpdateShapeFromMesh(nifly::NiShape* shape, const Mesh* m);\n\tvoid UpdateMorphResult(nifly::NiShape* shape, const std::string& sliderName, const TargetDataDiffs& vertUpdates);\n\n\t// Converts per-vertex diffs from posed mesh space to rest mesh space.\n\t// Only has effect when bPose is true; otherwise diffs are unchanged.\n\tvoid UndoPoseDiffs(nifly::NiShape* shape, std::unordered_map<uint16_t, nifly::Vector3>& diffs);\n\n\t// Computes and stores rest-space NIF diffs in the undo state for\n\t// pose-independent undo/redo. Only has effect when bPose is true.\n\tvoid ComputeUndoRestDiffs(nifly::NiShape* shape, UndoStateShape& uss);\n\tvoid ScaleMorphResult(nifly::NiShape* shape, const std::string& sliderName, float scaleValue);\n\tvoid MoveVertex(nifly::NiShape* shape, const nifly::Vector3& pos, const int& id);\n\tvoid OffsetShape(nifly::NiShape* shape, const nifly::Vector3& xlate, std::unordered_map<uint16_t, float>* mask = nullptr);\n\tvoid ScaleShape(nifly::NiShape* shape, const nifly::Vector3& scale, std::unordered_map<uint16_t, float>* mask = nullptr);\n\tvoid RotateShape(nifly::NiShape* shape, const nifly::Vector3& angle, std::unordered_map<uint16_t, float>* mask = nullptr);\n\tvoid ApplyTransformToShapeGeometry(nifly::NiShape* shape, const nifly::MatTransform& t);\n\n\t// Uses the AutoMorph class to generate proximity values for bone weights.\n\t// This is done by creating several virtual sliders that contain weight offsets for each vertex per bone.\n\t// These data sets are then temporarily linked to the AutoMorph class and result 'diffs' are generated.\n\t// The resulting data is then written back to the outfit shape as the green color channel.\n\tvoid CopyBoneWeights(nifly::NiShape* shape,\n\t\t\t\t\t\t const float proximityRadius,\n\t\t\t\t\t\t const int maxResults,\n\t\t\t\t\t\t std::unordered_map<uint16_t, float>& mask,\n\t\t\t\t\t\t const std::vector<std::string>& boneList,\n\t\t\t\t\t\t int nCopyBones,\n\t\t\t\t\t\t const std::vector<std::string>& lockedBones,\n\t\t\t\t\t\t UndoStateShape& uss,\n\t\t\t\t\t\t bool bSpreadWeight);\n\t// Transfers the weights of the selected bones from reference to chosen shape 1:1. Requires same vertex count and order.\n\tvoid TransferSelectedWeights(nifly::NiShape* shape, std::unordered_map<uint16_t, float>* mask = nullptr, std::vector<std::string>* inBoneList = nullptr);\n\tbool HasUnweighted(std::vector<std::string>* shapeNames = nullptr);\n\n\tvoid AddBoneRef(const std::string& boneName);\n\tvoid AddCustomBoneRef(const std::string& boneName, const std::string& parentBone, const nifly::MatTransform& xformToParent);\n\tvoid ModifyCustomBone(AnimBone* bPtr, const std::string& parentBone, const nifly::MatTransform& xformToParent);\n\n\t// CopySegPart returns the number of failed triangles, or 0 for success.\n\tint CopySegPart(nifly::NiShape* shape);\n\n\tvoid ClearWorkSliders();\n\tvoid ClearReference();\n\tvoid ClearOutfit();\n\tvoid ClearSlider(nifly::NiShape* shape, const std::string& sliderName);\n\tvoid ClearUnmaskedDiff(nifly::NiShape* shape, const std::string& sliderName, std::unordered_map<uint16_t, float>* mask);\n\tvoid DeleteSlider(const std::string& sliderName);\n\n\tint LoadSkeletonReference(const std::string& skeletonFileName);\n\tint LoadReferenceTemplate(const std::string& sourceFile,\n\t\t\t\t\t\t\t  const std::string& set,\n\t\t\t\t\t\t\t  const std::string& shape,\n\t\t\t\t\t\t\t  bool loadAll = false,\n\t\t\t\t\t\t\t  bool mergeSliders = false,\n\t\t\t\t\t\t\t  bool mergeZaps = false,\n\t\t\t\t\t\t\t  bool appendNewSliders = true);\n\tint LoadReferenceNif(const std::string& fileName, const std::string& shapeName, bool mergeSliders = false, bool mergeZaps = false);\n\tint LoadReference(\n\t\tconst std::string& fileName, const std::string& setName, const std::string& shapeName = \"\", bool mergeSliders = false, bool mergeZaps = false, bool appendNewSliders = true);\n\n\tint LoadFromSliderSet(const std::string& fileName, const std::string& setName, std::vector<std::string>* origShapeOrder = nullptr);\n\tint AddFromSliderSet(const std::string& fileName, const std::string& setName, const bool newDataLocal = true, const bool appendNewSliders = true);\n\n\tTargetDataDiffs* GetDiffSet(SliderData& silderData, nifly::NiShape* shape);\n\n\tvoid CollectVertexData(nifly::NiShape* shape, UndoStateShape& uss, const std::vector<uint16_t>& indices);\n\tvoid CollectTriangleData(nifly::NiShape* shape, UndoStateShape& uss, const std::vector<uint32_t>& indices);\n\tbool PrepareDeleteVerts(nifly::NiShape* shape, const std::unordered_map<uint16_t, float>& mask, UndoStateShape& uss);\n\tvoid ApplyShapeMeshUndo(nifly::NiShape* shape, std::vector<float>& mask, const UndoStateShape& uss, bool bUndo);\n\n\tbool PrepareCollapseVertex(nifly::NiShape* shape, UndoStateShape& uss, const std::vector<uint16_t>& indices);\n\tbool PrepareFlipEdge(nifly::NiShape* shape, UndoStateShape& uss, const nifly::Edge& edge);\n\tbool PrepareRefineMesh(nifly::NiShape* shape, UndoStateShape& uss, std::vector<bool>& pincs, const Mesh::WeldVertsType& weldVerts, const bool noCurveOffset, std::vector<nifly::Edge>* badEdges = nullptr);\n\n\tbool IsVertexOnBoundary(nifly::NiShape* shape, int vi);\n\tbool PointsHaveDifferingWeightsOrDiffs(nifly::NiShape* shape1, int p1, nifly::NiShape* shape2, int p2);\n\tvoid PrepareMergeVertex(nifly::NiShape* shape, UndoStateShape& uss, int selVert, int targVert);\n\tvoid PrepareWeldVertex(nifly::NiShape* shape, UndoStateShape& uss, int selVert, int targVert, nifly::NiShape* targShape);\n\n\tvoid CheckMerge(const std::string& sourceName, const std::string& targetName, MergeCheckErrors& e);\n\tvoid PrepareCopyGeo(nifly::NiShape* source, nifly::NiShape* target, UndoStateShape& uss);\n\n\tnifly::NiShape* DuplicateShape(nifly::NiShape* sourceShape, const std::string& destShapeName);\n\tvoid DeleteShape(nifly::NiShape* shape);\n\tvoid CaptureShapeDeleteState(nifly::NiShape* shape, UndoStateShapeDelete& state);\n\tnifly::NiShape* RestoreDeletedShape(UndoStateShapeDelete& state);\n\n\tvoid DeleteBone(const std::string& boneName) {\n\t\tif (workNif.IsValid()) {\n\t\t\tfor (auto& s : workNif.GetShapeNames())\n\t\t\t\tworkAnim.RemoveShapeBone(s, boneName);\n\n\t\t\tint blockID = workNif.GetBlockID(workNif.FindBlockByName<nifly::NiNode>(boneName));\n\t\t\tif (blockID >= 0)\n\t\t\t\tworkNif.GetHeader().DeleteBlock(blockID);\n\t\t}\n\t}\n\n\tvoid RenameShape(nifly::NiShape* shape, const std::string& newShapeName);\n\tvoid UpdateNifNormals(nifly::NifFile* nif, const std::vector<Mesh*>& shapemeshes);\n\n\tvoid MatchSymmetricVertices(nifly::NiShape* shape, const Mesh::WeldVertsType& weldVerts, SymmetricVertices& r);\n\tvoid MatchSymmetricBoneNames(std::vector<std::pair<std::string, std::string>>& pairs, std::vector<std::string>& singles);\n\tvoid FindVertexAsymmetries(nifly::NiShape* shape, const SymmetricVertices& symverts, const Mesh::WeldVertsType& weldVerts, VertexAsymmetries& r);\n\tvoid PrepareSymmetrizeVertices(nifly::NiShape* shape, UndoStateShape& uss, const SymmetricVertices& symverts, const VertexAsymmetries& asyms, const VertexAsymmetryTasks& tasks, const Mesh::WeldVertsType& weldVerts, const std::vector<bool>& selVerts, const std::vector<std::string>& userNormBones, const std::vector<std::string>& userNotNormBones);\n\tstd::vector<bool> CalculateAsymmetricTriangleVertexMask(nifly::NiShape* shape, const Mesh::WeldVertsType& weldVerts);\n\n\tvoid ChooseClothData(nifly::NifFile& nif);\n\tvoid ResetTransforms();\n\n\tvoid CreateSkinning(nifly::NiShape* s);\n\tvoid RemoveSkinning(nifly::NiShape* s);\n\tvoid RemoveSkinning();\n\n\tbool CheckForBadBones(bool interactive = true);\n\tbool ShapeHasBadBones(nifly::NiShape* s);\n\n\tvoid GetAllPoseTransforms(nifly::NiShape* s, std::vector<nifly::MatTransform>& ts);\n\tvoid ApplyTransformToOneVertexGeometry(UndoStateVertex& usv, const nifly::MatTransform& t);\n\tvoid ApplyPoseTransformsToShapeGeometry(nifly::NiShape* s, UndoStateShape& uss);\n\tvoid ApplyPoseTransformsToAllShapeGeometry(UndoStateProject& usp);\n\n\tint ImportNIF(const std::string& fileName, bool clear = true, const std::string& inOutfitName = \"\", std::map<std::string, std::string>* renamedShapes = nullptr);\n\tint ExportNIF(const std::string& fileName, const std::vector<Mesh*>& modMeshes, bool withRef = false, std::optional<bool> useInternalGeom = std::nullopt);\n\tint ExportShapeNIF(const std::string& fileName, const std::vector<std::string>& exportShapes, std::optional<bool> useInternalGeom = std::nullopt);\n\n\t// Force internal geometry (flag 0x200) on all BSGeometry shapes in a Starfield NIF.\n\tvoid ForceInternalGeometry(nifly::NifFile& nif);\n\n\t// Prompt the user to choose internal or external geometry for Starfield NIF export.\n\tvoid ConfigureInternalGeometry(nifly::NifFile& nif, const std::string& nifFileName, std::optional<bool> useInternalGeom = std::nullopt);\n\n\t// Save external .mesh files for Starfield BSGeometry shapes alongside the NIF.\n\tbool SaveExternalMeshes(nifly::NifFile& nif, const std::string& nifFileName);\n\n\tint ImportOBJ(const std::string& fileName, const std::string& shapeName = \"\", nifly::NiShape* mergeShape = nullptr);\n\tint ExportOBJ(const std::string& fileName,\n\t\t\t\t  const std::vector<nifly::NiShape*>& shapes,\n\t\t\t\t  bool transToGlobal,\n\t\t\t\t  const nifly::Vector3& scale = nifly::Vector3(1.0f, 1.0f, 1.0f),\n\t\t\t\t  const nifly::Vector3& offset = nifly::Vector3());\n\n#ifdef USE_FBXSDK\n\tint ImportFBX(const std::string& fileName, const std::string& shapeName = \"\", nifly::NiShape* mergeShape = nullptr);\n\tint ExportFBX(const std::string& fileName, const std::vector<nifly::NiShape*>& shapes, bool transToGlobal);\n#endif\n};\n"
  },
  {
    "path": "src/program/OutfitStudio.cpp",
    "content": "﻿/*\nBodySlide and Outfit Studio\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#include \"OutfitStudio.h\"\n#include \"../components/SliderGroup.h\"\n#include \"../components/SliderPresets.h\"\n#include \"../files/MaskFile.h\"\n#include \"../files/TriFile.h\"\n#include \"../files/SFMorphFile.h\"\n#include \"../ui/wxBrushSettingsPopup.h\"\n#include \"../utils/ConfigDialogUtil.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"EditUV.h\"\n#include \"GroupManager.h\"\n#include \"PresetSaveDialog.h\"\n#include \"ShapeProperties.h\"\n#include \"SliderDataImportDialog.h\"\n#include \"AutomationDialog.h\"\n#include \"../components/ClippingFixer.h\"\n\n#include <sstream>\n#include <wx/debugrpt.h>\n#include <wx/wfstream.h>\n#include <wx/zipstrm.h>\n\n#include \"ConvertBodyReferenceDialog.h\"\n\nusing namespace nifly;\n\n// IPC connection handler for Outfit Studio single-instance checking\nclass OutfitStudioIPCConnection : public wxConnection {\npublic:\n\tOutfitStudioIPCConnection() {}\n\n\tvirtual bool OnExec(const wxString& WXUNUSED(topic), const wxString& data) override {\n\t\t// data is expected to be newline-separated file paths\n\t\twxArrayString files;\n\t\twxStringTokenizer tokenizer(data, \"\\n\");\n\t\twhile (tokenizer.HasMoreTokens()) {\n\t\t\twxString token = tokenizer.GetNextToken().Trim();\n\t\t\tif (!token.IsEmpty())\n\t\t\t\tfiles.Add(token);\n\t\t}\n\n\t\tOutfitStudio* app = dynamic_cast<OutfitStudio*>(wxTheApp);\n\t\tif (!files.IsEmpty() && app && app->GetTopWindow()) {\n\t\t\tOutfitStudioFrame* frame = dynamic_cast<OutfitStudioFrame*>(app->GetTopWindow());\n\t\t\tif (frame) {\n\t\t\t\t// Use wxCallAfter to call OpenFiles on the main GUI thread\n\t\t\t\twxTheApp->CallAfter([frame, files]() {\n\t\t\t\t\tframe->LoadFiles(files);\n\t\t\t\t});\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n};\n\nclass OutfitStudioIPCServer : public wxServer {\npublic:\n\tvirtual wxConnectionBase* OnAcceptConnection(const wxString& WXUNUSED(topic)) override {\n\t\treturn new OutfitStudioIPCConnection();\n\t}\n};\n\n\n// ----------------------------------------------------------------------------\n// event tables and other macros for wxWidgets\n// ----------------------------------------------------------------------------\n\nwxBEGIN_EVENT_TABLE(OutfitStudioFrame, wxFrame)\n\tEVT_CLOSE(OutfitStudioFrame::OnClose)\n\tEVT_MENU(XRCID(\"fileExit\"), OutfitStudioFrame::OnExit)\n\n\tEVT_MENU(wxID_ANY, OutfitStudioFrame::OnMenuItem)\n\tEVT_MENU(XRCID(\"packProjects\"), OutfitStudioFrame::OnPackProjects)\n\tEVT_MENU(XRCID(\"fileSettings\"), OutfitStudioFrame::OnSettings)\n\tEVT_MENU(XRCID(\"btnNewProject\"), OutfitStudioFrame::OnNewProject)\n\tEVT_MENU(XRCID(\"btnLoadProject\"), OutfitStudioFrame::OnLoadProject)\n\tEVT_MENU(XRCID(\"btnAddProject\"), OutfitStudioFrame::OnAddProject)\n\tEVT_MENU(XRCID(\"fileLoadRef\"), OutfitStudioFrame::OnLoadReference)\n\tEVT_MENU(XRCID(\"fileConvBodyRef\"), OutfitStudioFrame::OnConvertBodyReference)\n\tEVT_MENU(XRCID(\"menuRunAutomation\"), OutfitStudioFrame::OnRunAutomation)\n\tEVT_MENU(XRCID(\"fileLoadOutfit\"), OutfitStudioFrame::OnLoadOutfit)\n\tEVT_MENU(XRCID(\"fileSave\"), OutfitStudioFrame::OnSaveSliderSet)\n\tEVT_MENU(XRCID(\"fileSaveAs\"), OutfitStudioFrame::OnSaveSliderSetAs)\n\tEVT_MENU(XRCID(\"fileUnload\"), OutfitStudioFrame::OnUnloadProject)\n\n\tEVT_COLLAPSIBLEPANE_CHANGED(XRCID(\"masksPane\"), OutfitStudioFrame::OnPaneCollapse)\n\tEVT_COMBOBOX(XRCID(\"cMaskName\"), OutfitStudioFrame::OnSelectMask)\n\tEVT_BUTTON(XRCID(\"saveMask\"), OutfitStudioFrame::OnSaveMask)\n\tEVT_BUTTON(XRCID(\"deleteMask\"), OutfitStudioFrame::OnDeleteMask)\n\tEVT_BUTTON(XRCID(\"exportMask\"), OutfitStudioFrame::OnExportMask)\n\tEVT_BUTTON(XRCID(\"importMask\"), OutfitStudioFrame::OnImportMask)\n\n\tEVT_COLLAPSIBLEPANE_CHANGED(XRCID(\"posePane\"), OutfitStudioFrame::OnPaneCollapse)\n\tEVT_COLLAPSIBLEPANE_CHANGED(XRCID(\"notesPane\"), OutfitStudioFrame::OnPaneCollapse)\n\tEVT_CHOICE(XRCID(\"cPoseBone\"), OutfitStudioFrame::OnPoseBoneChanged)\n\tEVT_COMMAND_SCROLL(XRCID(\"rxPoseSlider\"), OutfitStudioFrame::OnRXPoseSlider)\n\tEVT_COMMAND_SCROLL(XRCID(\"ryPoseSlider\"), OutfitStudioFrame::OnRYPoseSlider)\n\tEVT_COMMAND_SCROLL(XRCID(\"rzPoseSlider\"), OutfitStudioFrame::OnRZPoseSlider)\n\tEVT_COMMAND_SCROLL(XRCID(\"txPoseSlider\"), OutfitStudioFrame::OnTXPoseSlider)\n\tEVT_COMMAND_SCROLL(XRCID(\"tyPoseSlider\"), OutfitStudioFrame::OnTYPoseSlider)\n\tEVT_COMMAND_SCROLL(XRCID(\"tzPoseSlider\"), OutfitStudioFrame::OnTZPoseSlider)\n\tEVT_COMMAND_SCROLL(XRCID(\"scPoseSlider\"), OutfitStudioFrame::OnScPoseSlider)\n\tEVT_TEXT(XRCID(\"rxPoseText\"), OutfitStudioFrame::OnRXPoseTextChanged)\n\tEVT_TEXT(XRCID(\"ryPoseText\"), OutfitStudioFrame::OnRYPoseTextChanged)\n\tEVT_TEXT(XRCID(\"rzPoseText\"), OutfitStudioFrame::OnRZPoseTextChanged)\n\tEVT_TEXT(XRCID(\"txPoseText\"), OutfitStudioFrame::OnTXPoseTextChanged)\n\tEVT_TEXT(XRCID(\"tyPoseText\"), OutfitStudioFrame::OnTYPoseTextChanged)\n\tEVT_TEXT(XRCID(\"tzPoseText\"), OutfitStudioFrame::OnTZPoseTextChanged)\n\tEVT_TEXT(XRCID(\"scPoseText\"), OutfitStudioFrame::OnScPoseTextChanged)\n\tEVT_BUTTON(XRCID(\"resetBonePose\"), OutfitStudioFrame::OnResetBonePose)\n\tEVT_BUTTON(XRCID(\"resetAllPose\"), OutfitStudioFrame::OnResetAllPose)\n\tEVT_BUTTON(XRCID(\"poseToMesh\"), OutfitStudioFrame::OnPoseToMesh)\n\tEVT_CHECKBOX(XRCID(\"cbPose\"), OutfitStudioFrame::OnPoseCheckBox)\n\n\tEVT_COMBOBOX(XRCID(\"cPoseName\"), OutfitStudioFrame::OnSelectPose)\n\tEVT_BUTTON(XRCID(\"savePose\"), OutfitStudioFrame::OnSavePose)\n\tEVT_BUTTON(XRCID(\"deletePose\"), OutfitStudioFrame::OnDeletePose)\n\tEVT_BUTTON(XRCID(\"loadHkxPose\"), OutfitStudioFrame::OnLoadHkxPose)\n\n\tEVT_CHECKBOX(XRCID(\"selectSliders\"), OutfitStudioFrame::OnSelectSliders)\n\tEVT_TEXT_ENTER(XRCID(\"sliderFilter\"), OutfitStudioFrame::OnSliderFilterChanged)\n\tEVT_TEXT(XRCID(\"sliderFilter\"), OutfitStudioFrame::OnSliderFilterChanged)\n\tEVT_CHECKBOX(XRCID(\"cbFixedWeight\"), OutfitStudioFrame::OnFixedWeight)\n\tEVT_CHECKBOX(XRCID(\"cbNormalizeWeights\"), OutfitStudioFrame::OnCBNormalizeWeights)\n\n\tEVT_MENU(XRCID(\"saveBaseShape\"), OutfitStudioFrame::OnSetBaseShape)\n\tEVT_MENU(XRCID(\"makeConvRef\"), OutfitStudioFrame::OnMakeConvRef)\n\n\tEVT_MENU(XRCID(\"importNIF\"), OutfitStudioFrame::OnImportNIF)\n\tEVT_MENU(XRCID(\"exportNIF\"), OutfitStudioFrame::OnExportNIF)\n\tEVT_MENU(XRCID(\"exportNIFWithRef\"), OutfitStudioFrame::OnExportNIFWithRef)\n\tEVT_MENU(XRCID(\"exportShapeNIF\"), OutfitStudioFrame::OnExportShapeNIF)\n\n\tEVT_MENU(XRCID(\"importOBJ\"), OutfitStudioFrame::OnImportOBJ)\n\tEVT_MENU(XRCID(\"exportOBJ\"), OutfitStudioFrame::OnExportOBJ)\n\tEVT_MENU(XRCID(\"exportShapeOBJ\"), OutfitStudioFrame::OnExportShapeOBJ)\n\n\tEVT_MENU(XRCID(\"importFBX\"), OutfitStudioFrame::OnImportFBX)\n\tEVT_MENU(XRCID(\"exportFBX\"), OutfitStudioFrame::OnExportFBX)\n\tEVT_MENU(XRCID(\"exportShapeFBX\"), OutfitStudioFrame::OnExportShapeFBX)\n\n\tEVT_MENU(XRCID(\"importTRIHead\"), OutfitStudioFrame::OnImportTRIHead)\n\tEVT_MENU(XRCID(\"exportTRIHead\"), OutfitStudioFrame::OnExportTRIHead)\n\tEVT_MENU(XRCID(\"exportShapeTRIHead\"), OutfitStudioFrame::OnExportShapeTRIHead)\n\n\tEVT_MENU(XRCID(\"importPhysicsData\"), OutfitStudioFrame::OnImportPhysicsData)\n\tEVT_MENU(XRCID(\"exportPhysicsData\"), OutfitStudioFrame::OnExportPhysicsData)\n\n\tEVT_MENU(XRCID(\"sliderLoadPreset\"), OutfitStudioFrame::OnLoadPreset)\n\tEVT_MENU(XRCID(\"sliderSavePreset\"), OutfitStudioFrame::OnSavePreset)\n\tEVT_MENU(XRCID(\"sliderConform\"), OutfitStudioFrame::OnSliderConform)\n\tEVT_MENU(XRCID(\"sliderConformAll\"), OutfitStudioFrame::OnSliderConformAll)\n\tEVT_MENU(XRCID(\"sliderFixClipping\"), OutfitStudioFrame::OnSliderFixClipping)\n\tEVT_MENU(XRCID(\"sliderImportNIF\"), OutfitStudioFrame::OnSliderImportNIF)\n\tEVT_MENU(XRCID(\"sliderImportBSD\"), OutfitStudioFrame::OnSliderImportBSD)\n\tEVT_MENU(XRCID(\"sliderImportOBJ\"), OutfitStudioFrame::OnSliderImportOBJ)\n\tEVT_MENU(XRCID(\"sliderImportFBX\"), OutfitStudioFrame::OnSliderImportFBX)\n\tEVT_MENU(XRCID(\"sliderImportOSD\"), OutfitStudioFrame::OnSliderImportOSD)\n\tEVT_MENU(XRCID(\"sliderImportTRI\"), OutfitStudioFrame::OnSliderImportTRI)\n\tEVT_MENU(XRCID(\"sliderImportMorphsSF\"), OutfitStudioFrame::OnSliderImportMorphsSF)\n\tEVT_MENU(XRCID(\"sliderExportNIF\"), OutfitStudioFrame::OnSliderExportNIF)\n\tEVT_MENU(XRCID(\"sliderExportBSD\"), OutfitStudioFrame::OnSliderExportBSD)\n\tEVT_MENU(XRCID(\"sliderExportOBJ\"), OutfitStudioFrame::OnSliderExportOBJ)\n\tEVT_MENU(XRCID(\"sliderExportOSD\"), OutfitStudioFrame::OnSliderExportOSD)\n\tEVT_MENU(XRCID(\"sliderExportTRI\"), OutfitStudioFrame::OnSliderExportTRI)\n\tEVT_MENU(XRCID(\"sliderExportMorphsSF\"), OutfitStudioFrame::OnSliderExportMorphsSF)\n\tEVT_MENU(XRCID(\"sliderExportToOBJs\"), OutfitStudioFrame::OnSliderExportToOBJs)\n\tEVT_MENU(XRCID(\"sliderNew\"), OutfitStudioFrame::OnNewSlider)\n\tEVT_MENU(XRCID(\"sliderNewZap\"), OutfitStudioFrame::OnNewZapSlider)\n\tEVT_MENU(XRCID(\"sliderNewCombined\"), OutfitStudioFrame::OnNewCombinedSlider)\n\tEVT_MENU(XRCID(\"sliderClone\"), OutfitStudioFrame::OnSliderClone)\n\tEVT_MENU(XRCID(\"sliderNegate\"), OutfitStudioFrame::OnSliderNegate)\n\tEVT_MENU(XRCID(\"sliderMask\"), OutfitStudioFrame::OnMaskAffected)\n\tEVT_MENU(XRCID(\"sliderClear\"), OutfitStudioFrame::OnClearSlider)\n\tEVT_MENU(XRCID(\"sliderDelete\"), OutfitStudioFrame::OnDeleteSlider)\n\tEVT_MENU(XRCID(\"sliderProperties\"), OutfitStudioFrame::OnSliderProperties)\n\n\tEVT_MENU(XRCID(\"btnXMirror\"), OutfitStudioFrame::OnXMirror)\n\tEVT_MENU(XRCID(\"btnConnected\"), OutfitStudioFrame::OnConnectedOnly)\n\tEVT_MENU(XRCID(\"btnMerge\"), OutfitStudioFrame::OnToolOptionMerge)\n\tEVT_MENU(XRCID(\"btnWeld\"), OutfitStudioFrame::OnToolOptionWeld)\n\tEVT_MENU(XRCID(\"btnRestrictSurface\"), OutfitStudioFrame::OnToolOptionRestrictSurface)\n\tEVT_MENU(XRCID(\"btnRestrictPlane\"), OutfitStudioFrame::OnToolOptionRestrictPlane)\n\tEVT_MENU(XRCID(\"btnRestrictNormal\"), OutfitStudioFrame::OnToolOptionRestrictNormal)\n\n\tEVT_MENU(XRCID(\"btnSelect\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnTransform\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnPivot\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnVertexEdit\"), OutfitStudioFrame::OnSelectTool)\n\n\tEVT_MENU(XRCID(\"btnMaskBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnInflateBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnDeflateBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnMoveBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnSmoothBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnUndiffBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnWeightBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnColorBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnAlphaBrush\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnCollapseVertex\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnFlipEdgeTool\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnSplitEdgeTool\"), OutfitStudioFrame::OnSelectTool)\n\tEVT_MENU(XRCID(\"btnMoveVertexTool\"), OutfitStudioFrame::OnSelectTool)\n\n\tEVT_MENU(XRCID(\"btnViewFront\"), OutfitStudioFrame::OnSetView)\n\tEVT_MENU(XRCID(\"btnViewBack\"), OutfitStudioFrame::OnSetView)\n\tEVT_MENU(XRCID(\"btnViewLeft\"), OutfitStudioFrame::OnSetView)\n\tEVT_MENU(XRCID(\"btnViewRight\"), OutfitStudioFrame::OnSetView)\n\tEVT_MENU(XRCID(\"btnViewPerspective\"), OutfitStudioFrame::OnTogglePerspective)\n\tEVT_MENU(XRCID(\"btnToggleRotationCenter\"), OutfitStudioFrame::OnToggleRotationCenter)\n\tEVT_MENU(XRCID(\"btnFrameSelected\"), OutfitStudioFrame::OnFrameSelected)\n\n\tEVT_MENU(XRCID(\"btnShowNodes\"), OutfitStudioFrame::OnShowNodes)\n\tEVT_MENU(XRCID(\"btnShowBones\"), OutfitStudioFrame::OnShowBones)\n\tEVT_MENU(XRCID(\"btnShowFloor\"), OutfitStudioFrame::OnShowFloor)\n\n\tEVT_MENU(XRCID(\"btnIncreaseSize\"), OutfitStudioFrame::OnIncBrush)\n\tEVT_MENU(XRCID(\"btnDecreaseSize\"), OutfitStudioFrame::OnDecBrush)\n\tEVT_MENU(XRCID(\"btnIncreaseStr\"), OutfitStudioFrame::OnIncStr)\n\tEVT_MENU(XRCID(\"btnDecreaseStr\"), OutfitStudioFrame::OnDecStr)\n\tEVT_MENU(XRCID(\"btnMaskLess\"), OutfitStudioFrame::OnMaskLess)\n\tEVT_MENU(XRCID(\"btnMaskMore\"), OutfitStudioFrame::OnMaskMore)\n\tEVT_MENU(XRCID(\"btnClearMask\"), OutfitStudioFrame::OnClearMask)\n\tEVT_MENU(XRCID(\"btnInvertMask\"), OutfitStudioFrame::OnInvertMask)\n\n\tEVT_MENU(XRCID(\"btnRecalcNormals\"), OutfitStudioFrame::OnRecalcNormals)\n\tEVT_MENU(XRCID(\"disableNormalsCalc\"), OutfitStudioFrame::OnDisableNormalsCalc)\n\tEVT_MENU(XRCID(\"btnSmoothSeams\"), OutfitStudioFrame::OnSmoothNormalSeams)\n\tEVT_MENU(XRCID(\"btnSmoothSeamsAngle\"), OutfitStudioFrame::OnSmoothSeamsAngle)\n\tEVT_MENU(XRCID(\"btnLockNormals\"), OutfitStudioFrame::OnLockNormals)\n\n\tEVT_MENU(XRCID(\"btnToggleVisibility\"), OutfitStudioFrame::OnToggleVisibility)\n\tEVT_MENU(XRCID(\"btnShowWireframe\"), OutfitStudioFrame::OnShowWireframe)\n\tEVT_MENU(XRCID(\"btnEnableLighting\"), OutfitStudioFrame::OnEnableLighting)\n\tEVT_MENU(XRCID(\"btnEnableTextures\"), OutfitStudioFrame::OnEnableTextures)\n\tEVT_MENU(XRCID(\"btnEnableVertexColors\"), OutfitStudioFrame::OnEnableVertexColors)\n\n\tEVT_MENU(XRCID(\"uvEdit\"), OutfitStudioFrame::OnEditUV)\n\tEVT_MENU(XRCID(\"uvInvertX\"), OutfitStudioFrame::OnInvertUV)\n\tEVT_MENU(XRCID(\"uvInvertY\"), OutfitStudioFrame::OnInvertUV)\n\tEVT_MENU(XRCID(\"mirrorShape\"), OutfitStudioFrame::OnMirrorShape)\n\n\tEVT_MENU(XRCID(\"moveShape\"), OutfitStudioFrame::OnMoveShape)\n\tEVT_MENU(XRCID(\"scaleShape\"), OutfitStudioFrame::OnScaleShape)\n\tEVT_MENU(XRCID(\"rotateShape\"), OutfitStudioFrame::OnRotateShape)\n\tEVT_MENU(XRCID(\"inflateShape\"), OutfitStudioFrame::OnInflateShape)\n\tEVT_MENU(XRCID(\"fixClippingShape\"), OutfitStudioFrame::OnFixClippingShape)\n\tEVT_MENU(XRCID(\"renameShape\"), OutfitStudioFrame::OnRenameShape)\n\tEVT_MENU(XRCID(\"setReference\"), OutfitStudioFrame::OnSetReference)\n\tEVT_MENU(XRCID(\"deleteVerts\"), OutfitStudioFrame::OnDeleteVerts)\n\tEVT_MENU(XRCID(\"separateVerts\"), OutfitStudioFrame::OnSeparateVerts)\n\tEVT_MENU(XRCID(\"copyGeo\"), OutfitStudioFrame::OnCopyGeo)\n\tEVT_MENU(XRCID(\"copyShape\"), OutfitStudioFrame::OnDupeShape)\n\tEVT_MENU(XRCID(\"refineMesh\"), OutfitStudioFrame::OnRefineMesh)\n\tEVT_MENU(XRCID(\"deleteShape\"), OutfitStudioFrame::OnDeleteShape)\n\tEVT_MENU(XRCID(\"setBoneSkin\"), OutfitStudioFrame::OnSetBoneSkin)\n\tEVT_MENU(XRCID(\"setBoneNode\"), OutfitStudioFrame::OnSetBoneNode)\n\tEVT_MENU(XRCID(\"addBone\"), OutfitStudioFrame::OnAddBone)\n\tEVT_MENU(XRCID(\"addCustomBone\"), OutfitStudioFrame::OnAddCustomBone)\n\tEVT_MENU(XRCID(\"deleteBone\"), OutfitStudioFrame::OnDeleteBone)\n\tEVT_MENU(XRCID(\"deleteBoneSelected\"), OutfitStudioFrame::OnDeleteBoneFromSelected)\n\tEVT_MENU(XRCID(\"editBone\"), OutfitStudioFrame::OnEditBone)\n\tEVT_MENU(XRCID(\"copyBoneWeight\"), OutfitStudioFrame::OnCopyBoneWeight)\n\tEVT_MENU(XRCID(\"transferSelectedWeight\"), OutfitStudioFrame::OnTransferSelectedWeight)\n\tEVT_MENU(XRCID(\"maskWeightedVerts\"), OutfitStudioFrame::OnMaskWeighted)\n\tEVT_MENU(XRCID(\"checkBadBones\"), OutfitStudioFrame::OnCheckBadBones)\n\tEVT_MENU(XRCID(\"maskBoneWeightedVerts\"), OutfitStudioFrame::OnMaskBoneWeighted)\n\tEVT_MENU(XRCID(\"copySegPart\"), OutfitStudioFrame::OnCopySegPart)\n\tEVT_MENU(XRCID(\"maskSymVert\"), OutfitStudioFrame::OnMaskSymVert)\n\tEVT_MENU(XRCID(\"symVert\"), OutfitStudioFrame::OnSymVert)\n\tEVT_MENU(XRCID(\"maskSymTri\"), OutfitStudioFrame::OnMaskSymTri)\n\tEVT_MENU(XRCID(\"resetTransforms\"), OutfitStudioFrame::OnResetTransforms)\n\tEVT_MENU(XRCID(\"deleteUnreferencedNodes\"), OutfitStudioFrame::OnDeleteUnreferencedNodes)\n\tEVT_MENU(XRCID(\"removeSkinning\"), OutfitStudioFrame::OnRemoveSkinning)\n\tEVT_MENU(XRCID(\"shapeProperties\"), OutfitStudioFrame::OnShapeProperties)\n\n\tEVT_MENU(XRCID(\"editUndo\"), OutfitStudioFrame::OnUndo)\n\tEVT_MENU(XRCID(\"editRedo\"), OutfitStudioFrame::OnRedo)\n\n\tEVT_TREE_STATE_IMAGE_CLICK(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnShapeVisToggle)\n\tEVT_TREE_SEL_CHANGING(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnCheckTreeSel)\n\tEVT_TREE_SEL_CHANGED(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnShapeSelect)\n\tEVT_TREE_ITEM_ACTIVATED(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnShapeActivated)\n\tEVT_TREE_ITEM_RIGHT_CLICK(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnShapeContext)\n\tEVT_TREE_BEGIN_DRAG(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnShapeDrag)\n\tEVT_TREE_END_DRAG(XRCID(\"outfitShapes\"), OutfitStudioFrame::OnShapeDrop)\n\n\tEVT_TEXT_ENTER(XRCID(\"bonesFilter\"), OutfitStudioFrame::OnBonesFilterChanged)\n\tEVT_TEXT(XRCID(\"bonesFilter\"), OutfitStudioFrame::OnBonesFilterChanged)\n\tEVT_TREE_STATE_IMAGE_CLICK(XRCID(\"outfitBones\"), OutfitStudioFrame::OnBoneStateToggle)\n\tEVT_TREE_SEL_CHANGED(XRCID(\"outfitBones\"), OutfitStudioFrame::OnBoneSelect)\n\tEVT_TREE_ITEM_ACTIVATED(XRCID(\"outfitBones\"), OutfitStudioFrame::OnBoneActivated)\n\tEVT_TREE_ITEM_RIGHT_CLICK(XRCID(\"outfitBones\"), OutfitStudioFrame::OnBoneContext)\n\tEVT_COMMAND_RIGHT_CLICK(XRCID(\"outfitBones\"), OutfitStudioFrame::OnBoneTreeContext)\n\n\tEVT_TREE_SEL_CHANGED(XRCID(\"segmentTree\"), OutfitStudioFrame::OnSegmentSelect)\n\tEVT_TREE_ITEM_RIGHT_CLICK(XRCID(\"segmentTree\"), OutfitStudioFrame::OnSegmentContext)\n\tEVT_COMMAND_RIGHT_CLICK(XRCID(\"segmentTree\"), OutfitStudioFrame::OnSegmentTreeContext)\n\tEVT_MENU(XRCID(\"addSegment\"), OutfitStudioFrame::OnAddSegment)\n\tEVT_MENU(XRCID(\"addSubSegment\"), OutfitStudioFrame::OnAddSubSegment)\n\tEVT_MENU(XRCID(\"deleteSegment\"), OutfitStudioFrame::OnDeleteSegment)\n\tEVT_MENU(XRCID(\"deleteSubSegment\"), OutfitStudioFrame::OnDeleteSubSegment)\n\tEVT_CHOICE(XRCID(\"segmentSlot\"), OutfitStudioFrame::OnSegmentSlotChanged)\n\tEVT_CHOICE(XRCID(\"segmentType\"), OutfitStudioFrame::OnSegmentTypeChanged)\n\tEVT_BUTTON(XRCID(\"segmentApply\"), OutfitStudioFrame::OnSegmentApply)\n\tEVT_BUTTON(XRCID(\"segmentReset\"), OutfitStudioFrame::OnSegmentReset)\n\tEVT_BUTTON(XRCID(\"segmentSSFEdit\"), OutfitStudioFrame::OnSegmentEditSSF)\n\n\tEVT_TREE_SEL_CHANGED(XRCID(\"partitionTree\"), OutfitStudioFrame::OnPartitionSelect)\n\tEVT_TREE_ITEM_RIGHT_CLICK(XRCID(\"partitionTree\"), OutfitStudioFrame::OnPartitionContext)\n\tEVT_COMMAND_RIGHT_CLICK(XRCID(\"partitionTree\"), OutfitStudioFrame::OnPartitionTreeContext)\n\tEVT_MENU(XRCID(\"addPartition\"), OutfitStudioFrame::OnAddPartition)\n\tEVT_MENU(XRCID(\"deletePartition\"), OutfitStudioFrame::OnDeletePartition)\n\tEVT_CHOICE(XRCID(\"partitionType\"), OutfitStudioFrame::OnPartitionTypeChanged)\n\tEVT_BUTTON(XRCID(\"partitionApply\"), OutfitStudioFrame::OnPartitionApply)\n\tEVT_BUTTON(XRCID(\"partitionReset\"), OutfitStudioFrame::OnPartitionReset)\n\n\tEVT_BUTTON(XRCID(\"meshTabButton\"), OutfitStudioFrame::OnTabButtonClick)\n\tEVT_BUTTON(XRCID(\"boneTabButton\"), OutfitStudioFrame::OnTabButtonClick)\n\tEVT_BUTTON(XRCID(\"segmentTabButton\"), OutfitStudioFrame::OnTabButtonClick)\n\tEVT_BUTTON(XRCID(\"partitionTabButton\"), OutfitStudioFrame::OnTabButtonClick)\n\tEVT_BUTTON(XRCID(\"colorsTabButton\"), OutfitStudioFrame::OnTabButtonClick)\n\tEVT_BUTTON(XRCID(\"lightsTabButton\"), OutfitStudioFrame::OnTabButtonClick)\n\n\tEVT_COLOURPICKER_CHANGED(XRCID(\"cpBrushColor\"), OutfitStudioFrame::OnBrushColorChanged)\n\tEVT_SLIDER(XRCID(\"cpClampMaxValueSlider\"), OutfitStudioFrame::OnColorClampMaxValueSlider)\n\tEVT_TEXT_ENTER(XRCID(\"cpClampMaxValueTxt\"), OutfitStudioFrame::OnColorClampMaxValueChanged)\n\tEVT_TEXT(XRCID(\"cpClampMaxValueTxt\"), OutfitStudioFrame::OnColorClampMaxValueChanged)\n\tEVT_BUTTON(XRCID(\"btnSwapBrush\"), OutfitStudioFrame::OnSwapBrush)\n\tEVT_BUTTON(XRCID(\"btnMaskVertexColor\"), OutfitStudioFrame::OnMaskVertexColor)\n\n\tEVT_SLIDER(XRCID(\"lightAmbientSlider\"), OutfitStudioFrame::OnUpdateLights)\n\tEVT_SLIDER(XRCID(\"lightFrontalSlider\"), OutfitStudioFrame::OnUpdateLights)\n\tEVT_SLIDER(XRCID(\"lightDirectional0Slider\"), OutfitStudioFrame::OnUpdateLights)\n\tEVT_SLIDER(XRCID(\"lightDirectional1Slider\"), OutfitStudioFrame::OnUpdateLights)\n\tEVT_SLIDER(XRCID(\"lightDirectional2Slider\"), OutfitStudioFrame::OnUpdateLights)\n\tEVT_BUTTON(XRCID(\"lightReset\"), OutfitStudioFrame::OnResetLights)\n\n\tEVT_MENU(XRCID(\"btnDiscord\"), OutfitStudioFrame::OnDiscord)\n\tEVT_MENU(XRCID(\"btnGitHub\"), OutfitStudioFrame::OnGitHub)\n\tEVT_MENU(XRCID(\"btnPayPal\"), OutfitStudioFrame::OnPayPal)\n\n\tEVT_SPLITTER_SASH_POS_CHANGED(XRCID(\"splitter\"), OutfitStudioFrame::OnSashPosChanged)\n\tEVT_SPLITTER_SASH_POS_CHANGED(XRCID(\"splitterRight\"), OutfitStudioFrame::OnSashPosChanged)\n\tEVT_MOVE_START(OutfitStudioFrame::OnMoveWindowStart)\n\tEVT_MOVE_END(OutfitStudioFrame::OnMoveWindowEnd)\n\tEVT_SIZE(OutfitStudioFrame::OnSetSize)\nwxEND_EVENT_TABLE()\n\nwxIMPLEMENT_APP(OutfitStudio);\n\n\nConfigurationManager Config;\nConfigurationManager OutfitStudioConfig;\n\nconst std::array<wxString, 10> TargetGames = {\"Fallout3\", \"FalloutNewVegas\", \"Skyrim\", \"Fallout4\", \"SkyrimSpecialEdition\", \"Fallout4VR\", \"SkyrimVR\", \"Fallout76\", \"Oblivion\", \"Starfield\"};\nconst std::array<wxLanguage, 37> SupportedLangs = {wxLANGUAGE_ENGLISH,\t  wxLANGUAGE_AFRIKAANS,\t\t   wxLANGUAGE_ARABIC,  wxLANGUAGE_CATALAN,\t  wxLANGUAGE_CZECH,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_DANISH,\t  wxLANGUAGE_GERMAN,\t\t   wxLANGUAGE_GREEK,   wxLANGUAGE_SPANISH,\t  wxLANGUAGE_BASQUE,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_FINNISH,\t  wxLANGUAGE_FRENCH,\t\t   wxLANGUAGE_HINDI,   wxLANGUAGE_HUNGARIAN,  wxLANGUAGE_INDONESIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_ITALIAN,\t  wxLANGUAGE_JAPANESE,\t\t   wxLANGUAGE_KOREAN,  wxLANGUAGE_LITHUANIAN, wxLANGUAGE_LATVIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_MALAY,\t  wxLANGUAGE_NORWEGIAN_BOKMAL, wxLANGUAGE_NEPALI,  wxLANGUAGE_DUTCH,\t  wxLANGUAGE_POLISH,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_PORTUGUESE, wxLANGUAGE_ROMANIAN,\t\t   wxLANGUAGE_RUSSIAN, wxLANGUAGE_SLOVAK,\t  wxLANGUAGE_SLOVENIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_ALBANIAN,\t  wxLANGUAGE_SWEDISH,\t\t   wxLANGUAGE_TAMIL,   wxLANGUAGE_TURKISH,\t  wxLANGUAGE_UKRAINIAN,\n\t\t\t\t\t\t\t\t\t\t\t\t   wxLANGUAGE_VIETNAMESE, wxLANGUAGE_CHINESE};\n\nstd::string GetProjectPath() {\n\tstd::string res = Config[\"ProjectPath\"];\n\treturn res.empty() ? Config[\"AppDir\"] : res;\n}\n\n// Load files into the current project\nvoid OutfitStudioFrame::LoadFiles(const wxArrayString& files, const wxString& projectName) {\n\tfor (auto& f : files) {\n\t\twxFileName loadFile(f);\n\t\tif (loadFile.FileExists()) {\n\t\t\tstd::string fileName{loadFile.GetFullPath().ToUTF8()};\n\t\t\twxString fileExt = loadFile.GetExt().MakeLower();\n\t\t\tif (fileExt == \"osp\") {\n\t\t\t\tstd::string loadProjectName{projectName.ToUTF8()};\n\t\t\t\tLoadProject(fileName, loadProjectName);\n\t\t\t\t// only open first project file\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse if (fileExt == \"nif\") {\n\t\t\t\tStartProgress(_(\"Adding NIF file...\"));\n\t\t\t\tUpdateProgress(1, _(\"Adding NIF file...\"));\n\t\t\t\tproject->ImportNIF(fileName, false);\n\t\t\t\tproject->SetTextures();\n\n\t\t\t\tUpdateProgress(60, _(\"Refreshing GUI...\"));\n\t\t\t\tRefreshGUIFromProj();\n\n\t\t\t\tEndProgress();\n\t\t\t}\n\t\t\telse if (fileExt == \"obj\") {\n\t\t\t\tStartProgress(\"Adding OBJ file...\");\n\t\t\t\tUpdateProgress(1, _(\"Adding OBJ file...\"));\n\t\t\t\tproject->ImportOBJ(fileName);\n\t\t\t\tproject->SetTextures();\n\n\t\t\t\tUpdateProgress(60, _(\"Refreshing GUI...\"));\n\t\t\t\tRefreshGUIFromProj();\n\n\t\t\t\tEndProgress();\n\t\t\t}\n\t\t\telse if (fileExt == \"fbx\") {\n#ifdef USE_FBXSDK\n\t\t\t\tStartProgress(_(\"Adding FBX file...\"));\n\t\t\t\tUpdateProgress(1, _(\"Adding FBX file...\"));\n\t\t\t\tproject->ImportFBX(fileName);\n\t\t\t\tproject->SetTextures();\n\n\t\t\t\tUpdateProgress(60, _(\"Refreshing GUI...\"));\n\t\t\t\tRefreshGUIFromProj();\n\n\t\t\t\tEndProgress();\n#endif\n\t\t\t}\n\t\t}\n\t}\n}\n\nOutfitStudio::~OutfitStudio() {\n\tif (ipcServer) {\n\t\tdelete ipcServer;\n\t\tipcServer = nullptr;\n\t}\n\n\tif (singleChecker) {\n\t\tdelete singleChecker;\n\t\tsingleChecker = nullptr;\n\t}\n\n\tif (locale) {\n\t\tdelete locale;\n\t\tlocale = nullptr;\n\t}\n\n\tFSManager::del();\n}\n\nbool OutfitStudio::OnInit() {\n\tif (!wxApp::OnInit())\n\t\treturn false;\n\n#ifdef _DEBUG\n\tstd::string dataDir{wxGetCwd().ToUTF8()};\n#else\n\tstd::string dataDir{wxStandardPaths::Get().GetDataDir().ToUTF8()};\n#endif\n\n\tConfig.LoadConfig(dataDir + \"/Config.xml\");\n\tOutfitStudioConfig.LoadConfig(dataDir + \"/OutfitStudio.xml\", \"OutfitStudioConfig\");\n\n\tConfig.SetDefaultValue(\"AppDir\", dataDir);\n\n\tlogger.Initialize(Config.GetIntValue(\"LogLevel\", -1), dataDir + \"/Log_OS.txt\");\n\twxLogMessage(\"Initializing Outfit Studio...\");\n\n#ifdef NDEBUG\n\twxHandleFatalExceptions();\n#endif\n\n\twxString appDirUri = wxString::FromUTF8(dataDir);\n\tappDirUri.Replace(\"#\", \"%23\");\n\twxSetEnv(\"AppDir\", appDirUri);\n\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->SetFlags(wxXRC_USE_LOCALE | wxXRC_USE_ENVVARS);\n\txrc->InitAllHandlers();\n\twxInitAllImageHandlers();\n\n\twxLogMessage(\"Working directory: %s\", wxGetCwd());\n\twxLogMessage(\"Executable directory: %s\", wxString::FromUTF8(dataDir));\n\tif (!SetDefaultConfig())\n\t\treturn false;\n\n\tInitLanguage();\n\n\twxString gameName = \"Target game: \";\n\tswitch (targetGame) {\n\t\tcase FO3: gameName.Append(\"Fallout 3\"); break;\n\t\tcase FONV: gameName.Append(\"Fallout New Vegas\"); break;\n\t\tcase SKYRIM: gameName.Append(\"Skyrim\"); break;\n\t\tcase FO4: gameName.Append(\"Fallout 4\"); break;\n\t\tcase SKYRIMSE: gameName.Append(\"Skyrim Special Edition\"); break;\n\t\tcase FO4VR: gameName.Append(\"Fallout 4 VR\"); break;\n\t\tcase SKYRIMVR: gameName.Append(\"Skyrim VR\"); break;\n\t\tcase FO76: gameName.Append(\"Fallout 76\"); break;\n\t\tcase OB: gameName.Append(\"Oblivion\"); break;\n\t\tcase SF: gameName.Append(\"Starfield\"); break;\n\t\tdefault: gameName.Append(\"Invalid\");\n\t}\n\twxLogMessage(gameName);\n\n\tint x = OutfitStudioConfig.GetIntValue(\"OutfitStudioFrame.x\");\n\tint y = OutfitStudioConfig.GetIntValue(\"OutfitStudioFrame.y\");\n\tint w = OutfitStudioConfig.GetIntValue(\"OutfitStudioFrame.width\");\n\tint h = OutfitStudioConfig.GetIntValue(\"OutfitStudioFrame.height\");\n\tstd::string maximized = OutfitStudioConfig[\"OutfitStudioFrame.maximized\"];\n\n\t// create single instance checker\n\tsingleChecker = new wxSingleInstanceChecker(wxString(\"OutfitStudioInstance\"));\n\n\t// If files were passed on the command line, try single-instance IPC via wxWidgets\n\tif (!cmdFiles.IsEmpty()) {\n\t\tif (singleChecker->IsAnotherRunning()) {\n\t\t\tint behavior = OutfitStudioConfig.GetIntValue(\"SingleInstanceBehavior\", 0);\n\n\t\t\t// Override behavior with command line argument if provided\n\t\t\tif (cmdForceSingleInstanceBehavior >= 0) {\n\t\t\t\t// cmdForceSingleInstanceBehavior: 0 = force new, 1 = force existing\n\t\t\t\tbehavior = cmdForceSingleInstanceBehavior == 1 ? 1 : 2;  // 1 = Open in Existing, 2 = Open in New\n\t\t\t}\n\n\t\t\t// 0 = Ask (Message Box), 1 = Open in Existing, 2 = Open in New\n\t\t\tint answer = wxYES;\n\t\t\tif (behavior == 0) {\n\t\t\t\twxDialog dlg(nullptr, wxID_ANY, _(\"Open in existing instance?\"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE);\n\t\t\t\twxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);\n\n\t\t\t\twxBoxSizer* msgSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\t\tmsgSizer->Add(new wxStaticBitmap(&dlg, wxID_ANY, wxArtProvider::GetBitmap(wxART_QUESTION, wxART_MESSAGE_BOX)), 0, wxALL | wxALIGN_CENTER_VERTICAL, 10);\n\t\t\t\tmsgSizer->Add(new wxStaticText(&dlg, wxID_ANY, _(\"An instance of Outfit Studio is already running. Open file(s) in the existing instance?\")), 1, wxALL | wxALIGN_CENTER_VERTICAL, 10);\n\t\t\t\tmainSizer->Add(msgSizer, 1, wxEXPAND);\n\n\t\t\t\twxBoxSizer* btnSizer = new wxBoxSizer(wxHORIZONTAL);\n\t\t\t\twxButton* btnYes = new wxButton(&dlg, wxID_YES, _(\"Yes\"));\n\t\t\t\twxButton* btnYesAlways = new wxButton(&dlg, wxID_YES + 100, _(\"Yes (always)\"));\n\t\t\t\twxButton* btnNo = new wxButton(&dlg, wxID_NO, _(\"No\"));\n\t\t\t\twxButton* btnNoNever = new wxButton(&dlg, wxID_NO + 100, _(\"No (never)\"));\n\t\t\t\tbtnSizer->Add(btnYes, 0, wxALL, 5);\n\t\t\t\tbtnSizer->Add(btnYesAlways, 0, wxALL, 5);\n\t\t\t\tbtnSizer->Add(btnNo, 0, wxALL, 5);\n\t\t\t\tbtnSizer->Add(btnNoNever, 0, wxALL, 5);\n\t\t\t\tmainSizer->Add(btnSizer, 0, wxALIGN_CENTER | wxBOTTOM, 5);\n\n\t\t\t\tbtnYes->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { dlg.EndModal(wxID_YES); });\n\t\t\t\tbtnYesAlways->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { dlg.EndModal(wxID_YES + 100); });\n\t\t\t\tbtnNo->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { dlg.EndModal(wxID_NO); });\n\t\t\t\tbtnNoNever->Bind(wxEVT_BUTTON, [&](wxCommandEvent&) { dlg.EndModal(wxID_NO + 100); });\n\n\t\t\t\tdlg.SetSizerAndFit(mainSizer);\n\t\t\t\tdlg.CenterOnScreen();\n\n\t\t\t\tint result = dlg.ShowModal();\n\t\t\t\tif (result == wxID_YES || result == wxID_YES + 100) {\n\t\t\t\t\tanswer = wxYES;\n\t\t\t\t\tif (result == wxID_YES + 100) {\n\t\t\t\t\t\tOutfitStudioConfig.SetValue(\"SingleInstanceBehavior\", 1);\n\t\t\t\t\t\tOutfitStudioConfig.SaveConfig(Config[\"AppDir\"] + \"/OutfitStudio.xml\", \"OutfitStudioConfig\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tanswer = wxNO;\n\t\t\t\t\tif (result == wxID_NO + 100) {\n\t\t\t\t\t\tOutfitStudioConfig.SetValue(\"SingleInstanceBehavior\", 2);\n\t\t\t\t\t\tOutfitStudioConfig.SaveConfig(Config[\"AppDir\"] + \"/OutfitStudio.xml\", \"OutfitStudioConfig\");\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (behavior == 1) {\n\t\t\t\tanswer = wxYES;  // Open in existing\n\t\t\t}\n\t\t\telse if (behavior == 2) {\n\t\t\t\tanswer = wxNO;   // Open in new\n\t\t\t}\n\n\t\t\tif (answer == wxYES) {\n\t\t\t\t// Build newline-separated list\n\t\t\t\twxString concat;\n\t\t\t\tfor (size_t i = 0; i < cmdFiles.GetCount(); ++i) {\n\t\t\t\t\tif (i)\n\t\t\t\t\t\tconcat.Append(\"\\n\");\n\t\t\t\t\tconcat.Append(cmdFiles[i]);\n\t\t\t\t}\n\n\t\t\t\twxClient client;\n\t\t\t\t// Try to connect to the server\n\t\t\t\twxConnectionBase* conn = client.MakeConnection(\"localhost\", OS_IPC_SERVICE, OS_IPC_SERVICE);\n\t\t\t\tif (conn) {\n\t\t\t\t\tconn->Execute(concat);\n\t\t\t\t\tconn->Disconnect();\n\t\t\t\t}\n\n\t\t\t\t// exit this new instance\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\t// we'll be the server; create it after frame is created\n\t\t}\n\t}\n\n\tframe = new OutfitStudioFrame(wxPoint(x, y), wxSize(w, h));\n\tif (maximized == \"true\")\n\t\tframe->Maximize();\n\n\tframe->Show();\n\tSetTopWindow(frame);\n\n\t// If we are the primary instance create IPC server so subsequent launches can connect\n\tipcServer = new OutfitStudioIPCServer();\n\tif (!ipcServer->Create(OS_IPC_SERVICE)) {\n\t\tdelete ipcServer;\n\t\tipcServer = nullptr;\n\t}\n\n\tInitArchives();\n\n\tif (!Config[\"GameDataPath\"].empty()) {\n\t\tbool dirWritable = wxFileName::IsDirWritable(Config[\"GameDataPath\"]);\n\t\tbool dirReadable = wxFileName::IsDirReadable(Config[\"GameDataPath\"]);\n\t\tif (!dirWritable || !dirReadable)\n\t\t\twxMessageBox(\n\t\t\t\t_(\"No read/write permission for game data path!\\n\\nPlease launch the program with admin elevation and make sure the game data path in the settings is correct.\"),\n\t\t\t\t_(\"Warning\"),\n\t\t\t\twxICON_WARNING);\n\t}\n\n\tif (!Config[\"ProjectPath\"].empty()) {\n\t\tbool dirWritable = wxFileName::IsDirWritable(Config[\"ProjectPath\"]);\n\t\tbool dirReadable = wxFileName::IsDirReadable(Config[\"ProjectPath\"]);\n\t\tif (!dirWritable || !dirReadable)\n\t\t\twxMessageBox(\n\t\t\t\t_(\"No read/write permission for project path!\\n\\nPlease launch the program with admin elevation and make sure the project path in the settings is correct.\"),\n\t\t\t\t_(\"Warning\"),\n\t\t\t\twxICON_WARNING);\n\t}\n\n\tif (!cmdFiles.IsEmpty()) {\n\t\tframe->LoadFiles(cmdFiles, cmdProject);\n\t}\n\n\tBind(wxEVT_CHAR_HOOK, &OutfitStudio::CharHook, this);\n\n\tframe->UpdateTitle();\n\twxLogMessage(\"Outfit Studio initialized.\");\n\treturn true;\n}\n\nvoid OutfitStudio::OnInitCmdLine(wxCmdLineParser& parser) {\n\tparser.SetDesc(g_cmdLineDesc);\n\tparser.SetSwitchChars(\"-\");\n}\n\nbool OutfitStudio::OnCmdLineParsed(wxCmdLineParser& parser) {\n\tparser.Found(\"proj\", &cmdProject);\n\n\twxString singleInstanceArg;\n\tif (parser.Found(\"single\", &singleInstanceArg)) {\n\t\twxString lowerArg = singleInstanceArg.Lower();\n\t\tif (lowerArg == \"yes\") {\n\t\t\tcmdForceSingleInstanceBehavior = 1;  // Force open in existing\n\t\t}\n\t\telse if (lowerArg == \"no\") {\n\t\t\tcmdForceSingleInstanceBehavior = 0;  // Force open in new\n\t\t}\n\t\t// Otherwise leave it as -1 (not set)\n\t}\n\n\tfor (size_t i = 0; i < parser.GetParamCount(); i++)\n\t\tcmdFiles.Add(parser.GetParam(i));\n\n\treturn true;\n}\n\nbool OutfitStudio::OnExceptionInMainLoop() {\n\twxString error;\n\ttry {\n\t\tthrow;\n\t}\n\tcatch (const std::exception& e) {\n\t\terror = e.what();\n\t}\n\tcatch (...) {\n\t\terror = \"unknown error\";\n\t}\n\n\twxLog::FlushActive();\n\tlogger.SetFormatter(false);\n\n\twxLogError(\"Unexpected exception has occurred: %s, the program will terminate.\", error);\n\twxMessageBox(wxString::Format(_(\"Unexpected exception has occurred: %s, the program will terminate.\"), error), _(\"Unexpected exception\"), wxICON_ERROR);\n\treturn false;\n}\n\nvoid OutfitStudio::OnUnhandledException() {\n\twxString error;\n\ttry {\n\t\tthrow;\n\t}\n\tcatch (const std::exception& e) {\n\t\terror = e.what();\n\t}\n\tcatch (...) {\n\t\terror = \"unknown error\";\n\t}\n\n\twxLog::FlushActive();\n\tlogger.SetFormatter(false);\n\n\twxLogError(\"Unhandled exception has occurred: %s, the program will terminate.\", error);\n\twxMessageBox(wxString::Format(_(\"Unhandled exception has occurred: %s, the program will terminate.\"), error), _(\"Unhandled exception\"), wxICON_ERROR);\n}\n\nvoid OutfitStudio::OnFatalException() {\n\twxLog::FlushActive();\n\tlogger.SetFormatter(false);\n\n\twxLogError(\"Fatal exception has occurred, the program will terminate.\");\n\twxMessageBox(_(\"Fatal exception has occurred, the program will terminate.\"), _(\"Fatal exception\"), wxICON_ERROR);\n\n\twxDebugReport report;\n\treport.AddExceptionContext();\n\treport.Process();\n}\n\nvoid OutfitStudio::CharHook(wxKeyEvent& event) {\n\twxWindow* w = (wxWindow*)event.GetEventObject();\n\tif (!w) {\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\tif (!frame->IsDescendant(w)) {\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n#ifdef _WINDOWS\n\tbool isTextCtrl = dynamic_cast<wxTextCtrl*>(w) != nullptr || dynamic_cast<wxComboBox*>(w) != nullptr;\n\tif (isTextCtrl) {\n\t\tBYTE keyState[256];\n\t\tGetKeyboardState(keyState);\n\t\tWCHAR result[4] = {};\n\t\tint len = ToUnicode(event.GetRawKeyCode(), MapVirtualKey(event.GetRawKeyCode(), MAPVK_VK_TO_VSC), keyState, result, 4, 0);\n\t\tif (len == 1 && result[0] >= 0x20) {\n\t\t\tHWND hwnd = static_cast<HWND>(w->GetHandle());\n\t\t\t::SendMessage(hwnd, WM_CHAR, result[0], event.GetRawKeyFlags());\n\t\t\treturn;\n\t\t}\n\t}\n#endif\n\n\tevent.Skip();\n}\n\nbool OutfitStudio::SetDefaultConfig() {\n\tint currentTarget = -1;\n\tConfig.SetDefaultValue(\"TargetGame\", currentTarget);\n\tcurrentTarget = Config.GetIntValue(\"TargetGame\");\n\n\tConfig.SetDefaultBoolValue(\"WarnMissingGamePath\", true);\n\tConfig.SetDefaultBoolValue(\"BSATextureScan\", true);\n\tConfig.SetDefaultValue(\"LogLevel\", \"3\");\n\tConfig.SetDefaultBoolValue(\"UseSystemLanguage\", false);\n\tConfig.SetDefaultValue(\"Input/SliderMinimum\", 0);\n\tConfig.SetDefaultValue(\"Input/SliderMaximum\", 100);\n\tConfig.SetDefaultBoolValue(\"Input/LeftMousePan\", false);\n\tConfig.SetDefaultBoolValue(\"Input/BrushSettingsNearCursor\", true);\n\tConfig.SetDefaultBoolValue(\"Input/MaskHistory\", true);\n\tConfig.SetDefaultValue(\"Lights/Ambient\", 20);\n\tConfig.SetDefaultValue(\"Lights/Frontal\", 20);\n\tConfig.SetDefaultValue(\"Lights/Directional0\", 60);\n\tConfig.SetDefaultValue(\"Lights/Directional0.x\", -90);\n\tConfig.SetDefaultValue(\"Lights/Directional0.y\", 10);\n\tConfig.SetDefaultValue(\"Lights/Directional0.z\", 100);\n\tConfig.SetDefaultValue(\"Lights/Directional1\", 60);\n\tConfig.SetDefaultValue(\"Lights/Directional1.x\", 70);\n\tConfig.SetDefaultValue(\"Lights/Directional1.y\", 10);\n\tConfig.SetDefaultValue(\"Lights/Directional1.z\", 100);\n\tConfig.SetDefaultValue(\"Lights/Directional2\", 85);\n\tConfig.SetDefaultValue(\"Lights/Directional2.x\", 30);\n\tConfig.SetDefaultValue(\"Lights/Directional2.y\", 20);\n\tConfig.SetDefaultValue(\"Lights/Directional2.z\", -100);\n\tOutfitStudioConfig.SetDefaultValue(\"OutfitStudioFrame.width\", 1150);\n\tOutfitStudioConfig.SetDefaultValue(\"OutfitStudioFrame.height\", 780);\n\tOutfitStudioConfig.SetDefaultValue(\"OutfitStudioFrame.x\", 100);\n\tOutfitStudioConfig.SetDefaultValue(\"OutfitStudioFrame.y\", 100);\n\tOutfitStudioConfig.SetDefaultValue(\"OutfitStudioFrame.sashpos\", 768);\n\tOutfitStudioConfig.SetDefaultValue(\"OutfitStudioFrame.sashrightpos\", 200);\n\n\tconstexpr int DEF_PROJECT_HISTORY = 15;\n\tif (!OutfitStudioConfig.Exists(\"ProjectHistory.maxcount\"))\n\t\tOutfitStudioConfig.SetValue(\"ProjectHistory.maxcount\", DEF_PROJECT_HISTORY);\n\n\tConfig.SetDefaultValue(\"GameRegKey/Oblivion\", \"Software\\\\Bethesda Softworks\\\\Oblivion\");\n\tConfig.SetDefaultValue(\"GameRegVal/Oblivion\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Fallout3\", \"Software\\\\Bethesda Softworks\\\\Fallout3\");\n\tConfig.SetDefaultValue(\"GameRegVal/Fallout3\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/FalloutNewVegas\", \"Software\\\\Bethesda Softworks\\\\FalloutNV\");\n\tConfig.SetDefaultValue(\"GameRegVal/FalloutNewVegas\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Skyrim\", \"Software\\\\Bethesda Softworks\\\\Skyrim\");\n\tConfig.SetDefaultValue(\"GameRegVal/Skyrim\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Fallout4\", \"Software\\\\Bethesda Softworks\\\\Fallout4\");\n\tConfig.SetDefaultValue(\"GameRegVal/Fallout4\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/SkyrimSpecialEdition\", \"Software\\\\Bethesda Softworks\\\\Skyrim Special Edition\");\n\tConfig.SetDefaultValue(\"GameRegVal/SkyrimSpecialEdition\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/Fallout4VR\", \"Software\\\\Bethesda Softworks\\\\Fallout 4 VR\");\n\tConfig.SetDefaultValue(\"GameRegVal/Fallout4VR\", \"Installed Path\");\n\tConfig.SetDefaultValue(\"GameRegKey/SkyrimVR\", \"Software\\\\Bethesda Softworks\\\\Skyrim VR\");\n\tConfig.SetDefaultValue(\"GameRegVal/SkyrimVR\", \"Installed Path\");\n\n\t// Target game not set, show setup dialog\n\tif (currentTarget == -1)\n\t\tif (!ShowSetup())\n\t\t\treturn false;\n\n\ttargetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\n\twxString gameKey = Config[\"GameRegKey/\" + TargetGames[targetGame]];\n\twxString gameValueKey = Config[\"GameRegVal/\" + TargetGames[targetGame]];\n\n\tif (Config[\"GameDataPath\"].empty()) {\n#ifdef _WINDOWS\n\t\twxRegKey key(wxRegKey::HKLM, gameKey, wxRegKey::WOW64ViewMode_32);\n\t\tif (!gameKey.empty() && key.Exists()) {\n\t\t\twxString installPath;\n\t\t\tif (key.HasValues() && key.QueryValue(gameValueKey, installPath)) {\n\t\t\t\tinstallPath.Append(\"Data\").Append(PathSepChar);\n\t\t\t\tConfig.SetDefaultValue(\"GameDataPath\", installPath.ToUTF8().data());\n\t\t\t\twxLogMessage(\"Registry game data path: %s\", installPath);\n\t\t\t}\n\t\t\telse if (Config[\"WarnMissingGamePath\"] == \"true\") {\n\t\t\t\twxLogWarning(\"Failed to find game install path registry value or GameDataPath in the config.\");\n\t\t\t\twxMessageBox(_(\"Failed to find game install path registry value or GameDataPath in the config.\"), _(\"Warning\"), wxICON_WARNING);\n\t\t\t}\n\t\t}\n\t\telse\n#endif\n\t\t\tif (Config[\"WarnMissingGamePath\"] == \"true\") {\n\t\t\twxLogWarning(\"Failed to find game install path registry key or GameDataPath in the config.\");\n\t\t\twxMessageBox(_(\"Failed to find game install path registry key or GameDataPath in the config.\"), _(\"Warning\"), wxICON_WARNING);\n\t\t}\n\t}\n\telse\n\t\twxLogMessage(\"Game data path in config: %s\", Config[\"GameDataPath\"]);\n\n\tif (!Config[\"OutputDataPath\"].empty()) {\n\t\twxLogMessage(\"Output data path in config: %s\", Config[\"OutputDataPath\"]);\n\t}\n\n\tif (!Config[\"ProjectPath\"].empty()) {\n\t\twxLogMessage(\"Project path in config: %s\", Config[\"ProjectPath\"]);\n\t}\n\n\treturn true;\n}\n\nbool OutfitStudio::ShowSetup() {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\tbool loaded = xrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Setup.xrc\");\n\tif (!loaded) {\n\t\twxMessageBox(\"Failed to load Setup.xrc file!\", \"Error\", wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\twxDialog* setup = xrc->LoadDialog(nullptr, \"dlgSetup\");\n\tif (setup) {\n\t\tsetup->SetSize(setup->FromDIP(wxSize(700, -1)));\n\t\tsetup->CenterOnScreen();\n\n\t\twxButton* btOblivion = XRCCTRL(*setup, \"btOblivion\", wxButton);\n\t\tbtOblivion->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)OB); });\n\n\t\twxButton* btFallout3 = XRCCTRL(*setup, \"btFallout3\", wxButton);\n\t\tbtFallout3->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FO3); });\n\n\t\twxButton* btFalloutNV = XRCCTRL(*setup, \"btFalloutNV\", wxButton);\n\t\tbtFalloutNV->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FONV); });\n\n\t\twxButton* btSkyrim = XRCCTRL(*setup, \"btSkyrim\", wxButton);\n\t\tbtSkyrim->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SKYRIM); });\n\n\t\twxButton* btFallout4 = XRCCTRL(*setup, \"btFallout4\", wxButton);\n\t\tbtFallout4->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FO4); });\n\n\t\twxButton* btSkyrimSE = XRCCTRL(*setup, \"btSkyrimSE\", wxButton);\n\t\tbtSkyrimSE->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SKYRIMSE); });\n\n\t\twxButton* btFallout4VR = XRCCTRL(*setup, \"btFallout4VR\", wxButton);\n\t\tbtFallout4VR->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)FO4VR); });\n\n\t\twxButton* btSkyrimVR = XRCCTRL(*setup, \"btSkyrimVR\", wxButton);\n\t\tbtSkyrimVR->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SKYRIMVR); });\n\n\t\twxButton* btStarfield = XRCCTRL(*setup, \"btStarfield\", wxButton);\n\t\tbtStarfield->Bind(wxEVT_BUTTON, [&setup](wxCommandEvent&) { setup->EndModal((int)SF); });\n\n\t\twxDirPickerCtrl* dirOblivion = XRCCTRL(*setup, \"dirOblivion\", wxDirPickerCtrl);\n\t\tdirOblivion->Bind(wxEVT_DIRPICKER_CHANGED, [&dirOblivion, &btOblivion](wxFileDirPickerEvent&) { btOblivion->Enable(dirOblivion->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFallout3 = XRCCTRL(*setup, \"dirFallout3\", wxDirPickerCtrl);\n\t\tdirFallout3->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFallout3, &btFallout3](wxFileDirPickerEvent&) { btFallout3->Enable(dirFallout3->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFalloutNV = XRCCTRL(*setup, \"dirFalloutNV\", wxDirPickerCtrl);\n\t\tdirFalloutNV->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFalloutNV, &btFalloutNV](wxFileDirPickerEvent&) { btFalloutNV->Enable(dirFalloutNV->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirSkyrim = XRCCTRL(*setup, \"dirSkyrim\", wxDirPickerCtrl);\n\t\tdirSkyrim->Bind(wxEVT_DIRPICKER_CHANGED, [&dirSkyrim, &btSkyrim](wxFileDirPickerEvent&) { btSkyrim->Enable(dirSkyrim->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFallout4 = XRCCTRL(*setup, \"dirFallout4\", wxDirPickerCtrl);\n\t\tdirFallout4->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFallout4, &btFallout4](wxFileDirPickerEvent&) { btFallout4->Enable(dirFallout4->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirSkyrimSE = XRCCTRL(*setup, \"dirSkyrimSE\", wxDirPickerCtrl);\n\t\tdirSkyrimSE->Bind(wxEVT_DIRPICKER_CHANGED, [&dirSkyrimSE, &btSkyrimSE](wxFileDirPickerEvent&) { btSkyrimSE->Enable(dirSkyrimSE->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirFallout4VR = XRCCTRL(*setup, \"dirFallout4VR\", wxDirPickerCtrl);\n\t\tdirFallout4VR->Bind(wxEVT_DIRPICKER_CHANGED, [&dirFallout4VR, &btFallout4VR](wxFileDirPickerEvent&) { btFallout4VR->Enable(dirFallout4VR->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirSkyrimVR = XRCCTRL(*setup, \"dirSkyrimVR\", wxDirPickerCtrl);\n\t\tdirSkyrimVR->Bind(wxEVT_DIRPICKER_CHANGED, [&dirSkyrimVR, &btSkyrimVR](wxFileDirPickerEvent&) { btSkyrimVR->Enable(dirSkyrimVR->GetDirName().DirExists()); });\n\n\t\twxDirPickerCtrl* dirStarfield = XRCCTRL(*setup, \"dirStarfield\", wxDirPickerCtrl);\n\t\tdirStarfield->Bind(wxEVT_DIRPICKER_CHANGED, [&dirStarfield, &btStarfield](wxFileDirPickerEvent&) { btStarfield->Enable(dirStarfield->GetDirName().DirExists()); });\n\n\t\twxFileName dir = GetGameDataPath(OB);\n\t\tif (dir.DirExists()) {\n\t\t\tdirOblivion->SetDirName(dir);\n\t\t\tbtOblivion->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FO3);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFallout3->SetDirName(dir);\n\t\t\tbtFallout3->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FONV);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFalloutNV->SetDirName(dir);\n\t\t\tbtFalloutNV->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SKYRIM);\n\t\tif (dir.DirExists()) {\n\t\t\tdirSkyrim->SetDirName(dir);\n\t\t\tbtSkyrim->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FO4);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFallout4->SetDirName(dir);\n\t\t\tbtFallout4->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SKYRIMSE);\n\t\tif (dir.DirExists()) {\n\t\t\tdirSkyrimSE->SetDirName(dir);\n\t\t\tbtSkyrimSE->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(FO4VR);\n\t\tif (dir.DirExists()) {\n\t\t\tdirFallout4VR->SetDirName(dir);\n\t\t\tbtFallout4VR->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SKYRIMVR);\n\t\tif (dir.DirExists()) {\n\t\t\tdirSkyrimVR->SetDirName(dir);\n\t\t\tbtSkyrimVR->Enable();\n\t\t}\n\n\t\tdir = GetGameDataPath(SF);\n\t\tif (dir.DirExists()) {\n\t\t\tdirStarfield->SetDirName(dir);\n\t\t\tbtStarfield->Enable();\n\t\t}\n\n\t\tif (setup->ShowModal() != wxID_CANCEL) {\n\t\t\tint targ = setup->GetReturnCode();\n\t\t\tConfig.SetValue(\"TargetGame\", targ);\n\n\t\t\twxFileName dataDir;\n\t\t\tswitch (targ) {\n\t\t\t\tcase OB:\n\t\t\t\t\tdataDir = dirOblivion->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_ob.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Bip01\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FO3:\n\t\t\t\t\tdataDir = dirFallout3->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo3nv.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Bip01\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FONV:\n\t\t\t\t\tdataDir = dirFalloutNV->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo3nv.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Bip01\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SKYRIM:\n\t\t\t\t\tdataDir = dirSkyrim->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sk.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"NPC Root [Root]\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FO4:\n\t\t\t\t\tdataDir = dirFallout4->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo4.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Root\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SKYRIMSE:\n\t\t\t\t\tdataDir = dirSkyrimSE->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sse.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"NPC Root [Root]\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase FO4VR:\n\t\t\t\t\tdataDir = dirFallout4VR->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_fo4.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Root\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SKYRIMVR:\n\t\t\t\t\tdataDir = dirSkyrimVR->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sse.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"NPC Root [Root]\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase SF:\n\t\t\t\t\tdataDir = dirStarfield->GetDirName();\n\t\t\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", \"res/skeleton_female_sf.nif\");\n\t\t\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", \"Root\");\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tConfig.SetValue(\"GameDataPath\", dataDir.GetFullPath().ToUTF8().data());\n\t\t\tConfig.SetValue(\"GameDataPaths/\" + TargetGames[targ].ToStdString(), dataDir.GetFullPath().ToUTF8().data());\n\n\t\t\tConfig.SaveConfig(Config[\"AppDir\"] + \"/Config.xml\");\n\t\t\tdelete setup;\n\t\t}\n\t\telse {\n\t\t\tdelete setup;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nwxString OutfitStudio::GetGameDataPath(TargetGame targ) {\n\twxString dataPath;\n\twxString gamestr = TargetGames[targ];\n\twxString gkey = \"GameRegKey/\" + gamestr;\n\twxString gval = \"GameRegVal/\" + gamestr;\n\twxString cust = \"GameDataPaths/\" + gamestr;\n\n\tif (!Config[cust].IsEmpty()) {\n\t\tdataPath = Config[cust];\n\t}\n#ifdef _WINDOWS\n\telse {\n\t\tstd::string gameKey = Config[gkey];\n\t\twxRegKey key(wxRegKey::HKLM, gameKey, wxRegKey::WOW64ViewMode_32);\n\t\tif (!gameKey.empty() && key.Exists()) {\n\t\t\tif (key.HasValues() && key.QueryValue(Config[gval], dataPath)) {\n\t\t\t\tdataPath.Append(\"Data\").Append(PathSepChar);\n\t\t\t}\n\t\t}\n\t}\n#endif\n\treturn dataPath;\n}\n\nvoid OutfitStudio::InitLanguage() {\n\tif (locale)\n\t\tdelete locale;\n\n\tint lang = Config.GetIntValue(\"Language\");\n\tif (lang < 0)\n\t\tlang = wxLANGUAGE_ENGLISH;\n\n\t// Load language if possible, fall back to English otherwise\n\tif (wxLocale::IsAvailable(lang)) {\n\t\tlocale = new wxLocale(lang);\n\t\tlocale->AddCatalogLookupPathPrefix(wxString::FromUTF8(Config[\"AppDir\"]) + \"/lang\");\n\t\tlocale->AddCatalog(\"BodySlide\");\n\n\t\tif (!locale->IsOk()) {\n\t\t\twxLogError(\"System language '%d' is wrong.\", lang);\n\t\t\twxMessageBox(wxString::Format(_(\"System language '%d' is wrong.\"), lang));\n\n\t\t\tdelete locale;\n\t\t\tlocale = new wxLocale(wxLANGUAGE_ENGLISH);\n\t\t\tlang = wxLANGUAGE_ENGLISH;\n\t\t}\n\t}\n\telse {\n\t\twxLogError(\"The system language '%d' is not supported by your system. Try installing support for this language.\", lang);\n\t\twxMessageBox(wxString::Format(_(\"The system language '%d' is not supported by your system. Try installing support for this language.\"), lang));\n\n\t\tlocale = new wxLocale(wxLANGUAGE_ENGLISH);\n\t\tlang = wxLANGUAGE_ENGLISH;\n\t}\n\n\twxLogMessage(\"Using language '%s'.\", wxLocale::GetLanguageName(lang));\n}\n\nvoid OutfitStudio::InitArchives() {\n\t// Auto-detect archives\n\tFSManager::del();\n\n\tstd::vector<std::string> fileList;\n\tGetArchiveFiles(fileList);\n\n\tFSManager::addArchives(fileList);\n}\n\nvoid OutfitStudio::GetArchiveFiles(std::vector<std::string>& outList) {\n\tTargetGame targ = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tstd::string cp = \"GameDataFiles/\" + TargetGames[targ].ToStdString();\n\twxString activatedFiles = Config[cp];\n\n\twxStringTokenizer tokenizer(activatedFiles, \";\");\n\tstd::map<wxString, bool> fsearch;\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString val = tokenizer.GetNextToken().Trim(false);\n\t\tval = val.Trim().MakeLower();\n\t\tfsearch[val] = true;\n\t}\n\n\twxString dataDir = Config[\"GameDataPath\"];\n\twxArrayString files;\n\twxDir::GetAllFiles(dataDir, &files, \"*.ba2\", wxDIR_FILES);\n\twxDir::GetAllFiles(dataDir, &files, \"*.bsa\", wxDIR_FILES);\n\tfor (auto& f : files) {\n\t\tf = f.AfterLast('/').AfterLast('\\\\');\n\t\tif (fsearch.find(f.Lower()) == fsearch.end())\n\t\t\toutList.push_back((dataDir + f).ToUTF8().data());\n\t}\n}\n\n\nvoid ToolBarButtonHider::Init(wxToolBar* tbi) {\n\ttb = tbi;\n\tsize_t tc = tb->GetToolsCount();\n\tbutdats.resize(tc);\n\tfor (size_t pos = 0; pos < tc; ++pos)\n\t\tbutdats[pos].id = tb->GetToolByPos(pos)->GetId();\n}\n\nvoid ToolBarButtonHider::Show(int toolId, bool show) {\n\tsize_t hidcount = 0;\n\tfor (size_t pos = 0; pos < butdats.size(); ++pos) {\n\t\tButDat& bd = butdats[pos];\n\t\tif (bd.id != toolId) {\n\t\t\tif (bd.but)\n\t\t\t\t++hidcount;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!show && !bd.but)\n\t\t\tbd.but.reset(tb->RemoveTool(toolId));\n\t\tif (show && bd.but) {\n\t\t\ttb->InsertTool(pos - hidcount, bd.but.release());\n\t\t\tbd.but = nullptr;\n\t\t}\n\t\tbreak;\n\t}\n\n\ttb->Realize();\n}\n\n\nOutfitStudioFrame::OutfitStudioFrame(const wxPoint& pos, const wxSize& size) {\n\twxLogMessage(\"Loading Outfit Studio frame at X:%d Y:%d with W:%d H:%d...\", pos.x, pos.y, size.GetWidth(), size.GetHeight());\n\n\twxXmlResource* xrc = wxXmlResource::Get();\n\tif (!xrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/OutfitStudio.xrc\")) {\n\t\twxMessageBox(_(\"Failed to load OutfitStudio.xrc file!\"), _(\"Error\"), wxICON_ERROR);\n\t\tClose(true);\n\t\treturn;\n\t}\n\n\tif (!xrc->LoadFrame(this, nullptr, \"outfitStudio\")) {\n\t\twxMessageBox(_(\"Failed to load Outfit Studio frame!\"), _(\"Error\"), wxICON_ERROR);\n\t\tClose(true);\n\t\treturn;\n\t}\n\n\tSetIcon(wxIcon(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/OutfitStudio.png\", wxBITMAP_TYPE_PNG));\n\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Project.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Actions.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/WeightCopy.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Slider.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Skeleton.xrc\");\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/Settings.xrc\");\n\n\tconst std::array<int, 3> statusWidths = {-1, 400, 100};\n\tstatusBar = (wxStatusBar*)FindWindowByName(\"statusBar\");\n\tif (statusBar) {\n\t\tstatusBar->SetFieldsCount(3);\n\t\tstatusBar->SetStatusWidths(3, statusWidths.data());\n\t\tstatusBar->SetStatusText(_(\"Ready!\"));\n\t}\n\n\tthis->DragAcceptFiles(true);\n\n\tmenuBar = xrc->LoadMenuBar(this, \"menuBar\");\n\n\tstd::vector<std::string> projectHistoryFiles;\n\tOutfitStudioConfig.GetValueAttributeArray(\"ProjectHistory\", \"Project\", \"file\", projectHistoryFiles);\n\tstd::vector<std::string> projectHistoryNames;\n\tOutfitStudioConfig.GetValueAttributeArray(\"ProjectHistory\", \"Project\", \"name\", projectHistoryNames);\n\n\tif (projectHistoryFiles.size() == projectHistoryNames.size())\n\t\tfor (size_t i = projectHistoryFiles.size(); i > 0; --i)\n\t\t\tAddProjectHistory(projectHistoryFiles[i - 1], projectHistoryNames[i - 1]);\n\n\tbool disableNormalsCalc = OutfitStudioConfig.GetBoolValue(\"DisableNormalsCalc\");\n\tmenuBar->Check(XRCID(\"disableNormalsCalc\"), disableNormalsCalc);\n\n\ttoolBarH = (wxToolBar*)FindWindowByName(\"toolBarH\");\n\ttoolBarV = (wxToolBar*)FindWindowByName(\"toolBarV\");\n\ttbvHider.Init(toolBarV);\n\n\tif (toolBarH) {\n\t\tbrushSettings = reinterpret_cast<wxButton*>(toolBarH->FindWindowByName(\"brushSettings\"));\n\t\tif (brushSettings)\n\t\t\tbrushSettings->Bind(wxEVT_BUTTON, &OutfitStudioFrame::OnBrushSettings, this);\n\n\t\tfovSlider = reinterpret_cast<wxSlider*>(toolBarH->FindWindowByName(\"fovSlider\"));\n\t\tif (fovSlider)\n\t\t\tfovSlider->Bind(wxEVT_SLIDER, &OutfitStudioFrame::OnFieldOfViewSlider, this);\n\n\t\tcbDepthClip = reinterpret_cast<wxCheckBox*>(toolBarH->FindWindowByName(\"cbDepthClip\"));\n\t\tif (cbDepthClip)\n\t\t\tcbDepthClip->Bind(wxEVT_CHECKBOX, &OutfitStudioFrame::OnDepthClip, this);\n\t}\n\n\tsliderScroll = (wxScrolledWindow*)FindWindowByName(\"sliderScroll\");\n\tbmpEditSlider = new wxBitmap(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/EditSmall.png\", wxBITMAP_TYPE_ANY);\n\twxBitmapHelpers::Rescale(*bmpEditSlider, FromDIP(wxSize(16, 16)));\n\tbmpEditSliderGreen = new wxBitmap(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/EditSmall_green.png\", wxBITMAP_TYPE_ANY);\n\twxBitmapHelpers::Rescale(*bmpEditSliderGreen, FromDIP(wxSize(16, 16)));\n\tbmpSliderSettings = new wxBitmap(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/Settings.png\", wxBITMAP_TYPE_ANY);\n\twxBitmapHelpers::Rescale(*bmpSliderSettings, FromDIP(wxSize(16, 16)));\n\n\tmeshTabButton = (wxStateButton*)FindWindowByName(\"meshTabButton\");\n\tboneTabButton = (wxStateButton*)FindWindowByName(\"boneTabButton\");\n\tcolorsTabButton = (wxStateButton*)FindWindowByName(\"colorsTabButton\");\n\tsegmentTabButton = (wxStateButton*)FindWindowByName(\"segmentTabButton\");\n\tpartitionTabButton = (wxStateButton*)FindWindowByName(\"partitionTabButton\");\n\tlightsTabButton = (wxStateButton*)FindWindowByName(\"lightsTabButton\");\n\tmasksPane = dynamic_cast<wxCollapsiblePane*>(FindWindowByName(\"masksPane\"));\n\tposePane = dynamic_cast<wxCollapsiblePane*>(FindWindowByName(\"posePane\"));\n\tnotesPane = dynamic_cast<wxCollapsiblePane*>(FindWindowByName(\"notesPane\"));\n\tprojectNotes = (wxTextCtrl*)FindWindowByName(\"projectNotes\");\n\n\tif (meshTabButton) {\n\t\tmeshTabButton->SetCheck();\n\t\tcurrentTabButton = meshTabButton;\n\t}\n\n\tif (partitionTabButton) {\n\t\tbool showPartitionTab = wxGetApp().targetGame == FO3 || wxGetApp().targetGame == FONV || wxGetApp().targetGame == SKYRIM || wxGetApp().targetGame == SKYRIMSE\n\t\t\t\t\t\t\t\t|| wxGetApp().targetGame == SKYRIMVR;\n\t\tpartitionTabButton->Show(showPartitionTab);\n\t}\n\n\tif (segmentTabButton) {\n\t\tbool showSegmentTab = wxGetApp().targetGame == FO4 || wxGetApp().targetGame == FO4VR || wxGetApp().targetGame == FO76;\n\t\tsegmentTabButton->Show(showSegmentTab);\n\t}\n\n\t// The HKX pose pipeline supports Skyrim LE/SE/VR and Fallout 4/VR\n\t// natively (no external tools required). Other games use unsupported\n\t// Havok variants (Skyrim ragdoll-only formats, Starfield, etc.).\n\tif (wxWindow* loadHkxPoseBtn = FindWindow(XRCID(\"loadHkxPose\"))) {\n\t\tTargetGame tg = wxGetApp().targetGame;\n\t\tbool showLoadHkx = (tg == SKYRIM || tg == SKYRIMSE || tg == SKYRIMVR || tg == FO4 || tg == FO4VR);\n\t\tloadHkxPoseBtn->Show(showLoadHkx);\n\t}\n\n\toutfitShapes = (wxTreeCtrl*)FindWindowByName(\"outfitShapes\");\n\tif (outfitShapes) {\n\t\twxImageList* visStateImages = new wxImageList(16, 16, false, 2);\n\t\twxBitmap visImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoVisible.png\", wxBITMAP_TYPE_PNG);\n\t\twxBitmap invImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoInvisible.png\", wxBITMAP_TYPE_PNG);\n\t\twxBitmap wfImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoWireframe.png\", wxBITMAP_TYPE_PNG);\n\n\t\tif (visImg.IsOk())\n\t\t\tvisStateImages->Add(visImg);\n\t\tif (invImg.IsOk())\n\t\t\tvisStateImages->Add(invImg);\n\t\tif (wfImg.IsOk())\n\t\t\tvisStateImages->Add(wfImg);\n\n\t\toutfitShapes->AssignStateImageList(visStateImages);\n\t\tshapesRoot = outfitShapes->AddRoot(\"Shapes\");\n\t}\n\n\toutfitBones = (wxTreeCtrl*)FindWindowByName(\"outfitBones\");\n\tif (outfitBones) {\n\t\twxBitmap noneImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoNone.png\", wxBITMAP_TYPE_PNG);\n\t\twxBitmap changeImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoChange.png\", wxBITMAP_TYPE_PNG);\n\t\twxBitmap brokenBoneImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoBrokenBone.png\", wxBITMAP_TYPE_PNG);\n\t\twxBitmap brokenBoneChangeImg(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/icoBrokenBoneChange.png\", wxBITMAP_TYPE_PNG);\n\t\twxImageList* boneStateImages = new wxImageList(16, 16, false, 4);\n\t\tif (noneImg.IsOk())\n\t\t\tboneStateImages->Add(noneImg);\n\t\tif (changeImg.IsOk())\n\t\t\tboneStateImages->Add(changeImg);\n\t\tif (brokenBoneImg.IsOk())\n\t\t\tboneStateImages->Add(brokenBoneImg);\n\t\tif (brokenBoneChangeImg.IsOk())\n\t\t\tboneStateImages->Add(brokenBoneChangeImg);\n\t\toutfitBones->AssignStateImageList(boneStateImages);\n\t\tbonesRoot = outfitBones->AddRoot(\"Bones\");\n\t}\n\n\tcolorSettings = (wxPanel*)FindWindowByName(\"colorSettings\");\n\n\tsegmentTree = (wxTreeCtrl*)FindWindowByName(\"segmentTree\");\n\tif (segmentTree)\n\t\tsegmentRoot = segmentTree->AddRoot(\"Segments\");\n\n\tpartitionTree = (wxTreeCtrl*)FindWindowByName(\"partitionTree\");\n\tif (partitionTree)\n\t\tpartitionRoot = partitionTree->AddRoot(\"Partitions\");\n\n\tint ambient = Config.GetIntValue(\"Lights/Ambient\");\n\tint frontal = Config.GetIntValue(\"Lights/Frontal\");\n\tint directional0 = Config.GetIntValue(\"Lights/Directional0\");\n\tint directional1 = Config.GetIntValue(\"Lights/Directional1\");\n\tint directional2 = Config.GetIntValue(\"Lights/Directional2\");\n\n\tlightSettings = (wxPanel*)FindWindowByName(\"lightSettings\");\n\tif (lightSettings) {\n\t\tauto lightAmbientSlider = (wxSlider*)lightSettings->FindWindowByName(\"lightAmbientSlider\");\n\t\tlightAmbientSlider->SetValue(ambient);\n\n\t\tauto lightFrontalSlider = (wxSlider*)lightSettings->FindWindowByName(\"lightFrontalSlider\");\n\t\tlightFrontalSlider->SetValue(frontal);\n\n\t\tauto lightDirectional0Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional0Slider\");\n\t\tlightDirectional0Slider->SetValue(directional0);\n\n\t\tauto lightDirectional1Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional1Slider\");\n\t\tlightDirectional1Slider->SetValue(directional1);\n\n\t\tauto lightDirectional2Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional2Slider\");\n\t\tlightDirectional2Slider->SetValue(directional2);\n\t}\n\n\tauto editPanel = (wxPanel*)FindWindowByName(\"editPanel\");\n\tif (editPanel)\n\t\teditPanel->SetBackgroundColour(wxColour(112, 112, 112));\n\n\tcXMirrorBone = (wxChoice*)FindWindowByName(\"cXMirrorBone\");\n\tcPoseBone = (wxChoice*)FindWindowByName(\"cPoseBone\");\n\trxPoseSlider = (wxSlider*)FindWindowByName(\"rxPoseSlider\");\n\tryPoseSlider = (wxSlider*)FindWindowByName(\"ryPoseSlider\");\n\trzPoseSlider = (wxSlider*)FindWindowByName(\"rzPoseSlider\");\n\ttxPoseSlider = (wxSlider*)FindWindowByName(\"txPoseSlider\");\n\ttyPoseSlider = (wxSlider*)FindWindowByName(\"tyPoseSlider\");\n\ttzPoseSlider = (wxSlider*)FindWindowByName(\"tzPoseSlider\");\n\tscPoseSlider = (wxSlider*)FindWindowByName(\"scPoseSlider\");\n\trxPoseText = (wxTextCtrl*)FindWindowByName(\"rxPoseText\");\n\tryPoseText = (wxTextCtrl*)FindWindowByName(\"ryPoseText\");\n\trzPoseText = (wxTextCtrl*)FindWindowByName(\"rzPoseText\");\n\ttxPoseText = (wxTextCtrl*)FindWindowByName(\"txPoseText\");\n\ttyPoseText = (wxTextCtrl*)FindWindowByName(\"tyPoseText\");\n\ttzPoseText = (wxTextCtrl*)FindWindowByName(\"tzPoseText\");\n\tscPoseText = (wxTextCtrl*)FindWindowByName(\"scPoseText\");\n\tcbPose = (wxCheckBox*)FindWindowByName(\"cbPose\");\n\tposeToMesh = (wxButton*)FindWindowByName(\"poseToMesh\");\n\n\twxWindow* leftPanel = FindWindowByName(\"leftSplitPanel\");\n\tif (leftPanel) {\n\t\tglView = new wxGLPanel(leftPanel, wxDefaultSize, GLSurface::GetGLAttribs());\n\t\tglView->SetNotifyWindow(this);\n\n\t\tfloat brushSize = OutfitStudioConfig.GetFloatValue(\"BrushSettings.brushsize\");\n\t\tif (brushSize != 0.0f)\n\t\t\tglView->SetBrushSize(brushSize);\n\t\telse\n\t\t\tglView->ResetBrushSize();\n\n\t\tstd::vector<std::string> brushNames;\n\t\tOutfitStudioConfig.GetValueAttributeArray(\"BrushSettings\", \"Brush\", \"name\", brushNames);\n\t\tstd::vector<std::string> brushStrengthValues;\n\t\tOutfitStudioConfig.GetValueAttributeArray(\"BrushSettings\", \"Brush\", \"strength\", brushStrengthValues);\n\t\tstd::vector<std::string> brushFocusValues;\n\t\tOutfitStudioConfig.GetValueAttributeArray(\"BrushSettings\", \"Brush\", \"focus\", brushFocusValues);\n\t\tstd::vector<std::string> brushSpacingValues;\n\t\tOutfitStudioConfig.GetValueAttributeArray(\"BrushSettings\", \"Brush\", \"spacing\", brushSpacingValues);\n\n\t\tauto brushList = glView->GetBrushList();\n\n\t\tfor (size_t i = 0; i < brushNames.size(); i++) {\n\t\t\tstd::string brushName = brushNames[i];\n\t\t\tauto brushIt = std::find_if(brushList.begin(), brushList.end(), [&brushName](TweakBrush* brush) { return brush->Name() == brushName; });\n\n\t\t\tif (brushIt != brushList.end()) {\n\t\t\t\tif (brushStrengthValues.size() > i) {\n\t\t\t\t\tfloat brushStrength = std::atof(brushStrengthValues[i].data());\n\t\t\t\t\t(*brushIt)->setStrength(brushStrength);\n\t\t\t\t}\n\n\t\t\t\tif (brushFocusValues.size() > i) {\n\t\t\t\t\tfloat brushFocus = std::atof(brushFocusValues[i].data());\n\t\t\t\t\t(*brushIt)->setFocus(brushFocus);\n\t\t\t\t}\n\n\t\t\t\tif (brushSpacingValues.size() > i) {\n\t\t\t\t\tfloat brushSpacing = std::atof(brushSpacingValues[i].data());\n\t\t\t\t\t(*brushIt)->setSpacing(brushSpacing);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\twxWindow* rightPanel = FindWindowByName(\"rightSplitPanel\");\n\tif (rightPanel)\n\t\trightPanel->SetDoubleBuffered(true);\n\n\txrc->AttachUnknownControl(\"mGLView\", glView, this);\n\n\tsliderFilter = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, -1), wxTE_PROCESS_ENTER);\n\tsliderFilter->ShowSearchButton(true);\n\tsliderFilter->ShowCancelButton(true);\n\tsliderFilter->SetDescriptiveText(\"Slider Filter\");\n\tsliderFilter->SetToolTip(\"Filter slider list by name\");\n\n\tbonesFilter = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(-1, -1), wxTE_PROCESS_ENTER);\n\tbonesFilter->ShowSearchButton(true);\n\tbonesFilter->ShowCancelButton(true);\n\tbonesFilter->SetDescriptiveText(\"Filter\");\n\tbonesFilter->SetToolTip(\"Filter bone list by name\");\n\n\txrc->AttachUnknownControl(\"sliderFilter\", sliderFilter, this);\n\txrc->AttachUnknownControl(\"bonesFilter\", bonesFilter, this);\n\tbonesFilter->GetParent()->Hide();\n\n\tproject = new OutfitProject(this); // Create empty project\n\tCreateSetSliders();\n\n\tselectedItems.clear();\n\n\tSetSize(size);\n\tSetPosition(pos);\n\n\tauto splitter = (wxSplitterWindow*)FindWindowByName(\"splitter\");\n\tif (splitter) {\n\t\tint sashPos = OutfitStudioConfig.GetIntValue(\"OutfitStudioFrame.sashpos\");\n\t\tsplitter->SetSashPosition(sashPos);\n\t}\n\n\tauto splitterRight = (wxSplitterWindow*)FindWindowByName(\"splitterRight\");\n\tif (splitterRight) {\n\t\tint sashRightPos = OutfitStudioConfig.GetIntValue(\"OutfitStudioFrame.sashrightpos\");\n\t\tsplitterRight->SetSashPosition(sashRightPos);\n\t}\n\n\tif (leftPanel)\n\t\tleftPanel->Layout();\n\n\tReEnableToolOptionsUI();\n\n\tSetDropTarget(new DnDFile(this));\n\n\t// Create initial slider pool\n\tconst size_t minSliderPoolSize = 100;\n\tsliderPool.CreatePool(minSliderPoolSize, sliderScroll, *bmpEditSlider, *bmpSliderSettings);\n\n\twxLogMessage(\"Outfit Studio frame loaded.\");\n}\n\nvoid OutfitStudioFrame::OnExit(wxCommandEvent& WXUNUSED(event)) {\n\tClose(true);\n}\n\nvoid OutfitStudioFrame::OnClose(wxCloseEvent& WXUNUSED(event)) {\n\tif (!CheckPendingChanges())\n\t\treturn;\n\n\tif (editUV)\n\t\teditUV->Close();\n\n\tif (project) {\n\t\tdelete project;\n\t\tproject = nullptr;\n\t}\n\n\tsliderPool.Clear();\n\n\tOutfitStudioConfig.SetValue(\"BrushSettings.brushsize\", glView->GetBrushSize());\n\n\tstd::vector<std::map<std::string, std::string>> brushSettingsEntries;\n\n\tauto brushList = glView->GetBrushList();\n\tfor (auto& brush : brushList) {\n\t\tstd::map<std::string, std::string> attributeValues;\n\t\tattributeValues[\"name\"] = brush->Name();\n\t\tattributeValues[\"strength\"] = std::to_string(brush->getStrength());\n\t\tattributeValues[\"focus\"] = std::to_string(brush->getFocus());\n\t\tattributeValues[\"spacing\"] = std::to_string(brush->getSpacing());\n\t\tbrushSettingsEntries.push_back(attributeValues);\n\t}\n\n\tOutfitStudioConfig.ClearValueArray(\"BrushSettings\", \"Brush\");\n\tOutfitStudioConfig.AppendValueArray(\"BrushSettings\", \"Brush\", brushSettingsEntries);\n\n\tif (glView)\n\t\tdelete glView;\n\n\tif (bmpEditSlider)\n\t\tdelete bmpEditSlider;\n\tif (bmpEditSliderGreen)\n\t\tdelete bmpEditSliderGreen;\n\tif (bmpSliderSettings)\n\t\tdelete bmpSliderSettings;\n\n\tOutfitStudioConfig.ClearValueArray(\"ProjectHistory\", \"Project\");\n\n\tstd::vector<std::map<std::string, std::string>> phArrayEntries;\n\tfor (auto& ph : projectHistory) {\n\t\tstd::map<std::string, std::string> attributeValues;\n\t\tattributeValues[\"name\"] = ph.projectName;\n\t\tattributeValues[\"file\"] = ph.fileName;\n\t\tphArrayEntries.push_back(attributeValues);\n\t}\n\n\tOutfitStudioConfig.AppendValueArray(\"ProjectHistory\", \"Project\", phArrayEntries);\n\n\t// Reload SingleInstanceBehavior from disk before saving, as it may have been\n\t// changed by another process via the \"Yes (always)\" / \"No (never)\" dialog.\n\t{\n\t\tConfigurationManager diskConfig;\n\t\tstd::string configPath = Config[\"AppDir\"] + \"/OutfitStudio.xml\";\n\t\tdiskConfig.LoadConfig(configPath, \"OutfitStudioConfig\");\n\t\tif (diskConfig.Exists(\"SingleInstanceBehavior\"))\n\t\t\tOutfitStudioConfig.SetValue(\"SingleInstanceBehavior\", diskConfig.GetIntValue(\"SingleInstanceBehavior\"));\n\t}\n\n\tint ret = OutfitStudioConfig.SaveConfig(Config[\"AppDir\"] + \"/OutfitStudio.xml\", \"OutfitStudioConfig\");\n\tif (ret)\n\t\twxLogWarning(\"Failed to save configuration (%d)!\", ret);\n\n\twxLogMessage(\"Outfit Studio frame closed.\");\n\tDestroy();\n}\n\nbool OutfitStudioFrame::CopyStreamData(wxInputStream& inputStream, wxOutputStream& outputStream, wxFileOffset size) {\n\tauto buf = std::make_unique<wxChar[]>(128 * 1024);\n\tint readSize = 128 * 1024;\n\twxFileOffset copiedData = 0;\n\n\tfor (;;) {\n\t\tif (size != -1 && copiedData + readSize > size)\n\t\t\treadSize = size - copiedData;\n\n\t\tinputStream.Read(buf.get(), readSize);\n\n\t\tsize_t actuallyRead = inputStream.LastRead();\n\t\toutputStream.Write(buf.get(), actuallyRead);\n\t\tif (outputStream.LastWrite() != actuallyRead) {\n\t\t\twxLogError(\"Failed to output data when copying stream.\");\n\t\t\treturn false;\n\t\t}\n\n\t\tif (size == -1) {\n\t\t\tif (inputStream.Eof())\n\t\t\t\tbreak;\n\t\t}\n\t\telse {\n\t\t\tcopiedData += actuallyRead;\n\t\t\tif (copiedData >= size)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nvoid OutfitStudioFrame::OnMenuItem(wxCommandEvent& event) {\n\tint id = event.GetId();\n\tif (id >= 1000 && id < 2000) {\n\t\t// Load project history entry\n\t\tif (static_cast<int>(projectHistory.size()) > id - 1000) {\n\t\t\tif (!CheckPendingChanges())\n\t\t\t\treturn;\n\n\t\t\tauto projectHistoryEntry = projectHistory[id - 1000];\n\t\t\tLoadProject(projectHistoryEntry.fileName, projectHistoryEntry.projectName);\n\t\t}\n\t}\n\telse\n\t\tevent.Skip();\n}\n\nvoid OutfitStudioFrame::OnPackProjects(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\twxXmlResource* xrc = wxXmlResource::Get();\n\twxDialog* packProjects = xrc->LoadDialog(this, \"dlgPackProjects\");\n\tif (packProjects) {\n\t\tauto projectFilter = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, FromDIP(wxSize(200, -1)), wxTE_PROCESS_ENTER);\n\t\tprojectFilter->ShowSearchButton(true);\n\t\tprojectFilter->SetDescriptiveText(\"Project Filter\");\n\t\tprojectFilter->SetToolTip(\"Filter project list by name\");\n\n\t\txrc->AttachUnknownControl(\"projectFilter\", projectFilter, packProjects);\n\n\t\tpackProjects->SetSize(FromDIP(wxSize(550, 300)));\n\t\tpackProjects->SetMinSize(FromDIP(wxSize(400, 200)));\n\t\tpackProjects->CenterOnParent();\n\n\t\tstd::map<std::string, SliderSet> projectSources;\n\t\tstd::set<std::string> selectedProjects;\n\n\t\tauto projectList = XRCCTRL(*packProjects, \"projectList\", wxCheckListBox);\n\t\tprojectList->Bind(wxEVT_RIGHT_UP, [&](wxMouseEvent& WXUNUSED(event)) {\n\t\t\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"projectListContext\");\n\t\t\tif (menu) {\n\t\t\t\tmenu->Bind(wxEVT_MENU, [&](wxCommandEvent& event) {\n\t\t\t\t\tif (event.GetId() == XRCID(\"projectListNone\")) {\n\t\t\t\t\t\tfor (uint32_t i = 0; i < projectList->GetCount(); i++) {\n\t\t\t\t\t\t\tstd::string name{projectList->GetString(i).ToUTF8()};\n\t\t\t\t\t\t\tprojectList->Check(i, false);\n\t\t\t\t\t\t\tselectedProjects.erase(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (event.GetId() == XRCID(\"projectListAll\")) {\n\t\t\t\t\t\tfor (uint32_t i = 0; i < projectList->GetCount(); i++) {\n\t\t\t\t\t\t\tstd::string name{projectList->GetString(i).ToUTF8()};\n\t\t\t\t\t\t\tprojectList->Check(i);\n\t\t\t\t\t\t\tselectedProjects.insert(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse if (event.GetId() == XRCID(\"projectListInvert\")) {\n\t\t\t\t\t\tfor (uint32_t i = 0; i < projectList->GetCount(); i++) {\n\t\t\t\t\t\t\tstd::string name{projectList->GetString(i).ToUTF8()};\n\n\t\t\t\t\t\t\tbool check = !projectList->IsChecked(i);\n\t\t\t\t\t\t\tprojectList->Check(i, check);\n\n\t\t\t\t\t\t\tif (check)\n\t\t\t\t\t\t\t\tselectedProjects.insert(name);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t\tPopupMenu(menu);\n\t\t\t\tdelete menu;\n\t\t\t}\n\t\t});\n\n\t\tprojectList->Bind(wxEVT_CHECKLISTBOX, [&](wxCommandEvent& event) {\n\t\t\tstd::string name{event.GetString().ToUTF8()};\n\t\t\tint item = event.GetInt();\n\t\t\tif (projectList->IsChecked(item))\n\t\t\t\tselectedProjects.insert(name);\n\t\t\telse\n\t\t\t\tselectedProjects.erase(name);\n\t\t});\n\n\t\tprojectFilter->Bind(wxEVT_TEXT, [&](wxCommandEvent& event) {\n\t\t\twxString filterStr = event.GetString();\n\t\t\tfilterStr.MakeLower();\n\n\t\t\tprojectList->Clear();\n\n\t\t\t// Add outfits that are no members to list\n\t\t\tfor (auto& project : projectSources) {\n\t\t\t\t// Filter outfit by name\n\t\t\t\twxString projectStr = wxString::FromUTF8(project.first);\n\t\t\t\tif (projectStr.Lower().Contains(filterStr)) {\n\t\t\t\t\tint item = projectList->Append(projectStr);\n\t\t\t\t\tif (selectedProjects.find(project.first) != selectedProjects.end())\n\t\t\t\t\t\tprojectList->Check(item);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\twxArrayString files;\n\t\twxDir::GetAllFiles(wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\", &files, \"*.osp\");\n\t\twxDir::GetAllFiles(wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\", &files, \"*.xml\");\n\n\t\tfor (auto& file : files) {\n\t\t\tstd::string fileName{file.ToUTF8()};\n\n\t\t\tSliderSetFile sliderDoc;\n\t\t\tsliderDoc.Open(fileName);\n\t\t\tif (sliderDoc.fail())\n\t\t\t\tcontinue;\n\n\t\t\tstd::vector<std::string> setNames;\n\t\t\tsliderDoc.GetSetNamesUnsorted(setNames, false);\n\n\t\t\tfor (auto& setName : setNames) {\n\t\t\t\tif (projectSources.find(setName) != projectSources.end())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tSliderSet set;\n\t\t\t\tif (sliderDoc.GetSet(setName, set) == 0) {\n\t\t\t\t\tprojectSources[setName] = set;\n\t\t\t\t\tprojectList->Append(wxString::FromUTF8(setName));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tstd::string sep{wxString(wxFileName::GetPathSeparator()).ToUTF8()};\n\t\twxString baseDir = \"Tools\" + sep + \"BodySlide\";\n\n\t\tTargetGame targetGame = wxGetApp().targetGame;\n\t\tif (targetGame == SKYRIM || targetGame == SKYRIMSE || targetGame == SKYRIMVR)\n\t\t\tbaseDir = \"CalienteTools\" + sep + \"BodySlide\";\n\n\t\tauto groupManager = XRCCTRL(*packProjects, \"groupManager\", wxButton);\n\t\tgroupManager->Bind(wxEVT_BUTTON, [&](wxCommandEvent& WXUNUSED(event)) {\n\t\t\tstd::vector<std::string> gmOutfits;\n\t\t\tgmOutfits.reserve(projectSources.size());\n\n\t\t\tstd::transform(std::begin(projectSources), std::end(projectSources), std::back_inserter(gmOutfits), [](auto const& pair) { return pair.first; });\n\n\t\t\tGroupManager gm(packProjects, gmOutfits);\n\t\t\tgm.ShowModal();\n\t\t});\n\n\t\tauto groupFile = XRCCTRL(*packProjects, \"groupFile\", wxFilePickerCtrl);\n\t\tgroupFile->SetInitialDirectory(wxString::FromUTF8(GetProjectPath()) + \"/SliderGroups\");\n\n\t\tauto mergedFileName = XRCCTRL(*packProjects, \"mergedFileName\", wxTextCtrl);\n\t\tauto packFolder = XRCCTRL(*packProjects, \"packFolder\", wxButton);\n\t\tauto packArchive = XRCCTRL(*packProjects, \"packArchive\", wxButton);\n\n\t\tmergedFileName->Bind(wxEVT_TEXT, [&](wxCommandEvent& WXUNUSED(event)) {\n\t\t\tpackFolder->Enable(!mergedFileName->GetValue().IsEmpty());\n\t\t\tpackArchive->Enable(!mergedFileName->GetValue().IsEmpty());\n\t\t});\n\n\t\tpackFolder->Bind(wxEVT_BUTTON, [&](wxCommandEvent& WXUNUSED(event)) {\n\t\t\twxString dir = wxDirSelector(_(\"Packing projects to folder...\"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, packProjects);\n\t\t\tif (dir.IsEmpty())\n\t\t\t\treturn;\n\n\t\t\twxLogMessage(\"Packing project to folder...\");\n\t\t\tStartProgress(_(\"Packing projects to folder...\"));\n\n\t\t\tstd::string mergedFile{wxString(mergedFileName->GetValue() + \".osp\").ToUTF8()};\n\t\t\tstd::string mergedFilePath{wxFileName::CreateTempFileName(\"os\").ToUTF8()};\n\t\t\tproject->ReplaceForbidden(mergedFile);\n\n\t\t\tSliderSetFile projectFile;\n\t\t\tprojectFile.New(mergedFilePath);\n\n\t\t\tfor (auto& setName : selectedProjects) {\n\t\t\t\tif (projectSources.find(setName) == projectSources.end())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tSliderSet set = projectSources[setName];\n\t\t\t\tprojectFile.UpdateSet(set);\n\n\t\t\t\t// Add input file to folder\n\t\t\t\twxString inputFilePath = wxString::FromUTF8(GetProjectPath() + sep + \"ShapeData\" + sep + set.GetInputFileName());\n\t\t\t\twxFileInputStream inputFileStream(inputFilePath);\n\t\t\t\tif (!inputFileStream.IsOk()) {\n\t\t\t\t\twxLogError(\"Failed to open input file '%s'!\", inputFilePath);\n\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open input file '%s'!\"), inputFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Copy input file to destination folder\n\t\t\t\twxString inputFileDest = wxString::FromUTF8(dir + sep + baseDir + sep + \"ShapeData\" + sep + set.GetInputFileName());\n\t\t\t\twxFileName::Mkdir(inputFileDest.BeforeLast(wxFileName::GetPathSeparator()), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\t\t\t\tif (!wxCopyFile(inputFilePath, inputFileDest)) {\n\t\t\t\t\twxLogError(\"Failed to copy input file '%s'!\", inputFilePath);\n\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to copy input file '%s'!\"), inputFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tstd::set<std::string> dataFiles;\n\n\t\t\t\tfor (size_t i = 0; i < set.size(); i++) {\n\t\t\t\t\tfor (auto it = set.ShapesBegin(); it != set.ShapesEnd(); ++it) {\n\t\t\t\t\t\tstd::string target = set.ShapeToTarget(it->first);\n\t\t\t\t\t\tstd::string targetDataName = set[i].TargetDataName(target);\n\t\t\t\t\t\tif (set[i].IsLocalData(targetDataName)) {\n\t\t\t\t\t\t\tstd::string dataFileName = set[i].DataFileName(targetDataName);\n\t\t\t\t\t\t\tif (dataFileName.compare(dataFileName.size() - 4, dataFileName.size(), \".bsd\") != 0) {\n\t\t\t\t\t\t\t\t// Split target file name to get OSD file name\n\t\t\t\t\t\t\t\tint split = dataFileName.find_last_of('/');\n\t\t\t\t\t\t\t\tif (split < 0)\n\t\t\t\t\t\t\t\t\tsplit = dataFileName.find_last_of('\\\\');\n\t\t\t\t\t\t\t\tif (split < 0)\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\tdataFiles.insert(set.GetDefaultDataFolder() + sep + dataFileName.substr(0, split));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdataFiles.insert(set.GetDefaultDataFolder() + sep + dataFileName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Add data files to folder\n\t\t\t\tfor (auto& df : dataFiles) {\n\t\t\t\t\twxString dataFilePath = wxString::FromUTF8(GetProjectPath() + sep + \"ShapeData\" + sep + df);\n\t\t\t\t\twxFileInputStream dataFileStream(dataFilePath);\n\t\t\t\t\tif (!dataFileStream.IsOk()) {\n\t\t\t\t\t\twxLogError(\"Failed to open input file '%s'!\", dataFilePath);\n\t\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open input file '%s'!\"), dataFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\t\tEndProgress();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Copy data file to destination folder\n\t\t\t\t\twxString dataFileDest = wxString::FromUTF8(dir + sep + baseDir + sep + \"ShapeData\" + sep + df);\n\t\t\t\t\twxFileName::Mkdir(dataFileDest.BeforeLast(wxFileName::GetPathSeparator()), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\t\t\t\t\tif (!wxCopyFile(dataFilePath, dataFileDest)) {\n\t\t\t\t\t\twxLogError(\"Failed to copy data file '%s'!\", dataFilePath);\n\t\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to copy data file '%s'!\"), dataFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\t\tEndProgress();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Save new merged project file\n\t\t\tif (!projectFile.Save()) {\n\t\t\t\twxLogError(\"Failed to save merged project file '%s'!\", mergedFilePath);\n\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to save merged project file '%s'!\"), mergedFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add merged project file to folder\n\t\t\twxFileInputStream projectFileStream(mergedFilePath);\n\t\t\tif (!projectFileStream.IsOk()) {\n\t\t\t\twxLogError(\"Failed to open project file '%s'!\", mergedFilePath);\n\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open project file '%s'!\"), mergedFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Copy merged project file to destination folder\n\t\t\twxString projectFileDest = wxString::FromUTF8(dir + sep + baseDir + sep + \"SliderSets\" + sep + mergedFile);\n\t\t\twxFileName::Mkdir(projectFileDest.BeforeLast(wxFileName::GetPathSeparator()), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\t\t\tif (!wxCopyFile(mergedFilePath, projectFileDest)) {\n\t\t\t\twxLogError(\"Failed to copy merged project file '%s'!\", mergedFilePath);\n\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to copy merged project file '%s'!\"), mergedFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twxString groupFilePath = groupFile->GetPath();\n\t\t\tif (!groupFilePath.IsEmpty()) {\n\t\t\t\t// Add group file to folder\n\t\t\t\twxFileInputStream groupFileStream(groupFilePath);\n\t\t\t\tif (!groupFileStream.IsOk()) {\n\t\t\t\t\twxLogError(\"Failed to open group file '%s'!\", groupFilePath);\n\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open group file '%s'!\"), groupFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Copy group file to destination folder\n\t\t\t\tstd::string groupFileName{groupFilePath.AfterLast(wxFileName::GetPathSeparator()).ToUTF8()};\n\t\t\t\twxString groupFileDest = wxString::FromUTF8(dir + sep + baseDir + sep + \"SliderGroups\" + sep + groupFileName);\n\t\t\t\twxFileName::Mkdir(groupFileDest.BeforeLast(wxFileName::GetPathSeparator()), wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\t\t\t\tif (!wxCopyFile(groupFilePath, groupFileDest)) {\n\t\t\t\t\twxLogError(\"Failed to copy group file '%s'!\", groupFilePath);\n\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to copy group file '%s'!\"), groupFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tEndProgress(_(\"Packing finished.\"));\n\t\t});\n\n\t\tpackArchive->Bind(wxEVT_BUTTON, [&](wxCommandEvent& WXUNUSED(event)) {\n\t\t\twxString fileName = wxFileSelector(_(\"Packing projects to archive...\"), wxEmptyString, wxEmptyString, \".zip\", \"*.zip\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, packProjects);\n\t\t\tif (fileName.IsEmpty())\n\t\t\t\treturn;\n\n\t\t\twxLogMessage(\"Packing project to archive...\");\n\t\t\tStartProgress(_(\"Packing projects to archive...\"));\n\n\t\t\tstd::string mergedFile{wxString(mergedFileName->GetValue() + \".osp\").ToUTF8()};\n\t\t\tstd::string mergedFilePath{wxFileName::CreateTempFileName(\"os\").ToUTF8()};\n\t\t\tproject->ReplaceForbidden(mergedFile);\n\n\t\t\tSliderSetFile projectFile;\n\t\t\tprojectFile.New(mergedFilePath);\n\n\t\t\twxFFileOutputStream out(fileName);\n\t\t\twxZipOutputStream zip(out);\n\n\t\t\tfor (auto& setName : selectedProjects) {\n\t\t\t\tif (projectSources.find(setName) == projectSources.end())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tSliderSet set = projectSources[setName];\n\t\t\t\tprojectFile.UpdateSet(set);\n\n\t\t\t\t// Add input file to archive\n\t\t\t\twxString inputFilePath = wxString::FromUTF8(GetProjectPath() + sep + \"ShapeData\" + sep + set.GetInputFileName());\n\t\t\t\twxFileInputStream inputFileStream(inputFilePath);\n\t\t\t\tif (!inputFileStream.IsOk()) {\n\t\t\t\t\twxLogError(\"Failed to open input file '%s'!\", inputFilePath);\n\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open input file '%s'!\"), inputFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\twxString inputFileEntry = wxString::FromUTF8(baseDir + sep + \"ShapeData\" + sep + set.GetInputFileName());\n\t\t\t\tif (!zip.PutNextEntry(inputFileEntry, wxDateTime::Now(), inputFileStream.GetLength())) {\n\t\t\t\t\twxLogError(\"Failed to put new entry into archive!\");\n\t\t\t\t\twxMessageBox(_(\"Failed to put new entry into archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!CopyStreamData(inputFileStream, zip, inputFileStream.GetLength())) {\n\t\t\t\t\twxLogError(\"Failed to copy file contents to archive!\");\n\t\t\t\t\twxMessageBox(_(\"Failed to copy file contents to archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tstd::set<std::string> dataFiles;\n\n\t\t\t\tfor (size_t i = 0; i < set.size(); i++) {\n\t\t\t\t\tfor (auto it = set.ShapesBegin(); it != set.ShapesEnd(); ++it) {\n\t\t\t\t\t\tstd::string target = set.ShapeToTarget(it->first);\n\t\t\t\t\t\tstd::string targetDataName = set[i].TargetDataName(target);\n\t\t\t\t\t\tif (set[i].IsLocalData(targetDataName)) {\n\t\t\t\t\t\t\tstd::string dataFileName = set[i].DataFileName(targetDataName);\n\t\t\t\t\t\t\tif (dataFileName.compare(dataFileName.size() - 4, dataFileName.size(), \".bsd\") != 0) {\n\t\t\t\t\t\t\t\t// Split target file name to get OSD file name\n\t\t\t\t\t\t\t\tint split = dataFileName.find_last_of('/');\n\t\t\t\t\t\t\t\tif (split < 0)\n\t\t\t\t\t\t\t\t\tsplit = dataFileName.find_last_of('\\\\');\n\t\t\t\t\t\t\t\tif (split < 0)\n\t\t\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t\t\tdataFiles.insert(set.GetDefaultDataFolder() + sep + dataFileName.substr(0, split));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdataFiles.insert(set.GetDefaultDataFolder() + sep + dataFileName);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Add data files to archive\n\t\t\t\tfor (auto& df : dataFiles) {\n\t\t\t\t\twxString dataFilePath = wxString::FromUTF8(GetProjectPath() + sep + \"ShapeData\" + sep + df);\n\t\t\t\t\twxFileInputStream dataFileStream(dataFilePath);\n\t\t\t\t\tif (!dataFileStream.IsOk()) {\n\t\t\t\t\t\twxLogError(\"Failed to open data file '%s'!\", dataFilePath);\n\t\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open data file '%s'!\"), dataFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\t\tEndProgress();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\twxString dataFileEntry = wxString::FromUTF8(baseDir + sep + \"ShapeData\" + sep + df);\n\t\t\t\t\tif (!zip.PutNextEntry(dataFileEntry, wxDateTime::Now(), dataFileStream.GetLength())) {\n\t\t\t\t\t\twxLogError(\"Failed to put new entry into archive!\");\n\t\t\t\t\t\twxMessageBox(_(\"Failed to put new entry into archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\t\tEndProgress();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!CopyStreamData(dataFileStream, zip, dataFileStream.GetLength())) {\n\t\t\t\t\t\twxLogError(\"Failed to copy file contents to archive!\");\n\t\t\t\t\t\twxMessageBox(_(\"Failed to copy file contents to archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\t\tEndProgress();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Save new merged project file\n\t\t\tif (!projectFile.Save()) {\n\t\t\t\twxLogError(\"Failed to save merged project file '%s'!\", mergedFilePath);\n\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to save merged project file '%s'!\"), mergedFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add merged project file to archive\n\t\t\twxFileInputStream projectFileStream(mergedFilePath);\n\t\t\tif (!projectFileStream.IsOk()) {\n\t\t\t\twxLogError(\"Failed to open project file '%s'!\", mergedFilePath);\n\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open project file '%s'!\"), mergedFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twxString projectFileEntry = wxString::FromUTF8(baseDir + sep + \"SliderSets\" + sep + mergedFile);\n\t\t\tif (!zip.PutNextEntry(projectFileEntry, wxDateTime::Now(), projectFileStream.GetLength())) {\n\t\t\t\twxLogError(\"Failed to put new entry into archive!\");\n\t\t\t\twxMessageBox(_(\"Failed to put new entry into archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (!CopyStreamData(projectFileStream, zip, projectFileStream.GetLength())) {\n\t\t\t\twxLogError(\"Failed to copy file contents to archive!\");\n\t\t\t\twxMessageBox(_(\"Failed to copy file contents to archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\tEndProgress();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\twxString groupFilePath = groupFile->GetPath();\n\t\t\tif (!groupFilePath.IsEmpty()) {\n\t\t\t\t// Add group file to archive\n\t\t\t\twxFileInputStream groupFileStream(groupFilePath);\n\t\t\t\tif (!groupFileStream.IsOk()) {\n\t\t\t\t\twxLogError(\"Failed to open group file '%s'!\", groupFilePath);\n\t\t\t\t\twxMessageBox(wxString::Format(_(\"Failed to open group file '%s'!\"), groupFilePath), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tstd::string groupFileName{groupFilePath.AfterLast(wxFileName::GetPathSeparator()).ToUTF8()};\n\t\t\t\twxString groupFileEntry = wxString::FromUTF8(baseDir + sep + \"SliderGroups\" + sep + groupFileName);\n\t\t\t\tif (!zip.PutNextEntry(groupFileEntry, wxDateTime::Now(), groupFileStream.GetLength())) {\n\t\t\t\t\twxLogError(\"Failed to put new entry into archive!\");\n\t\t\t\t\twxMessageBox(_(\"Failed to put new entry into archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (!CopyStreamData(groupFileStream, zip, groupFileStream.GetLength())) {\n\t\t\t\t\twxLogError(\"Failed to copy file contents to archive!\");\n\t\t\t\t\twxMessageBox(_(\"Failed to copy file contents to archive!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\t\t\tEndProgress();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tEndProgress(_(\"Packing finished.\"));\n\t\t});\n\n\t\tpackProjects->ShowModal();\n\t}\n}\n\nvoid OutfitStudioFrame::OnChooseTargetGame(wxCommandEvent& event) {\n\twxChoice* choiceTargetGame = (wxChoice*)event.GetEventObject();\n\twxWindow* parent = choiceTargetGame->GetGrandParent();\n\twxFilePickerCtrl* fpSkeletonFile = XRCCTRL(*parent, \"fpSkeletonFile\", wxFilePickerCtrl);\n\twxChoice* choiceSkeletonRoot = XRCCTRL(*parent, \"choiceSkeletonRoot\", wxChoice);\n\n\tTargetGame targ = (TargetGame)choiceTargetGame->GetSelection();\n\tswitch (targ) {\n\t\tcase OB:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_ob.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Bip01\");\n\t\t\tbreak;\n\t\tcase FO3:\n\t\tcase FONV:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_fo3nv.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Bip01\");\n\t\t\tbreak;\n\t\tcase SKYRIM:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_female_sk.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"NPC Root [Root]\");\n\t\t\tbreak;\n\t\tcase SKYRIMSE:\n\t\tcase SKYRIMVR:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_female_sse.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"NPC Root [Root]\");\n\t\t\tbreak;\n\t\tcase SF:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_female_sf.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Root\");\n\t\t\tbreak;\n\t\tcase FO4:\n\t\tcase FO4VR:\n\t\tcase FO76:\n\t\tdefault:\n\t\t\tfpSkeletonFile->SetPath(\"res/skeleton_fo4.nif\");\n\t\t\tchoiceSkeletonRoot->SetStringSelection(\"Root\");\n\t\t\tbreak;\n\t}\n\n\twxCheckListBox* dataFileList = XRCCTRL(*parent, \"DataFileList\", wxCheckListBox);\n\twxString dataDir = wxGetApp().GetGameDataPath(targ);\n\n\twxDirPickerCtrl* dpGameDataPath = XRCCTRL(*parent, \"dpGameDataPath\", wxDirPickerCtrl);\n\tdpGameDataPath->SetPath(dataDir);\n\n\tSettingsFillDataFiles(dataFileList, dataDir, targ);\n}\n\nvoid OutfitStudioFrame::SettingsFillDataFiles(wxCheckListBox* dataFileList, wxString& dataDir, int targetGame) {\n\tdataFileList->Clear();\n\n\twxString cp = \"GameDataFiles/\" + TargetGames[targetGame];\n\twxString activatedFiles = Config[cp];\n\n\twxStringTokenizer tokenizer(activatedFiles, \";\");\n\tstd::map<wxString, bool> fsearch;\n\twhile (tokenizer.HasMoreTokens()) {\n\t\twxString val = tokenizer.GetNextToken().Trim(false).Trim();\n\t\tval.MakeLower();\n\t\tfsearch[val] = true;\n\t}\n\n\twxArrayString files;\n\twxDir::GetAllFiles(dataDir, &files, \"*.ba2\", wxDIR_FILES);\n\twxDir::GetAllFiles(dataDir, &files, \"*.bsa\", wxDIR_FILES);\n\tfor (auto& file : files) {\n\t\tfile = file.AfterLast('/').AfterLast('\\\\');\n\t\tdataFileList->Insert(file, dataFileList->GetCount());\n\n\t\tif (fsearch.find(file.Lower()) == fsearch.end())\n\t\t\tdataFileList->Check(dataFileList->GetCount() - 1);\n\t}\n}\n\nvoid OutfitStudioFrame::OnSettings(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\twxDialog* settings = wxXmlResource::Get()->LoadDialog(this, \"dlgSettings\");\n\tif (settings) {\n\t\tsettings->SetSize(settings->FromDIP(wxSize(525, -1)));\n\t\tsettings->SetMinSize(settings->FromDIP(wxSize(525, -1)));\n\t\tsettings->CenterOnParent();\n\n\t\twxCollapsiblePane* advancedPane = XRCCTRL(*settings, \"advancedPane\", wxCollapsiblePane);\n\t\tadvancedPane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [&settings](wxCommandEvent&) { settings->Fit(); });\n\n\t\twxChoice* choiceTargetGame = XRCCTRL(*settings, \"choiceTargetGame\", wxChoice);\n\t\tchoiceTargetGame->Select(Config.GetIntValue(\"TargetGame\"));\n\n\t\twxDirPickerCtrl* dpGameDataPath = XRCCTRL(*settings, \"dpGameDataPath\", wxDirPickerCtrl);\n\t\twxString gameDataPath = wxString::FromUTF8(Config[\"GameDataPath\"]);\n\t\tdpGameDataPath->SetPath(gameDataPath);\n\n\t\twxDirPickerCtrl* dpOutputPath = XRCCTRL(*settings, \"dpOutputPath\", wxDirPickerCtrl);\n\t\twxString outputPath = wxString::FromUTF8(Config[\"OutputDataPath\"]);\n\t\tdpOutputPath->SetPath(outputPath);\n\n\t\twxDirPickerCtrl* dpProjectPath = XRCCTRL(*settings, \"dpProjectPath\", wxDirPickerCtrl);\n\t\twxString projectPath = wxString::FromUTF8(Config[\"ProjectPath\"]);\n\t\tdpProjectPath->SetPath(projectPath);\n\n\t\twxCheckBox* cbShowForceBodyNormals = XRCCTRL(*settings, \"cbShowForceBodyNormals\", wxCheckBox);\n\t\tcbShowForceBodyNormals->SetValue(Config.GetBoolValue(\"ShowForceBodyNormals\"));\n\n\t\twxCheckBox* cbBBOverrideWarn = XRCCTRL(*settings, \"cbBBOverrideWarn\", wxCheckBox);\n\t\tcbBBOverrideWarn->SetValue(Config.GetBoolValue(\"WarnBatchBuildOverride\"));\n\n\t\twxCheckBox* cbBSATextures = XRCCTRL(*settings, \"cbBSATextures\", wxCheckBox);\n\t\tcbBSATextures->SetValue(Config.GetBoolValue(\"BSATextureScan\"));\n\n\t\twxCheckBox* cbLeftMousePan = XRCCTRL(*settings, \"cbLeftMousePan\", wxCheckBox);\n\t\tcbLeftMousePan->SetValue(Config.GetBoolValue(\"Input/LeftMousePan\"));\n\n\t\twxCheckBox* cbBrushSettingsNearCursor = XRCCTRL(*settings, \"cbBrushSettingsNearCursor\", wxCheckBox);\n\t\tcbBrushSettingsNearCursor->SetValue(Config.GetBoolValue(\"Input/BrushSettingsNearCursor\"));\n\n\t\twxCheckBox* cbMaskHistory = XRCCTRL(*settings, \"cbMaskHistory\", wxCheckBox);\n\t\tcbMaskHistory->SetValue(Config.GetBoolValue(\"Input/MaskHistory\"));\n\n\t\twxChoice* choiceSingleInstanceBehavior = XRCCTRL(*settings, \"choiceSingleInstanceBehavior\", wxChoice);\n\t\tchoiceSingleInstanceBehavior->SetSelection(OutfitStudioConfig.GetIntValue(\"SingleInstanceBehavior\", 0));\n\n\t\twxChoice* choiceLanguage = XRCCTRL(*settings, \"choiceLanguage\", wxChoice);\n\t\tfor (size_t i = 0; i < SupportedLangs.size(); i++)\n\t\t\tchoiceLanguage->AppendString(wxLocale::GetLanguageName(SupportedLangs[i]));\n\n\t\tif (!choiceLanguage->SetStringSelection(wxLocale::GetLanguageName(Config.GetIntValue(\"Language\"))))\n\t\t\tchoiceLanguage->SetStringSelection(\"English\");\n\n\t\twxCheckBox* cbPerspectiveView = XRCCTRL(*settings, \"cbPerspectiveView\", wxCheckBox);\n\t\tcbPerspectiveView->SetValue(OutfitStudioConfig.GetBoolValue(\"Rendering/PerspectiveView\", true));\n\n\t\twxColourPickerCtrl* cpColorBackground = XRCCTRL(*settings, \"cpColorBackground\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorBackground\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorBackground.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorBackground.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorBackground.b\");\n\t\t\tcpColorBackground->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxColourPickerCtrl* cpColorWire = XRCCTRL(*settings, \"cpColorWire\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorWire\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorWire.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorWire.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorWire.b\");\n\t\t\tcpColorWire->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxColourPickerCtrl* cpColorPoints = XRCCTRL(*settings, \"cpColorPoints\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorPoints\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPoints.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPoints.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPoints.b\");\n\t\t\tcpColorPoints->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxColourPickerCtrl* cpColorPointsMasked = XRCCTRL(*settings, \"cpColorPointsMasked\", wxColourPickerCtrl);\n\t\tif (Config.Exists(\"Rendering/ColorPointsMasked\")) {\n\t\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPointsMasked.r\");\n\t\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPointsMasked.g\");\n\t\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPointsMasked.b\");\n\t\t\tcpColorPointsMasked->SetColour(wxColour(colorR, colorG, colorB));\n\t\t}\n\n\t\twxFilePickerCtrl* fpSkeletonFile = XRCCTRL(*settings, \"fpSkeletonFile\", wxFilePickerCtrl);\n\t\tfpSkeletonFile->SetPath(wxString::FromUTF8(Config[\"Anim/DefaultSkeletonReference\"]));\n\n\t\twxChoice* choiceSkeletonRoot = XRCCTRL(*settings, \"choiceSkeletonRoot\", wxChoice);\n\t\tchoiceSkeletonRoot->SetStringSelection(Config[\"Anim/SkeletonRootName\"]);\n\n\t\twxCheckListBox* dataFileList = XRCCTRL(*settings, \"DataFileList\", wxCheckListBox);\n\t\tSettingsFillDataFiles(dataFileList, gameDataPath, Config.GetIntValue(\"TargetGame\"));\n\n\t\tchoiceTargetGame->Bind(wxEVT_CHOICE, &OutfitStudioFrame::OnChooseTargetGame, this);\n\n\t\tif (settings->ShowModal() == wxID_OK) {\n\t\t\tTargetGame targ = (TargetGame)choiceTargetGame->GetSelection();\n\t\t\tConfig.SetValue(\"TargetGame\", targ);\n\n\t\t\tif (!dpGameDataPath->GetPath().IsEmpty()) {\n\t\t\t\twxFileName gameDataDir = dpGameDataPath->GetDirName();\n\t\t\t\tConfig.SetValue(\"GameDataPath\", gameDataDir.GetFullPath().ToUTF8().data());\n\t\t\t\tConfig.SetValue(\"GameDataPaths/\" + TargetGames[targ].ToStdString(), gameDataDir.GetFullPath().ToUTF8().data());\n\t\t\t}\n\n\t\t\t// set OutputDataPath even if it is empty\n\t\t\twxFileName outputDataDir = dpOutputPath->GetDirName();\n\t\t\tConfig.SetValue(\"OutputDataPath\", outputDataDir.GetFullPath().ToUTF8().data());\n\n\t\t\t// set ProjectPath even if it is empty\n\t\t\twxFileName projectDir = dpProjectPath->GetDirName();\n\t\t\tConfig.SetValue(\"ProjectPath\", projectDir.GetFullPath().ToUTF8().data());\n\n\t\t\twxArrayInt items;\n\t\t\twxString selectedfiles;\n\t\t\tfor (uint32_t i = 0; i < dataFileList->GetCount(); i++)\n\t\t\t\tif (!dataFileList->IsChecked(i))\n\t\t\t\t\tselectedfiles += dataFileList->GetString(i) + \"; \";\n\n\t\t\tselectedfiles = selectedfiles.BeforeLast(';');\n\t\t\tConfig.SetValue(\"GameDataFiles/\" + TargetGames[targ].ToStdString(), selectedfiles.ToUTF8().data());\n\n\t\t\tConfig.SetBoolValue(\"ShowForceBodyNormals\", cbShowForceBodyNormals->IsChecked());\n\t\t\tConfig.SetBoolValue(\"WarnBatchBuildOverride\", cbBBOverrideWarn->IsChecked());\n\t\t\tConfig.SetBoolValue(\"BSATextureScan\", cbBSATextures->IsChecked());\n\t\t\tConfig.SetBoolValue(\"Input/LeftMousePan\", cbLeftMousePan->IsChecked());\n\t\t\tConfig.SetBoolValue(\"Input/BrushSettingsNearCursor\", cbBrushSettingsNearCursor->IsChecked());\n\t\t\tConfig.SetBoolValue(\"Input/MaskHistory\", cbMaskHistory->IsChecked());\n\n\t\t\tOutfitStudioConfig.SetValue(\"SingleInstanceBehavior\", choiceSingleInstanceBehavior->GetSelection());\n\t\t\tOutfitStudioConfig.SaveConfig(Config[\"AppDir\"] + \"/OutfitStudio.xml\", \"OutfitStudioConfig\");\n\n\t\t\tint oldLang = Config.GetIntValue(\"Language\");\n\t\t\tint newLang = SupportedLangs[choiceLanguage->GetSelection()];\n\t\t\tif (oldLang != newLang) {\n\t\t\t\tConfig.SetValue(\"Language\", newLang);\n\t\t\t\twxGetApp().InitLanguage();\n\t\t\t}\n\n\t\t\tOutfitStudioConfig.SetBoolValue(\"Rendering/PerspectiveView\", cbPerspectiveView->IsChecked());\n\n\t\t\twxColour colorBackground = cpColorBackground->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorBackground.r\", colorBackground.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorBackground.g\", colorBackground.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorBackground.b\", colorBackground.Blue());\n\t\t\tif (glView)\n\t\t\t\tglView->gls.SetBackgroundColor(Vector3(colorBackground.Red() / 255.0f, colorBackground.Green() / 255.0f, colorBackground.Blue() / 255.0f));\n\n\t\t\twxColour colorWire = cpColorWire->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorWire.r\", colorWire.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorWire.g\", colorWire.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorWire.b\", colorWire.Blue());\n\t\t\tif (glView)\n\t\t\t\tglView->gls.SetWireColor(Vector3(colorWire.Red() / 255.0f, colorWire.Green() / 255.0f, colorWire.Blue() / 255.0f));\n\n\t\t\twxColour colorPoints = cpColorPoints->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorPoints.r\", colorPoints.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorPoints.g\", colorPoints.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorPoints.b\", colorPoints.Blue());\n\t\t\tif (glView)\n\t\t\t\tglView->gls.SetPointColor(Vector3(colorPoints.Red() / 255.0f, colorPoints.Green() / 255.0f, colorPoints.Blue() / 255.0f));\n\n\t\t\twxColour colorPointsMasked = cpColorPointsMasked->GetColour();\n\t\t\tConfig.SetValue(\"Rendering/ColorPointsMasked.r\", colorPointsMasked.Red());\n\t\t\tConfig.SetValue(\"Rendering/ColorPointsMasked.g\", colorPointsMasked.Green());\n\t\t\tConfig.SetValue(\"Rendering/ColorPointsMasked.b\", colorPointsMasked.Blue());\n\t\t\tif (glView)\n\t\t\t\tglView->gls.SetMaskedPointColor(Vector3(colorPointsMasked.Red() / 255.0f, colorPointsMasked.Green() / 255.0f, colorPointsMasked.Blue() / 255.0f));\n\n\t\t\twxFileName skeletonFile = fpSkeletonFile->GetFileName();\n\t\t\tConfig.SetValue(\"Anim/DefaultSkeletonReference\", skeletonFile.GetFullPath().ToUTF8().data());\n\t\t\tConfig.SetValue(\"Anim/SkeletonRootName\", choiceSkeletonRoot->GetStringSelection().ToUTF8().data());\n\n\t\t\tConfig.SaveConfig(Config[\"AppDir\"] + \"/Config.xml\");\n\t\t\twxGetApp().InitArchives();\n\t\t}\n\n\t\tdelete settings;\n\t}\n}\n\nvoid OutfitStudioFrame::OnSashPosChanged(wxSplitterEvent& event) {\n\tif (!IsVisible())\n\t\treturn;\n\n\tint pos = event.GetSashPosition();\n\tif (event.GetId() == XRCID(\"splitter\"))\n\t\tOutfitStudioConfig.SetValue(\"OutfitStudioFrame.sashpos\", pos);\n\telse if (event.GetId() == XRCID(\"splitterRight\"))\n\t\tOutfitStudioConfig.SetValue(\"OutfitStudioFrame.sashrightpos\", pos);\n}\n\nvoid OutfitStudioFrame::OnMoveWindowStart(wxMoveEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n}\n\nvoid OutfitStudioFrame::OnMoveWindowEnd(wxMoveEvent& event) {\n\twxPoint p = GetPosition();\n\tOutfitStudioConfig.SetValue(\"OutfitStudioFrame.x\", p.x);\n\tOutfitStudioConfig.SetValue(\"OutfitStudioFrame.y\", p.y);\n\tevent.Skip();\n}\n\nvoid OutfitStudioFrame::OnSetSize(wxSizeEvent& event) {\n\tCloseBrushSettings();\n\n\tbool maximized = IsMaximized();\n\tif (!maximized) {\n\t\twxSize p = event.GetSize();\n\t\tOutfitStudioConfig.SetValue(\"OutfitStudioFrame.width\", p.x);\n\t\tOutfitStudioConfig.SetValue(\"OutfitStudioFrame.height\", p.y);\n\t}\n\n\tOutfitStudioConfig.SetBoolValue(\"OutfitStudioFrame.maximized\", maximized);\n\tevent.Skip();\n}\n\nbool OutfitStudioFrame::SaveProject() {\n\tif (project->mFileName.empty())\n\t\treturn SaveProjectAs();\n\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn false;\n\t}\n\n\tif (HasUnweightedCheck())\n\t\treturn false;\n\n\twxLogMessage(\"Saving project '%s'...\", wxString::FromUTF8(project->OutfitName()));\n\tStartProgress(wxString::Format(_(\"Saving project '%s'...\"), wxString::FromUTF8(project->OutfitName())));\n\n\tstd::vector<Mesh*> shapeMeshes;\n\tfor (auto& s : project->GetWorkNif()->GetShapes()) {\n\t\tif (!project->IsBaseShape(s)) {\n\t\t\tMesh* m = glView->GetMesh(s->name.get());\n\t\t\tif (m)\n\t\t\t\tshapeMeshes.push_back(m);\n\t\t}\n\t}\n\n\tproject->UpdateNifNormals(project->GetWorkNif(), shapeMeshes);\n\n\tif (projectNotes)\n\t\tproject->activeSet.SetNotes(projectNotes->GetValue().ToUTF8().data());\n\n\tstd::string error = project->Save(project->mFileName,\n\t\t\t\t\t\t\t\t\t  project->mOutfitName,\n\t\t\t\t\t\t\t\t\t  project->mDataDir,\n\t\t\t\t\t\t\t\t\t  project->mBaseFile,\n\t\t\t\t\t\t\t\t\t  project->mGamePath,\n\t\t\t\t\t\t\t\t\t  project->mGameFile,\n\t\t\t\t\t\t\t\t\t  project->mGenWeights,\n\t\t\t\t\t\t\t\t\t  project->mCopyRef,\n\t\t\t\t\t\t\t\t\t  project->bPreventMorphFile,\n\t\t\t\t\t\t\t\t\t  project->bKeepZappedShapes);\n\n\tif (!error.empty()) {\n\t\twxLogError(error.c_str());\n\t\twxMessageBox(error, _(\"Error\"), wxOK | wxICON_ERROR);\n\t\tEndProgress(_(\"Saving failed.\"));\n\t\treturn false;\n\t}\n\n\tSetPendingChanges(false);\n\tEndProgress(_(\"Saved.\"));\n\treturn true;\n}\n\nbool OutfitStudioFrame::SaveProjectAs() {\n\twxDialog dlg;\n\tint result = wxID_CANCEL;\n\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn false;\n\t}\n\n\tif (HasUnweightedCheck())\n\t\treturn false;\n\n\tCloseBrushSettings();\n\n\tif (wxXmlResource::Get()->LoadObject((wxObject*)&dlg, this, \"dlgSaveProject\", \"wxDialog\")) {\n\t\tXRCCTRL(dlg, \"sssNameCopy\", wxButton)->Bind(wxEVT_BUTTON, &OutfitStudioFrame::OnSSSNameCopy, this);\n\t\tXRCCTRL(dlg, \"sssGenWeightsTrue\", wxRadioButton)->Bind(wxEVT_RADIOBUTTON, &OutfitStudioFrame::OnSSSGenWeightsTrue, this);\n\t\tXRCCTRL(dlg, \"sssGenWeightsFalse\", wxRadioButton)->Bind(wxEVT_RADIOBUTTON, &OutfitStudioFrame::OnSSSGenWeightsFalse, this);\n\n\t\tstd::string outName;\n\t\tif (!project->mOutfitName.empty())\n\t\t\toutName = project->mOutfitName.ToUTF8();\n\t\telse if (!project->OutfitName().empty())\n\t\t\toutName = project->OutfitName();\n\t\telse\n\t\t\toutName = \"New Outfit\";\n\n\t\tproject->ReplaceForbidden(outName);\n\n\t\twxString sssName = wxString::FromUTF8(outName);\n\n\t\tXRCCTRL(dlg, \"sssName\", wxTextCtrl)->SetValue(sssName);\n\t\tXRCCTRL(dlg, \"sssSliderSetFile\", wxFilePickerCtrl)->SetInitialDirectory(wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\");\n\n\t\tif (!project->mFileName.empty())\n\t\t\tXRCCTRL(dlg, \"sssSliderSetFile\", wxFilePickerCtrl)->SetPath(project->mFileName);\n\t\telse\n\t\t\tXRCCTRL(dlg, \"sssSliderSetFile\", wxFilePickerCtrl)->SetPath(sssName + \".osp\");\n\n\t\tif (!project->mDataDir.empty())\n\t\t\tXRCCTRL(dlg, \"sssShapeDataFolder\", wxDirPickerCtrl)->SetPath(project->mDataDir);\n\t\telse\n\t\t\tXRCCTRL(dlg, \"sssShapeDataFolder\", wxDirPickerCtrl)->SetPath(sssName);\n\n\t\tif (!project->mBaseFile.empty())\n\t\t\tXRCCTRL(dlg, \"sssShapeDataFile\", wxFilePickerCtrl)->SetPath(project->mBaseFile);\n\t\telse\n\t\t\tXRCCTRL(dlg, \"sssShapeDataFile\", wxFilePickerCtrl)->SetPath(sssName + \".nif\");\n\n\t\tif (!project->mGamePath.empty())\n\t\t\tXRCCTRL(dlg, \"sssOutputDataPath\", wxTextCtrl)->ChangeValue(project->mGamePath);\n\t\telse\n\t\t\tXRCCTRL(dlg, \"sssOutputDataPath\", wxTextCtrl)->ChangeValue(wxString::Format(\"meshes%carmor%c%s\", PathSepChar, PathSepChar, sssName));\n\n\t\tif (!project->mGameFile.empty())\n\t\t\tXRCCTRL(dlg, \"sssOutputFileName\", wxTextCtrl)->ChangeValue(project->mGameFile);\n\t\telse\n\t\t\tXRCCTRL(dlg, \"sssOutputFileName\", wxTextCtrl)->ChangeValue(sssName);\n\n\t\tif (project->mGenWeights) {\n\t\t\tXRCCTRL(dlg, \"sssGenWeightsTrue\", wxRadioButton)->SetValue(true);\n\t\t\tXRCCTRL(dlg, \"sssGenWeightsFalse\", wxRadioButton)->SetValue(false);\n\t\t}\n\t\telse {\n\t\t\tXRCCTRL(dlg, \"sssGenWeightsTrue\", wxRadioButton)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"sssGenWeightsFalse\", wxRadioButton)->SetValue(true);\n\t\t}\n\n\t\tXRCCTRL(dlg, \"sssPreventMorphFile\", wxCheckBox)->SetValue(project->bPreventMorphFile);\n\t\tXRCCTRL(dlg, \"sssKeepZappedShapes\", wxCheckBox)->SetValue(project->bKeepZappedShapes);\n\n\t\tif (!project->GetBaseShape()) {\n\t\t\tXRCCTRL(dlg, \"sssAutoCopyRef\", wxCheckBox)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"sssAutoCopyRef\", wxCheckBox)->Disable();\n\t\t}\n\t\telse\n\t\t\tXRCCTRL(dlg, \"sssAutoCopyRef\", wxCheckBox)->SetValue(project->mCopyRef);\n\n\t\tresult = dlg.ShowModal();\n\t}\n\tif (result == wxID_CANCEL)\n\t\treturn false;\n\n\twxString strOutfitName;\n\twxString strDataDir;\n\twxString strBaseFile;\n\twxString strGamePath;\n\twxString strGameFile;\n\n\twxFileName sliderSetFile = XRCCTRL(dlg, \"sssSliderSetFile\", wxFilePickerCtrl)->GetFileName();\n\tif (!sliderSetFile.IsOk()) {\n\t\twxMessageBox(_(\"Invalid or no slider set file specified! Please try again.\"), _(\"Error\"), wxOK | wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\tif (sliderSetFile.GetExt() != \"osp\")\n\t\tsliderSetFile.SetExt(\"osp\");\n\n\tstrOutfitName = XRCCTRL(dlg, \"sssName\", wxTextCtrl)->GetValue();\n\tif (strOutfitName.empty()) {\n\t\twxMessageBox(_(\"No outfit name specified! Please try again.\"), _(\"Error\"), wxOK | wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\tstrDataDir = XRCCTRL(dlg, \"sssShapeDataFolder\", wxDirPickerCtrl)->GetDirName().GetFullName();\n\tif (strDataDir.empty()) {\n\t\tstrDataDir = XRCCTRL(dlg, \"sssShapeDataFolder\", wxDirPickerCtrl)->GetPath();\n\t\tif (strDataDir.empty()) {\n\t\t\twxMessageBox(_(\"No data folder specified! Please try again.\"), _(\"Error\"), wxOK | wxICON_ERROR);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\twxFileName relativeFolder(strDataDir);\n\tif (!relativeFolder.IsRelative()) {\n\t\twxString dataFolder(wxString::Format(\"%s/%s\", wxString::FromUTF8(GetProjectPath()), \"ShapeData\"));\n\t\trelativeFolder.MakeRelativeTo(dataFolder);\n\t\tstrDataDir = relativeFolder.GetFullPath();\n\t}\n\n\tstrBaseFile = XRCCTRL(dlg, \"sssShapeDataFile\", wxFilePickerCtrl)->GetFileName().GetFullName();\n\tif (strBaseFile.length() <= 4) {\n\t\twxMessageBox(_(\"An invalid or no base outfit .nif file name specified! Please try again.\"), _(\"Error\"), wxOK | wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\tif (!strBaseFile.EndsWith(\".nif\"))\n\t\tstrBaseFile = strBaseFile.Append(\".nif\");\n\n\tstrGamePath = XRCCTRL(dlg, \"sssOutputDataPath\", wxTextCtrl)->GetValue();\n\tif (strGamePath.empty()) {\n\t\twxMessageBox(_(\"No game file path specified! Please try again.\"), _(\"Error\"), wxOK | wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\tstrGameFile = XRCCTRL(dlg, \"sssOutputFileName\", wxTextCtrl)->GetValue();\n\tif (strGameFile.empty()) {\n\t\twxMessageBox(_(\"No game file name specified! Please try again.\"), _(\"Error\"), wxOK | wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\tbool copyRef = XRCCTRL(dlg, \"sssAutoCopyRef\", wxCheckBox)->GetValue();\n\tbool genWeights = XRCCTRL(dlg, \"sssGenWeightsTrue\", wxRadioButton)->GetValue();\n\tbool preventMorphFile = XRCCTRL(dlg, \"sssPreventMorphFile\", wxCheckBox)->GetValue();\n\tbool keepZappedShapes = XRCCTRL(dlg, \"sssKeepZappedShapes\", wxCheckBox)->GetValue();\n\n\twxLogMessage(\"Saving project '%s'...\", strOutfitName);\n\tStartProgress(wxString::Format(_(\"Saving project '%s'...\"), strOutfitName));\n\n\tstd::vector<Mesh*> shapeMeshes;\n\tfor (auto& s : project->GetWorkNif()->GetShapes()) {\n\t\tif (!project->IsBaseShape(s)) {\n\t\t\tMesh* m = glView->GetMesh(s->name.get());\n\t\t\tif (m)\n\t\t\t\tshapeMeshes.push_back(m);\n\t\t}\n\t}\n\n\tproject->UpdateNifNormals(project->GetWorkNif(), shapeMeshes);\n\n\tif (projectNotes)\n\t\tproject->activeSet.SetNotes(projectNotes->GetValue().ToUTF8().data());\n\n\tstd::string error = project->Save(sliderSetFile, strOutfitName, strDataDir, strBaseFile, strGamePath, strGameFile, genWeights, copyRef, preventMorphFile, keepZappedShapes);\n\n\tif (error.empty()) {\n\t\tSetPendingChanges(false);\n\t\tmenuBar->Enable(XRCID(\"fileSave\"), true);\n\n\t\tRenameProject(strOutfitName.ToUTF8().data());\n\t\tEndProgress(_(\"Saved.\"));\n\t}\n\telse {\n\t\twxLogError(error.c_str());\n\t\twxMessageBox(error, _(\"Error\"), wxOK | wxICON_ERROR);\n\t\tEndProgress(_(\"Saving failed.\"));\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool OutfitStudioFrame::LoadProject(const std::string& fileName, const std::string& projectName, bool clearProject) {\n\tstd::vector<std::string> setnames;\n\tSliderSetFile InFile(fileName);\n\tif (InFile.fail()) {\n\t\twxLogError(\"Failed to open '%s' as a slider set file!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Failed to open '%s' as a slider set file!\"), fileName), _(\"Slider Set Error\"), wxICON_ERROR);\n\t\treturn false;\n\t}\n\n\tstd::string outfit;\n\tInFile.GetSetNames(setnames);\n\n\tif (!projectName.empty()) {\n\t\tauto it = std::find(setnames.begin(), setnames.end(), projectName);\n\t\tif (it != setnames.end())\n\t\t\toutfit = projectName;\n\t}\n\n\tif (outfit.empty()) {\n\t\twxArrayString choices;\n\t\tfor (auto& s : setnames)\n\t\t\tchoices.Add(wxString::FromUTF8(s));\n\n\t\tif (choices.GetCount() > 1) {\n\t\t\toutfit = wxGetSingleChoice(_(\"Please choose an outfit to load\"), _(\"Load a slider set\"), choices, 0, this).ToUTF8();\n\t\t\tif (outfit.empty())\n\t\t\t\treturn false;\n\t\t}\n\t\telse if (choices.GetCount() == 1)\n\t\t\toutfit = choices.front().ToUTF8();\n\t\telse\n\t\t\treturn false;\n\t}\n\n\twxLogMessage(\"Loading project '%s' from file '%s'...\", outfit, fileName);\n\tStartProgress(_(\"Loading project...\"));\n\n\tif (clearProject) {\n\t\tClearProject();\n\t\tproject->ClearReference();\n\t\tproject->ClearOutfit();\n\n\t\tglView->Cleanup();\n\t\tglView->GetUndoHistory()->ClearHistory();\n\n\t\tactiveSlider.clear();\n\t\tlastActiveSlider.clear();\n\t\tbEditSlider = false;\n\t\tMenuExitSliderEdit();\n\n\t\tdelete project;\n\t\tproject = new OutfitProject(this);\n\t}\n\n\twxLogMessage(\"Loading outfit data...\");\n\tUpdateProgress(10, _(\"Loading outfit data...\"));\n\tStartSubProgress(10, 40);\n\n\tint error = 0;\n\tstd::vector<std::string> origShapeOrder;\n\n\tif (clearProject)\n\t\terror = project->LoadFromSliderSet(fileName, outfit, &origShapeOrder);\n\telse\n\t\terror = project->AddFromSliderSet(fileName, outfit);\n\n\tif (error) {\n\t\tEndProgress();\n\t\twxLogError(\"Failed to create project (%d)!\", error);\n\t\twxMessageBox(wxString::Format(_(\"Failed to create project '%s' from file '%s' (%d)!\"), outfit, fileName, error), _(\"Slider Set Error\"), wxICON_ERROR);\n\t\tRefreshGUIFromProj();\n\t\treturn false;\n\t}\n\n\tif (clearProject) {\n\t\tNiShape* shape = project->GetBaseShape();\n\t\tif (shape) {\n\t\t\tstd::string shapeName = shape->name.get();\n\n\t\t\t// Prevent duplication if valid reference was found\n\t\t\tproject->DeleteShape(shape);\n\n\t\t\twxLogMessage(\"Loading reference shape '%s'...\", shapeName);\n\t\t\tUpdateProgress(50, wxString::Format(_(\"Loading reference shape '%s'...\"), shapeName));\n\n\t\t\terror = project->LoadReferenceNif(project->activeSet.GetInputFileName(), shapeName, true, true);\n\t\t\tif (error) {\n\t\t\t\tEndProgress();\n\t\t\t\tRefreshGUIFromProj();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tproject->GetWorkNif()->SetShapeOrder(origShapeOrder);\n\t}\n\n\twxLogMessage(\"Loading textures...\");\n\tUpdateProgress(60, _(\"Loading textures...\"));\n\n\tproject->SetTextures();\n\n\twxLogMessage(\"Creating outfit...\");\n\tUpdateProgress(80, _(\"Creating outfit...\"));\n\tRefreshGUIFromProj();\n\n\twxLogMessage(\"Creating %zu slider(s)...\", project->SliderCount());\n\tUpdateProgress(90, wxString::Format(_(\"Creating %zu slider(s)...\"), project->SliderCount()));\n\tStartSubProgress(90, 99);\n\tCreateSetSliders();\n\n\tif (projectNotes && notesPane) {\n\t\twxString notesText = wxString::FromUTF8(project->activeSet.GetNotes());\n\t\tprojectNotes->SetValue(notesText);\n\t\tnotesPane->Collapse(notesText.empty());\n\n\t\twxWindow* parentPanel = FindWindowByName(\"bottomSplitPanel\");\n\t\tif (parentPanel)\n\t\t\tparentPanel->Layout();\n\t}\n\n\tUpdateTitle();\n\tAddProjectHistory(fileName, outfit);\n\n\twxLogMessage(\"Project loaded.\");\n\tmenuBar->Enable(XRCID(\"fileSave\"), true);\n\tEndProgress();\n\treturn true;\n}\n\nvoid OutfitStudioFrame::CreateSetSliders() {\n\twxSizer* rootSz = sliderScroll->GetSizer();\n\n\tint inc = 1;\n\tif (project->SliderCount()) {\n\t\tinc = 90 / project->SliderCount();\n\t\tStartProgress(_(\"Creating sliders...\"));\n\t}\n\n\tUpdateProgress(0, _(\"Clearing old sliders...\"));\n\n\tsliderScroll->Freeze();\n\n\tfor (auto& sliderPanel : sliderPanels)\n\t\tHideSliderPanel(sliderPanel.second);\n\n\tsliderPanels.clear();\n\tsliderFilter->Clear();\n\n\tfor (size_t i = 0; i < project->SliderCount(); i++) {\n\t\tUpdateProgress(inc, _(\"Loading slider: \") + project->GetSliderName(i));\n\t\tif (project->SliderClamp(i)) // clamp sliders are a special case, usually an incorrect scale\n\t\t\tcontinue;\n\n\t\tcreateSliderGUI(project->GetSliderName(i), sliderScroll, rootSz);\n\t}\n\n\tif (!sliderScroll->GetDropTarget())\n\t\tsliderScroll->SetDropTarget(new DnDSliderFile(this));\n\n\tsliderScroll->FitInside();\n\tsliderScroll->Thaw();\n\n\tDoFilterSliders();\n\tHighlightSliderData();\n\n\tEndProgress();\n}\n\nvoid OutfitStudioFrame::createSliderGUI(const std::string& name, wxScrolledWindow* wnd, wxSizer* rootSz) {\n\twxString sliderName = wxString::FromUTF8(name);\n\n\twxSliderPanel* sliderPanel = sliderPool.GetNext();\n\tif (sliderPanel) {\n\t\tint minValue = Config.GetIntValue(\"Input/SliderMinimum\");\n\t\tint maxValue = Config.GetIntValue(\"Input/SliderMaximum\");\n\n\t\tif (sliderPanel->Create(wnd, sliderName, minValue, maxValue, *bmpEditSlider, *bmpSliderSettings)) {\n\t\t\t// Hover enter\n\t\t\tsliderPanel->btnSliderEdit->Bind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\t\t\tsliderPanel->sliderCheck->Bind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\t\t\tsliderPanel->sliderName->Bind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\t\t\tsliderPanel->slider->Bind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\t\t\tsliderPanel->sliderReadout->Bind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\n\t\t\t// Hover leave\n\t\t\tsliderPanel->btnSliderEdit->Bind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\t\t\tsliderPanel->sliderCheck->Bind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\t\t\tsliderPanel->sliderName->Bind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\t\t\tsliderPanel->slider->Bind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\t\t\tsliderPanel->sliderReadout->Bind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\n\t\t\tsliderPanel->btnSliderEdit->Bind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\t\t\tsliderPanel->btnSliderProp->Bind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\t\t\tsliderPanel->btnMinus->Bind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\t\t\tsliderPanel->btnPlus->Bind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\t\t\tsliderPanel->sliderCheck->Bind(wxEVT_CHECKBOX, &OutfitStudioFrame::OnSliderCheckBox, this);\n\t\t\tsliderPanel->slider->Bind(wxEVT_SLIDER, &OutfitStudioFrame::OnSlider, this);\n\t\t\tsliderPanel->sliderReadout->Bind(wxEVT_TEXT, &OutfitStudioFrame::OnReadoutChange, this);\n\n\t\t\tif (sliderPanel->GetContainingSizer())\n\t\t\t\trootSz->Detach(sliderPanel);\n\n\t\t\trootSz->Add(sliderPanel, 0, wxALL | wxEXPAND | wxFIXED_MINSIZE, 1);\n\n\t\t\tif (!sliderPanel->IsShown())\n\t\t\t\tsliderPanel->Show();\n\n\t\t\tsliderPanels[name] = sliderPanel;\n\t\t\tShowSliderEffect(name);\n\t\t}\n\t}\n}\n\nstd::string OutfitStudioFrame::NewSlider(const std::string& suggestedName, bool skipPrompt) {\n\tstd::string baseName = \"New Slider\";\n\tif (!suggestedName.empty())\n\t\tbaseName = suggestedName;\n\n\tint count = 1;\n\tstd::string fillName = baseName;\n\n\twhile (project->ValidSlider(fillName))\n\t\tfillName = wxString::Format(\"%s %d\", baseName, ++count).ToUTF8();\n\n\tstd::string sliderName;\n\tif (!skipPrompt) {\n\t\tdo {\n\t\t\tsliderName = wxGetTextFromUser(_(\"Enter a name for the new slider:\"), _(\"Create New Slider\"), fillName, this).ToUTF8();\n\t\t\tif (sliderName.empty())\n\t\t\t\treturn sliderName;\n\t\t} while (project->ValidSlider(sliderName));\n\t}\n\telse\n\t\tsliderName = fillName;\n\n\twxLogMessage(\"Creating new slider '%s'.\", sliderName);\n\n\tproject->AddEmptySlider(sliderName);\n\tcreateSliderGUI(sliderName, sliderScroll, sliderScroll->GetSizer());\n\n\tsliderScroll->FitInside();\n\tSetPendingChanges();\n\n\treturn sliderName;\n}\n\nvoid OutfitStudioFrame::SetSliderValue(const size_t index, int val) {\n\tstd::string name = project->GetSliderName(index);\n\tproject->SliderValue(index) = val / 100.0f;\n\tauto it = sliderPanels.find(name);\n\tif (it != sliderPanels.end() && it->second) {\n\t\tit->second->sliderReadout->ChangeValue(wxString::Format(\"%d%%\", val));\n\t\tit->second->slider->SetValue(val);\n\t}\n}\n\nvoid OutfitStudioFrame::SetSliderValue(const std::string& name, int val) {\n\tproject->SliderValue(name) = val / 100.0f;\n\tauto it = sliderPanels.find(name);\n\tif (it != sliderPanels.end() && it->second) {\n\t\tit->second->sliderReadout->ChangeValue(wxString::Format(\"%d%%\", val));\n\t\tit->second->slider->SetValue(val);\n\t}\n}\n\nvoid OutfitStudioFrame::ApplySliders(bool recalcBVH) {\n\tstd::vector<Vector3> verts;\n\tstd::vector<Vector2> uvs;\n\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tproject->GetLiveVerts(shape, verts, &uvs);\n\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, recalcBVH, true, false, &uvs);\n\t}\n\n\tbool tMode = glView->GetTransformMode();\n\n\tif (tMode)\n\t\tglView->ShowTransformTool();\n\n\tif (!tMode)\n\t\tglView->Render();\n}\n\nvoid OutfitStudioFrame::ShowSliderEffect(const std::string& sliderName, bool show) {\n\tif (project->ValidSlider(sliderName)) {\n\t\tproject->SliderShow(sliderName) = show;\n\n\t\twxSliderPanel* sliderPanel = sliderPanels[sliderName];\n\t\tif (sliderPanel) {\n\t\t\tif (show)\n\t\t\t\tsliderPanel->sliderCheck->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED);\n\t\t\telse\n\t\t\t\tsliderPanel->sliderCheck->Set3StateValue(wxCheckBoxState::wxCHK_UNCHECKED);\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::UpdateActiveShape() {\n\tbool smoothSeamNormals = true;\n\tbool lockNormals = false;\n\tbool enableSmoothSeamsAngle = true;\n\n\tif (!activeItem) {\n\t\tif (glView->GetTransformMode())\n\t\t\tglView->ShowTransformTool(false);\n\t\tif (glView->GetVertexEdit())\n\t\t\tglView->ShowVertexEdit(false);\n\n\t\tCreateSegmentTree();\n\t\tCreatePartitionTree();\n\t\toutfitBones->UnselectAll();\n\t\tlastSelectedBones.clear();\n\n\t\tmenuBar->Enable(XRCID(\"btnSmoothSeams\"), false);\n\t\tenableSmoothSeamsAngle = false;\n\t\tmenuBar->Enable(XRCID(\"btnLockNormals\"), false);\n\t}\n\telse {\n\t\tMesh* m = glView->GetMesh(activeItem->GetShape()->name.get());\n\t\tif (m) {\n\t\t\tsmoothSeamNormals = m->smoothSeamNormals;\n\t\t\tlockNormals = m->lockNormals;\n\n\t\t\tif (glView->GetTransformMode())\n\t\t\t\tglView->ShowTransformTool();\n\t\t\tif (glView->GetVertexEdit())\n\t\t\t\tglView->ShowVertexEdit();\n\t\t}\n\t\telse\n\t\t\tenableSmoothSeamsAngle = false;\n\n\t\tmenuBar->Enable(XRCID(\"btnSmoothSeams\"), m != nullptr);\n\t\tmenuBar->Enable(XRCID(\"btnSmoothSeamsAngle\"), m != nullptr);\n\t\tmenuBar->Enable(XRCID(\"btnLockNormals\"), m != nullptr);\n\n\t\tCreateSegmentTree(activeItem->GetShape());\n\t\tCreatePartitionTree(activeItem->GetShape());\n\t}\n\n\tif (!smoothSeamNormals)\n\t\tenableSmoothSeamsAngle = false;\n\n\tmenuBar->Check(XRCID(\"btnSmoothSeams\"), smoothSeamNormals);\n\tmenuBar->Enable(XRCID(\"btnSmoothSeamsAngle\"), enableSmoothSeamsAngle);\n\tmenuBar->Check(XRCID(\"btnLockNormals\"), lockNormals);\n\n\tif (autoFrameSelected)\n\t\tFrameSelected();\n\telse if (glView->rotationCenterMode == RotationCenterMode::MeshCenter)\n\t\tglView->gls.camRotOffset = glView->gls.GetActiveCenter();\n\n\tglView->UpdateBones();\n\tglView->Render();\n\n\tHighlightSliderData();\n\tHighlightBoneNamesWithWeights();\n\tUpdateBoneCounts();\n}\n\nvoid OutfitStudioFrame::UpdateVertexColors() {\n\tbool enableVertexColors = menuBar->IsChecked(XRCID(\"btnEnableVertexColors\"));\n\tglView->SetColorsVisible(enableVertexColors);\n\tif (enableVertexColors)\n\t\tFillVertexColors();\n\telse if (colorSettings->IsShown())\n\t\tglView->ClearColors();\n}\n\nvoid OutfitStudioFrame::UpdateBoneCounts() {\n\tauto totalBoneCountLabel = reinterpret_cast<wxStaticText*>(FindWindowByName(\"totalBoneCountLabel\"));\n\ttotalBoneCountLabel->SetLabel(wxString::Format(_(\"Total Bones: %zu\"), project->GetActiveBoneCount()));\n\n\tstd::vector<std::string> boneNames;\n\tproject->GetActiveBones(boneNames);\n\n\tsize_t selectedBoneCount = 0;\n\tfor (auto& s : selectedItems) {\n\t\tfor (auto& bone : boneNames) {\n\t\t\tif (project->GetWorkAnim()->HasWeights(s->GetShape()->name.get(), bone)) {\n\t\t\t\tselectedBoneCount++;\n\t\t\t}\n\t\t}\n\t}\n\n\tauto selectedBoneCountLabel = reinterpret_cast<wxStaticText*>(FindWindowByName(\"selectedBoneCountLabel\"));\n\tselectedBoneCountLabel->SetLabel(wxString::Format(_(\"Shape Selection Bones: %zu\"), selectedBoneCount));\n}\n\nvoid OutfitStudioFrame::HighlightSliderData() {\n\tfor (auto& sliderPanel : sliderPanels) {\n\t\tsliderPanel.second->btnSliderEdit->SetBitmap(*bmpEditSlider);\n\n\t\tSliderData& sd = project->activeSet[sliderPanel.first];\n\n\t\tfor (auto& i : selectedItems) {\n\t\t\tauto diff = project->GetDiffSet(sd, i->GetShape());\n\t\t\tif (diff && !diff->empty()) {\n\t\t\t\tsliderPanel.second->btnSliderEdit->SetBitmap(*bmpEditSliderGreen);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::HighlightBoneNamesWithWeights() {\n\twxTreeItemIdValue cookie;\n\twxTreeItemId item = outfitBones->GetFirstChild(bonesRoot, cookie);\n\twhile (item.IsOk()) {\n\t\toutfitBones->SetItemTextColour(item, wxColour(255, 255, 255));\n\n\t\tauto boneName = outfitBones->GetItemText(item).ToStdString();\n\t\tfor (auto& i : selectedItems) {\n\t\t\tif (project->GetWorkAnim()->HasWeights(i->GetShape()->name.get(), boneName)) {\n\t\t\t\toutfitBones->SetItemTextColour(item, wxColour(0, 255, 0));\n\t\t\t}\n\t\t}\n\n\t\tUpdateBoneItemState(item, boneName);\n\n\t\titem = outfitBones->GetNextChild(bonesRoot, cookie);\n\t}\n}\n\nvoid OutfitStudioFrame::GetNormalizeBones(std::vector<std::string>* normBones, std::vector<std::string>* notNormBones) {\n\tstd::vector<std::string> activeBones;\n\tproject->GetActiveBones(activeBones);\n\n\tfor (auto& boneName : activeBones) {\n\t\tif (lastNormalizeBones.find(boneName) != lastNormalizeBones.end()) {\n\t\t\tif (normBones)\n\t\t\t\tnormBones->push_back(boneName);\n\t\t}\n\t\telse {\n\t\t\tif (notNormBones)\n\t\t\t\tnotNormBones->push_back(boneName);\n\t\t}\n\t}\n}\n\nstd::vector<std::string> OutfitStudioFrame::GetSelectedBones() {\n\tstd::vector<std::string> activeBones;\n\tproject->GetActiveBones(activeBones);\n\n\tstd::vector<std::string> boneList;\n\n\tfor (auto& selBone : lastSelectedBones) {\n\t\tif (std::find(activeBones.begin(), activeBones.end(), selBone) != activeBones.end()) {\n\t\t\tboneList.push_back(selBone);\n\t\t}\n\t}\n\n\treturn boneList;\n}\n\nvoid OutfitStudioFrame::CalcAutoXMirrorBone() {\n\t// Note that there is very similar code to this in OutfitProject::MatchSymmetricBoneNames.\n\n\tautoXMirrorBone.clear();\n\n\tconst size_t abLen = activeBone.length();\n\tstd::vector<std::string> bones;\n\tproject->GetActiveBones(bones);\n\n\tint bestFlips = 0;\n\tfor (const std::string& b : bones) {\n\t\tif (abLen != b.length())\n\t\t\tcontinue;\n\n\t\tint flips = 0;\n\t\tbool nomatch = false;\n\t\tfor (size_t i = 0; i < abLen && !nomatch; ++i) {\n\t\t\tchar abc = std::tolower(activeBone[i]);\n\t\t\tchar bc = std::tolower(b[i]);\n\t\t\tif (abc == 'l') {\n\t\t\t\tif (bc == 'r')\n\t\t\t\t\t++flips;\n\t\t\t\telse if (bc != abc)\n\t\t\t\t\tnomatch = true;\n\t\t\t}\n\t\t\telse if (abc == 'r') {\n\t\t\t\tif (bc == 'l')\n\t\t\t\t\t++flips;\n\t\t\t\telse if (bc != abc)\n\t\t\t\t\tnomatch = true;\n\t\t\t}\n\t\t\telse\n\t\t\t\tnomatch = bc != abc;\n\t\t}\n\n\t\tif (nomatch)\n\t\t\tcontinue;\n\t\tif (flips <= bestFlips)\n\t\t\tcontinue;\n\n\t\tbestFlips = flips;\n\t\tautoXMirrorBone = b;\n\t}\n\n\tif (autoXMirrorBone.empty())\n\t\tcXMirrorBone->SetString(1, \"Auto: None\");\n\telse\n\t\tcXMirrorBone->SetString(1, \"Auto: \" + autoXMirrorBone);\n}\n\nstd::string OutfitStudioFrame::GetXMirrorBone() {\n\tint xMChoice = cXMirrorBone->GetSelection();\n\tif (xMChoice == 0)\n\t\treturn std::string();\n\telse if (xMChoice == 1)\n\t\treturn autoXMirrorBone;\n\telse\n\t\treturn cXMirrorBone->GetString(xMChoice).ToStdString();\n}\n\nvoid OutfitStudioFrame::SelectShape(const std::string& shapeName) {\n\tif (activeItem && activeItem->GetShape()->name == shapeName)\n\t\treturn;\n\n\twxTreeItemId item;\n\twxTreeItemId subitem;\n\twxTreeItemIdValue cookie;\n\twxTreeItemIdValue subcookie;\n\titem = outfitShapes->GetFirstChild(shapesRoot, cookie);\n\twhile (item.IsOk()) {\n\t\tsubitem = outfitShapes->GetFirstChild(item, subcookie);\n\t\twhile (subitem.IsOk()) {\n\t\t\tif (outfitShapes->GetItemText(subitem) == shapeName) {\n\t\t\t\toutfitShapes->UnselectAll();\n\t\t\t\toutfitShapes->SelectItem(subitem);\n\t\t\t\toutfitShapes->EnsureVisible(subitem);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tsubitem = outfitShapes->GetNextChild(item, subcookie);\n\t\t}\n\t\titem = outfitShapes->GetNextSibling(item);\n\t}\n}\n\nstd::vector<std::string> OutfitStudioFrame::GetShapeList() {\n\tstd::vector<std::string> shapes;\n\n\tif (!outfitRoot.IsOk())\n\t\treturn shapes;\n\n\twxTreeItemIdValue cookie;\n\n\twxTreeItemId curItem = outfitShapes->GetFirstChild(outfitRoot, cookie);\n\twhile (curItem.IsOk()) {\n\t\twxString shapeName = outfitShapes->GetItemText(curItem);\n\t\tshapes.push_back(shapeName.ToStdString());\n\t\tcurItem = outfitShapes->GetNextChild(outfitRoot, cookie);\n\t}\n\n\treturn shapes;\n}\n\nvoid OutfitStudioFrame::UpdateShapeSource(NiShape* shape) {\n\tMesh* m = glView->GetMesh(shape->name.get());\n\tif (m)\n\t\tproject->UpdateShapeFromMesh(shape, m);\n}\n\nvoid OutfitStudioFrame::ActiveShapesUpdated(UndoStateProject* usp, bool bIsUndo) {\n\tif (!usp->sliderName.empty()) {\n\t\tfloat sliderscale = 1 / usp->sliderscale;\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tMesh* m = glView->GetMesh(uss.shapeName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tauto shape = project->GetWorkNif()->FindBlockByName<NiShape>(m->shapeName);\n\t\t\tif (!shape)\n\t\t\t\tcontinue;\n\n\t\t\tif (!uss.restDiffs.empty()) {\n\t\t\t\t// Pose-independent undo/redo: use stored rest-space NIF diffs\n\t\t\t\tstd::unordered_map<uint16_t, Vector3> morphDiff;\n\t\t\t\tfor (auto& rd : uss.restDiffs) {\n\t\t\t\t\tVector3 nifDiff = rd.second;\n\t\t\t\t\tif (bIsUndo)\n\t\t\t\t\t\tnifDiff *= -1.0f;\n\t\t\t\t\tmorphDiff[static_cast<uint16_t>(rd.first)] = Mesh::TransformDiffNifToMesh(nifDiff);\n\t\t\t\t}\n\t\t\t\tproject->UpdateMorphResult(shape, usp->sliderName, morphDiff);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tstd::unordered_map<uint16_t, Vector3> strokeDiff;\n\n\t\t\t\tfor (auto& ps : uss.pointStartState) {\n\t\t\t\t\tauto pe = uss.pointEndState.find(ps.first);\n\t\t\t\t\tif (pe == uss.pointEndState.end())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (bIsUndo)\n\t\t\t\t\t\tstrokeDiff[ps.first] = (ps.second - pe->second) * sliderscale;\n\t\t\t\t\telse\n\t\t\t\t\t\tstrokeDiff[ps.first] = (pe->second - ps.second) * sliderscale;\n\t\t\t\t}\n\n\t\t\t\tif (project->bPose)\n\t\t\t\t\tproject->UndoPoseDiffs(shape, strokeDiff);\n\n\t\t\t\t// Store rest-space NIF diffs for future undo/redo\n\t\t\t\tfor (auto& sd : strokeDiff)\n\t\t\t\t\tuss.restDiffs[sd.first] = Mesh::TransformDiffMeshToNif(sd.second);\n\n\t\t\t\tproject->UpdateMorphResult(shape, usp->sliderName, strokeDiff);\n\t\t\t}\n\t\t}\n\n\t\tHighlightSliderData();\n\t}\n\telse {\n\t\tif (usp->undoType == UndoType::Weight) {\n\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\tMesh* m = glView->GetMesh(uss.shapeName);\n\t\t\t\tif (!m)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tfor (auto& bw : uss.boneWeights) {\n\t\t\t\t\tif (bw.weights.empty())\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tproject->GetWorkAnim()->AddShapeBone(m->shapeName, bw.boneName);\n\t\t\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(m->shapeName, bw.boneName);\n\t\t\t\t\tif (!weights)\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tfor (auto& p : bw.weights) {\n\t\t\t\t\t\tfloat val = bIsUndo ? p.second.startVal : p.second.endVal;\n\t\t\t\t\t\tif (val == 0.0f)\n\t\t\t\t\t\t\tweights->erase(p.first);\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\t(*weights)[p.first] = val;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (project->bPose) {\n\t\t\t\t\tauto shape = project->GetWorkNif()->FindBlockByName<NiShape>(m->shapeName);\n\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (usp->undoType == UndoType::Color) {\n\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\tMesh* m = glView->GetMesh(uss.shapeName);\n\t\t\t\tif (!m)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tauto colorPtr = project->GetWorkNif()->GetColorsForShape(m->shapeName);\n\t\t\t\tif (!colorPtr || colorPtr->empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::vector<Color4> vcolors = (*colorPtr);\n\n\t\t\t\tif (bIsUndo) {\n\t\t\t\t\tfor (auto& p : uss.pointStartState) {\n\t\t\t\t\t\tvcolors[p.first].r = p.second.x;\n\t\t\t\t\t\tvcolors[p.first].g = p.second.y;\n\t\t\t\t\t\tvcolors[p.first].b = p.second.z;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor (auto& p : uss.pointEndState) {\n\t\t\t\t\t\tvcolors[p.first].r = p.second.x;\n\t\t\t\t\t\tvcolors[p.first].g = p.second.y;\n\t\t\t\t\t\tvcolors[p.first].b = p.second.z;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tproject->GetWorkNif()->SetColorsForShape(m->shapeName, vcolors);\n\t\t\t}\n\t\t}\n\t\telse if (usp->undoType == UndoType::Alpha) {\n\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\tMesh* m = glView->GetMesh(uss.shapeName);\n\t\t\t\tif (!m)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tauto colorPtr = project->GetWorkNif()->GetColorsForShape(m->shapeName);\n\t\t\t\tif (!colorPtr || colorPtr->empty())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::vector<Color4> vcolors = (*colorPtr);\n\n\t\t\t\tif (bIsUndo) {\n\t\t\t\t\tfor (auto& p : uss.pointStartState)\n\t\t\t\t\t\tvcolors[p.first].a = p.second.x;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tfor (auto& p : uss.pointEndState)\n\t\t\t\t\t\tvcolors[p.first].a = p.second.x;\n\t\t\t\t}\n\n\t\t\t\tproject->GetWorkNif()->SetColorsForShape(m->shapeName, vcolors);\n\t\t\t}\n\t\t}\n\t}\n\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::UpdateShapeReference(NiShape* shape, NiShape* newShape) {\n\tfor (auto& i : selectedItems) {\n\t\tif (i->GetShape() == shape) {\n\t\t\ti->SetShape(newShape);\n\t\t}\n\t}\n\n\tif (project->IsBaseShape(shape))\n\t\tproject->SetBaseShape(newShape, false);\n}\n\nstd::vector<ShapeItemData*>& OutfitStudioFrame::GetSelectedItems() {\n\treturn selectedItems;\n}\n\nvoid OutfitStudioFrame::ClearSelected(NiShape* shape) {\n\tif (activeItem && activeItem->GetShape() == shape)\n\t\tactiveItem = nullptr;\n\n\tselectedItems.erase(std::remove_if(selectedItems.begin(), selectedItems.end(), [&](ShapeItemData* i) { return i->GetShape() == shape; }), selectedItems.end());\n}\n\nstd::string OutfitStudioFrame::GetActiveBone() {\n\treturn activeBone;\n}\n\nvoid OutfitStudioFrame::HideSliderPanel(wxSliderPanel* sliderPanel) {\n\tif (!sliderPanel)\n\t\treturn;\n\n\t// Hover enter\n\tsliderPanel->btnSliderEdit->Unbind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\tsliderPanel->sliderCheck->Unbind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\tsliderPanel->sliderName->Unbind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\tsliderPanel->slider->Unbind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\tsliderPanel->sliderReadout->Unbind(wxEVT_ENTER_WINDOW, &OutfitStudioFrame::OnEnterHoverSlider, this);\n\n\t// Hover leave\n\tsliderPanel->btnSliderEdit->Bind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\tsliderPanel->sliderCheck->Unbind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\tsliderPanel->sliderName->Unbind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\tsliderPanel->slider->Unbind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\tsliderPanel->sliderReadout->Unbind(wxEVT_LEAVE_WINDOW, &OutfitStudioFrame::OnLeaveHoverSlider, this);\n\n\tsliderPanel->btnSliderEdit->Unbind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\tsliderPanel->btnSliderProp->Unbind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\tsliderPanel->btnMinus->Unbind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\tsliderPanel->btnPlus->Unbind(wxEVT_BUTTON, &OutfitStudioFrame::OnClickSliderButton, this);\n\tsliderPanel->sliderCheck->Unbind(wxEVT_CHECKBOX, &OutfitStudioFrame::OnSliderCheckBox, this);\n\tsliderPanel->slider->Unbind(wxEVT_SLIDER, &OutfitStudioFrame::OnSlider, this);\n\tsliderPanel->sliderReadout->Unbind(wxEVT_TEXT, &OutfitStudioFrame::OnReadoutChange, this);\n\n\tsliderPanel->Hide();\n}\n\nvoid OutfitStudioFrame::EnterSliderEdit(const std::string& sliderName) {\n\tstd::string sliderNameEdit = sliderName;\n\n\tif (sliderNameEdit.empty()) {\n\t\tif (lastActiveSlider.empty())\n\t\t\tsliderNameEdit = project->GetSliderName(0);\n\t\telse\n\t\t\tsliderNameEdit = lastActiveSlider;\n\t}\n\n\tif (sliderNameEdit.empty())\n\t\treturn;\n\n\tif (bEditSlider) {\n\t\twxSliderPanel* sliderPanel = sliderPanels[activeSlider];\n\t\tif (sliderPanel) {\n\t\t\tsliderPanel->sliderCheck->Enable(true);\n\t\t\tsliderPanel->btnSliderProp->Hide();\n\t\t\tsliderPanel->btnMinus->Hide();\n\t\t\tsliderPanel->btnPlus->Hide();\n\t\t\tsliderPanel->Layout();\n\t\t}\n\t}\n\n\twxSliderPanel* sliderPanel = sliderPanels[sliderNameEdit];\n\tif (!sliderPanel)\n\t\treturn;\n\n\tactiveSlider = sliderNameEdit;\n\tlastActiveSlider = activeSlider;\n\tbEditSlider = true;\n\n\tsliderPanel->slider->SetValue(100);\n\tSetSliderValue(activeSlider, 100);\n\tShowSliderEffect(activeSlider, true);\n\n\tsliderPanel->sliderCheck->Enable(false);\n\tsliderPanel->btnSliderProp->Show();\n\tsliderPanel->btnMinus->Show();\n\tsliderPanel->btnPlus->Show();\n\tsliderPanel->Layout();\n\tMenuEnterSliderEdit();\n\n\tHighlightSlider(activeSlider);\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::ExitSliderEdit() {\n\tif (!activeSlider.empty()) {\n\t\twxSliderPanel* sliderPanel = sliderPanels[activeSlider];\n\t\tif (sliderPanel) {\n\t\t\tsliderPanel->sliderCheck->Enable(true);\n\t\t\tsliderPanel->slider->SetValue(0);\n\t\t\tSetSliderValue(activeSlider, 0);\n\t\t\tShowSliderEffect(activeSlider, true);\n\t\t\tsliderPanel->btnSliderProp->Hide();\n\t\t\tsliderPanel->btnMinus->Hide();\n\t\t\tsliderPanel->btnPlus->Hide();\n\t\t\tsliderPanel->Layout();\n\t\t}\n\n\t\tactiveSlider.clear();\n\t}\n\n\tbEditSlider = false;\n\tMenuExitSliderEdit();\n\n\tHighlightSlider(activeSlider);\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::MenuEnterSliderEdit() {\n\tmenuBar->Enable(XRCID(\"menuImportSlider\"), true);\n\tmenuBar->Enable(XRCID(\"menuExportSlider\"), true);\n\tmenuBar->Enable(XRCID(\"sliderClone\"), true);\n\tmenuBar->Enable(XRCID(\"sliderNegate\"), true);\n\tmenuBar->Enable(XRCID(\"sliderMask\"), true);\n\tmenuBar->Enable(XRCID(\"sliderProperties\"), true);\n}\n\nvoid OutfitStudioFrame::MenuExitSliderEdit() {\n\tmenuBar->Enable(XRCID(\"menuImportSlider\"), false);\n\tmenuBar->Enable(XRCID(\"menuExportSlider\"), false);\n\tmenuBar->Enable(XRCID(\"sliderClone\"), false);\n\tmenuBar->Enable(XRCID(\"sliderNegate\"), false);\n\tmenuBar->Enable(XRCID(\"sliderMask\"), false);\n\tmenuBar->Enable(XRCID(\"sliderProperties\"), false);\n}\n\nvoid OutfitStudioFrame::ScrollToActiveSlider() {\n\tif (!activeSlider.empty()) {\n\t\tfor (auto& sliderPanel : sliderPanels) {\n\t\t\tif (sliderPanel.first == activeSlider) {\n\t\t\t\tScrollWindowIntoView(sliderScroll, sliderPanel.second);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::SelectTool(ToolID tool) {\n\tif (tool == ToolID::Select) {\n\t\tglView->SetEditMode(false);\n\t\tglView->SetBrushMode(false);\n\t\tglView->SetActiveTool(tool);\n\n\t\tmenuBar->Check(XRCID(\"btnSelect\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnSelect\"), true);\n\n\t\tReEnableToolOptionsUI();\n\t\tReToggleToolOptionsUI();\n\t\treturn;\n\t}\n\n\tif (tool == ToolID::Transform) {\n\t\tint id = XRCID(\"btnTransform\");\n\t\tbool state = !glView->GetTransformMode();\n\t\tmenuBar->Check(id, state);\n\t\ttoolBarV->ToggleTool(id, state);\n\t\tglView->SetTransformMode(state);\n\t\treturn;\n\t}\n\n\tif (tool == ToolID::Pivot) {\n\t\tint id = XRCID(\"btnPivot\");\n\t\tbool state = !glView->GetPivotMode();\n\t\tmenuBar->Check(id, state);\n\t\ttoolBarV->ToggleTool(id, state);\n\t\tglView->SetPivotMode(state);\n\t\treturn;\n\t}\n\n\tif (tool == ToolID::VertexEdit) {\n\t\tint id = XRCID(\"btnVertexEdit\");\n\t\tbool state = !glView->GetVertexEdit();\n\t\tmenuBar->Check(id, state);\n\t\ttoolBarV->ToggleTool(id, state);\n\t\tglView->SetVertexEdit(state);\n\t\treturn;\n\t}\n\n\tglView->SetActiveTool(tool);\n\tglView->SetCursorType(GLSurface::BrushCursor);\n\n\tReEnableToolOptionsUI();\n\tReToggleToolOptionsUI();\n\n\tif (tool == ToolID::MaskBrush) {\n\t\tmenuBar->Check(XRCID(\"btnMaskBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnMaskBrush\"), true);\n\t}\n\telse if (tool == ToolID::InflateBrush) {\n\t\tmenuBar->Check(XRCID(\"btnInflateBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnInflateBrush\"), true);\n\t}\n\telse if (tool == ToolID::DeflateBrush) {\n\t\tmenuBar->Check(XRCID(\"btnDeflateBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnDeflateBrush\"), true);\n\t}\n\telse if (tool == ToolID::MoveBrush) {\n\t\tmenuBar->Check(XRCID(\"btnMoveBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnMoveBrush\"), true);\n\t}\n\telse if (tool == ToolID::SmoothBrush) {\n\t\tmenuBar->Check(XRCID(\"btnSmoothBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnSmoothBrush\"), true);\n\t}\n\telse if (tool == ToolID::UndiffBrush) {\n\t\tmenuBar->Check(XRCID(\"btnUndiffBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnUndiffBrush\"), true);\n\t}\n\telse if (tool == ToolID::WeightBrush) {\n\t\tmenuBar->Check(XRCID(\"btnWeightBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnWeightBrush\"), true);\n\t}\n\telse if (tool == ToolID::ColorBrush) {\n\t\tmenuBar->Check(XRCID(\"btnColorBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnColorBrush\"), true);\n\n\t\tFindWindowById(XRCID(\"colorPalette\"), colorSettings)->Show();\n\t\tFindWindowById(XRCID(\"btnMaskVertexColor\"), colorSettings)->Show();\n\t\tFindWindowById(XRCID(\"clampMaxValue\"), colorSettings)->Hide();\n\t\tcolorSettings->Layout();\n\t\twxButton* btnSwapBrush = (wxButton*)FindWindowById(XRCID(\"btnSwapBrush\"), colorSettings);\n\t\tbtnSwapBrush->SetLabel(_(\"Edit Alpha\"));\n\t}\n\telse if (tool == ToolID::AlphaBrush) {\n\t\tmenuBar->Check(XRCID(\"btnAlphaBrush\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnAlphaBrush\"), true);\n\n\t\tFindWindowById(XRCID(\"colorPalette\"), colorSettings)->Hide();\n\t\tFindWindowById(XRCID(\"btnMaskVertexColor\"), colorSettings)->Hide();\n\t\tFindWindowById(XRCID(\"clampMaxValue\"), colorSettings)->Show();\n\t\tcolorSettings->Layout();\n\t\twxButton* btnSwapBrush = (wxButton*)FindWindowById(XRCID(\"btnSwapBrush\"), colorSettings);\n\t\tbtnSwapBrush->SetLabel(_(\"Edit Color\"));\n\t}\n\telse if (tool == ToolID::CollapseVertex) {\n\t\tmenuBar->Check(XRCID(\"btnCollapseVertex\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnCollapseVertex\"), true);\n\t\tglView->SetEditMode();\n\t\tglView->SetBrushMode(false);\n\t\tglView->SetCursorType(GLSurface::VertexCursor);\n\t\treturn;\n\t}\n\telse if (tool == ToolID::FlipEdge) {\n\t\tmenuBar->Check(XRCID(\"btnFlipEdgeTool\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnFlipEdgeTool\"), true);\n\t\tglView->SetEditMode();\n\t\tglView->SetBrushMode(false);\n\t\tglView->SetCursorType(GLSurface::EdgeCursor);\n\t\treturn;\n\t}\n\telse if (tool == ToolID::SplitEdge) {\n\t\tmenuBar->Check(XRCID(\"btnSplitEdgeTool\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnSplitEdgeTool\"), true);\n\t\tglView->SetEditMode();\n\t\tglView->SetBrushMode(false);\n\t\tglView->SetCursorType(GLSurface::EdgeCursor);\n\t\treturn;\n\t}\n\telse if (tool == ToolID::MoveVertex) {\n\t\tmenuBar->Check(XRCID(\"btnMoveVertexTool\"), true);\n\t\ttoolBarH->ToggleTool(XRCID(\"btnMoveVertexTool\"), true);\n\t\tglView->SetEditMode();\n\t\tglView->SetBrushMode(false);\n\t\tglView->SetCursorType(GLSurface::VertexCursor);\n\t\treturn;\n\t}\n\telse {\n\t\tglView->SetEditMode(false);\n\t\tglView->SetBrushMode(false);\n\t\tglView->SetTransformMode(false);\n\t\treturn;\n\t}\n\n\t// One of the brushes was activated\n\tglView->SetEditMode();\n\tglView->SetBrushMode();\n\tglView->SetBrushSize(glView->GetBrushSize());\n\n\tCheckBrushBounds();\n\tUpdateBrushSettings();\n}\n\nvoid OutfitStudioFrame::ReEnableToolOptionsUI() {\n\tbool isBrush = glView->GetActiveBrush() != nullptr;\n\tToolID toolid = glView->GetActiveTool();\n\tbool isMV = toolid == ToolID::MoveVertex;\n\tbool isIB = toolid == ToolID::InflateBrush || toolid == ToolID::DeflateBrush;\n\tbool isMB = toolid == ToolID::MoveBrush;\n\tbool isSB = toolid == ToolID::SmoothBrush;\n\n\tmenuBar->Enable(XRCID(\"btnXMirror\"), isBrush || isMV);\n\ttbvHider.Show(XRCID(\"btnXMirror\"), isBrush || isMV);\n\tmenuBar->Enable(XRCID(\"btnConnected\"), isBrush);\n\ttbvHider.Show(XRCID(\"btnConnected\"), isBrush);\n\tmenuBar->Enable(XRCID(\"btnMerge\"), isMV);\n\ttbvHider.Show(XRCID(\"btnMerge\"), isMV);\n\tmenuBar->Enable(XRCID(\"btnWeld\"), isMV);\n\ttbvHider.Show(XRCID(\"btnWeld\"), isMV);\n\tmenuBar->Enable(XRCID(\"btnRestrictSurface\"), isMV);\n\ttbvHider.Show(XRCID(\"btnRestrictSurface\"), isMV);\n\tmenuBar->Enable(XRCID(\"btnRestrictPlane\"), isMV || isMB || isSB);\n\ttbvHider.Show(XRCID(\"btnRestrictPlane\"), isMV || isMB || isSB);\n\tmenuBar->Enable(XRCID(\"btnRestrictNormal\"), isMV || isIB || isMB || isSB);\n\ttbvHider.Show(XRCID(\"btnRestrictNormal\"), isMV || isIB || isMB || isSB);\n}\n\nvoid OutfitStudioFrame::ReToggleToolOptionsUI() {\n\tbool isBrush = glView->GetActiveBrush() != nullptr;\n\tToolID toolid = glView->GetActiveTool();\n\tbool isMV = toolid == ToolID::MoveVertex;\n\tbool isIB = toolid == ToolID::InflateBrush || toolid == ToolID::DeflateBrush;\n\tbool isMB = toolid == ToolID::MoveBrush;\n\tbool isSB = toolid == ToolID::SmoothBrush;\n\tbool transformMode = glView->GetTransformMode();\n\tbool xMirror = glView->GetToolOptionXMirror();\n\tbool connOnly = glView->GetToolOptionConnectedOnly();\n\tbool merge = glView->GetToolOptionMerge();\n\tbool weld = glView->GetToolOptionWeld();\n\tbool rsurf = glView->GetToolOptionRestrictSurface();\n\tbool rplane = glView->GetToolOptionRestrictPlane();\n\tbool rnormal = glView->GetToolOptionRestrictNormal();\n\n\tmenuBar->Check(XRCID(\"btnTransform\"), transformMode);\n\ttoolBarV->ToggleTool(XRCID(\"btnTransform\"), transformMode);\n\tmenuBar->Check(XRCID(\"btnXMirror\"), (isBrush || isMV) && xMirror);\n\ttoolBarV->ToggleTool(XRCID(\"btnXMirror\"), (isBrush || isMV) && xMirror);\n\tmenuBar->Check(XRCID(\"btnConnected\"), isBrush && connOnly);\n\ttoolBarV->ToggleTool(XRCID(\"btnConnected\"), isBrush && connOnly);\n\tmenuBar->Check(XRCID(\"btnMerge\"), isMV && merge);\n\ttoolBarV->ToggleTool(XRCID(\"btnMerge\"), isMV && merge);\n\tmenuBar->Check(XRCID(\"btnWeld\"), isMV && weld);\n\ttoolBarV->ToggleTool(XRCID(\"btnWeld\"), isMV && weld);\n\tmenuBar->Check(XRCID(\"btnRestrictSurface\"), isMV && rsurf);\n\ttoolBarV->ToggleTool(XRCID(\"btnRestrictSurface\"), isMV && rsurf);\n\tmenuBar->Check(XRCID(\"btnRestrictPlane\"), (isMV || isMB || isSB) && rplane);\n\ttoolBarV->ToggleTool(XRCID(\"btnRestrictPlane\"), (isMV || isMB || isSB) && rplane);\n\tmenuBar->Check(XRCID(\"btnRestrictNormal\"), (isMV || isIB || isMB || isSB) && rnormal);\n\ttoolBarV->ToggleTool(XRCID(\"btnRestrictNormal\"), (isMV || isIB || isMB || isSB) && rnormal);\n}\n\nvoid OutfitStudioFrame::CloseBrushSettings() {\n\tif (brushSettingsPopupTransient) {\n\t\tbrushSettingsPopupTransient->Destroy();\n\t\tbrushSettingsPopupTransient = nullptr;\n\t}\n}\n\nvoid OutfitStudioFrame::PopupBrushSettings(wxWindow* popupAt) {\n\tCloseBrushSettings();\n\n\tif (!glView->GetBrushMode())\n\t\treturn;\n\n\twxPoint popupPos;\n\twxSize popupSize;\n\n\tif (popupAt) {\n\t\tpopupPos = popupAt->GetScreenPosition();\n\t\tpopupSize.y = popupAt->GetSize().y;\n\t}\n\telse {\n\t\tpopupPos = wxGetMousePosition();\n\t\tpopupSize.x = 10;\n\t\tpopupSize.y = 10;\n\t}\n\n\tbool stayOpen = popupAt != nullptr;\n\tbrushSettingsPopupTransient = new wxBrushSettingsPopupTransient(this, stayOpen);\n\tbrushSettingsPopupTransient->Position(popupPos, popupSize);\n\tbrushSettingsPopupTransient->Popup();\n\n\tUpdateBrushSettings();\n}\n\nvoid OutfitStudioFrame::UpdateBrushSettings() {\n\tTweakBrush* brush = glView->GetActiveBrush();\n\tif (!brush)\n\t\treturn;\n\n\tif (brushSettingsPopupTransient) {\n\t\tbrushSettingsPopupTransient->SetBrushName(wxString::FromUTF8(brush->Name()));\n\t\tbrushSettingsPopupTransient->SetBrushSize(glView->GetBrushSize());\n\t\tbrushSettingsPopupTransient->SetBrushStrength(brush->getStrength());\n\t\tbrushSettingsPopupTransient->SetBrushFocus(brush->getFocus());\n\t\tbrushSettingsPopupTransient->SetBrushSpacing(brush->getSpacing());\n\t}\n}\n\nbool OutfitStudioFrame::CheckEditableState() {\n\tif (!activeItem)\n\t\treturn false;\n\n\tToolID activeTool = glView->GetActiveTool();\n\tif (activeTool == ToolID::MaskBrush || activeTool == ToolID::WeightBrush || activeTool == ToolID::ColorBrush || activeTool == ToolID::AlphaBrush)\n\t\treturn true;\n\n\tif (bEditSlider) {\n\t\tif (project->SliderValue(activeSlider) == 0.0) {\n\t\t\tint response = wxMessageBox(_(\"You are trying to edit a slider's morph with that slider set to zero.  Do you wish to set the slider to one now?\"),\n\t\t\t\t\t\t\t\t\t\twxMessageBoxCaptionStr,\n\t\t\t\t\t\t\t\t\t\twxYES_NO,\n\t\t\t\t\t\t\t\t\t\tthis);\n\n\t\t\tif (response == wxYES) {\n\t\t\t\tSetSliderValue(activeSlider, 100);\n\t\t\t\tApplySliders();\n\t\t\t}\n\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t}\n\telse {\n\t\tif (activeTool == ToolID::UndiffBrush) {\n\t\t\twxMessageBox(_(\"You can only use the undiff brush while editing a slider. Note, use the pencil button next to a slider to enable editing of that slider's morph.\"),\n\t\t\t\t\t\t wxMessageBoxCaptionStr,\n\t\t\t\t\t\t wxOK,\n\t\t\t\t\t\t this);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tif (project->AllSlidersZero())\n\t\treturn true;\n\n\tint response = wxMessageBox(_(\"You can only edit the base shape when all sliders are zero. Do you wish to set all sliders to zero now?  Note, use the pencil button next to a \"\n\t\t\t\t\t\t\t\t  \"slider to enable editing of that slider's morph.\"),\n\t\t\t\t\t\t\t\twxMessageBoxCaptionStr,\n\t\t\t\t\t\t\t\twxYES_NO,\n\t\t\t\t\t\t\t\tthis);\n\n\tif (response == wxYES)\n\t\tZeroSliders();\n\n\treturn false;\n}\n\nvoid OutfitStudioFrame::UpdateTitle() {\n\twxString name = wxString::FromUTF8(project->OutfitName());\n\tif (name.empty() || name == \"New Outfit\")\n\t\tname = project->mBaseFile;\n\n\tif (!name.empty()) {\n\t\tif (pendingChanges)\n\t\t\tSetTitle(name + \"* - Outfit Studio\");\n\t\telse\n\t\t\tSetTitle(name + \" - Outfit Studio\");\n\t}\n\telse\n\t\tSetTitle(\"Outfit Studio\");\n}\n\nvoid OutfitStudioFrame::AddProjectHistory(const std::string& fileName, const std::string& projectName) {\n\tprojectHistory.erase(std::remove_if(projectHistory.begin(),\n\t\t\t\t\t\t\t\t\t\tprojectHistory.end(),\n\t\t\t\t\t\t\t\t\t\t[&fileName, &projectName](const ProjectHistoryEntry& rt) { return rt.fileName == fileName && rt.projectName == projectName; }),\n\t\t\t\t\t\t projectHistory.end());\n\n\tProjectHistoryEntry projectHistoryEntry{};\n\tprojectHistoryEntry.fileName = fileName;\n\tprojectHistoryEntry.projectName = projectName;\n\n\tconstexpr int DEF_PROJECT_HISTORY = 15;\n\tconstexpr int MAX_PROJECT_HISTORY = 100;\n\n\tint maxCount = OutfitStudioConfig.GetIntValue(\"ProjectHistory.maxcount\", DEF_PROJECT_HISTORY);\n\tif (maxCount <= 0)\n\t\tmaxCount = DEF_PROJECT_HISTORY;\n\telse if (maxCount > MAX_PROJECT_HISTORY)\n\t\tmaxCount = MAX_PROJECT_HISTORY;\n\n\tif (projectHistory.size() == maxCount)\n\t\tprojectHistory.pop_back();\n\n\tprojectHistory.push_front(projectHistoryEntry);\n\tUpdateProjectHistory();\n}\n\nvoid OutfitStudioFrame::UpdateProjectHistory() {\n\tmenuBar->Freeze();\n\n\twxMenuItem* menuItemRecentProjects = menuBar->FindItem(XRCID(\"menuRecentProjects\"));\n\tif (menuItemRecentProjects && menuItemRecentProjects->IsSubMenu()) {\n\t\twxMenu* menuRecentProjects = menuItemRecentProjects->GetSubMenu();\n\t\tif (menuRecentProjects) {\n\t\t\tauto menuItemList = menuRecentProjects->GetMenuItems();\n\t\t\tfor (auto menuItem : menuItemList)\n\t\t\t\tmenuRecentProjects->Delete(menuItem);\n\n\t\t\tint itemId = 0;\n\t\t\tfor (const auto& projectHistoryEntry : projectHistory) {\n\t\t\t\tmenuRecentProjects->Append(1000 + itemId, wxString::FromUTF8(projectHistoryEntry.projectName), wxString::FromUTF8(projectHistoryEntry.fileName));\n\t\t\t\t++itemId;\n\t\t\t}\n\n\t\t\tmenuBar->Enable(XRCID(\"menuRecentProjects\"), itemId > 0);\n\t\t}\n\t}\n\n\tmenuBar->Thaw();\n}\n\nvoid OutfitStudioFrame::SetPendingChanges(bool pending) {\n\tif (pendingChanges != pending) {\n\t\tpendingChanges = pending;\n\t\tUpdateTitle();\n\t}\n}\n\nbool OutfitStudioFrame::CheckPendingChanges() {\n\tif (pendingChanges) {\n\t\twxMessageDialog dlg(this,\n\t\t\t\t\t\t\twxString::Format(_(\"You have unsaved changes to '%s'. Would you like to save them now?\"), project->OutfitName()),\n\t\t\t\t\t\t\t_(\"Unsaved Changes\"),\n\t\t\t\t\t\t\twxYES_NO | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\n\t\tint res = dlg.ShowModal();\n\t\tif (res == wxID_YES) {\n\t\t\tif (!SaveProject())\n\t\t\t\treturn false;\n\t\t}\n\t\telse if (res == wxID_CANCEL)\n\t\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nvoid OutfitStudioFrame::UpdateUndoTools() {\n\tauto undoHistory = glView->GetUndoHistory();\n\ttoolBarH->EnableTool(XRCID(\"editUndo\"), undoHistory->CanUndo());\n\ttoolBarH->EnableTool(XRCID(\"editRedo\"), undoHistory->CanRedo());\n}\n\nvoid OutfitStudioFrame::OnNewProject(wxCommandEvent& WXUNUSED(event)) {\n\twxWizard wiz;\n\twxWizardPage* pg1;\n\tbool result = false;\n\n\tif (!CheckPendingChanges())\n\t\treturn;\n\n\tCloseBrushSettings();\n\tUpdateReferenceTemplates();\n\n\tif (wxXmlResource::Get()->LoadObject((wxObject*)&wiz, this, \"wizNewProject\", \"wxWizard\")) {\n\t\tpg1 = (wxWizardPage*)XRCCTRL(wiz, \"wizpgNewProj1\", wxWizardPageSimple);\n\t\tXRCCTRL(wiz, \"npSliderSetFile\", wxFilePickerCtrl)->Bind(wxEVT_FILEPICKER_CHANGED, &OutfitStudioFrame::OnNPWizChangeSliderSetFile, this);\n\t\tXRCCTRL(wiz, \"npSliderSetName\", wxChoice)->Bind(wxEVT_CHOICE, &OutfitStudioFrame::OnNPWizChangeSetNameChoice, this);\n\n\t\tXRCCTRL(wiz, \"npWorkFilename\", wxFilePickerCtrl)->Bind(wxEVT_FILEPICKER_CHANGED, &OutfitStudioFrame::OnLoadOutfitFP_File, this);\n\t\tXRCCTRL(wiz, \"npTexFilename\", wxFilePickerCtrl)->Bind(wxEVT_FILEPICKER_CHANGED, &OutfitStudioFrame::OnLoadOutfitFP_Texture, this);\n\n\t\tConfigDialogUtil::LoadDialogChoices(OutfitStudioConfig, wiz, \"LoadReference\", \"npTemplateChoice\", refTemplates);\n\n\t\twiz.FitToPage(pg1);\n\t\twiz.CenterOnParent();\n\n\t\tresult = wiz.RunWizard(pg1);\n\t}\n\tif (!result)\n\t\treturn;\n\n\tmenuBar->Enable(XRCID(\"fileSave\"), false);\n\n\tstd::string outfitName{XRCCTRL(wiz, \"npOutfitName\", wxTextCtrl)->GetValue().ToUTF8()};\n\n\twxLogMessage(\"Creating project '%s'...\", outfitName);\n\tStartProgress(wxString::Format(_(\"Creating project '%s'...\"), outfitName));\n\n\tClearProject();\n\tproject->ClearReference();\n\tproject->ClearOutfit();\n\n\tglView->Cleanup();\n\tglView->GetUndoHistory()->ClearHistory();\n\n\tactiveSlider.clear();\n\tlastActiveSlider.clear();\n\tbEditSlider = false;\n\tMenuExitSliderEdit();\n\n\tdelete project;\n\tproject = new OutfitProject(this);\n\n\tUpdateProgress(10, _(\"Loading reference...\"));\n\n\tint error = 0;\n\tif (XRCCTRL(wiz, \"npRefIsTemplate\", wxRadioButton)->GetValue() == true) {\n\t\twxString refTemplate = ConfigDialogUtil::SetStringFromDialogChoice(OutfitStudioConfig, wiz, \"LoadReference\", \"npTemplateChoice\");\n\t\twxLogMessage(\"Loading reference template '%s'...\", refTemplate);\n\n\t\tstd::string tmplName{refTemplate.ToUTF8()};\n\t\tauto tmpl = find_if(refTemplates.begin(), refTemplates.end(), [&tmplName](const RefTemplate& rt) { return rt.GetName() == tmplName; });\n\t\tif (tmpl != refTemplates.end()) {\n\t\t\tif (wxFileName(wxString::FromUTF8(tmpl->GetSource())).IsRelative())\n\t\t\t\terror = project->LoadReferenceTemplate(GetProjectPath() + PathSepStr + tmpl->GetSource(), tmpl->GetSetName(), tmpl->GetShape(), tmpl->GetLoadAll());\n\t\t\telse\n\t\t\t\terror = project->LoadReferenceTemplate(tmpl->GetSource(), tmpl->GetSetName(), tmpl->GetShape(), tmpl->GetLoadAll());\n\t\t}\n\t\telse\n\t\t\terror = 1;\n\t}\n\telse if (XRCCTRL(wiz, \"npRefIsSliderset\", wxRadioButton)->GetValue() == true) {\n\t\twxString fileName = XRCCTRL(wiz, \"npSliderSetFile\", wxFilePickerCtrl)->GetPath();\n\t\twxString refShape = XRCCTRL(wiz, \"npRefShapeName\", wxChoice)->GetStringSelection();\n\n\t\tif (fileName.EndsWith(\".osp\") || fileName.EndsWith(\".xml\")) {\n\t\t\twxString sliderSetName = XRCCTRL(wiz, \"npSliderSetName\", wxChoice)->GetStringSelection();\n\t\t\twxLogMessage(\"Loading reference '%s' from set '%s' of file '%s'...\", refShape, sliderSetName, fileName);\n\n\t\t\terror = project->LoadReference(fileName.ToUTF8().data(), sliderSetName.ToUTF8().data(), refShape.ToUTF8().data());\n\t\t}\n\t\telse if (fileName.EndsWith(\".nif\")) {\n\t\t\twxLogMessage(\"Loading reference '%s' from '%s'...\", refShape, fileName);\n\t\t\terror = project->LoadReferenceNif(fileName.ToUTF8().data(), refShape.ToUTF8().data());\n\t\t}\n\t}\n\n\tif (error) {\n\t\tEndProgress();\n\t\tRefreshGUIFromProj();\n\t\treturn;\n\t}\n\n\tUpdateProgress(40, _(\"Loading outfit...\"));\n\n\terror = 0;\n\tif (XRCCTRL(wiz, \"npWorkFile\", wxRadioButton)->GetValue() == true) {\n\t\twxString fileName = XRCCTRL(wiz, \"npWorkFilename\", wxFilePickerCtrl)->GetPath();\n\t\twxLogMessage(\"Loading outfit '%s' from '%s'...\", outfitName, fileName);\n\t\tif (fileName.Lower().EndsWith(\".nif\"))\n\t\t\terror = project->ImportNIF(fileName.ToUTF8().data(), true, outfitName);\n\t\telse if (fileName.Lower().EndsWith(\".obj\"))\n\t\t\terror = project->ImportOBJ(fileName.ToUTF8().data(), outfitName);\n#ifdef USE_FBXSDK\n\t\telse if (fileName.Lower().EndsWith(\".fbx\"))\n\t\t\terror = project->ImportFBX(fileName.ToUTF8().data(), outfitName);\n#endif\n\t}\n\n\tif (error) {\n\t\tEndProgress();\n\t\tRefreshGUIFromProj();\n\t\treturn;\n\t}\n\n\twxLogMessage(\"Creating outfit...\");\n\tUpdateProgress(80, _(\"Creating outfit...\"));\n\n\tif (XRCCTRL(wiz, \"npTexAuto\", wxRadioButton)->GetValue() == false)\n\t\tproject->SetTextures({XRCCTRL(wiz, \"npTexFilename\", wxFilePickerCtrl)->GetPath().ToUTF8().data()});\n\telse\n\t\tproject->SetTextures();\n\n\tRefreshGUIFromProj();\n\n\twxLogMessage(\"Creating %zu slider(s)...\", project->SliderCount());\n\tUpdateProgress(90, wxString::Format(_(\"Creating %zu slider(s)...\"), project->SliderCount()));\n\tStartSubProgress(90, 99);\n\tCreateSetSliders();\n\n\tif (!outfitName.empty())\n\t\tUpdateTitle();\n\n\twxLogMessage(\"Project created.\");\n\tUpdateProgress(100, _(\"Finished\"));\n\n\tEndProgress();\n}\n\nvoid OutfitStudioFrame::OnLoadProject(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog loadProjectDialog(this,\n\t\t\t\t\t\t\t\t   _(\"Select a slider set to load\"),\n\t\t\t\t\t\t\t\t   wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\",\n\t\t\t\t\t\t\t\t   wxEmptyString,\n\t\t\t\t\t\t\t\t   \"Slider Set Files (*.osp;*.xml)|*.osp;*.xml\",\n\t\t\t\t\t\t\t\t   wxFD_FILE_MUST_EXIST);\n\tif (loadProjectDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tif (!CheckPendingChanges())\n\t\treturn;\n\n\tstd::string fileName{loadProjectDialog.GetPath().ToUTF8()};\n\tLoadProject(fileName);\n}\n\nvoid OutfitStudioFrame::OnAddProject(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog addProjectDialog(this,\n\t\t\t\t\t\t\t\t  _(\"Select a slider set to add\"),\n\t\t\t\t\t\t\t\t  wxString::FromUTF8(GetProjectPath()) + \"/SliderSets\",\n\t\t\t\t\t\t\t\t  wxEmptyString,\n\t\t\t\t\t\t\t\t  \"Slider Set Files (*.osp;*.xml)|*.osp;*.xml\",\n\t\t\t\t\t\t\t\t  wxFD_FILE_MUST_EXIST);\n\tif (addProjectDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tif (!CheckPendingChanges())\n\t\treturn;\n\n\tstd::string fileName{addProjectDialog.GetPath().ToUTF8()};\n\tLoadProject(fileName, \"\", false);\n}\n\nvoid OutfitStudioFrame::OnLoadReference(wxCommandEvent& WXUNUSED(event)) {\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\tCloseBrushSettings();\n\tUpdateReferenceTemplates();\n\n\twxDialog dlg;\n\tint result = wxID_CANCEL;\n\tif (wxXmlResource::Get()->LoadObject((wxObject*)&dlg, this, \"dlgLoadRef\", \"wxDialog\")) {\n\t\tXRCCTRL(dlg, \"npSliderSetFile\", wxFilePickerCtrl)->Bind(wxEVT_FILEPICKER_CHANGED, &OutfitStudioFrame::OnNPWizChangeSliderSetFile, this);\n\t\tXRCCTRL(dlg, \"npSliderSetName\", wxChoice)->Bind(wxEVT_CHOICE, &OutfitStudioFrame::OnNPWizChangeSetNameChoice, this);\n\n\t\tConfigDialogUtil::LoadDialogChoices(OutfitStudioConfig, dlg, \"LoadReference\", \"npTemplateChoice\", refTemplates);\n\n\t\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, dlg, \"LoadReference\", \"chkMergeSliders\");\n\t\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, dlg, \"LoadReference\", \"chkMergeZaps\");\n\t\tConfigDialogUtil::LoadDialogCheckBox(OutfitStudioConfig, dlg, \"LoadReference\", \"chkAppendNewSliders\");\n\n\t\tdlg.Fit();\n\t\tresult = dlg.ShowModal();\n\t}\n\tif (result == wxID_CANCEL)\n\t\treturn;\n\n\tStartProgress(_(\"Loading reference...\"));\n\n\tNiShape* baseShape = project->GetBaseShape();\n\tif (baseShape)\n\t\tglView->DeleteMesh(baseShape->name.get());\n\n\tUpdateProgress(10, _(\"Loading reference set...\"));\n\tbool mergeSliders = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, dlg, \"LoadReference\", \"chkMergeSliders\");\n\tbool mergeZaps = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, dlg, \"LoadReference\", \"chkMergeZaps\");\n\tbool appendNewSliders = ConfigDialogUtil::SetBoolFromDialogCheckbox(OutfitStudioConfig, dlg, \"LoadReference\", \"chkAppendNewSliders\");\n\n\tint error = 0;\n\tif (XRCCTRL(dlg, \"npRefIsTemplate\", wxRadioButton)->GetValue() == true) {\n\t\twxString refTemplate = ConfigDialogUtil::SetStringFromDialogChoice(OutfitStudioConfig, dlg, \"LoadReference\", \"npTemplateChoice\");\n\t\twxLogMessage(\"Loading reference template '%s'...\", refTemplate);\n\n\t\tstd::string tmplName{refTemplate.ToUTF8()};\n\t\tauto tmpl = find_if(refTemplates.begin(), refTemplates.end(), [&tmplName](const RefTemplate& rt) { return rt.GetName() == tmplName; });\n\t\tif (tmpl != refTemplates.end()) {\n\t\t\tif (wxFileName(wxString::FromUTF8(tmpl->GetSource())).IsRelative())\n\t\t\t\terror = project->LoadReferenceTemplate(GetProjectPath() + PathSepStr + tmpl->GetSource(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t   tmpl->GetSetName(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t   tmpl->GetShape(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t   tmpl->GetLoadAll(),\n\t\t\t\t\t\t\t\t\t\t\t\t\t   mergeSliders,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   mergeZaps,\n\t\t\t\t\t\t\t\t\t\t\t\t\t   appendNewSliders);\n\t\t\telse\n\t\t\t\terror = project->LoadReferenceTemplate(tmpl->GetSource(), tmpl->GetSetName(), tmpl->GetShape(), tmpl->GetLoadAll(), mergeSliders, mergeZaps, appendNewSliders);\n\t\t}\n\t\telse\n\t\t\terror = 1;\n\t}\n\telse if (XRCCTRL(dlg, \"npRefIsSliderset\", wxRadioButton)->GetValue() == true) {\n\t\twxString fileName = XRCCTRL(dlg, \"npSliderSetFile\", wxFilePickerCtrl)->GetPath();\n\t\twxString refShape = XRCCTRL(dlg, \"npRefShapeName\", wxChoice)->GetStringSelection();\n\n\t\tif (fileName.EndsWith(\".osp\") || fileName.EndsWith(\".xml\")) {\n\t\t\twxString sliderSetName = XRCCTRL(dlg, \"npSliderSetName\", wxChoice)->GetStringSelection();\n\t\t\twxLogMessage(\"Loading reference '%s' from set '%s' of file '%s'...\", refShape, sliderSetName, fileName);\n\n\t\t\terror = project->LoadReference(fileName.ToUTF8().data(), sliderSetName.ToUTF8().data(), refShape.ToUTF8().data(), mergeSliders, mergeZaps, appendNewSliders);\n\t\t}\n\t\telse if (fileName.EndsWith(\".nif\")) {\n\t\t\twxLogMessage(\"Loading reference '%s' from '%s'...\", refShape, fileName);\n\t\t\terror = project->LoadReferenceNif(fileName.ToUTF8().data(), refShape.ToUTF8().data(), mergeSliders, mergeZaps);\n\t\t}\n\t}\n\telse\n\t\tproject->ClearReference();\n\n\tif (error) {\n\t\tEndProgress();\n\t\tRefreshGUIFromProj();\n\t\treturn;\n\t}\n\n\tproject->SetTextures(project->GetBaseShape());\n\n\twxLogMessage(\"Creating reference...\");\n\tUpdateProgress(60, _(\"Creating reference...\"));\n\tRefreshGUIFromProj();\n\n\twxLogMessage(\"Creating %zu slider(s)...\", project->SliderCount());\n\tUpdateProgress(70, wxString::Format(_(\"Creating %zu slider(s)...\"), project->SliderCount()));\n\tStartSubProgress(70, 99);\n\tCreateSetSliders();\n\n\twxLogMessage(\"Reference loaded.\");\n\tEndProgress();\n}\n\nvoid OutfitStudioFrame::OnConvertBodyReference(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tauto shapes = project->GetWorkNif()->GetShapes();\n\tauto baseShape = project->GetBaseShape();\n\tif (shapes.size() == 0 || (baseShape && shapes.size() == 1)) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\tUpdateReferenceTemplates();\n\n\tConvertBodyReferenceDialog dlg(this, project, OutfitStudioConfig, refTemplates);\n\tif (!dlg.Load())\n\t\treturn;\n\n\tdlg.ConvertBodyReference();\n}\n\nvoid OutfitStudioFrame::OnRunAutomation(wxCommandEvent& WXUNUSED(event)) {\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\tAutomationDialog dlg(this, project);\n\tdlg.ShowModal();\n}\n\n\nvoid OutfitStudioFrame::OnLoadOutfit(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tint result = wxID_CANCEL;\n\n\tCloseBrushSettings();\n\n\tif (wxXmlResource::Get()->LoadObject((wxObject*)&dlg, this, \"dlgLoadOutfit\", \"wxDialog\")) {\n\t\tXRCCTRL(dlg, \"npWorkFilename\", wxFilePickerCtrl)->Bind(wxEVT_FILEPICKER_CHANGED, &OutfitStudioFrame::OnLoadOutfitFP_File, this);\n\t\tXRCCTRL(dlg, \"npTexFilename\", wxFilePickerCtrl)->Bind(wxEVT_FILEPICKER_CHANGED, &OutfitStudioFrame::OnLoadOutfitFP_Texture, this);\n\t\tif (project->GetWorkNif()->IsValid())\n\t\t\tXRCCTRL(dlg, \"npWorkAdd\", wxCheckBox)->Enable();\n\n\t\tresult = dlg.ShowModal();\n\t}\n\tif (result == wxID_CANCEL)\n\t\treturn;\n\n\tstd::string outfitName = XRCCTRL(dlg, \"npOutfitName\", wxTextCtrl)->GetValue().ToStdString();\n\n\tmenuBar->Enable(XRCID(\"fileSave\"), false);\n\n\twxLogMessage(\"Loading outfit...\");\n\tStartProgress(_(\"Loading outfit...\"));\n\n\tfor (auto& s : project->GetWorkNif()->GetShapes()) {\n\t\tif (!project->IsBaseShape(s)) {\n\t\t\tglView->DeleteMesh(s->name.get());\n\t\t}\n\t}\n\n\tbool keepShapes = XRCCTRL(dlg, \"npWorkAdd\", wxCheckBox)->IsChecked();\n\tUpdateProgress(1, _(\"Loading outfit...\"));\n\n\tint ret = 0;\n\tif (XRCCTRL(dlg, \"npWorkFile\", wxRadioButton)->GetValue() == true) {\n\t\twxString fileName = XRCCTRL(dlg, \"npWorkFilename\", wxFilePickerCtrl)->GetPath();\n\t\tif (fileName.Lower().EndsWith(\".nif\")) {\n\t\t\tif (!keepShapes)\n\t\t\t\tret = project->ImportNIF(fileName.ToUTF8().data(), true, outfitName);\n\t\t\telse\n\t\t\t\tret = project->ImportNIF(fileName.ToUTF8().data(), false);\n\t\t}\n\t\telse if (fileName.Lower().EndsWith(\".obj\"))\n\t\t\tret = project->ImportOBJ(fileName.ToUTF8().data(), outfitName);\n#ifdef USE_FBXSDK\n\t\telse if (fileName.Lower().EndsWith(\".fbx\"))\n\t\t\tret = project->ImportFBX(fileName.ToUTF8().data(), outfitName);\n#endif\n\t}\n\telse\n\t\tproject->ClearOutfit();\n\n\tif (ret) {\n\t\tEndProgress();\n\t\tRefreshGUIFromProj();\n\t\treturn;\n\t}\n\n\tif (XRCCTRL(dlg, \"npTexAuto\", wxRadioButton)->GetValue() == true)\n\t\tproject->SetTextures();\n\telse {\n\t\tstd::vector<std::string> texVec = {XRCCTRL(dlg, \"npTexFilename\", wxFilePickerCtrl)->GetPath().ToUTF8().data()};\n\t\tproject->SetTextures(texVec);\n\t}\n\n\twxLogMessage(\"Creating outfit...\");\n\tUpdateProgress(50, _(\"Creating outfit...\"));\n\tRefreshGUIFromProj();\n\n\tUpdateTitle();\n\n\twxLogMessage(\"Outfit loaded.\");\n\tEndProgress();\n}\n\nvoid OutfitStudioFrame::OnUnloadProject(wxCommandEvent& WXUNUSED(event)) {\n\twxMessageDialog dlg(this, _(\"Unload the project? All unsaved changes will be lost\"), _(\"Unload Project\"), wxOK | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\tdlg.SetOKCancelLabels(_(\"Unload\"), _(\"Cancel\"));\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\twxLogMessage(\"Unloading project...\");\n\tmenuBar->Enable(XRCID(\"fileSave\"), false);\n\n\tResetProject();\n\n\tdelete project;\n\tproject = new OutfitProject(this);\n\n\tCreateSetSliders();\n\tRefreshGUIFromProj(false);\n\tglView->Render();\n\n\tstatusBar->SetStatusText(_(\"Ready!\"));\n}\n\nvoid OutfitStudioFrame::ResetProject() {\n\tClearProject();\n\tproject->ClearReference();\n\tproject->ClearOutfit();\n\n\tglView->Cleanup();\n\tglView->GetUndoHistory()->ClearHistory();\n\n\tactiveSlider.clear();\n\tlastActiveSlider.clear();\n\tbEditSlider = false;\n\tMenuExitSliderEdit();\n\n\tCreateSetSliders();\n\tRefreshGUIFromProj(false);\n}\n\nvoid OutfitStudioFrame::UpdateReferenceTemplates() {\n\trefTemplates.clear();\n\n\tstd::string fileName = GetProjectPath() + \"/RefTemplates.xml\";\n\tif (wxFileName::IsFileReadable(fileName)) {\n\t\tRefTemplateFile refTemplateFile(fileName);\n\t\trefTemplateFile.GetAll(refTemplates);\n\t}\n\n\tRefTemplateCollection refTemplateCol;\n\trefTemplateCol.Load(GetProjectPath() + \"/RefTemplates\");\n\trefTemplateCol.GetAll(refTemplates);\n}\n\nvoid OutfitStudioFrame::ClearProject() {\n\tif (editUV)\n\t\teditUV->Close();\n\n\tfor (auto& s : project->GetWorkNif()->GetShapeNames())\n\t\tglView->DeleteMesh(s);\n\n\tproject->mFileName.clear();\n\tproject->mOutfitName.clear();\n\tproject->mDataDir.clear();\n\tproject->mBaseFile.clear();\n\tproject->mGamePath.clear();\n\tproject->mGameFile.clear();\n\n\tif (wxGetApp().targetGame == SKYRIM || wxGetApp().targetGame == SKYRIMSE || wxGetApp().targetGame == SKYRIMVR)\n\t\tproject->mGenWeights = true;\n\telse\n\t\tproject->mGenWeights = false;\n\n\tproject->mCopyRef = true;\n\n\tglView->gls.ClearOverlays();\n\tactivePartition.Unset();\n\tactiveSegment.Unset();\n\n\tlastCheckedSlider.clear();\n\tlastSelectedBones.clear();\n\tlastNormalizeBones.clear();\n\n\tif (currentTabButton)\n\t\tcurrentTabButton->SetPendingChanges(false);\n\n\tauto cMaskName = (wxComboBox*)FindWindowByName(\"cMaskName\");\n\tcMaskName->Clear();\n\n\tauto cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\tcPoseName->Clear();\n\tcPoseName->Append(\"<New>\", (void*)nullptr);\n\tcPoseName->SetStringSelection(\"<New>\");\n\n\tif (projectNotes && notesPane) {\n\t\tprojectNotes->Clear();\n\t\tnotesPane->Collapse();\n\n\t\twxWindow* parentPanel = FindWindowByName(\"bottomSplitPanel\");\n\t\tif (parentPanel)\n\t\t\tparentPanel->Layout();\n\t}\n\n\tproject->outfitName.clear();\n\tpendingChanges = false;\n\tUpdateTitle();\n}\n\nvoid OutfitStudioFrame::RenameProject(const std::string& projectName) {\n\tproject->outfitName = projectName;\n\tif (outfitRoot.IsOk())\n\t\toutfitShapes->SetItemText(outfitRoot, wxString::FromUTF8(projectName));\n\n\tUpdateTitle();\n}\n\nvoid OutfitStudioFrame::LockShapeSelect() {\n\tselectionLocked = true;\n\toutfitShapes->Disable();\n}\n\nvoid OutfitStudioFrame::UnlockShapeSelect() {\n\tselectionLocked = false;\n\toutfitShapes->Enable();\n}\n\nvoid OutfitStudioFrame::RefreshGUIFromProj(bool render, bool stashMasks) {\n\tLockShapeSelect();\n\n\tselectedItems.clear();\n\tstd::vector<ShapeItemState> prevStates;\n\n\tif (outfitRoot.IsOk()) {\n\t\t// Collect names from tree items using the tree label text (safe even if NiShape* is dangling)\n\t\twxTreeItemIdValue cookie;\n\t\twxTreeItemId child = outfitShapes->GetFirstChild(outfitRoot, cookie);\n\t\twhile (child.IsOk()) {\n\t\t\tauto itemData = (ShapeItemData*)outfitShapes->GetItemData(child);\n\t\t\tif (itemData) {\n\t\t\t\tShapeItemState prevState{};\n\t\t\t\tprevState.shapeName = outfitShapes->GetItemText(child).ToUTF8().data();\n\t\t\t\tprevState.state = outfitShapes->GetItemState(child);\n\n\t\t\t\tif (outfitShapes->IsSelected(child))\n\t\t\t\t\tprevState.selected = true;\n\n\t\t\t\tprevStates.push_back(prevState);\n\t\t\t}\n\n\t\t\tchild = outfitShapes->GetNextChild(outfitRoot, cookie);\n\t\t}\n\n\t\toutfitShapes->UnselectAll();\n\t\toutfitShapes->DeleteChildren(outfitRoot);\n\t\toutfitShapes->Delete(outfitRoot);\n\t\toutfitRoot.Unset();\n\t}\n\n\tauto shapes = project->GetWorkNif()->GetShapes();\n\tif (shapes.size() > 0) {\n\t\tif (shapes.size() == 1 && project->IsBaseShape(shapes.front()))\n\t\t\toutfitRoot = outfitShapes->AppendItem(shapesRoot, \"Reference Only\");\n\t\telse\n\t\t\toutfitRoot = outfitShapes->AppendItem(shapesRoot, wxString::FromUTF8(project->OutfitName()));\n\t}\n\n\twxTreeItemId item;\n\twxTreeItemId firstItem;\n\twxTreeItemId prevFirstSelItem;\n\tfor (auto& shape : shapes) {\n\t\tauto itemData = new ShapeItemData(shape);\n\t\titem = outfitShapes->AppendItem(outfitRoot, wxString::FromUTF8(shape->name.get()));\n\t\toutfitShapes->SetItemState(item, 0);\n\t\toutfitShapes->SetItemData(item, itemData);\n\n\t\tif (project->IsBaseShape(shape)) {\n\t\t\toutfitShapes->SetItemBold(item);\n\t\t\toutfitShapes->SetItemTextColour(item, wxColour(0, 255, 0));\n\t\t}\n\n\t\tauto it = std::find_if(prevStates.begin(), prevStates.end(), [&shape](const ShapeItemState& state) { return state.shapeName == shape->name.get(); });\n\n\t\tif (it != prevStates.end()) {\n\t\t\toutfitShapes->SetItemState(item, it->state);\n\n\t\t\tif (it->selected) {\n\t\t\t\toutfitShapes->SelectItem(item);\n\t\t\t\tselectedItems.push_back(itemData);\n\n\t\t\t\tif (!prevFirstSelItem.IsOk())\n\t\t\t\t\tprevFirstSelItem = item;\n\t\t\t}\n\t\t}\n\n\t\tif (!firstItem.IsOk())\n\t\t\tfirstItem = item;\n\t}\n\n\tUnlockShapeSelect();\n\n\tif (prevFirstSelItem.IsOk())\n\t\tactiveItem = (ShapeItemData*)outfitShapes->GetItemData(prevFirstSelItem);\n\telse if (firstItem.IsOk())\n\t\toutfitShapes->SelectItem(firstItem);\n\telse\n\t\tactiveItem = nullptr;\n\n\toutfitShapes->ExpandAll();\n\n\tif (stashMasks) {\n\t\tauto maskStash = glView->StashMasks();\n\t\tMeshesFromProj();\n\t\tglView->UnstashMasks(maskStash);\n\t}\n\telse\n\t\tMeshesFromProj();\n\n\tUpdateAnimationGUI();\n\n\tif (outfitRoot.IsOk()) {\n\t\twxTreeItemIdValue cookie;\n\t\twxTreeItemId child = outfitShapes->GetFirstChild(outfitRoot, cookie);\n\t\twhile (child.IsOk()) {\n\t\t\tbool vis = true;\n\t\t\tbool ghost = false;\n\n\t\t\tint state = outfitShapes->GetItemState(child);\n\t\t\tswitch (state) {\n\t\t\t\tcase 1:\n\t\t\t\t\tvis = false;\n\t\t\t\t\tghost = false;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 2:\n\t\t\t\t\tvis = true;\n\t\t\t\t\tghost = true;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tvis = true;\n\t\t\t\t\tghost = false;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tstd::string shapeName{outfitShapes->GetItemText(child).ToUTF8()};\n\t\t\tglView->SetShapeGhostMode(shapeName, ghost);\n\t\t\tglView->ShowShape(shapeName, vis);\n\t\t\tchild = outfitShapes->GetNextChild(outfitRoot, cookie);\n\t\t}\n\t}\n\n\tUpdateUndoTools();\n\tglView->UpdateFloor();\n\n\tif (render)\n\t\tglView->Render();\n}\n\nvoid OutfitStudioFrame::UpdateAnimationGUI() {\n\t// Preserve x-mirror and pose bones\n\tint xMChoice = cXMirrorBone->GetSelection();\n\tstd::string manualXMirrorBone;\n\tif (xMChoice >= 2)\n\t\tmanualXMirrorBone = cXMirrorBone->GetString(xMChoice);\n\n\tstd::string poseBone;\n\tint poseBoneSel = cPoseBone->GetSelection();\n\tif (poseBoneSel != wxNOT_FOUND)\n\t\tposeBone = cPoseBone->GetString(poseBoneSel).ToStdString();\n\n\tif (lastSelectedBones.count(activeBone) == 0)\n\t\tactiveBone.clear();\n\n\tUpdateBoneTree();\n\n\tcXMirrorBone->Freeze();\n\tcXMirrorBone->Clear();\n\tcXMirrorBone->AppendString(\"None\");\n\tcXMirrorBone->AppendString(\"Auto\");\n\tcXMirrorBone->SetSelection(xMChoice == 1 ? 1 : 0);\n\n\tcPoseBone->Freeze();\n\tcPoseBone->Clear();\n\n\tstd::vector<std::string> activeBones;\n\tproject->GetActiveBones(activeBones);\n\n\twxArrayString activeBonesArr;\n\tfor (auto& bone : activeBones)\n\t\tactiveBonesArr.Add(wxString::FromUTF8(bone));\n\n\tcXMirrorBone->Append(activeBonesArr);\n\tcPoseBone->Append(activeBonesArr);\n\n\t// Re-fill mirror and pose bone lists\n\tfor (auto& bone : activeBones) {\n\t\tif (xMChoice >= 2 && bone == manualXMirrorBone)\n\t\t\tcXMirrorBone->SetSelection(cXMirrorBone->GetCount() - 1);\n\n\t\tif (poseBone == bone)\n\t\t\tcPoseBone->SetSelection(cPoseBone->GetCount() - 1);\n\t}\n\n\tCalcAutoXMirrorBone();\n\n\tif (cPoseBone->GetSelection() == wxNOT_FOUND && cPoseBone->GetCount() > 0)\n\t\tcPoseBone->SetSelection(0);\n\n\tcXMirrorBone->Thaw();\n\tcPoseBone->Thaw();\n\n\tauto cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\tcPoseName->Clear();\n\n\tstd::string poseDataPath = GetProjectPath() + \"/PoseData\";\n\tposeDataCollection.LoadData(poseDataPath);\n\n\t// Additionally load community-supplied ScreenArcherMenu/SAF poses if the\n\t// target game ships them in a known location:\n\t//   Skyrim SE/VR: Data\\SAM\\Poses\\*.yaml\n\t//   Fallout 4/VR: Data\\F4SE\\Plugins\\SAF\\Poses\\*.json\n\tconst TargetGame samGame = wxGetApp().targetGame;\n\twxString samRelDir;\n\tbool samUsesJson = false;\n\tswitch (samGame) {\n\tcase SKYRIMSE:\n\tcase SKYRIMVR:\n\t\tsamRelDir = wxString(\"SAM\") + PathSepChar + \"Poses\";\n\t\tbreak;\n\tcase FO4:\n\tcase FO4VR:\n\t\tsamRelDir = wxString(\"F4SE\") + PathSepChar + \"Plugins\" + PathSepChar + \"SAF\" + PathSepChar + \"Poses\";\n\t\tsamUsesJson = true;\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n\n\tif (!samRelDir.IsEmpty()) {\n\t\twxString gameDataPath = wxGetApp().GetGameDataPath(samGame);\n\t\tif (!gameDataPath.IsEmpty()) {\n\t\t\tif (!gameDataPath.EndsWith(PathSepChar))\n\t\t\t\tgameDataPath.Append(PathSepChar);\n\t\t\twxString samDir = gameDataPath + samRelDir;\n\t\t\tif (wxDirExists(samDir)) {\n\t\t\t\tstd::string utf8Dir(samDir.ToUTF8().data());\n\t\t\t\tif (samUsesJson)\n\t\t\t\t\tposeDataCollection.LoadJsonData(utf8Dir, \"SAM: \");\n\t\t\t\telse\n\t\t\t\t\tposeDataCollection.LoadYamlData(utf8Dir, \"SAM: \");\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (auto& poseData : poseDataCollection.poseData) {\n\t\twxString poseName = wxString::FromUTF8(poseData.name);\n\t\tcPoseName->Append(poseName, &poseData);\n\t}\n\n\t// Dummy sentinel entry representing a clean/empty pose.\n\tcPoseName->Append(\"<New>\", (void*)nullptr);\n\tcPoseName->SetStringSelection(\"<New>\");\n\n\t// Reflect the read-only state of the initially selected pose (if any).\n\tUpdatePoseButtonStates();\n\n\tRefreshGUIWeightColors();\n\tPoseToGUI();\n\n\tglView->UpdateNodes();\n\tglView->UpdateBones();\n}\n\nvoid OutfitStudioFrame::UpdateBoneItemState(const wxTreeItemId& item, const std::string& boneName) {\n\tbool badBone = false;\n\tif (activeItem) {\n\t\tauto* shape = activeItem->GetShape();\n\t\tif (shape && project->GetWorkNif()->IsValid() && project->GetWorkNif()->GetBlockID(shape) != nifly::NIF_NPOS)\n\t\t\tbadBone = project->GetWorkAnim()->BoneHasInconsistentTransforms(shape->name.get(), boneName);\n\t}\n\toutfitBones->SetItemState(item, (lastNormalizeBones.count(boneName) != 0 ? 1 : 0) + (badBone ? 2 : 0));\n}\n\nvoid OutfitStudioFrame::UpdateBoneTree() {\n\tbool saveRUI = recursingUI;\n\trecursingUI = true;\n\n\toutfitBones->Freeze();\n\n\t// Clear bone tree\n\tif (outfitBones->GetChildrenCount(bonesRoot) > 0)\n\t\toutfitBones->DeleteChildren(bonesRoot);\n\n\twxString filterStr = bonesFilter->GetValue();\n\tfilterStr.MakeLower();\n\n\t// Refill bone tree, re-setting normalize state and re-selecting bones\n\tstd::vector<std::string> activeBones;\n\tproject->GetActiveBones(activeBones);\n\n\tfor (auto& bone : activeBones) {\n\t\t// Filter out bone by name\n\t\twxString boneStr = wxString::FromUTF8(bone);\n\t\tif (!boneStr.Lower().Contains(filterStr))\n\t\t\tcontinue;\n\n\t\twxTreeItemId item = outfitBones->AppendItem(bonesRoot, boneStr);\n\t\tUpdateBoneItemState(item, bone);\n\n\t\tif (lastSelectedBones.count(bone) != 0) {\n\t\t\toutfitBones->SelectItem(item);\n\t\t\tif (activeBone.empty())\n\t\t\t\tactiveBone = bone;\n\t\t}\n\t}\n\n\toutfitBones->Thaw();\n\n\trecursingUI = saveRUI;\n\n\tHighlightBoneNamesWithWeights();\n\tUpdateBoneCounts();\n}\n\nvoid OutfitStudioFrame::MeshesFromProj(const bool reloadTextures) {\n\tglView->gls.DeleteOverlay(\"refineErrorEdges\");\n\n\tfor (auto& shape : project->GetWorkNif()->GetShapes())\n\t\tMeshFromProj(shape, reloadTextures);\n\n\tif (glView->GetVertexEdit())\n\t\tglView->ShowVertexEdit();\n}\n\nvoid OutfitStudioFrame::MeshFromProj(NiShape* shape, const bool reloadTextures) {\n\tif (editUV)\n\t\teditUV->Close();\n\n\tif (extInitialized) {\n\t\tglView->DeleteMesh(shape->name.get());\n\t\tglView->AddMeshFromNif(project->GetWorkNif(), shape->name.get());\n\n\t\tMaterialFile matFile;\n\t\tbool hasMatFile = project->GetShapeMaterialFile(shape, matFile);\n\t\tglView->SetMeshTextures(shape->name.get(), project->GetShapeTextures(shape), hasMatFile, matFile, reloadTextures);\n\n\t\tUpdateMeshFromSet(shape);\n\t}\n\n\tstd::vector<std::string> selShapes;\n\tfor (auto& i : selectedItems)\n\t\tselShapes.push_back(i->GetShape()->name.get());\n\n\tglView->SetActiveShapes(selShapes);\n\n\tif (activeItem)\n\t\tglView->SetSelectedShape(activeItem->GetShape()->name.get());\n\telse\n\t\tglView->SetSelectedShape(\"\");\n}\n\nvoid OutfitStudioFrame::UpdateMeshFromSet(NiShape* shape) {\n\tbool disableNormalsCalc = OutfitStudioConfig.GetBoolValue(\"DisableNormalsCalc\");\n\n\tstd::string shapeName = shape->name.get();\n\tMesh* m = glView->GetMesh(shapeName);\n\tif (m) {\n\t\tm->smoothSeamNormals = project->activeSet.GetSmoothSeamNormals(shapeName);\n\t\tm->smoothSeamNormalsAngle = project->activeSet.GetSmoothSeamNormalsAngle(shapeName);\n\t\tm->lockNormals = disableNormalsCalc || project->activeSet.GetLockNormals(shapeName);\n\t}\n}\n\nvoid OutfitStudioFrame::FillVertexColors() {\n\tstd::vector<std::string> shapeNames = project->GetWorkNif()->GetShapeNames();\n\n\tfor (auto& s : shapeNames) {\n\t\tMesh* m = glView->GetMesh(s);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tm->ColorFill(Vector3(1.0f, 1.0f, 1.0f));\n\t\tm->AlphaFill(1.0f);\n\n\t\tconst std::vector<Color4>* vcolors = project->GetWorkNif()->GetColorsForShape(s);\n\t\tif (vcolors) {\n\t\t\tfor (size_t v = 0; v < vcolors->size(); v++) {\n\t\t\t\tm->vcolors[v].x = vcolors->at(v).r;\n\t\t\t\tm->vcolors[v].y = vcolors->at(v).g;\n\t\t\t\tm->vcolors[v].z = vcolors->at(v).b;\n\t\t\t\tm->valpha[v] = vcolors->at(v).a;\n\t\t\t}\n\t\t}\n\t}\n}\n\nbool OutfitStudioFrame::ShapeSelectionCheck() {\n\tif (!activeItem) {\n\t\twxMessageBox(_(\"There is no shape selected!\"), _(\"Error\"));\n\t\treturn false;\n\t}\n\treturn true;\n}\n\nvoid OutfitStudioFrame::OnSSSNameCopy(wxCommandEvent& event) {\n\twxWindow* win = ((wxButton*)event.GetEventObject())->GetParent();\n\tstd::string copyStr{XRCCTRL(*win, \"sssName\", wxTextCtrl)->GetValue().ToUTF8()};\n\n\tproject->ReplaceForbidden(copyStr);\n\n\twxString defStr = wxString::FromUTF8(copyStr);\n\twxString defSliderSetFile = defStr + \".osp\";\n\twxString defShapeDataDir = defStr;\n\twxString defOutputFile = defStr + \".nif\";\n\n\twxFilePickerCtrl* fp = (wxFilePickerCtrl*)win->FindWindowByName(\"sssSliderSetFile\");\n\tfp->SetPath(defSliderSetFile);\n\n\twxDirPickerCtrl* dp = (wxDirPickerCtrl*)win->FindWindowByName(\"sssShapeDataFolder\");\n\tdp->SetPath(defShapeDataDir);\n\n\tfp = (wxFilePickerCtrl*)win->FindWindowByName(\"sssShapeDataFile\");\n\tfp->SetPath(defOutputFile);\n}\n\nvoid OutfitStudioFrame::OnSSSGenWeightsTrue(wxCommandEvent& event) {\n\twxWindow* win = ((wxRadioButton*)event.GetEventObject())->GetParent();\n\tXRCCTRL(*win, \"m_lowHighInfo\", wxStaticText)->SetLabel(\"_0/_1.nif\");\n}\n\nvoid OutfitStudioFrame::OnSSSGenWeightsFalse(wxCommandEvent& event) {\n\twxWindow* win = ((wxRadioButton*)event.GetEventObject())->GetParent();\n\tXRCCTRL(*win, \"m_lowHighInfo\", wxStaticText)->SetLabel(\".nif\");\n}\n\nvoid OutfitStudioFrame::OnSaveSliderSet(wxCommandEvent& WXUNUSED(event)) {\n\tSaveProject();\n}\n\nvoid OutfitStudioFrame::OnSaveSliderSetAs(wxCommandEvent& WXUNUSED(event)) {\n\tSaveProjectAs();\n}\n\nvoid OutfitStudioFrame::OnSetBaseShape(wxCommandEvent& WXUNUSED(event)) {\n\twxLogMessage(\"Setting new base shape.\");\n\tSetBaseShape();\n}\n\nvoid OutfitStudioFrame::SetBaseShape() {\n\tfor (auto& s : project->GetWorkNif()->GetShapes())\n\t\tUpdateShapeSource(s);\n\n\tZeroSliders();\n\tif (!activeSlider.empty()) {\n\t\tbEditSlider = false;\n\t\tauto it = sliderPanels.find(activeSlider);\n\t\tif (it != sliderPanels.end() && it->second)\n\t\t\tit->second->slider->SetFocus();\n\t\tHighlightSlider(\"\");\n\t\tactiveSlider.clear();\n\t}\n}\n\nvoid OutfitStudioFrame::OnImportNIF(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog importDialog(this, _(\"Import NIF file\"), wxEmptyString, wxEmptyString, \"NIF Files (*.nif)|*.nif\", wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\n\tif (importDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxArrayString fileNames;\n\timportDialog.GetPaths(fileNames);\n\n\tStartProgress(_(\"Importing NIF file...\"));\n\tUpdateProgress(1, _(\"Importing NIF file...\"));\n\n\tfor (auto& fileName : fileNames)\n\t\tproject->ImportNIF(fileName.ToUTF8().data(), false);\n\n\tUpdateProgress(60, _(\"Refreshing GUI...\"));\n\tproject->SetTextures();\n\n\tSetPendingChanges();\n\tRefreshGUIFromProj();\n\n\tUpdateTitle();\n\tEndProgress();\n}\n\nstd::optional<bool> OutfitStudioFrame::PromptStarfieldGeometryMode() {\n\tauto* nif = project->GetWorkNif();\n\tif (!nif->GetHeader().GetVersion().IsSF())\n\t\treturn std::nullopt;\n\n\tint result = wxMessageBox(\n\t\t_(\"Starfield supports two modes for mesh geometry data:\\n\\n\"\n\t\t  \"Internal: Mesh data is embedded directly in the NIF file.\\n\"\n\t\t  \"Simpler for modding - single file, no external dependencies.\\n\\n\"\n\t\t  \"External: Mesh data is stored in separate .mesh files under geometries/.\\n\"\n\t\t  \"Can be streamed from BA2 archives for better game performance.\\n\\n\"\n\t\t  \"Would you like to embed the geometry data in the NIF (internal)?\\n\"\n\t\t  \"Choose 'Yes' for internal or 'No' for external.\"),\n\t\t_(\"Starfield Geometry Mode\"),\n\t\twxYES_NO | wxICON_QUESTION,\n\t\tthis);\n\n\treturn (result == wxYES);\n}\n\nvoid OutfitStudioFrame::OnExportNIF(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid())\n\t\treturn;\n\n\tif (HasUnweightedCheck())\n\t\treturn;\n\n\twxString fileName = wxFileSelector(_(\"Export outfit NIF\"), wxEmptyString, wxEmptyString, \".nif\", \"*.nif\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fileName.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting project to NIF file '%s'...\", fileName);\n\n\tstd::vector<Mesh*> shapeMeshes;\n\tfor (auto& s : project->GetWorkNif()->GetShapes()) {\n\t\tif (!project->IsBaseShape(s)) {\n\t\t\tMesh* m = glView->GetMesh(s->name.get());\n\t\t\tif (m)\n\t\t\t\tshapeMeshes.push_back(m);\n\t\t}\n\t}\n\n\tauto useInternalGeom = PromptStarfieldGeometryMode();\n\n\tint error = project->ExportNIF(fileName.ToUTF8().data(), shapeMeshes, false, useInternalGeom);\n\tif (error) {\n\t\twxLogError(\"Failed to save NIF file '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Failed to save NIF file '%s'!\"), fileName), _(\"Export Error\"), wxICON_ERROR);\n\t}\n}\n\nvoid OutfitStudioFrame::OnExportNIFWithRef(wxCommandEvent& event) {\n\tif (!project->GetWorkNif()->IsValid())\n\t\treturn;\n\n\tif (!project->GetBaseShape()) {\n\t\tOnExportNIF(event);\n\t\treturn;\n\t}\n\n\tif (HasUnweightedCheck())\n\t\treturn;\n\n\twxString fileName = wxFileSelector(_(\"Export project NIF\"), wxEmptyString, wxEmptyString, \".nif\", \"*.nif\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fileName.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting project with reference to NIF file '%s'...\", fileName);\n\n\tstd::vector<Mesh*> shapeMeshes;\n\tfor (auto& s : project->GetWorkNif()->GetShapeNames()) {\n\t\tMesh* m = glView->GetMesh(s);\n\t\tif (m)\n\t\t\tshapeMeshes.push_back(m);\n\t}\n\n\tauto useInternalGeom = PromptStarfieldGeometryMode();\n\n\tint error = project->ExportNIF(fileName.ToUTF8().data(), shapeMeshes, true, useInternalGeom);\n\tif (error) {\n\t\twxLogError(\"Failed to save NIF file '%s' with reference!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Failed to save NIF file '%s' with reference!\"), fileName), _(\"Export Error\"), wxICON_ERROR);\n\t}\n}\n\nvoid OutfitStudioFrame::OnExportShapeNIF(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (HasUnweightedCheck())\n\t\treturn;\n\n\twxString fileName = wxFileSelector(_(\"Export selected shapes to NIF\"), wxEmptyString, wxEmptyString, \".nif\", \"*.nif\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fileName.IsEmpty())\n\t\treturn;\n\n\tstd::vector<std::string> shapes;\n\tfor (auto& i : selectedItems)\n\t\tshapes.push_back(i->GetShape()->name.get());\n\n\twxLogMessage(\"Exporting selected shapes to NIF file '%s'.\", fileName);\n\n\tauto useInternalGeom = PromptStarfieldGeometryMode();\n\n\tif (project->ExportShapeNIF(fileName.ToUTF8().data(), shapes, useInternalGeom)) {\n\t\twxLogError(\"Failed to export selected shapes to NIF file '%s'!\", fileName);\n\t\twxMessageBox(_(\"Failed to export selected shapes to NIF file!\"), _(\"Error\"), wxICON_ERROR);\n\t}\n}\n\nvoid OutfitStudioFrame::OnImportOBJ(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog importDialog(this, _(\"Import .obj file for new shape\"), wxEmptyString, wxEmptyString, \"OBJ Files (*.obj)|*.obj\", wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\n\tif (importDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxArrayString fileNames;\n\timportDialog.GetPaths(fileNames);\n\n\tfor (auto& fileName : fileNames) {\n\t\twxLogMessage(\"Importing shape(s) from OBJ file '%s'...\", fileName);\n\n\t\tint ret;\n\t\tif (activeItem)\n\t\t\tret = project->ImportOBJ(fileName.ToUTF8().data(), project->OutfitName(), activeItem->GetShape());\n\t\telse\n\t\t\tret = project->ImportOBJ(fileName.ToUTF8().data(), project->OutfitName());\n\n\t\tif (ret == 101)\n\t\t\twxLogMessage(\"Updated shape '%s' from OBJ file '%s'.\", activeItem->GetShape()->name.get(), fileName);\n\t}\n\n\tRefreshGUIFromProj(false);\n\tSetPendingChanges();\n\n\twxLogMessage(\"Imported shape(s) from OBJ.\");\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnExportOBJ(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid())\n\t\treturn;\n\n\tbool hasSkinTrans = false;\n\tfor (NiShape* shape : project->GetWorkNif()->GetShapes()) {\n\t\tif (!project->GetWorkAnim()->GetTransformGlobalToShape(shape).IsNearlyEqualTo(MatTransform()))\n\t\t\thasSkinTrans = true;\n\t}\n\tbool transToGlobal = false;\n\tif (hasSkinTrans) {\n\t\tint res = wxMessageBox(_(\"Some of the shapes have coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to \"\n\t\t\t\t\t\t\t\t \"global coordinates in the OBJ?  (This is not recommended.)\"),\n\t\t\t\t\t\t\t   _(\"Transform to global\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL);\n\t\tif (res == wxCANCEL)\n\t\t\treturn;\n\t\ttransToGlobal = (res == wxYES);\n\t}\n\n\twxString fileName = wxFileSelector(_(\"Export project as an .obj file\"), wxEmptyString, wxEmptyString, \".obj\", \"*.obj\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fileName.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting project to OBJ file '%s'...\", fileName);\n\n\tif (project->ExportOBJ(fileName.ToUTF8().data(), project->GetWorkNif()->GetShapes(), transToGlobal, Vector3(0.1f, 0.1f, 0.1f))) {\n\t\twxLogError(\"Failed to export OBJ file '%s'!\", fileName);\n\t\twxMessageBox(_(\"Failed to export OBJ file!\"), _(\"Export Error\"), wxICON_ERROR);\n\t}\n}\n\nvoid OutfitStudioFrame::OnExportShapeOBJ(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tbool hasSkinTrans = false;\n\tfor (auto& i : selectedItems) {\n\t\tNiShape* shape = i->GetShape();\n\t\tif (!project->GetWorkAnim()->GetTransformGlobalToShape(shape).IsNearlyEqualTo(MatTransform()))\n\t\t\thasSkinTrans = true;\n\t}\n\tbool transToGlobal = false;\n\tif (hasSkinTrans) {\n\t\tint res = wxMessageBox(_(\"Some of the shapes have skin coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to \"\n\t\t\t\t\t\t\t\t \"global coordinates in the OBJ?\"),\n\t\t\t\t\t\t\t   _(\"Transform to global\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL);\n\t\tif (res == wxCANCEL)\n\t\t\treturn;\n\t\ttransToGlobal = (res == wxYES);\n\t}\n\n\tif (selectedItems.size() > 1) {\n\t\twxString fileName\n\t\t\t= wxFileSelector(_(\"Export selected shapes as an .obj file\"), wxEmptyString, wxEmptyString, \".obj\", \"OBJ Files (*.obj)|*.obj\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\t\tif (fileName.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting selected shapes as OBJ file to '%s'.\", fileName);\n\n\t\tstd::vector<NiShape*> shapes;\n\t\tshapes.reserve(selectedItems.size());\n\t\tfor (auto& i : selectedItems)\n\t\t\tshapes.push_back(i->GetShape());\n\n\t\tif (project->ExportOBJ(fileName.ToUTF8().data(), shapes, transToGlobal, Vector3(0.1f, 0.1f, 0.1f))) {\n\t\t\twxLogError(\"Failed to export OBJ file '%s'!\", fileName);\n\t\t\twxMessageBox(_(\"Failed to export OBJ file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\telse {\n\t\twxString fileName = wxFileSelector(_(\"Export shape as an .obj file\"),\n\t\t\t\t\t\t\t\t\t\t   wxEmptyString,\n\t\t\t\t\t\t\t\t\t\t   wxString(activeItem->GetShape()->name.get() + \".obj\"),\n\t\t\t\t\t\t\t\t\t\t   \".obj\",\n\t\t\t\t\t\t\t\t\t\t   \"OBJ Files (*.obj)|*.obj\",\n\t\t\t\t\t\t\t\t\t\t   wxFD_SAVE | wxFD_OVERWRITE_PROMPT,\n\t\t\t\t\t\t\t\t\t\t   this);\n\t\tif (fileName.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting shape '%s' as OBJ file to '%s'.\", activeItem->GetShape()->name.get(), fileName);\n\n\t\tstd::vector<NiShape*> shapes = {activeItem->GetShape()};\n\t\tif (project->ExportOBJ(fileName.ToUTF8().data(), shapes, transToGlobal, Vector3(0.1f, 0.1f, 0.1f))) {\n\t\t\twxLogError(\"Failed to export OBJ file '%s'!\", fileName);\n\t\t\twxMessageBox(_(\"Failed to export OBJ file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnImportFBX(wxCommandEvent& WXUNUSED(event)) {\n#ifdef USE_FBXSDK\n\twxFileDialog importDialog(this, _(\"Import .fbx file for new shape\"), wxEmptyString, wxEmptyString, \"FBX Files (*.fbx)|*.fbx\", wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\n\tif (importDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxArrayString fileNames;\n\timportDialog.GetPaths(fileNames);\n\n\tfor (auto& fileName : fileNames) {\n\t\twxLogMessage(\"Importing shape(s) from FBX file '%s'...\", fileName);\n\n\t\tint ret;\n\t\tif (activeItem)\n\t\t\tret = project->ImportFBX(fileName.ToUTF8().data(), project->OutfitName(), activeItem->GetShape());\n\t\telse\n\t\t\tret = project->ImportFBX(fileName.ToUTF8().data(), project->OutfitName());\n\n\t\tif (ret == 101)\n\t\t\twxLogMessage(\"Updated shape '%s' from FBX file '%s'.\", activeItem->GetShape()->name.get(), fileName);\n\t}\n\n\tRefreshGUIFromProj(false);\n\tSetPendingChanges();\n\n\twxLogMessage(\"Imported shape(s) from FBX.\");\n\tglView->Render();\n#else\n\twxMessageBox(_(\"FBX is only supported in 64-bit builds of Outfit Studio. Start \\\"OutfitStudio x64\\\" instead.\"), _(\"Info\"), wxICON_INFORMATION);\n#endif\n}\n\nvoid OutfitStudioFrame::OnExportFBX(wxCommandEvent& WXUNUSED(event)) {\n#ifdef USE_FBXSDK\n\tif (!project->GetWorkNif()->IsValid())\n\t\treturn;\n\n\tif (HasUnweightedCheck())\n\t\treturn;\n\n\tbool hasSkinTrans = false;\n\tfor (NiShape* shape : project->GetWorkNif()->GetShapes()) {\n\t\tif (!project->GetWorkAnim()->GetTransformGlobalToShape(shape).IsNearlyEqualTo(MatTransform()))\n\t\t\thasSkinTrans = true;\n\t}\n\tbool transToGlobal = false;\n\tif (hasSkinTrans) {\n\t\tint res = wxMessageBox(_(\"Some of the shapes have skin coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to \"\n\t\t\t\t\t\t\t\t \"global coordinates in the FBX?  (This is not recommended.)\"),\n\t\t\t\t\t\t\t   _(\"Transform to global\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL);\n\t\tif (res == wxCANCEL)\n\t\t\treturn;\n\t\ttransToGlobal = (res == wxYES);\n\t}\n\n\twxString fileName = wxFileSelector(_(\"Export project as an .fbx file\"), wxEmptyString, wxEmptyString, \".fbx\", \"FBX Files (*.fbx)|*.fbx\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fileName.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting project to OBJ file '%s'...\", fileName);\n\n\tif (!project->ExportFBX(fileName.ToUTF8().data(), project->GetWorkNif()->GetShapes(), transToGlobal)) {\n\t\twxLogError(\"Failed to export FBX file '%s'!\", fileName);\n\t\twxMessageBox(_(\"Failed to export FBX file!\"), _(\"Export Error\"), wxICON_ERROR);\n\t}\n#else\n\twxMessageBox(_(\"FBX is only supported in 64-bit builds of Outfit Studio. Start \\\"OutfitStudio x64\\\" instead.\"), _(\"Info\"), wxICON_INFORMATION);\n#endif\n}\n\nvoid OutfitStudioFrame::OnExportShapeFBX(wxCommandEvent& WXUNUSED(event)) {\n#ifdef USE_FBXSDK\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tbool hasSkinTrans = false;\n\tfor (auto& i : selectedItems) {\n\t\tNiShape* shape = i->GetShape();\n\t\tif (!project->GetWorkAnim()->GetTransformGlobalToShape(shape).IsNearlyEqualTo(MatTransform()))\n\t\t\thasSkinTrans = true;\n\t}\n\tbool transToGlobal = false;\n\tif (hasSkinTrans) {\n\t\tint res = wxMessageBox(_(\"Some of the shapes have skin coordinate systems that are not the same as the global coordinate system.  Should the geometry be transformed to \"\n\t\t\t\t\t\t\t\t \"global coordinates in the FBX?\"),\n\t\t\t\t\t\t\t   _(\"Transform to global\"),\n\t\t\t\t\t\t\t   wxYES_NO | wxCANCEL);\n\t\tif (res == wxCANCEL)\n\t\t\treturn;\n\t\ttransToGlobal = (res == wxYES);\n\t}\n\n\tif (selectedItems.size() > 1) {\n\t\twxString fileName\n\t\t\t= wxFileSelector(_(\"Export selected shapes as an .fbx file\"), wxEmptyString, wxEmptyString, \".fbx\", \"FBX Files (*.fbx)|*.fbx\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\t\tif (fileName.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting selected shapes as FBX file to '%s'.\", fileName);\n\n\t\tstd::vector<NiShape*> shapes;\n\t\tshapes.reserve(selectedItems.size());\n\t\tfor (auto& i : selectedItems)\n\t\t\tshapes.push_back(i->GetShape());\n\n\t\tif (!project->ExportFBX(fileName.ToUTF8().data(), shapes, transToGlobal)) {\n\t\t\twxLogError(\"Failed to export FBX file '%s'!\", fileName);\n\t\t\twxMessageBox(_(\"Failed to export FBX file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\telse {\n\t\twxString fileName = wxFileSelector(_(\"Export shape as an .fbx file\"),\n\t\t\t\t\t\t\t\t\t\t   wxEmptyString,\n\t\t\t\t\t\t\t\t\t\t   wxString(activeItem->GetShape()->name.get() + \".fbx\"),\n\t\t\t\t\t\t\t\t\t\t   \".fbx\",\n\t\t\t\t\t\t\t\t\t\t   \"FBX Files (*.fbx)|*.fbx\",\n\t\t\t\t\t\t\t\t\t\t   wxFD_SAVE | wxFD_OVERWRITE_PROMPT,\n\t\t\t\t\t\t\t\t\t\t   this);\n\t\tif (fileName.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting shape '%s' as FBX file to '%s'.\", activeItem->GetShape()->name.get(), fileName);\n\n\t\tstd::vector<NiShape*> shapes = {activeItem->GetShape()};\n\t\tif (!project->ExportFBX(fileName.ToUTF8().data(), shapes, transToGlobal)) {\n\t\t\twxLogError(\"Failed to export FBX file '%s'!\", fileName);\n\t\t\twxMessageBox(_(\"Failed to export FBX file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n#else\n\twxMessageBox(_(\"FBX is only supported in 64-bit builds of Outfit Studio. Start \\\"OutfitStudio x64\\\" instead.\"), _(\"Info\"), wxICON_INFORMATION);\n#endif\n}\n\nvoid OutfitStudioFrame::OnImportTRIHead(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog importDialog(this, _(\"Import .tri morphs\"), wxEmptyString, wxEmptyString, \"TRI (Head) Files (*.tri)|*.tri\", wxFD_FILE_MUST_EXIST | wxFD_MULTIPLE);\n\tif (importDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxArrayString fileNames;\n\timportDialog.GetPaths(fileNames);\n\n\tsliderScroll->Freeze();\n\tMenuExitSliderEdit();\n\tsliderScroll->FitInside();\n\tactiveSlider.clear();\n\n\tfor (auto& fn : fileNames) {\n\t\twxFileName fileName(fn);\n\t\twxLogMessage(\"Importing morphs from TRI (head) file '%s'...\", fn);\n\n\t\tTriHeadFile tri;\n\t\tif (!tri.Read(fn.ToUTF8().data())) {\n\t\t\twxLogError(\"Failed to load TRI file '%s'!\", fn);\n\t\t\twxMessageBox(_(\"Failed to load TRI file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t\treturn;\n\t\t}\n\n\t\tstd::string shapeName{fileName.GetName().ToUTF8()};\n\t\twhile (project->IsValidShape(shapeName)) {\n\t\t\tstd::string result{wxGetTextFromUser(_(\"Please enter a new unique name for the shape.\"), _(\"Rename Shape\"), shapeName, this).ToUTF8()};\n\t\t\tif (result.empty())\n\t\t\t\tcontinue;\n\n\t\t\tshapeName = std::move(result);\n\t\t}\n\n\t\tauto verts = tri.GetVertices();\n\t\tauto tris = tri.GetTriangles();\n\t\tauto uvs = tri.GetUV();\n\t\tauto shape = project->CreateNifShapeFromData(shapeName, &verts, &tris, &uvs);\n\t\tif (!shape)\n\t\t\treturn;\n\n\t\tRefreshGUIFromProj(false);\n\n\t\tauto morphs = tri.GetMorphs();\n\t\tfor (auto& morph : morphs) {\n\t\t\tif (!project->ValidSlider(morph.morphName)) {\n\t\t\t\tproject->AddEmptySlider(morph.morphName);\n\t\t\t\tcreateSliderGUI(morph.morphName, sliderScroll, sliderScroll->GetSizer());\n\t\t\t}\n\n\t\t\tstd::unordered_map<uint16_t, Vector3> diff;\n\t\t\tdiff.reserve(morph.vertices.size());\n\n\t\t\tfor (size_t i = 0; i < morph.vertices.size(); i++)\n\t\t\t\tdiff[i] = morph.vertices[i];\n\n\t\t\tproject->SetSliderFromDiff(morph.morphName, shape, diff);\n\t\t}\n\t}\n\n\tsliderScroll->FitInside();\n\tsliderScroll->Thaw();\n\n\tSetPendingChanges();\n\n\tApplySliders();\n\tDoFilterSliders();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::OnExportTRIHead(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\twxString dir = wxDirSelector(_(\"Export .tri morphs\"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, this);\n\tif (dir.IsEmpty())\n\t\treturn;\n\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tstd::string fn = dir.ToStdString() + PathSepStr + shape->name.get() + \".tri\";\n\n\t\twxLogMessage(\"Exporting TRI (head) morphs of '%s' to '%s'...\", shape->name.get(), fn);\n\t\tif (!project->WriteHeadTRI(shape, fn)) {\n\t\t\twxLogError(\"Failed to export TRI file to '%s'!\", fn);\n\t\t\twxMessageBox(_(\"Failed to export TRI file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnExportShapeTRIHead(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\twxString fn = wxFileSelector(_(\"Export .tri morphs\"), wxEmptyString, wxEmptyString, \".tri\", \"*.tri\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting TRI (head) morphs to '%s'...\", fn);\n\tif (!project->WriteHeadTRI(activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to export TRI file to '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to export TRI file!\"), _(\"Error\"), wxICON_ERROR);\n\t}\n}\n\nvoid OutfitStudioFrame::OnImportPhysicsData(wxCommandEvent& WXUNUSED(event)) {\n\twxString fileName = wxFileSelector(_(\"Import physics data to project\"), wxEmptyString, wxEmptyString, \".hkx\", \"*.hkx\", wxFD_FILE_MUST_EXIST, this);\n\tif (fileName.IsEmpty())\n\t\treturn;\n\n\tauto physicsBlock = std::make_unique<BSClothExtraData>();\n\tif (!physicsBlock->FromHKX(fileName.ToUTF8().data())) {\n\t\twxLogError(\"Failed to import physics data file '%s'!\", fileName);\n\t\twxMessageBox(wxString::Format(_(\"Failed to import physics data file '%s'!\"), fileName), _(\"Import Error\"), wxICON_ERROR);\n\t}\n\n\tauto& physicsData = project->GetClothData();\n\tphysicsData[fileName.ToUTF8().data()] = std::move(physicsBlock);\n\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnExportPhysicsData(wxCommandEvent& WXUNUSED(event)) {\n\tauto& physicsData = project->GetClothData();\n\tif (physicsData.empty()) {\n\t\twxMessageBox(_(\"There is no physics data loaded!\"), _(\"Info\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\twxArrayString fileNames;\n\tfor (auto& data : physicsData)\n\t\tfileNames.Add(wxString::FromUTF8(data.first));\n\n\twxSingleChoiceDialog physicsDataChoice(this, _(\"Please choose the physics data source you want to export.\"), _(\"Choose physics data\"), fileNames);\n\tif (physicsDataChoice.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tint sel = physicsDataChoice.GetSelection();\n\tstd::string selString{fileNames[sel].ToUTF8()};\n\n\tif (!selString.empty()) {\n\t\twxString fileName = wxFileSelector(_(\"Export physics data\"), wxEmptyString, wxEmptyString, \".hkx\", \"*.hkx\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\t\tif (fileName.IsEmpty())\n\t\t\treturn;\n\n\t\tif (!physicsData[selString]->ToHKX(fileName.ToUTF8().data())) {\n\t\t\twxLogError(\"Failed to save physics data file '%s'!\", fileName);\n\t\t\twxMessageBox(wxString::Format(_(\"Failed to save physics data file '%s'!\"), fileName), _(\"Export Error\"), wxICON_ERROR);\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnMakeConvRef(wxCommandEvent& WXUNUSED(event)) {\n\tif (project->AllSlidersZero()) {\n\t\twxMessageBox(_(\"This function requires at least one slider position to be non-zero.\"));\n\t\treturn;\n\t}\n\n\tstd::string namebase = \"ConvertToBase\";\n\tchar thename[256];\n\tsnprintf(thename, 256, \"%s\", namebase.c_str());\n\tint count = 1;\n\twhile (sliderPanels.find(thename) != sliderPanels.end())\n\t\tsnprintf(thename, 256, \"%s%d\", namebase.c_str(), count++);\n\n\tstd::string finalName{\n\t\twxGetTextFromUser(_(\"Create a conversion slider for the current slider settings with the following name: \"), _(\"Create New Conversion Slider\"), thename, this).ToUTF8()};\n\tif (finalName.empty())\n\t\treturn;\n\n\twxLogMessage(\"Creating new conversion slider '%s'...\", finalName);\n\n\tproject->AddCombinedSlider(finalName);\n\n\tauto baseShape = project->GetBaseShape();\n\tif (baseShape) {\n\t\tMesh* m = glView->GetMesh(baseShape->name.get());\n\t\tif (m)\n\t\t\tproject->UpdateShapeFromMesh(baseShape, m);\n\n\t\tproject->NegateSlider(finalName, baseShape);\n\t}\n\n\tstd::vector<std::string> sliderList;\n\tproject->GetSliderList(sliderList);\n\tfor (auto& s : sliderList) {\n\t\tif (!s.compare(finalName))\n\t\t\tcontinue;\n\t\tproject->DeleteSlider(s);\n\t}\n\n\tglView->GetUndoHistory()->ClearHistory();\n\tUpdateUndoTools();\n\n\tactiveSlider.clear();\n\tlastActiveSlider.clear();\n\tbEditSlider = false;\n\tMenuExitSliderEdit();\n\n\tCreateSetSliders();\n}\n\nvoid OutfitStudioFrame::OnSelectSliders(wxCommandEvent& event) {\n\tbool checked = event.IsChecked();\n\tfor (auto& sliderPanel : sliderPanels)\n\t\tShowSliderEffect(sliderPanel.first, checked);\n\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnSliderFilterChanged(wxCommandEvent& WXUNUSED(event)) {\n\tDoFilterSliders();\n}\n\nvoid OutfitStudioFrame::DoFilterSliders() {\n\twxString filterStr = sliderFilter->GetValue();\n\tfilterStr.MakeLower();\n\n\tfor (auto& sliderPanel : sliderPanels) {\n\t\tif (!sliderPanel.second)\n\t\t\tcontinue;\n\n\t\t// Filter slider by name\n\t\twxString sliderStr = wxString::FromUTF8(sliderPanel.first);\n\t\tif (sliderStr.Lower().Contains(filterStr)) {\n\t\t\tif (!sliderPanel.second->IsShown())\n\t\t\t\tsliderPanel.second->Show();\n\t\t}\n\t\telse {\n\t\t\tif (sliderPanel.second->IsShown())\n\t\t\t\tsliderPanel.second->Hide();\n\t\t}\n\t}\n\n\tsliderScroll->FitInside();\n}\n\nvoid OutfitStudioFrame::OnBonesFilterChanged(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateBoneTree();\n}\n\nvoid OutfitStudioFrame::OnFixedWeight(wxCommandEvent& event) {\n\tbool checked = event.IsChecked();\n\tTB_Weight* weightBrush = dynamic_cast<TB_Weight*>(glView->GetActiveBrush());\n\tif (weightBrush)\n\t\tweightBrush->bFixedWeight = checked;\n}\n\nvoid OutfitStudioFrame::OnCBNormalizeWeights(wxCommandEvent& event) {\n\tbool checked = event.IsChecked();\n\tTB_Weight* weightBrush = dynamic_cast<TB_Weight*>(glView->GetActiveBrush());\n\tif (weightBrush)\n\t\tweightBrush->bNormalizeWeights = checked;\n}\n\nvoid OutfitStudioFrame::ToggleVisibility(wxTreeItemId firstItem) {\n\tbool vis = true;\n\tbool ghost = false;\n\tint state = 0;\n\n\tif (!firstItem.IsOk()) {\n\t\tif (!selectedItems.empty()) {\n\t\t\tfirstItem = selectedItems.front()->GetId();\n\t\t}\n\t}\n\n\tif (firstItem.IsOk()) {\n\t\tstate = outfitShapes->GetItemState(firstItem);\n\t\tswitch (state) {\n\t\t\tcase 0:\n\t\t\t\tvis = false;\n\t\t\t\tghost = false;\n\t\t\t\tstate = 1;\n\t\t\t\tbreak;\n\t\t\tcase 1:\n\t\t\t\tvis = true;\n\t\t\t\tghost = true;\n\t\t\t\tstate = 2;\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tvis = true;\n\t\t\t\tghost = false;\n\t\t\t\tstate = 0;\n\t\t\t\tbreak;\n\t\t}\n\n\t\tstd::string shapeName{outfitShapes->GetItemText(firstItem).ToUTF8()};\n\t\tglView->SetShapeGhostMode(shapeName, ghost);\n\t\tglView->ShowShape(shapeName, vis);\n\t\toutfitShapes->SetItemState(firstItem, state);\n\t}\n\n\tif (selectedItems.size() > 1) {\n\t\tfor (auto& i : selectedItems) {\n\t\t\tif (i->GetId().GetID() != firstItem.GetID()) {\n\t\t\t\tstd::string shapeName{outfitShapes->GetItemText(i->GetId()).ToUTF8()};\n\t\t\t\tglView->SetShapeGhostMode(shapeName, ghost);\n\t\t\t\tglView->ShowShape(shapeName, vis);\n\t\t\t\toutfitShapes->SetItemState(i->GetId(), state);\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnShapeVisToggle(wxTreeEvent& event) {\n\tToggleVisibility(event.GetItem());\n\tevent.Skip();\n}\n\nvoid OutfitStudioFrame::OnShapeSelect(wxTreeEvent& event) {\n\twxTreeItemId item = event.GetItem();\n\tif (!item.IsOk()) {\n\t\tevent.Veto();\n\t\treturn;\n\t}\n\n\tif (selectionLocked) {\n\t\tevent.Veto();\n\t\treturn;\n\t}\n\n\tif (outfitShapes->GetItemParent(item).IsOk()) {\n\t\tif (outfitShapes->IsSelected(item))\n\t\t\tactiveItem = (ShapeItemData*)outfitShapes->GetItemData(item);\n\t\telse\n\t\t\tactiveItem = nullptr;\n\t}\n\telse {\n\t\twxTreeItemIdValue cookie;\n\t\twxTreeItemId subitem = outfitShapes->GetFirstChild(item, cookie);\n\t\tif (subitem.IsOk() && outfitShapes->IsSelected(subitem))\n\t\t\tactiveItem = (ShapeItemData*)outfitShapes->GetItemData(subitem);\n\t\telse\n\t\t\tactiveItem = nullptr;\n\t}\n\n\tselectedItems.clear();\n\n\tstd::vector<std::string> shapeNames;\n\twxArrayTreeItemIds selected;\n\toutfitShapes->GetSelections(selected);\n\n\tfor (auto& i : selected) {\n\t\tif (outfitShapes->GetItemParent(i).IsOk()) {\n\t\t\tauto data = (ShapeItemData*)outfitShapes->GetItemData(i);\n\t\t\tif (data) {\n\t\t\t\tshapeNames.push_back(data->GetShape()->name.get());\n\t\t\t\tselectedItems.push_back(data);\n\n\t\t\t\tif (!activeItem)\n\t\t\t\t\tactiveItem = data;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\twxTreeItemIdValue cookie;\n\t\t\twxTreeItemId subitem = outfitShapes->GetFirstChild(i, cookie);\n\t\t\tif (subitem.IsOk()) {\n\t\t\t\tauto data = (ShapeItemData*)outfitShapes->GetItemData(subitem);\n\t\t\t\tif (data) {\n\t\t\t\t\tshapeNames.push_back(data->GetShape()->name.get());\n\t\t\t\t\tselectedItems.push_back(data);\n\n\t\t\t\t\tif (!activeItem)\n\t\t\t\t\t\tactiveItem = data;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->SetActiveShapes(shapeNames);\n\n\tif (activeItem)\n\t\tglView->SetSelectedShape(activeItem->GetShape()->name.get());\n\telse\n\t\tglView->SetSelectedShape(\"\");\n\n\tUpdateActiveShape();\n}\n\nvoid OutfitStudioFrame::OnShapeActivated(wxTreeEvent& event) {\n\tint hitFlags;\n\toutfitShapes->HitTest(event.GetPoint(), hitFlags);\n\n\tif (hitFlags & wxTREE_HITTEST_ONITEMSTATEICON)\n\t\treturn;\n\n\twxCommandEvent evt;\n\tOnShapeProperties(evt);\n}\n\nvoid OutfitStudioFrame::ToggleBoneState(wxTreeItemId item) {\n\tif (!item.IsOk())\n\t\treturn;\n\n\tstd::string boneName = outfitBones->GetItemText(item).ToStdString();\n\tif ((outfitBones->GetItemState(item) & 1) != 0)\n\t\tlastNormalizeBones.erase(boneName);\n\telse\n\t\tlastNormalizeBones.insert(boneName);\n\tUpdateBoneItemState(item, boneName);\n}\n\nvoid OutfitStudioFrame::OnBoneStateToggle(wxTreeEvent& event) {\n\tToggleBoneState(event.GetItem());\n\tevent.Skip();\n}\n\nvoid OutfitStudioFrame::RefreshGUIWeightColors() {\n\t// Clear weight color of all shapes\n\tfor (auto& s : project->GetWorkNif()->GetShapeNames()) {\n\t\tMesh* m = glView->GetMesh(s);\n\t\tif (m)\n\t\t\tm->WeightFill(0.0f);\n\t}\n\n\tif (!activeBone.empty()) {\n\t\t// Show weights of selected shapes without reference\n\t\tfor (auto& s : selectedItems) {\n\t\t\tif (!project->IsBaseShape(s->GetShape())) {\n\t\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(s->GetShape()->name.get(), activeBone);\n\n\t\t\t\tMesh* m = glView->GetMesh(s->GetShape()->name.get());\n\t\t\t\tif (m) {\n\t\t\t\t\tm->WeightFill(0.0f);\n\t\t\t\t\tif (weights) {\n\t\t\t\t\t\tfor (auto& bw : *weights)\n\t\t\t\t\t\t\tm->weight[bw.first] = bw.second;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Always show weights of reference shape\n\t\tNiShape* baseShape = project->GetBaseShape();\n\t\tif (baseShape) {\n\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(baseShape->name.get(), activeBone);\n\n\t\t\tMesh* m = glView->GetMesh(baseShape->name.get());\n\t\t\tif (m) {\n\t\t\t\tm->WeightFill(0.0f);\n\t\t\t\tif (weights) {\n\t\t\t\t\tfor (auto& bw : *weights)\n\t\t\t\t\t\tm->weight[bw.first] = bw.second;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->Refresh();\n}\n\nvoid OutfitStudioFrame::OnBoneSelect(wxTreeEvent& event) {\n\tif (recursingUI)\n\t\treturn;\n\n\twxTreeItemId item = event.GetItem();\n\tif (!activeItem || !item.IsOk())\n\t\treturn;\n\n\twxArrayTreeItemIds selected;\n\toutfitBones->GetSelections(selected);\n\n\tactiveBone.clear();\n\tstd::string selBone = outfitBones->GetItemText(item).ToStdString();\n\n\tif (!outfitBones->IsSelected(item)) {\n\t\tif (!selected.IsEmpty()) {\n\t\t\tstd::string frontBone = outfitBones->GetItemText(selected.front()).ToStdString();\n\t\t\tactiveBone = frontBone;\n\t\t}\n\t}\n\telse {\n\t\tactiveBone = selBone;\n\t\tif (selected.GetCount() == 1)\n\t\t\tlastSelectedBones.clear();\n\t}\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId itemTree = outfitBones->GetFirstChild(bonesRoot, cookie);\n\twhile (itemTree.IsOk()) {\n\t\tstd::string boneName = outfitBones->GetItemText(itemTree).ToStdString();\n\t\tif (outfitBones->IsSelected(itemTree))\n\t\t\tlastSelectedBones.insert(boneName);\n\t\telse\n\t\t\tlastSelectedBones.erase(boneName);\n\n\t\titemTree = outfitBones->GetNextChild(bonesRoot, cookie);\n\t}\n\n\t// Sync with pose panel choice if the active bone exists there\n\tif (!activeBone.empty() && cPoseBone) {\n\t\twxString activeBoneStr = wxString::FromUTF8(activeBone);\n\t\tfor (unsigned int i = 0; i < cPoseBone->GetCount(); ++i) {\n\t\t\tif (cPoseBone->GetString(i) == activeBoneStr) {\n\t\t\t\tcPoseBone->SetSelection(i);\n\t\t\t\tPoseToGUI();  // Update sliders and text values for the selected bone\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->UpdateNodeColors();\n\tRefreshGUIWeightColors();\n\tCalcAutoXMirrorBone();\n\n\tif (glView->GetTransformMode())\n\t\tglView->ShowTransformTool();\n}\n\nvoid OutfitStudioFrame::OnBoneActivated(wxTreeEvent& event) {\n\tint hitFlags;\n\toutfitBones->HitTest(event.GetPoint(), hitFlags);\n\n\tif (hitFlags & wxTREE_HITTEST_ONITEMSTATEICON)\n\t\treturn;\n\n\twxCommandEvent evt;\n\tOnEditBone(evt);\n}\n\nvoid OutfitStudioFrame::OnCheckTreeSel(wxTreeEvent& event) {\n\tint outflags;\n\twxPoint p;\n\twxGetMousePosition(&p.x, &p.y);\n\tp = outfitShapes->ScreenToClient(p);\n\n\tint mask = wxTREE_HITTEST_ONITEMINDENT | wxTREE_HITTEST_ONITEMSTATEICON;\n\toutfitShapes->HitTest(p, outflags);\n\tif ((outflags & mask) != 0)\n\t\tevent.Veto();\n}\n\nvoid OutfitStudioFrame::OnShapeContext(wxTreeEvent& event) {\n\twxTreeItemId item = event.GetItem();\n\tif (outfitShapes->GetItemParent(item).IsOk()) {\n\t\toutfitShapes->SelectItem(item);\n\n\t\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"menuMeshContext\");\n\t\tif (menu) {\n\t\t\tPopupMenu(menu);\n\t\t\tdelete menu;\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnShapeDrag(wxTreeEvent& event) {\n\tif (activeItem) {\n\t\twxPoint p;\n\t\twxGetMousePosition(&p.x, &p.y);\n\t\tp = outfitShapes->ScreenToClient(p);\n\n\t\tint outflags;\n\t\toutfitShapes->HitTest(p, outflags);\n\n\t\tint mask = wxTREE_HITTEST_ONITEMINDENT | wxTREE_HITTEST_ONITEMSTATEICON;\n\t\tif ((outflags & mask) == 0) {\n\t\t\toutfitShapes->SetCursor(wxCURSOR_HAND);\n\t\t\tevent.Allow();\n\t\t}\n\t\telse\n\t\t\tevent.Veto();\n\t}\n}\n\nvoid OutfitStudioFrame::OnShapeDrop(wxTreeEvent& event) {\n\toutfitShapes->SetCursor(wxNullCursor);\n\twxTreeItemId dropItem = event.GetItem();\n\n\tif (!dropItem.IsOk() || !activeItem)\n\t\treturn;\n\n\t// Make first child\n\tif (dropItem == outfitRoot)\n\t\tdropItem = 0;\n\n\t// Duplicate item\n\twxTreeItemId movedItem = outfitShapes->InsertItem(outfitRoot, dropItem, activeItem->GetShape()->name.get());\n\tif (!movedItem.IsOk())\n\t\treturn;\n\n\t// Set data\n\tauto dropData = new ShapeItemData(activeItem->GetShape());\n\toutfitShapes->SetItemState(movedItem, 0);\n\toutfitShapes->SetItemData(movedItem, dropData);\n\tif (project->IsBaseShape(dropData->GetShape())) {\n\t\toutfitShapes->SetItemBold(movedItem);\n\t\toutfitShapes->SetItemTextColour(movedItem, wxColour(0, 255, 0));\n\t}\n\n\t// Delete old item\n\toutfitShapes->Delete(activeItem->GetId());\n\n\t// Select new item\n\toutfitShapes->UnselectAll();\n\toutfitShapes->SelectItem(movedItem);\n\n\t// Keep NIF shape order in sync with the tree order so future GUI refreshes preserve user reordering.\n\tproject->GetWorkNif()->SetShapeOrder(GetShapeList());\n}\n\nvoid OutfitStudioFrame::OnBoneContext(wxTreeEvent& WXUNUSED(event)) {\n\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"menuBoneContext\");\n\tif (menu) {\n\t\tif (!activeBone.empty() && activeItem && project->GetWorkAnim()->BoneHasInconsistentTransforms(activeItem->GetShape()->name.get(), activeBone)) {\n\t\t\tif (AnimSkeleton::getInstance().GetBonePtr(activeBone)->isStandardBone)\n\t\t\t\tmenu->Enable(XRCID(\"setBoneNode\"), false);\n\t\t}\n\t\telse\n\t\t\tmenu->Destroy(XRCID(\"menuBadBone\"));\n\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid OutfitStudioFrame::OnBoneTreeContext(wxCommandEvent& WXUNUSED(event)) {\n\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"menuBoneTreeContext\");\n\tif (menu) {\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid OutfitStudioFrame::OnSegmentSelect(wxTreeEvent& event) {\n\tShowSegment(event.GetItem());\n}\n\nvoid OutfitStudioFrame::OnSegmentContext(wxTreeEvent& event) {\n\tif (!event.GetItem().IsOk())\n\t\treturn;\n\n\tsegmentTree->SelectItem(event.GetItem());\n\n\twxMenu* menu = nullptr;\n\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(event.GetItem()));\n\tif (subSegmentData)\n\t\tmenu = wxXmlResource::Get()->LoadMenu(\"menuSubSegmentContext\");\n\telse\n\t\tmenu = wxXmlResource::Get()->LoadMenu(\"menuSegmentContext\");\n\n\tif (menu) {\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid OutfitStudioFrame::OnSegmentTreeContext(wxCommandEvent& WXUNUSED(event)) {\n\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"menuSegmentTreeContext\");\n\tif (menu) {\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nint OutfitStudioFrame::CalcMaxSegPartID() {\n\tint maxid = -1;\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = segmentTree->GetFirstChild(segmentRoot, cookie);\n\twhile (child.IsOk()) {\n\t\tSegmentItemData* segmentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(child));\n\t\tif (segmentData)\n\t\t\tmaxid = std::max(maxid, segmentData->partID);\n\t\twxTreeItemIdValue subCookie;\n\t\twxTreeItemId subChild = segmentTree->GetFirstChild(child, subCookie);\n\t\twhile (subChild.IsOk()) {\n\t\t\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(subChild));\n\t\t\tif (subSegmentData)\n\t\t\t\tmaxid = std::max(maxid, subSegmentData->partID);\n\t\t\tsubChild = segmentTree->GetNextChild(child, subCookie);\n\t\t}\n\t\tchild = segmentTree->GetNextChild(segmentRoot, cookie);\n\t}\n\treturn maxid;\n}\n\nvoid OutfitStudioFrame::OnAddSegment(wxCommandEvent& WXUNUSED(event)) {\n\tint newPartID = CalcMaxSegPartID() + 1;\n\twxTreeItemId newItem;\n\tif (!activeSegment.IsOk() || segmentTree->GetChildrenCount(segmentRoot) <= 0) {\n\t\t// The new segment is the only partition: assign all triangles.\n\t\tfor (size_t i = 0; i < triSParts.size(); ++i)\n\t\t\ttriSParts[i] = newPartID;\n\n\t\tnewItem = segmentTree->AppendItem(segmentRoot, \"Segment\", -1, -1, new SegmentItemData(newPartID));\n\t}\n\telse\n\t\tnewItem = segmentTree->InsertItem(segmentRoot, activeSegment, \"Segment\", -1, -1, new SegmentItemData(newPartID));\n\n\tif (newItem.IsOk()) {\n\t\tsegmentTree->UnselectAll();\n\t\tsegmentTree->SelectItem(newItem);\n\t}\n\n\tUpdateSegmentNames();\n\tsegmentTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnAddSubSegment(wxCommandEvent& WXUNUSED(event)) {\n\tint newPartID = CalcMaxSegPartID() + 1;\n\twxTreeItemId newItem;\n\twxTreeItemId parent = segmentTree->GetItemParent(activeSegment);\n\tif (parent == segmentRoot) {\n\t\tif (segmentTree->GetChildrenCount(activeSegment) <= 0) {\n\t\t\t// The new subsegment will be the only child: assign all of\n\t\t\t// the segment's triangles to it.\n\t\t\tSegmentItemData* segmentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\t\t\tif (segmentData)\n\t\t\t\tfor (size_t i = 0; i < triSParts.size(); ++i)\n\t\t\t\t\tif (triSParts[i] == segmentData->partID)\n\t\t\t\t\t\ttriSParts[i] = newPartID;\n\t\t}\n\n\t\tnewItem = segmentTree->PrependItem(activeSegment, \"Sub Segment\", -1, -1, new SubSegmentItemData(newPartID, 0, 0xFFFFFFFF));\n\t}\n\telse\n\t\tnewItem = segmentTree->InsertItem(parent, activeSegment, \"Sub Segment\", -1, -1, new SubSegmentItemData(newPartID, 0, 0xFFFFFFFF));\n\n\tif (newItem.IsOk()) {\n\t\tsegmentTree->UnselectAll();\n\t\tsegmentTree->SelectItem(newItem);\n\t}\n\n\tUpdateSegmentNames();\n\tsegmentTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeleteSegment(wxCommandEvent& WXUNUSED(event)) {\n\tSegmentItemData* segmentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\tif (segmentData) {\n\t\t// Collect list of partition IDs that will be disappearing.\n\t\tstd::vector<bool> oldPartIDs(CalcMaxSegPartID() + 1, false);\n\t\toldPartIDs[segmentData->partID] = true;\n\t\twxTreeItemIdValue cookie;\n\t\twxTreeItemId child = segmentTree->GetFirstChild(activeSegment, cookie);\n\t\twhile (child.IsOk()) {\n\t\t\tSubSegmentItemData* childData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(child));\n\t\t\tif (childData)\n\t\t\t\toldPartIDs[childData->partID] = true;\n\t\t\tchild = segmentTree->GetNextChild(activeSegment, cookie);\n\t\t}\n\n\t\t// Find a new partition to put triangles into.\n\t\tint newPartID = -1;\n\t\twxTreeItemId sibling = segmentTree->GetPrevSibling(activeSegment);\n\t\tif (!sibling.IsOk())\n\t\t\tsibling = segmentTree->GetNextSibling(activeSegment);\n\t\tif (sibling.IsOk()) {\n\t\t\tSegmentItemData* siblingData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(sibling));\n\t\t\tif (siblingData)\n\t\t\t\tnewPartID = siblingData->partID;\n\n\t\t\tchild = segmentTree->GetFirstChild(sibling, cookie);\n\t\t\tif (child.IsOk()) {\n\t\t\t\tSubSegmentItemData* childData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(child));\n\t\t\t\tif (childData)\n\t\t\t\t\tnewPartID = childData->partID;\n\t\t\t}\n\t\t}\n\n\t\t// Assign triangles from old partitions to new partition.\n\t\tfor (size_t i = 0; i < triSParts.size(); ++i)\n\t\t\tif (triSParts[i] >= 0 && triSParts[i] < static_cast<int>(oldPartIDs.size()) && oldPartIDs[triSParts[i]])\n\t\t\t\ttriSParts[i] = newPartID;\n\n\t\tsegmentTree->UnselectAll();\n\t\tsegmentTree->Delete(activeSegment);\n\t\tif (sibling.IsOk())\n\t\t\tsegmentTree->SelectItem(sibling);\n\t\telse\n\t\t\tactiveSegment.Unset();\n\t}\n\n\tUpdateSegmentNames();\n\tsegmentTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeleteSubSegment(wxCommandEvent& WXUNUSED(event)) {\n\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\twxTreeItemId newSelItem;\n\tif (subSegmentData) {\n\t\tint oldPartID = subSegmentData->partID, newPartID = -1;\n\n\t\t// Find a partition to assign triangles to.\n\t\twxTreeItemId sibling = segmentTree->GetPrevSibling(activeSegment);\n\t\tif (!sibling.IsOk())\n\t\t\tsibling = segmentTree->GetNextSibling(activeSegment);\n\n\t\tif (sibling.IsOk()) {\n\t\t\tSubSegmentItemData* siblingData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(sibling));\n\t\t\tif (siblingData)\n\t\t\t\tnewPartID = siblingData->partID;\n\t\t\tnewSelItem = sibling;\n\t\t}\n\t\telse {\n\t\t\twxTreeItemId parent = segmentTree->GetItemParent(activeSegment);\n\t\t\tif (parent.IsOk()) {\n\t\t\t\tSegmentItemData* parentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(parent));\n\t\t\t\tif (parentData)\n\t\t\t\t\tnewPartID = parentData->partID;\n\t\t\t}\n\t\t\tnewSelItem = parent;\n\t\t}\n\n\t\t// Assign triangles to new partition.\n\t\tfor (size_t i = 0; i < triSParts.size(); ++i)\n\t\t\tif (triSParts[i] == oldPartID)\n\t\t\t\ttriSParts[i] = newPartID;\n\n\t\tsegmentTree->UnselectAll();\n\t\tsegmentTree->Delete(activeSegment);\n\t\tsegmentTree->SelectItem(newSelItem);\n\t}\n\n\tUpdateSegmentNames();\n\tsegmentTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::UpdateActiveSlotID() {\n\twxChoice* segmentSlot = (wxChoice*)FindWindowByName(\"segmentSlot\");\n\n\tif (activeSegment.IsOk() && segmentTree->GetItemParent(activeSegment).IsOk()) {\n\t\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\t\tif (subSegmentData) {\n\t\t\tsubSegmentData->userSlotID = 0;\n\n\t\t\tif (segmentSlot->GetSelection() > 0) {\n\t\t\t\twxString slotSel = segmentSlot->GetStringSelection().BeforeFirst(' ');\n\t\t\t\tif (slotSel.length() >= 1) {\n\t\t\t\t\tunsigned long slot = 0;\n\t\t\t\t\tslotSel.ToULong(&slot);\n\n\t\t\t\t\tif (slot > 0)\n\t\t\t\t\t\tsubSegmentData->userSlotID = slot;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tUpdateSegmentNames();\n\t\t\tsegmentTabButton->SetPendingChanges();\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnSegmentSlotChanged(wxCommandEvent& WXUNUSED(event)) {\n\tUpdateActiveSlotID();\n}\n\nvoid OutfitStudioFrame::OnSegmentTypeChanged(wxCommandEvent& event) {\n\twxChoice* segmentType = (wxChoice*)event.GetEventObject();\n\n\tif (activeSegment.IsOk() && segmentTree->GetItemParent(activeSegment).IsOk()) {\n\t\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\t\tif (subSegmentData) {\n\t\t\tunsigned long type = 0xFFFFFFFF;\n\n\t\t\twxString hashSel = segmentType->GetStringSelection();\n\t\t\tint hashPos = hashSel.First(\"0x\");\n\t\t\tif (hashPos != wxNOT_FOUND)\n\t\t\t\thashSel.Mid(hashPos).ToULong(&type, 16);\n\n\t\t\tsubSegmentData->material = type;\n\t\t\tUpdateSegmentNames();\n\t\t\tsegmentTabButton->SetPendingChanges();\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnSegmentApply(wxCommandEvent& WXUNUSED(event)) {\n\tApplySegments();\n}\n\nvoid OutfitStudioFrame::ApplySegments() {\n\tNifSegmentationInfo inf;\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = segmentTree->GetFirstChild(segmentRoot, cookie);\n\n\twhile (child.IsOk()) {\n\t\tSegmentItemData* segmentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(child));\n\t\tif (segmentData) {\n\t\t\tinf.segs.emplace_back();\n\t\t\tNifSegmentInfo& seg = inf.segs.back();\n\t\t\tseg.partID = segmentData->partID;\n\t\t\tsize_t childCount = segmentTree->GetChildrenCount(child);\n\n\t\t\tif (childCount > 0) {\n\t\t\t\tseg.subs.resize(childCount);\n\t\t\t\tint childInd = 0;\n\n\t\t\t\twxTreeItemIdValue subCookie;\n\t\t\t\twxTreeItemId subChild = segmentTree->GetFirstChild(child, subCookie);\n\t\t\t\twhile (subChild.IsOk()) {\n\t\t\t\t\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(subChild));\n\t\t\t\t\tif (subSegmentData) {\n\t\t\t\t\t\tNifSubSegmentInfo& sub = seg.subs[childInd++];\n\t\t\t\t\t\tsub.partID = subSegmentData->partID;\n\t\t\t\t\t\tsub.userSlotID = subSegmentData->userSlotID;\n\t\t\t\t\t\tsub.material = subSegmentData->material;\n\t\t\t\t\t\tsub.extraData = subSegmentData->extraData;\n\t\t\t\t\t}\n\n\t\t\t\t\tsubChild = segmentTree->GetNextChild(child, subCookie);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tchild = segmentTree->GetNextChild(segmentRoot, cookie);\n\t}\n\n\twxTextCtrl* segmentSSF = (wxTextCtrl*)FindWindowByName(\"segmentSSF\");\n\tinf.ssfFile = segmentSSF->GetValue().ToStdString();\n\n\tproject->GetWorkNif()->SetShapeSegments(activeItem->GetShape(), inf, triSParts);\n\tMeshFromProj(activeItem->GetShape());\n\n\tCreateSegmentTree(activeItem->GetShape());\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnSegmentReset(wxCommandEvent& WXUNUSED(event)) {\n\tResetSegments();\n}\n\nvoid OutfitStudioFrame::ResetSegments() {\n\tif (activeItem)\n\t\tCreateSegmentTree(activeItem->GetShape());\n\telse\n\t\tCreateSegmentTree(nullptr);\n}\n\nvoid OutfitStudioFrame::OnSegmentEditSSF(wxCommandEvent& WXUNUSED(event)) {\n\tauto segmentSSF = (wxTextCtrl*)FindWindowByName(\"segmentSSF\");\n\n\twxString result = wxGetTextFromUser(_(\"Please enter an SSF file path.\"), _(\"SSF File\"), segmentSSF->GetValue());\n\tif (result.empty())\n\t\treturn;\n\n\tsegmentSSF->ChangeValue(result);\n\tsegmentTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::CreateSegmentTree(NiShape* shape) {\n\tif (segmentTree->GetChildrenCount(segmentRoot) > 0) {\n\t\ttriSParts.clear(); // DeleteChildren calls OnSegmentSelect\n\t\tsegmentTree->DeleteChildren(segmentRoot);\n\t}\n\n\tsegmentTabButton->SetPendingChanges(false);\n\n\tNifSegmentationInfo inf;\n\tif (project->GetWorkNif()->GetShapeSegments(shape, inf, triSParts)) {\n\t\tfor (size_t i = 0; i < inf.segs.size(); i++) {\n\t\t\twxTreeItemId segID = segmentTree->AppendItem(segmentRoot, \"Segment\", -1, -1, new SegmentItemData(inf.segs[i].partID));\n\t\t\tif (segID.IsOk()) {\n\t\t\t\tfor (size_t j = 0; j < inf.segs[i].subs.size(); j++) {\n\t\t\t\t\tNifSubSegmentInfo& sub = inf.segs[i].subs[j];\n\t\t\t\t\tsegmentTree->AppendItem(segID, \"Sub Segment\", -1, -1, new SubSegmentItemData(sub.partID, sub.userSlotID, sub.material, sub.extraData));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\twxTextCtrl* segmentSSF = (wxTextCtrl*)FindWindowByName(\"segmentSSF\");\n\tsegmentSSF->ChangeValue(inf.ssfFile);\n\n\tUpdateSegmentNames();\n\tsegmentTree->ExpandAll();\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = segmentTree->GetFirstChild(segmentRoot, cookie);\n\tif (child.IsOk())\n\t\tsegmentTree->SelectItem(child);\n}\n\nbool OutfitStudioFrame::PaintSegmentPartitionTriangles(Mesh* hitMesh, int hitTri, const Vector3& hitPointModel, float radiusModel) {\n\tif (!hitMesh || !activeItem || !glView->GetSegmentMode())\n\t\treturn false;\n\n\tauto shape = activeItem->GetShape();\n\tif (!shape || shape->name.get() != hitMesh->shapeName)\n\t\treturn false;\n\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\tif (tris.empty() || hitTri < 0 || static_cast<size_t>(hitTri) >= tris.size())\n\t\treturn false;\n\n\tstd::vector<bool> paintTris(tris.size(), false);\n\tpaintTris[hitTri] = true;\n\n\tfloat radiusMesh = hitMesh->TransformDistModelToMesh(radiusModel);\n\tif (radiusMesh > 0.0f) {\n\t\tVector3 hitPointMesh = hitMesh->TransformPosModelToMesh(hitPointModel);\n\t\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\t\tconst Triangle& t = tris[ti];\n\t\t\tVector3 centroid = (hitMesh->verts[t.p1] + hitMesh->verts[t.p2] + hitMesh->verts[t.p3]) / 3.0f;\n\t\t\tif (centroid.DistanceTo(hitPointMesh) <= radiusMesh)\n\t\t\t\tpaintTris[ti] = true;\n\t\t}\n\t}\n\n\tbool changed = false;\n\n\tif (triSParts.size() == tris.size() && activeSegment.IsOk() && segmentTree->GetItemParent(activeSegment).IsOk()) {\n\t\tstd::vector<bool> selPartIDs(CalcMaxSegPartID() + 1, false);\n\t\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\t\tif (subSegmentData) {\n\t\t\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\t\t\tif (paintTris[ti] && triSParts[ti] != subSegmentData->partID) {\n\t\t\t\t\ttriSParts[ti] = subSegmentData->partID;\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tSegmentItemData* segmentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\t\t\tif (segmentData) {\n\t\t\t\tselPartIDs[segmentData->partID] = true;\n\t\t\t\tint destPartID = segmentData->partID;\n\t\t\t\twxTreeItemIdValue subCookie;\n\t\t\t\twxTreeItemId child = segmentTree->GetFirstChild(activeSegment, subCookie);\n\t\t\t\twhile (child.IsOk()) {\n\t\t\t\t\tSubSegmentItemData* childData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(child));\n\t\t\t\t\tif (childData) {\n\t\t\t\t\t\tselPartIDs[childData->partID] = true;\n\t\t\t\t\t\tdestPartID = childData->partID;\n\t\t\t\t\t}\n\t\t\t\t\tchild = segmentTree->GetNextChild(activeSegment, subCookie);\n\t\t\t\t}\n\n\t\t\t\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\t\t\t\tif (!paintTris[ti])\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (triSParts[ti] >= 0 && triSParts[ti] < static_cast<int>(selPartIDs.size()) && selPartIDs[triSParts[ti]])\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\tif (triSParts[ti] != destPartID) {\n\t\t\t\t\t\ttriSParts[ti] = destPartID;\n\t\t\t\t\t\tchanged = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (triParts.size() == tris.size() && activePartition.IsOk() && partitionTree->GetItemParent(activePartition).IsOk()) {\n\t\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(activePartition));\n\t\tif (partitionData) {\n\t\t\tfor (size_t ti = 0; ti < tris.size(); ++ti) {\n\t\t\t\tif (paintTris[ti] && triParts[ti] != partitionData->index) {\n\t\t\t\t\ttriParts[ti] = partitionData->index;\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn changed;\n}\n\nvoid OutfitStudioFrame::ShowSegment(const wxTreeItemId& item) {\n\tif (!activeItem || !glView->GetSegmentMode())\n\t\treturn;\n\n\twxChoice* segmentType = (wxChoice*)FindWindowByName(\"segmentType\");\n\tsegmentType->Disable();\n\tsegmentType->SetSelection(0);\n\n\twxChoice* segmentSlot = (wxChoice*)FindWindowByName(\"segmentSlot\");\n\tsegmentSlot->Disable();\n\tsegmentSlot->SetSelection(0);\n\n\tif (item.IsOk())\n\t\tactiveSegment = item;\n\n\tif (!activeSegment.IsOk() || !segmentTree->GetItemParent(activeSegment).IsOk())\n\t\treturn;\n\n\t// Get all triangles of the active shape\n\tstd::vector<Triangle> tris;\n\tif (activeItem->GetShape())\n\t\tactiveItem->GetShape()->GetTriangles(tris);\n\tif (triSParts.size() != tris.size())\n\t\treturn;\n\n\t// selPartIDs will be true for selected item and its children.\n\tstd::vector<bool> selPartIDs(CalcMaxSegPartID() + 1, false);\n\n\tSubSegmentItemData* subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\tif (subSegmentData) {\n\t\t// Active segment is a subsegment\n\t\tselPartIDs[subSegmentData->partID] = true;\n\n\t\tif (subSegmentData->material != 0xFFFFFFFF) {\n\t\t\tbool typeFound = false;\n\t\t\tauto typeHash = wxString::Format(\"0x%08x\", subSegmentData->material);\n\t\t\tfor (uint32_t i = 0; i < segmentType->GetCount(); i++) {\n\t\t\t\tauto typeString = segmentType->GetString(i);\n\t\t\t\tif (typeString.Contains(typeHash)) {\n\t\t\t\t\tsegmentType->SetSelection((int)i);\n\t\t\t\t\ttypeFound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!typeFound)\n\t\t\t\tsegmentType->SetSelection(segmentType->Append(typeHash));\n\t\t}\n\n\t\tsegmentType->Enable();\n\n\t\tfor (uint32_t i = 0; i < segmentSlot->GetCount(); i++) {\n\t\t\tuint32_t userSlotID = subSegmentData->userSlotID;\n\n\t\t\t// Find matching slot in choice\n\t\t\twxString slotPrefix = wxString::Format(\"%d - \", userSlotID);\n\t\t\tauto slotString = segmentSlot->GetString(i);\n\t\t\tif (slotString.StartsWith(slotPrefix)) {\n\t\t\t\tsegmentSlot->SetSelection((int)i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tsegmentSlot->Enable();\n\t}\n\telse {\n\t\tSegmentItemData* segmentData = dynamic_cast<SegmentItemData*>(segmentTree->GetItemData(activeSegment));\n\t\tif (segmentData) {\n\t\t\t// Active segment is a normal segment\n\t\t\t// Collect list of partition IDs for segment and children.\n\t\t\t// Also find partition ID of last child, or segment if none.\n\t\t\tselPartIDs[segmentData->partID] = true;\n\t\t\tint destPartID = segmentData->partID;\n\t\t\twxTreeItemIdValue subCookie;\n\t\t\twxTreeItemId child = segmentTree->GetFirstChild(activeSegment, subCookie);\n\t\t\twhile (child.IsOk()) {\n\t\t\t\tSubSegmentItemData* childData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(child));\n\t\t\t\tif (childData) {\n\t\t\t\t\tselPartIDs[childData->partID] = true;\n\t\t\t\t\tdestPartID = childData->partID;\n\t\t\t\t}\n\t\t\t\tchild = segmentTree->GetNextChild(activeSegment, subCookie);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Display segmentation colors depending on what is selected\n\tMesh* m = glView->GetMesh(activeItem->GetShape()->name.get());\n\tif (m) {\n\t\tSetSubMeshesForPartitions(m, triSParts);\n\n\t\t// Set colors for segments\n\t\tint nsm = m->subMeshes.size();\n\t\tm->subMeshesColor.resize(nsm);\n\t\tfor (int pi = 0; pi < nsm; ++pi) {\n\t\t\tif (selPartIDs[pi]) {\n\t\t\t\tm->subMeshesColor[pi].x = 1.0f;\n\t\t\t\tm->subMeshesColor[pi].y = 0.0f;\n\t\t\t\tm->subMeshesColor[pi].z = 0.0f;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfloat colorValue = (pi + 1.0f) / (nsm + 1);\n\t\t\t\tm->subMeshesColor[pi] = glView->CreateColorRamp(colorValue);\n\t\t\t}\n\t\t}\n\n\t\t// Set mask\n\t\tm->MaskFill(0.0f);\n\n\t\tfor (size_t i = 0; i < triSParts.size(); ++i) {\n\t\t\tif (triSParts[i] < 0 || !selPartIDs[triSParts[i]])\n\t\t\t\tcontinue;\n\n\t\t\tm->mask[tris[i].p1] = 1.0f;\n\t\t\tm->mask[tris[i].p2] = 1.0f;\n\t\t\tm->mask[tris[i].p3] = 1.0f;\n\t\t}\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::UpdateSegmentNames() {\n\tauto segmentType = (wxChoice*)FindWindowByName(\"segmentType\");\n\tauto segmentSlot = (wxChoice*)FindWindowByName(\"segmentSlot\");\n\n\tint segmentIndex = 0;\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = segmentTree->GetFirstChild(segmentRoot, cookie);\n\n\twhile (child.IsOk()) {\n\t\tsegmentTree->SetItemText(child, wxString::Format(\"Segment #%d\", segmentIndex));\n\n\t\tint subSegmentIndex = 0;\n\t\twxTreeItemIdValue subCookie;\n\t\twxTreeItemId subChild = segmentTree->GetFirstChild(child, subCookie);\n\n\t\twhile (subChild.IsOk()) {\n\t\t\tstd::string subSegmentName = \"Default\";\n\t\t\tstd::string subSegmentSlot = \"\";\n\n\t\t\tauto subSegmentData = dynamic_cast<SubSegmentItemData*>(segmentTree->GetItemData(subChild));\n\t\t\tif (subSegmentData) {\n\t\t\t\tif (subSegmentData->material != 0xFFFFFFFF) {\n\t\t\t\t\tbool typeFound = false;\n\t\t\t\t\tauto typeHash = wxString::Format(\"0x%08x\", subSegmentData->material);\n\t\t\t\t\tfor (uint32_t i = 0; i < segmentType->GetCount(); i++) {\n\t\t\t\t\t\tauto typeString = segmentType->GetString(i);\n\t\t\t\t\t\tif (typeString.Contains(typeHash)) {\n\t\t\t\t\t\t\tsubSegmentName = typeString.BeforeLast('|');\n\t\t\t\t\t\t\ttypeFound = true;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (!typeFound)\n\t\t\t\t\t\tsubSegmentName = typeHash;\n\t\t\t\t}\n\n\t\t\t\tuint32_t userSlotID = subSegmentData->userSlotID;\n\t\t\t\tif (userSlotID >= 30) {\n\t\t\t\t\twxString slotPrefix = wxString::Format(\"%d - \", userSlotID);\n\n\t\t\t\t\t// Find matching slot in choice\n\t\t\t\t\tfor (uint32_t i = 0; i < segmentSlot->GetCount(); i++) {\n\t\t\t\t\t\tauto slotString = segmentSlot->GetString(i);\n\t\t\t\t\t\tif (slotString.StartsWith(slotPrefix)) {\n\t\t\t\t\t\t\tsubSegmentSlot = wxString::Format(\"(Slot %s)\", slotString);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsegmentTree->SetItemText(subChild, wxString::Format(\"#%d: %s%s\", subSegmentIndex, subSegmentName, subSegmentSlot));\n\n\t\t\tsubChild = segmentTree->GetNextChild(child, subCookie);\n\t\t\tsubSegmentIndex++;\n\t\t}\n\n\t\tchild = segmentTree->GetNextChild(segmentRoot, cookie);\n\t\tsegmentIndex++;\n\t}\n}\n\nvoid OutfitStudioFrame::OnPartitionSelect(wxTreeEvent& event) {\n\tShowPartition(event.GetItem());\n}\n\nvoid OutfitStudioFrame::OnPartitionContext(wxTreeEvent& event) {\n\tif (!event.GetItem().IsOk())\n\t\treturn;\n\n\tpartitionTree->SelectItem(event.GetItem());\n\n\twxMenu* menu = nullptr;\n\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(event.GetItem()));\n\tif (partitionData)\n\t\tmenu = wxXmlResource::Get()->LoadMenu(\"menuPartitionContext\");\n\n\tif (menu) {\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid OutfitStudioFrame::OnPartitionTreeContext(wxCommandEvent& WXUNUSED(event)) {\n\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"menuPartitionTreeContext\");\n\tif (menu) {\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid OutfitStudioFrame::OnAddPartition(wxCommandEvent& WXUNUSED(event)) {\n\tbool isSkyrim = wxGetApp().targetGame == SKYRIM || wxGetApp().targetGame == SKYRIMSE || wxGetApp().targetGame == SKYRIMVR;\n\n\t// Find an unused partition index\n\tstd::set<int> partInds;\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = partitionTree->GetFirstChild(partitionRoot, cookie);\n\twhile (child.IsOk()) {\n\t\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(child));\n\t\tif (partitionData)\n\t\t\tpartInds.insert(partitionData->index);\n\t\tchild = partitionTree->GetNextChild(partitionRoot, cookie);\n\t}\n\n\tint partInd = 0;\n\twhile (partInds.count(partInd) != 0)\n\t\t++partInd;\n\n\t// Create partition item\n\twxTreeItemId newItem;\n\tif (!activePartition.IsOk() || partitionTree->GetChildrenCount(partitionRoot) <= 0) {\n\t\tauto shape = activeItem->GetShape();\n\t\tif (shape && shape->GetNumVertices() > 0) {\n\t\t\tnewItem = partitionTree->AppendItem(partitionRoot, \"Partition\", -1, -1, new PartitionItemData(partInd, isSkyrim ? 32 : 0));\n\t\t}\n\n\t\tfor (int& pi : triParts)\n\t\t\tpi = partInd;\n\t}\n\telse\n\t\tnewItem = partitionTree->InsertItem(partitionRoot, activePartition, \"Partition\", -1, -1, new PartitionItemData(partInd, isSkyrim ? 32 : 0));\n\n\tif (newItem.IsOk()) {\n\t\tpartitionTree->UnselectAll();\n\t\tpartitionTree->SelectItem(newItem);\n\t}\n\n\tUpdatePartitionNames();\n\tpartitionTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeletePartition(wxCommandEvent& WXUNUSED(event)) {\n\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(activePartition));\n\tif (partitionData) {\n\t\twxTreeItemId sibling = partitionTree->GetPrevSibling(activePartition);\n\t\tif (!sibling.IsOk())\n\t\t\tsibling = partitionTree->GetNextSibling(activePartition);\n\n\t\tint newIndex = -1;\n\t\tif (sibling.IsOk()) {\n\t\t\tPartitionItemData* siblingData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(sibling));\n\t\t\tif (siblingData)\n\t\t\t\tnewIndex = siblingData->index;\n\t\t}\n\t\tfor (size_t i = 0; i < triParts.size(); ++i)\n\t\t\tif (triParts[i] == partitionData->index)\n\t\t\t\ttriParts[i] = newIndex;\n\n\t\tif (sibling.IsOk()) {\n\t\t\tpartitionTree->UnselectAll();\n\t\t\tpartitionTree->Delete(activePartition);\n\t\t\tpartitionTree->SelectItem(sibling);\n\n\t\t\tShowPartition(sibling);\n\t\t}\n\t\telse {\n\t\t\tpartitionTree->Delete(activePartition);\n\t\t\tactivePartition.Unset();\n\t\t}\n\t}\n\n\tUpdatePartitionNames();\n\tpartitionTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnPartitionTypeChanged(wxCommandEvent& event) {\n\twxChoice* partitionType = (wxChoice*)event.GetEventObject();\n\n\tif (activePartition.IsOk() && partitionTree->GetItemParent(activePartition).IsOk()) {\n\t\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(activePartition));\n\t\tif (partitionData) {\n\t\t\tunsigned long type = 0;\n\t\t\tpartitionType->GetStringSelection().ToULong(&type);\n\t\t\tpartitionData->type = type;\n\t\t}\n\t}\n\n\tUpdatePartitionNames();\n\tpartitionTabButton->SetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnPartitionApply(wxCommandEvent& WXUNUSED(event)) {\n\tApplyPartitions();\n}\n\nvoid OutfitStudioFrame::ApplyPartitions() {\n\tauto shape = activeItem->GetShape();\n\tif (!shape)\n\t\treturn;\n\n\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\tstd::vector<bool> delPartFlags;\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = partitionTree->GetFirstChild(partitionRoot, cookie);\n\n\twhile (child.IsOk()) {\n\t\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(child));\n\t\tif (partitionData) {\n\t\t\tconst int index = partitionData->index;\n\t\t\tif (index >= static_cast<int64_t>(partitionInfo.size())) {\n\t\t\t\tpartitionInfo.resize(index + 1);\n\t\t\t\tdelPartFlags.resize(index + 1, true);\n\t\t\t}\n\t\t\tpartitionInfo[index].flags = PF_EDITOR_VISIBLE;\n\t\t\tpartitionInfo[index].partID = partitionData->type;\n\t\t\tdelPartFlags[index] = false;\n\t\t}\n\n\t\tchild = partitionTree->GetNextChild(partitionRoot, cookie);\n\t}\n\n\tstd::vector<uint32_t> delPartInds;\n\tfor (uint32_t pi = 0; pi < delPartFlags.size(); ++pi)\n\t\tif (delPartFlags[pi])\n\t\t\tdelPartInds.push_back(pi);\n\n\tproject->GetWorkNif()->SetShapePartitions(shape, partitionInfo, triParts);\n\tif (!delPartInds.empty())\n\t\tproject->GetWorkNif()->DeletePartitions(shape, delPartInds);\n\n\tCreatePartitionTree(shape);\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnPartitionReset(wxCommandEvent& WXUNUSED(event)) {\n\tResetPartitions();\n}\n\nvoid OutfitStudioFrame::ResetPartitions() {\n\tif (activeItem)\n\t\tCreatePartitionTree(activeItem->GetShape());\n\telse\n\t\tCreatePartitionTree(nullptr);\n}\n\nvoid OutfitStudioFrame::CreatePartitionTree(NiShape* shape) {\n\tif (partitionTree->GetChildrenCount(partitionRoot) > 0) {\n\t\ttriParts.clear(); // DeleteChildren calls OnPartitionSelect\n\t\tpartitionTree->DeleteChildren(partitionRoot);\n\t}\n\n\tpartitionTabButton->SetPendingChanges(false);\n\n\tNiVector<BSDismemberSkinInstance::PartitionInfo> partitionInfo;\n\tif (project->GetWorkNif()->GetShapePartitions(shape, partitionInfo, triParts)) {\n\t\tfor (uint32_t i = 0; i < partitionInfo.size(); i++) {\n\t\t\tpartitionTree->AppendItem(partitionRoot, \"Partition\", -1, -1, new PartitionItemData(static_cast<int>(i), partitionInfo[i].partID));\n\t\t}\n\t}\n\n\tUpdatePartitionNames();\n\tpartitionTree->ExpandAll();\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = partitionTree->GetFirstChild(partitionRoot, cookie);\n\tif (child.IsOk())\n\t\tpartitionTree->SelectItem(child);\n}\n\nvoid OutfitStudioFrame::ShowPartition(const wxTreeItemId& item) {\n\tif (!activeItem || !glView->GetSegmentMode())\n\t\treturn;\n\n\tauto shape = activeItem->GetShape();\n\tif (!shape)\n\t\treturn;\n\n\twxChoice* partitionType = (wxChoice*)FindWindowByName(\"partitionType\");\n\tpartitionType->Disable();\n\tpartitionType->SetSelection(0);\n\twxArrayString partitionStrings = partitionType->GetStrings();\n\n\tif (item.IsOk())\n\t\tactivePartition = item;\n\n\tif (!activePartition.IsOk() || !partitionTree->GetItemParent(activePartition).IsOk())\n\t\treturn;\n\n\t// Get all triangles of the active shape\n\tstd::vector<Triangle> allTris;\n\tshape->GetTriangles(allTris);\n\tif (allTris.size() != triParts.size())\n\t\treturn;\n\n\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(activePartition));\n\tif (partitionData) {\n\t\tfor (auto& s : partitionStrings) {\n\t\t\tif (s.StartsWith(wxString::Format(\"%d\", partitionData->type))) {\n\t\t\t\t// Show correct data in UI\n\t\t\t\tpartitionType->Enable();\n\t\t\t\tpartitionType->SetStringSelection(s);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Display partition colors depending on what is selected\n\tMesh* m = glView->GetMesh(activeItem->GetShape()->name.get());\n\tif (m) {\n\t\tSetSubMeshesForPartitions(m, triParts);\n\n\t\t// Set colors for non-selected partitions\n\t\tint nsm = m->subMeshes.size();\n\t\tm->subMeshesColor.resize(nsm);\n\n\t\tfor (int pi = 0; pi < nsm; ++pi) {\n\t\t\tfloat colorValue = (pi + 1.0f) / (nsm + 1);\n\t\t\tm->subMeshesColor[pi] = glView->CreateColorRamp(colorValue);\n\t\t}\n\n\t\t// Set color for selected partition\n\t\tif (partitionData) {\n\t\t\tif (nsm > partitionData->index) {\n\t\t\t\tm->subMeshesColor[partitionData->index].x = 1.0f;\n\t\t\t\tm->subMeshesColor[partitionData->index].y = 0.0f;\n\t\t\t\tm->subMeshesColor[partitionData->index].z = 0.0f;\n\t\t\t}\n\t\t}\n\n\t\t// Set mask\n\t\tm->MaskFill(0.0f);\n\n\t\tif (partitionData) {\n\t\t\tfor (size_t i = 0; i < allTris.size(); ++i) {\n\t\t\t\tif (triParts[i] != partitionData->index)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tconst Triangle& t = allTris[i];\n\t\t\t\tm->mask[t.p1] = 1.0f;\n\t\t\t\tm->mask[t.p2] = 1.0f;\n\t\t\t\tm->mask[t.p3] = 1.0f;\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::UpdatePartitionNames() {\n\twxChoice* partitionType = (wxChoice*)FindWindowByName(\"partitionType\");\n\twxArrayString partitionStrings = partitionType->GetStrings();\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId child = partitionTree->GetFirstChild(partitionRoot, cookie);\n\n\twhile (child.IsOk()) {\n\t\tPartitionItemData* partitionData = dynamic_cast<PartitionItemData*>(partitionTree->GetItemData(child));\n\t\tif (partitionData) {\n\t\t\tbool found = false;\n\t\t\tfor (auto& s : partitionStrings) {\n\t\t\t\tif (s.StartsWith(wxString::Format(\"%d\", partitionData->type))) {\n\t\t\t\t\tpartitionTree->SetItemText(child, s);\n\t\t\t\t\tfound = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!found)\n\t\t\t\tpartitionTree->SetItemText(child, wxString::Format(\"%d Unknown\", partitionData->type));\n\t\t}\n\n\t\tchild = partitionTree->GetNextChild(partitionRoot, cookie);\n\t}\n}\n\nvoid OutfitStudioFrame::SetSubMeshesForPartitions(Mesh* m, const std::vector<int>& tp) {\n\tuint32_t nTris = static_cast<uint32_t>(tp.size());\n\n\t// Sort triangles (via triInds) by partition number, negative partition\n\t// numbers at the end.\n\tstd::vector<uint32_t> triInds(nTris);\n\tfor (uint32_t ti = 0; ti < nTris; ++ti)\n\t\ttriInds[ti] = ti;\n\n\tstd::stable_sort(triInds.begin(), triInds.end(), [&tp](int i, int j) { return tp[j] < 0 || tp[i] < tp[j]; });\n\n\t// Re-order triangles\n\tfor (uint32_t ti = 0; ti < nTris; ++ti)\n\t\tm->renderTris[ti] = m->tris[triInds[ti]];\n\n\t// Find first triangle of each sub-mesh.\n\tm->subMeshes.clear();\n\tm->subMeshesColor.clear();\n\n\tfor (uint32_t ti = 0; ti < nTris; ++ti) {\n\t\twhile (tp[triInds[ti]] >= static_cast<int>(m->subMeshes.size()))\n\t\t\tm->subMeshes.emplace_back(ti, 0);\n\n\t\tif (tp[triInds[ti]] < 0) {\n\t\t\tm->subMeshes.emplace_back(ti, 0);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Calculate size of each sub-mesh.\n\tm->subMeshes.emplace_back(nTris, 0);\n\tfor (size_t si = 0; si + 1 < m->subMeshes.size(); ++si)\n\t\tm->subMeshes[si].second = m->subMeshes[si + 1].first - m->subMeshes[si].first;\n\n\tm->subMeshes.pop_back();\n\tm->QueueUpdate(Mesh::UpdateType::Indices);\n}\n\nvoid OutfitStudioFrame::SetNoSubMeshes(Mesh* m) {\n\tif (!m)\n\t\treturn;\n\n\tm->subMeshes.clear();\n\tm->subMeshesColor.clear();\n\n\tfor (int ti = 0; ti < m->nTris; ++ti)\n\t\tm->renderTris[ti] = m->tris[ti];\n\n\tm->QueueUpdate(Mesh::UpdateType::Indices);\n}\n\nvoid OutfitStudioFrame::SetNoSubMeshes() {\n\tif (!activeItem)\n\t\treturn;\n\n\tSetNoSubMeshes(glView->GetMesh(activeItem->GetShape()->name.get()));\n}\n\nvoid OutfitStudioFrame::OnSliderCheckBox(wxCommandEvent& event) {\n\twxCheckBox* box = (wxCheckBox*)event.GetEventObject();\n\tif (!box)\n\t\treturn;\n\n\tbool checked = event.IsChecked();\n\n\tstd::string sliderName = box->GetName().BeforeLast('|').ToStdString();\n\tShowSliderEffect(sliderName, checked);\n\n\tbool shiftDown = wxGetKeyState(WXK_SHIFT);\n\n\tif (!lastCheckedSlider.empty() && shiftDown) {\n\t\twxSliderPanel* sliderPanel = sliderPanels[sliderName];\n\t\twxSliderPanel* lastSliderPanel = sliderPanels[lastCheckedSlider];\n\n\t\tif (sliderPanel && lastSliderPanel) {\n\t\t\tsize_t sliderIndex = sliderPool.FindIndex(sliderPanel);\n\t\t\tsize_t lastSliderIndex = sliderPool.FindIndex(lastSliderPanel);\n\n\t\t\tif (sliderIndex != -1 && lastSliderIndex != -1 && sliderIndex != lastSliderIndex) {\n\t\t\t\tsize_t startIndex, endIndex;\n\t\t\t\tif (sliderIndex > lastSliderIndex) {\n\t\t\t\t\tstartIndex = lastSliderIndex;\n\t\t\t\t\tendIndex = sliderIndex;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tstartIndex = sliderIndex;\n\t\t\t\t\tendIndex = lastSliderIndex;\n\t\t\t\t}\n\n\t\t\t\tfor (size_t i = startIndex; i < endIndex; i++) {\n\t\t\t\t\twxSliderPanel* sliderPanelIndex = sliderPool.Get(i);\n\t\t\t\t\tif (sliderPanelIndex && sliderPanelIndex->IsCreated()) {\n\t\t\t\t\t\tstd::string sliderNameIndex = sliderPanelIndex->sliderCheck->GetName().BeforeLast('|').ToStdString();\n\t\t\t\t\t\tShowSliderEffect(sliderNameIndex, checked);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tApplySliders();\n\n\tif (!shiftDown)\n\t\tlastCheckedSlider = sliderName;\n}\n\nvoid OutfitStudioFrame::OnSelectTool(wxCommandEvent& event) {\n\tint id = event.GetId();\n\n\tif (id == XRCID(\"btnSelect\"))\n\t\tSelectTool(ToolID::Select);\n\telse if (id == XRCID(\"btnTransform\"))\n\t\tSelectTool(ToolID::Transform);\n\telse if (id == XRCID(\"btnPivot\"))\n\t\tSelectTool(ToolID::Pivot);\n\telse if (id == XRCID(\"btnVertexEdit\"))\n\t\tSelectTool(ToolID::VertexEdit);\n\telse if (id == XRCID(\"btnMaskBrush\"))\n\t\tSelectTool(ToolID::MaskBrush);\n\telse if (id == XRCID(\"btnInflateBrush\"))\n\t\tSelectTool(ToolID::InflateBrush);\n\telse if (id == XRCID(\"btnDeflateBrush\"))\n\t\tSelectTool(ToolID::DeflateBrush);\n\telse if (id == XRCID(\"btnMoveBrush\"))\n\t\tSelectTool(ToolID::MoveBrush);\n\telse if (id == XRCID(\"btnSmoothBrush\"))\n\t\tSelectTool(ToolID::SmoothBrush);\n\telse if (id == XRCID(\"btnUndiffBrush\"))\n\t\tSelectTool(ToolID::UndiffBrush);\n\telse if (id == XRCID(\"btnWeightBrush\"))\n\t\tSelectTool(ToolID::WeightBrush);\n\telse if (id == XRCID(\"btnColorBrush\"))\n\t\tSelectTool(ToolID::ColorBrush);\n\telse if (id == XRCID(\"btnAlphaBrush\"))\n\t\tSelectTool(ToolID::AlphaBrush);\n\telse if (id == XRCID(\"btnCollapseVertex\"))\n\t\tSelectTool(ToolID::CollapseVertex);\n\telse if (id == XRCID(\"btnFlipEdgeTool\"))\n\t\tSelectTool(ToolID::FlipEdge);\n\telse if (id == XRCID(\"btnSplitEdgeTool\"))\n\t\tSelectTool(ToolID::SplitEdge);\n\telse if (id == XRCID(\"btnMoveVertexTool\"))\n\t\tSelectTool(ToolID::MoveVertex);\n\telse\n\t\tSelectTool(ToolID::Any);\n\n\t// Remember last standard tool used in regular tabs\n\tif (meshTabButton->GetCheck() || lightsTabButton->GetCheck()) {\n\t\tauto activeBrush = glView->GetActiveBrush();\n\t\tif (activeBrush) {\n\t\t\tTweakBrush::BrushType brushType = activeBrush->Type();\n\t\t\tif (brushType == TweakBrush::BrushType::Inflate || brushType == TweakBrush::BrushType::Mask || brushType == TweakBrush::BrushType::Move) {\n\t\t\t\tglView->SetLastTool(glView->GetActiveTool());\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnSetView(wxCommandEvent& event) {\n\tint id = event.GetId();\n\n\tif (id == XRCID(\"btnViewFront\"))\n\t\tglView->SetView('F');\n\telse if (id == XRCID(\"btnViewBack\"))\n\t\tglView->SetView('B');\n\telse if (id == XRCID(\"btnViewLeft\"))\n\t\tglView->SetView('L');\n\telse if (id == XRCID(\"btnViewRight\"))\n\t\tglView->SetView('R');\n}\n\nvoid OutfitStudioFrame::OnTogglePerspective(wxCommandEvent& event) {\n\tbool enabled = event.IsChecked();\n\tmenuBar->Check(event.GetId(), enabled);\n\ttoolBarV->ToggleTool(event.GetId(), enabled);\n\n\tglView->SetPerspective(enabled);\n\tOutfitStudioConfig.SetBoolValue(\"Rendering/PerspectiveView\", enabled);\n}\n\nvoid OutfitStudioFrame::OnToggleRotationCenter(wxCommandEvent& WXUNUSED(event)) {\n\tautoFrameSelected = false;\n\n\tif (glView->rotationCenterMode != RotationCenterMode::Zero) {\n\t\tglView->rotationCenterMode = RotationCenterMode::Zero;\n\t\tglView->gls.camRotOffset.Zero();\n\t}\n\telse {\n\t\tglView->rotationCenterMode = RotationCenterMode::MeshCenter;\n\t\tglView->gls.camRotOffset = glView->gls.GetActiveCenter();\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnFrameSelected(wxCommandEvent& WXUNUSED(event)) {\n\tautoFrameSelected = !autoFrameSelected;\n\tFrameSelected();\n}\n\nvoid OutfitStudioFrame::FrameSelected() {\n\tauto& gls = glView->gls;\n\tconst auto& meshes = gls.GetActiveMeshes();\n\tif (meshes.empty())\n\t\treturn;\n\n\tnifly::Vector3 bbMin(std::numeric_limits<float>::max(), std::numeric_limits<float>::max(), std::numeric_limits<float>::max());\n\tnifly::Vector3 bbMax(std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest(), std::numeric_limits<float>::lowest());\n\tint count = 0;\n\n\tfor (auto& m : meshes) {\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tif (m->mask && m->mask[i] != 0.0f)\n\t\t\t\tcontinue;\n\t\t\tnifly::Vector3 v = m->TransformPosMeshToModel(m->verts[i]);\n\t\t\tbbMin.x = std::min(bbMin.x, v.x);\n\t\t\tbbMin.y = std::min(bbMin.y, v.y);\n\t\t\tbbMin.z = std::min(bbMin.z, v.z);\n\t\t\tbbMax.x = std::max(bbMax.x, v.x);\n\t\t\tbbMax.y = std::max(bbMax.y, v.y);\n\t\t\tbbMax.z = std::max(bbMax.z, v.z);\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tif (count == 0)\n\t\treturn;\n\n\tnifly::Vector3 center = (bbMin + bbMax) / 2.0f;\n\tfloat extentX = bbMax.x - bbMin.x;\n\tfloat extentY = bbMax.y - bbMin.y;\n\tfloat extentZ = bbMax.z - bbMin.z;\n\tfloat radius = std::max({extentX, extentY, extentZ}) / 2.0f;\n\tif (radius < 0.001f)\n\t\tradius = 0.001f;\n\n\tgls.camRotOffset = center;\n\tglView->rotationCenterMode = RotationCenterMode::MeshCenter;\n\n\tgls.camPos.x = -center.x;\n\tgls.camPos.y = -center.y;\n\n\tif (gls.perspective) {\n\t\tfloat fovRad = gls.mFov * DEG2RAD;\n\t\tfloat distance = radius / std::tan(fovRad / 2.0f);\n\t\tgls.camPos.z = -(distance + radius);\n\t}\n\telse {\n\t\tgls.camPos.z = -(radius * 2.5f);\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnShowNodes(wxCommandEvent& event) {\n\tbool enabled = event.IsChecked();\n\tmenuBar->Check(event.GetId(), enabled);\n\ttoolBarV->ToggleTool(event.GetId(), enabled);\n\tglView->ShowNodes(enabled);\n\tUpdateBoneTransformToolEnabled();\n}\n\nvoid OutfitStudioFrame::OnShowBones(wxCommandEvent& event) {\n\tbool enabled = event.IsChecked();\n\tmenuBar->Check(event.GetId(), enabled);\n\ttoolBarV->ToggleTool(event.GetId(), enabled);\n\tglView->ShowBones(enabled);\n\tUpdateBoneTransformToolEnabled();\n}\n\nvoid OutfitStudioFrame::OnShowFloor(wxCommandEvent& event) {\n\tbool enabled = event.IsChecked();\n\tmenuBar->Check(event.GetId(), enabled);\n\ttoolBarV->ToggleTool(event.GetId(), enabled);\n\tglView->ShowFloor(enabled);\n}\n\nvoid OutfitStudioFrame::OnBrushSettings(wxCommandEvent& WXUNUSED(event)) {\n\tif (brushSettingsPopupTransient && brushSettingsPopupTransient->IsShown())\n\t\tCloseBrushSettings();\n\telse\n\t\tPopupBrushSettings(brushSettings);\n}\n\nvoid OutfitStudioFrame::OnFieldOfViewSlider(wxCommandEvent& WXUNUSED(event)) {\n\tint fieldOfView = fovSlider->GetValue();\n\n\twxStaticText* fovLabel = (wxStaticText*)toolBarH->FindWindowByName(\"fovLabel\");\n\tfovLabel->SetLabel(wxString::Format(_(\"Field of View: %d\"), fieldOfView));\n\n\tglView->SetFieldOfView(fieldOfView);\n}\n\nvoid OutfitStudioFrame::OnDepthClip(wxCommandEvent& WXUNUSED(event)) {\n\tfloat zNear = cbDepthClip->IsChecked() ? 0.001f : 0.1f;\n\tglView->SetDepthClip(zNear, glView->gls.zFar);\n}\n\nvoid OutfitStudioFrame::OnUpdateLights(wxCommandEvent& WXUNUSED(event)) {\n\twxSlider* ambientSlider = (wxSlider*)lightSettings->FindWindowByName(\"lightAmbientSlider\");\n\twxSlider* frontalSlider = (wxSlider*)lightSettings->FindWindowByName(\"lightFrontalSlider\");\n\twxSlider* directional0Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional0Slider\");\n\twxSlider* directional1Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional1Slider\");\n\twxSlider* directional2Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional2Slider\");\n\n\tint ambient = ambientSlider->GetValue();\n\tint frontal = frontalSlider->GetValue();\n\tint directional0 = directional0Slider->GetValue();\n\tint directional1 = directional1Slider->GetValue();\n\tint directional2 = directional2Slider->GetValue();\n\tglView->UpdateLights(ambient, frontal, directional0, directional1, directional2);\n\n\tConfig.SetValue(\"Lights/Ambient\", ambient);\n\tConfig.SetValue(\"Lights/Frontal\", frontal);\n\tConfig.SetValue(\"Lights/Directional0\", directional0);\n\tConfig.SetValue(\"Lights/Directional1\", directional1);\n\tConfig.SetValue(\"Lights/Directional2\", directional2);\n}\n\nvoid OutfitStudioFrame::OnResetLights(wxCommandEvent& WXUNUSED(event)) {\n\tint ambient = 20;\n\tint frontal = 20;\n\tint directional0 = 60;\n\tint directional1 = 60;\n\tint directional2 = 85;\n\n\tglView->UpdateLights(ambient, frontal, directional0, directional1, directional2);\n\n\twxSlider* lightAmbientSlider = (wxSlider*)lightSettings->FindWindowByName(\"lightAmbientSlider\");\n\tlightAmbientSlider->SetValue(ambient);\n\n\twxSlider* lightFrontalSlider = (wxSlider*)lightSettings->FindWindowByName(\"lightFrontalSlider\");\n\tlightFrontalSlider->SetValue(frontal);\n\n\twxSlider* lightDirectional0Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional0Slider\");\n\tlightDirectional0Slider->SetValue(directional0);\n\n\twxSlider* lightDirectional1Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional1Slider\");\n\tlightDirectional1Slider->SetValue(directional1);\n\n\twxSlider* lightDirectional2Slider = (wxSlider*)lightSettings->FindWindowByName(\"lightDirectional2Slider\");\n\tlightDirectional2Slider->SetValue(directional2);\n\n\tConfig.SetValue(\"Lights/Ambient\", ambient);\n\tConfig.SetValue(\"Lights/Frontal\", frontal);\n\tConfig.SetValue(\"Lights/Directional0\", directional0);\n\tConfig.SetValue(\"Lights/Directional1\", directional1);\n\tConfig.SetValue(\"Lights/Directional2\", directional2);\n}\n\nvoid OutfitStudioFrame::OnClickSliderButton(wxCommandEvent& event) {\n\twxWindow* btn = (wxWindow*)event.GetEventObject();\n\tif (!btn)\n\t\treturn;\n\n\twxString buttonName = btn->GetName();\n\tstd::string clickedName{buttonName.BeforeLast('|').ToUTF8()};\n\tif (clickedName.empty()) {\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\twxString buttonNameId = buttonName.AfterLast('|');\n\n\tfloat scale = 0.0f;\n\tif (buttonNameId == \"btnMinus\")\n\t\tscale = 0.99f;\n\telse if (buttonNameId == \"btnPlus\")\n\t\tscale = 1.01f;\n\n\tif (scale != 0.0f) {\n\t\tfor (auto& i : selectedItems) {\n\t\t\tauto shape = i->GetShape();\n\t\t\tstd::vector<Vector3> verts;\n\t\t\tproject->ScaleMorphResult(shape, activeSlider, scale);\n\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\tglView->UpdateMeshVertices(shape->name.get(), &verts);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (buttonNameId == \"btnSliderProp\") {\n\t\tShowSliderProperties(clickedName);\n\t\treturn;\n\t}\n\n\tif (activeSlider != clickedName)\n\t\tEnterSliderEdit(clickedName);\n\telse\n\t\tExitSliderEdit();\n}\n\nvoid OutfitStudioFrame::OnEnterHoverSlider(wxMouseEvent& event) {\n\tevent.Skip();\n\n\tif (!event.ControlDown())\n\t\treturn;\n\n\tif (currentTabButton != meshTabButton)\n\t\treturn;\n\n\twxWindow* winObj = (wxWindow*)event.GetEventObject();\n\tif (!winObj)\n\t\treturn;\n\n\twxString objName = winObj->GetName();\n\tstd::string sliderName{objName.BeforeLast('|').ToUTF8()};\n\tif (sliderName.empty())\n\t\treturn;\n\n\tSliderData& sd = project->activeSet[sliderName];\n\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tMesh* m = glView->GetMesh(shape->name.get());\n\t\tif (m && m->weight) {\n\t\t\t// Clear color\n\t\t\tm->WeightFill(0.0f);\n\n\t\t\tauto diff = project->GetDiffSet(sd, shape);\n\t\t\tif (!diff)\n\t\t\t\tcontinue;\n\n\t\t\t// Get largest diff (length)\n\t\t\tfloat maxLength = 0.0f;\n\t\t\tfor (auto& d : *diff) {\n\t\t\t\tif (d.second.length() > maxLength)\n\t\t\t\t\tmaxLength = d.second.length();\n\t\t\t}\n\n\t\t\t// Apply color gradient to all vertices with diffs\n\t\t\tfor (auto& d : *diff) {\n\t\t\t\tif (m->nVerts > d.first) {\n\t\t\t\t\tfloat gradient = d.second.length() / maxLength;\n\t\t\t\t\tm->weight[d.first] = gradient;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Weight);\n\t\t}\n\t}\n\n\tglView->SetWeightVisible();\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnLeaveHoverSlider(wxMouseEvent& event) {\n\tevent.Skip();\n\n\tif (currentTabButton != meshTabButton)\n\t\treturn;\n\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tMesh* m = glView->GetMesh(shape->name.get());\n\t\tif (m && m->weight) {\n\t\t\t// Clear color\n\t\t\tm->WeightFill(0.0f);\n\t\t}\n\t}\n\n\tglView->SetWeightVisible(false);\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnReadoutChange(wxCommandEvent& event) {\n\twxTextCtrl* w = (wxTextCtrl*)event.GetEventObject();\n\tevent.Skip();\n\tif (!w)\n\t\treturn;\n\n\twxString sn = w->GetName();\n\tif (!sn.EndsWith(\"|readout\", &sn))\n\t\treturn;\n\n\tstd::string sliderName{sn.ToUTF8()};\n\n\tdouble v;\n\twxString val = w->GetValue();\n\tval.Replace(\"%\", \"\");\n\tif (!val.ToDouble(&v))\n\t\treturn;\n\n\twxSliderPanel* sliderPanel = sliderPanels[sliderName];\n\tsliderPanel->slider->SetValue(v);\n\n\tproject->SliderValue(sliderName) = v / 100.0f;\n\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnTabButtonClick(wxCommandEvent& event) {\n\tint id = event.GetId();\n\n\tif (currentTabButton && currentTabButton->HasPendingChanges()) {\n\t\twxMessageDialog dlg(this,\n\t\t\t\t\t\t\t_(\"Your changes were not applied yet. Do you want to apply or reset them?\"),\n\t\t\t\t\t\t\t_(\"Pending Changes\"),\n\t\t\t\t\t\t\twxYES_NO | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\t\tdlg.SetYesNoCancelLabels(_(\"Apply\"), _(\"Reset\"), _(\"Cancel\"));\n\n\t\tint res = dlg.ShowModal();\n\t\tif (res == wxID_YES) {\n\t\t\tif (currentTabButton == partitionTabButton)\n\t\t\t\tApplyPartitions();\n\t\t\telse if (currentTabButton == segmentTabButton)\n\t\t\t\tApplySegments();\n\t\t}\n\t\telse if (res == wxID_NO) {\n\t\t\tif (currentTabButton == partitionTabButton)\n\t\t\t\tResetPartitions();\n\t\t\telse if (currentTabButton == segmentTabButton)\n\t\t\t\tResetSegments();\n\t\t}\n\t\telse {\n\t\t\tevent.Skip();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif ((id == segmentTabButton->GetId() || id == partitionTabButton->GetId()) && selectedItems.size() != 1) {\n\t\twxMessageBox(_(\"You must have exactly one mesh selected in order to edit partitions or segments.\"), _(\"Info\"), wxICON_INFORMATION, this);\n\t\tevent.Skip();\n\t\treturn;\n\t}\n\n\tif (id != meshTabButton->GetId())\n\t\tmasksPane->Hide();\n\n\tif (id != segmentTabButton->GetId()) {\n\t\twxStaticText* segmentTypeLabel = (wxStaticText*)FindWindowByName(\"segmentTypeLabel\");\n\t\twxChoice* segmentType = (wxChoice*)FindWindowByName(\"segmentType\");\n\t\twxStaticText* segmentSlotLabel = (wxStaticText*)FindWindowByName(\"segmentSlotLabel\");\n\t\twxChoice* segmentSlot = (wxChoice*)FindWindowByName(\"segmentSlot\");\n\t\twxStaticText* segmentSSFLabel = (wxStaticText*)FindWindowByName(\"segmentSSFLabel\");\n\t\twxButton* segmentSSFEdit = (wxButton*)FindWindowByName(\"segmentSSFEdit\");\n\t\twxTextCtrl* segmentSSF = (wxTextCtrl*)FindWindowByName(\"segmentSSF\");\n\t\twxButton* segmentApply = (wxButton*)FindWindowByName(\"segmentApply\");\n\t\twxButton* segmentReset = (wxButton*)FindWindowByName(\"segmentReset\");\n\n\t\tsegmentTypeLabel->Show(false);\n\t\tsegmentType->Show(false);\n\t\tsegmentSlotLabel->Show(false);\n\t\tsegmentSlot->Show(false);\n\t\tsegmentSSFLabel->Show(false);\n\t\tsegmentSSFEdit->Show(false);\n\t\tsegmentSSF->Show(false);\n\t\tsegmentApply->Show(false);\n\t\tsegmentReset->Show(false);\n\n\t\tif (glView->GetSegmentMode())\n\t\t\tglView->ClearActiveMask();\n\n\t\tglView->SetSegmentMode(false);\n\t\tglView->SetMaskVisible();\n\n\t\tmenuBar->Enable(XRCID(\"btnSelect\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnClearMask\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnInvertMask\"), true);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), true);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), true);\n\n\t\ttoolBarH->EnableTool(XRCID(\"btnSelect\"), true);\n\t}\n\n\tif (id != partitionTabButton->GetId()) {\n\t\twxStaticText* partitionTypeLabel = (wxStaticText*)FindWindowByName(\"partitionTypeLabel\");\n\t\twxChoice* partitionType = (wxChoice*)FindWindowByName(\"partitionType\");\n\t\twxButton* partitionApply = (wxButton*)FindWindowByName(\"partitionApply\");\n\t\twxButton* partitionReset = (wxButton*)FindWindowByName(\"partitionReset\");\n\n\t\tpartitionTypeLabel->Show(false);\n\t\tpartitionType->Show(false);\n\t\tpartitionApply->Show(false);\n\t\tpartitionReset->Show(false);\n\n\t\tif (glView->GetSegmentMode())\n\t\t\tglView->ClearActiveMask();\n\n\t\tglView->SetSegmentMode(false);\n\t\tglView->SetMaskVisible();\n\n\t\tmenuBar->Enable(XRCID(\"btnSelect\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnClearMask\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnInvertMask\"), true);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), true);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), true);\n\n\t\ttoolBarH->EnableTool(XRCID(\"btnSelect\"), true);\n\t}\n\n\tif (id != boneTabButton->GetId()) {\n\t\tcXMirrorBone->Show(false);\n\n\t\twxStaticText* totalBoneCountLabel = (wxStaticText*)FindWindowByName(\"totalBoneCountLabel\");\n\t\twxStaticText* selectedBoneCountLabel = (wxStaticText*)FindWindowByName(\"selectedBoneCountLabel\");\n\t\twxCheckBox* cbFixedWeight = (wxCheckBox*)FindWindowByName(\"cbFixedWeight\");\n\t\twxCheckBox* cbNormalizeWeights = (wxCheckBox*)FindWindowByName(\"cbNormalizeWeights\");\n\t\twxStaticText* xMirrorBoneLabel = (wxStaticText*)FindWindowByName(\"xMirrorBoneLabel\");\n\n\t\ttotalBoneCountLabel->Show(false);\n\t\tselectedBoneCountLabel->Show(false);\n\t\tcbFixedWeight->Show(false);\n\t\tcbNormalizeWeights->Show(false);\n\t\txMirrorBoneLabel->Show(false);\n\t\tposePane->Show(false);\n\t\tbonesFilter->GetParent()->Show(false);\n\n\t\tif (project->bPose) {\n\t\t\tproject->bPose = false;\n\t\t\tApplyPose();\n\t\t}\n\n\t\tglView->SetWeightVisible(false);\n\t}\n\n\tif (id != colorsTabButton->GetId()) {\n\t\tUpdateVertexColors();\n\t}\n\n\tif (id != boneTabButton->GetId() && id != colorsTabButton->GetId()) {\n\t\tmenuBar->Check(XRCID(\"btnInflateBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnTransform\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnPivot\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnVertexEdit\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnWeightBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnColorBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnAlphaBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInflateBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnDeflateBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnMoveBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnSmoothBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnUndiffBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnCollapseVertex\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnFlipEdgeTool\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnSplitEdgeTool\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnMoveVertexTool\"), true);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), true);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), true);\n\n\t\ttoolBarH->ToggleTool(XRCID(\"btnInflateBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnWeightBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnColorBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnAlphaBrush\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnTransform\"), true);\n\t\ttoolBarV->EnableTool(XRCID(\"btnPivot\"), true);\n\t\ttoolBarV->EnableTool(XRCID(\"btnVertexEdit\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnInflateBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnDeflateBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSmoothBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnUndiffBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnCollapseVertex\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnFlipEdgeTool\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSplitEdgeTool\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveVertexTool\"), true);\n\t}\n\n\tif (id == meshTabButton->GetId()) {\n\t\tcurrentTabButton = meshTabButton;\n\n\t\toutfitBones->Hide();\n\t\tcolorSettings->Hide();\n\t\tsegmentTree->Hide();\n\t\tpartitionTree->Hide();\n\t\tlightSettings->Hide();\n\t\toutfitShapes->Show();\n\n\t\tboneTabButton->SetCheck(false);\n\t\tcolorsTabButton->SetCheck(false);\n\t\tsegmentTabButton->SetCheck(false);\n\t\tpartitionTabButton->SetCheck(false);\n\t\tlightsTabButton->SetCheck(false);\n\n\t\tmasksPane->Show();\n\n\t\tSetNoSubMeshes();\n\t\tSelectTool(glView->GetLastTool());\n\t}\n\telse if (id == boneTabButton->GetId()) {\n\t\tcurrentTabButton = boneTabButton;\n\n\t\toutfitShapes->Hide();\n\t\tcolorSettings->Hide();\n\t\tsegmentTree->Hide();\n\t\tpartitionTree->Hide();\n\t\tlightSettings->Hide();\n\t\toutfitBones->Show();\n\n\t\tmeshTabButton->SetCheck(false);\n\t\tcolorsTabButton->SetCheck(false);\n\t\tsegmentTabButton->SetCheck(false);\n\t\tpartitionTabButton->SetCheck(false);\n\t\tlightsTabButton->SetCheck(false);\n\n\t\tcXMirrorBone->Show();\n\n\t\twxStaticText* totalBoneCountLabel = (wxStaticText*)FindWindowByName(\"totalBoneCountLabel\");\n\t\twxStaticText* selectedBoneCountLabel = (wxStaticText*)FindWindowByName(\"selectedBoneCountLabel\");\n\t\twxCheckBox* cbFixedWeight = (wxCheckBox*)FindWindowByName(\"cbFixedWeight\");\n\t\twxCheckBox* cbNormalizeWeights = (wxCheckBox*)FindWindowByName(\"cbNormalizeWeights\");\n\t\twxStaticText* xMirrorBoneLabel = (wxStaticText*)FindWindowByName(\"xMirrorBoneLabel\");\n\n\t\ttotalBoneCountLabel->Show();\n\t\tselectedBoneCountLabel->Show();\n\t\tcbFixedWeight->Show();\n\t\tcbNormalizeWeights->Show();\n\t\txMirrorBoneLabel->Show();\n\t\tposePane->Show();\n\t\tbonesFilter->GetParent()->Show();\n\n\t\tUpdateBoneTransformToolEnabled();\n\n\t\tSelectTool(ToolID::WeightBrush);\n\t\tglView->SetWeightVisible();\n\n\t\tproject->bPose = cbPose->GetValue();\n\n\t\tif (project->bPose)\n\t\t\tApplyPose();\n\n\t\tmenuBar->Check(XRCID(\"btnWeightBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnWeightBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnColorBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnAlphaBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnPivot\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnVertexEdit\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInflateBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnDeflateBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnMoveBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnSmoothBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnUndiffBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnCollapseVertex\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnFlipEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSplitEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveVertexTool\"), true);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), false);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), false);\n\n\t\ttoolBarH->ToggleTool(XRCID(\"btnWeightBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnWeightBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnColorBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnAlphaBrush\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnPivot\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnVertexEdit\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnInflateBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnDeflateBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSmoothBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnUndiffBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnCollapseVertex\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnFlipEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSplitEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveVertexTool\"), true);\n\n\t\tSetNoSubMeshes();\n\n\t\tReselectBone();\n\t\tUpdateUndoTools();\n\t}\n\telse if (id == colorsTabButton->GetId()) {\n\t\tcurrentTabButton = colorsTabButton;\n\n\t\toutfitShapes->Hide();\n\t\toutfitBones->Hide();\n\t\tsegmentTree->Hide();\n\t\tpartitionTree->Hide();\n\t\tlightSettings->Hide();\n\t\tcolorSettings->Show();\n\n\t\tmeshTabButton->SetCheck(false);\n\t\tboneTabButton->SetCheck(false);\n\t\tsegmentTabButton->SetCheck(false);\n\t\tpartitionTabButton->SetCheck(false);\n\t\tlightsTabButton->SetCheck(false);\n\n\t\tglView->SetTransformMode(false);\n\t\tSelectTool(ToolID::ColorBrush);\n\t\tglView->SetColorsVisible();\n\n\t\twxButton* btnSwapBrush = (wxButton*)FindWindowById(XRCID(\"btnSwapBrush\"), colorSettings);\n\t\tbtnSwapBrush->SetLabel(_(\"Edit Alpha\"));\n\n\t\tFillVertexColors();\n\n\t\tmenuBar->Check(XRCID(\"btnColorBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnColorBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnAlphaBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnWeightBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnTransform\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnPivot\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnVertexEdit\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInflateBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnDeflateBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSmoothBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnUndiffBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnCollapseVertex\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnFlipEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSplitEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveVertexTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), false);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), false);\n\n\t\ttoolBarH->ToggleTool(XRCID(\"btnColorBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnColorBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnAlphaBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnWeightBrush\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnTransform\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnPivot\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnVertexEdit\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnInflateBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnDeflateBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSmoothBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnUndiffBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnCollapseVertex\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnFlipEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSplitEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveVertexTool\"), false);\n\n\t\tSetNoSubMeshes();\n\t}\n\telse if (id == segmentTabButton->GetId()) {\n\t\tcurrentTabButton = segmentTabButton;\n\n\t\toutfitShapes->Hide();\n\t\toutfitBones->Hide();\n\t\tcolorSettings->Hide();\n\t\tpartitionTree->Hide();\n\t\tlightSettings->Hide();\n\t\tsegmentTree->Show();\n\n\t\tmeshTabButton->SetCheck(false);\n\t\tboneTabButton->SetCheck(false);\n\t\tcolorsTabButton->SetCheck(false);\n\t\tpartitionTabButton->SetCheck(false);\n\t\tlightsTabButton->SetCheck(false);\n\n\t\twxStaticText* segmentTypeLabel = (wxStaticText*)FindWindowByName(\"segmentTypeLabel\");\n\t\twxChoice* segmentType = (wxChoice*)FindWindowByName(\"segmentType\");\n\t\twxStaticText* segmentSlotLabel = (wxStaticText*)FindWindowByName(\"segmentSlotLabel\");\n\t\twxChoice* segmentSlot = (wxChoice*)FindWindowByName(\"segmentSlot\");\n\t\twxStaticText* segmentSSFLabel = (wxStaticText*)FindWindowByName(\"segmentSSFLabel\");\n\t\twxButton* segmentSSFEdit = (wxButton*)FindWindowByName(\"segmentSSFEdit\");\n\t\twxTextCtrl* segmentSSF = (wxTextCtrl*)FindWindowByName(\"segmentSSF\");\n\t\twxButton* segmentApply = (wxButton*)FindWindowByName(\"segmentApply\");\n\t\twxButton* segmentReset = (wxButton*)FindWindowByName(\"segmentReset\");\n\n\t\tsegmentTypeLabel->Show();\n\t\tsegmentType->Show();\n\t\tsegmentSlotLabel->Show();\n\t\tsegmentSlot->Show();\n\t\tsegmentSSFLabel->Show();\n\t\tsegmentSSFEdit->Show();\n\t\tsegmentSSF->Show();\n\t\tsegmentApply->Show();\n\t\tsegmentReset->Show();\n\n\t\tglView->SetSegmentMode();\n\t\tSelectTool(ToolID::MaskBrush); // Use mask brush for segment editing (but with custom painting function 'PaintSegmentPartitionTriangles')\n\t\tglView->SetMaskVisible(false);\n\t\tglView->ClearMasks();\n\n\t\tmenuBar->Check(XRCID(\"btnMaskBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnSelect\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnTransform\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnPivot\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnVertexEdit\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInflateBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnDeflateBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSmoothBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnUndiffBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnClearMask\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInvertMask\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnCollapseVertex\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnFlipEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSplitEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveVertexTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), false);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), false);\n\n\t\ttoolBarH->ToggleTool(XRCID(\"btnMaskBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSelect\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnTransform\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnPivot\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnVertexEdit\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnInflateBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnDeflateBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSmoothBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnUndiffBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnCollapseVertex\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnFlipEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSplitEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveVertexTool\"), false);\n\n\t\tShowSegment(segmentTree->GetSelection());\n\t}\n\telse if (id == partitionTabButton->GetId()) {\n\t\tcurrentTabButton = partitionTabButton;\n\n\t\toutfitShapes->Hide();\n\t\toutfitBones->Hide();\n\t\tcolorSettings->Hide();\n\t\tsegmentTree->Hide();\n\t\tlightSettings->Hide();\n\t\tpartitionTree->Show();\n\n\t\tmeshTabButton->SetCheck(false);\n\t\tboneTabButton->SetCheck(false);\n\t\tcolorsTabButton->SetCheck(false);\n\t\tsegmentTabButton->SetCheck(false);\n\t\tlightsTabButton->SetCheck(false);\n\n\t\twxStaticText* partitionTypeLabel = (wxStaticText*)FindWindowByName(\"partitionTypeLabel\");\n\t\twxChoice* partitionType = (wxChoice*)FindWindowByName(\"partitionType\");\n\t\twxButton* partitionApply = (wxButton*)FindWindowByName(\"partitionApply\");\n\t\twxButton* partitionReset = (wxButton*)FindWindowByName(\"partitionReset\");\n\n\t\tpartitionTypeLabel->Show();\n\t\tpartitionType->Show();\n\t\tpartitionApply->Show();\n\t\tpartitionReset->Show();\n\n\t\tglView->SetSegmentMode();\n\t\tSelectTool(ToolID::MaskBrush); // Use mask brush for partition editing (but with custom painting function 'PaintSegmentPartitionTriangles')\n\t\tglView->SetMaskVisible(false);\n\t\tglView->ClearMasks();\n\n\t\tmenuBar->Check(XRCID(\"btnMaskBrush\"), true);\n\t\tmenuBar->Enable(XRCID(\"btnSelect\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnTransform\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnPivot\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnVertexEdit\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInflateBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnDeflateBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSmoothBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnUndiffBrush\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnClearMask\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnInvertMask\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnCollapseVertex\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnFlipEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnSplitEdgeTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"btnMoveVertexTool\"), false);\n\t\tmenuBar->Enable(XRCID(\"deleteVerts\"), false);\n\t\tmenuBar->Enable(XRCID(\"refineMesh\"), false);\n\n\t\ttoolBarH->ToggleTool(XRCID(\"btnMaskBrush\"), true);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSelect\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnTransform\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnPivot\"), false);\n\t\ttoolBarV->EnableTool(XRCID(\"btnVertexEdit\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnInflateBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnDeflateBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSmoothBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnUndiffBrush\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnCollapseVertex\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnFlipEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnSplitEdgeTool\"), false);\n\t\ttoolBarH->EnableTool(XRCID(\"btnMoveVertexTool\"), false);\n\n\t\tShowPartition(partitionTree->GetSelection());\n\t}\n\telse if (id == lightsTabButton->GetId()) {\n\t\tcurrentTabButton = lightsTabButton;\n\n\t\toutfitShapes->Hide();\n\t\toutfitBones->Hide();\n\t\tcolorSettings->Hide();\n\t\tsegmentTree->Hide();\n\t\tpartitionTree->Hide();\n\t\tlightSettings->Show();\n\n\t\tmeshTabButton->SetCheck(false);\n\t\tboneTabButton->SetCheck(false);\n\t\tcolorsTabButton->SetCheck(false);\n\t\tsegmentTabButton->SetCheck(false);\n\t\tpartitionTabButton->SetCheck(false);\n\n\t\tSetNoSubMeshes();\n\t\tSelectTool(glView->GetLastTool());\n\t}\n\n\tCheckBrushBounds();\n\tUpdateBrushSettings();\n\n\twxPanel* topSplitPanel = (wxPanel*)FindWindowByName(\"topSplitPanel\");\n\twxPanel* bottomSplitPanel = (wxPanel*)FindWindowByName(\"bottomSplitPanel\");\n\n\ttopSplitPanel->Layout();\n\tbottomSplitPanel->Layout();\n\n\tRefresh();\n}\n\nvoid OutfitStudioFrame::OnBrushColorChanged(wxColourPickerEvent& event) {\n\twxColour color = event.GetColour();\n\tVector3 brushColor;\n\tbrushColor.x = color.Red() / 255.0f;\n\tbrushColor.y = color.Green() / 255.0f;\n\tbrushColor.z = color.Blue() / 255.0f;\n\tglView->SetColorBrush(brushColor);\n}\n\nvoid OutfitStudioFrame::OnColorClampMaxValueSlider(wxCommandEvent& WXUNUSED(event)) {\n\twxSlider* slider = (wxSlider*)colorSettings->FindWindowByName(\"cpClampMaxValueSlider\");\n\twxTextCtrl* txtControl = (wxTextCtrl*)colorSettings->FindWindowByName(\"cpClampMaxValueTxt\");\n\tint clampMaxValue = slider->GetValue();\n\ttxtControl->SetValue(wxString::Format(\"%d\", clampMaxValue));\n\n\tClampBrush* clampBrush = dynamic_cast<ClampBrush*>(glView->GetActiveBrush());\n\tif (clampBrush)\n\t\tclampBrush->clampMaxValue = clampMaxValue / 255.0f;\n}\n\nvoid OutfitStudioFrame::OnColorClampMaxValueChanged(wxCommandEvent& WXUNUSED(event)) {\n\twxTextCtrl* txtControl = (wxTextCtrl*)colorSettings->FindWindowByName(\"cpClampMaxValueTxt\");\n\twxSlider* slider = (wxSlider*)colorSettings->FindWindowByName(\"cpClampMaxValueSlider\");\n\tint clampMaxValue = std::clamp(atoi(txtControl->GetValue().c_str()), 0, 255);\n\tslider->SetValue(clampMaxValue);\n\n\tif (!glView)\n\t\treturn;\n\tClampBrush* clampBrush = dynamic_cast<ClampBrush*>(glView->GetActiveBrush());\n\tif (clampBrush)\n\t\tclampBrush->clampMaxValue = clampMaxValue / 255.0f;\n}\n\nvoid OutfitStudioFrame::OnSwapBrush(wxCommandEvent& WXUNUSED(event)) {\n\tToolID activeTool = glView->GetActiveTool();\n\tif (activeTool == ToolID::ColorBrush)\n\t\tSelectTool(ToolID::AlphaBrush);\n\telse if (activeTool == ToolID::AlphaBrush)\n\t\tSelectTool(ToolID::ColorBrush);\n}\n\nvoid OutfitStudioFrame::OnMaskVertexColor(wxCommandEvent& WXUNUSED(event)) {\n\tauto cpBrushColor = (wxColourPickerCtrl*)FindWindowById(XRCID(\"cpBrushColor\"));\n\tif (!cpBrushColor)\n\t\treturn;\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\twxColour color = cpBrushColor->GetColour();\n\tVector3 brushColor;\n\tbrushColor.x = color.Red() / 255.0f;\n\tbrushColor.y = color.Green() / 255.0f;\n\tbrushColor.z = color.Blue() / 255.0f;\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\n\tauto isSimilarColor = [](const Vector3& a,\n\t\t\t\t\t\t\t const Vector3& b,\n\t\t\t\t\t\t\t float angleEps = 1e-3f,\t   // ~cos angle tolerance\n\t\t\t\t\t\t\t float chromaThresh = 1e-4f) { // how much colorfulness we require\n\t\tif (a == b)\n\t\t\treturn true;\n\n\t\tauto getChromaDir = [&](const Vector3& c, Vector3& outDir) {\n\t\t\tfloat minc = std::min({c.x, c.y, c.z});\n\t\t\tVector3 chroma{c.x - minc, c.y - minc, c.z - minc}; // strip added white\n\t\t\tfloat l = chroma.length();\n\t\t\tif (l < chromaThresh)\n\t\t\t\treturn false; // basically gray/white -> no reliable hue\n\n\t\t\toutDir = {chroma.x / l, chroma.y / l, chroma.z / l};\n\t\t\treturn true;\n\t\t};\n\n\t\tVector3 da, db;\n\t\tbool okA = getChromaDir(a, da);\n\t\tbool okB = getChromaDir(b, db);\n\n\t\tif (!okA && !okB) // both are essentially gray/white\n\t\t\treturn false; // treat all near-white/gray as mismatch\n\t\tif (okA != okB)\n\t\t\treturn false; // one has hue, the other doesn't\n\n\t\treturn da.dot(db) > 1.0f - angleEps;\n\t};\n\n\tfor (auto& selItem : selectedItems) {\n\t\tstd::string shapeName = selItem->GetShape()->name.get();\n\t\tMesh* m = glView->GetMesh(shapeName);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tuss.pointStartState[i].x = m->mask[i];\n\n\t\t\tif (m->vcolors && isSimilarColor(m->vcolors[i], brushColor))\n\t\t\t\tuss.pointEndState[i].x = 1.0f;\n\t\t\telse\n\t\t\t\tuss.pointEndState[i].x = 0.0f;\n\t\t}\n\t}\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tglView->GetUndoHistory()->PopState();\n\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::ScrollWindowIntoView(wxScrolledWindow* scrolled, wxWindow* window) {\n\t// \"window\" must be an immediate child of \"scrolled\"\n\tint scrollRateY = 0;\n\tscrolled->GetScrollPixelsPerUnit(nullptr, &scrollRateY);\n\n\twxPoint window_pos = scrolled->CalcUnscrolledPosition(window->GetPosition());\n\tscrolled->Scroll(0, window_pos.y / scrollRateY);\n}\n\nvoid OutfitStudioFrame::HighlightSlider(const std::string& name) {\n\tfor (auto& d : sliderPanels) {\n\t\tif (d.first == name) {\n\t\t\td.second->editing = true;\n\t\t\td.second->SetBackgroundColour(wxColour(125, 77, 138));\n\t\t}\n\t\telse {\n\t\t\td.second->editing = false;\n\t\t\td.second->SetBackgroundColour(wxColour(64, 64, 64));\n\t\t}\n\t}\n\tsliderScroll->Refresh();\n}\n\nvoid OutfitStudioFrame::ZeroSliders() {\n\tif (!project->AllSlidersZero()) {\n\t\tfor (size_t s = 0; s < project->SliderCount(); s++) {\n\t\t\tif (project->SliderClamp(s))\n\t\t\t\tcontinue;\n\n\t\t\tSetSliderValue(s, 0);\n\t\t}\n\t\tApplySliders();\n\t}\n}\n\nvoid OutfitStudioFrame::OnSlider(wxCommandEvent& event) {\n\twxSlider* s = ((wxSlider*)event.GetEventObject());\n\tif (!s)\n\t\treturn;\n\n\twxString sliderName = s->GetName();\n\tstd::string sn{sliderName.BeforeLast('|').ToUTF8()};\n\tif (sn.empty())\n\t\treturn;\n\n\tSetSliderValue(sn, event.GetInt());\n\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnLoadPreset(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tPresetCollection presets;\n\tstd::vector<std::string> names;\n\twxChoice* presetChoice;\n\n\tstd::string choice;\n\tbool hi = true;\n\n\tCloseBrushSettings();\n\n\tpresets.LoadPresets(GetProjectPath() + \"/SliderPresets\", choice, names, true);\n\tpresets.GetPresetNames(names);\n\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgChoosePreset\")) {\n\t\tpresetChoice = XRCCTRL(dlg, \"choicePreset\", wxChoice);\n\t\tpresetChoice->AppendString(\"Zero All\");\n\t\tfor (auto& n : names)\n\t\t\tpresetChoice->AppendString(n);\n\n\t\tpresetChoice->SetSelection(0);\n\n\t\tdlg.SetSize(dlg.FromDIP(wxSize(325, 175)));\n\t\tdlg.SetSizeHints(dlg.FromDIP(wxSize(325, 175)), wxSize(-1, -1));\n\t\tdlg.CenterOnParent();\n\n\t\tif (dlg.ShowModal() != wxID_OK)\n\t\t\treturn;\n\n\t\tchoice = presetChoice->GetStringSelection();\n\t\tif (XRCCTRL(dlg, \"weightLo\", wxRadioButton)->GetValue())\n\t\t\thi = false;\n\n\t\tZeroSliders();\n\n\t\tif (choice == \"Zero All\") {\n\t\t\twxLogMessage(\"Sliders were reset to zero.\");\n\t\t\treturn;\n\t\t}\n\n\t\twxLogMessage(\"Applying preset '%s' with option '%s'.\", choice, hi ? \"High\" : \"Low\");\n\n\t\tfloat v;\n\t\tbool r;\n\t\tfor (size_t i = 0; i < project->SliderCount(); i++) {\n\t\t\tif (!presets.GetSliderExists(choice, project->GetSliderName(i)))\n\t\t\t\tcontinue;\n\n\t\t\tif (project->SliderClamp(i))\n\t\t\t\tcontinue;\n\n\t\t\tif (hi)\n\t\t\t\tr = presets.GetBigPreset(choice, project->GetSliderName(i), v);\n\t\t\telse\n\t\t\t\tr = presets.GetSmallPreset(choice, project->GetSliderName(i), v);\n\n\t\t\tif (!r)\n\t\t\t\tv = project->SliderDefault(i, hi) / 100.0f;\n\t\t\tif (project->SliderInvert(i))\n\t\t\t\tv = 1.0f - v;\n\n\t\t\tv *= 100.0f;\n\t\t\tSetSliderValue(i, v);\n\t\t}\n\n\t\tApplySliders();\n\t}\n}\n\nvoid OutfitStudioFrame::OnSavePreset(wxCommandEvent& WXUNUSED(event)) {\n\tstd::vector<std::string> sliders;\n\tproject->GetSliderList(sliders);\n\tif (sliders.empty()) {\n\t\twxMessageBox(_(\"There are no sliders loaded!\"), _(\"Error\"), wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\tCloseBrushSettings();\n\n\tSliderSetGroupCollection groupCollection;\n\tgroupCollection.LoadGroups(GetProjectPath() + \"/SliderGroups\");\n\n\tstd::set<std::string> allGroups;\n\tgroupCollection.GetAllGroups(allGroups);\n\n\tPresetSaveDialog psd(this);\n\tpsd.allGroupNames.assign(allGroups.begin(), allGroups.end());\n\tpsd.FilterGroups();\n\n\tpsd.ShowModal();\n\tif (psd.outFileName.empty())\n\t\treturn;\n\n\tstd::string fileName = psd.outFileName;\n\tstd::string presetName = psd.outPresetName;\n\n\tstd::vector<std::string> groups;\n\tgroups.assign(psd.outGroups.begin(), psd.outGroups.end());\n\n\tbool addedSlider = false;\n\tPresetCollection presets;\n\tfor (auto& s : sliders) {\n\t\tsize_t index = 0;\n\t\tif (!project->SliderIndexFromName(s, index))\n\t\t\tcontinue;\n\n\t\tif (project->SliderZap(index) || project->SliderHidden(index))\n\t\t\tcontinue;\n\n\t\tfloat value = project->SliderValue(index);\n\t\tif (project->SliderInvert(index))\n\t\t\tvalue = 1.0f - value;\n\n\t\tif (project->SliderDefault(index, true) == value)\n\t\t\tcontinue;\n\n\t\tpresets.SetSliderPreset(presetName, s, value, -10000.0f);\n\n\t\tif (!addedSlider)\n\t\t\taddedSlider = true;\n\t}\n\n\tif (!addedSlider) {\n\t\twxLogMessage(\"No changes were made to the sliders, so no preset was saved!\");\n\t\twxMessageBox(_(\"No changes were made to the sliders, so no preset was saved!\"), _(\"Info\"), wxICON_INFORMATION, this);\n\t\treturn;\n\t}\n\n\tint error = presets.SavePreset(fileName, presetName, \"OutfitStudioFrame\", groups);\n\tif (error) {\n\t\twxLogError(\"Failed to save preset (%d)!\", error);\n\t\twxMessageBox(wxString::Format(_(\"Failed to save preset (%d)!\"), error), _(\"Error\"), wxICON_ERROR, this);\n\t}\n}\n\nvoid OutfitStudioFrame::OnSliderImportNIF(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to import data to!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Import .nif file for slider calculation\"), wxEmptyString, wxEmptyString, \".nif\", \"*.nif\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing slider to '%s' for shape '%s' from NIF file '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\tif (!project->SetSliderFromNIF(activeSlider, activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\twxLogError(\"No mesh found in the .nif file that matches currently selected shape!\");\n\t\twxMessageBox(_(\"No mesh found in the .nif file that matches currently selected shape!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tSetPendingChanges();\n\tApplySliders();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::OnSliderImportBSD(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to import data to!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Import .bsd slider data\"), wxEmptyString, wxEmptyString, \".bsd\", \"*.bsd\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing slider to '%s' for shape '%s' from BSD file '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\tproject->SetSliderFromBSD(activeSlider, activeItem->GetShape(), fn.ToUTF8().data());\n\n\tSetPendingChanges();\n\tApplySliders();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::OnSliderImportOBJ(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to import data to!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Import .obj file for slider calculation\"), wxEmptyString, wxEmptyString, \".obj\", \"*.obj\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing slider to '%s' for shape '%s' from OBJ file '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\tif (!project->SetSliderFromOBJ(activeSlider, activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\twxLogError(\"Vertex count of .obj file mesh does not match currently selected shape!\");\n\t\twxMessageBox(_(\"Vertex count of .obj file mesh does not match currently selected shape!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tSetPendingChanges();\n\tApplySliders();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::OnSliderImportOSD(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Import .osd file\"), wxEmptyString, wxEmptyString, \".osd\", \"*.osd\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing morphs from OSD file '%s'...\", fn);\n\n\tOSDataFile osd;\n\tif (!osd.Read(fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to import OSD file '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to import OSD file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tstd::unordered_map<std::string, std::unordered_map<std::string, std::string>> shapeToSliders;\n\tauto& diffs = osd.GetDataDiffs();\n\tconst auto& shapes = project->GetWorkNif()->GetShapes();\n\tfor (auto& diff : diffs) {\n\t\tstd::string bestTargetName;\n\t\tfor (auto& shape : shapes) {\n\t\t\tstd::string shapeName = shape->name.get();\n\t\t\tstd::string targetName = project->ShapeToTarget(shapeName);\n\n\t\t\t// Diff name is supposed to begin with matching shape name\n\t\t\tif (diff.first.substr(0, targetName.size()) != targetName)\n\t\t\t\tcontinue;\n\n\t\t\tif (shapeName.length() > bestTargetName.length())\n\t\t\t\tbestTargetName = targetName;\n\t\t}\n\n\t\tif (bestTargetName.length() == 0)\n\t\t\tcontinue;\n\n\t\t// Find slider name from data name\n\t\tauto sliderName = project->activeSet.SliderFromDataName(bestTargetName, diff.first);\n\t\tif (sliderName.empty())\n\t\t\tsliderName = diff.first.substr(bestTargetName.length(), diff.first.length() - bestTargetName.length() + 1);\n\n\t\tshapeToSliders[bestTargetName].emplace(sliderName, diff.first);\n\t}\n\n\tSliderDataImportDialog import(this, project, OutfitStudioConfig);\n\tif (import.ShowModal(shapeToSliders) != wxID_OK)\n\t\treturn;\n\n\tconst auto& options = import.GetOptions();\n\n\tsliderScroll->Freeze();\n\tif (!options.mergeSliders) {\n\t\twxMessageDialog dlg(this, _(\"This will delete all loaded sliders. Are you sure?\"), _(\"OSD Import\"), wxOK | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\t\tdlg.SetOKCancelLabels(_(\"Import\"), _(\"Cancel\"));\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tsliderScroll->Thaw();\n\t\t\treturn;\n\t\t}\n\n\t\t// Deleting sliders\n\t\tstd::vector<std::string> erase;\n\t\tfor (auto& sliderPanel : sliderPanels) {\n\t\t\tsliderPanel.second->slider->SetValue(0);\n\t\t\tSetSliderValue(sliderPanel.first, 0);\n\t\t\tShowSliderEffect(sliderPanel.first, true);\n\t\t\tsliderPanel.second->slider->SetFocus();\n\t\t\tHideSliderPanel(sliderPanel.second);\n\n\t\t\terase.push_back(sliderPanel.first);\n\t\t\tproject->DeleteSlider(sliderPanel.first);\n\t\t}\n\n\t\tfor (auto& e : erase)\n\t\t\tsliderPanels.erase(e);\n\n\t\tMenuExitSliderEdit();\n\t\tsliderScroll->FitInside();\n\t\tactiveSlider.clear();\n\t\tlastActiveSlider.clear();\n\t}\n\n\tstd::unordered_set<NiShape*> addedShapes;\n\n\tfor (auto& shape : shapes) {\n\t\t// check if the shape is selected\n\t\tauto selectedSliders = options.selectedShapesToSliders.find(shape->name.get());\n\t\tif (selectedSliders == options.selectedShapesToSliders.end())\n\t\t\tcontinue;\n\n\t\taddedShapes.emplace(shape);\n\n\t\tfor (auto& diff : diffs) {\n\t\t\tauto& sliderNameToDisplayName = selectedSliders->second;\n\n\t\t\t// check the diff is selected for the specific shape\n\t\t\tauto sliderName = selectedSliders->second.find(diff.first);\n\t\t\tif (sliderName == sliderNameToDisplayName.end())\n\t\t\t\tcontinue;\n\n\t\t\tif (!project->ValidSlider(sliderName->second)) {\n\t\t\t\tproject->AddEmptySlider(sliderName->second);\n\t\t\t\tcreateSliderGUI(sliderName->second, sliderScroll, sliderScroll->GetSizer());\n\t\t\t}\n\n\t\t\tproject->SetSliderFromDiff(sliderName->second, shape, *diff.second);\n\t\t}\n\t}\n\n\twxString addedDiffs;\n\tfor (auto& addedShape : addedShapes) {\n\t\taddedDiffs += addedShape->name.get() + \"\\n\";\n\t}\n\n\tsliderScroll->FitInside();\n\tsliderScroll->Thaw();\n\n\tSetPendingChanges();\n\tApplySliders();\n\tDoFilterSliders();\n\tHighlightSliderData();\n\n\twxLogMessage(\"Added morphs for the following shapes:\\n%s\", addedDiffs);\n\twxMessageBox(wxString::Format(_(\"Added morphs for the following shapes:\\n\\n%s\"), addedDiffs), _(\"OSD Import\"));\n}\n\nvoid OutfitStudioFrame::OnSliderImportTRI(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Import .tri morphs\"), wxEmptyString, wxEmptyString, \".tri\", \"*.tri\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing morphs from TRI file '%s'...\", fn);\n\n\tTriFile tri;\n\tif (!tri.Read(fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to load TRI file '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to load TRI file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tstd::unordered_map<std::string, std::unordered_map<std::string, std::string>> shapeToSliders;\n\tauto morphs = tri.GetMorphs();\n\tfor (auto& morph : morphs) {\n\t\tauto shape = project->GetWorkNif()->FindBlockByName<NiShape>(morph.first);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\tfor (auto& morphData : morph.second)\n\t\t\tshapeToSliders[shape->name.get()].emplace(morphData->name, morphData->name);\n\t}\n\n\tSliderDataImportDialog import(this, project, OutfitStudioConfig);\n\tif (import.ShowModal(shapeToSliders) != wxID_OK)\n\t\treturn;\n\n\tconst auto& options = import.GetOptions();\n\n\tsliderScroll->Freeze();\n\tif (!options.mergeSliders) {\n\t\twxMessageDialog dlg(this, _(\"This will delete all loaded sliders. Are you sure?\"), _(\"TRI Import\"), wxOK | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\t\tdlg.SetOKCancelLabels(_(\"Import\"), _(\"Cancel\"));\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tsliderScroll->Thaw();\n\t\t\treturn;\n\t\t}\n\n\t\t// Deleting sliders\n\t\tstd::vector<std::string> erase;\n\t\tfor (auto& sliderPanel : sliderPanels) {\n\t\t\tsliderPanel.second->slider->SetValue(0);\n\t\t\tSetSliderValue(sliderPanel.first, 0);\n\t\t\tShowSliderEffect(sliderPanel.first, true);\n\t\t\tsliderPanel.second->slider->SetFocus();\n\t\t\tHideSliderPanel(sliderPanel.second);\n\n\t\t\terase.push_back(sliderPanel.first);\n\t\t\tproject->DeleteSlider(sliderPanel.first);\n\t\t}\n\n\t\tfor (auto& e : erase)\n\t\t\tsliderPanels.erase(e);\n\n\t\tMenuExitSliderEdit();\n\t\tsliderScroll->FitInside();\n\t\tactiveSlider.clear();\n\t\tlastActiveSlider.clear();\n\t}\n\n\twxString addedMorphs;\n\tstd::unordered_set<NiShape*> addedShapes;\n\n\tfor (auto& morph : morphs) {\n\t\tauto shape = project->GetWorkNif()->FindBlockByName<NiShape>(morph.first);\n\t\tif (!shape)\n\t\t\tcontinue;\n\n\t\t// check if the shape is selected\n\t\tauto selectedSliders = options.selectedShapesToSliders.find(shape->name.get());\n\t\tif (selectedSliders == options.selectedShapesToSliders.end())\n\t\t\tcontinue;\n\n\t\taddedMorphs += morph.first + \"\\n\";\n\t\tfor (auto& morphData : morph.second) {\n\t\t\t// check the morph is selected for the specific shape\n\t\t\tif (selectedSliders->second.find(morphData->name) == selectedSliders->second.end())\n\t\t\t\tcontinue;\n\n\t\t\tif (!project->ValidSlider(morphData->name)) {\n\t\t\t\tproject->AddEmptySlider(morphData->name);\n\t\t\t\tcreateSliderGUI(morphData->name, sliderScroll, sliderScroll->GetSizer());\n\t\t\t}\n\n\t\t\tstd::unordered_map<uint16_t, Vector3> diff(morphData->offsets.begin(), morphData->offsets.end());\n\t\t\tproject->SetSliderFromDiff(morphData->name, shape, diff);\n\n\t\t\tif (morphData->type == MORPHTYPE_UV) {\n\t\t\t\tsize_t sliderIndex = 0;\n\t\t\t\tif (!project->SliderIndexFromName(morphData->name, sliderIndex))\n\t\t\t\t\tcontinue;\n\n\t\t\t\tproject->SetSliderUV(sliderIndex, true);\n\t\t\t}\n\t\t}\n\t}\n\n\tsliderScroll->FitInside();\n\tsliderScroll->Thaw();\n\n\tSetPendingChanges();\n\tApplySliders();\n\tDoFilterSliders();\n\tHighlightSliderData();\n\n\twxLogMessage(\"Added morphs for the following shapes:\\n%s\", addedMorphs);\n\twxMessageBox(wxString::Format(_(\"Added morphs for the following shapes:\\n\\n%s\"), addedMorphs), _(\"TRI Import\"));\n}\n\nvoid OutfitStudioFrame::OnSliderImportMorphsSF(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\twxString fn = wxFileSelector(_(\"Import Starfield morph.dat file\"), wxEmptyString, wxEmptyString, \".dat\", \"*.dat\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing morphs from Starfield morph file '%s'...\", fn);\n\n\tSFMorphFile morphFile;\n\tif (!morphFile.Read(fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to import Starfield morph file '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to import Starfield morph file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tif (!morphFile.FileToCacheData()) {\n\t\twxLogError(\"Failed to import Starfield morph file '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to import Starfield morph file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tmorphFile.UpdateCachedMorphData();\n\t\n\tauto shape = activeItem->GetShape();\n\n\tstd::string shapeName = shape->name.get();\n\tstd::string targetName = project->ShapeToTarget(shapeName);\n\n\tstd::unordered_map<std::string, std::unordered_map<std::string, std::string>> shapeToSliders;\n\n\tfor (auto& morphName : morphFile.GetMorphNames()) {\n\t\t// Find slider name from morph name\n\t\tauto sliderName = project->activeSet.SliderFromDataName(shapeName, morphName);\n\t\tif (sliderName.empty())\n\t\t\tsliderName = morphName;\n\n\t\tshapeToSliders[shapeName].emplace(sliderName, morphName);\n\t}\n\n\tSliderDataImportDialog import(this, project, OutfitStudioConfig);\n\tif (import.ShowModal(shapeToSliders) != wxID_OK)\n\t\treturn;\n\n\tconst auto& options = import.GetOptions();\n\n\tsliderScroll->Freeze();\n\tif (!options.mergeSliders) {\n\t\twxMessageDialog dlg(this, _(\"This will delete all loaded sliders. Are you sure?\"), _(\"Starfield Morph Import\"), wxOK | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\t\tdlg.SetOKCancelLabels(_(\"Import\"), _(\"Cancel\"));\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tsliderScroll->Thaw();\n\t\t\treturn;\n\t\t}\n\n\t\t// Deleting sliders\n\t\tstd::vector<std::string> erase;\n\t\tfor (auto& sliderPanel : sliderPanels) {\n\t\t\tsliderPanel.second->slider->SetValue(0);\n\t\t\tSetSliderValue(sliderPanel.first, 0);\n\t\t\tShowSliderEffect(sliderPanel.first, true);\n\t\t\tsliderPanel.second->slider->SetFocus();\n\t\t\tHideSliderPanel(sliderPanel.second);\n\n\t\t\terase.push_back(sliderPanel.first);\n\t\t\tproject->DeleteSlider(sliderPanel.first);\n\t\t}\n\n\t\tfor (auto& e : erase)\n\t\t\tsliderPanels.erase(e);\n\n\t\tMenuExitSliderEdit();\n\t\tsliderScroll->FitInside();\n\t\tactiveSlider.clear();\n\t\tlastActiveSlider.clear();\n\t}\n\n\t// Check if the shape is selected\n\tauto selectedSliders = options.selectedShapesToSliders.find(shapeName);\n\tif (selectedSliders == options.selectedShapesToSliders.end())\n\t\treturn;\n\n\tfor (auto& morphName : morphFile.GetMorphNames()) {\n\t\tauto& sliderNameToDisplayName = selectedSliders->second;\n\n\t\t// check the diff is selected for the specific shape\n\t\tauto sliderName = selectedSliders->second.find(morphName);\n\t\tif (sliderName == sliderNameToDisplayName.end())\n\t\t\tcontinue;\n\n\t\tif (!project->ValidSlider(sliderName->second)) {\n\t\t\tproject->AddEmptySlider(sliderName->second);\n\t\t\tcreateSliderGUI(sliderName->second, sliderScroll, sliderScroll->GetSizer());\n\t\t}\n\n\t\tauto& morphIndex = morphFile.morphNamesCacheMap[morphName];\n\t\tauto& morphOffsets = morphFile.morphOffsetsCache[morphIndex];\n\t\tproject->SetSliderFromDiff(sliderName->second, shape, morphOffsets);\n\t}\n\n\twxString addedDiffs = shapeName + \"\\n\";\n\n\tsliderScroll->FitInside();\n\tsliderScroll->Thaw();\n\n\tSetPendingChanges();\n\tApplySliders();\n\tDoFilterSliders();\n\tHighlightSliderData();\n\n\twxLogMessage(\"Added morphs for the following shapes:\\n%s\", addedDiffs);\n\twxMessageBox(wxString::Format(_(\"Added morphs for the following shapes:\\n\\n%s\"), addedDiffs), _(\"Starfield Morph Import\"));\n}\n\nvoid OutfitStudioFrame::OnSliderImportFBX(wxCommandEvent& WXUNUSED(event)) {\n#ifdef USE_FBXSDK\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to import data to!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Import .fbx file for slider calculation\"), wxEmptyString, wxEmptyString, \".fbx\", \"*.fbx\", wxFD_FILE_MUST_EXIST, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Importing slider to '%s' for shape '%s' from FBX file '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\tif (!project->SetSliderFromFBX(activeSlider, activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\twxLogError(\"Vertex count of .obj file mesh does not match currently selected shape!\");\n\t\twxMessageBox(_(\"Vertex count of .obj file mesh does not match currently selected shape!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tSetPendingChanges();\n\tApplySliders();\n\tHighlightSliderData();\n#else\n\twxMessageBox(_(\"FBX is only supported in 64-bit builds of Outfit Studio. Start \\\"OutfitStudio x64\\\" instead.\"), _(\"Info\"), wxICON_INFORMATION);\n#endif\n}\n\nvoid OutfitStudioFrame::OnSliderExportNIF(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to export data from!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (selectedItems.size() > 1) {\n\t\twxString dir = wxDirSelector(_(\"Export .nif slider data to directory\"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, this);\n\t\tif (dir.IsEmpty())\n\t\t\treturn;\n\n\t\tfor (auto& i : selectedItems) {\n\t\t\tstd::string targetFile = std::string(dir.ToUTF8()) + PathSepStr + i->GetShape()->name.get() + \"_\" + activeSlider + \".nif\";\n\t\t\twxLogMessage(\"Exporting NIF slider data of '%s' for shape '%s' to '%s'...\", activeSlider, i->GetShape()->name.get(), targetFile);\n\t\t\tproject->SaveSliderNIF(activeSlider, i->GetShape(), targetFile);\n\t\t}\n\t}\n\telse {\n\t\twxString fn = wxFileSelector(_(\"Export .nif slider data\"), wxEmptyString, wxEmptyString, \".nif\", \"*.nif\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\t\tif (fn.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting NIF slider data of '%s' for shape '%s' to '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\t\tif (project->SaveSliderNIF(activeSlider, activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\t\twxLogError(\"Failed to export NIF file '%s'!\", fn);\n\t\t\twxMessageBox(_(\"Failed to export NIF file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnSliderExportBSD(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to export data from!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (selectedItems.size() > 1) {\n\t\twxString dir = wxDirSelector(_(\"Export .bsd slider data to directory\"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, this);\n\t\tif (dir.IsEmpty())\n\t\t\treturn;\n\n\t\tfor (auto& i : selectedItems) {\n\t\t\tstd::string targetFile = std::string(dir.ToUTF8()) + PathSepStr + i->GetShape()->name.get() + \"_\" + activeSlider + \".bsd\";\n\t\t\twxLogMessage(\"Exporting BSD slider data of '%s' for shape '%s' to '%s'...\", activeSlider, i->GetShape()->name.get(), targetFile);\n\t\t\tproject->SaveSliderBSD(activeSlider, i->GetShape(), targetFile);\n\t\t}\n\t}\n\telse {\n\t\twxString fn = wxFileSelector(_(\"Export .bsd slider data\"), wxEmptyString, wxEmptyString, \".bsd\", \"*.bsd\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\t\tif (fn.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting BSD slider data of '%s' for shape '%s' to '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\t\tproject->SaveSliderBSD(activeSlider, activeItem->GetShape(), fn.ToUTF8().data());\n\t}\n\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnSliderExportOBJ(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to export data from!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (selectedItems.size() > 1) {\n\t\twxString dir = wxDirSelector(_(\"Export .obj slider data to directory\"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, this);\n\t\tif (dir.IsEmpty())\n\t\t\treturn;\n\n\t\tfor (auto& i : selectedItems) {\n\t\t\tstd::string targetFile = std::string(dir.ToUTF8()) + PathSepStr + i->GetShape()->name.get() + \"_\" + activeSlider + \".obj\";\n\t\t\twxLogMessage(\"Exporting OBJ slider data of '%s' for shape '%s' to '%s'...\", activeSlider, i->GetShape()->name.get(), targetFile);\n\t\t\tproject->SaveSliderOBJ(activeSlider, i->GetShape(), targetFile);\n\t\t}\n\t}\n\telse {\n\t\twxString fn = wxFileSelector(_(\"Export .obj slider data\"), wxEmptyString, wxEmptyString, \".obj\", \"*.obj\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\t\tif (fn.IsEmpty())\n\t\t\treturn;\n\n\t\twxLogMessage(\"Exporting OBJ slider data of '%s' for shape '%s' to '%s'...\", activeSlider, activeItem->GetShape()->name.get(), fn);\n\t\tif (project->SaveSliderOBJ(activeSlider, activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\t\twxLogError(\"Failed to export OBJ file '%s'!\", fn);\n\t\t\twxMessageBox(_(\"Failed to export OBJ file!\"), _(\"Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnSliderExportOSD(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Export .osd file\"), wxEmptyString, wxEmptyString, \".osd\", \"*.osd\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting OSD file to '%s'...\", fn);\n\tif (!project->SaveSliderData(fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to export OSD file to '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to export OSD file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n}\n\nvoid OutfitStudioFrame::OnSliderExportTRI(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString fn = wxFileSelector(_(\"Export .tri morphs\"), wxEmptyString, wxEmptyString, \".tri\", \"*.tri\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting TRI morphs to '%s'...\", fn);\n\tif (!project->WriteMorphTRI(fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to export TRI file to '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to export TRI file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n}\n\nvoid OutfitStudioFrame::OnSliderExportMorphsSF(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\twxString fn = wxFileSelector(_(\"Export Starfield morph.dat\"), wxEmptyString, wxEmptyString, \".dat\", \"*.dat\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT, this);\n\tif (fn.IsEmpty())\n\t\treturn;\n\n\twxLogMessage(\"Exporting Starfield morph.dat to '%s'...\", fn);\n\tif (!project->WriteSFMorphs(activeItem->GetShape(), fn.ToUTF8().data())) {\n\t\twxLogError(\"Failed to export Starfield morph.dat file to '%s'!\", fn);\n\t\twxMessageBox(_(\"Failed to export Starfield morph.dat file!\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n}\n\nvoid OutfitStudioFrame::OnSliderExportToOBJs(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetWorkNif()->IsValid()) {\n\t\twxMessageBox(_(\"There are no valid shapes loaded!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxString dir = wxDirSelector(_(\"Export .obj slider data to directory\"), wxEmptyString, wxDD_DEFAULT_STYLE, wxDefaultPosition, this);\n\tif (dir.IsEmpty())\n\t\treturn;\n\n\tstd::vector<std::string> sliderList;\n\tproject->GetSliderList(sliderList);\n\n\twxLogMessage(\"Exporting sliders to OBJ files in '%s'...\", dir);\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tfor (auto& slider : sliderList) {\n\t\t\tif (!project->SliderShow(slider))\n\t\t\t\tcontinue;\n\n\t\t\tstd::string targetFile = std::string(dir.ToUTF8()) + PathSepStr + shape->name.get() + \"_\" + slider + \".obj\";\n\t\t\twxLogMessage(\"Exporting OBJ slider data of '%s' for shape '%s' to '%s'...\", slider, shape->name.get(), targetFile);\n\t\t\tif (project->SaveSliderOBJ(slider, shape, targetFile, true))\n\t\t\t\twxLogError(\"Failed to export OBJ file '%s'!\", targetFile);\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnClearSlider(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tint result;\n\tif (selectedItems.size() > 1) {\n\t\twxString prompt = _(\"Are you sure you wish to clear the unmasked slider data for the selected shapes?  This action cannot be undone.\");\n\t\tresult = wxMessageBox(prompt, _(\"Confirm data erase\"), wxYES_NO | wxICON_WARNING, this);\n\t}\n\telse {\n\t\twxString prompt = wxString::Format(_(\"Are you sure you wish to clear the unmasked slider data for the shape '%s'?  This action cannot be undone.\"),\n\t\t\t\t\t\t\t\t\t\t   activeItem->GetShape()->name.get());\n\t\tresult = wxMessageBox(prompt, _(\"Confirm data erase\"), wxYES_NO | wxICON_WARNING, this);\n\t}\n\n\tif (result != wxYES)\n\t\treturn;\n\n\tauto clearSlider = [&](const std::string& sliderName) {\n\t\tstd::unordered_map<uint16_t, float> mask;\n\t\tfor (auto& i : selectedItems) {\n\t\t\tmask.clear();\n\t\t\tglView->GetShapeMask(mask, i->GetShape()->name.get());\n\t\t\tif (mask.size() > 0)\n\t\t\t\tproject->ClearUnmaskedDiff(i->GetShape(), sliderName, &mask);\n\t\t\telse\n\t\t\t\tproject->ClearSlider(i->GetShape(), sliderName);\n\t\t}\n\t};\n\n\tif (!bEditSlider) {\n\t\twxLogMessage(\"Clearing slider data of the checked sliders for the selected shapes.\");\n\t\tfor (auto& sliderPanel : sliderPanels)\n\t\t\tif (sliderPanel.second->sliderCheck->Get3StateValue() == wxCheckBoxState::wxCHK_CHECKED)\n\t\t\t\tclearSlider(sliderPanel.first);\n\t}\n\telse {\n\t\twxLogMessage(\"Clearing slider data of '%s' for the selected shapes.\", activeSlider);\n\t\tclearSlider(activeSlider);\n\t}\n\n\tSetPendingChanges();\n\tApplySliders();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::OnNewSlider(wxCommandEvent& WXUNUSED(event)) {\n\tNewSlider();\n}\n\nvoid OutfitStudioFrame::OnNewZapSlider(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tstd::string baseName = \"New Zap\";\n\n\tint count = 1;\n\tstd::string fillName = baseName;\n\n\twhile (project->ValidSlider(fillName))\n\t\tfillName = wxString::Format(\"%s %d\", baseName, ++count).ToUTF8();\n\n\tstd::string sliderName;\n\tdo {\n\t\tsliderName = wxGetTextFromUser(_(\"Enter a name for the new zap:\"), _(\"Create New Zap\"), fillName, this).ToUTF8();\n\t\tif (sliderName.empty())\n\t\t\treturn;\n\t} while (project->ValidSlider(sliderName));\n\n\twxLogMessage(\"Creating new zap '%s'.\", sliderName);\n\n\tstd::unordered_map<uint16_t, float> unmasked;\n\tfor (auto& i : selectedItems) {\n\t\tunmasked.clear();\n\t\tglView->GetShapeUnmasked(unmasked, i->GetShape()->name.get());\n\t\tproject->AddZapSlider(sliderName, unmasked, i->GetShape());\n\t}\n\n\tcreateSliderGUI(sliderName, sliderScroll, sliderScroll->GetSizer());\n\n\tsliderScroll->FitInside();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnNewCombinedSlider(wxCommandEvent& WXUNUSED(event)) {\n\tstd::string baseName = \"New Slider\";\n\n\tint count = 1;\n\tstd::string fillName = baseName;\n\n\twhile (project->ValidSlider(fillName))\n\t\tfillName = wxString::Format(\"%s %d\", baseName, ++count).ToUTF8();\n\n\tstd::string sliderName;\n\tdo {\n\t\tsliderName = wxGetTextFromUser(_(\"Enter a name for the new slider:\"), _(\"Create New Slider\"), fillName, this).ToUTF8();\n\t\tif (sliderName.empty())\n\t\t\treturn;\n\t} while (project->ValidSlider(sliderName));\n\n\twxLogMessage(\"Creating new combined slider '%s'.\", sliderName);\n\n\tcreateSliderGUI(sliderName, sliderScroll, sliderScroll->GetSizer());\n\n\tproject->AddCombinedSlider(sliderName);\n\tsliderScroll->FitInside();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnSliderClone(wxCommandEvent& WXUNUSED(event)) {\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to clone!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxLogMessage(\"Cloning slider '%s'.\", activeSlider);\n\n\tstd::string baseName = \"Cloned Slider\";\n\n\tint count = 1;\n\tstd::string fillName = baseName;\n\n\twhile (project->ValidSlider(fillName))\n\t\tfillName = wxString::Format(\"%s %d\", baseName, ++count).ToUTF8();\n\n\tstd::string sliderName;\n\tdo {\n\t\tsliderName = wxGetTextFromUser(_(\"Enter a name for the cloned slider:\"), _(\"Clone Slider\"), fillName, this).ToUTF8();\n\t\tif (sliderName.empty())\n\t\t\treturn;\n\t} while (project->ValidSlider(sliderName));\n\n\twxLogMessage(\"Creating cloned slider '%s'.\", sliderName);\n\n\tproject->CloneSlider(activeSlider, sliderName);\n\tcreateSliderGUI(sliderName, sliderScroll, sliderScroll->GetSizer());\n\n\tsliderScroll->FitInside();\n\tSetPendingChanges();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::OnSliderNegate(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to negate!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxLogMessage(\"Negating slider '%s' for the selected shapes.\", activeSlider);\n\tfor (auto& i : selectedItems)\n\t\tproject->NegateSlider(activeSlider, i->GetShape());\n\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnMaskAffected(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to create a mask from!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\twxLogMessage(\"Creating mask for affected vertices of the slider '%s'.\", activeSlider);\n\tfor (auto& i : selectedItems)\n\t\tproject->MaskAffected(activeSlider, i->GetShape());\n}\n\nvoid OutfitStudioFrame::OnDeleteSlider(wxCommandEvent& WXUNUSED(event)) {\n\twxString prompt = _(\"Are you sure you wish to delete the selected slider(s)?\");\n\tint result = wxMessageBox(prompt, _(\"Confirm slider delete\"), wxYES_NO | wxICON_WARNING, this);\n\tif (result != wxYES)\n\t\treturn;\n\n\tDeleteSliders();\n}\n\nvoid OutfitStudioFrame::DeleteSliders(bool keepSliders, bool keepZaps) {\n\tif (keepSliders && keepZaps)\n\t\treturn;\n\n\tauto deleteSlider = [&](const std::string& sliderName) {\n\t\twxSliderPanel* sliderPanel = sliderPanels[sliderName];\n\t\tsliderPanel->slider->SetValue(0);\n\t\tSetSliderValue(sliderName, 0);\n\t\tShowSliderEffect(sliderName, true);\n\t\tsliderPanel->slider->SetFocus();\n\t\tHideSliderPanel(sliderPanel);\n\n\t\tsliderScroll->FitInside();\n\t\tproject->DeleteSlider(sliderName);\n\t};\n\n\tif (!bEditSlider) {\n\t\tfor (auto it = sliderPanels.begin(); it != sliderPanels.end();) {\n\t\t\tif (it->second->sliderCheck->Get3StateValue() == wxCheckBoxState::wxCHK_CHECKED) {\n\t\t\t\tif ((keepZaps && project->activeSet[it->first].bZap) || (keepSliders && !project->activeSet[it->first].bZap)) {\n\t\t\t\t\t++it;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tdeleteSlider(it->first);\n\t\t\t\tit = sliderPanels.erase(it);\n\t\t\t}\n\t\t\telse\n\t\t\t\t++it;\n\t\t}\n\t}\n\telse {\n\t\twxLogMessage(\"Deleting slider '%s'.\", activeSlider);\n\n\t\tdeleteSlider(activeSlider);\n\t\tsliderPanels.erase(activeSlider);\n\n\t\tMenuExitSliderEdit();\n\t\tactiveSlider.clear();\n\t\tlastActiveSlider.clear();\n\t\tbEditSlider = false;\n\t}\n\n\tSetPendingChanges();\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::ShowSliderProperties(const std::string& sliderName) {\n\tsize_t curSlider = 0;\n\tif (!project->SliderIndexFromName(sliderName, curSlider))\n\t\treturn;\n\n\tCloseBrushSettings();\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgSliderProp\")) {\n\t\twxTextCtrl* edSliderName = XRCCTRL(dlg, \"edSliderName\", wxTextCtrl);\n\t\twxStaticText* lbValLo = XRCCTRL(dlg, \"lbValLo\", wxStaticText);\n\t\twxStaticText* lbValHi = XRCCTRL(dlg, \"lbValHi\", wxStaticText);\n\t\twxTextCtrl* edValLo = XRCCTRL(dlg, \"edValLo\", wxTextCtrl);\n\t\twxTextCtrl* edValHi = XRCCTRL(dlg, \"edValHi\", wxTextCtrl);\n\t\twxCheckBox* cbValZapped = XRCCTRL(dlg, \"cbValZapped\", wxCheckBox);\n\t\twxCheckBox* chkHidden = XRCCTRL(dlg, \"chkHidden\", wxCheckBox);\n\t\twxCheckBox* chkInvert = XRCCTRL(dlg, \"chkInvert\", wxCheckBox);\n\t\twxCheckBox* chkZap = XRCCTRL(dlg, \"chkZap\", wxCheckBox);\n\t\twxCheckBox* chkUV = XRCCTRL(dlg, \"chkUV\", wxCheckBox);\n\t\twxCheckListBox* zapToggleList = XRCCTRL(dlg, \"zapToggleList\", wxCheckListBox);\n\n\t\tlong loVal = (int)(project->SliderDefault(curSlider, false));\n\t\tlong hiVal = (int)(project->SliderDefault(curSlider, true));\n\n\t\tedSliderName->SetValue(wxString::FromUTF8(activeSlider));\n\t\tedValLo->SetValue(wxString::Format(\"%d\", loVal));\n\t\tedValHi->SetValue(wxString::Format(\"%d\", hiVal));\n\n\t\tif (project->SliderHidden(curSlider))\n\t\t\tchkHidden->SetValue(true);\n\n\t\tif (project->SliderInvert(curSlider))\n\t\t\tchkInvert->SetValue(true);\n\n\t\tif (project->SliderUV(curSlider))\n\t\t\tchkUV->SetValue(true);\n\n\t\tif (project->SliderZap(curSlider)) {\n\t\t\tlbValLo->Hide();\n\t\t\tlbValHi->Hide();\n\t\t\tedValLo->Hide();\n\t\t\tedValHi->Hide();\n\t\t\tcbValZapped->Show();\n\n\t\t\tchkZap->SetValue(true);\n\t\t\tzapToggleList->Enable();\n\n\t\t\tfor (size_t i = 0; i < project->SliderCount(); i++)\n\t\t\t\tif (i != curSlider && (project->SliderZap(i) || project->SliderHidden(i)))\n\t\t\t\t\tzapToggleList->Append(wxString::FromUTF8(project->GetSliderName(i)));\n\n\t\t\tfor (auto& s : project->SliderZapToggles(curSlider)) {\n\t\t\t\tint stringId = zapToggleList->FindString(s, true);\n\t\t\t\tif (stringId != wxNOT_FOUND)\n\t\t\t\t\tzapToggleList->Check(stringId);\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tcbValZapped->Hide();\n\n\t\t\tif (!project->mGenWeights) {\n\t\t\t\tlbValLo->Hide();\n\t\t\t\tedValLo->Hide();\n\t\t\t\tlbValHi->SetLabel(_(\"Default\"));\n\t\t\t}\n\t\t}\n\n\t\tif (hiVal > 0 || loVal > 0)\n\t\t\tcbValZapped->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED);\n\t\telse\n\t\t\tcbValZapped->Set3StateValue(wxCheckBoxState::wxCHK_UNCHECKED);\n\n\t\tchkZap->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& event) {\n\t\t\tbool checked = event.IsChecked();\n\n\t\t\tlbValLo->Show(!checked);\n\t\t\tlbValHi->Show(!checked);\n\t\t\tedValLo->Show(!checked);\n\t\t\tedValHi->Show(!checked);\n\t\t\tcbValZapped->Show(checked);\n\t\t\tzapToggleList->Enable(checked);\n\n\t\t\tdlg.Layout();\n\t\t});\n\n\t\tXRCCTRL(dlg, \"wxID_CANCEL\", wxButton)->SetFocus();\n\n\t\tif (dlg.ShowModal() == wxID_OK) {\n\t\t\tif (chkZap->IsChecked()) {\n\t\t\t\tif (cbValZapped->IsChecked()) {\n\t\t\t\t\tloVal = 100;\n\t\t\t\t\thiVal = 100;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tloVal = 0;\n\t\t\t\t\thiVal = 0;\n\t\t\t\t}\n\n\t\t\t\twxArrayString zapToggles;\n\t\t\t\twxArrayInt toggled;\n\t\t\t\tzapToggleList->GetCheckedItems(toggled);\n\t\t\t\tfor (auto& i : toggled)\n\t\t\t\t\tzapToggles.Add(zapToggleList->GetString(i));\n\n\t\t\t\tproject->SetSliderZapToggles(curSlider, zapToggles);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tedValLo->GetValue().ToLong(&loVal);\n\t\t\t\tedValHi->GetValue().ToLong(&hiVal);\n\t\t\t}\n\n\t\t\tproject->SetSliderZap(curSlider, chkZap->GetValue());\n\t\t\tproject->SetSliderInvert(curSlider, chkInvert->GetValue());\n\t\t\tproject->SetSliderHidden(curSlider, chkHidden->GetValue());\n\t\t\tproject->SetSliderUV(curSlider, chkUV->GetValue());\n\t\t\tproject->SetSliderDefault(curSlider, loVal, false);\n\t\t\tproject->SetSliderDefault(curSlider, hiVal, true);\n\n\t\t\tstd::string newSliderName{edSliderName->GetValue().ToUTF8()};\n\t\t\tif (sliderName != newSliderName && !project->ValidSlider(newSliderName)) {\n\t\t\t\tproject->SetSliderName(curSlider, newSliderName);\n\t\t\t\twxSliderPanel* d = sliderPanels[sliderName];\n\t\t\t\tsliderPanels[newSliderName] = d;\n\t\t\t\tsliderPanels.erase(sliderName);\n\n\t\t\t\twxString sn = wxString::FromUTF8(newSliderName);\n\t\t\t\td->slider->SetName(sn + \"|slider\");\n\t\t\t\td->sliderName->SetName(sn + \"|lbl\");\n\t\t\t\td->btnSliderEdit->SetName(sn + \"|btn\");\n\t\t\t\td->btnSliderProp->SetName(sn + \"|btnSliderProp\");\n\t\t\t\td->btnMinus->SetName(sn + \"|btnMinus\");\n\t\t\t\td->btnPlus->SetName(sn + \"|btnPlus\");\n\t\t\t\td->sliderCheck->SetName(sn + \"|check\");\n\t\t\t\td->sliderReadout->SetName(sn + \"|readout\");\n\t\t\t\td->sliderName->SetLabel(sn);\n\n\t\t\t\tif (sliderName == activeSlider)\n\t\t\t\t\tactiveSlider = std::move(newSliderName);\n\t\t\t}\n\n\t\t\tSetPendingChanges();\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnSliderProperties(wxCommandEvent& WXUNUSED(event)) {\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"There is no slider in edit mode to show properties for!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tShowSliderProperties(activeSlider);\n}\n\nbool OutfitStudioFrame::ShowClippingFixStrength(float& outStrength) {\n\tint strengthPct = 50;\n\n\twxDialog dlg(this, wxID_ANY, _(\"Fix Clipping\"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* label = new wxStaticText(&dlg, wxID_ANY, wxString::Format(_(\"Strength: %d\"), strengthPct));\n\tauto* slider = new wxSlider(&dlg, wxID_ANY, strengthPct, 1, 100);\n\n\tslider->Bind(wxEVT_SLIDER, [&](wxCommandEvent&) {\n\t\tstrengthPct = slider->GetValue();\n\t\tlabel->SetLabel(wxString::Format(_(\"Strength: %d\"), strengthPct));\n\t});\n\n\tsizer->Add(label, 0, wxALL, 10);\n\tsizer->Add(slider, 0, wxEXPAND | wxLEFT | wxRIGHT, 10);\n\tsizer->Add(dlg.CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxALL | wxEXPAND, 10);\n\tdlg.SetSizerAndFit(sizer);\n\tdlg.CenterOnParent();\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn false;\n\n\toutStrength = strengthPct / 100.0f;\n\treturn true;\n}\n\nvoid OutfitStudioFrame::FixClippingForShape(const std::vector<Vector3>& bodyVerts,\n\t\t\t\t\t\t\t\t\t\t\tconst std::vector<Triangle>& bodyTris,\n\t\t\t\t\t\t\t\t\t\t\tNiShape* shape,\n\t\t\t\t\t\t\t\t\t\t\tconst std::vector<Vector3>& outfitVerts,\n\t\t\t\t\t\t\t\t\t\t\tconst ClippingFixOptions& options,\n\t\t\t\t\t\t\t\t\t\t\tUndoStateProject* usp,\n\t\t\t\t\t\t\t\t\t\t\tconst std::unordered_set<uint16_t>* allowedVerts) {\n\tstd::vector<Triangle> outfitTris;\n\tshape->GetTriangles(outfitTris);\n\n\tstd::vector<Vector3> fixedVerts = outfitVerts;\n\tClippingFixer::FixClipping(bodyVerts, bodyTris, fixedVerts, outfitTris, options);\n\n\tUndoStateShape uss;\n\tuss.shapeName = shape->name.get();\n\n\tfor (size_t i = 0; i < outfitVerts.size(); i++) {\n\t\tVector3 diff = fixedVerts[i] - outfitVerts[i];\n\t\tif (diff.IsZero(true))\n\t\t\tcontinue;\n\n\t\tif (allowedVerts && allowedVerts->find(static_cast<uint16_t>(i)) == allowedVerts->end())\n\t\t\tcontinue;\n\n\t\tuss.pointStartState[i] = Mesh::TransformPosNifToMesh(outfitVerts[i]);\n\t\tuss.pointEndState[i] = Mesh::TransformPosNifToMesh(fixedVerts[i]);\n\t}\n\n\tif (!uss.pointStartState.empty())\n\t\tusp->usss.push_back(std::move(uss));\n}\n\nvoid OutfitStudioFrame::OnSliderFixClipping(wxCommandEvent& WXUNUSED(event)) {\n\tif (!bEditSlider) {\n\t\twxMessageBox(_(\"You must be in slider edit mode to fix clipping for a slider.\"), _(\"Fix Clipping\"), wxICON_WARNING);\n\t\treturn;\n\t}\n\n\tNiShape* refShape = project->GetBaseShape();\n\tif (!refShape) {\n\t\twxMessageBox(_(\"No reference shape set.\"), _(\"Fix Clipping\"), wxICON_WARNING);\n\t\treturn;\n\t}\n\n\tfloat strength = 0.0f;\n\tif (!ShowClippingFixStrength(strength))\n\t\treturn;\n\n\tClippingFixOptions options;\n\toptions.strength = strength;\n\n\t// Get reference shape live verts (base + slider applied)\n\tstd::vector<Vector3> bodyVerts;\n\tstd::vector<Triangle> bodyTris;\n\tproject->GetLiveVerts(refShape, bodyVerts);\n\trefShape->GetTriangles(bodyTris);\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::VertexPosition;\n\n\tfor (auto& sel : selectedItems) {\n\t\tNiShape* shape = sel->GetShape();\n\t\tif (project->IsBaseShape(shape))\n\t\t\tcontinue;\n\n\t\t// Only process shapes that have a diff for the active slider\n\t\tsize_t sliderIndex = 0;\n\t\tif (!project->SliderIndexFromName(activeSlider, sliderIndex))\n\t\t\tcontinue;\n\n\t\tTargetDataDiffs* diffSet = project->GetDiffSet(project->activeSet[sliderIndex], shape);\n\t\tif (!diffSet || diffSet->empty())\n\t\t\tcontinue;\n\n\t\tstd::unordered_map<uint16_t, float> unmasked;\n\t\tglView->GetShapeUnmasked(unmasked, shape->name.get());\n\n\t\tstd::unordered_set<uint16_t> allowed;\n\t\tfor (auto& d : *diffSet) {\n\t\t\tif (unmasked.empty() || unmasked.count(d.first))\n\t\t\t\tallowed.insert(d.first);\n\t\t}\n\n\t\tif (allowed.empty())\n\t\t\tcontinue;\n\n\t\tstd::vector<Vector3> outfitVerts;\n\t\tproject->GetLiveVerts(shape, outfitVerts);\n\n\t\tFixClippingForShape(bodyVerts, bodyTris, shape, outfitVerts, options, usp, &allowed);\n\t}\n\n\tif (usp->usss.empty()) {\n\t\tglView->GetUndoHistory()->PopState();\n\t\treturn;\n\t}\n\n\tusp->sliderName = activeSlider;\n\n\tfloat sliderscale = project->SliderValue(activeSlider);\n\tif (sliderscale == 0.0)\n\t\tsliderscale = 1.0;\n\n\tusp->sliderscale = sliderscale;\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (glView->GetTransformMode())\n\t\tglView->ShowTransformTool();\n\n\tUpdateUndoTools();\n\tHighlightSliderData();\n}\n\nvoid OutfitStudioFrame::ConformSliders(NiShape* shape, const ConformOptions& options) {\n\tif (project->IsBaseShape(shape))\n\t\treturn;\n\n\tstd::string shapeName = shape->name.get();\n\twxLogMessage(\"Conforming '%s'...\", shapeName);\n\tUpdateProgress(50, _(\"Conforming: \") + shapeName);\n\n\tMesh* m = glView->GetMesh(shapeName);\n\tif (m) {\n\t\tproject->morpher.CopyMeshMask(m, shapeName);\n\t\tproject->ConformShape(shape, options);\n\t}\n\n\tUpdateProgress(99);\n}\n\nvoid OutfitStudioFrame::OnSliderConform(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetBaseShape())\n\t\treturn;\n\n\tstd::vector<NiShape*> shapes;\n\tfor (auto& i : selectedItems)\n\t\tshapes.push_back(i->GetShape());\n\n\tConformShapes(shapes);\n}\n\nvoid OutfitStudioFrame::OnSliderConformAll(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->GetBaseShape())\n\t\treturn;\n\n\tauto shapes = project->GetWorkNif()->GetShapes();\n\tConformShapes(shapes);\n}\n\nint OutfitStudioFrame::ConformShapes(std::vector<NiShape*> shapes, bool silent) {\n\tStartProgress(_(\"Conforming shapes...\"));\n\n\tConformOptions options;\n\tif (ShowConform(options, silent)) {\n\t\twxLogMessage(\"Conforming shapes...\");\n\n\t\t// Collect shown slider names before zeroing\n\t\tfor (size_t i = 0; i < project->SliderCount(); i++)\n\t\t\tif (project->SliderShow(i))\n\t\t\t\toptions.sliderNames.push_back(project->GetSliderName(i));\n\n\t\tZeroSliders();\n\n\t\tproject->InitConform();\n\n\t\tint inc = 100 / shapes.size() - 1;\n\t\tint pos = 0;\n\n\t\tfor (auto& shape : shapes) {\n\t\t\tUpdateProgress(pos * inc, _(\"Conforming: \") + shape->name.get());\n\t\t\tStartSubProgress(pos * inc, pos * inc + inc);\n\t\t\tConformSliders(shape, options);\n\t\t\tpos++;\n\t\t\tEndProgress();\n\t\t}\n\n\t\tproject->morpher.ClearProximityCache();\n\t\tproject->morpher.UnlinkRefDiffData();\n\n\t\tif (statusBar)\n\t\t\tstatusBar->SetStatusText(_(\"All shapes conformed.\"));\n\n\t\tSetPendingChanges();\n\n\t\twxLogMessage(\"All shapes conformed.\");\n\t}\n\n\tEndProgress();\n\tHighlightSliderData();\n\treturn 0;\n}\n\nbool OutfitStudioFrame::ShowConform(ConformOptions& options, bool silent) {\n\tCloseBrushSettings();\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgConforming\")) {\n\t\tXRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->Bind(wxEVT_SLIDER, [&dlg](wxCommandEvent&) {\n\t\t\tfloat changed = XRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->GetValue() / 1000.0f;\n\t\t\tXRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", changed));\n\t\t});\n\n\t\tXRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->Bind(wxEVT_TEXT, [&dlg](wxCommandEvent&) {\n\t\t\tfloat changed = atof(XRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->GetValue().c_str());\n\t\t\tXRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->SetValue(changed * 1000);\n\t\t});\n\n\t\tXRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->Bind(wxEVT_SLIDER, [&dlg](wxCommandEvent&) {\n\t\t\tint changed = XRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->GetValue();\n\t\t\tXRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->ChangeValue(wxString::Format(\"%d\", changed));\n\t\t});\n\n\t\tXRCCTRL(dlg, \"noTargetLimit\", wxCheckBox)->Bind(wxEVT_CHECKBOX, [&dlg](wxCommandEvent&) {\n\t\t\tbool noTargetLimit = XRCCTRL(dlg, \"noTargetLimit\", wxCheckBox)->IsChecked();\n\t\t\tXRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->Enable(!noTargetLimit);\n\t\t\tXRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->Enable(!noTargetLimit);\n\n\t\t\tif (noTargetLimit) {\n\t\t\t\tXRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->ChangeValue(\"5.00000\");\n\t\t\t\tXRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->SetValue(5000);\n\t\t\t}\n\t\t});\n\n\t\tXRCCTRL(dlg, \"presetDefault\", wxButton)->Bind(wxEVT_BUTTON, [&dlg](wxCommandEvent&) {\n\t\t\tXRCCTRL(dlg, \"noTargetLimit\", wxCheckBox)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"noSqueeze\", wxCheckBox)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"solidMode\", wxCheckBox)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->ChangeValue(\"10.00000\");\n\t\t\tXRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->SetValue(10000);\n\t\t\tXRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->Enable();\n\t\t\tXRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->Enable();\n\t\t\tXRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->ChangeValue(\"10\");\n\t\t\tXRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->SetValue(10);\n\t\t});\n\n\t\tXRCCTRL(dlg, \"presetEvenMovement\", wxButton)->Bind(wxEVT_BUTTON, [&dlg](wxCommandEvent&) {\n\t\t\tXRCCTRL(dlg, \"noTargetLimit\", wxCheckBox)->SetValue(true);\n\t\t\tXRCCTRL(dlg, \"noSqueeze\", wxCheckBox)->SetValue(true);\n\t\t\tXRCCTRL(dlg, \"solidMode\", wxCheckBox)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->Disable();\n\t\t\tXRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->Disable();\n\t\t\tXRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->ChangeValue(\"5.00000\");\n\t\t\tXRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->SetValue(5000);\n\t\t});\n\n\t\tXRCCTRL(dlg, \"presetSolidObject\", wxButton)->Bind(wxEVT_BUTTON, [&dlg](wxCommandEvent&) {\n\t\t\tXRCCTRL(dlg, \"noTargetLimit\", wxCheckBox)->SetValue(true);\n\t\t\tXRCCTRL(dlg, \"noSqueeze\", wxCheckBox)->SetValue(false);\n\t\t\tXRCCTRL(dlg, \"solidMode\", wxCheckBox)->SetValue(true);\n\t\t\tXRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->Disable();\n\t\t\tXRCCTRL(dlg, \"maxResultsSlider\", wxSlider)->Disable();\n\t\t\tXRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->ChangeValue(\"10.00000\");\n\t\t\tXRCCTRL(dlg, \"proximityRadiusSlider\", wxSlider)->SetValue(10000);\n\t\t});\n\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\tif (silent || dlg.ShowModal() == wxID_OK) {\n\t\t\toptions.proximityRadius = atof(XRCCTRL(dlg, \"proximityRadiusText\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tbool noTargetLimit = XRCCTRL(dlg, \"noTargetLimit\", wxCheckBox)->IsChecked();\n\t\t\tif (!noTargetLimit)\n\t\t\t\toptions.maxResults = atol(XRCCTRL(dlg, \"maxResultsText\", wxTextCtrl)->GetValue().c_str());\n\t\t\telse\n\t\t\t\toptions.maxResults = std::numeric_limits<int>::max();\n\n\t\t\toptions.noSqueeze = XRCCTRL(dlg, \"noSqueeze\", wxCheckBox)->IsChecked();\n\t\t\toptions.solidMode = XRCCTRL(dlg, \"solidMode\", wxCheckBox)->IsChecked();\n\t\t\toptions.axisX = XRCCTRL(dlg, \"axisX\", wxCheckBox)->IsChecked();\n\t\t\toptions.axisY = XRCCTRL(dlg, \"axisY\", wxCheckBox)->IsChecked();\n\t\t\toptions.axisZ = XRCCTRL(dlg, \"axisZ\", wxCheckBox)->IsChecked();\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\nvoid OutfitStudioFrame::OnInvertUV(wxCommandEvent& event) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tbool invertX = (event.GetId() == XRCID(\"uvInvertX\"));\n\tbool invertY = (event.GetId() == XRCID(\"uvInvertY\"));\n\n\tfor (auto& i : selectedItems) {\n\t\tproject->GetWorkNif()->InvertUVsForShape(i->GetShape(), invertX, invertY);\n\t}\n\n\tRefreshGUIFromProj();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnMirrorShape(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!CheckEditableState())\n\t\treturn;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgMirrorShape\")) {\n\t\tbool previewMirror = false;\n\n\t\tauto updateMirrorPreview = [&]() {\n\t\t\tif (previewMirror) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true, false);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t\tpreviewMirror = false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbool mirrorAxisX = XRCCTRL(dlg, \"mirrorAxisX\", wxCheckBox)->IsChecked();\n\t\t\tbool mirrorAxisY = XRCCTRL(dlg, \"mirrorAxisY\", wxCheckBox)->IsChecked();\n\t\t\tbool mirrorAxisZ = XRCCTRL(dlg, \"mirrorAxisZ\", wxCheckBox)->IsChecked();\n\n\t\t\twxCheckBox* swapBonesX = XRCCTRL(dlg, \"swapBonesX\", wxCheckBox);\n\t\t\tif (mirrorAxisX && !swapBonesX->IsEnabled())\n\t\t\t\tswapBonesX->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED);\n\n\t\t\tswapBonesX->Enable(mirrorAxisX);\n\n\t\t\tif (mirrorAxisX || mirrorAxisY || mirrorAxisZ) {\n\t\t\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\t\t\tusp->undoType = UndoType::Mirror;\n\t\t\t\tusp->mirrorX = mirrorAxisX;\n\t\t\t\tusp->mirrorY = mirrorAxisY;\n\t\t\t\tusp->mirrorZ = mirrorAxisZ;\n\t\t\t\tusp->swapBonesX = swapBonesX->IsChecked();\n\n\t\t\t\tfor (auto& sel : selectedItems) {\n\t\t\t\t\tNiShape* shape = sel->GetShape();\n\n\t\t\t\t\tUndoStateShape uss;\n\t\t\t\t\tuss.shapeName = shape->name.get();\n\n\t\t\t\t\tusp->usss.push_back(std::move(uss));\n\t\t\t\t}\n\n\t\t\t\tglView->ApplyUndoState(usp, false);\n\n\t\t\t\tpreviewMirror = true;\n\n\t\t\t\tif (glView->GetTransformMode())\n\t\t\t\t\tglView->ShowTransformTool();\n\t\t\t}\n\t\t};\n\n\t\tauto mirrorAxisChanged = [&](wxCommandEvent&) { updateMirrorPreview(); };\n\n\t\tXRCCTRL(dlg, \"mirrorAxisX\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tXRCCTRL(dlg, \"mirrorAxisY\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tXRCCTRL(dlg, \"mirrorAxisZ\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tXRCCTRL(dlg, \"swapBonesX\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tif (previewMirror) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tUpdateUndoTools();\n\t\tSetPendingChanges();\n\t}\n}\n\nvoid OutfitStudioFrame::OnRenameShape(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tstd::string shapeName = activeItem->GetShape()->name.get();\n\tstd::string newShapeName;\n\tdo {\n\t\tstd::string result{wxGetTextFromUser(_(\"Please enter a new unique name for the shape.\"), _(\"Rename Shape\"), wxString::FromUTF8(shapeName), this).ToUTF8()};\n\t\tif (result.empty())\n\t\t\treturn;\n\n\t\tnewShapeName = std::move(result);\n\t} while (project->IsValidShape(newShapeName));\n\n\twxLogMessage(\"Renaming shape '%s' to '%s'.\", shapeName, newShapeName);\n\tproject->RenameShape(activeItem->GetShape(), newShapeName);\n\tglView->RenameShape(shapeName, newShapeName);\n\n\toutfitShapes->SetItemText(activeItem->GetId(), wxString::FromUTF8(newShapeName));\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnSetReference(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tauto shape = activeItem->GetShape();\n\tif (!project->IsBaseShape(shape))\n\t\tproject->SetBaseShape(shape);\n\telse\n\t\tproject->SetBaseShape(nullptr);\n\n\tRefreshGUIFromProj();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnEnterClose(wxKeyEvent& event) {\n\tif (event.GetKeyCode() == WXK_RETURN) {\n\t\twxDialog* parent = (wxDialog*)((wxWindow*)event.GetEventObject())->GetParent();\n\t\tif (!parent)\n\t\t\treturn;\n\n\t\tparent->Close();\n\t\tparent->SetReturnCode(wxID_OK);\n\t}\n\telse\n\t\tevent.Skip();\n}\n\nvoid OutfitStudioFrame::OnMoveShape(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!CheckEditableState())\n\t\treturn;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgMoveShape\")) {\n\t\tVector3 previewMove;\n\n\t\tauto updateMovePreview = [&]() {\n\t\t\tstd::unordered_map<uint16_t, float> mask;\n\t\t\tstd::unordered_map<uint16_t, float>* mptr = nullptr;\n\t\t\tstd::vector<Vector3> verts;\n\n\t\t\tif (!previewMove.IsZero()) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true, false);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tVector3 changed;\n\t\t\tchanged.x = atof(XRCCTRL(dlg, \"msTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\tchanged.y = atof(XRCCTRL(dlg, \"msTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\tchanged.z = atof(XRCCTRL(dlg, \"msTextZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tbool mirrorAxisX = XRCCTRL(dlg, \"mirrorAxisX\", wxCheckBox)->IsChecked();\n\t\t\tbool mirrorAxisY = XRCCTRL(dlg, \"mirrorAxisY\", wxCheckBox)->IsChecked();\n\t\t\tbool mirrorAxisZ = XRCCTRL(dlg, \"mirrorAxisZ\", wxCheckBox)->IsChecked();\n\n\t\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\t\tusp->undoType = UndoType::VertexPosition;\n\n\t\t\tfor (auto& sel : selectedItems) {\n\t\t\t\tmask.clear();\n\t\t\t\tmptr = nullptr;\n\n\t\t\t\tNiShape* shape = sel->GetShape();\n\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\tglView->GetShapeMask(mask, shape->name.get());\n\n\t\t\t\tif (!mask.empty())\n\t\t\t\t\tmptr = &mask;\n\n\t\t\t\tUndoStateShape uss;\n\t\t\t\tuss.shapeName = shape->name.get();\n\n\t\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\t\tVector3& vertPos = verts[i];\n\t\t\t\t\tVector3 diff = changed;\n\n\t\t\t\t\tif (mptr)\n\t\t\t\t\t\tdiff *= 1.0f - mask[i];\n\n\t\t\t\t\tif (diff.IsZero(true))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tif (mirrorAxisX && vertPos.x < 0.0f)\n\t\t\t\t\t\tdiff.x = -diff.x;\n\t\t\t\t\tif (mirrorAxisY && vertPos.y < 0.0f)\n\t\t\t\t\t\tdiff.y = -diff.y;\n\t\t\t\t\tif (mirrorAxisZ && vertPos.z < 0.0f)\n\t\t\t\t\t\tdiff.z = -diff.z;\n\n\t\t\t\t\tVector3 newPos = vertPos + diff;\n\t\t\t\t\tuss.pointStartState[i] = Mesh::TransformPosNifToMesh(vertPos);\n\t\t\t\t\tuss.pointEndState[i] = Mesh::TransformPosNifToMesh(newPos);\n\t\t\t\t}\n\n\t\t\t\tusp->usss.push_back(std::move(uss));\n\t\t\t}\n\n\t\t\tif (bEditSlider) {\n\t\t\t\tusp->sliderName = activeSlider;\n\n\t\t\t\tfloat sliderscale = project->SliderValue(activeSlider);\n\t\t\t\tif (sliderscale == 0.0)\n\t\t\t\t\tsliderscale = 1.0;\n\n\t\t\t\tusp->sliderscale = sliderscale;\n\t\t\t}\n\n\t\t\tglView->ApplyUndoState(usp, false);\n\n\t\t\tpreviewMove = changed;\n\n\t\t\tif (glView->GetTransformMode())\n\t\t\t\tglView->ShowTransformTool();\n\t\t};\n\n\t\tauto sliderMoved = [&](wxCommandEvent&) {\n\t\t\tVector3 slider;\n\t\t\tslider.x = XRCCTRL(dlg, \"msSliderX\", wxSlider)->GetValue() / 1000.0f;\n\t\t\tslider.y = XRCCTRL(dlg, \"msSliderY\", wxSlider)->GetValue() / 1000.0f;\n\t\t\tslider.z = XRCCTRL(dlg, \"msSliderZ\", wxSlider)->GetValue() / 1000.0f;\n\n\t\t\tXRCCTRL(dlg, \"msTextX\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", slider.x));\n\t\t\tXRCCTRL(dlg, \"msTextY\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", slider.y));\n\t\t\tXRCCTRL(dlg, \"msTextZ\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", slider.z));\n\n\t\t\tupdateMovePreview();\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent&) {\n\t\t\tVector3 changed;\n\t\t\tchanged.x = atof(XRCCTRL(dlg, \"msTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\tchanged.y = atof(XRCCTRL(dlg, \"msTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\tchanged.z = atof(XRCCTRL(dlg, \"msTextZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tXRCCTRL(dlg, \"msSliderX\", wxSlider)->SetValue(changed.x * 1000);\n\t\t\tXRCCTRL(dlg, \"msSliderY\", wxSlider)->SetValue(changed.y * 1000);\n\t\t\tXRCCTRL(dlg, \"msSliderZ\", wxSlider)->SetValue(changed.z * 1000);\n\n\t\t\tupdateMovePreview();\n\t\t};\n\n\t\tauto mirrorAxisChanged = [&](wxCommandEvent&) { updateMovePreview(); };\n\n\t\tXRCCTRL(dlg, \"msSliderX\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"msSliderY\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"msSliderZ\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\n\t\tXRCCTRL(dlg, \"msTextX\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"msTextY\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"msTextZ\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\n\t\tXRCCTRL(dlg, \"mirrorAxisX\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tXRCCTRL(dlg, \"mirrorAxisY\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tXRCCTRL(dlg, \"mirrorAxisZ\", wxCheckBox)->Bind(wxEVT_CHECKBOX, mirrorAxisChanged);\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tif (!previewMove.IsZero()) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tUpdateUndoTools();\n\t}\n}\n\nvoid OutfitStudioFrame::OnScaleShape(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!CheckEditableState())\n\t\treturn;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgScaleShape\")) {\n\t\tVector3 previewScale(1.0f, 1.0f, 1.0f);\n\n\t\tauto updateScalePreview = [&]() {\n\t\t\tstd::unordered_map<uint16_t, float> mask;\n\t\t\tstd::unordered_map<uint16_t, float>* mptr = nullptr;\n\t\t\tstd::vector<Vector3> verts;\n\n\t\t\tif (previewScale != Vector3(1.0f, 1.0f, 1.0f)) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true, false);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tVector3 scale;\n\t\t\tscale.x = atof(XRCCTRL(dlg, \"ssTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\tscale.y = atof(XRCCTRL(dlg, \"ssTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\tscale.z = atof(XRCCTRL(dlg, \"ssTextZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tif (scale.x < 0.01f)\n\t\t\t\tscale.x = 0.01f;\n\t\t\tif (scale.y < 0.01f)\n\t\t\t\tscale.y = 0.01f;\n\t\t\tif (scale.z < 0.01f)\n\t\t\t\tscale.z = 0.01f;\n\n\t\t\tVector3 origin;\n\t\t\tint originSelection = XRCCTRL(dlg, \"origin\", wxChoice)->GetCurrentSelection();\n\t\t\tif (originSelection == 1) {\n\t\t\t\t// Center of selected shape(s), respecting mask\n\t\t\t\torigin = glView->gls.GetActiveCenter();\n\t\t\t\torigin = Mesh::TransformPosMeshToNif(origin);\n\t\t\t}\n\n\t\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\t\tusp->undoType = UndoType::VertexPosition;\n\n\t\t\tfor (auto& sel : selectedItems) {\n\t\t\t\tmask.clear();\n\t\t\t\tmptr = nullptr;\n\n\t\t\t\tNiShape* shape = sel->GetShape();\n\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\tglView->GetShapeMask(mask, shape->name.get());\n\n\t\t\t\tif (!mask.empty())\n\t\t\t\t\tmptr = &mask;\n\n\t\t\t\tUndoStateShape uss;\n\t\t\t\tuss.shapeName = shape->name.get();\n\n\t\t\t\tMatrix4 xform;\n\t\t\t\txform.PushTranslate(origin);\n\t\t\t\txform.PushScale(scale.x, scale.y, scale.z);\n\t\t\t\txform.PushTranslate(origin * -1.0f);\n\n\t\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\t\tVector3& vertPos = verts[i];\n\t\t\t\t\tVector3 diff = xform * vertPos - vertPos;\n\n\t\t\t\t\tif (mptr)\n\t\t\t\t\t\tdiff *= 1.0f - mask[i];\n\n\t\t\t\t\tif (diff.IsZero(true))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tVector3 newPos = vertPos + diff;\n\t\t\t\t\tuss.pointStartState[i] = Mesh::TransformPosNifToMesh(vertPos);\n\t\t\t\t\tuss.pointEndState[i] = Mesh::TransformPosNifToMesh(newPos);\n\t\t\t\t}\n\n\t\t\t\tusp->usss.push_back(std::move(uss));\n\t\t\t}\n\n\t\t\tif (bEditSlider) {\n\t\t\t\tusp->sliderName = activeSlider;\n\n\t\t\t\tfloat sliderscale = project->SliderValue(activeSlider);\n\t\t\t\tif (sliderscale == 0.0)\n\t\t\t\t\tsliderscale = 1.0;\n\n\t\t\t\tusp->sliderscale = sliderscale;\n\t\t\t}\n\n\t\t\tglView->ApplyUndoState(usp, false);\n\n\t\t\tpreviewScale = scale;\n\n\t\t\tif (glView->GetTransformMode())\n\t\t\t\tglView->ShowTransformTool();\n\t\t};\n\n\t\tauto sliderMoved = [&](wxCommandEvent& event) {\n\t\t\tVector3 scale(1.0f, 1.0f, 1.0f);\n\n\t\t\tbool uniform = XRCCTRL(dlg, \"ssUniform\", wxCheckBox)->IsChecked();\n\t\t\tif (uniform) {\n\t\t\t\tfloat uniformValue = ((wxSlider*)event.GetEventObject())->GetValue() / 1000.0f;\n\t\t\t\tscale = Vector3(uniformValue, uniformValue, uniformValue);\n\n\t\t\t\tXRCCTRL(dlg, \"ssSliderX\", wxSlider)->SetValue(scale.x * 1000);\n\t\t\t\tXRCCTRL(dlg, \"ssSliderY\", wxSlider)->SetValue(scale.y * 1000);\n\t\t\t\tXRCCTRL(dlg, \"ssSliderZ\", wxSlider)->SetValue(scale.z * 1000);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tscale.x = XRCCTRL(dlg, \"ssSliderX\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t\tscale.y = XRCCTRL(dlg, \"ssSliderY\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t\tscale.z = XRCCTRL(dlg, \"ssSliderZ\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t}\n\n\t\t\tXRCCTRL(dlg, \"ssTextX\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.x));\n\t\t\tXRCCTRL(dlg, \"ssTextY\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.y));\n\t\t\tXRCCTRL(dlg, \"ssTextZ\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", scale.z));\n\n\t\t\tupdateScalePreview();\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent& event) {\n\t\t\tVector3 scale(1.0f, 1.0f, 1.0f);\n\n\t\t\tbool uniform = XRCCTRL(dlg, \"ssUniform\", wxCheckBox)->IsChecked();\n\t\t\tif (uniform) {\n\t\t\t\tfloat uniformValue = atof(((wxTextCtrl*)event.GetEventObject())->GetValue().c_str());\n\t\t\t\tscale.x = atof(XRCCTRL(dlg, \"ssTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tif (scale.x != uniformValue)\n\t\t\t\t\tXRCCTRL(dlg, \"ssTextX\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", uniformValue));\n\n\t\t\t\tscale.y = atof(XRCCTRL(dlg, \"ssTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tif (scale.y != uniformValue)\n\t\t\t\t\tXRCCTRL(dlg, \"ssTextY\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", uniformValue));\n\n\t\t\t\tscale.z = atof(XRCCTRL(dlg, \"ssTextZ\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tif (scale.z != uniformValue)\n\t\t\t\t\tXRCCTRL(dlg, \"ssTextZ\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", uniformValue));\n\n\t\t\t\tscale = Vector3(uniformValue, uniformValue, uniformValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tscale.x = atof(XRCCTRL(dlg, \"ssTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tscale.y = atof(XRCCTRL(dlg, \"ssTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tscale.z = atof(XRCCTRL(dlg, \"ssTextZ\", wxTextCtrl)->GetValue().c_str());\n\t\t\t}\n\n\t\t\tXRCCTRL(dlg, \"ssSliderX\", wxSlider)->SetValue(scale.x * 1000);\n\t\t\tXRCCTRL(dlg, \"ssSliderY\", wxSlider)->SetValue(scale.y * 1000);\n\t\t\tXRCCTRL(dlg, \"ssSliderZ\", wxSlider)->SetValue(scale.z * 1000);\n\n\t\t\tupdateScalePreview();\n\t\t};\n\n\t\tauto originChanged = [&](wxCommandEvent&) { updateScalePreview(); };\n\n\t\tXRCCTRL(dlg, \"ssSliderX\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"ssSliderY\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"ssSliderZ\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"ssTextX\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"ssTextY\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"ssTextZ\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"origin\", wxChoice)->Bind(wxEVT_CHOICE, originChanged);\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tif (previewScale != Vector3(1.0f, 1.0f, 1.0f)) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tUpdateUndoTools();\n\t}\n}\n\nvoid OutfitStudioFrame::OnRotateShape(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!CheckEditableState())\n\t\treturn;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgRotateShape\")) {\n\t\tVector3 previewRotation;\n\n\t\tauto updateRotationPreview = [&]() {\n\t\t\tstd::unordered_map<uint16_t, float> mask;\n\t\t\tstd::unordered_map<uint16_t, float>* mptr = nullptr;\n\t\t\tstd::vector<Vector3> verts;\n\n\t\t\tif (!previewRotation.IsZero()) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true, false);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tVector3 angle;\n\t\t\tangle.x = atof(XRCCTRL(dlg, \"rsTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\tangle.y = atof(XRCCTRL(dlg, \"rsTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\tangle.z = atof(XRCCTRL(dlg, \"rsTextZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tVector3 origin;\n\t\t\tint originSelection = XRCCTRL(dlg, \"origin\", wxChoice)->GetCurrentSelection();\n\t\t\tif (originSelection == 1) {\n\t\t\t\t// Center of selected shape(s), respecting mask\n\t\t\t\torigin = glView->gls.GetActiveCenter();\n\t\t\t\torigin = Mesh::TransformPosMeshToNif(origin);\n\t\t\t}\n\n\t\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\t\tusp->undoType = UndoType::VertexPosition;\n\n\t\t\tfor (auto& sel : selectedItems) {\n\t\t\t\tmask.clear();\n\t\t\t\tmptr = nullptr;\n\n\t\t\t\tNiShape* shape = sel->GetShape();\n\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\tglView->GetShapeMask(mask, shape->name.get());\n\n\t\t\t\tif (!mask.empty())\n\t\t\t\t\tmptr = &mask;\n\n\t\t\t\tUndoStateShape uss;\n\t\t\t\tuss.shapeName = shape->name.get();\n\n\t\t\t\tMatrix4 xform;\n\t\t\t\txform.PushTranslate(origin);\n\t\t\t\txform.PushRotate(angle.x * DEG2RAD, Vector3(1.0f, 0.0f, 0.0f));\n\t\t\t\txform.PushRotate(angle.y * DEG2RAD, Vector3(0.0f, 1.0f, 0.0f));\n\t\t\t\txform.PushRotate(angle.z * DEG2RAD, Vector3(0.0f, 0.0f, 1.0f));\n\t\t\t\txform.PushTranslate(origin * -1.0f);\n\n\t\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\t\tVector3& vertPos = verts[i];\n\t\t\t\t\tVector3 diff = xform * vertPos - vertPos;\n\n\t\t\t\t\tif (mptr)\n\t\t\t\t\t\tdiff *= 1.0f - mask[i];\n\n\t\t\t\t\tif (diff.IsZero(true))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tVector3 newPos = vertPos + diff;\n\t\t\t\t\tuss.pointStartState[i] = Mesh::TransformPosNifToMesh(vertPos);\n\t\t\t\t\tuss.pointEndState[i] = Mesh::TransformPosNifToMesh(newPos);\n\t\t\t\t}\n\n\t\t\t\tusp->usss.push_back(std::move(uss));\n\t\t\t}\n\n\t\t\tif (bEditSlider) {\n\t\t\t\tusp->sliderName = activeSlider;\n\n\t\t\t\tfloat sliderscale = project->SliderValue(activeSlider);\n\t\t\t\tif (sliderscale == 0.0)\n\t\t\t\t\tsliderscale = 1.0;\n\n\t\t\t\tusp->sliderscale = sliderscale;\n\t\t\t}\n\n\t\t\tglView->ApplyUndoState(usp, false);\n\n\t\t\tpreviewRotation = angle;\n\n\t\t\tif (glView->GetTransformMode())\n\t\t\t\tglView->ShowTransformTool();\n\t\t};\n\n\t\tauto sliderMoved = [&](wxCommandEvent&) {\n\t\t\tVector3 angle;\n\t\t\tangle.x = XRCCTRL(dlg, \"rsSliderX\", wxSlider)->GetValue() / 100.0f;\n\t\t\tangle.y = XRCCTRL(dlg, \"rsSliderY\", wxSlider)->GetValue() / 100.0f;\n\t\t\tangle.z = XRCCTRL(dlg, \"rsSliderZ\", wxSlider)->GetValue() / 100.0f;\n\n\t\t\tXRCCTRL(dlg, \"rsTextX\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.4f\", angle.x));\n\t\t\tXRCCTRL(dlg, \"rsTextY\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.4f\", angle.y));\n\t\t\tXRCCTRL(dlg, \"rsTextZ\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.4f\", angle.z));\n\n\t\t\tupdateRotationPreview();\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent&) {\n\t\t\tVector3 angle;\n\t\t\tangle.x = atof(XRCCTRL(dlg, \"rsTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\tangle.y = atof(XRCCTRL(dlg, \"rsTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\tangle.z = atof(XRCCTRL(dlg, \"rsTextZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tXRCCTRL(dlg, \"rsSliderX\", wxSlider)->SetValue(angle.x * 100);\n\t\t\tXRCCTRL(dlg, \"rsSliderY\", wxSlider)->SetValue(angle.y * 100);\n\t\t\tXRCCTRL(dlg, \"rsSliderZ\", wxSlider)->SetValue(angle.z * 100);\n\n\t\t\tupdateRotationPreview();\n\t\t};\n\n\t\tauto originChanged = [&](wxCommandEvent&) { updateRotationPreview(); };\n\n\t\tXRCCTRL(dlg, \"rsSliderX\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"rsSliderY\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"rsSliderZ\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"rsTextX\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"rsTextY\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"rsTextZ\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"origin\", wxChoice)->Bind(wxEVT_CHOICE, originChanged);\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tif (!previewRotation.IsZero()) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tUpdateUndoTools();\n\t}\n}\n\nvoid OutfitStudioFrame::OnInflateShape(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!CheckEditableState())\n\t\treturn;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgInflateShape\")) {\n\t\tVector3 previewInflate;\n\n\t\tauto updateInflatePreview = [&]() {\n\t\t\tstd::unordered_map<uint16_t, float> mask;\n\t\t\tstd::unordered_map<uint16_t, float>* mptr = nullptr;\n\t\t\tstd::vector<Vector3> verts;\n\n\t\t\tif (!previewInflate.IsZero()) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true, false);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tVector3 inflate;\n\t\t\tinflate.x = atof(XRCCTRL(dlg, \"isTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\tinflate.y = atof(XRCCTRL(dlg, \"isTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\tinflate.z = atof(XRCCTRL(dlg, \"isTextZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\t\tusp->undoType = UndoType::VertexPosition;\n\n\t\t\tfor (auto& sel : selectedItems) {\n\t\t\t\tmask.clear();\n\t\t\t\tmptr = nullptr;\n\n\t\t\t\tNiShape* shape = sel->GetShape();\n\n\t\t\t\tauto mesh = glView->GetMesh(shape->name.get());\n\t\t\t\tif (!mesh || !mesh->norms)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\tglView->GetShapeMask(mask, shape->name.get());\n\n\t\t\t\tif (!mesh->bGotWeldVerts)\n\t\t\t\t\tmesh->CalcWeldVerts();\n\n\t\t\t\tif (!mask.empty())\n\t\t\t\t\tmptr = &mask;\n\n\t\t\t\tUndoStateShape uss;\n\t\t\t\tuss.shapeName = shape->name.get();\n\n\t\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\t\tVector3& vertPos = verts[i];\n\t\t\t\t\tVector3 norm = Mesh::TransformDirMeshToNif(mesh->norms[i]);\n\t\t\t\t\tVector3 diff = norm.ComponentMultiply(inflate);\n\n\t\t\t\t\tif (mptr)\n\t\t\t\t\t\tdiff *= 1.0f - mask[i];\n\n\t\t\t\t\tif (diff.IsZero(true))\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tVector3 newPos = vertPos + diff;\n\t\t\t\t\tuss.pointStartState[i] = Mesh::TransformPosNifToMesh(vertPos);\n\t\t\t\t\tuss.pointEndState[i] = Mesh::TransformPosNifToMesh(newPos);\n\t\t\t\t}\n\n\t\t\t\tfor (size_t i = 0; i < verts.size(); i++) {\n\t\t\t\t\tauto pointEndStateIt = uss.pointEndState.find(i);\n\t\t\t\t\tif (pointEndStateIt != uss.pointEndState.end()) {\n\t\t\t\t\t\tmesh->DoForEachWeldedVertex(i, [&](int p) {\n\t\t\t\t\t\t\tauto pointEndStateWeldIt = uss.pointEndState.find(p);\n\t\t\t\t\t\t\tif (pointEndStateWeldIt != uss.pointEndState.end())\n\t\t\t\t\t\t\t\tpointEndStateWeldIt->second = pointEndStateIt->second;\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tusp->usss.push_back(std::move(uss));\n\t\t\t}\n\n\t\t\tif (bEditSlider) {\n\t\t\t\tusp->sliderName = activeSlider;\n\n\t\t\t\tfloat sliderscale = project->SliderValue(activeSlider);\n\t\t\t\tif (sliderscale == 0.0)\n\t\t\t\t\tsliderscale = 1.0;\n\n\t\t\t\tusp->sliderscale = sliderscale;\n\t\t\t}\n\n\t\t\tglView->ApplyUndoState(usp, false);\n\n\t\t\tpreviewInflate = inflate;\n\n\t\t\tif (glView->GetTransformMode())\n\t\t\t\tglView->ShowTransformTool();\n\t\t};\n\n\t\tauto sliderMoved = [&](wxCommandEvent& event) {\n\t\t\tVector3 inflate;\n\n\t\t\tbool uniform = XRCCTRL(dlg, \"isUniform\", wxCheckBox)->IsChecked();\n\t\t\tif (uniform) {\n\t\t\t\tfloat uniformValue = ((wxSlider*)event.GetEventObject())->GetValue() / 1000.0f;\n\t\t\t\tinflate = Vector3(uniformValue, uniformValue, uniformValue);\n\n\t\t\t\tXRCCTRL(dlg, \"isSliderX\", wxSlider)->SetValue(inflate.x * 1000);\n\t\t\t\tXRCCTRL(dlg, \"isSliderY\", wxSlider)->SetValue(inflate.y * 1000);\n\t\t\t\tXRCCTRL(dlg, \"isSliderZ\", wxSlider)->SetValue(inflate.z * 1000);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tinflate.x = XRCCTRL(dlg, \"isSliderX\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t\tinflate.y = XRCCTRL(dlg, \"isSliderY\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t\tinflate.z = XRCCTRL(dlg, \"isSliderZ\", wxSlider)->GetValue() / 1000.0f;\n\t\t\t}\n\n\t\t\tXRCCTRL(dlg, \"isTextX\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", inflate.x));\n\t\t\tXRCCTRL(dlg, \"isTextY\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", inflate.y));\n\t\t\tXRCCTRL(dlg, \"isTextZ\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", inflate.z));\n\n\t\t\tupdateInflatePreview();\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent& event) {\n\t\t\tVector3 inflate;\n\n\t\t\tbool uniform = XRCCTRL(dlg, \"isUniform\", wxCheckBox)->IsChecked();\n\t\t\tif (uniform) {\n\t\t\t\tfloat uniformValue = atof(((wxTextCtrl*)event.GetEventObject())->GetValue().c_str());\n\t\t\t\tinflate.x = atof(XRCCTRL(dlg, \"isTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tif (inflate.x != uniformValue)\n\t\t\t\t\tXRCCTRL(dlg, \"isTextX\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", uniformValue));\n\n\t\t\t\tinflate.y = atof(XRCCTRL(dlg, \"isTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tif (inflate.y != uniformValue)\n\t\t\t\t\tXRCCTRL(dlg, \"isTextY\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", uniformValue));\n\n\t\t\t\tinflate.z = atof(XRCCTRL(dlg, \"isTextZ\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tif (inflate.z != uniformValue)\n\t\t\t\t\tXRCCTRL(dlg, \"isTextZ\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", uniformValue));\n\n\t\t\t\tinflate = Vector3(uniformValue, uniformValue, uniformValue);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tinflate.x = atof(XRCCTRL(dlg, \"isTextX\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tinflate.y = atof(XRCCTRL(dlg, \"isTextY\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\tinflate.z = atof(XRCCTRL(dlg, \"isTextZ\", wxTextCtrl)->GetValue().c_str());\n\t\t\t}\n\n\t\t\tXRCCTRL(dlg, \"isSliderX\", wxSlider)->SetValue(inflate.x * 1000);\n\t\t\tXRCCTRL(dlg, \"isSliderY\", wxSlider)->SetValue(inflate.y * 1000);\n\t\t\tXRCCTRL(dlg, \"isSliderZ\", wxSlider)->SetValue(inflate.z * 1000);\n\n\t\t\tupdateInflatePreview();\n\t\t};\n\n\t\tXRCCTRL(dlg, \"isSliderX\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"isSliderY\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"isSliderZ\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"isTextX\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"isTextY\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tXRCCTRL(dlg, \"isTextZ\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tif (!previewInflate.IsZero()) {\n\t\t\t\tUndoStateProject* curState = glView->GetUndoHistory()->GetBackState();\n\t\t\t\tif (curState) {\n\t\t\t\t\tglView->ApplyUndoState(curState, true);\n\t\t\t\t\tglView->GetUndoHistory()->PopState();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tUpdateUndoTools();\n\t}\n}\n\nvoid OutfitStudioFrame::OnFixClippingShape(wxCommandEvent& event) {\n\tif (bEditSlider) {\n\t\tOnSliderFixClipping(event);\n\t\treturn;\n\t}\n\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!CheckEditableState())\n\t\treturn;\n\n\tNiShape* refShape = project->GetBaseShape();\n\tif (!refShape) {\n\t\twxMessageBox(_(\"No reference shape set.\"), _(\"Fix Clipping\"), wxICON_WARNING);\n\t\treturn;\n\t}\n\n\tfloat strength = 0.0f;\n\tif (!ShowClippingFixStrength(strength))\n\t\treturn;\n\n\tClippingFixOptions options;\n\toptions.strength = strength;\n\n\t// Get reference shape geometry (unmorphed)\n\tstd::vector<Vector3> bodyVerts;\n\tstd::vector<Triangle> bodyTris;\n\tproject->GetWorkNif()->GetVertsForShape(refShape, bodyVerts);\n\trefShape->GetTriangles(bodyTris);\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::VertexPosition;\n\n\tfor (auto& sel : selectedItems) {\n\t\tNiShape* shape = sel->GetShape();\n\t\tif (project->IsBaseShape(shape))\n\t\t\tcontinue;\n\n\t\tstd::unordered_map<uint16_t, float> unmasked;\n\t\tglView->GetShapeUnmasked(unmasked, shape->name.get());\n\n\t\tstd::unordered_set<uint16_t> allowed;\n\t\tif (!unmasked.empty())\n\t\t\tfor (auto& u : unmasked)\n\t\t\t\tallowed.insert(u.first);\n\n\t\tstd::vector<Vector3> outfitVerts;\n\t\tproject->GetWorkNif()->GetVertsForShape(shape, outfitVerts);\n\n\t\tFixClippingForShape(bodyVerts, bodyTris, shape, outfitVerts, options, usp, allowed.empty() ? nullptr : &allowed);\n\t}\n\n\tif (usp->usss.empty()) {\n\t\tglView->GetUndoHistory()->PopState();\n\t\treturn;\n\t}\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (glView->GetTransformMode())\n\t\tglView->ShowTransformTool();\n\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::OnDeleteVerts(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\t// Prepare the undo data and determine if any shapes are being deleted.\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tstd::vector<NiShape*> delShapes;\n\tfor (auto& i : selectedItems) {\n\t\tif (editUV && editUV->shape == i->GetShape())\n\t\t\teditUV->Close();\n\n\t\tstd::unordered_map<uint16_t, float> mask;\n\t\tglView->GetShapeUnmasked(mask, i->GetShape()->name.get());\n\t\tUndoStateShape uss;\n\t\tuss.shapeName = i->GetShape()->name.get();\n\t\tif (project->PrepareDeleteVerts(i->GetShape(), mask, uss))\n\t\t\tdelShapes.push_back(i->GetShape());\n\t\telse\n\t\t\tusp->usss.push_back(std::move(uss));\n\t}\n\n\t// Confirm deleting shapes; then delete them.\n\tif (!delShapes.empty()) {\n\t\tif (wxMessageBox(_(\"Are you sure you wish to delete parts of the selected shapes?\"), _(\"Confirm Delete\"), wxYES_NO) == wxNO)\n\t\t\treturn;\n\n\t\tfor (NiShape* shape : delShapes) {\n\t\t\tusp->deletedShapes.emplace_back();\n\t\t\tproject->CaptureShapeDeleteState(shape, usp->deletedShapes.back());\n\t\t\tproject->DeleteShape(shape);\n\t\t}\n\t}\n\n\t// Now do the vertex deletion\n\tstd::unordered_map<std::string, std::vector<float>> maskStash = glView->StashMasks();\n\tfor (auto& uss : usp->usss) {\n\t\tNiShape* shape = project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\tif (!shape)\n\t\t\tcontinue;\n\t\tproject->ApplyShapeMeshUndo(shape, maskStash[uss.shapeName], uss, false);\n\t}\n\n\tproject->GetWorkAnim()->CleanupBones();\n\n\tRefreshGUIFromProj(false, false);\n\tSetPendingChanges();\n\n\tglView->UnstashMasks(maskStash);\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnSeparateVerts(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\tstd::unordered_map<uint16_t, float> masked;\n\tglView->GetShapeMask(masked, activeItem->GetShape()->name.get());\n\tif (masked.empty())\n\t\treturn;\n\n\tstd::string shapeName = activeItem->GetShape()->name.get();\n\tstd::string newShapeName;\n\tdo {\n\t\tstd::string result{wxGetTextFromUser(_(\"Please enter a unique name for the new separated shape.\"), _(\"Separate Vertices...\"), wxString::FromUTF8(shapeName), this).ToUTF8()};\n\t\tif (result.empty())\n\t\t\treturn;\n\n\t\tnewShapeName = std::move(result);\n\t} while (project->IsValidShape(newShapeName));\n\n\tif (editUV && editUV->shape == activeItem->GetShape())\n\t\teditUV->Close();\n\n\tauto newShape = project->DuplicateShape(activeItem->GetShape(), newShapeName);\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.resize(2);\n\tusp->usss[0].shapeName = shapeName;\n\tusp->usss[1].shapeName = newShapeName;\n\n\tstd::unordered_map<uint16_t, float> unmasked = masked;\n\tglView->InvertMaskTris(unmasked, shapeName);\n\n\tproject->PrepareDeleteVerts(activeItem->GetShape(), masked, usp->usss[0]);\n\tproject->PrepareDeleteVerts(newShape, unmasked, usp->usss[1]);\n\n\tstd::unordered_map<std::string, std::vector<float>> maskStash = glView->StashMasks();\n\n\tproject->ApplyShapeMeshUndo(activeItem->GetShape(), maskStash[usp->usss[0].shapeName], usp->usss[0], false);\n\tproject->ApplyShapeMeshUndo(newShape, maskStash[usp->usss[1].shapeName], usp->usss[1], false);\n\n\tproject->SetTextures();\n\tRefreshGUIFromProj(false, false);\n\tSetPendingChanges();\n\n\tglView->UnstashMasks(maskStash);\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::CheckCopyGeo(wxDialog& dlg) {\n\twxStaticText* errors = XRCCTRL(dlg, \"copyGeometryErrors\", wxStaticText);\n\twxChoice* sourceChoice = XRCCTRL(dlg, \"sourceChoice\", wxChoice);\n\twxChoice* targetChoice = XRCCTRL(dlg, \"targetChoice\", wxChoice);\n\n\tstd::string source = sourceChoice->GetString(sourceChoice->GetSelection()).ToStdString();\n\tstd::string target = targetChoice->GetString(targetChoice->GetSelection()).ToStdString();\n\n\tMergeCheckErrors e;\n\tproject->CheckMerge(source, target, e);\n\tXRCCTRL(dlg, \"wxID_OK\", wxButton)->Enable(e.canMerge);\n\n\tif (e.canMerge) {\n\t\terrors->SetLabel(_(\"No errors found!\"));\n\t\tdlg.SetSize(dlg.GetBestSize());\n\t\treturn;\n\t}\n\n\twxString msg;\n\tmsg << _(\"Errors:\");\n\tif (e.shapesSame)\n\t\tmsg << \"\\n- \" << _(\"Target must be different from source.\");\n\tif (e.partitionsMismatch)\n\t\tmsg << \"\\n- \" << _(\"Partitions do not match. Make sure the amount of partitions and their slots match up.\");\n\tif (e.segmentsMismatch)\n\t\tmsg << \"\\n- \" << _(\"Segments do not match. Make sure the amount of segments, sub segments and their info as well as the segmentation file match.\");\n\tif (e.tooManyVertices)\n\t\tmsg << \"\\n- \" << _(\"Resulting shape would have too many vertices.\");\n\tif (e.tooManyTriangles)\n\t\tmsg << \"\\n- \" << _(\"Resulting shape would have too many triangles.\");\n\tif (e.shaderMismatch)\n\t\tmsg << \"\\n- \" << _(\"Shaders do not match. Make sure both shapes either have or don't have a shader and their shader type matches.\");\n\tif (e.textureMismatch)\n\t\tmsg << \"\\n- \" << _(\"Base texture doesn't match. Make sure both shapes have the same base/diffuse texture path.\");\n\tif (e.alphaPropMismatch)\n\t\tmsg << \"\\n- \" << _(\"Alpha property mismatch. Make sure both shapes either have or don't have an alpha property and their flags + threshold match.\");\n\n\terrors->SetLabel(msg);\n\tdlg.SetSize(dlg.GetBestSize());\n}\n\nvoid OutfitStudioFrame::OnCopyGeo(wxCommandEvent& WXUNUSED(event)) {\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\twxDialog dlg;\n\tif (!wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgCopyGeometry\"))\n\t\treturn;\n\n\twxChoice* sourceChoice = XRCCTRL(dlg, \"sourceChoice\", wxChoice);\n\twxChoice* targetChoice = XRCCTRL(dlg, \"targetChoice\", wxChoice);\n\tif (!sourceChoice || !targetChoice)\n\t\treturn;\n\n\tstd::string sourceShapeName;\n\tif (activeItem)\n\t\tsourceShapeName = activeItem->GetShape()->name.get();\n\n\tstd::vector<std::string> shapeList = GetShapeList();\n\tif (shapeList.size() < 2)\n\t\treturn;\n\n\tCloseBrushSettings();\n\n\tfor (const std::string& shape : shapeList) {\n\t\tsourceChoice->AppendString(shape);\n\t\ttargetChoice->AppendString(shape);\n\t\tif (shape == sourceShapeName)\n\t\t\tsourceChoice->SetSelection(sourceChoice->GetCount() - 1);\n\t}\n\n\tif (sourceChoice->GetSelection() == wxNOT_FOUND)\n\t\tsourceChoice->SetSelection(0);\n\tif (sourceChoice->GetSelection() == 0)\n\t\ttargetChoice->SetSelection(1);\n\telse\n\t\ttargetChoice->SetSelection(0);\n\n\tsourceChoice->Bind(wxEVT_CHOICE, [this, &dlg](wxCommandEvent&) { CheckCopyGeo(dlg); });\n\ttargetChoice->Bind(wxEVT_CHOICE, [this, &dlg](wxCommandEvent&) { CheckCopyGeo(dlg); });\n\tCheckCopyGeo(dlg);\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\tsourceShapeName = sourceChoice->GetString(sourceChoice->GetSelection()).ToStdString();\n\tstd::string targetShapeName = targetChoice->GetString(targetChoice->GetSelection()).ToStdString();\n\n\tNiShape* sourceShape = project->GetWorkNif()->FindBlockByName<NiShape>(sourceShapeName);\n\tif (!sourceShape)\n\t\treturn;\n\tNiShape* targetShape = project->GetWorkNif()->FindBlockByName<NiShape>(targetShapeName);\n\tif (!targetShape)\n\t\treturn;\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.resize(1);\n\tusp->usss[0].shapeName = targetShapeName;\n\n\tproject->PrepareCopyGeo(sourceShape, targetShape, usp->usss[0]);\n\n\tstd::unordered_map<std::string, std::vector<float>> maskStash = glView->StashMasks();\n\n\tproject->ApplyShapeMeshUndo(targetShape, maskStash[usp->usss[0].shapeName], usp->usss[0], false);\n\n\tif (XRCCTRL(dlg, \"checkDeleteSource\", wxCheckBox)->IsChecked())\n\t\tproject->DeleteShape(sourceShape);\n\n\tRefreshGUIFromProj(false, false);\n\tSetPendingChanges();\n\tglView->UnstashMasks(maskStash);\n\tApplySliders();\n}\n\nvoid OutfitStudioFrame::OnDupeShape(wxCommandEvent& WXUNUSED(event)) {\n\tstd::string newName;\n\twxTreeItemId subitem;\n\tif (activeItem) {\n\t\tif (!outfitRoot.IsOk()) {\n\t\t\twxMessageBox(_(\"You can only copy shapes into an outfit, and there is no outfit in the current project. Load one first!\"));\n\t\t\treturn;\n\t\t}\n\n\t\tCloseBrushSettings();\n\n\t\tstd::string shapeName = activeItem->GetShape()->name.get();\n\t\tdo {\n\t\t\tstd::string result{wxGetTextFromUser(_(\"Please enter a unique name for the duplicated shape.\"), _(\"Duplicate Shape\"), wxString::FromUTF8(shapeName), this).ToUTF8()};\n\t\t\tif (result.empty())\n\t\t\t\treturn;\n\n\t\t\tnewName = std::move(result);\n\t\t} while (project->IsValidShape(newName));\n\n\t\twxLogMessage(\"Duplicating shape '%s' as '%s'.\", shapeName, newName);\n\n\t\tauto shape = project->DuplicateShape(activeItem->GetShape(), newName);\n\t\tif (shape) {\n\t\t\tglView->AddMeshFromNif(project->GetWorkNif(), newName);\n\t\t\tUpdateMeshFromSet(shape);\n\t\t\tproject->SetTextures(shape);\n\n\t\t\tMaterialFile matFile;\n\t\t\tbool hasMatFile = project->GetShapeMaterialFile(shape, matFile);\n\t\t\tglView->SetMeshTextures(newName, project->GetShapeTextures(shape), hasMatFile, matFile);\n\n\t\t\tsubitem = outfitShapes->AppendItem(outfitRoot, wxString::FromUTF8(newName));\n\t\t\toutfitShapes->SetItemState(subitem, 0);\n\t\t\toutfitShapes->SetItemData(subitem, new ShapeItemData(shape));\n\n\t\t\toutfitShapes->UnselectAll();\n\t\t\toutfitShapes->SelectItem(subitem);\n\t\t\tSetPendingChanges();\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnRefineMesh(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tglView->gls.DeleteOverlay(\"refineErrorEdges\");\n\n\tif (bEditSlider) {\n\t\twxMessageBox(_(\"You're currently editing slider data, please exit the slider's edit mode (pencil button) and try again.\"));\n\t\treturn;\n\t}\n\n\tif (selectedItems.size() != 1) {\n\t\twxMessageBox(_(\"There is more than one shape selected.\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\t// Determine unmasked vertices\n\tNiShape* shape = selectedItems[0]->GetShape();\n\tsize_t nverts = shape->GetNumVertices();\n\tstd::unordered_map<uint16_t, float> mask;\n\tglView->GetShapeUnmasked(mask, shape->name.get());\n\tstd::vector<bool> pincs(nverts, false);\n\tfor (auto& m : mask)\n\t\tpincs[m.first] = true;\n\n\t// Count unmasked edges\n\tstd::vector<Triangle> tris;\n\tshape->GetTriangles(tris);\n\tsize_t nedges = 0;\n\tfor (Triangle& tri : tris) {\n\t\tint ntripts = pincs[tri.p1] + pincs[tri.p2] + pincs[tri.p3];\n\t\tif (ntripts == 3)\n\t\t\tnedges += 3;\n\t\telse if (ntripts == 2)\n\t\t\tnedges += 1;\n\t}\n\n\t// Determine maximum possible vertices and triangles for this Nif type\n\tauto workNif = project->GetWorkNif();\n\tif (!workNif)\n\t\treturn;\n\n\tconstexpr size_t maxVertIndex = std::numeric_limits<uint16_t>().max();\n\tsize_t maxTriIndex = std::numeric_limits<uint16_t>().max();\n\n\tif (workNif->GetHeader().GetVersion().IsFO4() || workNif->GetHeader().GetVersion().IsFO76())\n\t\tmaxTriIndex = std::numeric_limits<uint32_t>().max();\n\n\t// Check if we'll overflow the vertex or triangle arrays.\n\t// Note that the actual number of vertices added could be as low as\n\t// nedges/2; nedges is the upper bound (if every edge is welded or\n\t// boundary).\n\tif (nverts + nedges > maxVertIndex) {\n\t\twxMessageBox(_(\"The shape has reached the vertex count limit.\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tif (shape->GetNumTriangles() + nedges > maxTriIndex) {\n\t\twxMessageBox(_(\"The shape has reached the triangle count limit.\"), _(\"Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\t// Prepare list of changes\n\tUndoStateShape uss;\n\tuss.shapeName = shape->name.get();\n\tMesh* m = glView->GetMesh(shape->name.get());\n\tstd::vector<Edge> badEdges;\n\tif (!project->PrepareRefineMesh(shape, uss, pincs, m->weldVerts, false, &badEdges)) {\n\t\tif (!badEdges.empty()) {\n\t\t\tglView->gls.AddVisEdges(m, badEdges, \"refineErrorEdges\");\n\n\t\t\t// Add bad edge vertices to the mask\n\t\t\tfor (const auto& e : badEdges) {\n\t\t\t\tm->mask[e.p1] = 1.0f;\n\t\t\t\tm->mask[e.p2] = 1.0f;\n\t\t\t}\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Mask);\n\t\t}\n\n\t\twxMessageBox(_(\"Some edges have multiple triangles of the same orientation. They have been highlighted and masked. Correct the orientations before refining.\"), _(\"Error\"), wxICON_ERROR);\n\t\tglView->Render();\n\t\treturn;\n\t}\n\n\t// Push changes onto undo stack and execute.\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.push_back(std::move(uss));\n\tglView->ApplyUndoState(usp, false);\n\n\tUpdateUndoTools();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeleteShape(wxCommandEvent& WXUNUSED(event)) {\n\tif (currentTabButton == meshTabButton) {\n\t\tif (bEditSlider) {\n\t\t\twxMessageBox(_(\"Can't delete shape while in slider edit mode.  Use CTRL+Delete to delete sliders instead.\"), _(\"Error\"));\n\t\t\treturn;\n\t\t}\n\n\t\tif (!ShapeSelectionCheck())\n\t\t\treturn;\n\n\t\t// Delete shape(s) when in meshes tab\n\t\tif (wxMessageBox(_(\"Are you sure you wish to delete the selected shapes?\"), _(\"Confirm Delete\"), wxYES_NO | wxICON_WARNING) == wxNO)\n\t\t\treturn;\n\n\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\tusp->undoType = UndoType::ShapeDelete;\n\n\t\tstd::vector<ShapeItemData> selected;\n\t\tfor (auto& i : selectedItems)\n\t\t\tselected.push_back(*i);\n\n\t\tactiveItem = nullptr;\n\t\tselectedItems.clear();\n\n\t\tfor (auto& i : selected) {\n\t\t\tif (editUV && editUV->shape == i.GetShape())\n\t\t\t\teditUV->Close();\n\n\t\t\tstd::string shapeName = i.GetShape()->name.get();\n\t\t\twxLogMessage(\"Deleting shape '%s'.\", shapeName);\n\n\t\t\tusp->deletedShapes.emplace_back();\n\t\t\tproject->CaptureShapeDeleteState(i.GetShape(), usp->deletedShapes.back());\n\n\t\t\tproject->DeleteShape(i.GetShape());\n\t\t\twxTreeItemId item = i.GetId();\n\t\t\toutfitShapes->Delete(item);\n\t\t}\n\n\t\tSetPendingChanges();\n\t\tUpdateAnimationGUI();\n\t\tUpdateUndoTools();\n\t\tglView->Render();\n\t}\n\telse if (currentTabButton == boneTabButton) {\n\t\t// Delete bone(s) when in bones tab\n\t\tbool shiftDown = wxGetKeyState(WXK_SHIFT);\n\t\tbool ctrlDown = wxGetKeyState(WXK_CONTROL);\n\t\tif (shiftDown && ctrlDown) {\n\t\t\tif (wxMessageBox(_(\"Delete selected bones?  This action cannot be undone.\"), _(\"Confirm Delete\"), wxYES_NO | wxICON_WARNING) == wxNO)\n\t\t\t\treturn;\n\n\t\t\twxCommandEvent evt;\n\t\t\tOnDeleteBone(evt);\n\t\t}\n\t\telse {\n\t\t\tif (!ShapeSelectionCheck())\n\t\t\t\treturn;\n\n\t\t\tif (wxMessageBox(_(\"Delete bones from selected shape(s)?  This action cannot be undone.\"), _(\"Confirm Delete\"), wxYES_NO | wxICON_WARNING) == wxNO)\n\t\t\t\treturn;\n\n\t\t\twxCommandEvent evt;\n\t\t\tOnDeleteBoneFromSelected(evt);\n\t\t}\n\t}\n\telse if (currentTabButton == partitionTabButton) {\n\t\tif (wxMessageBox(_(\"Delete partition?  This action cannot be undone.\"), _(\"Confirm Delete\"), wxYES_NO | wxICON_WARNING) == wxNO)\n\t\t\treturn;\n\n\t\twxCommandEvent evt;\n\t\tOnDeletePartition(evt);\n\t}\n\telse if (currentTabButton == segmentTabButton) {\n\t\tif (wxMessageBox(_(\"Delete segment?  This action cannot be undone.\"), _(\"Confirm Delete\"), wxYES_NO | wxICON_WARNING) == wxNO)\n\t\t\treturn;\n\n\t\twxCommandEvent evt;\n\t\tOnDeleteSegment(evt);\n\t}\n}\n\nvoid OutfitStudioFrame::OnSetBoneSkin(wxCommandEvent& WXUNUSED(event)) {\n\tstd::string shape = activeItem->GetShape()->name.get();\n\tproject->GetWorkAnim()->RecalcXFormSkinToBone(shape, activeBone);\n\n\tglView->UpdateBones();\n\tHighlightBoneNamesWithWeights();\n\tApplyPose();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnSetBoneNode(wxCommandEvent& WXUNUSED(event)) {\n\tstd::string shape = activeItem->GetShape()->name.get();\n\tproject->GetWorkAnim()->RecalcCustomBoneXFormsFromSkin(shape, activeBone);\n\n\tglView->UpdateBones();\n\tHighlightBoneNamesWithWeights();\n\tApplyPose();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnAddBone(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tif (!wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgSkeletonBones\"))\n\t\treturn;\n\n\tCloseBrushSettings();\n\n\tdlg.SetSize(450, 470);\n\tdlg.CenterOnParent();\n\n\twxTreeCtrl* boneTree = XRCCTRL(dlg, \"boneTree\", wxTreeCtrl);\n\n\tstd::function<void(wxTreeItemId, AnimBone*)> fAddBoneChildren = [&](wxTreeItemId treeParent, AnimBone* boneParent) {\n\t\tfor (auto& cb : boneParent->children) {\n\t\t\tif (!cb->boneName.empty()) {\n\t\t\t\tauto newItem = boneTree->AppendItem(treeParent, cb->boneName);\n\t\t\t\tfAddBoneChildren(newItem, cb);\n\t\t\t\tif (cb->boneName == activeBone)\n\t\t\t\t\tboneTree->SelectItem(newItem);\n\t\t\t}\n\t\t\telse\n\t\t\t\tfAddBoneChildren(treeParent, cb);\n\t\t}\n\t};\n\n\tAnimBone* rb = AnimSkeleton::getInstance().GetRootBonePtr();\n\twxTreeItemId rt = boneTree->AddRoot(rb->boneName);\n\tfAddBoneChildren(rt, rb);\n\n\tif (dlg.ShowModal() == wxID_OK) {\n\t\twxArrayTreeItemIds sel;\n\t\tboneTree->GetSelections(sel);\n\t\tfor (size_t i = 0; i < sel.size(); i++) {\n\t\t\tstd::string bone = boneTree->GetItemText(sel[i]).ToStdString();\n\t\t\twxLogMessage(\"Adding bone '%s' to project.\", bone);\n\n\t\t\tproject->AddBoneRef(bone);\n\t\t\twxTreeItemId item = outfitBones->AppendItem(bonesRoot, bone);\n\t\t\tUpdateBoneItemState(item, bone);\n\t\t\tcXMirrorBone->AppendString(bone);\n\t\t\tcPoseBone->AppendString(bone);\n\t\t}\n\n\t\tglView->UpdateBones();\n\t\tUpdateBoneCounts();\n\t\tSetPendingChanges();\n\t\tglView->Render();\n\t}\n}\n\nvoid OutfitStudioFrame::FillParentBoneChoice(wxDialog& dlg, const std::string& selBone) {\n\twxChoice* cParentBone = XRCCTRL(dlg, \"cParentBone\", wxChoice);\n\tcParentBone->AppendString(\"(none)\");\n\n\tstd::set<std::string> boneSet;\n\tfor (auto selItem : selectedItems) {\n\t\tconst std::vector<std::string>& bones = project->GetWorkAnim()->shapeBones[selItem->GetShape()->name.get()];\n\t\tfor (const std::string& b : bones)\n\t\t\tboneSet.insert(b);\n\t}\n\n\tfor (auto& bone : boneSet) {\n\t\tcParentBone->AppendString(bone);\n\t\tif (bone == selBone)\n\t\t\tcParentBone->SetSelection(cParentBone->GetCount() - 1);\n\t}\n\n\tif (cParentBone->GetSelection() == wxNOT_FOUND) {\n\t\tif (selBone.empty()) {\n\t\t\tcParentBone->SetSelection(0);\n\t\t}\n\t\telse {\n\t\t\tcParentBone->AppendString(selBone);\n\t\t\tcParentBone->SetSelection(cParentBone->GetCount() - 1);\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::GetBoneDlgData(wxDialog& dlg, MatTransform& xform, std::string& parentBone, int& addCount) {\n\txform.translation.x = atof(XRCCTRL(dlg, \"textX\", wxTextCtrl)->GetValue().c_str());\n\txform.translation.y = atof(XRCCTRL(dlg, \"textY\", wxTextCtrl)->GetValue().c_str());\n\txform.translation.z = atof(XRCCTRL(dlg, \"textZ\", wxTextCtrl)->GetValue().c_str());\n\n\tVector3 rotvec;\n\trotvec.x = atof(XRCCTRL(dlg, \"textRX\", wxTextCtrl)->GetValue().c_str());\n\trotvec.y = atof(XRCCTRL(dlg, \"textRY\", wxTextCtrl)->GetValue().c_str());\n\trotvec.z = atof(XRCCTRL(dlg, \"textRZ\", wxTextCtrl)->GetValue().c_str());\n\txform.rotation = RotVecToMat(rotvec);\n\n\twxChoice* cParentBone = XRCCTRL(dlg, \"cParentBone\", wxChoice);\n\tint pBChoice = cParentBone->GetSelection();\n\tif (pBChoice != wxNOT_FOUND)\n\t\tparentBone = cParentBone->GetString(pBChoice).ToStdString();\n\n\tif (parentBone == \"(none)\")\n\t\tparentBone = std::string();\n\n\twxSpinCtrl* numAddCount = XRCCTRL(dlg, \"numAddCount\", wxSpinCtrl);\n\tif (numAddCount)\n\t\taddCount = numAddCount->GetValue();\n}\n\nvoid OutfitStudioFrame::OnAddCustomBone(wxCommandEvent& WXUNUSED(event)) {\n\twxDialog dlg;\n\tif (!wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgCustomBone\"))\n\t\treturn;\n\n\tCloseBrushSettings();\n\n\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\tFillParentBoneChoice(dlg, activeBone);\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\twxString bone = XRCCTRL(dlg, \"boneName\", wxTextCtrl)->GetValue();\n\tif (bone.empty()) {\n\t\twxMessageBox(_(\"No bone name was entered!\"), _(\"Error\"), wxICON_INFORMATION, this);\n\t\treturn;\n\t}\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId item = outfitBones->GetFirstChild(bonesRoot, cookie);\n\twhile (item.IsOk()) {\n\t\tif (outfitBones->GetItemText(item) == bone) {\n\t\t\twxMessageBox(wxString::Format(_(\"Bone '%s' already exists in the project!\"), bone), _(\"Error\"), wxICON_INFORMATION, this);\n\t\t\treturn;\n\t\t}\n\t\titem = outfitBones->GetNextChild(bonesRoot, cookie);\n\t}\n\n\tMatTransform xform;\n\tstd::string parentBone;\n\tint addCount = 1;\n\tGetBoneDlgData(dlg, xform, parentBone, addCount);\n\n\twxLogMessage(\"Adding custom bone '%s' to project (%d/%d).\", bone, 1, addCount);\n\tproject->AddCustomBoneRef(bone.ToStdString(), parentBone, xform);\n\n\twxTreeItemId newItem = outfitBones->AppendItem(bonesRoot, bone);\n\tUpdateBoneItemState(newItem, bone.ToStdString());\n\n\tcXMirrorBone->AppendString(bone);\n\tcPoseBone->AppendString(bone);\n\n\twxString origBone = bone;\n\tint suffixNumber = 0;\n\n\tsize_t firstDigit = origBone.find_first_of(\"0123456789\");\n\tif (firstDigit != std::string::npos) {\n\t\twxString strNumber = origBone.substr(origBone.find_first_of(\"0123456789\"));\n\t\tsuffixNumber = wxAtoi(strNumber);\n\t}\n\n\tparentBone = bone;\n\n\tfor (int i = 1; i < addCount; i++) {\n\t\tif (firstDigit != std::string::npos)\n\t\t\tbone = origBone.substr(0, firstDigit) + std::to_string(++suffixNumber);\n\t\telse\n\t\t\tbone = origBone + std::to_string(++suffixNumber);\n\n\t\twxTreeItemIdValue cookie2;\n\t\titem = outfitBones->GetFirstChild(bonesRoot, cookie2);\n\t\twhile (item.IsOk()) {\n\t\t\tif (outfitBones->GetItemText(item) == bone) {\n\t\t\t\twxMessageBox(wxString::Format(_(\"Bone '%s' already exists in the project!\"), bone), _(\"Error\"), wxICON_INFORMATION, this);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\titem = outfitBones->GetNextChild(bonesRoot, cookie2);\n\t\t}\n\n\t\twxLogMessage(\"Adding custom bone '%s' to project (%d/%d).\", bone, i, addCount);\n\t\tproject->AddCustomBoneRef(bone.ToStdString(), parentBone, xform);\n\n\t\tnewItem = outfitBones->AppendItem(bonesRoot, bone);\n\t\tUpdateBoneItemState(newItem, bone.ToStdString());\n\n\t\tcXMirrorBone->AppendString(bone);\n\t\tcPoseBone->AppendString(bone);\n\n\t\tparentBone = bone;\n\t}\n\n\tglView->UpdateBones();\n\tUpdateBoneCounts();\n\tSetPendingChanges();\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnEditBone(wxCommandEvent& WXUNUSED(event)) {\n\tAnimBone* bPtr = AnimSkeleton::getInstance().GetBonePtr(activeBone);\n\tif (!bPtr)\n\t\treturn;\n\n\twxDialog dlg;\n\tif (!wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgCustomBone\"))\n\t\treturn;\n\n\tCloseBrushSettings();\n\n\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\tif (bPtr->parent)\n\t\tFillParentBoneChoice(dlg, bPtr->parent->boneName);\n\telse\n\t\tFillParentBoneChoice(dlg);\n\n\twxTextCtrl* boneNameTC = XRCCTRL(dlg, \"boneName\", wxTextCtrl);\n\tboneNameTC->SetValue(bPtr->boneName);\n\tboneNameTC->Disable();\n\n\tVector3 rotvec = RotMatToVec(bPtr->xformToParent.rotation);\n\tXRCCTRL(dlg, \"textX\", wxTextCtrl)->SetValue(wxString() << bPtr->xformToParent.translation.x);\n\tXRCCTRL(dlg, \"textY\", wxTextCtrl)->SetValue(wxString() << bPtr->xformToParent.translation.y);\n\tXRCCTRL(dlg, \"textZ\", wxTextCtrl)->SetValue(wxString() << bPtr->xformToParent.translation.z);\n\tXRCCTRL(dlg, \"textRX\", wxTextCtrl)->SetValue(wxString() << rotvec.x);\n\tXRCCTRL(dlg, \"textRY\", wxTextCtrl)->SetValue(wxString() << rotvec.y);\n\tXRCCTRL(dlg, \"textRZ\", wxTextCtrl)->SetValue(wxString() << rotvec.z);\n\n\tXRCCTRL(dlg, \"lbAddCount\", wxStaticText)->Hide();\n\tXRCCTRL(dlg, \"numAddCount\", wxSpinCtrl)->Hide();\n\n\tif (bPtr->isStandardBone) {\n\t\tdlg.SetLabel(_(\"View Standard Bone\"));\n\t\tXRCCTRL(dlg, \"textX\", wxTextCtrl)->Disable();\n\t\tXRCCTRL(dlg, \"textY\", wxTextCtrl)->Disable();\n\t\tXRCCTRL(dlg, \"textZ\", wxTextCtrl)->Disable();\n\t\tXRCCTRL(dlg, \"textRX\", wxTextCtrl)->Disable();\n\t\tXRCCTRL(dlg, \"textRY\", wxTextCtrl)->Disable();\n\t\tXRCCTRL(dlg, \"textRZ\", wxTextCtrl)->Disable();\n\t\tXRCCTRL(dlg, \"cParentBone\", wxChoice)->Disable();\n\t\tXRCCTRL(dlg, \"wxID_OK\", wxButton)->Disable();\n\t}\n\telse {\n\t\tdlg.SetLabel(_(\"Edit Custom Bone\"));\n\t}\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\tMatTransform xform;\n\tstd::string parentBone;\n\tint addCount = 1;\n\tGetBoneDlgData(dlg, xform, parentBone, addCount);\n\n\tproject->ModifyCustomBone(bPtr, parentBone, xform);\n\tglView->UpdateBones();\n\tApplyPose();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeleteBone(wxCommandEvent& WXUNUSED(event)) {\n\twxArrayTreeItemIds selItems;\n\toutfitBones->GetSelections(selItems);\n\tfor (size_t i = 0; i < selItems.size(); i++) {\n\t\twxString boneText = outfitBones->GetItemText(selItems[i]);\n\t\twxLogMessage(\"Deleting bone '%s' from project.\", boneText);\n\n\t\tstd::string bone = boneText.ToStdString();\n\t\tproject->DeleteBone(bone);\n\t\tactiveBone.clear();\n\n\t\toutfitBones->Delete(selItems[i]);\n\t\tlastSelectedBones.erase(bone);\n\t\tlastNormalizeBones.erase(bone);\n\n\t\tint idxMirrorBone = cXMirrorBone->FindString(boneText);\n\t\tif (idxMirrorBone != wxNOT_FOUND)\n\t\t\tcXMirrorBone->Delete(idxMirrorBone);\n\n\t\tint idxPoseBone = cPoseBone->FindString(boneText);\n\t\tif (idxPoseBone != wxNOT_FOUND)\n\t\t\tcPoseBone->Delete(idxPoseBone);\n\t}\n\n\tif (cXMirrorBone->GetStringSelection().IsEmpty())\n\t\tcXMirrorBone->SetSelection(0);\n\n\tif (cPoseBone->GetStringSelection().IsEmpty())\n\t\tcPoseBone->SetSelection(wxNOT_FOUND);\n\n\tglView->UpdateBones();\n\tReselectBone();\n\tCalcAutoXMirrorBone();\n\tglView->GetUndoHistory()->ClearHistory();\n\tUpdateBoneCounts();\n\tUpdateUndoTools();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeleteBoneFromSelected(wxCommandEvent& WXUNUSED(event)) {\n\twxArrayTreeItemIds selItems;\n\toutfitBones->GetSelections(selItems);\n\tfor (size_t i = 0; i < selItems.size(); i++) {\n\t\tstd::string bone = outfitBones->GetItemText(selItems[i]).ToStdString();\n\t\twxLogMessage(\"Deleting weights of bone '%s' from selected shapes.\", bone);\n\n\t\tfor (auto& s : selectedItems)\n\t\t\tproject->GetWorkAnim()->RemoveShapeBone(s->GetShape()->name.get(), bone);\n\t}\n\n\tglView->UpdateBones();\n\tReselectBone();\n\tglView->GetUndoHistory()->ClearHistory();\n\tHighlightBoneNamesWithWeights();\n\tUpdateBoneCounts();\n\tUpdateUndoTools();\n\tSetPendingChanges();\n}\n\nbool OutfitStudioFrame::HasUnweightedCheck() {\n\tstd::vector<std::string> unweighted;\n\tif (project->HasUnweighted(&unweighted)) {\n\t\tstd::string shapesJoin = JoinStrings(unweighted, \"; \");\n\t\twxLogWarning(wxString::Format(\"Unweighted vertices found on shapes: %s\", shapesJoin));\n\n\t\tint error = wxMessageBox(wxString::Format(\"%s\\n \\n%s\",\n\t\t\t\t\t\t\t\t\t\t\t\t  _(\"The following shapes have unweighted vertices, which can cause issues. The affected vertices have been put under a mask. Do \"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\"you want to save anyway?\"),\n\t\t\t\t\t\t\t\t\t\t\t\t  shapesJoin),\n\t\t\t\t\t\t\t\t _(\"Unweighted Vertices\"),\n\t\t\t\t\t\t\t\t wxYES_NO | wxICON_WARNING,\n\t\t\t\t\t\t\t\t this);\n\t\tif (error != wxYES)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid OutfitStudioFrame::ReselectBone() {\n\twxArrayTreeItemIds selItems;\n\toutfitBones->GetSelections(selItems);\n\tif (!selItems.empty()) {\n\t\twxTreeEvent treeEvent(wxEVT_TREE_SEL_CHANGED, outfitBones, selItems.front());\n\t\tOnBoneSelect(treeEvent);\n\t}\n}\n\nvoid OutfitStudioFrame::CalcCopySkinTransOption(WeightCopyOptions& options) {\n\t// This function calculates whether the \"copy global-to-skin transform\n\t// from base shape\" checkbox should be shown and what the default value\n\t// for the \"transform-geometry\" checkbox should be\n\n\tNifFile* nif = project->GetWorkNif();\n\tNiShape* baseShape = project->GetBaseShape();\n\tif (!baseShape)\n\t\treturn;\n\n\tAnimInfo& workAnim = *project->GetWorkAnim();\n\n\tMatTransform globalToBaseShape = workAnim.GetTransformGlobalToShape(baseShape);\n\n\t// Check if any shape's CS is different from the base shape's\n\tfor (size_t i = 0; i < selectedItems.size(); i++) {\n\t\tNiShape* shape = selectedItems[i]->GetShape();\n\t\tif (shape == baseShape)\n\t\t\tcontinue;\n\n\t\tMatTransform globalToShape = workAnim.GetTransformGlobalToShape(shape);\n\t\tif (!globalToShape.IsNearlyEqualTo(globalToBaseShape)) {\n\t\t\toptions.showSkinTransOption = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!options.showSkinTransOption)\n\t\t// They're all the same, so hide the option\n\t\treturn;\n\n\toptions.doSkinTransCopy = true;\n\n\t// As a first step in calculating a good default for the transform-geometry option,\n\t// find the average vertex position of the base shape in its own skin coordinates\n\tVector3 baseAvg;\n\n\tconst std::vector<Vector3>& baseVerts = *nif->GetVertsForShape(baseShape);\n\tfor (size_t i = 0; i < baseVerts.size(); ++i)\n\t\tbaseAvg += baseVerts[i];\n\n\tif (baseVerts.size())\n\t\tbaseAvg /= static_cast<uint32_t>(baseVerts.size());\n\n\t// Now check if any shape would be better aligned by changing its global-to-skin transform\n\tfor (size_t i = 0; i < selectedItems.size(); i++) {\n\t\tNiShape* shape = selectedItems[i]->GetShape();\n\t\tif (shape == baseShape)\n\t\t\tcontinue;\n\n\t\tMatTransform globalToShape = workAnim.GetTransformGlobalToShape(shape);\n\t\tif (globalToShape.IsNearlyEqualTo(globalToBaseShape))\n\t\t\tcontinue;\n\n\t\tconst std::vector<Vector3>& verts = *nif->GetVertsForShape(shape);\n\t\tif (verts.empty())\n\t\t\tcontinue;\n\n\t\t// Calculate old average and new average.\n\t\tMatTransform shapeToGlobal = globalToShape.InverseTransform();\n\t\tMatTransform shapeToBaseShape = globalToBaseShape.ComposeTransforms(shapeToGlobal);\n\n\t\tVector3 oldAvg, newAvg;\n\t\tfor (size_t j = 0; j < verts.size(); ++j) {\n\t\t\toldAvg += shapeToBaseShape.ApplyTransform(verts[j]);\n\t\t\tnewAvg += verts[j];\n\t\t}\n\n\t\toldAvg /= static_cast<uint32_t>(verts.size());\n\t\tnewAvg /= static_cast<uint32_t>(verts.size());\n\n\t\t// Check whether old or new is closer to the base shape.\n\t\t// If new is farther away, then transforming the geometry would be a good idea\n\t\tif (newAvg.DistanceTo(baseAvg) > oldAvg.DistanceTo(baseAvg)) {\n\t\t\toptions.doTransformGeo = true;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nvoid OutfitStudioFrame::OnCopyBoneWeight(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!project->GetBaseShape()) {\n\t\twxMessageBox(_(\"There is no reference shape!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tstd::vector<NiShape*> selectedShapes;\n\tfor (auto& s : selectedItems) {\n\t\tif (auto shape = s->GetShape(); !project->IsBaseShape(shape))\n\t\t\tselectedShapes.push_back(s->GetShape());\n\t\telse\n\t\t\twxMessageBox(_(\"Sorry, you can't copy weights from the reference shape to itself. Skipping this shape.\"), _(\"Can't copy weights\"), wxICON_WARNING);\n\t}\n\tCopyBoneWeightForShapes(selectedShapes);\n}\n\nint OutfitStudioFrame::CopyBoneWeightForShapes(std::vector<NiShape*> shapes, bool silent) {\n\tCloseBrushSettings();\n\n\tWeightCopyOptions options;\n\tCalcCopySkinTransOption(options);\n\tAnimInfo& workAnim = *project->GetWorkAnim();\n\n\tWeightCopyDialog dlg(this, project, glView, poseDataCollection, lastNormalizeBones, shapes, options, silent);\n\tif (dlg.GetResult()) {\n\t\tStartProgress(_(\"Copying bone weights...\"));\n\n\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\tusp->undoType = UndoType::Weight;\n\n\t\tstd::vector<std::string> baseBones;\n\t\tif (!options.selectedBones.empty())\n\t\t\tbaseBones = options.selectedBones;\n\t\telse\n\t\t\tbaseBones = workAnim.shapeBones[project->GetBaseShape()->name.get()];\n\n\t\tstd::sort(baseBones.begin(), baseBones.end());\n\n\t\tint nCopyBones = static_cast<int>(baseBones.size());\n\t\tstd::vector<std::string> lockedBones;\n\t\tbool bSpreadWeight = false;\n\n\t\t// When copying a subset of bones, compute normalization info\n\t\tif (!options.selectedBones.empty()) {\n\t\t\tstd::unordered_set<std::string> selBones{baseBones.begin(), baseBones.end()};\n\t\t\tstd::vector<std::string> normBones, notNormBones;\n\t\t\tGetNormalizeBones(&normBones, &notNormBones);\n\n\t\t\tfor (auto& bone : normBones)\n\t\t\t\tif (!selBones.count(bone))\n\t\t\t\t\tbaseBones.push_back(bone);\n\n\t\t\tbSpreadWeight = static_cast<int>(baseBones.size()) > nCopyBones;\n\n\t\t\tif (bSpreadWeight) {\n\t\t\t\tfor (auto& bone : notNormBones)\n\t\t\t\t\tif (!selBones.count(bone))\n\t\t\t\t\t\tlockedBones.push_back(bone);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tfor (auto& bone : notNormBones)\n\t\t\t\t\tif (!selBones.count(bone))\n\t\t\t\t\t\tbaseBones.push_back(bone);\n\t\t\t}\n\t\t}\n\n\t\tstd::unordered_map<uint16_t, float> mask;\n\n\t\tconst int inc = 100 / shapes.size() - 1;\n\n\t\tfor (size_t i = 0; i < shapes.size(); i++) {\n\t\t\tNiShape* shape = shapes[i];\n\t\t\twxLogMessage(\"Copying bone weights to '%s'...\", shape->name.get());\n\t\t\tStartSubProgress(i * inc, i * inc + inc);\n\n\t\t\tif (options.doSkinTransCopy) {\n\t\t\t\tMatTransform globalToBaseShape = workAnim.GetTransformGlobalToShape(project->GetBaseShape());\n\t\t\t\tMatTransform globalToShape = workAnim.GetTransformGlobalToShape(shape);\n\n\t\t\t\tif (options.doTransformGeo && !globalToBaseShape.IsNearlyEqualTo(globalToShape)) {\n\t\t\t\t\tMatTransform shapeToBaseShape = globalToBaseShape.ComposeTransforms(globalToShape.InverseTransform());\n\t\t\t\t\tproject->ApplyTransformToShapeGeometry(shape, shapeToBaseShape);\n\t\t\t\t}\n\n\t\t\t\tworkAnim.SetTransformGlobalToShape(shape, globalToBaseShape);\n\t\t\t}\n\n\t\t\tusp->usss.resize(usp->usss.size() + 1);\n\t\t\tusp->usss.back().shapeName = shape->name.get();\n\n\t\t\tmask.clear();\n\t\t\tglView->GetShapeMask(mask, shape->name.get());\n\n\t\t\tstd::vector<std::string> mergedBones = baseBones;\n\n\t\t\t// For full copy, also add shape-specific bones not already in baseBones\n\t\t\tif (options.selectedBones.empty()) {\n\t\t\t\tstd::vector<std::string> bones = workAnim.shapeBones[shape->name.get()];\n\t\t\t\tfor (auto& b : bones)\n\t\t\t\t\tif (!std::binary_search(baseBones.begin(), baseBones.end(), b))\n\t\t\t\t\t\tmergedBones.push_back(b);\n\t\t\t}\n\n\t\t\tproject->CopyBoneWeights(shape, options.proximityRadius, options.maxResults, mask, mergedBones, nCopyBones, lockedBones, usp->usss.back(), bSpreadWeight);\n\t\t\tEndProgress();\n\t\t}\n\n\t\tif (options.doSkinTransCopy || options.doTransformGeo)\n\t\t\tRefreshGUIFromProj();\n\n\t\tActiveShapesUpdated(usp, false);\n\t\tproject->morpher.ClearProximityCache();\n\n\t\tUpdateUndoTools();\n\n\t\tworkAnim.CleanupBones();\n\t\tUpdateAnimationGUI();\n\n\t\tEndProgress();\n\t}\n\n\treturn 0;\n}\n\nvoid OutfitStudioFrame::OnTransferSelectedWeight(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tauto baseShape = project->GetBaseShape();\n\tif (!baseShape) {\n\t\twxMessageBox(_(\"There is no reference shape!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tif (project->IsBaseShape(activeItem->GetShape())) {\n\t\twxMessageBox(_(\"Sorry, you can't copy weights from the reference shape to itself.\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tint baseVertCount = project->GetVertexCount(baseShape);\n\tint workVertCount = project->GetVertexCount(activeItem->GetShape());\n\tif (baseVertCount != workVertCount) {\n\t\twxMessageBox(_(\"The vertex count of the reference and chosen shape is not the same!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tstd::vector<std::string> selectedBones = GetSelectedBones();\n\tif (selectedBones.size() < 1)\n\t\treturn;\n\n\tstd::string bonesString;\n\tfor (std::string& boneName : selectedBones)\n\t\tbonesString += \"'\" + boneName + \"' \";\n\n\twxLogMessage(\"Transferring selected bone weights to '%s' for %s...\", activeItem->GetShape()->name.get(), bonesString);\n\tStartProgress(_(\"Transferring bone weights...\"));\n\n\tstd::unordered_map<uint16_t, float> mask;\n\tglView->GetActiveMask(mask);\n\tproject->TransferSelectedWeights(activeItem->GetShape(), &mask, &selectedBones);\n\n\tUpdateAnimationGUI();\n\n\tEndProgress();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnMaskWeighted(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\n\tfor (auto& selItem : selectedItems) {\n\t\tstd::string shapeName = selItem->GetShape()->name.get();\n\t\tMesh* m = glView->GetMesh(shapeName);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tuss.pointStartState[i].x = m->mask[i];\n\t\t\tuss.pointEndState[i].x = 0.0f;\n\t\t}\n\n\t\tauto& bones = project->GetWorkAnim()->shapeBones;\n\t\tif (bones.find(shapeName) != bones.end()) {\n\t\t\tfor (auto& b : bones[shapeName]) {\n\t\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(shapeName, b);\n\t\t\t\tif (weights) {\n\t\t\t\t\tfor (auto& bw : *weights)\n\t\t\t\t\t\tif (bw.second > 0.0f)\n\t\t\t\t\t\t\tuss.pointEndState[bw.first].x = 1.0f;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tglView->GetUndoHistory()->PopState();\n\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::OnMaskBoneWeighted(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\n\tfor (auto& selItem : selectedItems) {\n\t\tstd::string shapeName = selItem->GetShape()->name.get();\n\t\tMesh* m = glView->GetMesh(shapeName);\n\t\tif (!m || !m->mask)\n\t\t\tcontinue;\n\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tuss.pointStartState[i].x = m->mask[i];\n\t\t\tuss.pointEndState[i].x = 0.0f;\n\t\t}\n\n\t\tfor (auto& b : GetSelectedBones()) {\n\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(shapeName, b);\n\t\t\tif (weights) {\n\t\t\t\tfor (auto& bw : *weights)\n\t\t\t\t\tif (bw.second > 0.0f)\n\t\t\t\t\t\tuss.pointEndState[bw.first].x = 1.0f;\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tglView->GetUndoHistory()->PopState();\n\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::OnCheckBadBones(wxCommandEvent& WXUNUSED(event)) {\n\tif (!project->CheckForBadBones())\n\t\treturn;\n\n\t// CheckForBadBones updates AnimBone transforms in-place but leaves the\n\t// NIF nodes untouched; push the fixed transforms out so every view\n\t// (node overlays, bad-bone indicator, gizmo center) is consistent.\n\tif (auto* nif = project->GetWorkNif()) {\n\t\tif (auto* workAnim = project->GetWorkAnim())\n\t\t\tworkAnim->WriteNodesToNif(nif);\n\t}\n\n\tglView->UpdateBones();\n\tglView->UpdateNodes();\n\tRefreshBoneTreeBadBoneIcons();\n\tHighlightBoneNamesWithWeights();\n\tApplyPose();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnCopySegPart(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tif (!project->GetBaseShape()) {\n\t\twxMessageBox(_(\"There is no reference shape!\"), _(\"Error\"));\n\t\treturn;\n\t}\n\n\tstd::vector<NiShape*> selectedShapes;\n\tfor (auto& s : selectedItems) {\n\t\tif (auto shape = s->GetShape(); !project->IsBaseShape(shape))\n\t\t\tselectedShapes.push_back(s->GetShape());\n\t\telse\n\t\t\twxMessageBox(_(\"Sorry, you can't copy partitions/segments from the reference shape to itself. Skipping this shape.\"), _(\"Can't copy segments/partitions\"), wxICON_WARNING);\n\t}\n\tif (selectedShapes.empty())\n\t\treturn;\n\n\tif (wxMessageBox(_(\"Triangles will be assigned to the partition/segment of the nearest triangle in the reference.  Existing partitions/segments are cleared.  This action can't be undone.\"), _(\"Copy Partitions/Segments\"), wxOK | wxCANCEL | wxICON_INFORMATION | wxOK_DEFAULT) != wxOK)\n\t\treturn;\n\n\tCopySegPartForShapes(selectedShapes);\n}\n\nint OutfitStudioFrame::CopySegPartForShapes(std::vector<NiShape*> shapes, bool silent) {\n\tint failshapes = 0;\n\n\tStartProgress(_(\"Copying segments/partitions...\"));\n\n\tconst int inc = 100 / shapes.size() - 1;\n\n\tfor (size_t i = 0; i < shapes.size(); i++) {\n\t\tNiShape* shape = shapes[i];\n\t\twxLogMessage(\"Copying segments/partitions to '%s'...\", shape->name.get());\n\t\tStartSubProgress(i * inc, i * inc + inc);\n\n\t\tint failcount = project->CopySegPart(shape);\n\t\tif (failcount && !silent)\n\t\t\twxMessageBox(wxString::Format(_(\"The partitions/segments could not be copied for '%s' because %d triangles could not be matched.\"), shape->name.get(), failcount), _(\"Error\"));\n\t\tif (failcount)\n\t\t\t++failshapes;\n\n\t\tif (!failcount) {\n\t\t\tMeshFromProj(shape);\n\n\t\t\tif (shape == activeItem->GetShape()) {\n\t\t\t\tCreateSegmentTree(shape);\n\t\t\t\tCreatePartitionTree(shape);\n\t\t\t}\n\t\t}\n\n\t\tEndProgress();\n\t}\n\n\tSetPendingChanges();\n\tUpdateUndoTools();\n\n\tEndProgress();\n\n\treturn failshapes;\n}\n\nbool OutfitStudioFrame::ShowVertexAsym(Mesh* m, const SymmetricVertices& symverts, const VertexAsymmetries& asyms, VertexAsymmetryTasks& tasks, const std::vector<bool>& selVerts, bool trize) {\n\t// This dialog has two versions, one for OnMaskSymVert and one for\n\t// OnSymVert.  trize tells us which version to do.\n\n\tCloseBrushSettings();\n\n\tint nSliders = static_cast<int>(asyms.sliders.size());\n\tint nBones = static_cast<int>(asyms.bones.size());\n\tint nUnmatched = static_cast<int>(symverts.unmatched.size());\n\n\tVertexAsymmetryStats stats;\n\tCalcVertexAsymmetryStats(symverts, asyms, selVerts, stats);\n\n\t// Initialize the portion of tasks that doesn't get initialized by\n\t// member initialization.\n\ttasks.doSliders.resize(nSliders, false);\n\ttasks.doBones.resize(nBones, false);\n\n\twxDialog dlg;\n\tif (!wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgVertexAsym\"))\n\t\treturn false;\n\n\t// Fill in static labels\n\tXRCCTRL(dlg, \"currentUnmaskedText\", wxStaticText)->SetLabel(wxString() << stats.unmaskedCount);\n\tXRCCTRL(dlg, \"unmatchedVerticesText\", wxStaticText)->SetLabel(wxString() << nUnmatched);\n\tXRCCTRL(dlg, \"posAvgText\", wxStaticText)->SetLabel(wxString() << stats.posAvg);\n\tXRCCTRL(dlg, \"positionText\", wxStaticText)->SetLabel(wxString() << stats.posCount);\n\tXRCCTRL(dlg, \"anySliderLabel\", wxStaticText)->SetLabel(wxString() << nSliders << _(\" sliders\"));\n\tXRCCTRL(dlg, \"anySliderText\", wxStaticText)->SetLabel(wxString() << stats.anySliderCount);\n\tXRCCTRL(dlg, \"anyBoneLabel\", wxStaticText)->SetLabel(wxString() << nBones << _(\" bones\"));\n\tXRCCTRL(dlg, \"anyBoneText\", wxStaticText)->SetLabel(wxString() << stats.anyBoneCount);\n\n\t// The controls we need later\n\twxCheckBox* cbUnmatched = XRCCTRL(dlg, \"checkUnmatched\", wxCheckBox);\n\twxCheckBox* cbPosition = XRCCTRL(dlg, \"checkPosition\", wxCheckBox);\n\twxCheckBox* cbAnySlider = XRCCTRL(dlg, \"checkAnySlider\", wxCheckBox);\n\twxCheckBox* cbAnyBone = XRCCTRL(dlg, \"checkAnyBone\", wxCheckBox);\n\tstd::vector<wxCheckBox*> cbSliders(nSliders, nullptr);\n\tstd::vector<wxCheckBox*> cbBones;\n\twxScrolledWindow* asymScroll = XRCCTRL(dlg, \"asymScroll\", wxScrolledWindow);\n\twxStaticText* stillUnmaskedText = XRCCTRL(dlg, \"stillUnmaskedText\", wxStaticText);\n\n\t// UpdateStillUnmasked: calculates value for the \"still unmasked\"\n\t// wxStaticText.\n\tauto UpdateStillUnmasked = [&]() {\n\t\tint stillUnmasked = 0;\n\t\tif (tasks.doUnmatched)\n\t\t\tstillUnmasked += nUnmatched;\n\t\tstd::vector<bool> doVert = CalcVertexListForAsymmetryTasks(symverts, asyms, tasks, m->nVerts);\n\t\tfor (int vi = 0; vi < m->nVerts; ++vi)\n\t\t\tif (selVerts[vi] && doVert[vi])\n\t\t\t\t++stillUnmasked;\n\t\tstillUnmaskedText->SetLabel(wxString() << stillUnmasked);\n\t};\n\n\t// UpdateChecks: update the individual slider check boxes, the any-slider\n\t// check box, and the any-bone check box.  Also calls UpdateStillUnmasked.\n\tauto UpdateChecks = [&]() {\n\t\tint sliderCount = 0;\n\t\tfor (int sai = 0; sai < nSliders; ++sai) {\n\t\t\tcbSliders[sai]->SetValue(tasks.doSliders[sai]);\n\t\t\tsliderCount += tasks.doSliders[sai];\n\t\t}\n\t\tcbAnySlider->Set3StateValue(sliderCount == nSliders ? wxCHK_CHECKED : sliderCount == 0 ? wxCHK_UNCHECKED : wxCHK_UNDETERMINED);\n\n\t\tint boneCount = 0, totalBones = 0;\n\t\tfor (int bai = 0; bai < nBones; ++bai) {\n\t\t\tif (!stats.boneCounts[bai])\n\t\t\t\tcontinue;\n\t\t\t++totalBones;\n\t\t\tboneCount += tasks.doBones[bai];\n\t\t}\n\t\tcbAnyBone->Set3StateValue(boneCount == totalBones ? wxCHK_CHECKED : boneCount == 0 ? wxCHK_UNCHECKED : wxCHK_UNDETERMINED);\n\n\t\tUpdateStillUnmasked();\n\t};\n\n\t// Checkbox event handling for the checkboxes that are not in either\n\t// of the collapsible panes.\n\tcbUnmatched->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) {\n\t\ttasks.doUnmatched = e.IsChecked();\n\t\tUpdateStillUnmasked();\n\t});\n\tcbPosition->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) {\n\t\ttasks.doPos = e.IsChecked();\n\t\tUpdateStillUnmasked();\n\t});\n\tcbAnySlider->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) {\n\t\tbool newval = e.IsChecked();\n\t\tfor (int sai = 0; sai < nSliders; ++sai)\n\t\t\ttasks.doSliders[sai] = newval;\n\t\tUpdateChecks();\n\t});\n\tcbAnyBone->Bind(wxEVT_CHECKBOX, [&](wxCommandEvent& e) {\n\t\tbool newval = e.IsChecked();\n\t\tfor (int bai = 0; bai < nBones; ++bai)\n\t\t\tif (stats.boneCounts[bai])\n\t\t\t\ttasks.doBones[bai] = newval;\n\t\tfor (size_t bci = 0; bci < cbBones.size(); ++bci)\n\t\t\tcbBones[bci]->SetValue(newval);\n\t\tUpdateChecks();\n\t});\n\n\t// Fill in Sliders collapsible pane\n\twxCollapsiblePane* slidersCollapse = XRCCTRL(dlg, \"slidersCollapse\", wxCollapsiblePane);\n\twxWindow* slidersPane = slidersCollapse->GetPane();\n\twxFlexGridSizer* slidersSz = new wxFlexGridSizer(3);\n\tslidersSz->AddGrowableCol(0, 1);\n\tfor (int sai = 0; sai < nSliders; ++sai) {\n\t\tconst auto& sa = asyms.sliders[sai];\n\t\twxCheckBox* cb = new wxCheckBox(slidersPane, wxID_ANY, sa.sliderName);\n\t\tslidersSz->Add(cb, 0, wxLEFT|wxRIGHT, 5);\n\t\tcbSliders[sai] = cb;\n\t\tslidersSz->Add(new wxStaticText(slidersPane, wxID_ANY, wxString() << stats.sliderAvgs[sai]), 0, wxRIGHT|wxALIGN_RIGHT, 20);\n\t\tslidersSz->Add(new wxStaticText(slidersPane, wxID_ANY, wxString() << stats.sliderCounts[sai]), 0, wxLEFT|wxRIGHT|wxALIGN_RIGHT, 5);\n\t\tcb->Bind(wxEVT_CHECKBOX, [&, sai](wxCommandEvent& e) {\n\t\t\ttasks.doSliders[sai] = e.IsChecked();\n\t\t\tUpdateChecks();\n\t\t});\n\t}\n\tslidersPane->SetSizerAndFit(slidersSz);\n\tslidersCollapse->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [&asymScroll](wxCollapsiblePaneEvent&) { asymScroll->FitInside(); });\n\n\t// Fill in Bones collapsible pane\n\twxCollapsiblePane* bonesCollapse = XRCCTRL(dlg, \"bonesCollapse\", wxCollapsiblePane);\n\twxWindow* bonesPane = bonesCollapse->GetPane();\n\twxFlexGridSizer* bonesSz = new wxFlexGridSizer(3);\n\tbonesSz->AddGrowableCol(0, 1);\n\tfor (int bai = 0; bai < nBones; ++bai) {\n\t\tconst auto& ba = asyms.bones[bai];\n\t\t// If a bone has no asymmetries but its mirror bone does, it's still\n\t\t// listed in asyms.bones.  But that doesn't mean we need to show it\n\t\t// to the user.\n\t\tif (!stats.boneCounts[bai])\n\t\t\tcontinue;\n\n\t\twxCheckBox* cb = new wxCheckBox(bonesPane, wxID_ANY, ba.boneName);\n\t\tbonesSz->Add(cb, 0, wxLEFT|wxRIGHT, 5);\n\t\tcbBones.push_back(cb);\n\t\tbonesSz->Add(new wxStaticText(bonesPane, wxID_ANY, wxString() << stats.boneAvgs[bai]), 0, wxRIGHT|wxALIGN_RIGHT, 20);\n\t\tbonesSz->Add(new wxStaticText(bonesPane, wxID_ANY, wxString() << stats.boneCounts[bai]), 0, wxLEFT|wxRIGHT|wxALIGN_RIGHT, 5);\n\t\tcb->Bind(wxEVT_CHECKBOX, [&, bai](wxCommandEvent& e) {\n\t\t\ttasks.doBones[bai] = e.IsChecked();\n\t\t\tUpdateChecks();\n\t\t});\n\t}\n\tbonesPane->SetSizerAndFit(bonesSz);\n\tbonesCollapse->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, [&asymScroll](wxCollapsiblePaneEvent&) { asymScroll->FitInside(); });\n\n\t// Disable irrelevant checkboxes\n\tauto DisableCheck = [](wxCheckBox* cb) {\n\t\tcb->SetValue(false);\n\t\tcb->Disable();\n\t};\n\tif (!nUnmatched)\n\t\tDisableCheck(cbUnmatched);\n\tif (!stats.posCount)\n\t\tDisableCheck(cbPosition);\n\tif (!stats.anySliderCount)\n\t\tDisableCheck(cbAnySlider);\n\tif (!stats.anyBoneCount)\n\t\tDisableCheck(cbAnyBone);\n\n\t// Customize the dialog for OnSymVert\n\tif (trize) {\n\t\tdlg.SetTitle(_(\"Symmetrize Vertices\"));\n\t\tcbUnmatched->Hide();\n\t\tauto desc = _(\"Eliminates the selected asymmetries from unmasked vertices by adjusting vertex data to be consistent with mirror vertices.\");\n\t\tif (nBones)\n\t\t\tdesc += _(\"  (Hint: To choose which non-selected bones are adjusted during weight normalization, unlock them in the bones list in the Bones tab.)\");\n\t\twxStaticText* descST = XRCCTRL(dlg, \"maskSymmetricVerticesDescription\", wxStaticText);\n\t\tdescST->SetLabel(desc);\n\t\tdescST->Wrap(600);\n\t\tXRCCTRL(dlg, \"stillUnmaskedLabel\", wxStaticText)->SetLabel(_(\"Vertices that will be symmetrized:\"));\n\t\tXRCCTRL(dlg, \"wxID_OK\", wxButton)->SetLabel(_(\"&Symmetrize\"));\n\t}\n\n\tUpdateStillUnmasked();\n\tdlg.SetSize(dlg.GetBestSize());\n\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn false;\n\n\treturn true;\n}\n\nvoid OutfitStudioFrame::OnMaskSymVert(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tNiShape* s = activeItem->GetShape();\n\tstd::string shapeName = s->name.get();\n\tMesh* m = glView->gls.GetMesh(shapeName);\n\tif (!m)\n\t\treturn;\n\n\tstd::vector<bool> selVerts(m->nVerts);\n\tfor (int i = 0; i < m->nVerts; ++i)\n\t\tselVerts[i] = m->mask[i] == 0.0f;\n\n\tSymmetricVertices r;\n\tproject->MatchSymmetricVertices(s, m->weldVerts, r);\n\n\tVertexAsymmetries a;\n\tproject->FindVertexAsymmetries(s, r, m->weldVerts, a);\n\n\tVertexAsymmetryTasks tasks;\n\tif (!ShowVertexAsym(m, r, a, tasks, selVerts, false))\n\t\treturn;\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\tusp->usss.resize(1);\n\tUndoStateShape& uss = usp->usss[0];\n\tuss.shapeName = shapeName;\n\n\t// Mask vertices based on selected tasks.\n\tstd::vector<bool> doVert = CalcVertexListForAsymmetryTasks(r, a, tasks, m->nVerts);\n\tAddWeldedToVertexList(m->weldVerts, doVert);\n\tfor (int i = 0; i < m->nVerts; ++i) {\n\t\tif (selVerts[i] && doVert[i])\n\t\t\tcontinue;\n\t\tuss.pointStartState[i].x = m->mask[i];\n\t\tuss.pointEndState[i].x = 1.0f;\n\t};\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tglView->GetUndoHistory()->PopState();\n\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::OnSymVert(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tNiShape* s = activeItem->GetShape();\n\tstd::string shapeName = s->name.get();\n\tMesh* m = glView->gls.GetMesh(shapeName);\n\tif (!m)\n\t\treturn;\n\n\tstd::vector<bool> selVerts(m->nVerts);\n\tfor (int i = 0; i < m->nVerts; ++i)\n\t\tselVerts[i] = m->mask[i] == 0.0f;\n\n\tSymmetricVertices r;\n\tproject->MatchSymmetricVertices(s, m->weldVerts, r);\n\n\tVertexAsymmetries a;\n\tproject->FindVertexAsymmetries(s, r, m->weldVerts, a);\n\n\tVertexAsymmetryTasks tasks;\n\tif (!ShowVertexAsym(m, r, a, tasks, selVerts, true))\n\t\treturn;\n\n\tstd::vector<std::string> normBones, notNormBones;\n\tGetNormalizeBones(&normBones, &notNormBones);\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.resize(1);\n\tUndoStateShape& uss = usp->usss[0];\n\tuss.shapeName = shapeName;\n\n\tproject->PrepareSymmetrizeVertices(s, uss, r, a, tasks, m->weldVerts, selVerts, normBones, notNormBones);\n\n\tglView->ApplyUndoState(usp, false);\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::OnMaskSymTri(wxCommandEvent& WXUNUSED(event)) {\n\tif (selectedItems.empty())\n\t\treturn;\n\n\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\n\tfor (auto& selItem : selectedItems) {\n\t\tNiShape* shape = selItem->GetShape();\n\t\tif (!shape)\n\t\t\tcontinue;\n\t\tstd::string shapeName = shape->name.get();\n\n\t\tMesh* m = glView->gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = shapeName;\n\n\t\tstd::vector<bool> amask = project->CalculateAsymmetricTriangleVertexMask(shape, m->weldVerts);\n\n\t\t// Mask vertices that are _not_ in amask.\n\t\tfor (int vi = 0; vi < m->nVerts; ++vi)\n\t\t\tif (m->mask[vi] != 1.0f && !amask[vi]) {\n\t\t\t\tuss.pointStartState[vi].x = m->mask[vi];\n\t\t\t\tuss.pointEndState[vi].x = 1.0f;\n\t\t\t}\n\t}\n\n\tglView->ApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tglView->GetUndoHistory()->PopState();\n\n\tUpdateUndoTools();\n}\n\nvoid OutfitStudioFrame::OnResetTransforms(wxCommandEvent& WXUNUSED(event)) {\n\tproject->ResetTransforms();\n\tRefreshGUIFromProj();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnDeleteUnreferencedNodes(wxCommandEvent& WXUNUSED(event)) {\n\tint deletionCount = 0;\n\tauto workNif = project->GetWorkNif();\n\tif (workNif)\n\t\tworkNif->DeleteUnreferencedNodes(&deletionCount);\n\n\tif (deletionCount > 0)\n\t\tSetPendingChanges();\n\n\twxString msg = wxString::Format(_(\"%d unreferenced nodes were deleted.\"), deletionCount);\n\twxMessageBox(msg, _(\"Delete Unreferenced Nodes\"));\n}\n\nvoid OutfitStudioFrame::OnRemoveSkinning(wxCommandEvent& WXUNUSED(event)) {\n\tproject->RemoveSkinning();\n\tRefreshGUIFromProj();\n\tSetPendingChanges();\n}\n\nvoid OutfitStudioFrame::OnShapeProperties(wxCommandEvent& WXUNUSED(event)) {\n\tCloseBrushSettings();\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tstd::vector<NiShape*> selectedShapes;\n\tfor (auto& s : selectedItems)\n\t\tselectedShapes.push_back(s->GetShape());\n\n\tauto shape = activeItem->GetShape();\n\tif (shape) {\n\t\tShapeProperties prop(this, project->GetWorkNif(), selectedShapes);\n\t\tprop.ShowModal();\n\t}\n}\n\nvoid OutfitStudioFrame::OnMaskLess(wxCommandEvent& WXUNUSED(event)) {\n\tif (!activeItem)\n\t\treturn;\n\n\tglView->MaskLess();\n\n\tif (glView->GetTransformMode())\n\t\tglView->ShowTransformTool();\n\telse\n\t\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnMaskMore(wxCommandEvent& WXUNUSED(event)) {\n\tif (!activeItem)\n\t\treturn;\n\n\tglView->MaskMore();\n\n\tif (glView->GetTransformMode())\n\t\tglView->ShowTransformTool();\n\telse\n\t\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event) {\n\tstd::string fn = event.GetPath().ToStdString();\n\tstd::vector<std::string> shapes;\n\twxWindow* npWiz = ((wxFilePickerCtrl*)event.GetEventObject())->GetParent();\n\twxChoice* setNameChoice = (wxChoice*)XRCCTRL((*npWiz), \"npSliderSetName\", wxChoice);\n\twxChoice* refShapeChoice = (wxChoice*)XRCCTRL((*npWiz), \"npRefShapeName\", wxChoice);\n\tXRCCTRL((*npWiz), \"npRefIsSliderset\", wxRadioButton)->SetValue(true);\n\tsetNameChoice->Clear();\n\trefShapeChoice->Clear();\n\n\tif (fn.rfind(\".osp\") != std::string::npos || fn.rfind(\".xml\") != std::string::npos) {\n\t\tSliderSetFile ssf(fn);\n\t\tif (ssf.fail())\n\t\t\treturn;\n\n\t\tstd::vector<std::string> setNames;\n\t\tssf.GetSetNames(setNames);\n\n\t\tfor (auto& sn : setNames)\n\t\t\tsetNameChoice->AppendString(sn);\n\n\t\tif (!setNames.empty()) {\n\t\t\tsetNameChoice->SetSelection(0);\n\t\t\tssf.SetShapes(setNames.front(), shapes);\n\t\t\tfor (auto& rsn : shapes)\n\t\t\t\trefShapeChoice->AppendString(rsn);\n\n\t\t\trefShapeChoice->SetSelection(0);\n\t\t}\n\t}\n\telse if (fn.rfind(\".nif\") != std::string::npos) {\n\t\tstd::fstream file;\n\t\tPlatformUtil::OpenFileStream(file, fn, std::ios::in | std::ios::binary);\n\n\t\tNifFile checkFile;\n\t\tif (checkFile.Load(file))\n\t\t\treturn;\n\n\t\tfor (auto& rsn : checkFile.GetShapeNames())\n\t\t\trefShapeChoice->AppendString(rsn);\n\n\t\trefShapeChoice->SetSelection(0);\n\t}\n}\n\nvoid OutfitStudioFrame::OnNPWizChangeSetNameChoice(wxCommandEvent& event) {\n\twxWindow* npWiz = ((wxChoice*)event.GetEventObject())->GetParent();\n\twxFilePickerCtrl* file = (wxFilePickerCtrl*)XRCCTRL((*npWiz), \"npSliderSetFile\", wxFilePickerCtrl);\n\tif (!file)\n\t\treturn;\n\n\tstd::string fn = file->GetPath().ToStdString();\n\tSliderSetFile ssf(fn);\n\tif (ssf.fail())\n\t\treturn;\n\n\tstd::vector<std::string> shapes;\n\twxChoice* chooser = (wxChoice*)event.GetEventObject();\n\tssf.SetShapes(chooser->GetStringSelection().ToStdString(), shapes);\n\twxChoice* refShapeChoice = (wxChoice*)XRCCTRL((*npWiz), \"npRefShapeName\", wxChoice);\n\trefShapeChoice->Clear();\n\n\tfor (auto& rsn : shapes)\n\t\trefShapeChoice->AppendString(rsn);\n\n\trefShapeChoice->SetSelection(0);\n}\n\nvoid OutfitStudioFrame::OnLoadOutfitFP_File(wxFileDirPickerEvent& event) {\n\twxWindow* win = ((wxDialog*)event.GetEventObject())->GetParent();\n\tXRCCTRL((*win), \"npWorkFile\", wxRadioButton)->SetValue(true);\n}\n\nvoid OutfitStudioFrame::OnLoadOutfitFP_Texture(wxFileDirPickerEvent& event) {\n\twxWindow* win = ((wxDialog*)event.GetEventObject())->GetParent();\n\tXRCCTRL((*win), \"npTexFile\", wxRadioButton)->SetValue(true);\n}\n\nvoid OutfitStudioFrame::OnRecalcNormals(wxCommandEvent& WXUNUSED(event)) {\n\tfor (auto& s : selectedItems)\n\t\tglView->RecalcNormals(s->GetShape()->name.get(), true);\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnDisableNormalsCalc(wxCommandEvent& event) {\n\tOutfitStudioConfig.SetBoolValue(\"DisableNormalsCalc\", event.IsChecked());\n}\n\nvoid OutfitStudioFrame::OnSmoothNormalSeams(wxCommandEvent& event) {\n\tbool enable = event.IsChecked();\n\tglView->SetNormalSeamSmoothMode(enable);\n\n\tfor (auto& s : selectedItems)\n\t\tproject->activeSet.SetSmoothSeamNormals(s->GetShape()->name.get(), enable);\n\n\tmenuBar->Enable(XRCID(\"btnSmoothSeamsAngle\"), enable);\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnSmoothSeamsAngle(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tstd::vector<Mesh*> activeMeshes = glView->gls.GetActiveMeshes();\n\tif (activeMeshes.empty())\n\t\treturn;\n\n\tstd::vector<float> oldMeshAngles;\n\toldMeshAngles.resize(activeMeshes.size());\n\n\tfor (int i = 0; i < activeMeshes.size(); i++)\n\t\toldMeshAngles[i] = activeMeshes[i]->smoothSeamNormalsAngle;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgSmoothSeams\")) {\n\t\tauto updatePreview = [&]() {\n\t\t\tfloat angle = atof(XRCCTRL(dlg, \"angleText\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\tfor (int i = 0; i < activeMeshes.size(); i++) {\n\t\t\t\tMesh* m = activeMeshes[i];\n\t\t\t\tm->smoothSeamNormalsAngle = angle;\n\t\t\t\tm->SmoothNormals();\n\t\t\t}\n\n\t\t\tglView->Render();\n\t\t};\n\n\t\tauto sliderMoved = [&](wxCommandEvent&) {\n\t\t\tfloat angle = XRCCTRL(dlg, \"angleSlider\", wxSlider)->GetValue() / 100.0f;\n\t\t\tXRCCTRL(dlg, \"angleText\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.2f\", angle));\n\n\t\t\tupdatePreview();\n\t\t};\n\n\t\tauto textChanged = [&](wxCommandEvent&) {\n\t\t\tfloat angle = atof(XRCCTRL(dlg, \"angleText\", wxTextCtrl)->GetValue().c_str());\n\t\t\tXRCCTRL(dlg, \"angleSlider\", wxSlider)->SetValue(angle * 100);\n\n\t\t\tfloat angleLimited = XRCCTRL(dlg, \"angleSlider\", wxSlider)->GetValue() / 100.0f;\n\t\t\tif (angle != angleLimited)\n\t\t\t\tXRCCTRL(dlg, \"angleText\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.2f\", angleLimited));\n\n\t\t\tupdatePreview();\n\t\t};\n\n\t\tXRCCTRL(dlg, \"angleSlider\", wxSlider)->Bind(wxEVT_SLIDER, sliderMoved);\n\t\tXRCCTRL(dlg, \"angleText\", wxTextCtrl)->Bind(wxEVT_TEXT, textChanged);\n\t\tdlg.Bind(wxEVT_CHAR_HOOK, &OutfitStudioFrame::OnEnterClose, this);\n\n\t\t// Set old value of first mesh\n\t\tXRCCTRL(dlg, \"angleText\", wxTextCtrl)->SetValue(wxString::Format(\"%0.2f\", oldMeshAngles.front()));\n\n\t\tif (dlg.ShowModal() != wxID_OK) {\n\t\t\tfor (int i = 0; i < activeMeshes.size(); i++) {\n\t\t\t\tMesh* m = activeMeshes[i];\n\t\t\t\tm->smoothSeamNormalsAngle = oldMeshAngles[i];\n\t\t\t\tm->SmoothNormals();\n\t\t\t}\n\n\t\t\tglView->Render();\n\t\t\treturn;\n\t\t}\n\n\t\tfloat angle = atof(XRCCTRL(dlg, \"angleText\", wxTextCtrl)->GetValue().c_str());\n\n\t\tfor (auto& s : selectedItems)\n\t\t\tproject->activeSet.SetSmoothSeamNormalsAngle(s->GetShape()->name.get(), angle);\n\t}\n}\n\nvoid OutfitStudioFrame::OnLockNormals(wxCommandEvent& event) {\n\tbool enable = event.IsChecked();\n\tglView->SetLockNormalsMode(enable);\n\n\tfor (auto& s : selectedItems)\n\t\tproject->activeSet.SetLockNormals(s->GetShape()->name.get(), enable);\n}\n\nvoid OutfitStudioFrame::OnEditUV(wxCommandEvent& WXUNUSED(event)) {\n\tif (editUV)\n\t\treturn;\n\n\tif (!ShapeSelectionCheck())\n\t\treturn;\n\n\tauto shape = activeItem->GetShape();\n\tMesh* m = glView->GetMesh(shape->name.get());\n\tif (shape && m) {\n\t\teditUV = new EditUV(this, project->GetWorkNif(), shape, m, activeSlider);\n\n\t\teditUV->Bind(wxEVT_CLOSE_WINDOW, [&](wxCloseEvent& event) {\n\t\t\teditUV = nullptr;\n\t\t\tevent.Skip();\n\t\t});\n\n\t\teditUV->CenterOnParent();\n\t\teditUV->Show();\n\t}\n}\n\nvoid OutfitStudioFrame::OnSelectMask(wxCommandEvent& WXUNUSED(event)) {\n\tauto cMaskName = (wxComboBox*)FindWindowByName(\"cMaskName\");\n\tint maskSel = cMaskName->GetSelection();\n\tif (maskSel != wxNOT_FOUND) {\n\t\tauto maskData = (std::map<std::string, std::unordered_map<uint16_t, float>>*)cMaskName->GetClientData(maskSel);\n\t\tfor (auto mask : (*maskData)) {\n\t\t\tglView->SetShapeMask(mask.second, mask.first);\n\t\t}\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnSaveMask(wxCommandEvent& WXUNUSED(event)) {\n\tauto cMaskName = (wxComboBox*)FindWindowByName(\"cMaskName\");\n\n\twxString maskName = cMaskName->GetValue();\n\tif (maskName.empty())\n\t\treturn;\n\n\tauto maskData = new std::map<std::string, std::unordered_map<uint16_t, float>>();\n\n\tstd::vector<std::string> shapes = GetShapeList();\n\tfor (auto& s : shapes) {\n\t\tstd::unordered_map<uint16_t, float> mask;\n\t\tglView->GetShapeMask(mask, s);\n\t\t(*maskData)[s] = std::move(mask);\n\t}\n\n\tint existingSel = cMaskName->FindString(maskName);\n\tif (existingSel != wxNOT_FOUND) {\n\t\tcMaskName->SetClientData(existingSel, maskData);\n\t\tcMaskName->SetSelection(existingSel);\n\t}\n\telse {\n\t\tint maskSel = cMaskName->Append(maskName, maskData);\n\t\tcMaskName->SetSelection(maskSel);\n\t}\n}\n\nvoid OutfitStudioFrame::OnDeleteMask(wxCommandEvent& WXUNUSED(event)) {\n\tauto cMaskName = (wxComboBox*)FindWindowByName(\"cMaskName\");\n\tint maskSel = cMaskName->GetSelection();\n\tif (maskSel != wxNOT_FOUND) {\n\t\tcMaskName->Delete(maskSel);\n\t\tcMaskName->SetValue(\"\");\n\t}\n}\n\nvoid OutfitStudioFrame::OnExportMask(wxCommandEvent& WXUNUSED(event)) {\n\tauto cMaskName = (wxComboBox*)FindWindowByName(\"cMaskName\");\n\tif (cMaskName->GetCount() == 0) {\n\t\twxMessageBox(_(\"No masks to export.\"), _(\"Export Masks\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\twxFileDialog saveDialog(this, _(\"Export Masks\"), wxEmptyString, \"masks.xml\",\n\t\t\"XML Files (*.xml)|*.xml\", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);\n\n\tif (saveDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tstd::string filePath = saveDialog.GetPath().ToUTF8().data();\n\n\tMaskFile maskFile;\n\tfor (unsigned int i = 0; i < cMaskName->GetCount(); i++) {\n\t\tauto maskData = (std::map<std::string, std::unordered_map<uint16_t, float>>*)cMaskName->GetClientData(i);\n\t\tif (!maskData)\n\t\t\tcontinue;\n\n\t\tMaskEntry entry;\n\t\tentry.name = cMaskName->GetString(i).ToUTF8().data();\n\n\t\tstd::map<std::string, int> vertexCounts;\n\t\tfor (auto& [shapeName, mask] : *maskData) {\n\t\t\tMesh* m = glView->GetMesh(shapeName);\n\t\t\tif (m)\n\t\t\t\tvertexCounts[shapeName] = m->nVerts;\n\t\t}\n\n\t\tentry.SetFromMaskData(*maskData, vertexCounts);\n\t\tmaskFile.GetEntries().push_back(std::move(entry));\n\t}\n\n\tint err = maskFile.Save(filePath);\n\tif (err)\n\t\twxMessageBox(_(\"Failed to save mask file.\"), _(\"Export Masks\"), wxICON_ERROR);\n}\n\nvoid OutfitStudioFrame::OnImportMask(wxCommandEvent& WXUNUSED(event)) {\n\twxFileDialog openDialog(this, _(\"Import Masks\"), wxEmptyString, wxEmptyString,\n\t\t\"XML Files (*.xml)|*.xml\", wxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\n\tif (openDialog.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\tstd::string filePath = openDialog.GetPath().ToUTF8().data();\n\n\tMaskFile maskFile;\n\tint err = maskFile.Load(filePath);\n\tif (err) {\n\t\twxMessageBox(_(\"Failed to load mask file.\"), _(\"Import Masks\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tauto cMaskName = (wxComboBox*)FindWindowByName(\"cMaskName\");\n\n\tfor (const auto& entry : maskFile.GetEntries()) {\n\t\twxString maskName = entry.name.empty() ? _(\"Imported Mask\") : wxString::FromUTF8(entry.name);\n\t\tauto maskData = new std::map<std::string, std::unordered_map<uint16_t, float>>(entry.ToMaskData());\n\n\t\tint existing = cMaskName->FindString(maskName);\n\t\tif (existing != wxNOT_FOUND) {\n\t\t\tcMaskName->SetClientData(existing, maskData);\n\t\t}\n\t\telse {\n\t\t\tcMaskName->Append(maskName, maskData);\n\t\t}\n\t}\n\n\t// Select and apply the first imported entry\n\tif (!maskFile.GetEntries().empty()) {\n\t\twxString firstName = wxString::FromUTF8(maskFile.GetEntries().front().name);\n\t\tint sel = cMaskName->FindString(firstName);\n\t\tif (sel != wxNOT_FOUND) {\n\t\t\tcMaskName->SetSelection(sel);\n\t\t\tauto maskData = (std::map<std::string, std::unordered_map<uint16_t, float>>*)cMaskName->GetClientData(sel);\n\t\t\tif (maskData) {\n\t\t\t\tfor (auto& [shapeName, mask] : *maskData)\n\t\t\t\t\tglView->SetShapeMask(mask, shapeName);\n\t\t\t}\n\t\t}\n\t}\n\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::OnPaneCollapse(wxCollapsiblePaneEvent& WXUNUSED(event)) {\n\twxWindow* parentPanel = FindWindowByName(\"bottomSplitPanel\");\n\tparentPanel->Layout();\n}\n\nvoid OutfitStudioFrame::ApplyPose() {\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tstd::vector<Vector3> verts;\n\t\tproject->GetLiveVerts(shape, verts);\n\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t}\n\tglView->UpdateBones();\n\tglView->Render();\n}\n\nvoid OutfitStudioFrame::UpdateBoneTransformToolEnabled() {\n\t// The transform tool is generally enabled on every tab except bones (and\n\t// colors), but on the bones tab we want it enabled when the user has\n\t// turned on bones-mode or nodes-mode, so they can drag bones/nodes.\n\tif (!currentTabButton || !boneTabButton || currentTabButton->GetId() != boneTabButton->GetId())\n\t\treturn;\n\n\tconst bool enable = glView->GetBonesMode() || glView->GetNodesMode();\n\tmenuBar->Enable(XRCID(\"btnTransform\"), enable);\n\ttoolBarV->EnableTool(XRCID(\"btnTransform\"), enable);\n\tif (!enable)\n\t\tglView->SetTransformMode(false);\n}\n\nvoid OutfitStudioFrame::RefreshBoneTreeBadBoneIcons() {\n\t// Iterate the bone list and refresh each item's state so that the\n\t// bad-bones icon reflects any inconsistent transforms introduced by the\n\t// last edit.\n\tif (!outfitBones || !bonesRoot.IsOk())\n\t\treturn;\n\n\twxTreeItemIdValue cookie;\n\twxTreeItemId item = outfitBones->GetFirstChild(bonesRoot, cookie);\n\twhile (item.IsOk()) {\n\t\tUpdateBoneItemState(item, outfitBones->GetItemText(item).ToStdString());\n\t\titem = outfitBones->GetNextChild(bonesRoot, cookie);\n\t}\n}\n\nAnimBone* OutfitStudioFrame::GetPoseBonePtr() {\n\tint selind = cPoseBone->GetSelection();\n\tif (selind == wxNOT_FOUND)\n\t\treturn nullptr;\n\tstd::string poseBone = cPoseBone->GetString(selind).ToStdString();\n\treturn AnimSkeleton::getInstance().GetBonePtr(poseBone);\n}\n\nvoid OutfitStudioFrame::PoseToGUI() {\n\tAnimBone* bone = GetPoseBonePtr();\n\tif (bone) {\n\t\trxPoseSlider->SetValue(bone->poseRotVec.x * 100);\n\t\tryPoseSlider->SetValue(bone->poseRotVec.y * 100);\n\t\trzPoseSlider->SetValue(bone->poseRotVec.z * 100);\n\t\ttxPoseSlider->SetValue(bone->poseTranVec.x * 100);\n\t\ttyPoseSlider->SetValue(bone->poseTranVec.y * 100);\n\t\ttzPoseSlider->SetValue(bone->poseTranVec.z * 100);\n\t\tscPoseSlider->SetValue(std::log(bone->poseScale) / std::log(2) * 500);\n\t\trxPoseText->ChangeValue(wxString() << bone->poseRotVec.x);\n\t\tryPoseText->ChangeValue(wxString() << bone->poseRotVec.y);\n\t\trzPoseText->ChangeValue(wxString() << bone->poseRotVec.z);\n\t\ttxPoseText->ChangeValue(wxString() << bone->poseTranVec.x);\n\t\ttyPoseText->ChangeValue(wxString() << bone->poseTranVec.y);\n\t\ttzPoseText->ChangeValue(wxString() << bone->poseTranVec.z);\n\t\tscPoseText->ChangeValue(wxString() << bone->poseScale);\n\t}\n\telse {\n\t\trxPoseSlider->SetValue(0);\n\t\tryPoseSlider->SetValue(0);\n\t\trzPoseSlider->SetValue(0);\n\t\ttxPoseSlider->SetValue(0);\n\t\ttyPoseSlider->SetValue(0);\n\t\ttzPoseSlider->SetValue(0);\n\t\tscPoseSlider->SetValue(0);\n\t\trxPoseText->ChangeValue(\"0\");\n\t\tryPoseText->ChangeValue(\"0\");\n\t\trzPoseText->ChangeValue(\"0\");\n\t\ttxPoseText->ChangeValue(\"0\");\n\t\ttyPoseText->ChangeValue(\"0\");\n\t\ttzPoseText->ChangeValue(\"0\");\n\t\tscPoseText->ChangeValue(\"1\");\n\t}\n\tif (project->bPose != cbPose->GetValue())\n\t\tcbPose->SetValue(project->bPose);\n}\n\nvoid OutfitStudioFrame::OnPoseBoneChanged(wxCommandEvent& WXUNUSED(event)) {\n\tPoseToGUI();\n}\n\nvoid OutfitStudioFrame::OnPoseValChanged(int cind, float val) {\n\t// Called when any pose slider or text control is changed.\n\tAnimBone* bone = GetPoseBonePtr();\n\tif (!bone)\n\t\treturn;\n\tif (cind < 3)\n\t\tbone->poseRotVec[cind] = val;\n\telse if (cind < 6)\n\t\tbone->poseTranVec[cind - 3] = val;\n\telse\n\t\tbone->poseScale = val > 0 ? val : .0001f;\n\n\tbone->UpdatePoseTransform();\n\tActivatePose(true);\n}\n\nvoid OutfitStudioFrame::OnAnyPoseSlider(wxScrollEvent& e, wxTextCtrl* t, int cind) {\n\tfloat val = (cind == 6) ?\n\t\tstd::exp(e.GetPosition() * 0.002f * std::log(2)) :\n\t\te.GetPosition() * 0.01f;\n\tt->ChangeValue(wxString() << val);\n\tOnPoseValChanged(cind, val);\n}\n\nvoid OutfitStudioFrame::OnRXPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, rxPoseText, 0);\n}\nvoid OutfitStudioFrame::OnRYPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, ryPoseText, 1);\n}\nvoid OutfitStudioFrame::OnRZPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, rzPoseText, 2);\n}\nvoid OutfitStudioFrame::OnTXPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, txPoseText, 3);\n}\nvoid OutfitStudioFrame::OnTYPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, tyPoseText, 4);\n}\nvoid OutfitStudioFrame::OnTZPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, tzPoseText, 5);\n}\nvoid OutfitStudioFrame::OnScPoseSlider(wxScrollEvent& e) {\n\tOnAnyPoseSlider(e, scPoseText, 6);\n}\n\nvoid OutfitStudioFrame::OnAnyPoseTextChanged(wxTextCtrl* t, wxSlider* s, int cind) {\n\tif (!t || !s)\n\t\treturn;\n\tdouble val;\n\tif (!t->GetValue().ToDouble(&val))\n\t\treturn;\n\tif (cind == 6)\n\t\ts->SetValue(std::log(val) / std::log(2) * 500);\n\telse\n\t\ts->SetValue(val * 100);\n\tOnPoseValChanged(cind, val);\n}\n\nvoid OutfitStudioFrame::OnRXPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(rxPoseText, rxPoseSlider, 0);\n}\nvoid OutfitStudioFrame::OnRYPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(ryPoseText, ryPoseSlider, 1);\n}\nvoid OutfitStudioFrame::OnRZPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(rzPoseText, rzPoseSlider, 2);\n}\nvoid OutfitStudioFrame::OnTXPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(txPoseText, txPoseSlider, 3);\n}\nvoid OutfitStudioFrame::OnTYPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(tyPoseText, tyPoseSlider, 4);\n}\nvoid OutfitStudioFrame::OnTZPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(tzPoseText, tzPoseSlider, 5);\n}\nvoid OutfitStudioFrame::OnScPoseTextChanged(wxCommandEvent& WXUNUSED(event)) {\n\tOnAnyPoseTextChanged(scPoseText, scPoseSlider, 6);\n}\n\nvoid OutfitStudioFrame::OnResetBonePose(wxCommandEvent& WXUNUSED(event)) {\n\tAnimBone* bone = GetPoseBonePtr();\n\tif (!bone)\n\t\treturn;\n\tbone->poseRotVec = Vector3(0, 0, 0);\n\tbone->poseTranVec = Vector3(0, 0, 0);\n\tbone->poseScale = 1.0f;\n\tbone->UpdatePoseTransform();\n\tPoseToGUI();\n\tApplyPose();\n}\n\nvoid OutfitStudioFrame::OnResetAllPose(wxCommandEvent& WXUNUSED(event)) {\n\twxMessageDialog dlg(this, _(\"Reset all bone poses?\"), _(\"Reset Pose\"), wxOK | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\tdlg.SetOKCancelLabels(_(\"Reset\"), _(\"Cancel\"));\n\tif (dlg.ShowModal() != wxID_OK)\n\t\treturn;\n\n\tResetAllPoseBones();\n\tPoseToGUI();\n\tApplyPose();\n}\n\nvoid OutfitStudioFrame::ResetAllPoseBones() {\n\n\tstd::vector<std::string> bones;\n\tAnimSkeleton::getInstance().GetBoneNames(bones);\n\n\tfor (const std::string& boneName : bones) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (!bone)\n\t\t\tcontinue;\n\n\t\tif (bone->IsUnposed())\n\t\t\tcontinue;\n\n\t\tbone->poseRotVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\tbone->poseTranVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\tbone->poseScale = 1.0f;\n\t\tbone->UpdatePoseTransform();\n\t}\n}\n\nvoid OutfitStudioFrame::OnPoseToMesh(wxCommandEvent& WXUNUSED(event)) {\n\tif (project->bPose) {\n\t\tUndoStateProject* usp = glView->GetUndoHistory()->PushState();\n\t\tproject->ApplyPoseTransformsToAllShapeGeometry(*usp);\n\n\t\tstd::vector<std::string> bones;\n\t\tAnimSkeleton::getInstance().GetBoneNames(bones);\n\n\t\tfor (const std::string& boneName : bones) {\n\t\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\t\tif (!bone)\n\t\t\t\tcontinue;\n\n\t\t\tif (bone->IsUnposed())\n\t\t\t\tcontinue;\n\n\t\t\tbone->poseRotVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseTranVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseScale = 1.0f;\n\t\t\tbone->UpdatePoseTransform();\n\t\t}\n\n\t\tPoseToGUI();\n\t\tglView->UpdateBones();\n\t\tglView->ApplyUndoState(usp, false);\n\t\tSetPendingChanges();\n\t}\n}\n\nvoid OutfitStudioFrame::ActivatePose(bool checked) {\n\tif (cbPose->IsChecked() != checked)\n\t\tcbPose->SetValue(checked);\n\n\tproject->bPose = checked;\n\tposeToMesh->Enable(checked);\n\n\tApplyPose();\n}\n\nvoid OutfitStudioFrame::OnPoseCheckBox(wxCommandEvent& e) {\n\tActivatePose(e.IsChecked());\n}\n\nvoid OutfitStudioFrame::OnSelectPose(wxCommandEvent& WXUNUSED(event)) {\n\twxComboBox* cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\tint poseSel = cPoseName->GetSelection();\n\tif (poseSel != wxNOT_FOUND) {\n\t\tauto poseData = reinterpret_cast<PoseData*>(cPoseName->GetClientData(poseSel));\n\n\t\tif (!poseData) {\n\t\t\t// \"<New>\" sentinel: reset all bones to an unposed state.\n\t\t\tResetAllPoseBones();\n\n\t\t\tPoseToGUI();\n\t\t\tApplyPose();\n\t\t\tUpdatePoseButtonStates();\n\t\t\treturn;\n\t\t}\n\n\t\tposeData->ApplyToSkeleton();\n\n\t\tPoseToGUI();\n\t\tActivatePose(true);\n\n\t\tUpdatePoseButtonStates();\n\t}\n}\n\nvoid OutfitStudioFrame::UpdatePoseButtonStates() {\n\twxComboBox* cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\twxWindow* savePose = FindWindow(XRCID(\"savePose\"));\n\twxWindow* deletePose = FindWindow(XRCID(\"deletePose\"));\n\tif (!cPoseName)\n\t\treturn;\n\n\tbool enableSave = true;\n\tbool enableDelete = true;\n\tint poseSel = cPoseName->GetSelection();\n\tif (poseSel != wxNOT_FOUND) {\n\t\tauto poseData = reinterpret_cast<PoseData*>(cPoseName->GetClientData(poseSel));\n\t\tif (!poseData) {\n\t\t\t// \"<New>\" sentinel: nothing to delete.\n\t\t\tenableDelete = false;\n\t\t}\n\t\telse if (poseData->readOnly) {\n\t\t\tenableSave = false;\n\t\t\tenableDelete = false;\n\t\t}\n\t}\n\n\tif (savePose)\n\t\tsavePose->Enable(enableSave);\n\tif (deletePose)\n\t\tdeletePose->Enable(enableDelete);\n}\n\nvoid OutfitStudioFrame::OnSavePose(wxCommandEvent& WXUNUSED(event)) {\n\twxComboBox* cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\n\twxString poseName = cPoseName->GetValue();\n\tposeName.Trim(true).Trim(false);\n\tif (poseName.empty() || poseName == \"<New>\") {\n\t\twxMessageBox(_(\"Please enter a name for the pose.\"), _(\"Save Pose\"), wxICON_INFORMATION);\n\t\treturn;\n\t}\n\n\t// If a pose with this name already exists, update it in place;\n\t// otherwise create a new entry (replacing the old Save As behavior).\n\tint existingSel = cPoseName->FindString(poseName);\n\tPoseData* poseData = nullptr;\n\tif (existingSel != wxNOT_FOUND) {\n\t\tposeData = reinterpret_cast<PoseData*>(cPoseName->GetClientData(existingSel));\n\t\tif (poseData) {\n\t\t\tif (poseData->readOnly)\n\t\t\t\treturn;\n\t\t\tposeData->boneData.clear();\n\t\t}\n\t\telse {\n\t\t\t// Defensive: an existing entry with null client data (shouldn't\n\t\t\t// happen for non-sentinel names). Treat as new.\n\t\t\tposeData = new PoseData(poseName.ToUTF8().data());\n\t\t\tcPoseName->SetClientData(existingSel, poseData);\n\t\t}\n\t}\n\telse {\n\t\tposeData = new PoseData(poseName.ToUTF8().data());\n\t}\n\n\tstd::vector<std::string> bones;\n\tAnimSkeleton::getInstance().GetBoneNames(bones);\n\n\tfor (const auto& boneName : bones) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (!bone)\n\t\t\tcontinue;\n\n\t\tif (bone->IsUnposed())\n\t\t\tcontinue;\n\n\t\tPoseBoneData poseBoneData{};\n\t\tposeBoneData.name = bone->boneName;\n\t\tposeBoneData.rotation = bone->poseRotVec;\n\t\tposeBoneData.translation = bone->poseTranVec;\n\t\tposeBoneData.scale = bone->poseScale;\n\t\tposeData->boneData.push_back(poseBoneData);\n\t}\n\n\tif (existingSel != wxNOT_FOUND) {\n\t\tcPoseName->SetSelection(existingSel);\n\t}\n\telse {\n\t\tint poseSel = cPoseName->Append(poseName, poseData);\n\t\tcPoseName->SetSelection(poseSel);\n\t}\n\n\twxString dirName = wxString::FromUTF8(GetProjectPath()) + \"/PoseData\";\n\twxFileName::Mkdir(dirName, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);\n\n\twxString fileName = dirName + \"/\" + wxString::FromUTF8(poseData->name) + \".xml\";\n\n\tPoseDataFile poseDataFile;\n\tposeDataFile.New(fileName.ToUTF8().data());\n\n\tstd::vector<PoseData> poses;\n\tposes.push_back(*poseData);\n\n\tposeDataFile.SetData(poses);\n\tposeDataFile.Save();\n\n\tUpdatePoseButtonStates();\n}\n\nvoid OutfitStudioFrame::OnDeletePose(wxCommandEvent& WXUNUSED(event)) {\n\twxComboBox* cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\tint poseSel = cPoseName->GetSelection();\n\tif (poseSel != wxNOT_FOUND) {\n\t\tauto poseData = reinterpret_cast<PoseData*>(cPoseName->GetClientData(poseSel));\n\t\tif (!poseData)\n\t\t\treturn; // \"<New>\" sentinel, nothing to delete\n\t\tif (poseData->readOnly)\n\t\t\treturn;\n\n\t\twxString prompt = wxString::Format(_(\"Are you sure you wish to delete the pose '%s'?\"), cPoseName->GetStringSelection());\n\t\tint result = wxMessageBox(prompt, _(\"Confirm pose delete\"), wxYES_NO | wxICON_WARNING, this);\n\t\tif (result != wxYES)\n\t\t\treturn;\n\n\t\twxString fileName = wxString::FromUTF8(GetProjectPath()) + \"/PoseData/\" + wxString::FromUTF8(poseData->name) + \".xml\";\n\t\twxRemoveFile(fileName);\n\n\t\tcPoseName->Delete(poseSel);\n\t\tcPoseName->SetStringSelection(\"<New>\");\n\t\tUpdatePoseButtonStates();\n\t}\n}\n\nvoid OutfitStudioFrame::OnLoadHkxPose(wxCommandEvent& WXUNUSED(event)) {\n\tTargetGame targetGame = wxGetApp().targetGame;\n\tif (targetGame != SKYRIM && targetGame != SKYRIMSE && targetGame != SKYRIMVR && targetGame != FO4 && targetGame != FO4VR) {\n\t\twxMessageBox(_(\"Loading HKX poses is currently only supported for Skyrim Legendary Edition, Skyrim Special Edition, Skyrim VR, Fallout 4 and Fallout 4 VR.\"),\n\t\t\t\t\t _(\"Load HKX Pose\"),\n\t\t\t\t\t wxOK | wxICON_INFORMATION,\n\t\t\t\t\t this);\n\t\treturn;\n\t}\n\n\t// Ask the user which .hkx pose file to load.\n\twxFileDialog loadDlg(this,\n\t\t\t\t\t\t _(\"Select HKX pose file\"),\n\t\t\t\t\t\t wxEmptyString,\n\t\t\t\t\t\t wxEmptyString,\n\t\t\t\t\t\t \"HKX files (*.hkx)|*.hkx\",\n\t\t\t\t\t\t wxFD_OPEN | wxFD_FILE_MUST_EXIST);\n\n\tif (loadDlg.ShowModal() == wxID_CANCEL)\n\t\treturn;\n\n\twxString srcHkx = loadDlg.GetPath();\n\n\t// Derive the Havok skeleton path from the reference skeleton configured\n\t// for this target game (Settings → Anim/DefaultSkeletonReference). The\n\t// NIF and HKX files share the same base name per Bethesda convention,\n\t// so we simply swap the extension.\n\twxString defSkelNif = wxString::FromUTF8(Config[\"Anim/DefaultSkeletonReference\"]);\n\tif (defSkelNif.IsEmpty()) {\n\t\twxMessageBox(_(\"No reference skeleton is configured. Please set a reference skeleton \"\n\t\t\t\t\t   \"in the application settings before loading an HKX pose.\"),\n\t\t\t\t\t _(\"Load HKX Pose\"),\n\t\t\t\t\t wxOK | wxICON_ERROR,\n\t\t\t\t\t this);\n\t\treturn;\n\t}\n\n\twxFileName defSkelFn(defSkelNif);\n\tif (defSkelFn.IsRelative())\n\t\tdefSkelFn = wxFileName(wxString::FromUTF8(Config[\"AppDir\"]) + PathSepChar + defSkelNif);\n\tdefSkelFn.SetExt(\"hkx\");\n\n\twxString skelHkx = defSkelFn.GetFullPath();\n\tif (!wxFileExists(skelHkx)) {\n\t\twxMessageBox(wxString::Format(_(\"No Havok skeleton file was found next to the configured \"\n\t\t\t\t\t\t\t\t\t    \"reference skeleton.\\n\\nExpected file:\\n%s\\n\\n\"\n\t\t\t\t\t\t\t\t\t    \"To load HKX poses, place a matching .hkx skeleton file \"\n\t\t\t\t\t\t\t\t\t    \"alongside the .nif reference skeleton.\"),\n\t\t\t\t\t\t\t\t\t  skelHkx),\n\t\t\t\t\t _(\"Load HKX Pose\"),\n\t\t\t\t\t wxOK | wxICON_ERROR,\n\t\t\t\t\t this);\n\t\treturn;\n\t}\n\n\t// Build a pose name from the source file name.\n\twxFileName srcFn(srcHkx);\n\tstd::string poseName = std::string(\"HKX: \") + std::string(srcFn.GetName().ToUTF8().data());\n\n\tPoseData pd;\n\tpd.name = poseName;\n\n\tif (!PoseDataCollection::LoadHkxPose(std::string(skelHkx.ToUTF8().data()), std::string(srcHkx.ToUTF8().data()), pd)) {\n\t\twxMessageBox(_(\"Failed to parse the HKX pose data.\"), _(\"Load HKX Pose\"), wxOK | wxICON_ERROR, this);\n\t\treturn;\n\t}\n\n\t// Add or replace the pose in the collection and the combobox. The\n\t// combobox stores raw PoseData pointers; PoseDataCollection uses a\n\t// deque so existing addresses stay valid across the AddPose call.\n\twxComboBox* cPoseName = (wxComboBox*)FindWindowByName(\"cPoseName\");\n\tif (!cPoseName)\n\t\treturn;\n\n\tauto makeUniquePoseName = [cPoseName](const std::string& baseName) {\n\t\twxString uniqueName = wxString::FromUTF8(baseName);\n\t\tif (cPoseName->FindString(uniqueName) == wxNOT_FOUND)\n\t\t\treturn uniqueName;\n\n\t\tfor (int suffix = 1;; ++suffix) {\n\t\t\twxString candidate = wxString::Format(\"%s (%d)\", uniqueName, suffix);\n\t\t\tif (cPoseName->FindString(candidate) == wxNOT_FOUND)\n\t\t\t\treturn candidate;\n\t\t}\n\t};\n\n\tint existingSel = cPoseName->FindString(wxString::FromUTF8(pd.name));\n\tif (existingSel != wxNOT_FOUND) {\n\t\tauto existing = reinterpret_cast<PoseData*>(cPoseName->GetClientData(existingSel));\n\t\tif (existing && !existing->readOnly) {\n\t\t\texisting->boneData = std::move(pd.boneData);\n\t\t\texisting->absoluteLocal = pd.absoluteLocal;\n\t\t\tcPoseName->SetSelection(existingSel);\n\t\t}\n\t\telse {\n\t\t\tpd.name = std::string(makeUniquePoseName(pd.name).ToUTF8().data());\n\t\t\tPoseData* added = poseDataCollection.AddPose(std::move(pd));\n\t\t\tint idx = cPoseName->Append(wxString::FromUTF8(added->name), added);\n\t\t\tcPoseName->SetSelection(idx);\n\t\t}\n\t}\n\telse {\n\t\tPoseData* added = poseDataCollection.AddPose(std::move(pd));\n\t\tint idx = cPoseName->Append(wxString::FromUTF8(added->name), added);\n\t\tcPoseName->SetSelection(idx);\n\t}\n\n\t// Apply the pose by replaying the OnSelectPose handler.\n\twxCommandEvent dummy;\n\tOnSelectPose(dummy);\n}\n\nwxBEGIN_EVENT_TABLE(wxGLPanel, wxGLCanvas)\n\tEVT_PAINT(wxGLPanel::OnPaint)\n\tEVT_SIZE(wxGLPanel::OnSize)\n\tEVT_MOUSEWHEEL(wxGLPanel::OnMouseWheel)\n\tEVT_MOTION(wxGLPanel::OnMouseMove)\n\tEVT_LEFT_DOWN(wxGLPanel::OnLeftDown)\n\tEVT_LEFT_DCLICK(wxGLPanel::OnLeftDown)\n\tEVT_LEFT_UP(wxGLPanel::OnLeftUp)\n\tEVT_MIDDLE_DOWN(wxGLPanel::OnMiddleDown)\n\tEVT_MIDDLE_UP(wxGLPanel::OnMiddleUp)\n\tEVT_RIGHT_DOWN(wxGLPanel::OnRightDown)\n\tEVT_RIGHT_UP(wxGLPanel::OnRightUp)\n\tEVT_CHAR_HOOK(wxGLPanel::OnKeys)\n\tEVT_IDLE(wxGLPanel::OnIdle)\n\tEVT_MOUSE_CAPTURE_LOST(wxGLPanel::OnCaptureLost)\nwxEND_EVENT_TABLE()\n\nwxGLPanel::wxGLPanel(wxWindow* parent, const wxSize& size, const wxGLAttributes& attribs)\n\t: wxGLCanvas(parent, attribs, wxID_ANY, wxDefaultPosition, size, wxFULL_REPAINT_ON_RESIZE) {\n\tcontext = std::make_unique<wxGLContext>(this, nullptr, &GLSurface::GetGLContextAttribs());\n}\n\nwxGLPanel::~wxGLPanel() {\n\tCleanup();\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::OnShown() {\n\tif (!context->IsOK()) {\n\t\twxLogError(\"Outfit Studio: OpenGL context is not OK.\");\n\t\twxMessageBox(_(\"Outfit Studio: OpenGL context is not OK.\"), _(\"OpenGL Error\"), wxICON_ERROR, os);\n\t}\n\n\tgls.Initialize(this, context.get());\n\tauto size = GetSize();\n\tgls.SetStartingView(Vector3(0.0f, -5.0f, -15.0f), Vector3(15.0f, 0.0f, 0.0f), size.GetWidth(), size.GetHeight());\n\tgls.SetMaskVisible();\n\n\tint ambient = Config.GetIntValue(\"Lights/Ambient\");\n\tint frontal = Config.GetIntValue(\"Lights/Frontal\");\n\n\tint directional0 = Config.GetIntValue(\"Lights/Directional0\");\n\tint directional0X = Config.GetIntValue(\"Lights/Directional0.x\");\n\tint directional0Y = Config.GetIntValue(\"Lights/Directional0.y\");\n\tint directional0Z = Config.GetIntValue(\"Lights/Directional0.z\");\n\n\tint directional1 = Config.GetIntValue(\"Lights/Directional1\");\n\tint directional1X = Config.GetIntValue(\"Lights/Directional1.x\");\n\tint directional1Y = Config.GetIntValue(\"Lights/Directional1.y\");\n\tint directional1Z = Config.GetIntValue(\"Lights/Directional1.z\");\n\n\tint directional2 = Config.GetIntValue(\"Lights/Directional2\");\n\tint directional2X = Config.GetIntValue(\"Lights/Directional2.x\");\n\tint directional2Y = Config.GetIntValue(\"Lights/Directional2.y\");\n\tint directional2Z = Config.GetIntValue(\"Lights/Directional2.z\");\n\n\tVector3 directional0Dir = Vector3(directional0X / 100.0f, directional0Y / 100.0f, directional0Z / 100.0f);\n\tVector3 directional1Dir = Vector3(directional1X / 100.0f, directional1Y / 100.0f, directional1Z / 100.0f);\n\tVector3 directional2Dir = Vector3(directional2X / 100.0f, directional2Y / 100.0f, directional2Z / 100.0f);\n\n\tUpdateLights(ambient, frontal, directional0, directional1, directional2, directional0Dir, directional1Dir, directional2Dir);\n\n\tif (Config.Exists(\"Rendering/ColorBackground\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorBackground.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorBackground.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorBackground.b\");\n\t\tgls.SetBackgroundColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorWire\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorWire.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorWire.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorWire.b\");\n\t\tgls.SetWireColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorPoints\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPoints.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPoints.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPoints.b\");\n\t\tgls.SetPointColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorPointsMasked\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPointsMasked.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPointsMasked.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPointsMasked.b\");\n\t\tgls.SetMaskedPointColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tbool perspectiveView = OutfitStudioConfig.GetBoolValue(\"Rendering/PerspectiveView\", true);\n\tos->menuBar->Check(XRCID(\"btnViewPerspective\"), perspectiveView);\n\tos->toolBarV->ToggleTool(XRCID(\"btnViewPerspective\"), perspectiveView);\n\tgls.SetPerspective(perspectiveView);\n\n\tos->MeshesFromProj();\n\n\tUpdateFloor();\n\tUpdateNodes();\n\tUpdateBones();\n\n\tRender();\n}\n\nvoid wxGLPanel::SetNotifyWindow(wxWindow* win) {\n\tos = dynamic_cast<OutfitStudioFrame*>(win);\n}\n\nvoid wxGLPanel::AddMeshFromNif(NifFile* nif, const std::string& shapeName) {\n\tstd::vector<std::string> shapeList = nif->GetShapeNames();\n\n\tfor (size_t i = 0; i < shapeList.size(); i++) {\n\t\tif (!shapeName.empty() && shapeList[i] != shapeName)\n\t\t\tcontinue;\n\n\t\tMesh* m = gls.AddMeshFromNif(nif, shapeList[i]);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tNiShape* shape = nif->FindBlockByName<NiShape>(shapeList[i]);\n\t\tif (shape && shape->IsSkinned()) {\n\t\t\t// Overwrite skin matrix with the one from AnimInfo\n\t\t\tMatTransform globalToShape = os->project->GetWorkAnim()->GetTransformGlobalToShape(shape);\n\t\t\tm->SetXformModelToMesh(Mesh::xformNifToMesh.ComposeTransforms(globalToShape.ComposeTransforms(Mesh::xformMeshToNif)));\n\t\t}\n\n\t\tm->BuildVertexAdjacency();\n\t\tm->BuildEdgeList();\n\t\tm->MaskFill(0.0f);\n\t\tm->WeightFill(0.0f);\n\n\t\tif (extInitialized) {\n\t\t\tgls.SetContext();\n\t\t\tm->CreateBuffers();\n\t\t}\n\t}\n}\n\nvoid wxGLPanel::SetMeshTextures(\n\tconst std::string& shapeName, const std::vector<std::string>& textureFiles, const bool hasMatFile, const MaterialFile& matFile, const bool reloadTextures) {\n\tMesh* m = gls.GetMesh(shapeName);\n\tif (!m)\n\t\treturn;\n\n\tstd::string vShader = Config[\"AppDir\"] + \"/res/shaders/default.vert\";\n\tstd::string fShader = Config[\"AppDir\"] + \"/res/shaders/default.frag\";\n\n\tauto targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tif (targetGame == FO4 || targetGame == FO4VR || targetGame == FO76) {\n\t\tvShader = Config[\"AppDir\"] + \"/res/shaders/fo4_default.vert\";\n\t\tfShader = Config[\"AppDir\"] + \"/res/shaders/fo4_default.frag\";\n\t}\n\telse if (targetGame == OB) {\n\t\tvShader = Config[\"AppDir\"] + \"/res/shaders/ob_default.vert\";\n\t\tfShader = Config[\"AppDir\"] + \"/res/shaders/ob_default.frag\";\n\t}\n\n\tGLMaterial* mat = gls.AddMaterial(textureFiles, vShader, fShader, reloadTextures);\n\tif (mat) {\n\t\tm->material = mat;\n\n\t\tif (hasMatFile)\n\t\t\tm->UpdateFromMaterialFile(matFile);\n\n\t\tgls.UpdateShaders(m);\n\t}\n}\n\nvoid wxGLPanel::UpdateMeshVertices(const std::string& shapeName, std::vector<Vector3>* verts, bool updateBVH, bool recalcNormals, bool render, std::vector<Vector2>* uvs) {\n\tMesh* m = gls.GetMesh(shapeName);\n\tif (m) {\n\t\tgls.Update(m, verts, uvs);\n\n\t\tif (updateBVH)\n\t\t\tBVHUpdateQueue.insert(m);\n\n\t\tif (recalcNormals)\n\t\t\tm->SmoothNormals();\n\t}\n\n\tif (render)\n\t\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::RecalculateMeshBVH(const std::string& shapeName) {\n\tgls.RecalculateMeshBVH(shapeName);\n}\n\nvoid wxGLPanel::ShowShape(const std::string& shapeName, bool show) {\n\tgls.SetMeshVisibility(shapeName, show);\n}\n\nvoid wxGLPanel::SetActiveShapes(const std::vector<std::string>& shapeNames) {\n\tgls.SetActiveMeshes(shapeNames);\n}\n\nvoid wxGLPanel::SetSelectedShape(const std::string& shapeName) {\n\tgls.SetSelectedMesh(shapeName);\n}\n\nvoid wxGLPanel::SetActiveTool(ToolID brushID) {\n\tactiveTool = brushID;\n\n\tswitch (brushID) {\n\t\tcase ToolID::MaskBrush: activeBrush = &maskBrush; break;\n\t\tcase ToolID::InflateBrush: activeBrush = &inflateBrush; break;\n\t\tcase ToolID::DeflateBrush: activeBrush = &deflateBrush; break;\n\t\tcase ToolID::MoveBrush: activeBrush = &moveBrush; break;\n\t\tcase ToolID::SmoothBrush: activeBrush = &smoothBrush; break;\n\t\tcase ToolID::UndiffBrush: activeBrush = &undiffBrush; break;\n\t\tcase ToolID::WeightBrush: activeBrush = &weightBrush; break;\n\t\tcase ToolID::ColorBrush: activeBrush = &colorBrush; break;\n\t\tcase ToolID::AlphaBrush: activeBrush = &alphaBrush; break;\n\t\tdefault: activeBrush = nullptr; break;\n\t}\n\n\tgls.SetXMirrorCursor(GetToolOptionXMirror());\n}\n\nvoid wxGLPanel::SetLastTool(ToolID tool) {\n\tlastTool = tool;\n}\n\nvoid wxGLPanel::OnKeys(wxKeyEvent& event) {\n\tif (!event.HasAnyModifiers()) {\n\t\tif (event.GetUnicodeKey() == 'V') {\n\t\t\twxPoint cursorPos(event.GetPosition());\n\n\t\t\tint vertIndex;\n\t\t\tMesh* outHitMesh;\n\t\t\tif (!gls.GetCursorVertex(cursorPos.x, cursorPos.y, &vertIndex, nullptr, &outHitMesh))\n\t\t\t\treturn;\n\n\t\t\tif (os->currentTabButton == os->colorsTabButton) {\n\t\t\t\tauto cpBrushColor = (wxColourPickerCtrl*)os->FindWindowById(XRCID(\"cpBrushColor\"));\n\t\t\t\tif (!cpBrushColor)\n\t\t\t\t\treturn;\n\n\t\t\t\tif (outHitMesh->vcolors) {\n\t\t\t\t\t// Set color for brush to vertex color\n\t\t\t\t\tVector3 vcolor = outHitMesh->vcolors[vertIndex];\n\t\t\t\t\tSetColorBrush(vcolor);\n\n\t\t\t\t\t// Set color for picker to vertex color\n\t\t\t\t\twxColour color(vcolor.x * 255.0f, vcolor.y * 255.0f, vcolor.z * 255.0f);\n\t\t\t\t\tcpBrushColor->SetColour(color);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// Find shape for hit mesh name\n\t\t\t\tNiShape* shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(outHitMesh->shapeName);\n\t\t\t\tif (!shape)\n\t\t\t\t\treturn;\n\n\t\t\t\tos->CloseBrushSettings();\n\n\t\t\t\twxDialog dlg;\n\t\t\t\tif (wxXmlResource::Get()->LoadDialog(&dlg, os, \"dlgMoveVertex\")) {\n\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\tos->project->GetLiveVerts(shape, verts);\n\n\t\t\t\t\tVector3 oldPos = verts[vertIndex];\n\t\t\t\t\tXRCCTRL(dlg, \"posX\", wxTextCtrl)->SetValue(wxString::Format(\"%0.5f\", oldPos.x));\n\t\t\t\t\tXRCCTRL(dlg, \"posY\", wxTextCtrl)->SetValue(wxString::Format(\"%0.5f\", oldPos.y));\n\t\t\t\t\tXRCCTRL(dlg, \"posZ\", wxTextCtrl)->SetValue(wxString::Format(\"%0.5f\", oldPos.z));\n\n\t\t\t\t\tif (dlg.ShowModal() == wxID_OK) {\n\t\t\t\t\t\tVector3 newPos;\n\t\t\t\t\t\tnewPos.x = atof(XRCCTRL(dlg, \"posX\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\t\t\tnewPos.y = atof(XRCCTRL(dlg, \"posY\", wxTextCtrl)->GetValue().c_str());\n\t\t\t\t\t\tnewPos.z = atof(XRCCTRL(dlg, \"posZ\", wxTextCtrl)->GetValue().c_str());\n\n\t\t\t\t\t\t// Move vertex in shape directly\n\t\t\t\t\t\tif (!os->bEditSlider)\n\t\t\t\t\t\t\tos->project->MoveVertex(shape, newPos, vertIndex);\n\n\t\t\t\t\t\t// To mesh coordinates\n\t\t\t\t\t\toldPos = Mesh::TransformPosNifToMesh(oldPos);\n\t\t\t\t\t\tnewPos = Mesh::TransformPosNifToMesh(newPos);\n\n\t\t\t\t\t\tUndoStateShape uss;\n\t\t\t\t\t\tuss.shapeName = shape->name.get();\n\t\t\t\t\t\tuss.pointStartState[vertIndex] = oldPos;\n\t\t\t\t\t\tuss.pointEndState[vertIndex] = newPos;\n\n\t\t\t\t\t\t// Push changes onto undo stack and execute\n\t\t\t\t\t\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\t\t\t\t\t\tusp->undoType = UndoType::VertexPosition;\n\t\t\t\t\t\tusp->usss.push_back(std::move(uss));\n\n\t\t\t\t\t\tif (os->bEditSlider) {\n\t\t\t\t\t\t\tusp->sliderName = os->activeSlider;\n\n\t\t\t\t\t\t\tfloat sliderscale = os->project->SliderValue(os->activeSlider);\n\t\t\t\t\t\t\tif (sliderscale == 0.0)\n\t\t\t\t\t\t\t\tsliderscale = 1.0;\n\n\t\t\t\t\t\t\tusp->sliderscale = sliderscale;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tApplyUndoState(usp, false);\n\t\t\t\t\t\tos->UpdateUndoTools();\n\t\t\t\t\t}\n\n\t\t\t\t\tif (transformMode)\n\t\t\t\t\t\tShowTransformTool();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (event.GetUnicodeKey() == '0' && os->menuBar->IsEnabled(XRCID(\"btnSelect\")))\n\t\t\tos->SelectTool(ToolID::Select);\n\t\telse if (event.GetUnicodeKey() == '1' && os->menuBar->IsEnabled(XRCID(\"btnMaskBrush\")))\n\t\t\tos->SelectTool(ToolID::MaskBrush);\n\t\telse if (event.GetUnicodeKey() == '2' && os->menuBar->IsEnabled(XRCID(\"btnInflateBrush\")))\n\t\t\tos->SelectTool(ToolID::InflateBrush);\n\t\telse if (event.GetUnicodeKey() == '3' && os->menuBar->IsEnabled(XRCID(\"btnDeflateBrush\")))\n\t\t\tos->SelectTool(ToolID::DeflateBrush);\n\t\telse if (event.GetUnicodeKey() == '4' && os->menuBar->IsEnabled(XRCID(\"btnMoveBrush\")))\n\t\t\tos->SelectTool(ToolID::MoveBrush);\n\t\telse if (event.GetUnicodeKey() == '5' && os->menuBar->IsEnabled(XRCID(\"btnSmoothBrush\")))\n\t\t\tos->SelectTool(ToolID::SmoothBrush);\n\t\telse if (event.GetUnicodeKey() == '6' && os->menuBar->IsEnabled(XRCID(\"btnUndiffBrush\")))\n\t\t\tos->SelectTool(ToolID::UndiffBrush);\n\t\telse if (event.GetUnicodeKey() == '7' && os->menuBar->IsEnabled(XRCID(\"btnWeightBrush\")))\n\t\t\tos->SelectTool(ToolID::WeightBrush);\n\t\telse if (event.GetUnicodeKey() == '8' && os->menuBar->IsEnabled(XRCID(\"btnColorBrush\")))\n\t\t\tos->SelectTool(ToolID::ColorBrush);\n\t\telse if (event.GetUnicodeKey() == '9' && os->menuBar->IsEnabled(XRCID(\"btnAlphaBrush\")))\n\t\t\tos->SelectTool(ToolID::AlphaBrush);\n\t\telse if (event.GetKeyCode() == WXK_SPACE) {\n\t\t\tif (event.ControlDown()) {\n\t\t\t\tif (!os->activeSlider.empty()) {\n\t\t\t\t\tos->ExitSliderEdit();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tos->EnterSliderEdit();\n\t\t\t\t\tos->ScrollToActiveSlider();\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (os->brushSettingsPopupTransient && os->brushSettingsPopupTransient->IsShown()) {\n\t\t\t\t\tos->CloseBrushSettings();\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tbool brushSettingsNearCursor = Config.GetBoolValue(\"Input/BrushSettingsNearCursor\");\n\t\t\t\t\tif (brushSettingsNearCursor)\n\t\t\t\t\t\tos->PopupBrushSettings();\n\t\t\t\t\telse\n\t\t\t\t\t\tos->PopupBrushSettings(os->brushSettings);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (event.GetKeyCode() == WXK_ESCAPE) {\n\t\t\tif (isMovingVertex) {\n\t\t\t\tCancelMoveVertex();\n\t\t\t\tisMovingVertex = false;\n\t\t\t}\n\t\t\tos->CloseBrushSettings();\n\t\t}\n\t}\n\n\tevent.Skip();\n}\n\nbool wxGLPanel::StartBrushStroke(const wxPoint& screenPos) {\n\t// Check if brush strokes are currently allowed\n\tif (activeBrush == &weightBrush) {\n\t\tstd::string activeBone = os->GetActiveBone();\n\t\tif (activeBone.empty())\n\t\t\treturn false;\n\t}\n\n\tTweakPickInfo tpi;\n\tMesh* hitMesh = nullptr;\n\tint hitTri = -1;\n\tbool hit = gls.CollideMeshes(screenPos.x, screenPos.y, tpi.origin, tpi.normal, false, &hitMesh, true, &hitTri);\n\tif (!hit || !hitMesh)\n\t\treturn false;\n\n\tif (!os->CheckEditableState())\n\t\treturn false;\n\n\ttpi.origin = hitMesh->TransformPosMeshToModel(tpi.origin);\n\ttpi.normal.Normalize();\n\ttpi.normal = hitMesh->TransformDirMeshToModel(tpi.normal);\n\n\tVector3 v;\n\tVector3 vo;\n\tgls.GetPickRay(screenPos.x, screenPos.y, nullptr, v, vo);\n\n\tv = v * -1.0f;\n\ttpi.view = v;\n\n\tsavedBrush = activeBrush;\n\n\tif (wxGetKeyState(WXK_CONTROL)) {\n\t\tif (wxGetKeyState(WXK_ALT) && !segmentMode) {\n\t\t\tUnMaskBrush.setStrength(-maskBrush.getStrength());\n\t\t\tUnMaskBrush.setFocus(maskBrush.getFocus());\n\t\t\tUnMaskBrush.setSpacing(maskBrush.getSpacing());\n\t\t\tactiveBrush = &UnMaskBrush;\n\t\t}\n\t\telse {\n\t\t\tactiveBrush = &maskBrush;\n\t\t}\n\t}\n\telse if (activeBrush == &weightBrush) {\n\t\tstd::vector<std::string> normBones, notNormBones, brushBones, lockedBones;\n\t\tos->GetNormalizeBones(&normBones, &notNormBones);\n\n\t\tstd::string activeBone = os->GetActiveBone();\n\t\tstd::string xMirrorBone = os->GetXMirrorBone();\n\t\tbrushBones.push_back(activeBone);\n\n\t\tif (!xMirrorBone.empty())\n\t\t\tbrushBones.push_back(xMirrorBone);\n\n\t\tbool bHasNormBones = false;\n\t\tfor (auto& bone : normBones) {\n\t\t\tif (bone != activeBone && bone != xMirrorBone) {\n\t\t\t\tbrushBones.push_back(bone);\n\t\t\t\tbHasNormBones = true;\n\t\t\t}\n\t\t}\n\n\t\tif (bHasNormBones) {\n\t\t\tfor (auto& bone : notNormBones)\n\t\t\t\tif (bone != activeBone && bone != xMirrorBone)\n\t\t\t\t\tlockedBones.push_back(bone);\n\t\t}\n\t\telse {\n\t\t\tfor (auto& bone : notNormBones)\n\t\t\t\tif (bone != activeBone && bone != xMirrorBone)\n\t\t\t\t\tbrushBones.push_back(bone);\n\t\t}\n\n\t\tif (wxGetKeyState(WXK_ALT)) {\n\t\t\tunweightBrush.animInfo = os->project->GetWorkAnim();\n\t\t\tunweightBrush.boneNames = brushBones;\n\t\t\tunweightBrush.lockedBoneNames = lockedBones;\n\t\t\tunweightBrush.bSpreadWeight = bHasNormBones;\n\t\t\tunweightBrush.bXMirrorBone = !xMirrorBone.empty();\n\t\t\tunweightBrush.bNormalizeWeights = weightBrush.bNormalizeWeights;\n\t\t\tunweightBrush.setStrength(-weightBrush.getStrength());\n\t\t\tunweightBrush.setFocus(weightBrush.getFocus());\n\t\t\tunweightBrush.setSpacing(weightBrush.getSpacing());\n\t\t\tactiveBrush = &unweightBrush;\n\t\t}\n\t\telse if (wxGetKeyState(WXK_SHIFT)) {\n\t\t\tsmoothWeightBrush.animInfo = os->project->GetWorkAnim();\n\t\t\tsmoothWeightBrush.boneNames = brushBones;\n\t\t\tsmoothWeightBrush.lockedBoneNames = lockedBones;\n\t\t\tsmoothWeightBrush.bSpreadWeight = bHasNormBones;\n\t\t\tsmoothWeightBrush.bXMirrorBone = !xMirrorBone.empty();\n\t\t\tsmoothWeightBrush.bNormalizeWeights = weightBrush.bNormalizeWeights;\n\t\t\tsmoothWeightBrush.setStrength(weightBrush.getStrength() * 15.0f);\n\t\t\tsmoothWeightBrush.setFocus(weightBrush.getFocus());\n\t\t\tsmoothWeightBrush.setSpacing(weightBrush.getSpacing());\n\t\t\tactiveBrush = &smoothWeightBrush;\n\t\t}\n\t\telse {\n\t\t\tweightBrush.animInfo = os->project->GetWorkAnim();\n\t\t\tweightBrush.boneNames = brushBones;\n\t\t\tweightBrush.lockedBoneNames = lockedBones;\n\t\t\tweightBrush.bSpreadWeight = bHasNormBones;\n\t\t\tweightBrush.bXMirrorBone = !xMirrorBone.empty();\n\t\t}\n\t}\n\telse if (wxGetKeyState(WXK_ALT) && !segmentMode) {\n\t\tif (activeBrush == &inflateBrush) {\n\t\t\tactiveBrush = &deflateBrush;\n\t\t}\n\t\telse if (activeBrush == &deflateBrush) {\n\t\t\tactiveBrush = &inflateBrush;\n\t\t}\n\t\telse if (activeBrush == &maskBrush) {\n\t\t\tUnMaskBrush.setStrength(-activeBrush->getStrength());\n\t\t\tUnMaskBrush.setFocus(activeBrush->getFocus());\n\t\t\tUnMaskBrush.setSpacing(activeBrush->getSpacing());\n\t\t\tactiveBrush = &UnMaskBrush;\n\t\t}\n\t\telse if (activeBrush == &colorBrush) {\n\t\t\tuncolorBrush.setStrength(-activeBrush->getStrength());\n\t\t\tuncolorBrush.setFocus(activeBrush->getFocus());\n\t\t\tuncolorBrush.setSpacing(activeBrush->getSpacing());\n\t\t\tactiveBrush = &uncolorBrush;\n\t\t}\n\t\telse if (activeBrush == &alphaBrush) {\n\t\t\tunalphaBrush.setStrength(-activeBrush->getStrength());\n\t\t\tunalphaBrush.setFocus(activeBrush->getFocus());\n\t\t\tunalphaBrush.setSpacing(activeBrush->getSpacing());\n\t\t\tactiveBrush = &unalphaBrush;\n\t\t}\n\t}\n\telse if (activeBrush == &maskBrush && wxGetKeyState(WXK_SHIFT)) {\n\t\tsmoothMaskBrush.setStrength(activeBrush->getStrength());\n\t\tsmoothMaskBrush.setFocus(activeBrush->getFocus());\n\t\tsmoothMaskBrush.setSpacing(activeBrush->getSpacing());\n\t\tactiveBrush = &smoothMaskBrush;\n\t}\n\telse if (activeBrush != &weightBrush && activeBrush != &maskBrush && wxGetKeyState(WXK_SHIFT)) {\n\t\tactiveBrush = &smoothBrush;\n\t}\n\n\tactiveBrush->setRadius(brushSize);\n\tactiveBrush->setMirror(GetToolOptionXMirror());\n\tactiveBrush->setConnected(toolOptionConnectedOnly);\n\tactiveBrush->setRestrictPlane(toolOptionRestrictPlane);\n\tactiveBrush->setRestrictNormal(toolOptionRestrictNormal);\n\n\tif (activeBrush->Type() == TweakBrush::BrushType::Weight) {\n\t\tfor (auto& sel : os->GetSelectedItems()) {\n\t\t\tos->project->CreateSkinning(sel->GetShape());\n\n\t\t\tint boneIndex = os->project->GetWorkAnim()->GetShapeBoneIndex(sel->GetShape()->name.get(), os->GetActiveBone());\n\t\t\tif (boneIndex < 0)\n\t\t\t\tos->project->AddBoneRef(os->GetActiveBone());\n\t\t}\n\t}\n\n\tactiveStroke = std::make_unique<TweakStroke>(gls.GetActiveMeshes(), activeBrush, *undoHistory.PushState());\n\n\tif (os->bEditSlider) {\n\t\tactiveStroke->usp.sliderName = os->activeSlider;\n\t\tfloat sliderscale = os->project->SliderValue(os->activeSlider);\n\t\tif (sliderscale == 0.0)\n\t\t\tsliderscale = 1.0;\n\n\t\tactiveStroke->usp.sliderscale = sliderscale;\n\t}\n\n\tif (activeBrush->Type() == TweakBrush::BrushType::Undiff) {\n\t\tstd::vector<Mesh*> refMeshes = activeStroke->GetRefMeshes();\n\n\t\tstd::vector<std::vector<Vector3>> positionData;\n\t\tpositionData.resize(refMeshes.size());\n\n\t\tfor (size_t i = 0; i < refMeshes.size(); i++) {\n\t\t\t// Get base vertex positions, not current mesh position\n\t\t\tMesh* m = refMeshes[i];\n\t\t\tstd::vector<Vector3> basePosition;\n\n\t\t\tauto workNif = os->project->GetWorkNif();\n\t\t\tauto shape = workNif->FindBlockByName<NiShape>(m->shapeName);\n\t\t\tif (shape)\n\t\t\t\tworkNif->GetVertsForShape(shape, basePosition);\n\n\t\t\tfor (auto& p : basePosition)\n\t\t\t\tp = Mesh::TransformPosNifToMesh(p);\n\n\t\t\tpositionData[i] = std::move(basePosition);\n\t\t}\n\n\t\tactiveStroke->beginStroke(tpi, positionData);\n\t}\n\telse\n\t\tactiveStroke->beginStroke(tpi);\n\n\tif (activeBrush->Type() != TweakBrush::BrushType::Move)\n\t\tif (segmentMode) {\n\t\t\tif (os->PaintSegmentPartitionTriangles(hitMesh, hitTri, tpi.origin, activeBrush->getRadius())) {\n\t\t\t\tos->ShowSegment();\n\t\t\t\tos->ShowPartition();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tactiveStroke->updateStroke(tpi);\n\t\t}\n\n\treturn true;\n}\n\nvoid wxGLPanel::UpdateBrushStroke(const wxPoint& screenPos) {\n\tTweakPickInfo tpi;\n\n\tif (activeStroke) {\n\t\tbool hit = gls.UpdateCursor(screenPos.x, screenPos.y, true);\n\t\tMesh* hitMesh = nullptr;\n\t\tint hitTri = -1;\n\n\t\tif (activeBrush->Type() == TweakBrush::BrushType::Move) {\n\t\t\tVector3 pn;\n\t\t\tfloat pd;\n\t\t\t((TB_Move*)activeBrush)->GetWorkingPlane(pn, pd);\n\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, pn, pd);\n\t\t}\n\t\telse {\n\t\t\tif (!hit)\n\t\t\t\treturn;\n\n\t\t\thit = gls.CollideMeshes(screenPos.x, screenPos.y, tpi.origin, tpi.normal, false, &hitMesh, true, &hitTri);\n\t\t\tif (!hit || !hitMesh)\n\t\t\t\treturn;\n\n\t\t\ttpi.origin = hitMesh->TransformPosMeshToModel(tpi.origin);\n\t\t\ttpi.normal.Normalize();\n\t\t\ttpi.normal = hitMesh->TransformDirMeshToModel(tpi.normal);\n\t\t}\n\n\t\tVector3 v;\n\t\tVector3 vo;\n\t\tgls.GetPickRay(screenPos.x, screenPos.y, nullptr, v, vo);\n\n\t\tv = v * -1.0f;\n\t\ttpi.view = v;\n\t\tif (segmentMode) {\n\t\t\tif (os->PaintSegmentPartitionTriangles(hitMesh, hitTri, tpi.origin, activeBrush->getRadius())) {\n\t\t\t\tos->ShowSegment();\n\t\t\t\tos->ShowPartition();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tactiveStroke->updateStroke(tpi);\n\t\t}\n\n\t\tif (activeBrush->Type() == TweakBrush::BrushType::Weight) {\n\t\t\tstd::string selectedBone = os->GetActiveBone();\n\t\t\tif (!selectedBone.empty()) {\n\t\t\t\tos->ActiveShapesUpdated(undoHistory.GetCurState(), false);\n\t\t\t}\n\t\t}\n\n\t\tif (transformMode)\n\t\t\tShowTransformTool();\n\n\t\tif (segmentMode) {\n\t\t\tos->ShowSegment();\n\t\t\tos->ShowPartition();\n\t\t}\n\t}\n}\n\nvoid wxGLPanel::EndBrushStroke() {\n\tif (activeStroke) {\n\t\tactiveStroke->endStroke();\n\n\t\tTweakBrush::BrushType brushType = activeStroke->BrushType();\n\t\tif (brushType != TweakBrush::BrushType::Mask) {\n\t\t\tos->ActiveShapesUpdated(undoHistory.GetCurState());\n\n\t\t\tif (brushType == TweakBrush::BrushType::Weight) {\n\t\t\t\tstd::string selectedBone = os->GetActiveBone();\n\t\t\t\tif (!selectedBone.empty()) {\n\t\t\t\t\tos->HighlightBoneNamesWithWeights();\n\t\t\t\t\tos->UpdateBoneCounts();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!os->bEditSlider && brushType != TweakBrush::BrushType::Weight && brushType != TweakBrush::BrushType::Color && brushType != TweakBrush::BrushType::Alpha) {\n\t\t\t\t{\n\t\t\t\t\tUndoStateProject* usp = undoHistory.GetCurState();\n\t\t\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\t\t\tif (shape)\n\t\t\t\t\t\t\tos->project->ComputeUndoRestDiffs(shape, uss);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tfor (auto& s : os->project->GetWorkNif()->GetShapes()) {\n\t\t\t\t\tos->UpdateShapeSource(s);\n\t\t\t\t\tos->project->RefreshMorphShape(s);\n\t\t\t\t}\n\n\t\t\t\tif (os->project->bPose) {\n\t\t\t\t\tfor (auto& s : os->project->GetWorkNif()->GetShapes()) {\n\t\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\t\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (os->bEditSlider && os->project->bPose && brushType != TweakBrush::BrushType::Weight && brushType != TweakBrush::BrushType::Color && brushType != TweakBrush::BrushType::Alpha) {\n\t\t\t\tfor (auto& s : os->project->GetWorkNif()->GetShapes()) {\n\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (brushType == TweakBrush::BrushType::Mask) {\n\t\t\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\t\t\tundoHistory.PopState();\n\t\t}\n\n\t\tactiveStroke = nullptr;\n\t\tactiveBrush = savedBrush;\n\n\t\tif (transformMode)\n\t\t\tShowTransformTool();\n\n\t\tif (segmentMode) {\n\t\t\tos->ShowSegment();\n\t\t\tos->ShowPartition();\n\n\t\t\tif (os->currentTabButton)\n\t\t\t\tos->currentTabButton->SetPendingChanges();\n\t\t}\n\n\t\tos->UpdateUndoTools();\n\t}\n}\n\nbool wxGLPanel::StartTransform(const wxPoint& screenPos) {\n\tTweakPickInfo tpi;\n\tMesh* hitMesh;\n\tbool hit = gls.CollideOverlay(screenPos.x, screenPos.y, tpi.origin, tpi.normal, &hitMesh);\n\tif (!hit)\n\t\treturn false;\n\n\tif (!os->CheckEditableState())\n\t\treturn false;\n\n\ttpi.center = xformCenter;\n\txformCenterInitial = xformCenter;\n\n\tstd::string mname = hitMesh->shapeName;\n\tif (mname.find(\"Move\") != std::string::npos) {\n\t\ttranslateBrush.SetXFormType(0);\n\t\tswitch (mname[0]) {\n\t\t\tcase 'X':\n\t\t\t\ttpi.view = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tbreak;\n\t\t\tcase 'Y':\n\t\t\t\ttpi.view = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tbreak;\n\t\t\tcase 'Z':\n\t\t\t\ttpi.view = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\ttpi.normal = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse if (mname.find(\"Rotate\") != std::string::npos) {\n\t\ttranslateBrush.SetXFormType(1);\n\t\tswitch (mname[0]) {\n\t\t\tcase 'X':\n\t\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, Vector3(1.0f, 0.0f, 0.0f), tpi.center.x);\n\t\t\t\t//tpi.view = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tbreak;\n\t\t\tcase 'Y':\n\t\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, Vector3(0.0f, 1.0f, 0.0f), tpi.center.y);\n\t\t\t\t//tpi.view = Vector3(-1.0f, 0.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\tbreak;\n\t\t\tcase 'Z':\n\t\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, Vector3(0.0f, 0.0f, 1.0f), tpi.center.z);\n\t\t\t\t//tpi.view = Vector3(-1.0f, 0.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse if (mname.find(\"Scale\") != std::string::npos) {\n\t\tif (mname.find(\"Uniform\") == std::string::npos) {\n\t\t\ttranslateBrush.SetXFormType(2);\n\t\t\tswitch (mname[0]) {\n\t\t\t\tcase 'X':\n\t\t\t\t\ttpi.view = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Y':\n\t\t\t\t\ttpi.view = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Z':\n\t\t\t\t\ttpi.view = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\t\ttpi.normal = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\ttranslateBrush.SetXFormType(3);\n\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, Vector3(1.0f, 0.0f, 0.0f), tpi.center.x);\n\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, Vector3(0.0f, 1.0f, 0.0f), tpi.center.y);\n\t\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, Vector3(0.0f, 0.0f, 1.0f), tpi.center.z);\n\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t}\n\t}\n\telse\n\t\treturn false;\n\n\tif (!nodesMode && !bonesMode) {\n\t\tactiveStroke = std::make_unique<TweakStroke>(gls.GetActiveMeshes(), &translateBrush, *undoHistory.PushState());\n\n\t\tif (os->bEditSlider) {\n\t\t\tactiveStroke->usp.sliderName = os->activeSlider;\n\n\t\t\tfloat sliderscale = os->project->SliderValue(os->activeSlider);\n\t\t\tif (sliderscale == 0.0)\n\t\t\t\tsliderscale = 1.0;\n\n\t\t\tactiveStroke->usp.sliderscale = sliderscale;\n\t\t}\n\n\t\tactiveStroke->beginStroke(tpi);\n\t}\n\telse {\n\t\t// Bones/nodes-mode transform: edit the active bone/node directly.\n\t\t// The TweakStroke machinery isn't used here because we don't need\n\t\t// to modify any mesh vertices through a brush -- we change the\n\t\t// bone's local transform and let skinning update the meshes.\n\t\tconst std::string activeBone = os->GetActiveBone();\n\t\tif (activeBone.empty())\n\t\t\treturn false;\n\n\t\t// Only translate and rotate are supported for bones/nodes.\n\t\tif (mname.find(\"Move\") != std::string::npos)\n\t\t\tboneXformType = 0;\n\t\telse if (mname.find(\"Rotate\") != std::string::npos)\n\t\t\tboneXformType = 1;\n\t\telse\n\t\t\treturn false;\n\n\t\tboneXformPickStart = tpi.origin;\n\t\tboneXformPlaneNormalModel = tpi.normal;\n\t\tboneXformAxisModel = tpi.view;\n\t\tboneXformPlaneDist = tpi.origin.dot(tpi.normal);\n\n\t\t// Pose mode: edit poseTranVec/poseRotVec only (no NIF writes, no\n\t\t// undo).  Only AnimBones have pose data; plain NIF nodes do not.\n\t\tboneXformPoseMode = false;\n\t\tAnimBone* poseBPtr = AnimSkeleton::getInstance().GetBonePtr(activeBone);\n\t\tif (os->project->bPose && poseBPtr) {\n\t\t\tboneXformPoseMode = true;\n\t\t\txformInitialLocalToParent = poseBPtr->xformToParent;\n\t\t\t// M = parent_pose_to_global ∘ xformToParent\n\t\t\tMatTransform parentPoseToGlobal;\n\t\t\tif (poseBPtr->parent)\n\t\t\t\tparentPoseToGlobal = poseBPtr->parent->xformPoseToGlobal;\n\t\t\txformInitialParentToGlobal = parentPoseToGlobal.ComposeTransforms(poseBPtr->xformToParent);\n\t\t\tboneXformPoseInitialTran = poseBPtr->poseTranVec;\n\t\t\tboneXformPoseInitialRot = poseBPtr->poseRotVec;\n\t\t}\n\t\telse {\n\t\t\t// Capture the initial transforms of the active bone/node.\n\t\t\txformInitialLocalToParent = MatTransform();\n\t\t\txformInitialParentToGlobal = MatTransform();\n\n\t\t\tconst AnimBone* bPtr = AnimSkeleton::getInstance().GetBonePtr(activeBone);\n\t\t\tif (bPtr) {\n\t\t\t\txformInitialLocalToParent = bPtr->xformToParent;\n\t\t\t\tif (bPtr->parent)\n\t\t\t\t\txformInitialParentToGlobal = bPtr->parent->xformToGlobal;\n\t\t\t}\n\t\t\telse if (auto* nif = os->project->GetWorkNif()) {\n\t\t\t\tif (NiNode* node = nif->FindBlockByName<NiNode>(activeBone)) {\n\t\t\t\t\txformInitialLocalToParent = node->GetTransformToParent();\n\t\t\t\t\t// Compose the transforms of all ancestor nodes to build\n\t\t\t\t\t// parent-to-global.\n\t\t\t\t\tNiNode* p = nif->GetParentNode(node);\n\t\t\t\t\twhile (p) {\n\t\t\t\t\t\txformInitialParentToGlobal = p->GetTransformToParent().ComposeTransforms(xformInitialParentToGlobal);\n\t\t\t\t\t\tp = nif->GetParentNode(p);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t// No AnimBone and no NiNode -- nothing to edit.\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse\n\t\t\t\treturn false;\n\n\t\t\t// Push an undo state.  nodeEndXformToParent is filled in in\n\t\t\t// EndTransform; until then it equals nodeStartXformToParent.\n\t\t\tUndoStateProject* usp = undoHistory.PushState();\n\t\t\tusp->undoType = UndoType::NodeTransform;\n\t\t\tusp->boneName = activeBone;\n\t\t\tusp->nodeStartXformToParent = xformInitialLocalToParent;\n\t\t\tusp->nodeEndXformToParent = xformInitialLocalToParent;\n\t\t}\n\t}\n\n\tXMoveMesh->bVisible = false;\n\tYMoveMesh->bVisible = false;\n\tZMoveMesh->bVisible = false;\n\tXRotateMesh->bVisible = false;\n\tYRotateMesh->bVisible = false;\n\tZRotateMesh->bVisible = false;\n\tXScaleMesh->bVisible = false;\n\tYScaleMesh->bVisible = false;\n\tZScaleMesh->bVisible = false;\n\tScaleUniformMesh->bVisible = false;\n\thitMesh->bVisible = true;\n\treturn true;\n}\n\nvoid wxGLPanel::UpdateTransform(const wxPoint& screenPos) {\n\tTweakPickInfo tpi;\n\tVector3 pn;\n\tfloat pd;\n\n\tif (!nodesMode && !bonesMode) {\n\t\ttranslateBrush.GetWorkingPlane(pn, pd);\n\t\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, pn, pd);\n\t\tactiveStroke->updateStroke(tpi);\n\t\tShowTransformTool();\n\t\treturn;\n\t}\n\n\t// Bones/nodes-mode transform: compute the bone/node's new local transform\n\t// directly from the drag and apply it.  Meshes update live via skinning.\n\tconst std::string activeBone = os->GetActiveBone();\n\tif (activeBone.empty()) {\n\t\tShowTransformTool();\n\t\treturn;\n\t}\n\n\t// Intersect the mouse ray with the pick plane captured in StartTransform.\n\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, boneXformPlaneNormalModel, boneXformPlaneDist);\n\n\tif (boneXformPoseMode) {\n\t\tAnimBone* bPtr = AnimSkeleton::getInstance().GetBonePtr(activeBone);\n\t\tif (!bPtr) {\n\t\t\tShowTransformTool();\n\t\t\treturn;\n\t\t}\n\n\t\t// M = parent_pose_to_global ∘ xformToParent  (captured in\n\t\t// xformInitialParentToGlobal).  Edits go into poseTranVec/poseRotVec\n\t\t// which are applied in the bone's own CS before xformToParent.\n\t\tif (boneXformType == 0) {\n\t\t\tconst float t = (tpi.origin - boneXformPickStart).dot(boneXformAxisModel);\n\t\t\tconst Vector3 axisGlobal = Mesh::TransformDirMeshToNif(boneXformAxisModel);\n\t\t\tconst Vector3 globalOffset = axisGlobal * Mesh::TransformDistMeshToNif(t);\n\t\t\tconst Vector3 localOffset = xformInitialParentToGlobal.InverseTransform().ApplyTransformToDiff(globalOffset);\n\t\t\tbPtr->poseTranVec = boneXformPoseInitialTran + localOffset;\n\t\t}\n\t\telse if (boneXformType == 1) {\n\t\t\tconst Vector3 a = boneXformPickStart - xformCenterInitial;\n\t\t\tconst Vector3 b = tpi.origin - xformCenterInitial;\n\t\t\tif (a.length() > EPSILON && b.length() > EPSILON) {\n\t\t\t\tconst float sinA = a.cross(b).dot(boneXformPlaneNormalModel);\n\t\t\t\tconst float cosA = a.dot(b);\n\t\t\t\tconst float angle = std::atan2(sinA, cosA);\n\n\t\t\t\tVector3 axisGlobal = Mesh::TransformDirMeshToNif(boneXformPlaneNormalModel);\n\t\t\t\tVector3 axisLocal = xformInitialParentToGlobal.rotation.Transpose() * axisGlobal;\n\t\t\t\tconst float axisLen = axisLocal.length();\n\t\t\t\tif (axisLen > EPSILON) {\n\t\t\t\t\taxisLocal /= axisLen;\n\t\t\t\t\tconst Matrix3 rot = RotVecToMat(axisLocal * angle);\n\t\t\t\t\tconst Matrix3 newPoseRot = rot * RotVecToMat(boneXformPoseInitialRot);\n\t\t\t\t\tbPtr->poseRotVec = RotMatToVec(newPoseRot);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tbPtr->UpdatePoseTransform();\n\n\t\t// Live mesh update to show the pose change immediately.\n\t\tif (auto* nif = os->project->GetWorkNif()) {\n\t\t\tfor (auto& s : nif->GetShapes()) {\n\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t\t}\n\t\t}\n\n\t\t// Keep the pose-sliders GUI in sync with the new values.\n\t\tos->PoseToGUI();\n\n\t\tUpdateBones();\n\t\tUpdateNodes();\n\t\tShowTransformTool();\n\t\treturn;\n\t}\n\n\tMatTransform newToParent = xformInitialLocalToParent;\n\n\tif (boneXformType == 0) {\n\t\t// Translate along the gizmo's axis.  Project the drag vector onto\n\t\t// the axis in model space, convert to nif distance, then map the\n\t\t// resulting global offset into parent space (so scale/rotation of\n\t\t// ancestor nodes is handled correctly).\n\t\tconst float t = (tpi.origin - boneXformPickStart).dot(boneXformAxisModel);\n\t\tconst Vector3 axisGlobal = Mesh::TransformDirMeshToNif(boneXformAxisModel);\n\t\tconst Vector3 globalOffset = axisGlobal * Mesh::TransformDistMeshToNif(t);\n\t\tconst Vector3 parentOffset = xformInitialParentToGlobal.InverseTransform().ApplyTransformToDiff(globalOffset);\n\t\tnewToParent.translation = xformInitialLocalToParent.translation + parentOffset;\n\t}\n\telse if (boneXformType == 1) {\n\t\t// Rotate about the gizmo ring's axis.  Angle is the signed angle\n\t\t// between the initial and current pick vectors in the rotation plane.\n\t\tconst Vector3 a = boneXformPickStart - xformCenterInitial;\n\t\tconst Vector3 b = tpi.origin - xformCenterInitial;\n\t\tif (a.length() > EPSILON && b.length() > EPSILON) {\n\t\t\tconst float sinA = a.cross(b).dot(boneXformPlaneNormalModel);\n\t\t\tconst float cosA = a.dot(b);\n\t\t\tconst float angle = std::atan2(sinA, cosA);\n\n\t\t\t// Convert axis from model to global, then to parent.\n\t\t\tVector3 axisGlobal = Mesh::TransformDirMeshToNif(boneXformPlaneNormalModel);\n\t\t\tVector3 axisParent = xformInitialParentToGlobal.rotation.Transpose() * axisGlobal;\n\t\t\tconst float axisLen = axisParent.length();\n\t\t\tif (axisLen > EPSILON) {\n\t\t\t\taxisParent /= axisLen;\n\t\t\t\tconst Matrix3 rot = RotVecToMat(axisParent * angle);\n\t\t\t\tnewToParent.rotation = rot * xformInitialLocalToParent.rotation;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Apply the new transform to the AnimBone (if any) and to the NIF node.\n\t// We deliberately do not recalculate xformSkinToBone: that way the mesh\n\t// follows the bone through skinning, the active pose updates live, and\n\t// the \"check for bad bones\" residual correctly flags the new mismatch.\n\tauto* nif = os->project->GetWorkNif();\n\tAnimBone* bPtr = AnimSkeleton::getInstance().GetBonePtr(activeBone);\n\tif (bPtr)\n\t\tbPtr->SetTransformBoneToParent(newToParent);\n\tif (nif)\n\t\tnif->SetNodeTransformToParent(activeBone, newToParent);\n\n\t// Record the end state on the open undo entry so an in-progress drag is\n\t// already undo-able if the stroke is canceled.\n\tif (UndoStateProject* usp = undoHistory.GetCurState()) {\n\t\tif (usp->undoType == UndoType::NodeTransform && usp->boneName == activeBone)\n\t\t\tusp->nodeEndXformToParent = newToParent;\n\t}\n\n\t// Live mesh update (so skinned vertices follow the bone).\n\tif (nif) {\n\t\tfor (auto& s : nif->GetShapes()) {\n\t\t\tstd::vector<Vector3> verts;\n\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t}\n\t}\n\n\tUpdateBones();\n\tUpdateNodes();\n\tShowTransformTool();\n}\n\nvoid wxGLPanel::EndTransform() {\n\tif (!nodesMode && !bonesMode) {\n\t\tactiveStroke->endStroke();\n\t\tactiveStroke = nullptr;\n\n\t\tos->ActiveShapesUpdated(undoHistory.GetCurState());\n\t\tif (!os->bEditSlider) {\n\t\t\t{\n\t\t\t\tUndoStateProject* usp = undoHistory.GetCurState();\n\t\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\t\tif (shape)\n\t\t\t\t\t\tos->project->ComputeUndoRestDiffs(shape, uss);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto& s : os->project->GetWorkNif()->GetShapes()) {\n\t\t\t\tos->UpdateShapeSource(s);\n\t\t\t\tos->project->RefreshMorphShape(s);\n\t\t\t}\n\n\t\t\tif (os->project->bPose) {\n\t\t\t\tfor (auto& s : os->project->GetWorkNif()->GetShapes()) {\n\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse if (os->project->bPose) {\n\t\t\tfor (auto& s : os->project->GetWorkNif()->GetShapes()) {\n\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t\t}\n\t\t}\n\t}\n\telse {\n\t\t// Bones/nodes-mode: sync the AnimInfo's bone transforms out to the\n\t\t// NIF, refresh the bone-tree bad-bone icons, and mark the project\n\t\t// as modified.  In pose mode we only edited poseTranVec/poseRotVec\n\t\t// on the AnimBone -- no NIF writes, no undo, no pending changes.\n\t\tif (!boneXformPoseMode) {\n\t\t\tif (auto* nif = os->project->GetWorkNif()) {\n\t\t\t\tif (auto* workAnim = os->project->GetWorkAnim())\n\t\t\t\t\tworkAnim->WriteNodesToNif(nif);\n\t\t\t}\n\t\t\tos->RefreshBoneTreeBadBoneIcons();\n\t\t\tos->SetPendingChanges();\n\t\t}\n\t\tboneXformPoseMode = false;\n\t}\n\n\tShowTransformTool();\n\tos->UpdateUndoTools();\n}\n\nbool wxGLPanel::StartPivotPosition(const wxPoint& screenPos) {\n\tTweakPickInfo tpi;\n\tMesh* hitMesh;\n\tbool hit = gls.CollideOverlay(screenPos.x, screenPos.y, tpi.origin, tpi.normal, &hitMesh);\n\tif (!hit)\n\t\treturn false;\n\n\ttpi.center = pivotPosition;\n\n\tstd::string mname = hitMesh->shapeName;\n\tif (mname.find(\"PivotMesh\") != std::string::npos) {\n\t\ttranslateBrush.SetXFormType(0);\n\t\tswitch (mname[0]) {\n\t\t\tcase 'X':\n\t\t\t\ttpi.view = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tbreak;\n\t\t\tcase 'Y':\n\t\t\t\ttpi.view = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\ttpi.normal = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tbreak;\n\t\t\tcase 'Z':\n\t\t\t\ttpi.view = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\ttpi.normal = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tbreak;\n\t\t}\n\t}\n\telse\n\t\treturn false;\n\n\tstd::vector<Mesh*> strokeMeshes{hitMesh};\n\tactiveStroke = std::make_unique<TweakStroke>(strokeMeshes, &translateBrush, *undoHistory.PushState());\n\tactiveStroke->beginStroke(tpi);\n\n\tXPivotMesh->bVisible = false;\n\tYPivotMesh->bVisible = false;\n\tZPivotMesh->bVisible = false;\n\tPivotCenterMesh->bVisible = false;\n\thitMesh->bVisible = true;\n\treturn true;\n}\n\nvoid wxGLPanel::UpdatePivotPosition(const wxPoint& screenPos) {\n\tTweakPickInfo tpi;\n\tVector3 pn;\n\tfloat pd;\n\n\ttranslateBrush.GetWorkingPlane(pn, pd);\n\tgls.CollidePlane(screenPos.x, screenPos.y, tpi.origin, pn, pd);\n\n\tactiveStroke->updateStroke(tpi);\n}\n\nvoid wxGLPanel::EndPivotPosition() {\n\tactiveStroke->endStroke();\n\n\tstd::vector<Mesh*> refMeshes = activeStroke->GetRefMeshes();\n\tif (refMeshes.size() > 0) {\n\t\tUndoStateShape& uss = activeStroke->usp.usss[0];\n\t\tif (uss.pointStartState.size() > 0 && uss.pointEndState.size() > 0) {\n\t\t\tVector3& pivotStartStatePos = uss.pointStartState[0];\n\t\t\tVector3& pivotEndStatePos = uss.pointEndState[0];\n\t\t\tVector3 pivotDiff = pivotEndStatePos - pivotStartStatePos;\n\t\t\tpivotPosition += pivotDiff;\n\t\t}\n\t}\n\n\tactiveStroke = nullptr;\n\tShowPivot();\n}\n\nbool wxGLPanel::SelectVertex(const wxPoint& screenPos) {\n\tint vertIndex;\n\tif (!gls.GetCursorVertex(screenPos.x, screenPos.y, &vertIndex))\n\t\treturn false;\n\n\tif (os->activeItem) {\n\t\tMesh* m = GetMesh(os->activeItem->GetShape()->name.get());\n\t\tif (m) {\n\t\t\tdouble newval = m->mask[vertIndex];\n\t\t\tif (wxGetKeyState(WXK_CONTROL))\n\t\t\t\tnewval = 1.0f;\n\t\t\telse if (!segmentMode)\n\t\t\t\tnewval = 0.0f;\n\n\t\t\tif (m->mask[vertIndex] != newval) {\n\t\t\t\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\t\t\t\tusp->undoType = UndoType::Mask;\n\t\t\t\tusp->usss.emplace_back();\n\t\t\t\tUndoStateShape& uss = usp->usss.back();\n\t\t\t\tuss.shapeName = m->shapeName;\n\t\t\t\tuss.pointStartState[vertIndex].x = m->mask[vertIndex];\n\t\t\t\tuss.pointEndState[vertIndex].x = newval;\n\t\t\t\tApplyUndoState(usp, false);\n\n\t\t\t\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\t\t\t\tGetUndoHistory()->PopState();\n\n\t\t\t\tos->UpdateUndoTools();\n\t\t\t}\n\t\t}\n\t}\n\n\tif (transformMode)\n\t\tShowTransformTool();\n\n\treturn true;\n}\n\nbool wxGLPanel::StartPickVertex() {\n\tif (lastHitResult.hitMeshName.empty() || lastHitResult.hoverPoint < 0)\n\t\treturn false;\n\n\tmouseDownMeshName = lastHitResult.hitMeshName;\n\tmouseDownPoint = lastHitResult.hoverPoint;\n\treturn true;\n}\n\nvoid wxGLPanel::UpdatePickVertex(const wxPoint& screenPos) {\n\tGLSurface::CursorHitResult hitResult{};\n\n\tbool hit = gls.UpdateCursor(screenPos.x, screenPos.y, true, &hitResult);\n\tif (!hit || hitResult.hitMeshName != mouseDownMeshName || hitResult.hoverPoint != mouseDownPoint)\n\t\tgls.HidePointCursor();\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::EndPickVertex() {\n\tif (lastHitResult.hitMeshName != mouseDownMeshName || lastHitResult.hoverPoint != mouseDownPoint)\n\t\treturn;\n\n\t// Clear PickVertex state so no accidents can happen\n\tlastHitResult.hitMeshName.clear();\n\tgls.HidePointCursor();\n\n\tif (activeTool == ToolID::CollapseVertex)\n\t\tClickCollapseVertex();\n}\n\nvoid wxGLPanel::ClickCollapseVertex() {\n\tMesh* m = GetMesh(mouseDownMeshName);\n\tif (!m || mouseDownPoint < 0)\n\t\treturn;\n\n\tauto workNif = os->project->GetWorkNif();\n\tif (!workNif)\n\t\treturn;\n\n\tNiShape* shape = workNif->FindBlockByName<NiShape>(mouseDownMeshName);\n\tif (!shape)\n\t\treturn;\n\n\t// Make list of this vertex and its welded vertices.\n\tstd::vector<uint16_t> verts;\n\tm->GetWeldSet(mouseDownPoint, verts);\n\n\tstd::sort(verts.begin(), verts.end());\n\n\t// Prepare list of changes\n\tUndoStateShape uss;\n\tuss.shapeName = mouseDownMeshName;\n\tif (!os->project->PrepareCollapseVertex(shape, uss, verts)) {\n\t\twxMessageBox(_(\"The vertex picked has more than three connections.\"), _(\"Error\"), wxICON_ERROR, os);\n\t\treturn;\n\t}\n\n\t// Push changes onto undo stack and execute.\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.push_back(std::move(uss));\n\tApplyUndoState(usp, false);\n\n\tos->UpdateUndoTools();\n\tos->SetPendingChanges();\n}\n\nbool wxGLPanel::StartMoveVertex(const wxPoint& screenPos) {\n\tif (lastHitResult.hitMeshName.empty() || lastHitResult.hoverPoint < 0)\n\t\treturn false;\n\n\tMesh* m = GetMesh(lastHitResult.hitMeshName);\n\tif (!m)\n\t\treturn false;\n\n\tif (!os->CheckEditableState())\n\t\treturn false;\n\n\tmouseDownMeshName = lastHitResult.hitMeshName;\n\tmouseDownPoint = lastHitResult.hoverPoint;\n\tmouseHasMovedSinceStart = false;\n\tmouseDownPointNormal = m->TransformDirMeshToModel(m->norms[mouseDownPoint]);\n\tmoveVertexOperation = MoveVertexOperation::None;\n\n\tVector3 viewOrigin;\n\tgls.GetPickRay(screenPos.x, screenPos.y, nullptr, mouseDownViewDir, viewOrigin);\n\tmouseDownViewDir *= -1.0f;\n\n\t// snapDistance: shortest edge length of triangle under pointer\n\tconst Triangle& tri = m->tris[lastHitResult.hoverTri];\n\tVector3 gtp1 = m->TransformPosMeshToModel(m->verts[tri.p1]);\n\tVector3 gtp2 = m->TransformPosMeshToModel(m->verts[tri.p2]);\n\tVector3 gtp3 = m->TransformPosMeshToModel(m->verts[tri.p3]);\n\tsnapDistance = gtp1.DistanceTo(gtp2);\n\tfloat elen = gtp2.DistanceTo(gtp3);\n\tif (snapDistance > elen)\n\t\tsnapDistance = elen;\n\telen = gtp3.DistanceTo(gtp1);\n\tif (snapDistance > elen)\n\t\tsnapDistance = elen;\n\n\tUndoStateProject* usp = undoHistory.PushState();\n\tusp->usss.emplace_back();\n\tusp->usss[0].shapeName = mouseDownMeshName;\n\tusp->usss[0].pointEndState[mouseDownPoint] = usp->usss[0].pointStartState[mouseDownPoint] = lastHitResult.hoverMeshCoord;\n\n\tif (mouseDownMirrorPoint != -1)\n\t\tusp->usss[0].pointEndState[mouseDownMirrorPoint] = usp->usss[0].pointStartState[mouseDownMirrorPoint] = m->verts[mouseDownMirrorPoint];\n\n\tif (os->bEditSlider) {\n\t\tusp->sliderName = os->activeSlider;\n\t\tfloat sliderscale = os->project->SliderValue(os->activeSlider);\n\t\tif (sliderscale == 0.0)\n\t\t\tsliderscale = 1.0;\n\n\t\tusp->sliderscale = sliderscale;\n\t}\n\n\twxPoint p;\n\tgls.ProjectPointToScreen(lastHitResult.hoverRealCoord, p.x, p.y);\n\tmouseDownOffset = screenPos - p;\n\n\tgls.SetPointCursor(lastHitResult.hoverRealCoord);\n\tgls.SetCenterCursor(lastHitResult.hoverRealCoord);\n\tgls.ShowCursor(true);\n\n\treturn true;\n}\n\nvoid wxGLPanel::UpdateMoveVertex(const wxPoint& screenPos) {\n\tMesh* m = GetMesh(mouseDownMeshName);\n\tif (!m || mouseDownPoint < 0)\n\t\treturn;\n\n\tUndoStateProject* usp = undoHistory.GetCurState();\n\tif (!usp)\n\t\treturn;\n\tUndoStateShape& uss = usp->usss[0];\n\n\t// Restore original position in m so CollideMeshes and IntersectSphere\n\t// will work.\n\tVector3 mesholdpos = uss.pointStartState[mouseDownPoint];\n\tm->verts[mouseDownPoint] = mesholdpos;\n\tif (mouseDownMirrorPoint != -1)\n\t\tm->verts[mouseDownMirrorPoint] = uss.pointStartState[mouseDownMirrorPoint];\n\tVector3 oldpos = m->TransformPosMeshToModel(mesholdpos);\n\n\t// Since the pointer can be offset from screenPos, calculate a point\n\t// to display at screenPos.  We do this by intersecting the\n\t// screenPos ray with the plane perpendicular to mouseDownViewDir at oldpos.\n\t// This will also be our default for newpos if all tool options are off.\n\tVector3 pointerPoint;\n\tgls.CollidePlane(screenPos.x, screenPos.y, pointerPoint, mouseDownViewDir, mouseDownViewDir.dot(oldpos));\n\n\t// Determining newpos: 1. intersect screenPos-ray with plane or surface.\n\tVector3 newpos = pointerPoint;\n\tmoveVertexOperation = MoveVertexOperation::Move;\n\tif (toolOptionRestrictSurface) {\n\t\tVector3 hitpt, hitnormal;\n\t\tMesh* hitmesh = nullptr;\n\t\tbool hit = gls.CollideMeshes(screenPos.x, screenPos.y, hitpt, hitnormal, false, &hitmesh);\n\t\tif (!hit || !hitmesh) {\n\t\t\tnewpos = oldpos;\n\t\t\tmoveVertexOperation = MoveVertexOperation::None;\n\t\t}\n\t\telse\n\t\t\tnewpos = hitmesh->TransformPosMeshToModel(hitpt);\n\t}\n\telse if (toolOptionRestrictPlane) {\n\t\tgls.CollidePlane(screenPos.x, screenPos.y, newpos, mouseDownPointNormal, mouseDownPointNormal.dot(oldpos));\n\t}\n\n\t// 2. Project onto normal\n\tif (toolOptionRestrictNormal && moveVertexOperation != MoveVertexOperation::None) {\n\t\tnewpos = oldpos + mouseDownPointNormal * mouseDownPointNormal.dot(newpos - oldpos);\n\t}\n\n\t// 3. Snap to nearest valid point\n\tif ((toolOptionMerge || toolOptionWeld) && moveVertexOperation != MoveVertexOperation::None) {\n\t\t// Get adjacent points (not including welded points)\n\t\tstd::unordered_set<int> adjPts;\n\t\tif (m->vertEdges && m->edges) {\n\t\t\tfor (int ei : m->vertEdges[mouseDownPoint]) {\n\t\t\t\tconst Edge& edge = m->edges[ei];\n\t\t\t\tif (edge.p1 != mouseDownPoint)\n\t\t\t\t\tadjPts.insert(edge.p1);\n\t\t\t\tif (edge.p2 != mouseDownPoint)\n\t\t\t\t\tadjPts.insert(edge.p2);\n\t\t\t}\n\t\t}\n\n\t\tint closestPoint = -1;\n\t\tMesh* closestMesh = nullptr;\n\t\tfloat closestDist = snapDistance;\n\n\t\tfor (Mesh* tm : gls.GetActiveMeshes()) {\n\t\t\tVector3 viewDir, viewOrigin;\n\t\t\tgls.GetPickRay(screenPos.x, screenPos.y, tm, viewDir, viewOrigin);\n\n\t\t\tVector3 tmnewpos = tm->TransformPosModelToMesh(newpos);\n\t\t\tfloat tmSnapDistance = tm->TransformDistModelToMesh(snapDistance);\n\n\t\t\tstd::vector<IntersectResult> iresults;\n\t\t\tif (tm->bvh && tm->bvh->IntersectSphere(tmnewpos, tmSnapDistance, &iresults)) {\n\t\t\t\tfor (const IntersectResult& ir : iresults) {\n\t\t\t\t\tconst Triangle& t = tm->tris[ir.HitFacet];\n\t\t\t\t\tfor (int tvi = 0; tvi < 3; ++tvi) {\n\t\t\t\t\t\tint tp = t[tvi];\n\t\t\t\t\t\tif (tm == m && tp == mouseDownPoint)\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\tif (tm == m && adjPts.count(tp) != 0)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\t// Calculate distance in plane perpendicular to view\n\t\t\t\t\t\tVector3 diff = tm->verts[tp] - tmnewpos;\n\t\t\t\t\t\tdiff -= viewDir * viewDir.dot(diff);\n\t\t\t\t\t\tfloat d = tm->TransformDistMeshToModel(diff.length());\n\t\t\t\t\t\tif (d >= closestDist)\n\t\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\t\tclosestPoint = tp;\n\t\t\t\t\t\tclosestMesh = tm;\n\t\t\t\t\t\tclosestDist = d;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (closestPoint != -1) {\n\t\t\tNiShape* s1 = os->project->GetWorkNif()->FindBlockByName<NiShape>(mouseDownMeshName);\n\t\t\tNiShape* s2 = os->project->GetWorkNif()->FindBlockByName<NiShape>(closestMesh->shapeName);\n\t\t\tbool canWeld = toolOptionWeld && s1 && s2 && os->project->PointsHaveDifferingWeightsOrDiffs(s1, mouseDownPoint, s2, closestPoint);\n\t\t\tbool canMerge = toolOptionMerge && m == closestMesh;\n\t\t\tif (canWeld || canMerge) {\n\t\t\t\tnewpos = closestMesh->TransformPosMeshToModel(closestMesh->verts[closestPoint]);\n\t\t\t\tif (canWeld)\n\t\t\t\t\tmoveVertexOperation = MoveVertexOperation::Weld;\n\t\t\t\telse if (canMerge)\n\t\t\t\t\tmoveVertexOperation = MoveVertexOperation::Merge;\n\t\t\t\tmoveVertexTarget = closestPoint;\n\t\t\t\tmoveVertexWeldTargetMeshName = closestMesh->shapeName;\n\t\t\t}\n\t\t}\n\t}\n\n\tVector3 meshnewpos = m->TransformPosModelToMesh(newpos);\n\tuss.pointEndState[mouseDownPoint] = meshnewpos;\n\tm->verts[mouseDownPoint] = meshnewpos;\n\tgls.SetPointCursor(newpos);\n\tgls.SetCenterCursor(pointerPoint);\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n\tgls.ShowCursor(true);\n\n\tif (mouseDownMirrorPoint != -1) {\n\t\tVector3 mp = newpos;\n\t\tmp.x = -mp.x;\n\t\tmp = m->TransformPosModelToMesh(mp);\n\t\tuss.pointEndState[mouseDownMirrorPoint] = mp;\n\t\tm->verts[mouseDownMirrorPoint] = mp;\n\t\tgls.ShowMirrorPointCursor(mp, m);\n\t}\n}\n\nvoid wxGLPanel::EndMoveVertex() {\n\tisMovingVertex = false;\n\tUndoStateProject* usp = undoHistory.GetCurState();\n\tif (!usp)\n\t\treturn;\n\n\tif (moveVertexOperation == MoveVertexOperation::None) {\n\t\tCancelMoveVertex();\n\t\treturn;\n\t}\n\n\tbool isWeld = moveVertexOperation == MoveVertexOperation::Weld;\n\tbool isMerge = moveVertexOperation == MoveVertexOperation::Merge;\n\n\tif (isWeld || isMerge) {\n\t\tNiShape* s1 = os->project->GetWorkNif()->FindBlockByName<NiShape>(mouseDownMeshName);\n\t\tNiShape* s2 = s1;\n\t\tif (isWeld)\n\t\t\ts2 = os->project->GetWorkNif()->FindBlockByName<NiShape>(moveVertexWeldTargetMeshName);\n\n\t\tbool p1b = os->project->IsVertexOnBoundary(s1, mouseDownPoint);\n\t\tbool p2b = os->project->IsVertexOnBoundary(s2, moveVertexTarget);\n\n\t\tif (!p1b || !p2b) {\n\t\t\tint response = wxMessageBox(\n\t\t\t\t!p1b ? !p2b ? _(\"Neither the selected nor target vertices are on the mesh boundary.  It is recommended that you only weld or merge boundary vertices.  Continue?\")\n\t\t\t\t\t\t\t: _(\"The selected vertex is not on the mesh boundary.  It is recommended that you only weld or merge boundary vertices.  Continue?\")\n\t\t\t\t\t : _(\"The target vertex is not on the mesh boundary.  It is recommended that you only weld or merge boundary vertices.  Continue?\"),\n\t\t\t\t_(\"Weld/Merge Non-Boundary Vertices\"),\n\t\t\t\twxOK | wxCANCEL | wxCANCEL_DEFAULT,\n\t\t\t\tos);\n\n\t\t\tif (response == wxCANCEL) {\n\t\t\t\tCancelMoveVertex();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tusp->undoType = UndoType::Mesh;\n\t\tusp->sliderName.clear();\n\t\tusp->usss[0].pointStartState.clear();\n\t\tusp->usss[0].pointEndState.clear();\n\n\t\tif (isWeld)\n\t\t\tos->project->PrepareWeldVertex(s1, usp->usss[0], mouseDownPoint, moveVertexTarget, s2);\n\n\t\tif (isMerge)\n\t\t\tos->project->PrepareMergeVertex(s1, usp->usss[0], mouseDownPoint, moveVertexTarget);\n\t}\n\n\tApplyUndoState(usp, false);\n\n\tos->UpdateUndoTools();\n\tos->SetPendingChanges();\n}\n\nvoid wxGLPanel::CancelMoveVertex() {\n\tUndoStateProject* usp = undoHistory.GetCurState();\n\tif (!usp)\n\t\treturn;\n\n\tApplyUndoState(usp, true);\n\tundoHistory.PopState();\n}\n\nbool wxGLPanel::StartPickEdge() {\n\tif (lastHitResult.hitMeshName.empty() || (lastHitResult.hoverEdge.p1 == 0 && lastHitResult.hoverEdge.p2 == 0))\n\t\treturn false;\n\n\tmouseDownMeshName = lastHitResult.hitMeshName;\n\tmouseDownEdge = lastHitResult.hoverEdge;\n\treturn true;\n}\n\nvoid wxGLPanel::UpdatePickEdge(const wxPoint& screenPos) {\n\tGLSurface::CursorHitResult hitResult{};\n\n\tbool hit = gls.UpdateCursor(screenPos.x, screenPos.y, true, &hitResult);\n\tif (!hit || hitResult.hitMeshName != mouseDownMeshName || !hitResult.hoverEdge.CompareIndices(mouseDownEdge))\n\t\tgls.HideSegCursor();\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::EndPickEdge() {\n\tif (lastHitResult.hitMeshName != mouseDownMeshName || !lastHitResult.hoverEdge.CompareIndices(mouseDownEdge))\n\t\treturn;\n\n\t// Clear PickEdge state so no accidents can happen\n\tlastHitResult.hitMeshName.clear();\n\tgls.HideSegCursor();\n\n\tif (activeTool == ToolID::FlipEdge)\n\t\tClickFlipEdge();\n\tif (activeTool == ToolID::SplitEdge)\n\t\tClickSplitEdge();\n}\n\nvoid wxGLPanel::ClickFlipEdge() {\n\tif (mouseDownMeshName.empty() || mouseDownEdge.p1 < 0 || mouseDownEdge.p1 == mouseDownEdge.p2)\n\t\treturn;\n\n\tNiShape* shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(mouseDownMeshName);\n\tif (!shape)\n\t\treturn;\n\n\t// Prepare list of changes\n\tUndoStateShape uss;\n\tuss.shapeName = mouseDownMeshName;\n\tif (!os->project->PrepareFlipEdge(shape, uss, mouseDownEdge)) {\n\t\twxMessageBox(_(\"The edge picked is on the surface boundary.  Pick an interior edge.\"), _(\"Error\"), wxICON_ERROR, os);\n\t\treturn;\n\t}\n\n\t// Push changes onto undo stack and execute.\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.push_back(std::move(uss));\n\tApplyUndoState(usp, false);\n\n\tos->UpdateUndoTools();\n\tos->SetPendingChanges();\n}\n\nvoid wxGLPanel::ClickSplitEdge() {\n\tif (mouseDownMeshName.empty() || mouseDownEdge.p1 < 0 || mouseDownEdge.p1 == mouseDownEdge.p2)\n\t\treturn;\n\n\tMesh* m = GetMesh(mouseDownMeshName);\n\tif (!m)\n\t\treturn;\n\n\tauto workNif = os->project->GetWorkNif();\n\tif (!workNif)\n\t\treturn;\n\n\tNiShape* shape = workNif->FindBlockByName<NiShape>(mouseDownMeshName);\n\tif (!shape)\n\t\treturn;\n\n\tbool shiftDown = wxGetKeyState(WXK_SHIFT);\n\n\tconstexpr uint16_t maxVertIndex = std::numeric_limits<uint16_t>().max();\n\tuint32_t maxTriIndex = std::numeric_limits<uint16_t>().max();\n\n\tif (workNif->GetHeader().GetVersion().IsFO4() || workNif->GetHeader().GetVersion().IsFO76())\n\t\tmaxTriIndex = std::numeric_limits<uint32_t>().max();\n\n\tif (shape->GetNumVertices() > maxVertIndex - 2) {\n\t\twxMessageBox(_(\"The shape has reached the vertex count limit.\"), _(\"Error\"), wxICON_ERROR, os);\n\t\treturn;\n\t}\n\n\tif (shape->GetNumTriangles() > maxTriIndex - 2) {\n\t\twxMessageBox(_(\"The shape has reached the triangle count limit.\"), _(\"Error\"), wxICON_ERROR, os);\n\t\treturn;\n\t}\n\n\tstd::vector<bool> pincs(shape->GetNumVertices(), false);\n\tpincs[mouseDownEdge.p1] = true;\n\tpincs[mouseDownEdge.p2] = true;\n\n\t// Prepare list of changes\n\tUndoStateShape uss;\n\tuss.shapeName = mouseDownMeshName;\n\tbool noCurveOffset = shiftDown;\n\tif (!os->project->PrepareRefineMesh(shape, uss, pincs, m->weldVerts, noCurveOffset)) {\n\t\twxMessageBox(_(\"The edge picked has multiple triangles of the same orientation.  Correct the orientations before splitting.\"), _(\"Error\"), wxICON_ERROR, os);\n\t\treturn;\n\t}\n\n\t// Push changes onto undo stack and execute.\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mesh;\n\tusp->usss.push_back(std::move(uss));\n\tApplyUndoState(usp, false);\n\n\tos->UpdateUndoTools();\n\tos->SetPendingChanges();\n}\n\nstd::unordered_map<std::string, std::vector<float>> wxGLPanel::StashMasks() {\n\tstd::unordered_map<std::string, std::vector<float>> stash;\n\tstd::vector<Mesh*> meshes = gls.GetMeshes();\n\tfor (Mesh* m : meshes) {\n\t\tif (!m->mask)\n\t\t\tcontinue;\n\t\tstd::vector<float>& mask = stash[m->shapeName];\n\t\tmask.resize(m->nVerts);\n\t\tstd::copy(m->mask.get(), m->mask.get() + m->nVerts, mask.begin());\n\t}\n\treturn stash;\n}\n\nvoid wxGLPanel::UnstashMasks(const std::unordered_map<std::string, std::vector<float>>& stash) {\n\tstd::vector<Mesh*> meshes = gls.GetMeshes();\n\tfor (Mesh* m : meshes) {\n\t\tauto stit = stash.find(m->shapeName);\n\t\tif (stit == stash.end())\n\t\t\tcontinue;\n\t\tconst std::vector<float>& mask = stit->second;\n\t\t// assert(mask.size() == m->nVerts);\n\t\tif (static_cast<int>(mask.size()) != m->nVerts)\n\t\t\tcontinue;\n\t\tstd::copy(mask.begin(), mask.end(), m->mask.get());\n\t\tm->QueueUpdate(Mesh::UpdateType::Mask);\n\t}\n}\n\nvoid wxGLPanel::MaskLess() {\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\tfor (auto& m : gls.GetActiveMeshes()) {\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\t// First, try to remove welds of unmasked points from the mask.\n\t\tbool unmaskedAWeld = false;\n\t\tfor (int i = 0; i < m->nVerts; ++i) {\n\t\t\tif (m->mask[i] > 0.0f)\n\t\t\t\tcontinue;\n\t\t\tm->DoForEachWeldedVertex(i, [&](int wvi){\n\t\t\t\tif (m->mask[wvi] != 0.0f) {\n\t\t\t\t\tuss.pointStartState[wvi].x = m->mask[wvi];\n\t\t\t\t\tuss.pointEndState[wvi].x = 0.0f;\n\t\t\t\t\tunmaskedAWeld = true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// If we unmasked a weld, we've done something useful, so stop.\n\t\tif (unmaskedAWeld)\n\t\t\tcontinue;\n\n\t\t// Get points adjacent to unmasked points, taking welds into account.\n\t\tstd::unordered_set<int> adjacentPoints;\n\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\tif (m->mask[i] == 0.0f)\n\t\t\t\tm->GetAdjacentPoints(i, adjacentPoints);\n\n\t\t// Unmask the adjacent points\n\t\tfor (auto& adj : adjacentPoints)\n\t\t\tif (m->mask[adj] != 0.0f) {\n\t\t\t\tuss.pointStartState[adj].x = m->mask[adj];\n\t\t\t\tuss.pointEndState[adj].x = 0.0f;\n\t\t\t}\n\t}\n\n\tApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tGetUndoHistory()->PopState();\n\n\tos->UpdateUndoTools();\n}\n\n\nvoid wxGLPanel::MaskMore() {\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\tfor (auto& m : gls.GetActiveMeshes()) {\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\t// First, try to add welds of masked points to the mask.\n\t\tbool maskedAWeld = false;\n\t\tfor (int i = 0; i < m->nVerts; ++i) {\n\t\t\tif (m->mask[i] == 0.0f)\n\t\t\t\tcontinue;\n\t\t\tm->DoForEachWeldedVertex(i, [&](int wvi){\n\t\t\t\tif (m->mask[wvi] != 1.0f) {\n\t\t\t\t\tuss.pointStartState[wvi].x = m->mask[wvi];\n\t\t\t\t\tuss.pointEndState[wvi].x = 1.0f;\n\t\t\t\t\tmaskedAWeld = true;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\n\t\t// If we masked a weld, we've done something useful, so stop.\n\t\tif (maskedAWeld)\n\t\t\tcontinue;\n\n\t\t// Get points adjacent to masked points, taking welds into account.\n\t\tstd::unordered_set<int> adjacentPoints;\n\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\tif (m->mask[i] > 0.0f)\n\t\t\t\tm->GetAdjacentPoints(i, adjacentPoints);\n\n\t\t// Mask the adjacent points\n\t\tfor (auto& adj : adjacentPoints) {\n\t\t\tif (m->mask[adj] != 1.0f) {\n\t\t\t\tuss.pointStartState[adj].x = m->mask[adj];\n\t\t\t\tuss.pointEndState[adj].x = 1.0f;\n\t\t\t}\n\t\t}\n\t}\n\n\tApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tGetUndoHistory()->PopState();\n\n\tos->UpdateUndoTools();\n}\n\nvoid wxGLPanel::InvertMask() {\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\n\tfor (auto& m : gls.GetActiveMeshes()) {\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tuss.pointStartState[i].x = m->mask[i];\n\t\t\tuss.pointEndState[i].x = 1.0f - m->mask[i];\n\t\t}\n\t}\n\n\tApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tGetUndoHistory()->PopState();\n\n\tos->UpdateUndoTools();\n}\n\nvoid wxGLPanel::ClearMask() {\n\tUndoStateProject* usp = GetUndoHistory()->PushState();\n\tusp->undoType = UndoType::Mask;\n\n\tfor (auto& m : gls.GetActiveMeshes()) {\n\t\tusp->usss.emplace_back();\n\t\tUndoStateShape& uss = usp->usss.back();\n\t\tuss.shapeName = m->shapeName;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tuss.pointStartState[i].x = m->mask[i];\n\t\t\tuss.pointEndState[i].x = 0.0f;\n\t\t}\n\t}\n\n\tApplyUndoState(usp, false);\n\n\tif (!Config.GetBoolValue(\"Input/MaskHistory\"))\n\t\tGetUndoHistory()->PopState();\n\n\tos->UpdateUndoTools();\n}\n\nbool wxGLPanel::RestoreMode(UndoStateProject* usp) {\n\tbool modeChanged = false;\n\tUndoType undoType = usp->undoType;\n\tif (undoType == UndoType::VertexPosition && os->activeSlider != usp->sliderName) {\n\t\tos->EnterSliderEdit(usp->sliderName);\n\t\tmodeChanged = true;\n\t}\n\tif ((undoType != UndoType::VertexPosition || usp->sliderName.empty()) && os->bEditSlider) {\n\t\tos->ExitSliderEdit();\n\t\tmodeChanged = true;\n\t}\n\tif (undoType == UndoType::VertexPosition && !usp->sliderName.empty() && usp->sliderscale != os->project->SliderValue(usp->sliderName)) {\n\t\tos->SetSliderValue(usp->sliderName, usp->sliderscale * 100);\n\t\tos->ApplySliders();\n\t\tmodeChanged = true;\n\t}\n\tif (undoType == UndoType::VertexPosition && usp->sliderName.empty() && !os->project->AllSlidersZero()) {\n\t\tos->ZeroSliders();\n\t\tmodeChanged = true;\n\t}\n\treturn modeChanged;\n}\n\nvoid wxGLPanel::ApplyUndoState(UndoStateProject* usp, bool bUndo, bool bRender) {\n\tUndoType undoType = usp->undoType;\n\tstd::unordered_map<std::string, std::vector<float>> maskStash;\n\tif (undoType == UndoType::Weight) {\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tfor (auto& bw : uss.boneWeights) {\n\t\t\t\tif (bw.boneName != os->GetActiveBone())\n\t\t\t\t\tcontinue;\n\n\t\t\t\tfor (auto& wIt : bw.weights)\n\t\t\t\t\tm->weight[wIt.first] = bUndo ? wIt.second.startVal : wIt.second.endVal;\n\t\t\t}\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Weight);\n\t\t}\n\n\t\tos->ActiveShapesUpdated(usp, bUndo);\n\t}\n\telse if (undoType == UndoType::Mask) {\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tfor (auto& pit : (bUndo ? uss.pointStartState : uss.pointEndState))\n\t\t\t\tm->mask[pit.first] = pit.second.x;\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Mask);\n\t\t}\n\t}\n\telse if (undoType == UndoType::Color) {\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tfor (auto& pit : (bUndo ? uss.pointStartState : uss.pointEndState))\n\t\t\t\tm->vcolors[pit.first] = pit.second;\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::VertexColors);\n\t\t}\n\t}\n\telse if (undoType == UndoType::Alpha) {\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tfor (auto& pit : (bUndo ? uss.pointStartState : uss.pointEndState))\n\t\t\t\tm->valpha[pit.first] = pit.second.x;\n\n\t\t\tm->QueueUpdate(Mesh::UpdateType::VertexAlpha);\n\t\t}\n\n\t\tos->ActiveShapesUpdated(usp, bUndo);\n\t}\n\telse if (undoType == UndoType::VertexPosition) {\n\t\tbool hasRestDiffs = false;\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tif (!uss.restDiffs.empty()) {\n\t\t\t\thasRestDiffs = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (hasRestDiffs) {\n\t\t\t// Pose-independent undo/redo: use stored rest-space NIF diffs\n\t\t\tif (usp->sliderName.empty()) {\n\t\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\t\tif (!shape)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tstd::vector<Vector3> restVerts;\n\t\t\t\t\tos->project->GetWorkNif()->GetVertsForShape(shape, restVerts);\n\n\t\t\t\t\tfor (auto& rd : uss.restDiffs) {\n\t\t\t\t\t\tif (bUndo)\n\t\t\t\t\t\t\trestVerts[rd.first] -= rd.second;\n\t\t\t\t\t\telse\n\t\t\t\t\t\t\trestVerts[rd.first] += rd.second;\n\t\t\t\t\t}\n\n\t\t\t\t\tos->project->GetWorkNif()->SetVertsForShape(shape, restVerts);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tos->ActiveShapesUpdated(usp, bUndo);\n\n\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\tif (!shape)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\tos->project->GetLiveVerts(shape, verts);\n\t\t\t\tUpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\n\t\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\t\tif (m)\n\t\t\t\t\tm->CalcWeldVerts();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\t\tif (!m)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tfor (auto& pit : (bUndo ? uss.pointStartState : uss.pointEndState))\n\t\t\t\t\tm->verts[pit.first] = pit.second;\n\n\t\t\t\tm->CalcWeldVerts();\n\t\t\t\tm->SmoothNormals();\n\t\t\t\tBVHUpdateQueue.insert(m);\n\n\t\t\t\tm->QueueUpdate(Mesh::UpdateType::Position);\n\t\t\t}\n\n\t\t\tos->ActiveShapesUpdated(usp, bUndo);\n\n\t\t\tif (usp->sliderName.empty()) {\n\t\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\t\tMesh* m = GetMesh(uss.shapeName);\n\t\t\t\t\tif (!m)\n\t\t\t\t\t\tcontinue;\n\n\t\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\t\tif (shape)\n\t\t\t\t\t\tos->project->UpdateShapeFromMesh(shape, m);\n\t\t\t\t}\n\n\t\t\t\tif (os->project->bPose) {\n\t\t\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\t\t\tif (shape) {\n\t\t\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\t\t\tos->project->GetLiveVerts(shape, verts);\n\t\t\t\t\t\t\tUpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (os->project->bPose) {\n\t\t\t\tfor (auto& uss : usp->usss) {\n\t\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\t\t\tif (shape) {\n\t\t\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\t\t\tos->project->GetLiveVerts(shape, verts);\n\t\t\t\t\t\tUpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (undoType == UndoType::Mesh) {\n\t\tmaskStash = StashMasks();\n\n\t\t// Undo: restore deleted shapes before processing vertex mesh undos\n\t\tif (bUndo) {\n\t\t\tfor (auto& ds : usp->deletedShapes)\n\t\t\t\tos->project->RestoreDeletedShape(ds);\n\t\t}\n\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tNiShape* shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\tif (!shape)\n\t\t\t\tcontinue;\n\n\t\t\tos->project->ApplyShapeMeshUndo(shape, maskStash[uss.shapeName], uss, bUndo);\n\t\t}\n\n\t\t// Redo: re-delete shapes after processing vertex mesh redos\n\t\tif (!bUndo) {\n\t\t\tfor (auto& ds : usp->deletedShapes) {\n\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(ds.shapeName);\n\t\t\t\tif (shape)\n\t\t\t\t\tos->project->DeleteShape(shape);\n\t\t\t}\n\t\t}\n\n\t\tos->RefreshGUIFromProj(false, false);\n\t\tUnstashMasks(maskStash);\n\t\tos->ApplySliders();\n\t}\n\telse if (undoType == UndoType::ShapeDelete) {\n\t\tif (bUndo) {\n\t\t\tfor (auto& ds : usp->deletedShapes)\n\t\t\t\tos->project->RestoreDeletedShape(ds);\n\t\t}\n\t\telse {\n\t\t\tfor (auto& ds : usp->deletedShapes) {\n\t\t\t\tauto shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(ds.shapeName);\n\t\t\t\tif (shape)\n\t\t\t\t\tos->project->DeleteShape(shape);\n\t\t\t}\n\t\t}\n\n\t\tos->RefreshGUIFromProj(false, false);\n\t\tos->ApplySliders();\n\t}\n\telse if (undoType == UndoType::Mirror) {\n\t\tfor (auto& uss : usp->usss) {\n\t\t\tNiShape* shape = os->project->GetWorkNif()->FindBlockByName<NiShape>(uss.shapeName);\n\t\t\tif (!shape)\n\t\t\t\tcontinue;\n\n\t\t\tos->project->GetWorkNif()->MirrorShape(shape, usp->mirrorX, usp->mirrorY, usp->mirrorZ);\n\t\t\tif (usp->swapBonesX)\n\t\t\t\tos->project->GetWorkAnim()->SwapBonesLR(uss.shapeName);\n\t\t}\n\n\t\tos->RefreshGUIFromProj(false);\n\t}\n\telse if (undoType == UndoType::NodeTransform) {\n\t\tconst MatTransform& target = bUndo ? usp->nodeStartXformToParent : usp->nodeEndXformToParent;\n\n\t\tif (AnimBone* bPtr = AnimSkeleton::getInstance().GetBonePtr(usp->boneName))\n\t\t\tbPtr->SetTransformBoneToParent(target);\n\n\t\tauto* nif = os->project->GetWorkNif();\n\t\tif (nif) {\n\t\t\tnif->SetNodeTransformToParent(usp->boneName, target);\n\t\t\tif (auto* workAnim = os->project->GetWorkAnim())\n\t\t\t\tworkAnim->WriteNodesToNif(nif);\n\n\t\t\t// Re-skin all shapes so poses and bind-pose display both follow\n\t\t\t// the restored bone transform.\n\t\t\tfor (auto& s : nif->GetShapes()) {\n\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\tos->project->GetLiveVerts(s, verts);\n\t\t\t\tUpdateMeshVertices(s->name.get(), &verts, true, true, false);\n\t\t\t}\n\t\t}\n\n\t\tUpdateBones();\n\t\tUpdateNodes();\n\t\tos->RefreshBoneTreeBadBoneIcons();\n\t\tos->SetPendingChanges();\n\t}\n\n\tif (bRender) {\n\t\tif (transformMode)\n\t\t\tShowTransformTool();\n\t\telse\n\t\t\tRender();\n\t}\n}\n\nbool wxGLPanel::UndoStroke() {\n\tUndoStateProject* curState = undoHistory.GetCurState();\n\tif (!curState)\n\t\treturn false;\n\tif (RestoreMode(curState))\n\t\treturn true;\n\tif (!undoHistory.BackStepHistory())\n\t\treturn false;\n\n\tApplyUndoState(curState, true);\n\n\treturn true;\n}\n\nbool wxGLPanel::RedoStroke() {\n\tUndoStateProject* curState = undoHistory.GetNextState();\n\tif (!curState)\n\t\treturn false;\n\tif (RestoreMode(curState))\n\t\treturn true;\n\tif (!undoHistory.ForwardStepHistory())\n\t\treturn false;\n\n\tApplyUndoState(curState, false);\n\n\treturn true;\n}\n\nvoid wxGLPanel::ShowRotationCenter(bool show) {\n\tif (show) {\n\t\tRotationCenterMesh = gls.AddVis3dSphere(gls.camRotOffset, 0.08f, Vector3(1.0f, 0.0f, 1.0f), \"RotationCenterMesh\");\n\t\tRotationCenterMesh->prop.alpha = 0.25f;\n\t\tRotationCenterMesh->bVisible = true;\n\n\t\tRotationCenterMeshRingX = gls.AddVis3dRing(gls.camRotOffset, Vector3(1.0f, 0.0f, 0.0f), 0.25f, 0.01f, Vector3(1.0f, 0.0f, 0.0f), \"RotationCenterMeshRingX\");\n\t\tRotationCenterMeshRingX->prop.alpha = 0.25f;\n\t\tRotationCenterMeshRingX->bVisible = true;\n\n\t\tRotationCenterMeshRingY = gls.AddVis3dRing(gls.camRotOffset, Vector3(0.0f, 1.0f, 0.0f), 0.25f, 0.01f, Vector3(0.0f, 1.0f, 0.0f), \"RotationCenterMeshRingY\");\n\t\tRotationCenterMeshRingY->prop.alpha = 0.25f;\n\t\tRotationCenterMeshRingY->bVisible = true;\n\n\t\tRotationCenterMeshRingZ = gls.AddVis3dRing(gls.camRotOffset, Vector3(0.0f, 0.0f, 1.0f), 0.25f, 0.01f, Vector3(0.0f, 0.0f, 1.0f), \"RotationCenterMeshRingZ\");\n\t\tRotationCenterMeshRingZ->prop.alpha = 0.25f;\n\t\tRotationCenterMeshRingZ->bVisible = true;\n\t}\n\telse {\n\t\tif (RotationCenterMesh) {\n\t\t\tRotationCenterMesh->bVisible = false;\n\t\t\tRotationCenterMeshRingX->bVisible = false;\n\t\t\tRotationCenterMeshRingY->bVisible = false;\n\t\t\tRotationCenterMeshRingZ->bVisible = false;\n\t\t}\n\t}\n}\n\nvoid wxGLPanel::ShowTransformTool(bool show) {\n\tUpdateTransformCenter();\n\n\tif (show) {\n\t\tXMoveMesh = gls.AddVis3dArrow(xformCenter, Vector3(1.0f, 0.0f, 0.0f), 0.04f, 0.15f, 1.75f, Vector3(1.0f, 0.0f, 0.0f), \"XMoveMesh\");\n\t\tXMoveMesh->prop.alpha = 0.6f;\n\t\tYMoveMesh = gls.AddVis3dArrow(xformCenter, Vector3(0.0f, 1.0f, 0.0f), 0.04f, 0.15f, 1.75f, Vector3(0.0f, 1.0f, 0.0f), \"YMoveMesh\");\n\t\tYMoveMesh->prop.alpha = 0.6f;\n\t\tZMoveMesh = gls.AddVis3dArrow(xformCenter, Vector3(0.0f, 0.0f, 1.0f), 0.04f, 0.15f, 1.75f, Vector3(0.0f, 0.0f, 1.0f), \"ZMoveMesh\");\n\t\tZMoveMesh->prop.alpha = 0.6f;\n\n\t\tXRotateMesh = gls.AddVis3dRing(xformCenter, Vector3(1.0f, 0.0f, 0.0f), 1.25f, 0.04f, Vector3(1.0f, 0.0f, 0.0f), \"XRotateMesh\");\n\t\tXRotateMesh->prop.alpha = 0.6f;\n\t\tYRotateMesh = gls.AddVis3dRing(xformCenter, Vector3(0.0f, 1.0f, 0.0f), 1.25f, 0.04f, Vector3(0.0f, 1.0f, 0.0f), \"YRotateMesh\");\n\t\tYRotateMesh->prop.alpha = 0.6f;\n\t\tZRotateMesh = gls.AddVis3dRing(xformCenter, Vector3(0.0f, 0.0f, 1.0f), 1.25f, 0.04f, Vector3(0.0f, 0.0f, 1.0f), \"ZRotateMesh\");\n\t\tZRotateMesh->prop.alpha = 0.6f;\n\n\t\tXScaleMesh = gls.AddVis3dCube(xformCenter + Vector3(0.75f, 0.0f, 0.0f), Vector3(1.0f, 0.0f, 0.0f), 0.12f, Vector3(1.0f, 0.0f, 0.0f), \"XScaleMesh\");\n\t\tYScaleMesh = gls.AddVis3dCube(xformCenter + Vector3(0.0f, 0.75f, 0.0f), Vector3(0.0f, 1.0f, 0.0f), 0.12f, Vector3(0.0f, 1.0f, 0.0f), \"YScaleMesh\");\n\t\tZScaleMesh = gls.AddVis3dCube(xformCenter + Vector3(0.0f, 0.0f, 0.75f), Vector3(0.0f, 0.0f, 1.0f), 0.12f, Vector3(0.0f, 0.0f, 1.0f), \"ZScaleMesh\");\n\t\tScaleUniformMesh = gls.AddVis3dCube(xformCenter, Vector3(1.0f, 0.0f, 0.0f), 0.15f, Vector3(0.0f, 0.0f, 0.0f), \"ScaleUniformMesh\");\n\n\t\tlastCenterDistance = 0.0f;\n\n\t\tXMoveMesh->bVisible = true;\n\t\tYMoveMesh->bVisible = true;\n\t\tZMoveMesh->bVisible = true;\n\t\tXRotateMesh->bVisible = true;\n\t\tYRotateMesh->bVisible = true;\n\t\tZRotateMesh->bVisible = true;\n\t\tXScaleMesh->bVisible = true;\n\t\tYScaleMesh->bVisible = true;\n\t\tZScaleMesh->bVisible = true;\n\t\tScaleUniformMesh->bVisible = true;\n\n\t\tif (XPivotMesh) {\n\t\t\tXPivotMesh->bVisible = false;\n\t\t\tYPivotMesh->bVisible = false;\n\t\t\tZPivotMesh->bVisible = false;\n\t\t\tPivotCenterMesh->bVisible = false;\n\t\t}\n\n\t\tif (nodesMode || bonesMode) {\n\t\t\t// Only move and rotate gizmos are supported for bones/nodes.\n\t\t\tXScaleMesh->bVisible = false;\n\t\t\tYScaleMesh->bVisible = false;\n\t\t\tZScaleMesh->bVisible = false;\n\t\t\tScaleUniformMesh->bVisible = false;\n\t\t}\n\t}\n\telse {\n\t\tif (XMoveMesh) {\n\t\t\tXMoveMesh->bVisible = false;\n\t\t\tYMoveMesh->bVisible = false;\n\t\t\tZMoveMesh->bVisible = false;\n\t\t\tXRotateMesh->bVisible = false;\n\t\t\tYRotateMesh->bVisible = false;\n\t\t\tZRotateMesh->bVisible = false;\n\t\t\tXScaleMesh->bVisible = false;\n\t\t\tYScaleMesh->bVisible = false;\n\t\t\tZScaleMesh->bVisible = false;\n\t\t\tScaleUniformMesh->bVisible = false;\n\t\t}\n\n\t\tif (XPivotMesh && pivotMode) {\n\t\t\tXPivotMesh->bVisible = true;\n\t\t\tYPivotMesh->bVisible = true;\n\t\t\tZPivotMesh->bVisible = true;\n\t\t\tPivotCenterMesh->bVisible = true;\n\t\t}\n\t}\n\n\tUpdateTransformTool();\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::UpdateTransformCenter() {\n\tbool centerSet = false;\n\n\tif (pivotMode) {\n\t\txformCenter = pivotPosition;\n\t\tcenterSet = true;\n\t}\n\telse if (nodesMode || bonesMode) {\n\t\tstd::string activeBone = os->GetActiveBone();\n\t\tif (!activeBone.empty()) {\n\t\t\tauto boneMesh = gls.GetOverlay(\"BP_\" + activeBone);\n\t\t\tif (boneMesh) {\n\t\t\t\txformCenter = boneMesh->verts[0];\n\t\t\t\tcenterSet = true;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tauto nodeMesh = gls.GetOverlay(\"P_\" + activeBone);\n\t\t\t\tif (nodeMesh) {\n\t\t\t\t\txformCenter = nodeMesh->verts[0];\n\t\t\t\t\tcenterSet = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!centerSet)\n\t\txformCenter = gls.GetActiveCenter();\n}\n\nvoid wxGLPanel::UpdateTransformTool() {\n\tif (!transformMode)\n\t\treturn;\n\n\tif (!XMoveMesh)\n\t\treturn;\n\n\tVector3 unprojected;\n\tgls.UnprojectCamera(unprojected);\n\n\tif (lastCenterDistance != 0.0f) {\n\t\tfloat factor = 1.0f / lastCenterDistance;\n\t\tXMoveMesh->ScaleVertices(xformCenter, factor);\n\t\tYMoveMesh->ScaleVertices(xformCenter, factor);\n\t\tZMoveMesh->ScaleVertices(xformCenter, factor);\n\n\t\tXRotateMesh->ScaleVertices(xformCenter, factor);\n\t\tYRotateMesh->ScaleVertices(xformCenter, factor);\n\t\tZRotateMesh->ScaleVertices(xformCenter, factor);\n\n\t\tXScaleMesh->ScaleVertices(xformCenter, factor);\n\t\tYScaleMesh->ScaleVertices(xformCenter, factor);\n\t\tZScaleMesh->ScaleVertices(xformCenter, factor);\n\t\tScaleUniformMesh->ScaleVertices(xformCenter, factor);\n\t}\n\n\tlastCenterDistance = unprojected.DistanceTo(xformCenter) / 15.0f;\n\n\tXMoveMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tYMoveMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tZMoveMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\n\tXRotateMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tYRotateMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tZRotateMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\n\tXScaleMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tYScaleMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tZScaleMesh->ScaleVertices(xformCenter, lastCenterDistance);\n\tScaleUniformMesh->ScaleVertices(xformCenter, lastCenterDistance);\n}\n\nvoid wxGLPanel::ShowPivot(bool show) {\n\tif (show) {\n\t\tXPivotMesh = gls.AddVis3dArrow(pivotPosition, Vector3(1.0f, 0.0f, 0.0f), 0.03f, 0.1f, 1.0f, Vector3(1.0f, 0.0f, 0.0f), \"XPivotMesh\");\n\t\tYPivotMesh = gls.AddVis3dArrow(pivotPosition, Vector3(0.0f, 1.0f, 0.0f), 0.03f, 0.1f, 1.0f, Vector3(0.0f, 1.0f, 0.0f), \"YPivotMesh\");\n\t\tZPivotMesh = gls.AddVis3dArrow(pivotPosition, Vector3(0.0f, 0.0f, 1.0f), 0.03f, 0.1f, 1.0f, Vector3(0.0f, 0.0f, 1.0f), \"ZPivotMesh\");\n\t\tPivotCenterMesh = gls.AddVis3dCube(pivotPosition, Vector3(1.0f, 0.0f, 0.0f), 0.075f, Vector3(0.0f, 0.0f, 0.0f), \"PivotCenterMesh\");\n\n\t\tXPivotMesh->bVisible = true;\n\t\tYPivotMesh->bVisible = true;\n\t\tZPivotMesh->bVisible = true;\n\t\tPivotCenterMesh->bVisible = true;\n\n\t\tlastCenterPivotDistance = 0.0f;\n\t}\n\telse {\n\t\tif (XPivotMesh) {\n\t\t\tXPivotMesh->bVisible = false;\n\t\t\tYPivotMesh->bVisible = false;\n\t\t\tZPivotMesh->bVisible = false;\n\t\t\tPivotCenterMesh->bVisible = false;\n\t\t}\n\t}\n\n\tUpdatePivot();\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::UpdatePivot() {\n\tif (!pivotMode)\n\t\treturn;\n\n\tif (!XPivotMesh)\n\t\treturn;\n\n\tVector3 unprojected;\n\tgls.UnprojectCamera(unprojected);\n\n\tif (lastCenterPivotDistance != 0.0f) {\n\t\tfloat factor = 1.0f / lastCenterPivotDistance;\n\t\tXPivotMesh->ScaleVertices(pivotPosition, factor);\n\t\tYPivotMesh->ScaleVertices(pivotPosition, factor);\n\t\tZPivotMesh->ScaleVertices(pivotPosition, factor);\n\t\tPivotCenterMesh->ScaleVertices(pivotPosition, factor);\n\t}\n\n\tlastCenterPivotDistance = unprojected.DistanceTo(pivotPosition) / 15.0f;\n\n\tXPivotMesh->ScaleVertices(pivotPosition, lastCenterPivotDistance);\n\tYPivotMesh->ScaleVertices(pivotPosition, lastCenterPivotDistance);\n\tZPivotMesh->ScaleVertices(pivotPosition, lastCenterPivotDistance);\n\tPivotCenterMesh->ScaleVertices(pivotPosition, lastCenterPivotDistance);\n}\n\nvoid wxGLPanel::ShowNodes(bool show) {\n\tnodesMode = show;\n\n\tfor (auto& m : nodesPoints)\n\t\tm->bVisible = show;\n\n\tfor (auto& m : nodesLines)\n\t\tm->bVisible = show;\n\n\tif (transformMode)\n\t\tShowTransformTool();\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::UpdateNodes() {\n\tfor (auto& m : nodesPoints)\n\t\tgls.DeleteOverlay(m);\n\n\tfor (auto& m : nodesLines)\n\t\tgls.DeleteOverlay(m);\n\n\tnodesPoints.clear();\n\tnodesLines.clear();\n\n\tauto workNif = os->project->GetWorkNif();\n\n\tstd::function<void(NiNode*, NiNode*, const Vector3&, const Vector3&)> addChildNodes =\n\t\t[&](NiNode* node, NiNode* parent, const Vector3& rootPosition, const Vector3& parentPosition) {\n\t\t\tMatTransform ttg = node->GetTransformToParent();\n\t\t\tNiNode* parentNode = parent;\n\t\t\twhile (parentNode) {\n\t\t\t\tttg = parentNode->GetTransformToParent().ComposeTransforms(ttg);\n\t\t\t\tparentNode = workNif->GetParentNode(parentNode);\n\t\t\t}\n\n\t\t\tVector3 position = ttg.ApplyTransform(rootPosition);\n\n\t\t\tstd::string nodeName = node->name.get();\n\t\t\tif (!nodeName.empty()) {\n\t\t\t\tVector3 renderPosition = Mesh::TransformPosNifToMesh(position);\n\n\t\t\t\tauto pointMesh = gls.AddVisPoint(renderPosition, \"P_\" + nodeName);\n\t\t\t\tif (pointMesh) {\n\t\t\t\t\tpointMesh->bVisible = nodesMode;\n\t\t\t\t\tnodesPoints.push_back(pointMesh);\n\t\t\t\t}\n\n\t\t\t\tif (parent) {\n\t\t\t\t\tVector3 renderParentPosition = Mesh::TransformPosNifToMesh(parentPosition);\n\n\t\t\t\t\tauto lineMesh = gls.AddVisSeg(renderParentPosition, renderPosition, \"L_\" + nodeName);\n\t\t\t\t\tif (lineMesh) {\n\t\t\t\t\t\tlineMesh->bVisible = nodesMode;\n\t\t\t\t\t\tnodesLines.push_back(lineMesh);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (auto& child : node->childRefs) {\n\t\t\t\tauto childNode = workNif->GetHeader().GetBlock<NiNode>(child);\n\t\t\t\tif (childNode)\n\t\t\t\t\taddChildNodes(childNode, node, rootPosition, position);\n\t\t\t}\n\t\t};\n\n\tauto rootNode = workNif->GetRootNode();\n\tif (rootNode)\n\t\taddChildNodes(rootNode, nullptr, rootNode->transform.translation, rootNode->transform.translation);\n\n\tUpdateNodeColors();\n}\n\nvoid wxGLPanel::ShowBones(bool show) {\n\tbonesMode = show;\n\n\tfor (auto& m : bonesPoints)\n\t\tm->bVisible = show;\n\n\tfor (auto& m : bonesLines)\n\t\tm->bVisible = show;\n\n\tif (transformMode)\n\t\tShowTransformTool();\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::UpdateBones() {\n\tfor (auto& m : bonesPoints)\n\t\tgls.DeleteOverlay(m);\n\n\tfor (auto& m : bonesLines)\n\t\tgls.DeleteOverlay(m);\n\n\tbonesPoints.clear();\n\tbonesLines.clear();\n\n\tauto workAnim = os->project->GetWorkAnim();\n\n\tstd::function<bool(AnimBone*)> addChildBones = [&](AnimBone* parent) {\n\t\tbool anyBoneInSelection = false;\n\n\t\tfor (auto& cb : parent->children) {\n\t\t\tbool childBonesInSelection = addChildBones(cb);\n\n\t\t\tif (!cb->boneName.empty()) {\n\t\t\t\tbool boneInSelection = false;\n\t\t\t\tfor (auto& si : os->GetSelectedItems()) {\n\t\t\t\t\tif (workAnim->GetShapeBoneIndex(si->GetShape()->name.get(), cb->boneName) != -1) {\n\t\t\t\t\t\tboneInSelection = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (boneInSelection || childBonesInSelection) {\n\t\t\t\t\tconst MatTransform& toGlobal = os->project->bPose ? cb->xformPoseToGlobal : cb->xformToGlobal;\n\t\t\t\t\tVector3 position = toGlobal.ApplyTransform(Vector3());\n\t\t\t\t\tconst MatTransform& parentToGlobal = os->project->bPose ? parent->xformPoseToGlobal : parent->xformToGlobal;\n\t\t\t\t\tVector3 parentPosition = parentToGlobal.ApplyTransform(Vector3());\n\t\t\t\t\tbool matchesParent = position.IsNearlyEqualTo(parentPosition);\n\n\t\t\t\t\tVector3 renderPosition = Mesh::TransformPosNifToMesh(position);\n\n\t\t\t\t\tauto pointMesh = gls.AddVisPoint(renderPosition, \"BP_\" + cb->boneName);\n\t\t\t\t\tif (pointMesh) {\n\t\t\t\t\t\tpointMesh->bVisible = bonesMode;\n\t\t\t\t\t\tbonesPoints.push_back(pointMesh);\n\t\t\t\t\t}\n\n\t\t\t\t\tVector3 renderParentPosition = Mesh::TransformPosNifToMesh(parentPosition);\n\n\t\t\t\t\tif (!matchesParent) {\n\t\t\t\t\t\tauto lineMesh = gls.AddVisSeg(renderParentPosition, renderPosition, \"BL_\" + cb->boneName);\n\t\t\t\t\t\tif (lineMesh) {\n\t\t\t\t\t\t\tlineMesh->bVisible = bonesMode;\n\t\t\t\t\t\t\tbonesLines.push_back(lineMesh);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tanyBoneInSelection = true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn anyBoneInSelection;\n\t};\n\n\tAnimBone* rb = AnimSkeleton::getInstance().GetRootBonePtr();\n\tif (rb)\n\t\taddChildBones(rb);\n\n\tUpdateNodeColors();\n}\n\nvoid wxGLPanel::UpdateNodeColors() {\n\tstd::string activeBone = os->GetActiveBone();\n\n\tfor (auto& m : nodesPoints) {\n\t\tauto nodeName = m->shapeName.substr(2, m->shapeName.length() - 2);\n\t\tif (nodeName == activeBone) {\n\t\t\tm->color.x = 1.0f;\n\t\t\tm->color.y = 0.0f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::NodeSelection;\n\t\t}\n\t\telse {\n\t\t\tm->color.x = 0.0f;\n\t\t\tm->color.y = 1.0f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::Default;\n\t\t}\n\t}\n\n\tfor (auto& m : nodesLines) {\n\t\tauto nodeName = m->shapeName.substr(2, m->shapeName.length() - 2);\n\t\tif (nodeName == activeBone) {\n\t\t\tm->color.x = 0.7f;\n\t\t\tm->color.y = 0.0f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::NodeSelection;\n\t\t}\n\t\telse {\n\t\t\tm->color.x = 0.0f;\n\t\t\tm->color.y = 0.7f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::Default;\n\t\t}\n\t}\n\n\tfor (auto& m : bonesPoints) {\n\t\tauto nodeName = m->shapeName.substr(3, m->shapeName.length() - 3);\n\t\tif (nodeName == activeBone) {\n\t\t\tm->color.x = 1.0f;\n\t\t\tm->color.y = 0.0f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::NodeSelection;\n\t\t}\n\t\telse {\n\t\t\tm->color.x = 0.0f;\n\t\t\tm->color.y = 1.0f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::Default;\n\t\t}\n\t}\n\n\tfor (auto& m : bonesLines) {\n\t\tauto nodeName = m->shapeName.substr(3, m->shapeName.length() - 3);\n\t\tif (nodeName == activeBone) {\n\t\t\tm->color.x = 0.7f;\n\t\t\tm->color.y = 0.0f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::NodeSelection;\n\t\t}\n\t\telse {\n\t\t\tm->color.x = 0.0f;\n\t\t\tm->color.y = 0.7f;\n\t\t\tm->color.z = 0.0f;\n\t\t\tm->overlayLayer = OverlayLayer::Default;\n\t\t}\n\t}\n}\n\nvoid wxGLPanel::ShowFloor(bool show) {\n\tfloorMode = show;\n\n\tfor (auto& m : floorMeshes)\n\t\tm->bVisible = show;\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::UpdateFloor() {\n\tfor (auto& m : floorMeshes)\n\t\tgls.DeleteMesh(m);\n\n\tfloorMeshes = gls.AddFloor();\n\n\tfor (auto& m : floorMeshes)\n\t\tm->bVisible = floorMode;\n}\n\nvoid wxGLPanel::ShowVertexEdit(bool show) {\n\tfor (auto& m : gls.GetMeshes())\n\t\tif (m)\n\t\t\tm->bShowPoints = false;\n\n\tif (show) {\n\t\tif (os->activeItem) {\n\t\t\tMesh* m = GetMesh(os->activeItem->GetShape()->name.get());\n\t\t\tif (m) {\n\t\t\t\tm->bShowPoints = true;\n\t\t\t\tm->QueueUpdate(Mesh::UpdateType::Mask);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid wxGLPanel::OnIdle(wxIdleEvent& WXUNUSED(event)) {\n\tif (wxGetKeyState(wxKeyCode::WXK_SHIFT) || wxGetKeyState(wxKeyCode::WXK_CONTROL) || wxGetKeyState(wxKeyCode::WXK_ALT) || lbuttonDown || rbuttonDown || mbuttonDown)\n\t\treturn;\n\n\tfor (auto& m : BVHUpdateQueue)\n\t\tm->CreateBVH();\n\n\tBVHUpdateQueue.clear();\n}\n\nvoid wxGLPanel::OnPaint(wxPaintEvent& event) {\n\t// Initialize OpenGL the first time the window is painted.\n\t// We unfortunately can't initialize it before the window is shown.\n\t// We could register for the EVT_SHOW event, but unfortunately it\n\t// appears to only be called after the first few EVT_PAINT events.\n\t// It also isn't supported on all platforms.\n\tif (firstPaint) {\n\t\tfirstPaint = false;\n\t\tOnShown();\n\t}\n\n\tgls.RenderOneFrame();\n\tevent.Skip();\n}\n\nvoid wxGLPanel::OnSize(wxSizeEvent& event) {\n\twxSize sz = event.GetSize();\n\tgls.SetSize(sz.GetX(), sz.GetY());\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::OnMouseWheel(wxMouseEvent& event) {\n\tint delt = event.GetWheelRotation();\n\n\tif (event.ControlDown()) {\n\t\tstd::string sliderName = os->lastActiveSlider;\n\n\t\tif (sliderName.empty())\n\t\t\tsliderName = os->project->GetSliderName(0);\n\n\t\tif (sliderName.empty())\n\t\t\treturn;\n\n\t\tif (!os->activeSlider.empty())\n\t\t\tos->ExitSliderEdit();\n\n\t\tsize_t sliderCount = os->project->SliderCount();\n\t\tsize_t sliderIndex = 0;\n\t\tif (os->project->SliderIndexFromName(sliderName, sliderIndex)) {\n\t\t\tif (delt < 0) {\n\t\t\t\t++sliderIndex;\n\n\t\t\t\tif (sliderIndex == sliderCount)\n\t\t\t\t\tsliderIndex = 0;\n\n\t\t\t\tos->EnterSliderEdit(os->project->GetSliderName(sliderIndex));\n\t\t\t\tos->ScrollToActiveSlider();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif (sliderIndex == 0)\n\t\t\t\t\tsliderIndex = sliderCount - 1;\n\t\t\t\telse\n\t\t\t\t\t--sliderIndex;\n\n\t\t\t\tos->EnterSliderEdit(os->project->GetSliderName(sliderIndex));\n\t\t\t\tos->ScrollToActiveSlider();\n\t\t\t}\n\t\t}\n\t}\n\telse if (wxGetKeyState(wxKeyCode('S'))) {\n\t\twxPoint p = event.GetPosition();\n\n\t\tif (brushMode) {\n\t\t\t// Adjust brush size\n\t\t\tif (delt < 0)\n\t\t\t\tDecBrush();\n\t\t\telse\n\t\t\t\tIncBrush();\n\n\t\t\tos->CheckBrushBounds();\n\t\t\tos->UpdateBrushSettings();\n\t\t\tgls.UpdateCursor(p.x, p.y, true);\n\t\t\tgls.RenderOneFrame();\n\t\t}\n\t}\n\telse {\n\t\tgls.DollyCamera(delt);\n\t\tUpdateTransformTool();\n\t\tUpdatePivot();\n\t\tgls.RenderOneFrame();\n\t}\n}\n\nvoid wxGLPanel::OnMouseMove(wxMouseEvent& event) {\n\tif (os->IsActive())\n\t\tSetFocus();\n\n\tbool cursorExists = false;\n\tint x;\n\tint y;\n\tevent.GetPosition(&x, &y);\n\n\tmouseHasMovedSinceStart = true;\n\n\tShowRotationCenter(false);\n\n\tif (mbuttonDown) {\n\t\tisMDragging = true;\n\t\tif (wxGetKeyState(wxKeyCode::WXK_SHIFT))\n\t\t\tgls.DollyCamera(y - lastY);\n\t\telse\n\t\t\tgls.PanCamera(x - lastX, y - lastY);\n\n\t\tUpdateTransformTool();\n\t\tUpdatePivot();\n\t\tgls.RenderOneFrame();\n\t}\n\n\tif (rbuttonDown) {\n\t\tisRDragging = true;\n\n\t\tif (wxGetKeyState(WXK_ALT)) {\n\t\t\tif (lastHitResult.hoverPoint != -1) {\n\t\t\t\trotationCenterMode = RotationCenterMode::Picked;\n\t\t\t\tgls.camRotOffset = lastHitResult.hoverRealCoord;\n\t\t\t}\n\t\t}\n\n\t\tif (wxGetKeyState(WXK_SHIFT)) {\n\t\t\tgls.PanCamera(x - lastX, y - lastY);\n\t\t}\n\t\telse {\n\t\t\tgls.TurnTableCamera(x - lastX);\n\t\t\tgls.PitchCamera(y - lastY);\n\t\t\tShowRotationCenter();\n\t\t}\n\n\t\tUpdateTransformTool();\n\t\tUpdatePivot();\n\t\tgls.RenderOneFrame();\n\t}\n\n\tif (lbuttonDown || isMovingVertex) {\n\t\tisLDragging = true;\n\t\tif (isTransforming) {\n\t\t\tUpdateTransform(event.GetPosition());\n\t\t}\n\t\telse if (isMovingPivot) {\n\t\t\tUpdatePivotPosition(event.GetPosition());\n\t\t}\n\t\telse if (isPainting) {\n\t\t\tUpdateBrushStroke(event.GetPosition());\n\t\t}\n\t\telse if (isSelecting) {\n\t\t\tSelectVertex(event.GetPosition());\n\t\t}\n\t\telse if (isPickingVertex) {\n\t\t\tUpdatePickVertex(event.GetPosition());\n\t\t}\n\t\telse if (isPickingEdge) {\n\t\t\tUpdatePickEdge(event.GetPosition());\n\t\t}\n\t\telse if (isMovingVertex) {\n\t\t\tUpdateMoveVertex(event.GetPosition() - mouseDownOffset);\n\t\t}\n\t\telse {\n\t\t\tif (Config.MatchValue(\"Input/LeftMousePan\", \"true\")) {\n\t\t\t\tgls.PanCamera(x - lastX, y - lastY);\n\t\t\t\tUpdateTransformTool();\n\t\t\t\tUpdatePivot();\n\t\t\t}\n\t\t}\n\n\t\tgls.RenderOneFrame();\n\t}\n\n\tif (!rbuttonDown && !lbuttonDown && !isMovingVertex) {\n\t\tGLSurface::CursorHitResult hitResult{};\n\n\t\tif (editMode) {\n\t\t\tcursorExists = gls.UpdateCursor(x, y, true, &hitResult);\n\t\t}\n\t\telse {\n\t\t\tcursorExists = false;\n\t\t\tgls.ShowCursor(false);\n\t\t}\n\n\t\tif (activeTool == ToolID::MoveVertex) {\n\t\t\tmouseDownMirrorPoint = -1;\n\t\t\tif (GetToolOptionXMirror()) {\n\t\t\t\tVector3 hitPt, hitNrm;\n\t\t\t\tMesh* mmesh = nullptr;\n\t\t\t\tint triInd = 0;\n\t\t\t\tif (gls.CollideMeshes(x, y, hitPt, hitNrm, true, &mmesh, true, &triInd) && mmesh == hitResult.hitMesh) {\n\t\t\t\t\tint hitPti = mmesh->tris[triInd].ClosestVertex(mmesh->verts.get(), hitPt);\n\t\t\t\t\tif (hitPti != hitResult.hoverPoint) {\n\t\t\t\t\t\t// Should we also check if the mirror point's location\n\t\t\t\t\t\t// is close to the mirror of the hover point's location?\n\t\t\t\t\t\tmouseDownMirrorPoint = hitPti;\n\t\t\t\t\t\tgls.ShowMirrorPointCursor(mmesh->verts[mouseDownMirrorPoint], mmesh);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tlastHitResult = hitResult;\n\n\t\tif ((transformMode || pivotMode) && !isTransforming && !isMovingPivot) {\n\t\t\tif (XMoveMesh) {\n\t\t\t\tXMoveMesh->color = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tYMoveMesh->color = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\tZMoveMesh->color = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tXRotateMesh->color = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tYRotateMesh->color = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\tZRotateMesh->color = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tXScaleMesh->color = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tYScaleMesh->color = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\tZScaleMesh->color = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tScaleUniformMesh->color = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\t}\n\n\t\t\tif (XPivotMesh) {\n\t\t\t\tXPivotMesh->color = Vector3(1.0f, 0.0f, 0.0f);\n\t\t\t\tYPivotMesh->color = Vector3(0.0f, 1.0f, 0.0f);\n\t\t\t\tZPivotMesh->color = Vector3(0.0f, 0.0f, 1.0f);\n\t\t\t\tPivotCenterMesh->color = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\t}\n\n\t\t\tVector3 outOrigin, outNormal;\n\t\t\tMesh* hitMesh = nullptr;\n\t\t\tif (gls.CollideOverlay(x, y, outOrigin, outNormal, &hitMesh)) {\n\t\t\t\tif (hitMesh && hitMesh != PivotCenterMesh) {\n\t\t\t\t\thitMesh->color = Vector3(1.0f, 1.0f, 0.0f);\n\t\t\t\t\tgls.ShowCursor(false);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tgls.RenderOneFrame();\n\n\t\tif (os->statusBar) {\n\t\t\tif (cursorExists) {\n\t\t\t\tif (activeTool == ToolID::MaskBrush)\n\t\t\t\t\tos->statusBar->SetStatusText(wxString::Format(\"Vertex: %d, Mask: %g\", hitResult.hoverPoint, hitResult.hoverMask), 1);\n\t\t\t\telse if (activeTool == ToolID::WeightBrush) {\n\t\t\t\t\tVector3 hoverCoordNif = Mesh::TransformPosMeshToNif(hitResult.hoverMeshCoord);\n\t\t\t\t\tos->statusBar->SetStatusText(wxString::Format(\"Vertex: %d, Weight: %g, X: %.5f Y: %.5f Z: %.5f\", hitResult.hoverPoint, hitResult.hoverWeight, hoverCoordNif.x, hoverCoordNif.y, hoverCoordNif.z), 1);\n\t\t\t\t}\n\t\t\t\telse if (activeTool == ToolID::ColorBrush || activeTool == ToolID::AlphaBrush)\n\t\t\t\t\tos->statusBar->SetStatusText(wxString::Format(\"Vertex: %d, Color: %g, %g, %g, Alpha: %g\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  hitResult.hoverPoint,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  hitResult.hoverColor.x,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  hitResult.hoverColor.y,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  hitResult.hoverColor.z,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  hitResult.hoverAlpha),\n\t\t\t\t\t\t\t\t\t\t\t\t 1);\n\t\t\t\telse {\n\t\t\t\t\tVector3 hoverCoordNif = Mesh::TransformPosMeshToNif(hitResult.hoverMeshCoord);\n\t\t\t\t\tos->statusBar->SetStatusText(wxString::Format(\"Vertex: %d, X: %.5f Y: %.5f Z: %.5f\", hitResult.hoverPoint, hoverCoordNif.x, hoverCoordNif.y, hoverCoordNif.z),\n\t\t\t\t\t\t\t\t\t\t\t\t 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tos->statusBar->SetStatusText(\"\", 1);\n\t\t\t}\n\t\t}\n\t}\n\n\tlastX = x;\n\tlastY = y;\n}\n\nvoid wxGLPanel::OnLeftDown(wxMouseEvent& event) {\n\tif (!HasCapture())\n\t\tCaptureMouse();\n\n\tlbuttonDown = true;\n\n\tif (transformMode) {\n\t\tbool meshHit = StartTransform(event.GetPosition());\n\t\tif (meshHit) {\n\t\t\tisTransforming = true;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (pivotMode) {\n\t\tbool meshHit = StartPivotPosition(event.GetPosition());\n\t\tif (meshHit) {\n\t\t\tisMovingPivot = true;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (brushMode) {\n\t\tbool meshHit = StartBrushStroke(event.GetPosition());\n\t\tif (meshHit)\n\t\t\tisPainting = true;\n\t}\n\telse if (activeTool == ToolID::CollapseVertex) {\n\t\tbool meshHit = StartPickVertex();\n\t\tif (meshHit)\n\t\t\tisPickingVertex = true;\n\t}\n\telse if (activeTool == ToolID::FlipEdge || activeTool == ToolID::SplitEdge) {\n\t\tbool meshHit = StartPickEdge();\n\t\tif (meshHit)\n\t\t\tisPickingEdge = true;\n\t}\n\telse if (activeTool == ToolID::MoveVertex) {\n\t\tif (isMovingVertex) {\n\t\t\tEndMoveVertex();\n\t\t\tisMovingVertex = false;\n\t\t}\n\t\telse {\n\t\t\tbool meshHit = StartMoveVertex(event.GetPosition());\n\t\t\tif (meshHit)\n\t\t\t\tisMovingVertex = true;\n\t\t}\n\t}\n\telse if (vertexEdit) {\n\t\tbool meshHit = SelectVertex(event.GetPosition());\n\t\tif (meshHit)\n\t\t\tisSelecting = true;\n\t}\n}\n\nvoid wxGLPanel::OnMiddleDown(wxMouseEvent& WXUNUSED(event)) {\n\tif (!HasCapture())\n\t\tCaptureMouse();\n\n\tmbuttonDown = true;\n}\n\nvoid wxGLPanel::OnMiddleUp(wxMouseEvent& WXUNUSED(event)) {\n\tif (GetCapture() == this)\n\t\tReleaseMouse();\n\n\tisMDragging = false;\n\tmbuttonDown = false;\n}\n\nvoid wxGLPanel::OnLeftUp(wxMouseEvent& event) {\n\tif (GetCapture() == this)\n\t\tReleaseMouse();\n\n\tif (!isLDragging && !isPainting && activeTool == ToolID::Select) {\n\t\tint x, y;\n\t\tevent.GetPosition(&x, &y);\n\n\t\tMesh* m = gls.PickMesh(x, y);\n\t\tif (m)\n\t\t\tos->SelectShape(m->shapeName);\n\t}\n\n\tif (isPainting) {\n\t\tEndBrushStroke();\n\t\tisPainting = false;\n\t}\n\n\tif (isPickingVertex) {\n\t\tEndPickVertex();\n\t\tisPickingVertex = false;\n\t}\n\n\tif (isPickingEdge) {\n\t\tEndPickEdge();\n\t\tisPickingEdge = false;\n\t}\n\n\tif (isMovingVertex) {\n\t\tif (mouseHasMovedSinceStart) {\n\t\t\tEndMoveVertex();\n\t\t\tisMovingVertex = false;\n\t\t}\n\t\telse\n\t\t\tmouseHasMovedSinceStart = true;\n\t}\n\n\tif (isTransforming) {\n\t\tEndTransform();\n\t\tisTransforming = false;\n\t}\n\n\tif (isMovingPivot) {\n\t\tEndPivotPosition();\n\t\tisMovingPivot = false;\n\t}\n\n\tif (isSelecting)\n\t\tisSelecting = false;\n\n\tisLDragging = false;\n\tlbuttonDown = false;\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) {\n\tif (isPainting) {\n\t\tEndBrushStroke();\n\t\tisPainting = false;\n\t}\n\n\tif (isPickingVertex) {\n\t\tEndPickVertex();\n\t\tisPickingVertex = false;\n\t}\n\n\tif (isPickingEdge) {\n\t\tEndPickEdge();\n\t\tisPickingEdge = false;\n\t}\n\n\tif (isMovingVertex) {\n\t\tCancelMoveVertex();\n\t\tisMovingVertex = false;\n\t}\n\n\tif (isTransforming) {\n\t\tEndTransform();\n\t\tisTransforming = false;\n\t}\n\n\tif (isMovingPivot) {\n\t\tEndPivotPosition();\n\t\tisMovingPivot = false;\n\t}\n\n\tif (isSelecting)\n\t\tisSelecting = false;\n\n\tisLDragging = false;\n\tlbuttonDown = false;\n\n\tisMDragging = false;\n\tmbuttonDown = false;\n\n\trbuttonDown = false;\n\n\tgls.RenderOneFrame();\n}\n\nvoid wxGLPanel::OnRightDown(wxMouseEvent& WXUNUSED(event)) {\n\tif (!HasCapture())\n\t\tCaptureMouse();\n\n\trbuttonDown = true;\n}\n\nvoid wxGLPanel::OnRightUp(wxMouseEvent& WXUNUSED(event)) {\n\tif (HasCapture())\n\t\tReleaseMouse();\n\n\trbuttonDown = false;\n}\n\n\nbool DnDFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) {\n\tif (owner) {\n\t\tNiShape* mergeShape = nullptr;\n\t\tif (owner->activeItem && fileNames.GetCount() == 1)\n\t\t\tmergeShape = owner->activeItem->GetShape();\n\n\t\tfor (auto& inputFile : fileNames) {\n\t\t\twxString dataName = inputFile.AfterLast('/').AfterLast('\\\\');\n\t\t\tdataName = dataName.BeforeLast('.');\n\n\t\t\tif (inputFile.Lower().EndsWith(\".nif\")) {\n\t\t\t\towner->StartProgress(_(\"Adding NIF file...\"));\n\t\t\t\towner->UpdateProgress(1, _(\"Adding NIF file...\"));\n\t\t\t\towner->project->ImportNIF(inputFile.ToUTF8().data(), false);\n\t\t\t\towner->project->SetTextures();\n\n\t\t\t\towner->UpdateProgress(60, _(\"Refreshing GUI...\"));\n\t\t\t\towner->RefreshGUIFromProj();\n\n\t\t\t\towner->EndProgress();\n\t\t\t}\n\t\t\telse if (inputFile.Lower().EndsWith(\".obj\")) {\n\t\t\t\towner->StartProgress(\"Adding OBJ file...\");\n\t\t\t\towner->UpdateProgress(1, _(\"Adding OBJ file...\"));\n\t\t\t\towner->project->ImportOBJ(inputFile.ToUTF8().data(), dataName.ToUTF8().data(), mergeShape);\n\t\t\t\towner->project->SetTextures();\n\n\t\t\t\towner->UpdateProgress(60, _(\"Refreshing GUI...\"));\n\t\t\t\towner->RefreshGUIFromProj();\n\n\t\t\t\towner->EndProgress();\n\t\t\t}\n#ifdef USE_FBXSDK\n\t\t\telse if (inputFile.Lower().EndsWith(\".fbx\")) {\n\t\t\t\towner->StartProgress(_(\"Adding FBX file...\"));\n\t\t\t\towner->UpdateProgress(1, _(\"Adding FBX file...\"));\n\t\t\t\towner->project->ImportFBX(inputFile.ToUTF8().data(), dataName.ToUTF8().data(), mergeShape);\n\t\t\t\towner->project->SetTextures();\n\n\t\t\t\towner->UpdateProgress(60, _(\"Refreshing GUI...\"));\n\t\t\t\towner->RefreshGUIFromProj();\n\n\t\t\t\towner->EndProgress();\n\t\t\t}\n#endif\n\t\t}\n\n\t\towner->UpdateTitle();\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nbool DnDSliderFile::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames) {\n\tif (owner) {\n\t\tbool isMultiple = (fileNames.GetCount() > 1);\n\t\tfor (size_t i = 0; i < fileNames.GetCount(); i++) {\n\t\t\twxString inputFile;\n\t\t\tinputFile = fileNames.Item(i);\n\n\t\t\twxString dataName = inputFile.AfterLast('/').AfterLast('\\\\');\n\t\t\tdataName = dataName.BeforeLast('.');\n\n\t\t\tbool isBSD = inputFile.MakeLower().EndsWith(\".bsd\");\n\t\t\tbool isOBJ = inputFile.MakeLower().EndsWith(\".obj\");\n#ifdef USE_FBXSDK\n\t\t\tbool isFBX = inputFile.MakeLower().EndsWith(\".fbx\");\n\t\t\tif (isBSD || isOBJ || isFBX) {\n#else\n\t\t\tif (isBSD || isOBJ) {\n#endif\n\t\t\t\tif (!owner->activeItem) {\n\t\t\t\t\twxMessageBox(_(\"There is no shape selected!\"), _(\"Error\"));\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif (lastResult == wxDragCopy) {\n\t\t\t\t\ttargetSlider = owner->NewSlider(dataName.ToUTF8().data(), isMultiple);\n\t\t\t\t}\n\n\t\t\t\tif (targetSlider.empty())\n\t\t\t\t\treturn false;\n\n\t\t\t\towner->StartProgress(_(\"Loading slider file...\"));\n\t\t\t\towner->UpdateProgress(1, _(\"Loading slider file...\"));\n\n\t\t\t\tif (isBSD)\n\t\t\t\t\towner->project->SetSliderFromBSD(targetSlider, owner->activeItem->GetShape(), inputFile.ToUTF8().data());\n\t\t\t\telse if (isOBJ)\n\t\t\t\t\towner->project->SetSliderFromOBJ(targetSlider, owner->activeItem->GetShape(), inputFile.ToUTF8().data());\n#ifdef USE_FBXSDK\n\t\t\t\telse if (isFBX)\n\t\t\t\t\towner->project->SetSliderFromFBX(targetSlider, owner->activeItem->GetShape(), inputFile.ToUTF8().data());\n#endif\n\t\t\t\telse\n\t\t\t\t\treturn false;\n\n\n\t\t\t\towner->EndProgress();\n\t\t\t}\n\t\t}\n\t\towner->EnterSliderEdit(targetSlider);\n\t\ttargetSlider.clear();\n\t}\n\telse\n\t\treturn false;\n\n\treturn true;\n}\n\nwxDragResult DnDSliderFile::OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult) {\n\ttargetSlider.clear();\n\tlastResult = defResult;\n\n\tif (defResult == wxDragCopy)\n\t\treturn lastResult;\n\n\tif (owner) {\n\t\tfor (auto& child : owner->sliderPanels) {\n\t\t\tif (child.second->GetRect().Contains(x, y)) {\n\t\t\t\ttargetSlider = child.first;\n\t\t\t\tlastResult = wxDragMove;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (targetSlider.empty())\n\t\t\tif (owner->sliderScroll->HitTest(x, y) == wxHT_WINDOW_INSIDE)\n\t\t\t\tlastResult = wxDragCopy;\n\t}\n\telse\n\t\tlastResult = wxDragCancel;\n\n\treturn lastResult;\n}\n"
  },
  {
    "path": "src/program/OutfitStudio.h",
    "content": "/*\nBodySlide and Outfit Studio\n\nThis program is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\n(at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program.  If not, see <http://www.gnu.org/licenses/>.\n*/\n\n#pragma once\n\n#include \"../components/Automorph.h\"\n#include \"../components/PoseData.h\"\n#include \"../components/RefTemplates.h\"\n#include \"../components/TweakBrush.h\"\n#include \"../components/UndoHistory.h\"\n#include \"../render/GLSurface.h\"\n#include \"../ui/WeightCopyDialog.h\"\n#include \"../ui/wxSliderPanel.h\"\n#include \"../ui/wxStateButton.h\"\n#include \"../utils/ConfigurationManager.h\"\n#include \"../utils/Log.h\"\n#include \"OutfitProject.h\"\n\n#include \"../FSEngine/FSEngine.h\"\n#include \"../FSEngine/FSManager.h\"\n\n#include <optional>\n#include <wx/clrpicker.h>\n#include <wx/cmdline.h>\n#include <wx/collpane.h>\n#include <wx/dataview.h>\n#include <wx/filepicker.h>\n#include <wx/grid.h>\n#include <wx/spinctrl.h>\n#include <wx/splitter.h>\n#include <wx/srchctrl.h>\n#include <wx/stdpaths.h>\n#include <wx/tokenzr.h>\n#include <wx/treectrl.h>\n#include <wx/wizard.h>\n#include <wx/xrc/xmlres.h>\n#include <wx/snglinst.h>\n#include <wx/ipc.h>\n#ifdef _WINDOWS\n#include <wx/msw/registry.h>\n#endif\n\nenum TargetGame { FO3, FONV, SKYRIM, FO4, SKYRIMSE, FO4VR, SKYRIMVR, FO76, OB, SF };\n\n\nclass ShapeItemData : public wxTreeItemData {\n\tnifly::NiShape* shape = nullptr;\n\npublic:\n\tShapeItemData(nifly::NiShape* inShape) { shape = inShape; }\n\n\tnifly::NiShape* GetShape() { return shape; }\n\n\tvoid SetShape(nifly::NiShape* newShape) { shape = newShape; }\n};\n\nstruct ShapeItemState {\n\tstd::string shapeName;\n\tint state = 0;\n\tbool selected = false;\n};\n\nclass SegmentItemData : public wxTreeItemData {\npublic:\n\t// partID: a small nonnegative integer uniquely identifying this\n\t// segment among all the segments and subsegments.  Used as a value\n\t// in triSParts.  Not in the file.\n\tint partID;\n\n\tSegmentItemData(const int inPartitionID) { partID = inPartitionID; }\n};\n\nclass SubSegmentItemData : public wxTreeItemData {\npublic:\n\t// partID: a small nonnegative integer uniquely identifying this\n\t// subsegment among all the segments and subsegments.  Used as a value\n\t// in triSParts.  Not in the file.\n\tint partID;\n\tuint32_t userSlotID;\n\tuint32_t material;\n\tstd::vector<float> extraData;\n\n\tSubSegmentItemData(const int inPartitionID, const uint32_t& inUserSlotID, const uint32_t& inMaterial, const std::vector<float>& inExtraData = std::vector<float>()) {\n\t\tpartID = inPartitionID;\n\t\tuserSlotID = inUserSlotID;\n\t\tmaterial = inMaterial;\n\t\textraData = inExtraData;\n\t}\n};\n\nclass PartitionItemData : public wxTreeItemData {\npublic:\n\tint index;\n\tuint16_t type;\n\n\tPartitionItemData(const int inIndex, const uint16_t& inType) {\n\t\tindex = inIndex;\n\t\ttype = inType;\n\t}\n};\n\n\n\nenum class ToolID {\n\tAny = -1,\n\tSelect = 0,\n\tMaskBrush,\n\tInflateBrush,\n\tDeflateBrush,\n\tMoveBrush,\n\tSmoothBrush,\n\tUndiffBrush,\n\tWeightBrush,\n\tColorBrush,\n\tAlphaBrush,\n\tCollapseVertex,\n\tFlipEdge,\n\tSplitEdge,\n\tMoveVertex,\n\tTransform,\n\tPivot,\n\tVertexEdit\n};\n\n\nstruct ConformOptions;\nstruct ClippingFixOptions;\nclass OutfitStudioFrame;\nclass EditUV;\nstruct SymmetricVertices;\nstruct VertexAsymmetries;\nstruct VertexAsymmetryTasks;\n\nenum OverlayLayer : uint32_t {\n\tDefault = 0,\n\tNodeSelection = 10,\n};\n\nenum class RotationCenterMode { Zero, MeshCenter, Picked };\n\nenum class MoveVertexOperation { None, Move, Weld, Merge };\n\nconstexpr float BrushSizeScale = 3.0f;\n\nclass wxGLPanel : public wxGLCanvas {\npublic:\n\tGLSurface gls;\n\tRotationCenterMode rotationCenterMode = RotationCenterMode::Zero;\n\n\twxGLPanel(wxWindow* parent, const wxSize& size, const wxGLAttributes& attribs);\n\t~wxGLPanel();\n\n\tvoid SetNotifyWindow(wxWindow* win);\n\n\tvoid AddMeshFromNif(nifly::NifFile* nif, const std::string& shapeName);\n\n\tvoid RenameShape(const std::string& shapeName, const std::string& newShapeName) { gls.RenameMesh(shapeName, newShapeName); }\n\n\tvoid SetMeshTextures(const std::string& shapeName,\n\t\t\t\t\t\t const std::vector<std::string>& textureFiles,\n\t\t\t\t\t\t const bool hasMatFile = false,\n\t\t\t\t\t\t const MaterialFile& matFile = MaterialFile(),\n\t\t\t\t\t\t const bool reloadTextures = false);\n\n\tMesh* GetMesh(const std::string& shapeName) { return gls.GetMesh(shapeName); }\n\n\tvoid UpdateMeshVertices(const std::string& shapeName,\n\t\t\t\t\t\t\tstd::vector<nifly::Vector3>* verts,\n\t\t\t\t\t\t\tbool updateBVH = true,\n\t\t\t\t\t\t\tbool recalcNormals = true,\n\t\t\t\t\t\t\tbool render = true,\n\t\t\t\t\t\t\tstd::vector<nifly::Vector2>* uvs = nullptr);\n\tvoid RecalculateMeshBVH(const std::string& shapeName);\n\n\tvoid ShowShape(const std::string& shapeName, bool show = true);\n\tvoid SetActiveShapes(const std::vector<std::string>& shapeNames);\n\tvoid SetSelectedShape(const std::string& shapeName);\n\n\tUndoHistory* GetUndoHistory() { return &undoHistory; }\n\n\tvoid SetActiveTool(ToolID brushID);\n\tToolID GetActiveTool() { return activeTool; }\n\n\tvoid SetLastTool(ToolID tool);\n\tToolID GetLastTool() { return lastTool; }\n\n\tTweakBrush* GetActiveBrush() { return activeBrush; }\n\n\tstd::vector<TweakBrush*> GetBrushList() {\n\t\tstd::vector<TweakBrush*> brushList{&inflateBrush,\n\t\t\t\t\t\t\t\t\t\t   &deflateBrush,\n\t\t\t\t\t\t\t\t\t\t   &moveBrush,\n\t\t\t\t\t\t\t\t\t\t   &smoothBrush,\n\t\t\t\t\t\t\t\t\t\t   &undiffBrush,\n\t\t\t\t\t\t\t\t\t\t   &maskBrush,\n\t\t\t\t\t\t\t\t\t\t   &weightBrush,\n\t\t\t\t\t\t\t\t\t\t   &colorBrush,\n\t\t\t\t\t\t\t\t\t\t   &alphaBrush};\n\n\t\treturn brushList;\n\t}\n\n\tvoid SetColorBrush(const nifly::Vector3& color) { colorBrush.color = color; }\n\n\tbool StartBrushStroke(const wxPoint& screenPos);\n\tvoid UpdateBrushStroke(const wxPoint& screenPos);\n\tvoid EndBrushStroke();\n\n\tbool StartTransform(const wxPoint& screenPos);\n\tvoid UpdateTransform(const wxPoint& screenPos);\n\tvoid EndTransform();\n\n\tbool StartPivotPosition(const wxPoint& screenPos);\n\tvoid UpdatePivotPosition(const wxPoint& screenPos);\n\tvoid EndPivotPosition();\n\n\tbool SelectVertex(const wxPoint& screenPos);\n\n\tbool StartPickVertex();\n\tvoid UpdatePickVertex(const wxPoint& screenPos);\n\tvoid EndPickVertex();\n\tvoid ClickCollapseVertex();\n\n\tbool StartPickEdge();\n\tvoid UpdatePickEdge(const wxPoint& screenPos);\n\tvoid EndPickEdge();\n\tvoid ClickFlipEdge();\n\tvoid ClickSplitEdge();\n\n\tbool StartMoveVertex(const wxPoint& screenPos);\n\tvoid UpdateMoveVertex(const wxPoint& screenPos);\n\tvoid EndMoveVertex();\n\tvoid CancelMoveVertex();\n\n\tbool RestoreMode(UndoStateProject* usp);\n\tvoid ApplyUndoState(UndoStateProject* usp, bool bUndo, bool bRender = true);\n\tbool UndoStroke();\n\tbool RedoStroke();\n\n\tvoid ShowRotationCenter(bool show = true);\n\n\tvoid ShowTransformTool(bool show = true);\n\tvoid UpdateTransformCenter();\n\tvoid UpdateTransformTool();\n\n\tvoid ShowPivot(bool show = true);\n\tvoid UpdatePivot();\n\n\tbool GetNodesMode() { return nodesMode; }\n\tvoid ShowNodes(bool show = true);\n\tvoid UpdateNodes();\n\tvoid UpdateNodeColors();\n\n\tbool GetBonesMode() { return bonesMode; }\n\tvoid ShowBones(bool show = true);\n\tbool IsBonesMode() { return bonesMode; }\n\tvoid UpdateBones();\n\n\tvoid ShowFloor(bool show = true);\n\tvoid UpdateFloor();\n\n\tvoid ShowVertexEdit(bool show = true);\n\n\tbool GetEditMode() { return editMode; }\n\tvoid SetEditMode(bool on = true) { editMode = on; }\n\n\tbool GetBrushMode() { return brushMode; }\n\tvoid SetBrushMode(bool on = true) { brushMode = on; }\n\n\tbool GetVertexEdit() { return vertexEdit; }\n\tvoid SetVertexEdit(bool on = true) {\n\t\tvertexEdit = on;\n\t\tShowVertexEdit(on);\n\t\tRender();\n\t}\n\n\tbool GetTransformMode() { return transformMode; }\n\tvoid SetTransformMode(bool on = true) {\n\t\ttransformMode = on;\n\t\tShowTransformTool(on);\n\t}\n\n\tbool GetPivotMode() { return pivotMode; }\n\tvoid SetPivotMode(bool on = true) {\n\t\tpivotMode = on;\n\t\tShowPivot(on);\n\n\t\tif (transformMode)\n\t\t\tShowTransformTool();\n\t}\n\n\tbool GetSegmentMode() { return segmentMode; }\n\tvoid SetSegmentMode(bool on = true) { segmentMode = on; }\n\n\tbool GetToolOptionXMirror() {\n\t\tif (activeTool == ToolID::WeightBrush)\n\t\t\treturn toolOptionXMirrorWeight;\n\t\treturn toolOptionXMirror;\n\t}\n\tvoid SetToolOptionXMirror(bool on = true) {\n\t\tif (activeTool == ToolID::WeightBrush)\n\t\t\ttoolOptionXMirrorWeight = on;\n\t\telse\n\t\t\ttoolOptionXMirror = on;\n\t\tgls.SetXMirrorCursor(on);\n\t}\n\n\tbool GetToolOptionConnectedOnly() { return toolOptionConnectedOnly; }\n\tvoid SetToolOptionConnectedOnly(bool on = true) { toolOptionConnectedOnly = on; }\n\n\tbool GetToolOptionMerge() { return toolOptionMerge; }\n\tvoid SetToolOptionMerge(bool on = true) { toolOptionMerge = on; }\n\n\tbool GetToolOptionWeld() { return toolOptionWeld; }\n\tvoid SetToolOptionWeld(bool on = true) { toolOptionWeld = on; }\n\n\tbool GetToolOptionRestrictSurface() { return toolOptionRestrictSurface; }\n\tvoid SetToolOptionRestrictSurface(bool on = true) { toolOptionRestrictSurface = on; }\n\n\tbool GetToolOptionRestrictPlane() { return toolOptionRestrictPlane; }\n\tvoid SetToolOptionRestrictPlane(bool on = true) { toolOptionRestrictPlane = on; }\n\n\tbool GetToolOptionRestrictNormal() { return toolOptionRestrictNormal; }\n\tvoid SetToolOptionRestrictNormal(bool on = true) { toolOptionRestrictNormal = on; }\n\n\tvoid SetShapeGhostMode(const std::string& shapeName, bool on = true) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tif (on)\n\t\t\tm->rendermode = Mesh::RenderMode::LitWire;\n\t\telse\n\t\t\tm->rendermode = Mesh::RenderMode::Normal;\n\t}\n\n\tvoid SetNormalSeamSmoothMode(bool enable) {\n\t\tfor (auto& m : gls.GetActiveMeshes()) {\n\t\t\tm->smoothSeamNormals = enable;\n\t\t\tm->SmoothNormals();\n\t\t}\n\t}\n\n\tvoid SetLockNormalsMode(bool enable) {\n\t\tfor (auto& m : gls.GetActiveMeshes())\n\t\t\tm->lockNormals = enable;\n\t}\n\n\tvoid RecalcNormals(const std::string& shapeName, bool force = false) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tbool oldLockNormals = m->lockNormals;\n\t\tif (m->lockNormals && force)\n\t\t\tm->lockNormals = false;\n\n\t\tm->SmoothNormals();\n\t\tm->lockNormals = oldLockNormals;\n\t}\n\n\tfloat GetBrushSize() { return brushSize / BrushSizeScale; }\n\tvoid SetBrushSize(float val) {\n\t\tval *= BrushSizeScale;\n\t\tbrushSize = val;\n\t\tgls.SetCursorSize(val);\n\t}\n\tvoid ResetBrushSize() {\n\t\tbrushSize = 0.45f;\n\t\tgls.SetCursorSize(brushSize);\n\t}\n\n\tfloat IncBrush() {\n\t\tgls.SetCursorSize(gls.GetCursorSize() + 0.010f);\n\t\tbrushSize += 0.010f;\n\t\tLimitBrushSize();\n\t\treturn brushSize;\n\t}\n\tfloat DecBrush() {\n\t\tgls.SetCursorSize(gls.GetCursorSize() - 0.010f);\n\t\tbrushSize -= 0.010f;\n\t\tLimitBrushSize();\n\t\treturn brushSize;\n\t}\n\n\tvoid LimitBrushSize() {\n\t\tif (brushSize < 0.000f) {\n\t\t\tgls.SetCursorSize(0.000f);\n\t\t\tbrushSize = 0.000f;\n\t\t}\n\t\telse if (brushSize > BrushSizeScale) {\n\t\t\tgls.SetCursorSize(BrushSizeScale);\n\t\t\tbrushSize = BrushSizeScale;\n\t\t}\n\t}\n\n\tfloat IncStr() {\n\t\tif (!activeBrush)\n\t\t\treturn 0.0f;\n\n\t\tfloat str = activeBrush->getStrength();\n\t\tstr += 0.010f;\n\t\tactiveBrush->setStrength(str);\n\t\treturn str;\n\t}\n\tfloat DecStr() {\n\t\tif (!activeBrush)\n\t\t\treturn 0.0f;\n\n\t\tfloat str = activeBrush->getStrength();\n\t\tstr -= 0.010f;\n\t\tactiveBrush->setStrength(str);\n\t\treturn str;\n\t}\n\n\tvoid SetCursorType(GLSurface::CursorType cursorType) { gls.SetCursorType(cursorType); }\n\n\tvoid ShowWireframe() { gls.ToggleWireframe(); }\n\n\tvoid ToggleLighting() { gls.ToggleLighting(); }\n\n\tvoid ToggleTextures() { gls.ToggleTextures(); }\n\n\tvoid SetMaskVisible(bool bVisible = true) { gls.SetMaskVisible(bVisible); }\n\n\tvoid SetWeightVisible(bool bVisible = true) { gls.SetWeightColors(bVisible); }\n\n\tvoid SetColorsVisible(bool bVisible = true) { gls.SetVertexColors(bVisible); }\n\n\tvoid ClearMasks() {\n\t\tfor (auto& m : gls.GetMeshes())\n\t\t\tm->MaskFill(0.0f);\n\t}\n\n\tvoid ClearActiveMask() {\n\t\tfor (auto& m : gls.GetActiveMeshes())\n\t\t\tm->MaskFill(0.0f);\n\t}\n\n\tvoid ClearColors() {\n\t\tfor (auto& m : gls.GetMeshes())\n\t\t\tm->ColorFill(nifly::Vector3());\n\t}\n\n\tvoid ClearActiveColors() {\n\t\tfor (auto& m : gls.GetActiveMeshes())\n\t\t\tm->ColorFill(nifly::Vector3());\n\t}\n\n\tvoid GetActiveMask(std::unordered_map<uint16_t, float>& mask) {\n\t\tif (gls.GetActiveMeshes().empty())\n\t\t\treturn;\n\n\t\tMesh* m = gls.GetActiveMeshes().back();\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tif (m->mask[i] != 0.0f)\n\t\t\t\tmask[i] = m->mask[i];\n\t\t}\n\t}\n\n\tvoid GetActiveUnmasked(std::unordered_map<uint16_t, float>& mask) {\n\t\tif (gls.GetActiveMeshes().empty())\n\t\t\treturn;\n\n\t\tMesh* m = gls.GetActiveMeshes().back();\n\n\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\tif (m->mask[i] == 0.0f)\n\t\t\t\tmask[i] = m->mask[i];\n\t}\n\n\tvoid GetShapeMask(std::unordered_map<uint16_t, float>& mask, const std::string& shapeName) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tif (m->mask[i] != 0.0f)\n\t\t\t\tmask[i] = m->mask[i];\n\t\t}\n\t}\n\n\tvoid GetShapeUnmasked(std::unordered_map<uint16_t, float>& mask, const std::string& shapeName) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\tif (m->mask[i] == 0.0f)\n\t\t\t\tmask[i] = m->mask[i];\n\t}\n\n\tvoid SetShapeMask(std::unordered_map<uint16_t, float>& mask, const std::string& shapeName) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tif (mask.find(i) != mask.end())\n\t\t\t\tm->mask[i] = mask[i];\n\t\t\telse\n\t\t\t\tm->mask[i] = 0.0f;\n\t\t}\n\n\t\tm->QueueUpdate(Mesh::UpdateType::Mask);\n\t}\n\n\tstd::unordered_map<std::string, std::vector<float>> StashMasks();\n\tvoid UnstashMasks(const std::unordered_map<std::string, std::vector<float>>& stash);\n\n\tvoid MaskLess();\n\tvoid MaskMore();\n\tvoid InvertMask();\n\tvoid ClearMask();\n\n\tvoid InvertMaskTris(std::unordered_map<uint16_t, float>& mask, const std::string& shapeName) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tstd::unordered_map<uint16_t, float> triMask;\n\t\tfor (int t = 0; t < m->nTris; t++) {\n\t\t\tauto& tri = m->tris[t];\n\t\t\tif (mask.find(tri.p1) != mask.end() || mask.find(tri.p2) != mask.end() || mask.find(tri.p3) != mask.end()) {\n\t\t\t\ttriMask.emplace(tri.p1, 1.0f);\n\t\t\t\ttriMask.emplace(tri.p2, 1.0f);\n\t\t\t\ttriMask.emplace(tri.p3, 1.0f);\n\t\t\t}\n\t\t}\n\n\t\tstd::unordered_map<uint16_t, float> invertMask;\n\t\tfor (int t = 0; t < m->nTris; t++) {\n\t\t\tauto& tri = m->tris[t];\n\t\t\tif (triMask.find(tri.p1) == triMask.end())\n\t\t\t\tinvertMask.emplace(tri.p1, 1.0f);\n\t\t\tif (triMask.find(tri.p2) == triMask.end())\n\t\t\t\tinvertMask.emplace(tri.p2, 1.0f);\n\t\t\tif (triMask.find(tri.p3) == triMask.end())\n\t\t\t\tinvertMask.emplace(tri.p3, 1.0f);\n\t\t}\n\n\t\tmask = std::move(invertMask);\n\t}\n\n\tnifly::Vector3 CreateColorRamp(const float value) {\n\t\tfloat r;\n\t\tfloat g;\n\t\tfloat b;\n\n\t\tif (value <= 0.0f) {\n\t\t\tr = g = b = 1.0;\n\t\t}\n\t\telse if (value <= 0.25) {\n\t\t\tr = 0.0;\n\t\t\tb = 1.0;\n\t\t\tg = value / 0.25;\n\t\t}\n\t\telse if (value <= 0.5) {\n\t\t\tr = 0.0;\n\t\t\tg = 1.0;\n\t\t\tb = 1.0 + (-1.0) * (value - 0.25) / 0.25;\n\t\t}\n\t\telse if (value <= 0.75) {\n\t\t\tr = (value - 0.5) / 0.25;\n\t\t\tg = 1.0;\n\t\t\tb = 0.0;\n\t\t}\n\t\telse {\n\t\t\tr = 1.0;\n\t\t\tg = 1.0 + (-1.0) * (value - 0.75) / 0.25;\n\t\t\tb = 0.0;\n\t\t}\n\n\t\treturn nifly::Vector3(r, g, b);\n\t}\n\n\tvoid DeleteMesh(const std::string& shape) {\n\t\tMesh* m = gls.GetMesh(shape);\n\t\tif (m) {\n\t\t\tBVHUpdateQueue.erase(m);\n\t\t\tgls.DeleteMesh(m);\n\t\t}\n\t}\n\n\tvoid Cleanup() {\n\t\tXMoveMesh = nullptr;\n\t\tYMoveMesh = nullptr;\n\t\tZMoveMesh = nullptr;\n\t\tXRotateMesh = nullptr;\n\t\tYRotateMesh = nullptr;\n\t\tZRotateMesh = nullptr;\n\t\tXScaleMesh = nullptr;\n\t\tYScaleMesh = nullptr;\n\t\tZScaleMesh = nullptr;\n\t\tScaleUniformMesh = nullptr;\n\n\t\tXPivotMesh = nullptr;\n\t\tYPivotMesh = nullptr;\n\t\tZPivotMesh = nullptr;\n\t\tPivotCenterMesh = nullptr;\n\n\t\tRotationCenterMesh = nullptr;\n\t\tRotationCenterMeshRingX = nullptr;\n\t\tRotationCenterMeshRingY = nullptr;\n\t\tRotationCenterMeshRingZ = nullptr;\n\n\t\tnodesPoints.clear();\n\t\tnodesLines.clear();\n\t\tbonesPoints.clear();\n\t\tbonesLines.clear();\n\t\tfloorMeshes.clear();\n\n\t\tBVHUpdateQueue.clear();\n\n\t\tgls.Cleanup();\n\t}\n\n\tvoid SetView(const char type) {\n\t\tgls.SetView(type);\n\n\t\tif (transformMode)\n\t\t\tShowTransformTool();\n\t\telse\n\t\t\tRender();\n\t}\n\n\tvoid SetPerspective(const bool enabled) {\n\t\tgls.SetPerspective(enabled);\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid SetFieldOfView(const int fieldOfView) {\n\t\tgls.SetFieldOfView(fieldOfView);\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid SetDepthClip(const float zNear, const float zFar) {\n\t\tgls.SetDepthClip(zNear, zFar);\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid UpdateLights(const int ambient,\n\t\t\t\t\t  const int frontal,\n\t\t\t\t\t  const int directional0,\n\t\t\t\t\t  const int directional1,\n\t\t\t\t\t  const int directional2,\n\t\t\t\t\t  const nifly::Vector3& directional0Dir = nifly::Vector3(),\n\t\t\t\t\t  const nifly::Vector3& directional1Dir = nifly::Vector3(),\n\t\t\t\t\t  const nifly::Vector3& directonal2Dir = nifly::Vector3()) {\n\t\tgls.UpdateLights(ambient, frontal, directional0, directional1, directional2, directional0Dir, directional1Dir, directonal2Dir);\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid Render() { gls.RenderOneFrame(); }\n\n\nprivate:\n\tvoid OnShown();\n\tvoid OnPaint(wxPaintEvent& event);\n\tvoid OnSize(wxSizeEvent& event);\n\n\tvoid OnMouseWheel(wxMouseEvent& event);\n\tvoid OnMouseMove(wxMouseEvent& event);\n\n\tvoid OnMiddleDown(wxMouseEvent& event);\n\tvoid OnMiddleUp(wxMouseEvent& event);\n\tvoid OnLeftDown(wxMouseEvent& event);\n\tvoid OnLeftUp(wxMouseEvent& event);\n\n\tvoid OnRightDown(wxMouseEvent& event);\n\tvoid OnRightUp(wxMouseEvent& event);\n\n\tvoid OnKeys(wxKeyEvent& event);\n\tvoid OnIdle(wxIdleEvent& event);\n\n\tvoid OnCaptureLost(wxMouseCaptureLostEvent& event);\n\n\tstd::unique_ptr<wxGLContext> context;\n\n\tbool rbuttonDown = false;\n\tbool lbuttonDown = false;\n\tbool mbuttonDown = false;\n\tbool isLDragging = false;\n\tbool isMDragging = false;\n\tbool isRDragging = false;\n\tbool firstPaint = true;\n\n\tint lastX = 0;\n\tint lastY = 0;\n\tGLSurface::CursorHitResult lastHitResult{};\n\tstd::string mouseDownMeshName;\n\tint mouseDownPoint;\n\tint mouseDownMirrorPoint;\n\tnifly::Edge mouseDownEdge;\n\tnifly::Vector3 mouseDownViewDir;\n\tbool mouseHasMovedSinceStart = false;\n\twxPoint mouseDownOffset;\n\tnifly::Vector3 mouseDownPointNormal;\n\tfloat snapDistance = 0.0f;\n\tMoveVertexOperation moveVertexOperation = MoveVertexOperation::None;\n\tint moveVertexTarget;\n\tstd::string moveVertexWeldTargetMeshName;\n\n\tstd::set<Mesh*> BVHUpdateQueue;\n\n\tOutfitStudioFrame* os = nullptr;\n\n\tfloat brushSize = 0.45f;\n\n\tbool editMode = false;\n\tbool brushMode = false;\n\tbool transformMode = false;\n\tbool pivotMode = false;\n\tbool nodesMode = false;\n\tbool bonesMode = false;\n\tbool floorMode = false;\n\tbool vertexEdit = false;\n\tbool segmentMode = false;\n\n\tToolID activeTool = ToolID::Select;\n\tToolID lastTool = ToolID::Select;\n\tbool isPainting = false;\n\tbool isTransforming = false;\n\tbool isMovingPivot = false;\n\tbool isSelecting = false;\n\tbool isPickingVertex = false;\n\tbool isPickingEdge = false;\n\tbool isMovingVertex = false;\n\tbool toolOptionXMirror = true;\n\tbool toolOptionXMirrorWeight = false;\n\tbool toolOptionConnectedOnly = false;\n\tbool toolOptionMerge = false;\n\tbool toolOptionWeld = false;\n\tbool toolOptionRestrictSurface = false;\n\tbool toolOptionRestrictPlane = false;\n\tbool toolOptionRestrictNormal = false;\n\n\tTweakBrush* activeBrush = nullptr;\n\tTweakBrush* savedBrush;\n\n\tTB_Inflate inflateBrush;\n\tTB_Deflate deflateBrush;\n\tTB_Move moveBrush;\n\tTB_Smooth smoothBrush;\n\tTB_Undiff undiffBrush;\n\tTB_Mask maskBrush;\n\tTB_Unmask UnMaskBrush;\n\tTB_SmoothMask smoothMaskBrush;\n\tTB_Weight weightBrush;\n\tTB_Unweight unweightBrush;\n\tTB_SmoothWeight smoothWeightBrush;\n\tTB_Color colorBrush;\n\tTB_Uncolor uncolorBrush;\n\tTB_Alpha alphaBrush;\n\tTB_Unalpha unalphaBrush;\n\tTB_XForm translateBrush;\n\n\tstd::unique_ptr<TweakStroke> activeStroke;\n\tUndoHistory undoHistory;\n\n\tMesh* RotationCenterMesh = nullptr;\n\tMesh* RotationCenterMeshRingX = nullptr;\n\tMesh* RotationCenterMeshRingY = nullptr;\n\tMesh* RotationCenterMeshRingZ = nullptr;\n\n\tMesh* XMoveMesh = nullptr;\n\tMesh* YMoveMesh = nullptr;\n\tMesh* ZMoveMesh = nullptr;\n\tMesh* XRotateMesh = nullptr;\n\tMesh* YRotateMesh = nullptr;\n\tMesh* ZRotateMesh = nullptr;\n\tMesh* XScaleMesh = nullptr;\n\tMesh* YScaleMesh = nullptr;\n\tMesh* ZScaleMesh = nullptr;\n\tMesh* ScaleUniformMesh = nullptr;\n\tnifly::Vector3 xformCenter; // Transform center for transform brushes (rotate, specifically cares about this)\n\tnifly::Vector3 xformCenterInitial;\n\t// Snapshots of the active bone/node's transforms at the start of a\n\t// bones/nodes-mode transform stroke.  Used to apply the accumulated drag\n\t// offset as an absolute change from the initial pose each frame, so that\n\t// the bone/node does not double-integrate its own movement.\n\tnifly::MatTransform xformInitialLocalToParent;\n\tnifly::MatTransform xformInitialParentToGlobal;\n\t// Active transform kind while editing a bone/node in bones/nodes mode.\n\t// 0 = translate, 1 = rotate.\n\tint boneXformType = 0;\n\t// Initial pick origin (model space) and rotation-plane normal (model\n\t// space) for a bones/nodes-mode rotation stroke.\n\tnifly::Vector3 boneXformPickStart;\n\tnifly::Vector3 boneXformPlaneNormalModel;\n\tnifly::Vector3 boneXformAxisModel;\n\tfloat boneXformPlaneDist = 0.0f;\n\t// Pose-mode transform: editing the bone's poseTranVec/poseRotVec only.\n\t// No NIF changes, no undo state.\n\tbool boneXformPoseMode = false;\n\tnifly::Vector3 boneXformPoseInitialTran;\n\tnifly::Vector3 boneXformPoseInitialRot;\n\tfloat lastCenterDistance = 0.0f;\n\n\tMesh* XPivotMesh = nullptr;\n\tMesh* YPivotMesh = nullptr;\n\tMesh* ZPivotMesh = nullptr;\n\tMesh* PivotCenterMesh = nullptr;\n\tnifly::Vector3 pivotPosition;\n\tfloat lastCenterPivotDistance = 0.0f;\n\n\tstd::vector<Mesh*> nodesPoints;\n\tstd::vector<Mesh*> nodesLines;\n\tstd::vector<Mesh*> bonesPoints;\n\tstd::vector<Mesh*> bonesLines;\n\tstd::vector<Mesh*> floorMeshes;\n\n\twxDECLARE_EVENT_TABLE();\n};\n\n\nstatic const wxCmdLineEntryDesc g_cmdLineDesc[] = {{wxCMD_LINE_OPTION, \"proj\", \"project\", \"Project Name\", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL},\n\t\t\t\t\t\t\t\t\t\t\t\t   {wxCMD_LINE_OPTION, \"single\", \"single-instance\", \"Force single instance behavior (yes/no)\", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL},\n\t\t\t\t\t\t\t\t\t\t\t\t   {wxCMD_LINE_PARAM, nullptr, nullptr, \"Files\", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE},\n\t\t\t\t\t\t\t\t\t\t\t\t   wxCMD_LINE_DESC_END};\n\nstd::string GetProjectPath();\n\nclass OutfitStudio : public wxApp {\npublic:\n\tvirtual ~OutfitStudio();\n\n\tvirtual bool OnInit();\n\tvirtual void OnInitCmdLine(wxCmdLineParser& parser);\n\tvirtual bool OnCmdLineParsed(wxCmdLineParser& parser);\n\n\tvirtual bool OnExceptionInMainLoop();\n\tvirtual void OnUnhandledException();\n\tvirtual void OnFatalException();\n\n\tvoid CharHook(wxKeyEvent& event);\n\n\twxString GetGameDataPath(TargetGame targ);\n\n\tvoid InitLanguage();\n\n\tbool SetDefaultConfig();\n\tbool ShowSetup();\n\n\tvoid InitArchives();\n\tvoid GetArchiveFiles(std::vector<std::string>& outList);\n\n\tTargetGame targetGame = TargetGame::FO3;\n\nprivate:\n\tOutfitStudioFrame* frame = nullptr;\n\n\tLog logger;\n\twxLocale* locale = nullptr;\n\tint language = 0;\n\n\twxArrayString cmdFiles;\n\twxString cmdProject;\n\tint cmdForceSingleInstanceBehavior = -1;  // -1 = not set, 0 = no (force new), 1 = yes (force existing)\n\n\t// DDE uses a service name, TCP uses a port number\n#if defined(__WINDOWS__) && wxUSE_DDE_FOR_IPC\n\tconst wxString OS_IPC_SERVICE = \"OutfitStudioIPC\";\n#else\n\tconst wxString OS_IPC_SERVICE = \"54318\";\n#endif\n\n\t// Single instance checker and IPC server\n\twxSingleInstanceChecker* singleChecker = nullptr;\n\twxServer* ipcServer = nullptr;\n};\n\nstruct ProjectHistoryEntry {\n\tstd::string fileName;\n\tstd::string projectName;\n};\n\nclass OutfitProject;\nclass wxBrushSettingsPopupTransient;\n\nclass ToolBarButtonHider {\npublic:\n\tstruct ButDat {\n\t\tint id = 0;\n\t\tstd::unique_ptr<wxToolBarToolBase> but;\n\t};\n\tstd::vector<ButDat> butdats;\n\twxToolBar* tb = nullptr;\n\n\tvoid Init(wxToolBar* tbi);\n\tvoid Show(int toolId, bool show);\n};\n\nclass OutfitStudioFrame : public wxFrame {\npublic:\n\tOutfitStudioFrame(const wxPoint& pos, const wxSize& size);\n\t~OutfitStudioFrame() {}\n\n\tvoid LoadFiles(const wxArrayString& files, const wxString& projectName = \"\");\n\n\tconst std::vector<RefTemplate>& GetRefTemplates() const { return refTemplates; }\n\n\twxGLPanel* glView = nullptr;\n\tEditUV* editUV = nullptr;\n\tOutfitProject* project = nullptr;\n\tShapeItemData* activeItem = nullptr;\n\tstd::string activeSlider;\n\tstd::string lastActiveSlider;\n\tbool bEditSlider = false;\n\tbool autoFrameSelected = false;\n\tstd::vector<int> triParts;\t// the partition index for each triangle, or -1 for none\n\tstd::vector<int> triSParts; // the segment partition index for each triangle, or -1 for none\n\n\tstd::deque<ProjectHistoryEntry> projectHistory;\n\n\tstd::unordered_set<std::string> lastSelectedBones;\n\tstd::unordered_set<std::string> lastNormalizeBones;\n\n\tPoseDataCollection poseDataCollection;\n\twxSliderPanelPool sliderPool;\n\n\twxTreeCtrl* outfitShapes = nullptr;\n\twxTreeCtrl* outfitBones = nullptr;\n\twxPanel* colorSettings = nullptr;\n\twxTreeCtrl* segmentTree = nullptr;\n\twxTreeCtrl* partitionTree = nullptr;\n\twxPanel* lightSettings = nullptr;\n\twxChoice* cXMirrorBone = nullptr;\n\twxChoice* cPoseBone = nullptr;\n\twxSlider* rxPoseSlider = nullptr;\n\twxSlider* ryPoseSlider = nullptr;\n\twxSlider* rzPoseSlider = nullptr;\n\twxSlider* txPoseSlider = nullptr;\n\twxSlider* tyPoseSlider = nullptr;\n\twxSlider* tzPoseSlider = nullptr;\n\twxSlider* scPoseSlider = nullptr;\n\twxTextCtrl* rxPoseText = nullptr;\n\twxTextCtrl* ryPoseText = nullptr;\n\twxTextCtrl* rzPoseText = nullptr;\n\twxTextCtrl* txPoseText = nullptr;\n\twxTextCtrl* tyPoseText = nullptr;\n\twxTextCtrl* tzPoseText = nullptr;\n\twxTextCtrl* scPoseText = nullptr;\n\twxCheckBox* cbPose = nullptr;\n\twxButton* poseToMesh = nullptr;\n\twxScrolledWindow* sliderScroll = nullptr;\n\twxMenuBar* menuBar = nullptr;\n\twxToolBar* toolBarH = nullptr;\n\twxToolBar* toolBarV = nullptr;\n\tToolBarButtonHider tbvHider;\n\twxStatusBar* statusBar = nullptr;\n\n\twxSearchCtrl* sliderFilter = nullptr;\n\twxSearchCtrl* bonesFilter = nullptr;\n\n\twxStateButton* currentTabButton = nullptr;\n\twxStateButton* meshTabButton = nullptr;\n\twxStateButton* boneTabButton = nullptr;\n\twxStateButton* colorsTabButton = nullptr;\n\twxStateButton* segmentTabButton = nullptr;\n\twxStateButton* partitionTabButton = nullptr;\n\twxStateButton* lightsTabButton = nullptr;\n\twxButton* brushSettings = nullptr;\n\twxSlider* fovSlider = nullptr;\n\twxCheckBox* cbDepthClip = nullptr;\n\twxBrushSettingsPopupTransient* brushSettingsPopupTransient = nullptr;\n\twxCollapsiblePane* masksPane = nullptr;\n\twxCollapsiblePane* posePane = nullptr;\n\twxCollapsiblePane* notesPane = nullptr;\n\twxTextCtrl* projectNotes = nullptr;\n\n\twxTreeItemId shapesRoot;\n\twxTreeItemId outfitRoot;\n\twxTreeItemId bonesRoot;\n\twxTreeItemId segmentRoot;\n\twxTreeItemId partitionRoot;\n\n\tstd::map<std::string, wxSliderPanel*> sliderPanels;\n\n\tvoid SetPendingChanges(bool pending = true);\n\tbool CheckPendingChanges();\n\n\tvoid UpdateUndoTools();\n\n\tbool SaveProject();\n\tbool SaveProjectAs();\n\tbool LoadProject(const std::string& fileName, const std::string& projectName = \"\", bool clearProject = true);\n\tvoid CreateSetSliders();\n\n\tvoid UpdateReferenceTemplates();\n\tvoid ResetProject();\n\n\tstd::string NewSlider(const std::string& suggestedName = \"\", bool skipPrompt = false);\n\n\tvoid SetSliderValue(const size_t index, int val);\n\tvoid SetSliderValue(const std::string& name, int val);\n\tvoid ZeroSliders();\n\n\tvoid ApplySliders(bool recalcBVH = true);\n\n\tvoid ShowSliderEffect(const std::string& sliderName, bool show = true);\n\n\tvoid SelectShape(const std::string& shapeName);\n\tstd::vector<std::string> GetShapeList();\n\n\tvoid UpdateShapeSource(nifly::NiShape* shape);\n\tvoid UpdateVertexColors();\n\n\tvoid ActiveShapesUpdated(UndoStateProject* usp, bool bIsUndo = false);\n\tvoid UpdateActiveShape();\n\tvoid UpdateBoneCounts();\n\tvoid HighlightSliderData();\n\tvoid HighlightBoneNamesWithWeights();\n\tvoid RefreshGUIWeightColors();\n\tvoid PoseToGUI();\n\tvoid GetNormalizeBones(std::vector<std::string>* normBones, std::vector<std::string>* notNormBones);\n\tstd::vector<std::string> GetSelectedBones();\n\tvoid CalcAutoXMirrorBone();\n\tstd::string GetXMirrorBone();\n\n\tvoid ShowSegment(const wxTreeItemId& item = nullptr);\n\tvoid UpdateSegmentNames();\n\tbool PaintSegmentPartitionTriangles(Mesh* hitMesh, int hitTri, const nifly::Vector3& hitPointModel, float radiusModel);\n\n\tvoid ShowPartition(const wxTreeItemId& item = nullptr);\n\tvoid UpdatePartitionNames();\n\n\tvoid SetSubMeshesForPartitions(Mesh* m, const std::vector<int>& tp);\n\tvoid SetNoSubMeshes(Mesh* m);\n\tvoid SetNoSubMeshes();\n\n\tvoid LockShapeSelect();\n\tvoid UnlockShapeSelect();\n\tvoid UpdateAnimationGUI();\n\tvoid UpdateBoneItemState(const wxTreeItemId& item, const std::string& boneName);\n\tvoid UpdateBoneTree();\n\tvoid RefreshGUIFromProj(bool render = true, bool stashMasks = true);\n\tvoid MeshesFromProj(const bool reloadTextures = false);\n\tvoid MeshFromProj(nifly::NiShape* shape, const bool reloadTextures = false);\n\n\tvoid UpdateShapeReference(nifly::NiShape* shape, nifly::NiShape* newShape);\n\tstd::vector<ShapeItemData*>& GetSelectedItems();\n\tvoid ClearSelected(nifly::NiShape* shape);\n\tstd::string GetActiveBone();\n\n\tbool CheckEditableState();\n\n\tvoid HideSliderPanel(wxSliderPanel* sliderPanel);\n\tvoid EnterSliderEdit(const std::string& sliderName = \"\");\n\tvoid ExitSliderEdit();\n\tvoid MenuEnterSliderEdit();\n\tvoid MenuExitSliderEdit();\n\tvoid ScrollToActiveSlider();\n\n\tvoid SelectTool(ToolID tool);\n\tvoid ReEnableToolOptionsUI();\n\tvoid ReToggleToolOptionsUI();\n\n\tvoid CloseBrushSettings();\n\tvoid PopupBrushSettings(wxWindow* popupAt = nullptr);\n\tvoid UpdateBrushSettings();\n\tvoid DeleteSliders(bool keepSliders = false, bool keepZaps = false);\n\tint CopyBoneWeightForShapes(std::vector<nifly::NiShape*> shapes, bool silent = false);\n\tint ConformShapes(std::vector<nifly::NiShape*> shapes, bool silent = false);\n\tvoid SetBaseShape();\n\tvoid UpdateTitle();\n\n\tvoid CheckBrushBounds() {\n\t\tTweakBrush* brush = glView->GetActiveBrush();\n\t\tif (!brush)\n\t\t\treturn;\n\n\t\tfloat size = glView->GetBrushSize();\n\t\tfloat strength = brush->getStrength();\n\t\t//float focus = brush->getFocus();\n\t\t//float spacing = brush->getSpacing();\n\n\t\tif (size >= 1.0f)\n\t\t\tmenuBar->Enable(XRCID(\"btnIncreaseSize\"), false);\n\t\telse\n\t\t\tmenuBar->Enable(XRCID(\"btnIncreaseSize\"), true);\n\n\t\tif (size <= 0.0f)\n\t\t\tmenuBar->Enable(XRCID(\"btnDecreaseSize\"), false);\n\t\telse\n\t\t\tmenuBar->Enable(XRCID(\"btnDecreaseSize\"), true);\n\n\t\tif (strength >= 1.0f)\n\t\t\tmenuBar->Enable(XRCID(\"btnIncreaseStr\"), false);\n\t\telse\n\t\t\tmenuBar->Enable(XRCID(\"btnIncreaseStr\"), true);\n\n\t\tif (strength <= 0.0f)\n\t\t\tmenuBar->Enable(XRCID(\"btnDecreaseStr\"), false);\n\t\telse\n\t\t\tmenuBar->Enable(XRCID(\"btnDecreaseStr\"), true);\n\t}\n\n\twxGauge* progressBar = nullptr;\n\tstd::vector<std::pair<int, int>> progressStack;\n\tint progressVal = 0;\n\n\tvoid StartProgress(const wxString& msg = \"\") {\n\t\tif (progressStack.empty()) {\n\t\t\tprogressVal = 0;\n\t\t\tprogressStack.emplace_back(0, 10000);\n\n\t\t\twxRect rect;\n\t\t\tstatusBar->GetFieldRect(1, rect);\n\n\t\t\twxBeginBusyCursor();\n\t\t\tprogressBar = new wxGauge(statusBar, wxID_ANY, 10000, rect.GetPosition(), rect.GetSize());\n\n\t\t\tif (msg.IsEmpty())\n\t\t\t\tstatusBar->SetStatusText(_(\"Starting...\"));\n\t\t\telse\n\t\t\t\tstatusBar->SetStatusText(msg);\n\t\t}\n\t}\n\n\tvoid StartSubProgress(int min, int max) {\n\t\tint range = progressStack.back().second - progressStack.back().first;\n\t\tfloat mindiv = min / 100.0f;\n\t\tfloat maxdiv = max / 100.0f;\n\t\tint minoff = mindiv * range + 1;\n\t\tint maxoff = maxdiv * range + 1;\n\t\tprogressStack.emplace_back(minoff + progressStack.back().first, maxoff + progressStack.back().first);\n\t}\n\n\tvoid EndProgress(const wxString& msg = \"\", bool forceEmpty = false) {\n\t\tif (progressStack.empty())\n\t\t\treturn;\n\n\t\tif (forceEmpty) {\n\t\t\tprogressBar->SetValue(progressStack.front().second);\n\t\t\tprogressStack.clear();\n\t\t}\n\t\telse {\n\t\t\tprogressBar->SetValue(progressStack.back().second);\n\t\t\tprogressStack.pop_back();\n\t\t}\n\n\t\tif (progressStack.empty()) {\n\t\t\tif (msg.IsEmpty())\n\t\t\t\tstatusBar->SetStatusText(_(\"Ready!\"));\n\t\t\telse\n\t\t\t\tstatusBar->SetStatusText(msg);\n\n\t\t\tdelete progressBar;\n\t\t\tprogressBar = nullptr;\n\t\t\twxEndBusyCursor();\n\t\t}\n\t}\n\n\tvoid UpdateProgress(int val, const wxString& msg = \"\") {\n\t\tif (progressStack.empty())\n\t\t\treturn;\n\n\t\tint range = progressStack.back().second - progressStack.back().first;\n\t\tfloat div = val / 100.0f;\n\t\tint offset = range * div + 1;\n\n\t\tprogressVal = progressStack.back().first + offset;\n\t\tif (progressVal > 10000)\n\t\t\tprogressVal = 10000;\n\n\t\tstatusBar->SetStatusText(msg);\n\t\tprogressBar->SetValue(progressVal);\n\t}\n\nprivate:\n\tbool pendingChanges = false;\n\n\tbool selectionLocked = false;\n\tstd::vector<ShapeItemData*> selectedItems;\n\tbool recursingUI = false;\n\tstd::string activeBone;\n\tstd::string autoXMirrorBone;\n\twxTreeItemId activeSegment;\n\twxTreeItemId activePartition;\n\tstd::string lastCheckedSlider;\n\n\tstd::vector<RefTemplate> refTemplates;\n\n\twxBitmap* bmpEditSlider = nullptr;\n\twxBitmap* bmpEditSliderGreen = nullptr;\n\twxBitmap* bmpSliderSettings = nullptr;\n\n\tvoid createSliderGUI(const std::string& name, wxScrolledWindow* wnd, wxSizer* rootSz);\n\n\tvoid ScrollWindowIntoView(wxScrolledWindow* scrolled, wxWindow* window);\n\tvoid HighlightSlider(const std::string& name);\n\n\tvoid ClearProject();\n\tvoid RenameProject(const std::string& projectName);\n\n\tvoid UpdateMeshFromSet(nifly::NiShape* shape);\n\tvoid FillVertexColors();\n\n\tbool ShapeSelectionCheck();\n\n\tbool HasUnweightedCheck();\n\tvoid CalcCopySkinTransOption(WeightCopyOptions& options);\n\tvoid ReselectBone();\n\n\tint CopySegPartForShapes(std::vector<nifly::NiShape*> shapes, bool silent = false);\n\n\tbool ShowVertexAsym(Mesh* m, const SymmetricVertices& symverts, const VertexAsymmetries& asyms, VertexAsymmetryTasks& tasks, const std::vector<bool>& selVerts, bool trize);\n\n\tvoid OnExit(wxCommandEvent& event);\n\tvoid OnClose(wxCloseEvent& event);\n\n\tbool CopyStreamData(wxInputStream& inputStream, wxOutputStream& outputStream, wxFileOffset size);\n\n\tvoid OnMenuItem(wxCommandEvent& event);\n\tvoid OnPackProjects(wxCommandEvent& event);\n\tvoid OnChooseTargetGame(wxCommandEvent& event);\n\tvoid SettingsFillDataFiles(wxCheckListBox* dataFileList, wxString& dataDir, int targetGame);\n\tvoid OnSettings(wxCommandEvent& event);\n\n\tvoid OnSashPosChanged(wxSplitterEvent& event);\n\tvoid OnMoveWindowStart(wxMoveEvent& event);\n\tvoid OnMoveWindowEnd(wxMoveEvent& event);\n\tvoid OnSetSize(wxSizeEvent& event);\n\n\tvoid AddProjectHistory(const std::string& fileName, const std::string& projectName);\n\tvoid UpdateProjectHistory();\n\n\tvoid OnNewProject(wxCommandEvent& event);\n\tvoid OnLoadProject(wxCommandEvent& event);\n\tvoid OnAddProject(wxCommandEvent& event);\n\tvoid OnLoadReference(wxCommandEvent& event);\n\tvoid OnConvertBodyReference(wxCommandEvent& event);\n\tvoid OnRunAutomation(wxCommandEvent& event);\n\tvoid OnLoadOutfit(wxCommandEvent& event);\n\tvoid OnUnloadProject(wxCommandEvent& event);\n\n\tvoid OnLoadOutfitFP_File(wxFileDirPickerEvent& event);\n\tvoid OnLoadOutfitFP_Texture(wxFileDirPickerEvent& event);\n\n\tvoid OnSetBaseShape(wxCommandEvent& event);\n\tvoid OnMakeConvRef(wxCommandEvent& event);\n\n\tvoid OnImportNIF(wxCommandEvent& event);\n\tvoid OnExportNIF(wxCommandEvent& event);\n\tvoid OnExportNIFWithRef(wxCommandEvent& event);\n\tvoid OnExportShapeNIF(wxCommandEvent& event);\n\n\tstd::optional<bool> PromptStarfieldGeometryMode();\n\n\tvoid OnImportOBJ(wxCommandEvent& event);\n\tvoid OnExportOBJ(wxCommandEvent& event);\n\tvoid OnExportShapeOBJ(wxCommandEvent& event);\n\n\tvoid OnImportFBX(wxCommandEvent& event);\n\tvoid OnExportFBX(wxCommandEvent& event);\n\tvoid OnExportShapeFBX(wxCommandEvent& event);\n\n\tvoid OnImportTRIHead(wxCommandEvent& event);\n\tvoid OnExportTRIHead(wxCommandEvent& event);\n\tvoid OnExportShapeTRIHead(wxCommandEvent& event);\n\n\tvoid OnImportPhysicsData(wxCommandEvent& event);\n\tvoid OnExportPhysicsData(wxCommandEvent& event);\n\n\tvoid OnSSSNameCopy(wxCommandEvent& event);\n\tvoid OnSSSGenWeightsTrue(wxCommandEvent& event);\n\tvoid OnSSSGenWeightsFalse(wxCommandEvent& event);\n\tvoid OnSaveSliderSet(wxCommandEvent& event);\n\tvoid OnSaveSliderSetAs(wxCommandEvent& event);\n\n\tvoid OnSlider(wxCommandEvent& event);\n\tvoid OnClickSliderButton(wxCommandEvent& event);\n\tvoid OnEnterHoverSlider(wxMouseEvent& event);\n\tvoid OnLeaveHoverSlider(wxMouseEvent& event);\n\tvoid OnReadoutChange(wxCommandEvent& event);\n\tvoid OnSliderCheckBox(wxCommandEvent& event);\n\n\tvoid OnTabButtonClick(wxCommandEvent& event);\n\tvoid OnBrushColorChanged(wxColourPickerEvent& event);\n\tvoid OnColorClampMaxValueSlider(wxCommandEvent& event);\n\tvoid OnColorClampMaxValueChanged(wxCommandEvent& event);\n\tvoid OnSwapBrush(wxCommandEvent& event);\n\tvoid OnMaskVertexColor(wxCommandEvent& event);\n\tvoid OnFixedWeight(wxCommandEvent& event);\n\tvoid OnCBNormalizeWeights(wxCommandEvent& event);\n\tvoid OnSelectSliders(wxCommandEvent& event);\n\n\tvoid OnSliderFilterChanged(wxCommandEvent&);\n\tvoid DoFilterSliders();\n\n\tvoid OnBonesFilterChanged(wxCommandEvent&);\n\n\tvoid ToggleVisibility(wxTreeItemId firstItem = wxTreeItemId());\n\tvoid OnShapeVisToggle(wxTreeEvent& event);\n\tvoid OnShapeSelect(wxTreeEvent& event);\n\tvoid OnShapeActivated(wxTreeEvent& event);\n\tvoid OnShapeContext(wxTreeEvent& event);\n\tvoid OnShapeDrag(wxTreeEvent& event);\n\tvoid OnShapeDrop(wxTreeEvent& event);\n\tvoid OnCheckTreeSel(wxTreeEvent& event);\n\n\tvoid ToggleBoneState(wxTreeItemId firstItem = wxTreeItemId());\n\tvoid OnBoneStateToggle(wxTreeEvent& event);\n\tvoid OnBoneSelect(wxTreeEvent& event);\n\tvoid OnBoneActivated(wxTreeEvent& event);\n\tvoid OnBoneContext(wxTreeEvent& event);\n\tvoid OnBoneTreeContext(wxCommandEvent& event);\n\n\tint CalcMaxSegPartID();\n\tvoid OnSegmentSelect(wxTreeEvent& event);\n\tvoid OnSegmentContext(wxTreeEvent& event);\n\tvoid OnSegmentTreeContext(wxCommandEvent& event);\n\tvoid OnAddSegment(wxCommandEvent& event);\n\tvoid OnAddSubSegment(wxCommandEvent& event);\n\tvoid OnDeleteSegment(wxCommandEvent& event);\n\tvoid OnDeleteSubSegment(wxCommandEvent& event);\n\n\tvoid UpdateActiveSlotID();\n\tvoid OnSegmentSlotChanged(wxCommandEvent& event);\n\n\tvoid OnSegmentTypeChanged(wxCommandEvent& event);\n\tvoid OnSegmentApply(wxCommandEvent& event);\n\tvoid ApplySegments();\n\tvoid OnSegmentReset(wxCommandEvent& event);\n\tvoid ResetSegments();\n\tvoid OnSegmentEditSSF(wxCommandEvent& event);\n\n\tvoid OnPartitionSelect(wxTreeEvent& event);\n\tvoid OnPartitionContext(wxTreeEvent& event);\n\tvoid OnPartitionTreeContext(wxCommandEvent& event);\n\tvoid OnAddPartition(wxCommandEvent& event);\n\tvoid OnDeletePartition(wxCommandEvent& event);\n\tvoid OnPartitionTypeChanged(wxCommandEvent& event);\n\tvoid OnPartitionApply(wxCommandEvent& event);\n\tvoid ApplyPartitions();\n\tvoid OnPartitionReset(wxCommandEvent& event);\n\tvoid ResetPartitions();\n\n\tvoid CreateSegmentTree(nifly::NiShape* shape = nullptr);\n\tvoid CreatePartitionTree(nifly::NiShape* shape = nullptr);\n\n\tvoid OnSelectTool(wxCommandEvent& event);\n\n\tvoid OnSetView(wxCommandEvent& event);\n\tvoid OnTogglePerspective(wxCommandEvent& event);\n\tvoid OnToggleRotationCenter(wxCommandEvent& event);\n\tvoid OnFrameSelected(wxCommandEvent& event);\n\tvoid FrameSelected();\n\tvoid OnShowNodes(wxCommandEvent& event);\n\tvoid OnShowBones(wxCommandEvent& event);\n\tvoid OnShowFloor(wxCommandEvent& event);\n\tvoid OnBrushSettings(wxCommandEvent& event);\n\tvoid OnFieldOfViewSlider(wxCommandEvent& event);\n\tvoid OnDepthClip(wxCommandEvent& event);\n\tvoid OnUpdateLights(wxCommandEvent& event);\n\tvoid OnResetLights(wxCommandEvent& event);\n\n\tvoid OnLoadPreset(wxCommandEvent& event);\n\tvoid OnSavePreset(wxCommandEvent& event);\n\tbool ShowConform(ConformOptions& options, bool silent = false);\n\tvoid ConformSliders(nifly::NiShape* shape, const ConformOptions& options);\n\tvoid OnSliderConform(wxCommandEvent& event);\n\tvoid OnSliderConformAll(wxCommandEvent& event);\n\tvoid OnSliderImportNIF(wxCommandEvent& event);\n\tvoid OnSliderImportBSD(wxCommandEvent& event);\n\tvoid OnSliderImportOBJ(wxCommandEvent& event);\n\tvoid OnSliderImportOSD(wxCommandEvent& event);\n\tvoid OnSliderImportTRI(wxCommandEvent& event);\n\tvoid OnSliderImportMorphsSF(wxCommandEvent& event);\n\tvoid OnSliderImportFBX(wxCommandEvent& event);\n\tvoid OnSliderExportNIF(wxCommandEvent& event);\n\tvoid OnSliderExportBSD(wxCommandEvent& event);\n\tvoid OnSliderExportOBJ(wxCommandEvent& event);\n\tvoid OnSliderExportOSD(wxCommandEvent& event);\n\tvoid OnSliderExportTRI(wxCommandEvent& event);\n\tvoid OnSliderExportMorphsSF(wxCommandEvent& event);\n\tvoid OnSliderExportToOBJs(wxCommandEvent& event);\n\n\tvoid OnNewSlider(wxCommandEvent& event);\n\tvoid OnNewZapSlider(wxCommandEvent& event);\n\tvoid OnNewCombinedSlider(wxCommandEvent& event);\n\tvoid OnSliderClone(wxCommandEvent& event);\n\tvoid OnSliderNegate(wxCommandEvent& event);\n\tvoid OnMaskAffected(wxCommandEvent& event);\n\tvoid OnClearSlider(wxCommandEvent& event);\n\tvoid OnDeleteSlider(wxCommandEvent& event);\n\n\tvoid ShowSliderProperties(const std::string& sliderName);\n\tvoid OnSliderProperties(wxCommandEvent& event);\n\tvoid OnSliderFixClipping(wxCommandEvent& event);\n\n\tbool ShowClippingFixStrength(float& outStrength);\n\tvoid FixClippingForShape(const std::vector<nifly::Vector3>& bodyVerts,\n\t\t\t\t\t\t\tconst std::vector<nifly::Triangle>& bodyTris,\n\t\t\t\t\t\t\tnifly::NiShape* shape,\n\t\t\t\t\t\t\tconst std::vector<nifly::Vector3>& outfitVerts,\n\t\t\t\t\t\t\tconst ClippingFixOptions& options,\n\t\t\t\t\t\t\tUndoStateProject* usp,\n\t\t\t\t\t\t\tconst std::unordered_set<uint16_t>* allowedVerts = nullptr);\n\n\tvoid OnInvertUV(wxCommandEvent& event);\n\tvoid OnMirrorShape(wxCommandEvent& event);\n\n\tvoid OnEnterClose(wxKeyEvent& event);\n\n\tvoid OnMoveShape(wxCommandEvent& event);\n\tvoid OnScaleShape(wxCommandEvent& event);\n\tvoid OnRotateShape(wxCommandEvent& event);\n\tvoid OnInflateShape(wxCommandEvent& event);\n\tvoid OnFixClippingShape(wxCommandEvent& event);\n\n\tvoid OnRenameShape(wxCommandEvent& event);\n\tvoid OnSetReference(wxCommandEvent& event);\n\tvoid OnDeleteVerts(wxCommandEvent& event);\n\tvoid OnSeparateVerts(wxCommandEvent& event);\n\tvoid CheckCopyGeo(wxDialog& dlg);\n\tvoid OnCopyGeo(wxCommandEvent& event);\n\tvoid OnDupeShape(wxCommandEvent& event);\n\tvoid OnDeleteShape(wxCommandEvent& event);\n\tvoid OnRefineMesh(wxCommandEvent& event);\n\tvoid OnSetBoneSkin(wxCommandEvent& event);\n\tvoid OnSetBoneNode(wxCommandEvent& event);\n\tvoid OnAddBone(wxCommandEvent& event);\n\tvoid OnAddCustomBone(wxCommandEvent& event);\n\tvoid OnDeleteBone(wxCommandEvent& event);\n\tvoid OnDeleteBoneFromSelected(wxCommandEvent& event);\n\tvoid FillParentBoneChoice(wxDialog& dlg, const std::string& selBone = \"\");\n\tvoid GetBoneDlgData(wxDialog& dlg, nifly::MatTransform& xform, std::string& parentBone, int& addCount);\n\tvoid OnEditBone(wxCommandEvent& event);\n\tvoid OnCopyBoneWeight(wxCommandEvent& event);\n\tvoid OnTransferSelectedWeight(wxCommandEvent& event);\n\tvoid OnMaskWeighted(wxCommandEvent& event);\n\tvoid OnCheckBadBones(wxCommandEvent& event);\n\tvoid OnMaskBoneWeighted(wxCommandEvent& event);\n\tvoid OnCopySegPart(wxCommandEvent& event);\n\tvoid OnMaskSymVert(wxCommandEvent& event);\n\tvoid OnSymVert(wxCommandEvent& event);\n\tvoid OnMaskSymTri(wxCommandEvent& event);\n\tvoid OnResetTransforms(wxCommandEvent& event);\n\tvoid OnDeleteUnreferencedNodes(wxCommandEvent& event);\n\tvoid OnRemoveSkinning(wxCommandEvent& event);\n\tvoid OnShapeProperties(wxCommandEvent& event);\n\n\tvoid OnMaskLess(wxCommandEvent& event);\n\tvoid OnMaskMore(wxCommandEvent& event);\n\n\tvoid OnNPWizChangeSliderSetFile(wxFileDirPickerEvent& event);\n\tvoid OnNPWizChangeSetNameChoice(wxCommandEvent& event);\n\n\tvoid OnXMirror(wxCommandEvent& event) {\n\t\tglView->SetToolOptionXMirror(event.IsChecked());\n\t\tif (event.IsChecked() && glView->GetActiveTool() == ToolID::MoveVertex) {\n\t\t\tglView->SetToolOptionWeld(false);\n\t\t\tglView->SetToolOptionMerge(false);\n\t\t}\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnConnectedOnly(wxCommandEvent& event) {\n\t\tglView->SetToolOptionConnectedOnly(event.IsChecked());\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnToolOptionMerge(wxCommandEvent& event) {\n\t\tglView->SetToolOptionMerge(event.IsChecked());\n\t\tif (event.IsChecked()) {\n\t\t\tglView->SetToolOptionRestrictSurface(true);\n\t\t\tglView->SetToolOptionXMirror(false);\n\t\t}\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnToolOptionWeld(wxCommandEvent& event) {\n\t\tglView->SetToolOptionWeld(event.IsChecked());\n\t\tif (event.IsChecked()) {\n\t\t\tglView->SetToolOptionRestrictSurface(true);\n\t\t\tglView->SetToolOptionXMirror(false);\n\t\t}\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnToolOptionRestrictSurface(wxCommandEvent& event) {\n\t\tglView->SetToolOptionRestrictSurface(event.IsChecked());\n\t\tif (event.IsChecked()) {\n\t\t\tglView->SetToolOptionRestrictPlane(false);\n\t\t}\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnToolOptionRestrictPlane(wxCommandEvent& event) {\n\t\tglView->SetToolOptionRestrictPlane(event.IsChecked());\n\t\tif (event.IsChecked()) {\n\t\t\tglView->SetToolOptionRestrictSurface(false);\n\t\t\tglView->SetToolOptionRestrictNormal(false);\n\t\t}\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnToolOptionRestrictNormal(wxCommandEvent& event) {\n\t\tglView->SetToolOptionRestrictNormal(event.IsChecked());\n\t\tif (event.IsChecked()) {\n\t\t\tglView->SetToolOptionRestrictPlane(false);\n\t\t}\n\t\tReToggleToolOptionsUI();\n\t}\n\n\tvoid OnUndo(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (glView->GetSegmentMode())\n\t\t\treturn;\n\n\t\tglView->UndoStroke();\n\t\tUpdateUndoTools();\n\t\tSetPendingChanges();\n\t}\n\n\tvoid OnRedo(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (glView->GetSegmentMode())\n\t\t\treturn;\n\n\t\tglView->RedoStroke();\n\t\tUpdateUndoTools();\n\t\tSetPendingChanges();\n\t}\n\n\tvoid OnRecalcNormals(wxCommandEvent& WXUNUSED(event));\n\tvoid OnDisableNormalsCalc(wxCommandEvent& WXUNUSED(event));\n\tvoid OnSmoothNormalSeams(wxCommandEvent& event);\n\tvoid OnSmoothSeamsAngle(wxCommandEvent& event);\n\tvoid OnLockNormals(wxCommandEvent& event);\n\n\tvoid OnEditUV(wxCommandEvent& event);\n\n\tvoid OnToggleVisibility(wxCommandEvent& WXUNUSED(event)) { ToggleVisibility(); }\n\n\tvoid OnShowWireframe(wxCommandEvent& WXUNUSED(event)) {\n\t\tglView->ShowWireframe();\n\t\tglView->Render();\n\t}\n\n\tvoid OnEnableLighting(wxCommandEvent& WXUNUSED(event)) {\n\t\tglView->ToggleLighting();\n\t\tglView->Render();\n\t}\n\n\tvoid OnEnableTextures(wxCommandEvent& WXUNUSED(event)) {\n\t\tglView->ToggleTextures();\n\t\tglView->Render();\n\t}\n\n\tvoid OnEnableVertexColors(wxCommandEvent& e) {\n\t\tif (colorSettings->IsShown())\n\t\t\treturn;\n\n\t\tglView->SetColorsVisible(e.IsChecked());\n\t\tif (e.IsChecked())\n\t\t\tFillVertexColors();\n\t\telse\n\t\t\tglView->ClearColors();\n\n\t\tglView->Render();\n\t}\n\n\tvoid OnIncBrush(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (glView->GetActiveBrush() && glView->GetBrushSize() < 1.0f) {\n\t\t\tfloat v = glView->IncBrush() / BrushSizeScale;\n\t\t\tif (statusBar)\n\t\t\t\tstatusBar->SetStatusText(wxString::Format(\"Rad: %f\", v), 2);\n\n\t\t\tCheckBrushBounds();\n\t\t\tUpdateBrushSettings();\n\t\t}\n\t}\n\tvoid OnDecBrush(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (glView->GetActiveBrush() && glView->GetBrushSize() > 0.0f) {\n\t\t\tfloat v = glView->DecBrush() / BrushSizeScale;\n\t\t\tif (statusBar)\n\t\t\t\tstatusBar->SetStatusText(wxString::Format(\"Rad: %f\", v), 2);\n\n\t\t\tCheckBrushBounds();\n\t\t\tUpdateBrushSettings();\n\t\t}\n\t}\n\tvoid OnIncStr(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (glView->GetActiveBrush() && glView->GetActiveBrush()->getStrength() < 1.0f) {\n\t\t\tfloat v = glView->IncStr();\n\t\t\tif (statusBar)\n\t\t\t\tstatusBar->SetStatusText(wxString::Format(\"Str: %f\", v), 2);\n\n\t\t\tCheckBrushBounds();\n\t\t\tUpdateBrushSettings();\n\t\t}\n\t}\n\tvoid OnDecStr(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (glView->GetActiveBrush() && glView->GetActiveBrush()->getStrength() > 0.0f) {\n\t\t\tfloat v = glView->DecStr();\n\t\t\tif (statusBar)\n\t\t\t\tstatusBar->SetStatusText(wxString::Format(\"Str: %f\", v), 2);\n\n\t\t\tCheckBrushBounds();\n\t\t\tUpdateBrushSettings();\n\t\t}\n\t}\n\n\tvoid OnClearMask(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (!activeItem)\n\t\t\treturn;\n\n\t\tglView->gls.DeleteOverlay(\"refineErrorEdges\");\n\t\tglView->ClearMask();\n\n\t\tif (glView->GetTransformMode())\n\t\t\tglView->ShowTransformTool();\n\t\telse\n\t\t\tglView->Render();\n\t}\n\n\tvoid OnInvertMask(wxCommandEvent& WXUNUSED(event)) {\n\t\tif (!activeItem)\n\t\t\treturn;\n\n\t\tglView->InvertMask();\n\n\t\tif (glView->GetTransformMode())\n\t\t\tglView->ShowTransformTool();\n\t\telse\n\t\t\tglView->Render();\n\t}\n\n\tvoid OnDiscord(wxCommandEvent& WXUNUSED(event)) {\n\t\twxString url = \"https://discordapp.com/invite/2qg2Rzw\";\n\t\twxLaunchDefaultBrowser(url);\n\t}\n\n\tvoid OnGitHub(wxCommandEvent& WXUNUSED(event)) {\n\t\twxString url = \"https://github.com/ousnius/BodySlide-and-Outfit-Studio\";\n\t\twxLaunchDefaultBrowser(url);\n\t}\n\n\tvoid OnPayPal(wxCommandEvent& WXUNUSED(event)) {\n\t\twxString url = \"https://www.paypal.me/ousnius\";\n\t\twxLaunchDefaultBrowser(url);\n\t}\n\n\tvoid OnSelectMask(wxCommandEvent& event);\n\tvoid OnSaveMask(wxCommandEvent& event);\n\tvoid OnDeleteMask(wxCommandEvent& event);\n\tvoid OnExportMask(wxCommandEvent& event);\n\tvoid OnImportMask(wxCommandEvent& event);\n\tvoid OnPaneCollapse(wxCollapsiblePaneEvent& event);\n\tvoid ApplyPose();\n\npublic:\n\t// Called after a bone/node transform is applied, to re-enable the\n\t// transform tool on the bones tab and refresh the bone tree icons so\n\t// that any newly-introduced bad-bones state is visible.\n\tvoid UpdateBoneTransformToolEnabled();\n\tvoid RefreshBoneTreeBadBoneIcons();\n\nprivate:\n\tAnimBone* GetPoseBonePtr();\n\tvoid OnPoseBoneChanged(wxCommandEvent& event);\n\tvoid OnPoseValChanged(int cind, float val);\n\tvoid OnAnyPoseSlider(wxScrollEvent& e, wxTextCtrl* t, int cind);\n\tvoid OnRXPoseSlider(wxScrollEvent& event);\n\tvoid OnRYPoseSlider(wxScrollEvent& event);\n\tvoid OnRZPoseSlider(wxScrollEvent& event);\n\tvoid OnTXPoseSlider(wxScrollEvent& event);\n\tvoid OnTYPoseSlider(wxScrollEvent& event);\n\tvoid OnTZPoseSlider(wxScrollEvent& event);\n\tvoid OnScPoseSlider(wxScrollEvent& event);\n\tvoid OnAnyPoseTextChanged(wxTextCtrl* t, wxSlider* s, int cind);\n\tvoid OnRXPoseTextChanged(wxCommandEvent& event);\n\tvoid OnRYPoseTextChanged(wxCommandEvent& event);\n\tvoid OnRZPoseTextChanged(wxCommandEvent& event);\n\tvoid OnTXPoseTextChanged(wxCommandEvent& event);\n\tvoid OnTYPoseTextChanged(wxCommandEvent& event);\n\tvoid OnTZPoseTextChanged(wxCommandEvent& event);\n\tvoid OnScPoseTextChanged(wxCommandEvent& event);\n\tvoid OnResetBonePose(wxCommandEvent& event);\n\tvoid OnResetAllPose(wxCommandEvent& event);\n\tvoid OnPoseToMesh(wxCommandEvent& event);\n\tvoid ResetAllPoseBones();\n\tvoid ActivatePose(bool checked);\n\tvoid OnPoseCheckBox(wxCommandEvent& event);\n\tvoid OnSelectPose(wxCommandEvent& event);\n\tvoid OnSavePose(wxCommandEvent& event);\n\tvoid OnDeletePose(wxCommandEvent& event);\n\tvoid OnLoadHkxPose(wxCommandEvent& event);\n\n\t// Updates enabled state of the Save/Delete pose buttons based on\n\t// whether the currently selected pose is read-only (e.g. SAM YAML).\n\tvoid UpdatePoseButtonStates();\n\n\twxDECLARE_EVENT_TABLE();\n};\n\nclass DnDFile : public wxFileDropTarget {\npublic:\n\tDnDFile(OutfitStudioFrame* pOwner = nullptr) { owner = pOwner; }\n\n\tvirtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames);\n\nprivate:\n\tOutfitStudioFrame* owner = nullptr;\n};\n\nclass DnDSliderFile : public wxFileDropTarget {\npublic:\n\tDnDSliderFile(OutfitStudioFrame* pOwner = nullptr) { owner = pOwner; }\n\n\tvirtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& fileNames);\n\tvirtual wxDragResult OnDragOver(wxCoord x, wxCoord y, wxDragResult defResult);\n\nprivate:\n\tOutfitStudioFrame* owner = nullptr;\n\twxDragResult lastResult = wxDragNone;\n\tstd::string targetSlider;\n};\n"
  },
  {
    "path": "src/program/PresetSaveDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PresetSaveDialog.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <regex>\n\nextern ConfigurationManager Config;\n\nwxBEGIN_EVENT_TABLE(PresetSaveDialog, wxDialog)\n\tEVT_TEXT_ENTER(XRCID(\"spFilter\"), PresetSaveDialog::FilterChanged)\n\tEVT_TEXT(XRCID(\"spFilter\"), PresetSaveDialog::FilterChanged)\n\tEVT_CHECKLISTBOX(XRCID(\"spGroupDisplay\"), PresetSaveDialog::CheckGroup)\n\tEVT_BUTTON(wxID_SAVE, PresetSaveDialog::OnSave)\nwxEND_EVENT_TABLE()\n\nPresetSaveDialog::PresetSaveDialog(wxWindow* parent) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/SavePreset.xrc\");\n\txrc->LoadDialog(this, parent, \"dlgSavePreset\");\n\n\tSetDoubleBuffered(true);\n\tSetSize(FromDIP(wxSize(460, 300)));\n\tSetSizeHints(FromDIP(wxSize(460, 300)), FromDIP(wxSize(460, -1)));\n\tCenterOnParent();\n\n\twxSearchCtrl* search = new wxSearchCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, FromDIP(wxSize(200, -1)), wxTE_PROCESS_ENTER);\n\tsearch->ShowSearchButton(true);\n\tsearch->SetDescriptiveText(\"Group Filter\");\n\tsearch->SetToolTip(\"Filter list by group name\");\n\n\txrc->AttachUnknownControl(\"spFilter\", search, this);\n\twxCheckListBox* chkbox = XRCCTRL((*this), \"spGroupDisplay\", wxCheckListBox);\n\tchkbox->SetDoubleBuffered(true);\n}\n\nPresetSaveDialog::~PresetSaveDialog() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/SavePreset.xrc\");\n}\n\nstd::string PresetSaveDialog::GetProjectPath() const {\n\tstd::string res = Config[\"ProjectPath\"];\n\treturn res.empty() ? Config[\"AppDir\"] : res;\n}\n\nvoid PresetSaveDialog::FilterGroups(const std::string& filter) {\n\twxCheckListBox* chkbox = XRCCTRL((*this), \"spGroupDisplay\", wxCheckListBox);\n\tchkbox->Clear();\n\tfilteredGroups.clear();\n\n\tif (filter.empty()) {\n\t\tfilteredGroups.assign(allGroupNames.begin(), allGroupNames.end());\n\t}\n\telse {\n\t\twxString filterStr = wxString::FromUTF8(filter);\n\t\tfilterStr.MakeLower();\n\n\t\tfor (auto& group : allGroupNames) {\n\t\t\twxString groupStr = wxString::FromUTF8(group);\n\t\t\tif (groupStr.Lower().Contains(filterStr))\n\t\t\t\tfilteredGroups.push_back(groupStr.ToUTF8().data());\n\t\t}\n\t}\n\n\tfor (auto& g : filteredGroups) {\n\t\tint i = chkbox->Append(g);\n\t\tif (selectedGroups.find(g) != selectedGroups.end())\n\t\t\tchkbox->Check(i);\n\t}\n}\n\nvoid PresetSaveDialog::FilterChanged(wxCommandEvent& event) {\n\tstd::string filter{event.GetString().ToUTF8()};\n\tFilterGroups(filter);\n}\n\nvoid PresetSaveDialog::CheckGroup(wxCommandEvent& event) {\n\tstd::string name;\n\twxCheckListBox* chk = (wxCheckListBox*)event.GetEventObject();\n\tint item = event.GetInt();\n\tif (chk->IsChecked(item)) {\n\t\tname = event.GetString().ToUTF8();\n\t\tselectedGroups.insert(name);\n\t}\n\telse {\n\t\tname = event.GetString().ToUTF8();\n\t\tselectedGroups.erase(name);\n\t}\n}\n\nvoid PresetSaveDialog::OnSave(wxCommandEvent& WXUNUSED(event)) {\n\toutPresetName = XRCCTRL((*this), \"spPresetName\", wxTextCtrl)->GetValue().ToUTF8();\n\tstd::string presetFile = outPresetName + \".xml\";\n\n\twxFileDialog savePresetDialog(this,\n\t\t\t\t\t\t\t\t  \"Choose a preset file\",\n\t\t\t\t\t\t\t\t  wxString::FromUTF8(GetProjectPath()) + \"/SliderPresets\",\n\t\t\t\t\t\t\t\t  wxString::FromUTF8(presetFile),\n\t\t\t\t\t\t\t\t  \"Preset Files (*.xml)|*.xml\",\n\t\t\t\t\t\t\t\t  wxFD_SAVE);\n\tif (savePresetDialog.ShowModal() == wxID_OK) {\n\t\toutFileName = savePresetDialog.GetPath().ToUTF8();\n\t\toutGroups.assign(selectedGroups.begin(), selectedGroups.end());\n\t\twxDialog::Close();\n\t}\n}\n\nvoid PresetSaveDialog::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) {\n\treturn;\n}\n"
  },
  {
    "path": "src/program/PresetSaveDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <set>\n#include <wx/srchctrl.h>\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n\nclass PresetSaveDialog : public wxDialog {\npublic:\n\tstd::vector<std::string> allGroupNames;\n\tstd::vector<std::string> filteredGroups;\n\tstd::set<std::string> selectedGroups;\n\tstd::string outFileName;\n\tstd::string outPresetName;\n\tstd::vector<std::string> outGroups;\n\n\tPresetSaveDialog(wxWindow* parent);\n\t~PresetSaveDialog();\n\n\tstd::string GetProjectPath() const;\n\n\tvoid FilterGroups(const std::string& filter = \"\");\n\n\tvoid OnEraseBackground(wxEraseEvent& event);\n\tvoid FilterChanged(wxCommandEvent& event);\n\tvoid CheckGroup(wxCommandEvent& event);\n\tvoid OnSave(wxCommandEvent& event);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/PreviewWindow.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PreviewWindow.h\"\n#include \"BodySlideApp.h\"\n\nextern ConfigurationManager Config;\nextern ConfigurationManager BodySlideConfig;\n\nwxBEGIN_EVENT_TABLE(PreviewWindow, wxFrame)\n\tEVT_CLOSE(PreviewWindow::OnClose)\n\tEVT_MOVE_END(PreviewWindow::OnMoveWindow)\n\tEVT_SIZE(PreviewWindow::OnSetSize)\nwxEND_EVENT_TABLE()\n\nPreviewWindow::PreviewWindow(const wxPoint& pos, const wxSize& size, BodySlideApp* app)\n\t: wxFrame(nullptr, wxID_ANY, _(\"Preview\"), pos, size)\n\t, app(app)\n\t, ownsPanel(true) {\n\tSetIcon(wxIcon(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/BodySlide.png\", wxBITMAP_TYPE_PNG));\n\n\tpanel = new PreviewPanel(this, app);\n\n\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\tsizer->Add(panel, 1, wxEXPAND);\n\tSetSizer(sizer);\n\tShow();\n}\n\nPreviewWindow::PreviewWindow(const wxPoint& pos, const wxSize& size, BodySlideApp* app, PreviewPanel* existingPanel)\n\t: wxFrame(nullptr, wxID_ANY, _(\"Preview\"), pos, size)\n\t, app(app)\n\t, panel(existingPanel)\n\t, ownsPanel(false) {\n\tSetIcon(wxIcon(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/images/BodySlide.png\", wxBITMAP_TYPE_PNG));\n\n\tpanel->Reparent(this);\n\n\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\tsizer->Add(panel, 1, wxEXPAND);\n\tSetSizer(sizer);\n\tpanel->Show();\n\tShow();\n}\n\nPreviewWindow::~PreviewWindow() {}\n\nPreviewPanel* PreviewWindow::ReleasePanel() {\n\tPreviewPanel* p = panel;\n\tpanel = nullptr;\n\townsPanel = false;\n\treturn p;\n}\n\nvoid PreviewWindow::OnMoveWindow(wxMoveEvent& event) {\n\twxPoint p = GetPosition();\n\tBodySlideConfig.SetValue(\"PreviewFrame.x\", p.x);\n\tBodySlideConfig.SetValue(\"PreviewFrame.y\", p.y);\n\tevent.Skip();\n}\n\nvoid PreviewWindow::OnSetSize(wxSizeEvent& event) {\n\tbool maximized = IsMaximized();\n\tif (!maximized) {\n\t\twxSize p = event.GetSize();\n\t\tBodySlideConfig.SetValue(\"PreviewFrame.width\", p.x);\n\t\tBodySlideConfig.SetValue(\"PreviewFrame.height\", p.y);\n\t}\n\n\tBodySlideConfig.SetBoolValue(\"PreviewFrame.maximized\", maximized);\n\tevent.Skip();\n}\n\nvoid PreviewWindow::OnClose(wxCloseEvent& WXUNUSED(event)) {\n\tif (ownsPanel) {\n\t\t// Standalone mode: clean up and destroy\n\t\tif (panel)\n\t\t\tpanel->Cleanup();\n\t\tDestroy();\n\t\tapp->PreviewClosed();\n\t}\n\telse {\n\t\t// Pop-out mode: dock the panel back into the main frame\n\t\tapp->DockPreview();\n\t}\n\twxLogMessage(\"Preview window closed.\");\n}\n"
  },
  {
    "path": "src/program/PreviewWindow.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../ui/PreviewPanel.h\"\n#include <wx/wx.h>\n\nclass BodySlideApp;\n\nextern ConfigurationManager Config;\n\n// Standalone preview window (pop-out mode).\n// Hosts a PreviewPanel as its only child and delegates all preview operations to it.\nclass PreviewWindow : public wxFrame {\n\tBodySlideApp* app = nullptr;\n\tPreviewPanel* panel = nullptr;\n\tbool ownsPanel = false;\n\n\twxDECLARE_EVENT_TABLE();\n\npublic:\n\t// Create a new standalone preview window with a fresh PreviewPanel\n\tPreviewWindow(const wxPoint& pos, const wxSize& size, BodySlideApp* app);\n\n\t// Create a standalone preview window hosting an existing PreviewPanel (reparenting)\n\tPreviewWindow(const wxPoint& pos, const wxSize& size, BodySlideApp* app, PreviewPanel* existingPanel);\n\n\t~PreviewWindow();\n\n\tvoid OnClose(wxCloseEvent& event);\n\tvoid OnMoveWindow(wxMoveEvent& event);\n\tvoid OnSetSize(wxSizeEvent& event);\n\n\tPreviewPanel* GetPanel() { return panel; }\n\n\t// Release the panel without destroying it (for reparenting back)\n\tPreviewPanel* ReleasePanel();\n};\n"
  },
  {
    "path": "src/program/ShaderFlagDefs.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <vector>\n\nstruct ShaderFlagDef {\n\tconst char* name;\n\tint bit;\n};\n\ninline std::vector<ShaderFlagDef> GetFO3ShaderFlags1() {\n\treturn {\n\t\t{\"Specular\", 0}, {\"Skinned\", 1}, {\"Low Detail\", 2}, {\"Vertex Alpha\", 3},\n\t\t{\"Unknown 1\", 4}, {\"Single Pass\", 5}, {\"Empty\", 6}, {\"Environment Mapping\", 7},\n\t\t{\"Alpha Texture\", 8}, {\"Unknown 2\", 9}, {\"FaceGen\", 10}, {\"Parallax\", 11},\n\t\t{\"Unknown 3\", 12}, {\"Non-Projective Shadows\", 13}, {\"Unknown 4\", 14}, {\"Refraction\", 15},\n\t\t{\"Fire Refraction\", 16}, {\"Eye Environment Mapping\", 17}, {\"Hair\", 18}, {\"Dynamic Alpha\", 19},\n\t\t{\"Localmap Hide Secret\", 20}, {\"Window Environment Mapping\", 21}, {\"Tree Billboard\", 22}, {\"Shadow Frustum\", 23},\n\t\t{\"Multiple Textures\", 24}, {\"Remappable Textures\", 25}, {\"Decal\", 26}, {\"Dynamic Decal\", 27},\n\t\t{\"Parallax Occlusion\", 28}, {\"External Emittance\", 29}, {\"Shadow Map\", 30}, {\"ZBuffer Test\", 31}\n\t};\n}\n\ninline std::vector<ShaderFlagDef> GetFO3ShaderFlags2() {\n\treturn {\n\t\t{\"ZBuffer Write\", 0}, {\"LOD Landscape\", 1}, {\"LOD Building\", 2}, {\"No Fade\", 3},\n\t\t{\"Refraction Tint\", 4}, {\"Vertex Colors\", 5}, {\"Unknown 1\", 6}, {\"1st Point Light\", 7},\n\t\t{\"2nd Light\", 8}, {\"3rd Light\", 9}, {\"Vertex Lighting\", 10}, {\"Uniform Scale\", 11},\n\t\t{\"Fit Slope\", 12}, {\"Billboard Envmap Light Fade\", 13}, {\"No LOD Land Blend\", 14}, {\"Envmap Light Fade\", 15},\n\t\t{\"Wireframe\", 16}, {\"VATS Selection\", 17}, {\"Show in Local Map\", 18}, {\"Premult Alpha\", 19},\n\t\t{\"Skip Normal Maps\", 20}, {\"Alpha Decal\", 21}, {\"No Transparency Multisampling\", 22}, {\"Unknown 2\", 23},\n\t\t{\"Unknown 3\", 24}, {\"Unknown 4\", 25}, {\"Unknown 5\", 26}, {\"Unknown 6\", 27},\n\t\t{\"Unknown 7\", 28}, {\"Unknown 8\", 29}, {\"Unknown 9\", 30}, {\"Unknown 10\", 31}\n\t};\n}\n\ninline std::vector<ShaderFlagDef> GetFO4ShaderFlags1() {\n\treturn {\n\t\t{\"Specular\", 0}, {\"Skinned\", 1}, {\"Temp Refraction\", 2}, {\"Vertex Alpha\", 3},\n\t\t{\"GreyscaleToPalette Color\", 4}, {\"GreyscaleToPalette Alpha\", 5}, {\"Use Falloff\", 6}, {\"Environment Mapping\", 7},\n\t\t{\"RGB Falloff\", 8}, {\"Cast Shadows\", 9}, {\"Face\", 10}, {\"UI Mask Rects\", 11},\n\t\t{\"Model Space Normals\", 12}, {\"Non-Projective Shadows\", 13}, {\"Landscape\", 14}, {\"Refraction\", 15},\n\t\t{\"Fire Refraction\", 16}, {\"Eye Environment Mapping\", 17}, {\"Hair\", 18}, {\"Screendoor Alpha Fade\", 19},\n\t\t{\"Localmap Hide Secret\", 20}, {\"Skin Tint\", 21}, {\"Own Emit\", 22}, {\"Projected UV\", 23},\n\t\t{\"Multiple Textures\", 24}, {\"Tessellate\", 25}, {\"Decal\", 26}, {\"Dynamic Decal\", 27},\n\t\t{\"Character Lighting\", 28}, {\"External Emittance\", 29}, {\"Soft Effect\", 30}, {\"ZBuffer Test\", 31}\n\t};\n}\n\ninline std::vector<ShaderFlagDef> GetFO4ShaderFlags2() {\n\treturn {\n\t\t{\"ZBuffer Write\", 0}, {\"LOD Landscape\", 1}, {\"LOD Objects\", 2}, {\"No Fade\", 3},\n\t\t{\"Double Sided\", 4}, {\"Vertex Colors\", 5}, {\"Glow Map\", 6}, {\"Transform Changed\", 7},\n\t\t{\"Dismemberment Meatcuff\", 8}, {\"Tint\", 9}, {\"Grass Vertex Lighting\", 10}, {\"Grass Uniform Scale\", 11},\n\t\t{\"Grass Fit Slope\", 12}, {\"Grass Billboard\", 13}, {\"No LOD Land Blend\", 14}, {\"Dismemberment\", 15},\n\t\t{\"Wireframe\", 16}, {\"Weapon Blood\", 17}, {\"Hide On Local Map\", 18}, {\"Premult Alpha\", 19},\n\t\t{\"VATS Target\", 20}, {\"Anisotropic Lighting\", 21}, {\"Skew Specular Alpha\", 22}, {\"Menu Screen\", 23},\n\t\t{\"Multi Layer Parallax\", 24}, {\"Alpha Test\", 25}, {\"Gradient Remap\", 26}, {\"VATS Target Draw All\", 27},\n\t\t{\"Pipboy Screen\", 28}, {\"Tree Anim\", 29}, {\"Effect Lighting\", 30}, {\"Refraction Writes Depth\", 31}\n\t};\n}\n\ninline std::vector<ShaderFlagDef> GetSkyrimShaderFlags1() {\n\treturn {\n\t\t{\"Specular\", 0}, {\"Skinned\", 1}, {\"Temp Refraction\", 2}, {\"Vertex Alpha\", 3},\n\t\t{\"GreyscaleToPalette Color\", 4}, {\"GreyscaleToPalette Alpha\", 5}, {\"Use Falloff\", 6}, {\"Environment Mapping\", 7},\n\t\t{\"Receive Shadows\", 8}, {\"Cast Shadows\", 9}, {\"Facegen Detail Map\", 10}, {\"Parallax\", 11},\n\t\t{\"Model Space Normals\", 12}, {\"Non-Projective Shadows\", 13}, {\"Landscape\", 14}, {\"Refraction\", 15},\n\t\t{\"Fire Refraction\", 16}, {\"Eye Environment Mapping\", 17}, {\"Hair Soft Lighting\", 18}, {\"Screendoor Alpha Fade\", 19},\n\t\t{\"Localmap Hide Secret\", 20}, {\"FaceGen RGB Tint\", 21}, {\"Own Emit\", 22}, {\"Projected UV\", 23},\n\t\t{\"Multiple Textures\", 24}, {\"Remappable Textures\", 25}, {\"Decal\", 26}, {\"Dynamic Decal\", 27},\n\t\t{\"Parallax Occlusion\", 28}, {\"External Emittance\", 29}, {\"Soft Effect\", 30}, {\"ZBuffer Test\", 31}\n\t};\n}\n\ninline std::vector<ShaderFlagDef> GetSkyrimShaderFlags2() {\n\treturn {\n\t\t{\"ZBuffer Write\", 0}, {\"LOD Landscape\", 1}, {\"LOD Objects\", 2}, {\"No Fade\", 3},\n\t\t{\"Double Sided\", 4}, {\"Vertex Colors\", 5}, {\"Glow Map\", 6}, {\"Assume Shadowmask\", 7},\n\t\t{\"Packed Tangent\", 8}, {\"Multi Index Snow\", 9}, {\"Vertex Lighting\", 10}, {\"Uniform Scale\", 11},\n\t\t{\"Fit Slope\", 12}, {\"Billboard\", 13}, {\"No LOD Land Blend\", 14}, {\"EnvMap Light Fade\", 15},\n\t\t{\"Wireframe\", 16}, {\"Weapon Blood\", 17}, {\"Hide On Local Map\", 18}, {\"Premult Alpha\", 19},\n\t\t{\"Cloud LOD\", 20}, {\"Anisotropic Lighting\", 21}, {\"No Transparency Multisampling\", 22}, {\"Unused 01\", 23},\n\t\t{\"Multi Layer Parallax\", 24}, {\"Soft Lighting\", 25}, {\"Rim Lighting\", 26}, {\"Back Lighting\", 27},\n\t\t{\"Unused 02\", 28}, {\"Tree Anim\", 29}, {\"Effect Lighting\", 30}, {\"HD LOD Objects\", 31}\n\t};\n}\n"
  },
  {
    "path": "src/program/ShapeProperties.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"ShapeProperties.h\"\n\n#include <wx/grid.h>\n#include <wx/valnum.h>\n\nextern ConfigurationManager Config;\n\nusing namespace nifly;\n\nwxBEGIN_EVENT_TABLE(ShapeProperties, wxDialog)\n\tEVT_BUTTON(XRCID(\"btnMaterialChooser\"), ShapeProperties::OnChooseMaterial)\n\tEVT_BUTTON(XRCID(\"btnAddShader\"), ShapeProperties::OnAddShader)\n\tEVT_BUTTON(XRCID(\"btnRemoveShader\"), ShapeProperties::OnRemoveShader)\n\tEVT_BUTTON(XRCID(\"btnSetTextures\"), ShapeProperties::OnSetTextures)\n\tEVT_BUTTON(XRCID(\"btnAddTransparency\"), ShapeProperties::OnAddTransparency)\n\tEVT_BUTTON(XRCID(\"btnRemoveTransparency\"), ShapeProperties::OnRemoveTransparency)\n\tEVT_BUTTON(XRCID(\"btnCopyShaderFromShape\"), ShapeProperties::OnCopyShaderFromShape)\n\tEVT_BUTTON(XRCID(\"btnAddExtraData\"), ShapeProperties::OnAddExtraData)\n\tEVT_TEXT(XRCID(\"textScale\"), ShapeProperties::OnTransChanged)\n\tEVT_TEXT(XRCID(\"textX\"), ShapeProperties::OnTransChanged)\n\tEVT_TEXT(XRCID(\"textY\"), ShapeProperties::OnTransChanged)\n\tEVT_TEXT(XRCID(\"textZ\"), ShapeProperties::OnTransChanged)\n\tEVT_TEXT(XRCID(\"textRX\"), ShapeProperties::OnTransChanged)\n\tEVT_TEXT(XRCID(\"textRY\"), ShapeProperties::OnTransChanged)\n\tEVT_TEXT(XRCID(\"textRZ\"), ShapeProperties::OnTransChanged)\n\tEVT_BUTTON(wxID_OK, ShapeProperties::OnApply)\nwxEND_EVENT_TABLE()\n\nShapeProperties::ShapeProperties(wxWindow* parent, NifFile* refNif, std::vector<NiShape*> refShapes) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\tbool loaded = xrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ShapeProperties.xrc\");\n\tif (!loaded) {\n\t\twxMessageBox(\"Failed to load ShapeProperties.xrc file!\", \"Error\", wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tloaded = xrc->LoadDialog(this, parent, \"dlgShapeProp\");\n\tif (!loaded) {\n\t\twxMessageBox(\"Failed to load ShapeProperties dialog!\", \"Error\", wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tif (refShapes.empty())\n\t\treturn;\n\n\tSetDoubleBuffered(true);\n\tCenterOnParent();\n\n\tos = (OutfitStudioFrame*)parent;\n\tnif = refNif;\n\tshapes = refShapes;\n\n\tnbProperties = XRCCTRL(*this, \"nbProperties\", wxNotebook);\n\n\tpgShader = XRCCTRL(*this, \"pgShader\", wxPanel);\n\tlbShaderName = XRCCTRL(*this, \"lbShaderName\", wxStaticText);\n\tshaderName = XRCCTRL(*this, \"shaderName\", wxTextCtrl);\n\tbtnMaterialChooser = XRCCTRL(*this, \"btnMaterialChooser\", wxButton);\n\tshaderType = XRCCTRL(*this, \"shaderType\", wxChoice);\n\tlbShadingType = XRCCTRL(*this, \"lbShadingType\", wxStaticText);\n\tshadingType = XRCCTRL(*this, \"shadingType\", wxChoice);\n\tspecularColor = XRCCTRL(*this, \"specularColor\", wxColourPickerCtrl);\n\tspecularStrength = XRCCTRL(*this, \"specularStrength\", wxTextCtrl);\n\tspecularPower = XRCCTRL(*this, \"specularPower\", wxTextCtrl);\n\temissiveColor = XRCCTRL(*this, \"emissiveColor\", wxColourPickerCtrl);\n\temissiveMultiple = XRCCTRL(*this, \"emissiveMultiple\", wxTextCtrl);\n\talpha = XRCCTRL(*this, \"alpha\", wxTextCtrl);\n\tvertexColors = XRCCTRL(*this, \"vertexColors\", wxCheckBox);\n\tdoubleSided = XRCCTRL(*this, \"doubleSided\", wxCheckBox);\n\tbtnAddShader = XRCCTRL(*this, \"btnAddShader\", wxButton);\n\tbtnRemoveShader = XRCCTRL(*this, \"btnRemoveShader\", wxButton);\n\tbtnSetTextures = XRCCTRL(*this, \"btnSetTextures\", wxButton);\n\n\tshaderFlagsPane = XRCCTRL(*this, \"shaderFlagsPane\", wxCollapsiblePane);\n\tshaderFlags1List = XRCCTRL(*this, \"shaderFlags1List\", wxCheckListBox);\n\tshaderFlags2List = XRCCTRL(*this, \"shaderFlags2List\", wxCheckListBox);\n\n\tadvancedShaderPane = XRCCTRL(*this, \"advancedShaderPane\", wxCollapsiblePane);\n\tuvOffsetU = XRCCTRL(*this, \"uvOffsetU\", wxTextCtrl);\n\tuvOffsetV = XRCCTRL(*this, \"uvOffsetV\", wxTextCtrl);\n\tuvScaleU = XRCCTRL(*this, \"uvScaleU\", wxTextCtrl);\n\tuvScaleV = XRCCTRL(*this, \"uvScaleV\", wxTextCtrl);\n\ttextureClampMode = XRCCTRL(*this, \"textureClampMode\", wxChoice);\n\tenvironmentMapScale = XRCCTRL(*this, \"environmentMapScale\", wxTextCtrl);\n\trefractionStrength = XRCCTRL(*this, \"refractionStrength\", wxTextCtrl);\n\trefractionFirePeriod = XRCCTRL(*this, \"refractionFirePeriod\", wxTextCtrl);\n\tparallaxMaxPasses = XRCCTRL(*this, \"parallaxMaxPasses\", wxTextCtrl);\n\tparallaxScale = XRCCTRL(*this, \"parallaxScale\", wxTextCtrl);\n\tlightingEffect1 = XRCCTRL(*this, \"lightingEffect1\", wxTextCtrl);\n\tlightingEffect2 = XRCCTRL(*this, \"lightingEffect2\", wxTextCtrl);\n\tskinTintColor = XRCCTRL(*this, \"skinTintColor\", wxColourPickerCtrl);\n\thairTintColor = XRCCTRL(*this, \"hairTintColor\", wxColourPickerCtrl);\n\tparallaxInnerLayerThickness = XRCCTRL(*this, \"parallaxInnerLayerThickness\", wxTextCtrl);\n\tparallaxRefractionScale = XRCCTRL(*this, \"parallaxRefractionScale\", wxTextCtrl);\n\tparallaxInnerLayerTexScaleU = XRCCTRL(*this, \"parallaxInnerLayerTexScaleU\", wxTextCtrl);\n\tparallaxInnerLayerTexScaleV = XRCCTRL(*this, \"parallaxInnerLayerTexScaleV\", wxTextCtrl);\n\tparallaxEnvmapStrength = XRCCTRL(*this, \"parallaxEnvmapStrength\", wxTextCtrl);\n\tsparkleParamsR = XRCCTRL(*this, \"sparkleParamsR\", wxTextCtrl);\n\tsparkleParamsG = XRCCTRL(*this, \"sparkleParamsG\", wxTextCtrl);\n\tsparkleParamsB = XRCCTRL(*this, \"sparkleParamsB\", wxTextCtrl);\n\tsparkleParamsA = XRCCTRL(*this, \"sparkleParamsA\", wxTextCtrl);\n\teyeCubemapScale = XRCCTRL(*this, \"eyeCubemapScale\", wxTextCtrl);\n\teyeLeftReflectX = XRCCTRL(*this, \"eyeLeftReflectX\", wxTextCtrl);\n\teyeLeftReflectY = XRCCTRL(*this, \"eyeLeftReflectY\", wxTextCtrl);\n\teyeLeftReflectZ = XRCCTRL(*this, \"eyeLeftReflectZ\", wxTextCtrl);\n\teyeRightReflectX = XRCCTRL(*this, \"eyeRightReflectX\", wxTextCtrl);\n\teyeRightReflectY = XRCCTRL(*this, \"eyeRightReflectY\", wxTextCtrl);\n\teyeRightReflectZ = XRCCTRL(*this, \"eyeRightReflectZ\", wxTextCtrl);\n\twetMaterialPath = XRCCTRL(*this, \"wetMaterialPath\", wxTextCtrl);\n\tsubsurfaceRolloff = XRCCTRL(*this, \"subsurfaceRolloff\", wxTextCtrl);\n\trimlightPower = XRCCTRL(*this, \"rimlightPower\", wxTextCtrl);\n\tbacklightPower = XRCCTRL(*this, \"backlightPower\", wxTextCtrl);\n\tgrayscaleToPaletteScale = XRCCTRL(*this, \"grayscaleToPaletteScale\", wxTextCtrl);\n\tfresnelPower = XRCCTRL(*this, \"fresnelPower\", wxTextCtrl);\n\twetnessSpecScale = XRCCTRL(*this, \"wetnessSpecScale\", wxTextCtrl);\n\twetnessSpecPower = XRCCTRL(*this, \"wetnessSpecPower\", wxTextCtrl);\n\twetnessMinVar = XRCCTRL(*this, \"wetnessMinVar\", wxTextCtrl);\n\twetnessEnvMapScale = XRCCTRL(*this, \"wetnessEnvMapScale\", wxTextCtrl);\n\twetnessFresnelPower = XRCCTRL(*this, \"wetnessFresnelPower\", wxTextCtrl);\n\twetnessMetalness = XRCCTRL(*this, \"wetnessMetalness\", wxTextCtrl);\n\n\talphaThreshold = XRCCTRL(*this, \"alphaThreshold\", wxTextCtrl);\n\tvertexAlpha = XRCCTRL(*this, \"vertexAlpha\", wxCheckBox);\n\talphaTest = XRCCTRL(*this, \"alphaTest\", wxCheckBox);\n\talphaBlend = XRCCTRL(*this, \"alphaBlend\", wxCheckBox);\n\talphaSrcBlend = XRCCTRL(*this, \"alphaSrcBlend\", wxChoice);\n\talphaDestBlend = XRCCTRL(*this, \"alphaDestBlend\", wxChoice);\n\talphaTestFunc = XRCCTRL(*this, \"alphaTestFunc\", wxChoice);\n\talphaNoSorter = XRCCTRL(*this, \"alphaNoSorter\", wxCheckBox);\n\tbtnAddTransparency = XRCCTRL(*this, \"btnAddTransparency\", wxButton);\n\tbtnRemoveTransparency = XRCCTRL(*this, \"btnRemoveTransparency\", wxButton);\n\n\ttransparencyPane = XRCCTRL(*this, \"transparencyPane\", wxCollapsiblePane);\n\n\t// Bind collapsible pane events to update layout\n\tauto onPaneChanged = [this](wxCollapsiblePaneEvent&) {\n\t\tpgShader->Layout();\n\t};\n\tshaderFlagsPane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, onPaneChanged);\n\tadvancedShaderPane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, onPaneChanged);\n\ttransparencyPane->Bind(wxEVT_COLLAPSIBLEPANE_CHANGED, onPaneChanged);\n\n\t// Update advanced field visibility when shader type changes\n\tshaderType->Bind(wxEVT_CHOICE, [this](wxCommandEvent&) {\n\t\tUpdateShaderTypeFields(shaderType->GetSelection());\n\t});\n\n\t// Sync vertex colors/alpha/double-sided checkboxes with shader flags list\n\tvertexColors->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& evt) {\n\t\tif (shaderFlags2List->GetCount() > 5)\n\t\t\tshaderFlags2List->Check(5, evt.IsChecked());\n\t});\n\tdoubleSided->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& evt) {\n\t\t// FO3/NV: bit 4 of shaderFlags2 is \"Refraction Tint\", not \"Double Sided\".\n\t\t// Double sided is controlled by NiStencilProperty for those games.\n\t\tif (!isFO3NV) {\n\t\t\tif (shaderFlags2List->GetCount() > 4)\n\t\t\t\tshaderFlags2List->Check(4, evt.IsChecked());\n\t\t}\n\t});\n\tvertexAlpha->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent& evt) {\n\t\t// FO3/NV: Vertex Alpha only works with BSShaderNoLightingProperty\n\t\tif (!isFO3NV || isFO3NVNoLighting) {\n\t\t\tif (shaderFlags1List->GetCount() > 3)\n\t\t\t\tshaderFlags1List->Check(3, evt.IsChecked());\n\t\t}\n\t\t// Enabling vertex alpha also enables vertex colors\n\t\tif (evt.IsChecked()) {\n\t\t\tif (shaderFlags2List->GetCount() > 5)\n\t\t\t\tshaderFlags2List->Check(5, true);\n\t\t\tvertexColors->SetValue(true);\n\t\t}\n\t});\n\n\tbtnCopyShaderFromShape = XRCCTRL(*this, \"btnCopyShaderFromShape\", wxButton);\n\n\tpgGeometry = XRCCTRL(*this, \"pgGeometry\", wxPanel);\n\tfullPrecision = XRCCTRL(*this, \"fullPrecision\", wxCheckBox);\n\tsubIndex = XRCCTRL(*this, \"subIndex\", wxCheckBox);\n\tskinned = XRCCTRL(*this, \"skinned\", wxCheckBox);\n\tdynamic = XRCCTRL(*this, \"dynamic\", wxCheckBox);\n\n\tpgExtraData = XRCCTRL(*this, \"pgExtraData\", wxPanel);\n\textraDataGrid = (wxFlexGridSizer*)XRCCTRL(*this, \"btnAddExtraData\", wxButton)->GetContainingSizer();\n\n\tpgCoordinates = XRCCTRL(*this, \"pgCoordinates\", wxPanel);\n\ttextScale = XRCCTRL(*this, \"textScale\", wxTextCtrl);\n\ttextX = XRCCTRL(*this, \"textX\", wxTextCtrl);\n\ttextY = XRCCTRL(*this, \"textY\", wxTextCtrl);\n\ttextZ = XRCCTRL(*this, \"textZ\", wxTextCtrl);\n\ttextRX = XRCCTRL(*this, \"textRX\", wxTextCtrl);\n\ttextRY = XRCCTRL(*this, \"textRY\", wxTextCtrl);\n\ttextRZ = XRCCTRL(*this, \"textRZ\", wxTextCtrl);\n\tcbTransformGeo = XRCCTRL(*this, \"cbTransformGeo\", wxCheckBox);\n\n\tauto& version = nif->GetHeader().GetVersion();\n\tif (version.Stream() >= 130) {\n\t\tlbShaderName->SetLabel(_(\"Material\"));\n\t\tbtnMaterialChooser->Show();\n\t\tpgShader->Layout();\n\t}\n\n\tGetShader();\n\tGetTransparency();\n\tGetGeometry();\n\tGetExtraData();\n\tGetCoordTrans();\n\n\tsize_t shapeCount = shapes.size();\n\tif (shapeCount > 1) {\n\t\tSetTitle(wxString::Format(\"%s - %s\", GetTitle(), wxString::Format(_(\"%zu shapes selected\"), shapeCount)));\n\t\tnbProperties->SetSelection(1); // Make \"Geometry\" active\n\t}\n}\n\nShapeProperties::~ShapeProperties() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/ShapeProperties.xrc\");\n}\n\nbool ShapeProperties::ShowConfirmationDialog() {\n\tif (confirmationAccepted)\n\t\treturn true;\n\n\tif (shapes.size() > 1) {\n\t\twxMessageDialog dlg(this,\n\t\t\t\t\t\t\twxString::Format(_(\"This action will affect all %zu selected shapes. Are you sure?\"), shapes.size()),\n\t\t\t\t\t\t\t_(\"Confirmation\"),\n\t\t\t\t\t\t\twxYES_NO | wxCANCEL | wxICON_WARNING | wxCANCEL_DEFAULT);\n\t\tdlg.SetYesNoCancelLabels(_(\"Yes\"), _(\"No\"), _(\"Cancel\"));\n\n\t\tint res = dlg.ShowModal();\n\t\tif (res != wxID_YES)\n\t\t\treturn false;\n\t}\n\n\tconfirmationAccepted = true;\n\treturn true;\n}\n\nvoid ShapeProperties::GetShader() {\n\tbool multipleShapes = shapes.size() > 1;\n\n\tbool anyWithShader = false;\n\tbool anyWithoutShader = false;\n\tfor (auto& shape : shapes) {\n\t\tNiShader* shader = nif->GetShader(shape);\n\t\tif (shader)\n\t\t\tanyWithShader = true;\n\t\telse\n\t\t\tanyWithoutShader = true;\n\t}\n\n\tNiShape* shape = shapes[0];\n\tNiShader* shader = nif->GetShader(shape);\n\n\tisFO3NV = shader && shader->HasType<BSShaderLightingProperty>();\n\tisFO3NVNoLighting = shader && shader->HasType<BSShaderNoLightingProperty>();\n\n\tif (multipleShapes) {\n\t\tbtnAddShader->Enable(anyWithoutShader);\n\t\tbtnRemoveShader->Enable(anyWithShader);\n\t\tbtnSetTextures->Enable(anyWithShader);\n\n\t\tbtnMaterialChooser->Disable();\n\t\tshaderName->Disable();\n\t\tspecularColor->Disable();\n\t\tspecularStrength->Disable();\n\t\tspecularPower->Disable();\n\t\temissiveColor->Disable();\n\t\temissiveMultiple->Disable();\n\t\talpha->Disable();\n\t\tvertexColors->Disable();\n\t\tdoubleSided->Disable();\n\t\tvertexAlpha->Disable();\n\t\talphaTest->Disable();\n\t\talphaBlend->Disable();\n\t\tshaderFlagsPane->Disable();\n\t\tadvancedShaderPane->Disable();\n\t}\n\telse {\n\t\tif (!shader) {\n\t\t\tbtnAddShader->Enable();\n\n\t\t\tbtnRemoveShader->Disable();\n\t\t\tbtnMaterialChooser->Disable();\n\t\t\tbtnSetTextures->Disable();\n\t\t\tshaderName->Disable();\n\t\t\tspecularColor->Disable();\n\t\t\tspecularStrength->Disable();\n\t\t\tspecularPower->Disable();\n\t\t\temissiveColor->Disable();\n\t\t\temissiveMultiple->Disable();\n\t\t\talpha->Disable();\n\t\t\tvertexColors->Disable();\n\t\t\tdoubleSided->Disable();\n\t\t\tvertexAlpha->Disable();\n\t\t\talphaTest->Disable();\n\t\t\talphaBlend->Disable();\n\t\t\tshaderFlagsPane->Disable();\n\t\t\tadvancedShaderPane->Disable();\n\n\t\t\t// Check for standalone NiMaterialProperty (Oblivion/FO3)\n\t\t\tNiMaterialProperty* material = nif->GetMaterialProperty(shape);\n\t\t\tif (material) {\n\t\t\t\tspecularColor->Enable();\n\t\t\t\tspecularPower->Enable();\n\t\t\t\temissiveColor->Enable();\n\t\t\t\temissiveMultiple->Enable();\n\t\t\t\talpha->Enable();\n\n\t\t\t\tVector3 colorVec = material->GetSpecularColor() * 255.0f;\n\t\t\t\tspecularColor->SetColour(wxColour(colorVec.x, colorVec.y, colorVec.z));\n\t\t\t\tspecularPower->SetValue(wxString::Format(\"%.4f\", material->GetGlossiness()));\n\n\t\t\t\tColor4 color = material->GetEmissiveColor() * 255.0f;\n\t\t\t\temissiveColor->SetColour(wxColour(color.r, color.g, color.b, color.a));\n\t\t\t\temissiveMultiple->SetValue(wxString::Format(\"%.4f\", material->GetEmissiveMultiple()));\n\t\t\t\talpha->SetValue(wxString::Format(\"%.4f\", material->GetAlpha()));\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tbtnAddShader->Disable();\n\t\t\talpha->Disable();\n\n\t\t\tbtnRemoveShader->Enable();\n\t\t\tbtnMaterialChooser->Enable();\n\t\t\tbtnSetTextures->Enable();\n\t\t\tshaderName->Enable();\n\t\t\tspecularColor->Enable();\n\t\t\tspecularStrength->Enable();\n\t\t\tspecularPower->Enable();\n\t\t\temissiveColor->Enable();\n\t\t\temissiveMultiple->Enable();\n\t\t\tvertexColors->Enable();\n\t\t\tdoubleSided->Enable();\n\t\t\tvertexAlpha->Enable();\n\n\t\t\t// FO3/NV: Vertex Alpha only works with BSShaderNoLightingProperty\n\t\t\tif (isFO3NV && !isFO3NVNoLighting)\n\t\t\t\tvertexAlpha->Disable();\n\n\t\t\talphaTest->Enable();\n\t\t\talphaBlend->Enable();\n\t\t\tshaderFlagsPane->Enable();\n\t\t\tadvancedShaderPane->Enable();\n\t\t}\n\t}\n\n\t// Set values of shader of first shape\n\tif (shader) {\n\t\tbool hasVertexColors = shader->HasVertexColors();\n\t\tbool isDoubleSided = shader->IsDoubleSided();\n\t\tbool hasVertexAlpha = shader->HasVertexAlpha();\n\t\tshaderName->SetValue(shader->name.get());\n\t\tvertexColors->SetValue(hasVertexColors);\n\t\tvertexAlpha->SetValue(hasVertexAlpha);\n\n\t\t// FO3/NV: Double sided is controlled by NiStencilProperty, not shader flags\n\t\tif (isFO3NV) {\n\t\t\tNiStencilProperty* stencil = nif->GetStencilProperty(shape);\n\t\t\tif (stencil) {\n\t\t\t\tint drawMode = (stencil->flags & DRAW_MASK) >> DRAW_POS;\n\t\t\t\tisDoubleSided = (drawMode == DRAW_BOTH);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tisDoubleSided = false;\n\t\t\t}\n\t\t}\n\n\t\tdoubleSided->SetValue(isDoubleSided);\n\n\t\tColor4 color;\n\t\tVector3 colorVec;\n\t\tif (shader->HasType<BSEffectShaderProperty>()) {\n\t\t\tspecularColor->Disable();\n\t\t\tspecularStrength->Disable();\n\t\t\tspecularPower->Disable();\n\n\t\t\tcolor = shader->GetEmissiveColor() * 255.0f;\n\t\t\temissiveColor->SetColour(wxColour(color.r, color.g, color.b, color.a));\n\t\t\temissiveMultiple->SetValue(wxString::Format(\"%.4f\", shader->GetEmissiveMultiple()));\n\t\t\talpha->SetValue(wxString::Format(\"%.4f\", shader->GetAlpha()));\n\t\t}\n\t\telse if (shader->HasType<BSLightingShaderProperty>()) {\n\t\t\tif (!multipleShapes)\n\t\t\t\talpha->Enable();\n\n\t\t\tcolorVec = shader->GetSpecularColor() * 255.0f;\n\t\t\tspecularColor->SetColour(wxColour(colorVec.x, colorVec.y, colorVec.z));\n\t\t\tspecularStrength->SetValue(wxString::Format(\"%.4f\", shader->GetSpecularStrength()));\n\t\t\tspecularPower->SetValue(wxString::Format(\"%.4f\", shader->GetGlossiness()));\n\n\t\t\tcolor = shader->GetEmissiveColor() * 255.0f;\n\t\t\temissiveColor->SetColour(wxColour(color.r, color.g, color.b, color.a));\n\t\t\temissiveMultiple->SetValue(wxString::Format(\"%.4f\", shader->GetEmissiveMultiple()));\n\t\t\talpha->SetValue(wxString::Format(\"%.4f\", shader->GetAlpha()));\n\t\t}\n\t\telse if (shader->HasType<BSShaderPPLightingProperty>() || shader->HasType<NiMaterialProperty>())\n\t\t\tspecularStrength->Disable();\n\n\t\tNiMaterialProperty* material = nif->GetMaterialProperty(shape);\n\t\tif (material) {\n\t\t\tif (!multipleShapes)\n\t\t\t\talpha->Enable();\n\n\t\t\tcolorVec = material->GetSpecularColor() * 255.0f;\n\t\t\tspecularColor->SetColour(wxColour(colorVec.x, colorVec.y, colorVec.z));\n\t\t\tspecularPower->SetValue(wxString::Format(\"%.4f\", material->GetGlossiness()));\n\n\t\t\tcolor = material->GetEmissiveColor() * 255.0f;\n\t\t\temissiveColor->SetColour(wxColour(color.r, color.g, color.b, color.a));\n\t\t\temissiveMultiple->SetValue(wxString::Format(\"%.4f\", material->GetEmissiveMultiple()));\n\t\t\talpha->SetValue(wxString::Format(\"%.4f\", material->GetAlpha()));\n\t\t}\n\t}\n\n\tGetShaderType();\n\tGetShaderFlags();\n\tGetAdvancedShaderProperties();\n}\n\n\nvoid ShapeProperties::GetShaderType() {\n\tshaderType->Disable();\n\tshaderType->Clear();\n\n\tbool multipleShapes = shapes.size() > 1;\n\tNiShape* shape = shapes[0];\n\n\tuint32_t type;\n\tNiShader* shader = nif->GetShader(shape);\n\tif (shader) {\n\t\tif (shader->HasType<BSLightingShaderProperty>()) {\n\t\t\ttype = shader->GetShaderType();\n\t\t\tif (type > BSLSP_LAST)\n\t\t\t\ttype = 0;\n\n\t\t\tshaderType->Append(\"Default\");\n\t\t\tshaderType->Append(\"Environment Map\");\n\t\t\tshaderType->Append(\"Glow Shader\");\n\t\t\tshaderType->Append(\"Heightmap\");\n\t\t\tshaderType->Append(\"Face Tint\");\n\t\t\tshaderType->Append(\"Skin Tint\");\n\t\t\tshaderType->Append(\"Hair Tint\");\n\t\t\tshaderType->Append(\"Parallax Occlusion Material\");\n\t\t\tshaderType->Append(\"World Multitexture\");\n\t\t\tshaderType->Append(\"World Map 1\");\n\t\t\tshaderType->Append(\"Unknown 10\");\n\t\t\tshaderType->Append(\"Multi Layer Parallax\");\n\t\t\tshaderType->Append(\"Unknown 12\");\n\t\t\tshaderType->Append(\"World Map 2\");\n\t\t\tshaderType->Append(\"Sparkle Snow\");\n\t\t\tshaderType->Append(\"World Map 3\");\n\t\t\tshaderType->Append(\"Eye Environment Map\");\n\t\t\tshaderType->Append(\"Unknown 17\");\n\t\t\tshaderType->Append(\"World Map 4\");\n\t\t\tshaderType->Append(\"World LOD Multitexture\");\n\n\t\t\tif (!multipleShapes)\n\t\t\t\tshaderType->Enable();\n\n\t\t\tshaderType->SetSelection(type);\n\t\t}\n\t\telse if (shader->HasType<BSShaderPPLightingProperty>()) {\n\t\t\ttype = shader->GetShaderType();\n\t\t\tshaderType->Append(\"Tall Grass\");\n\t\t\tshaderType->Append(\"Default\");\n\t\t\tshaderType->Append(\"Sky\");\n\t\t\tshaderType->Append(\"Skin\");\n\t\t\tshaderType->Append(\"Water\");\n\t\t\tshaderType->Append(\"Lighting 30\");\n\t\t\tshaderType->Append(\"Tile\");\n\t\t\tshaderType->Append(\"No Lighting\");\n\n\t\t\tif (!multipleShapes)\n\t\t\t\tshaderType->Enable();\n\n\t\t\tswitch (type) {\n\t\t\t\tcase BSShaderType::SHADER_TALL_GRASS: shaderType->SetSelection(0); break;\n\t\t\t\tcase BSShaderType::SHADER_DEFAULT: shaderType->SetSelection(1); break;\n\t\t\t\tcase BSShaderType::SHADER_SKY: shaderType->SetSelection(2); break;\n\t\t\t\tcase BSShaderType::SHADER_SKIN: shaderType->SetSelection(3); break;\n\t\t\t\tcase BSShaderType::SHADER_WATER: shaderType->SetSelection(4); break;\n\t\t\t\tcase BSShaderType::SHADER_LIGHTING30: shaderType->SetSelection(5); break;\n\t\t\t\tcase BSShaderType::SHADER_TILE: shaderType->SetSelection(6); break;\n\t\t\t\tcase BSShaderType::SHADER_NOLIGHTING: shaderType->SetSelection(7); break;\n\t\t\t\tdefault: shaderType->SetSelection(1);\n\t\t\t}\n\n\t\t\t// NiShadeProperty::shadingFlags (FO3/NV)\n\t\t\tauto* bsShaderProp = dynamic_cast<BSShaderProperty*>(shader);\n\t\t\tif (bsShaderProp) {\n\t\t\t\tlbShadingType->Show();\n\t\t\t\tshadingType->Show();\n\t\t\t\tshadingType->SetSelection(bsShaderProp->shadingFlags == SHADING_SMOOTH ? 1 : 0);\n\n\t\t\t\tif (!multipleShapes)\n\t\t\t\t\tshadingType->Enable();\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid ShapeProperties::GetShaderFlags() {\n\tshaderFlags1List->Clear();\n\tshaderFlags2List->Clear();\n\n\tbool multipleShapes = shapes.size() > 1;\n\tif (multipleShapes)\n\t\treturn;\n\n\tNiShape* shape = shapes[0];\n\tNiShader* shader = nif->GetShader(shape);\n\tif (!shader)\n\t\treturn;\n\n\tauto* bsShaderProp = dynamic_cast<BSShaderProperty*>(shader);\n\tif (!bsShaderProp)\n\t\treturn;\n\n\tuint32_t sf1 = bsShaderProp->shaderFlags1;\n\tuint32_t sf2 = bsShaderProp->shaderFlags2;\n\n\tstd::vector<ShaderFlagDef> flags1Defs;\n\tstd::vector<ShaderFlagDef> flags2Defs;\n\n\tif (isFO3NV) {\n\t\tflags1Defs = GetFO3ShaderFlags1();\n\t\tflags2Defs = GetFO3ShaderFlags2();\n\t}\n\telse if (nif->GetHeader().GetVersion().Stream() >= 130) {\n\t\tflags1Defs = GetFO4ShaderFlags1();\n\t\tflags2Defs = GetFO4ShaderFlags2();\n\t}\n\telse {\n\t\tflags1Defs = GetSkyrimShaderFlags1();\n\t\tflags2Defs = GetSkyrimShaderFlags2();\n\t}\n\n\twxArrayString flagNames1, flagNames2;\n\tfor (auto& def : flags1Defs)\n\t\tflagNames1.Add(wxString::Format(\"%s (Bit %d)\", def.name, def.bit));\n\tfor (auto& def : flags2Defs)\n\t\tflagNames2.Add(wxString::Format(\"%s (Bit %d)\", def.name, def.bit));\n\n\tshaderFlags1List->InsertItems(flagNames1, 0);\n\tshaderFlags2List->InsertItems(flagNames2, 0);\n\n\tfor (size_t i = 0; i < flags1Defs.size(); i++) {\n\t\tif (sf1 & (static_cast<uint32_t>(1) << flags1Defs[i].bit))\n\t\t\tshaderFlags1List->Check(i, true);\n\t}\n\n\tfor (size_t i = 0; i < flags2Defs.size(); i++) {\n\t\tif (sf2 & (static_cast<uint32_t>(1) << flags2Defs[i].bit))\n\t\t\tshaderFlags2List->Check(i, true);\n\t}\n}\n\nvoid ShapeProperties::GetAdvancedShaderProperties() {\n\tbool multipleShapes = shapes.size() > 1;\n\n\t// Helper to show/hide a control and its label in the advanced grid.\n\t// Handles both controls directly in the flex grid and controls nested in sub-sizers.\n\twxSizer* gridSizer = advancedShaderPane->GetPane()->GetSizer();\n\tauto showControl = [gridSizer](wxWindow* ctrl, bool show) {\n\t\tif (!ctrl || !gridSizer)\n\t\t\treturn;\n\t\tctrl->Show(show);\n\n\t\twxSizerItem* prevItem = nullptr;\n\t\tfor (auto* item : gridSizer->GetChildren()) {\n\t\t\tbool found = false;\n\n\t\t\tif (item->GetWindow() == ctrl) {\n\t\t\t\tfound = true;\n\t\t\t}\n\t\t\telse if (item->IsSizer()) {\n\t\t\t\t// Check if the control is inside a sub-sizer (e.g. UV offset box)\n\t\t\t\tfor (auto* subItem : item->GetSizer()->GetChildren()) {\n\t\t\t\t\tif (subItem->GetWindow() == ctrl) {\n\t\t\t\t\t\t// Show/hide all sibling controls in the sub-sizer\n\t\t\t\t\t\tfor (auto* s : item->GetSizer()->GetChildren())\n\t\t\t\t\t\t\tif (s->GetWindow())\n\t\t\t\t\t\t\t\ts->GetWindow()->Show(show);\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (found) {\n\t\t\t\titem->Show(show);\n\t\t\t\tif (prevItem) {\n\t\t\t\t\tprevItem->Show(show);\n\t\t\t\t\tif (prevItem->GetWindow())\n\t\t\t\t\t\tprevItem->GetWindow()->Show(show);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprevItem = item;\n\t\t}\n\t};\n\n\t// Hide all advanced controls initially\n\tauto hideAll = [&]() {\n\t\twxWindow* allCtrls[] = {\n\t\t\tuvOffsetU, uvScaleU, textureClampMode, environmentMapScale,\n\t\t\trefractionStrength, refractionFirePeriod, parallaxMaxPasses, parallaxScale,\n\t\t\tlightingEffect1, lightingEffect2, skinTintColor, hairTintColor,\n\t\t\tparallaxInnerLayerThickness, parallaxRefractionScale,\n\t\t\tparallaxInnerLayerTexScaleU,\n\t\t\tparallaxEnvmapStrength, sparkleParamsR,\n\t\t\teyeCubemapScale, eyeLeftReflectX,\n\t\t\teyeRightReflectX,\n\t\t\twetMaterialPath, subsurfaceRolloff, rimlightPower, backlightPower,\n\t\t\tgrayscaleToPaletteScale, fresnelPower,\n\t\t\twetnessSpecScale, wetnessSpecPower, wetnessMinVar, wetnessEnvMapScale,\n\t\t\twetnessFresnelPower, wetnessMetalness\n\t\t};\n\t\tfor (auto* ctrl : allCtrls)\n\t\t\tshowControl(ctrl, false);\n\t};\n\n\thideAll();\n\n\tif (multipleShapes)\n\t\treturn;\n\n\tNiShape* shape = shapes[0];\n\tNiShader* shader = nif->GetShader(shape);\n\tif (!shader)\n\t\treturn;\n\n\tauto& version = nif->GetHeader().GetVersion();\n\n\tif (shader->HasType<BSShaderPPLightingProperty>()) {\n\t\tauto bspplp = dynamic_cast<BSShaderPPLightingProperty*>(shader);\n\t\tauto* bssp = dynamic_cast<BSShaderProperty*>(shader);\n\t\tif (!bspplp || !bssp)\n\t\t\treturn;\n\n\t\tshowControl(environmentMapScale, true);\n\t\tenvironmentMapScale->SetValue(wxString::Format(\"%.4f\", bssp->environmentMapScale));\n\n\t\tauto* bsslp = dynamic_cast<BSShaderLightingProperty*>(shader);\n\t\tif (bsslp) {\n\t\t\tshowControl(textureClampMode, true);\n\t\t\ttextureClampMode->SetSelection(bsslp->textureClampMode < 4 ? bsslp->textureClampMode : 3);\n\t\t}\n\n\t\tshowControl(refractionStrength, true);\n\t\trefractionStrength->SetValue(wxString::Format(\"%.4f\", bspplp->refractionStrength));\n\n\t\tshowControl(refractionFirePeriod, true);\n\t\trefractionFirePeriod->SetValue(wxString::Format(\"%d\", bspplp->refractionFirePeriod));\n\n\t\tshowControl(parallaxMaxPasses, true);\n\t\tparallaxMaxPasses->SetValue(wxString::Format(\"%.4f\", bspplp->parallaxMaxPasses));\n\n\t\tshowControl(parallaxScale, true);\n\t\tparallaxScale->SetValue(wxString::Format(\"%.4f\", bspplp->parallaxScale));\n\t}\n\telse if (shader->HasType<BSLightingShaderProperty>()) {\n\t\tauto bslsp = dynamic_cast<BSLightingShaderProperty*>(shader);\n\t\tauto* bssp = dynamic_cast<BSShaderProperty*>(shader);\n\t\tif (!bslsp || !bssp)\n\t\t\treturn;\n\n\t\tuint32_t shaderTypeVal = bslsp->GetShaderType();\n\n\t\t// Common properties always shown for BSLightingShaderProperty\n\t\tshowControl(uvOffsetU, true);\n\t\tuvOffsetU->SetValue(wxString::Format(\"%.4f\", bssp->uvOffset.u));\n\t\tuvOffsetV->SetValue(wxString::Format(\"%.4f\", bssp->uvOffset.v));\n\n\t\tshowControl(uvScaleU, true);\n\t\tuvScaleU->SetValue(wxString::Format(\"%.4f\", bssp->uvScale.u));\n\t\tuvScaleV->SetValue(wxString::Format(\"%.4f\", bssp->uvScale.v));\n\n\t\tshowControl(textureClampMode, true);\n\t\ttextureClampMode->SetSelection(bslsp->textureClampMode < 4 ? bslsp->textureClampMode : 3);\n\n\t\tshowControl(refractionStrength, true);\n\t\trefractionStrength->SetValue(wxString::Format(\"%.4f\", bslsp->refractionStrength));\n\n\t\t// Lighting Effect 1/2 (softlighting/rimlightPower) - stream < 130\n\t\tif (version.Stream() < 130) {\n\t\t\tshowControl(lightingEffect1, true);\n\t\t\tlightingEffect1->SetValue(wxString::Format(\"%.4f\", bslsp->softlighting));\n\n\t\t\tshowControl(lightingEffect2, true);\n\t\t\tlightingEffect2->SetValue(wxString::Format(\"%.4f\", bslsp->rimlightPower));\n\t\t}\n\n\t\t// Shader type-specific fields\n\t\tUpdateShaderTypeFields(shaderTypeVal);\n\n\t\t// FO4+ properties (stream >= 130)\n\t\tif (version.Stream() >= 130) {\n\t\t\tshowControl(grayscaleToPaletteScale, true);\n\t\t\tgrayscaleToPaletteScale->SetValue(wxString::Format(\"%.4f\", bslsp->grayscaleToPaletteScale));\n\n\t\t\tshowControl(fresnelPower, true);\n\t\t\tfresnelPower->SetValue(wxString::Format(\"%.4f\", bslsp->fresnelPower));\n\n\t\t\tshowControl(wetnessSpecScale, true);\n\t\t\twetnessSpecScale->SetValue(wxString::Format(\"%.4f\", bslsp->wetnessSpecScale));\n\n\t\t\tshowControl(wetnessSpecPower, true);\n\t\t\twetnessSpecPower->SetValue(wxString::Format(\"%.4f\", bslsp->wetnessSpecPower));\n\n\t\t\tshowControl(wetnessMinVar, true);\n\t\t\twetnessMinVar->SetValue(wxString::Format(\"%.4f\", bslsp->wetnessMinVar));\n\n\t\t\tshowControl(wetnessFresnelPower, true);\n\t\t\twetnessFresnelPower->SetValue(wxString::Format(\"%.4f\", bslsp->wetnessFresnelPower));\n\n\t\t\tshowControl(wetnessMetalness, true);\n\t\t\twetnessMetalness->SetValue(wxString::Format(\"%.4f\", bslsp->wetnessMetalness));\n\n\t\t\tshowControl(wetMaterialPath, true);\n\t\t\twetMaterialPath->SetValue(bslsp->GetWetMaterialName());\n\n\t\t\tshowControl(subsurfaceRolloff, true);\n\t\t\tsubsurfaceRolloff->SetValue(wxString::Format(\"%.4f\", bslsp->subsurfaceRolloff));\n\n\t\t\tshowControl(rimlightPower, true);\n\t\t\trimlightPower->SetValue(wxString::Format(\"%.4f\", bslsp->rimlightPower));\n\n\t\t\tshowControl(backlightPower, true);\n\t\t\tbacklightPower->SetValue(wxString::Format(\"%.4f\", bslsp->backlightPower));\n\t\t}\n\n\t\t// FO4-only (stream 130-139)\n\t\tif (version.IsFO4()) {\n\t\t\tshowControl(wetnessEnvMapScale, true);\n\t\t\twetnessEnvMapScale->SetValue(wxString::Format(\"%.4f\", bslsp->wetnessEnvmapScale));\n\t\t}\n\t}\n\n\tadvancedShaderPane->GetPane()->Layout();\n}\n\nvoid ShapeProperties::UpdateShaderTypeFields(uint32_t shaderTypeVal) {\n\twxSizer* gridSizer = advancedShaderPane->GetPane()->GetSizer();\n\tauto showControl = [gridSizer](wxWindow* ctrl, bool show) {\n\t\tif (!ctrl || !gridSizer)\n\t\t\treturn;\n\t\tctrl->Show(show);\n\n\t\twxSizerItem* prevItem = nullptr;\n\t\tfor (auto* item : gridSizer->GetChildren()) {\n\t\t\tbool found = false;\n\t\t\tif (item->GetWindow() == ctrl) {\n\t\t\t\tfound = true;\n\t\t\t}\n\t\t\telse if (item->IsSizer()) {\n\t\t\t\tfor (auto* subItem : item->GetSizer()->GetChildren()) {\n\t\t\t\t\tif (subItem->GetWindow() == ctrl) {\n\t\t\t\t\t\tfor (auto* s : item->GetSizer()->GetChildren())\n\t\t\t\t\t\t\tif (s->GetWindow())\n\t\t\t\t\t\t\t\ts->GetWindow()->Show(show);\n\t\t\t\t\t\tfound = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (found) {\n\t\t\t\titem->Show(show);\n\t\t\t\tif (prevItem) {\n\t\t\t\t\tprevItem->Show(show);\n\t\t\t\t\tif (prevItem->GetWindow())\n\t\t\t\t\t\tprevItem->GetWindow()->Show(show);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprevItem = item;\n\t\t}\n\t};\n\n\t// Hide all shader-type-specific fields\n\twxWindow* typeSpecificCtrls[] = {\n\t\tenvironmentMapScale, skinTintColor, hairTintColor,\n\t\tparallaxMaxPasses, parallaxScale,\n\t\tparallaxInnerLayerThickness, parallaxRefractionScale,\n\t\tparallaxInnerLayerTexScaleU, parallaxEnvmapStrength,\n\t\tsparkleParamsR,\n\t\teyeCubemapScale, eyeLeftReflectX, eyeRightReflectX\n\t};\n\tfor (auto* ctrl : typeSpecificCtrls)\n\t\tshowControl(ctrl, false);\n\n\tswitch (shaderTypeVal) {\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_ENVMAP:\n\t\t\tshowControl(environmentMapScale, true);\n\t\t\tbreak;\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_SKINTINT:\n\t\t\tshowControl(skinTintColor, true);\n\t\t\tbreak;\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_HAIRTINT:\n\t\t\tshowControl(hairTintColor, true);\n\t\t\tbreak;\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_PARALLAXOCC:\n\t\t\tshowControl(parallaxMaxPasses, true);\n\t\t\tshowControl(parallaxScale, true);\n\t\t\tbreak;\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_MULTILAYERPARALLAX:\n\t\t\tshowControl(parallaxInnerLayerThickness, true);\n\t\t\tshowControl(parallaxRefractionScale, true);\n\t\t\tshowControl(parallaxInnerLayerTexScaleU, true);\n\t\t\tshowControl(parallaxEnvmapStrength, true);\n\t\t\tbreak;\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_MULTIINDEXSNOW:\n\t\t\tshowControl(sparkleParamsR, true);\n\t\t\tbreak;\n\t\tcase BSLightingShaderPropertyShaderType::BSLSP_EYE:\n\t\t\tshowControl(eyeCubemapScale, true);\n\t\t\tshowControl(eyeLeftReflectX, true);\n\t\t\tshowControl(eyeRightReflectX, true);\n\t\t\tbreak;\n\t}\n\n\tadvancedShaderPane->GetPane()->Layout();\n\tadvancedShaderPane->InvalidateBestSize();\n\tpgShader->InvalidateBestSize();\n\tnbProperties->InvalidateBestSize();\n\tInvalidateBestSize();\n\tpgShader->Layout();\n\n\t// Grow the dialog if needed, but don't shrink it\n\twxSize cur = GetSize();\n\twxSize best = GetBestSize();\n\twxSize newSize(std::max(cur.x, best.x), std::max(cur.y, best.y));\n\tSetMinSize(newSize);\n\tSetSize(newSize);\n}\n\nvoid ShapeProperties::OnChooseMaterial(wxCommandEvent& WXUNUSED(event)) {\n\twxString fileName = wxFileSelector(_(\"Choose material file\"), wxEmptyString, wxEmptyString, \".bgsm\", \"Material files (*.bgsm;*.bgem)|*.bgsm;*.bgem\", wxFD_FILE_MUST_EXIST, this);\n\tif (fileName.empty())\n\t\treturn;\n\n\twxString findStr = wxString::Format(\"%cmaterials%c\", PathSepChar, PathSepChar);\n\tint index = fileName.Lower().Find(findStr);\n\tif (index != wxNOT_FOUND && fileName.length() - 1 > (size_t)index + 1)\n\t\tfileName = fileName.Mid(index + 1);\n\n\tshaderName->SetValue(fileName);\n}\n\nvoid ShapeProperties::OnAddShader(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShowConfirmationDialog())\n\t\treturn;\n\n\tfor (auto& shape : shapes)\n\t\tAddShader(shape);\n\n\tGetShader();\n\tGetTransparency();\n}\n\nvoid ShapeProperties::AddShader(NiShape* shape) {\n\tNiShader* shader = nif->GetShader(shape);\n\tif (shader)\n\t\treturn;\n\n\tauto targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tstd::unique_ptr<NiShader> newShader = nullptr;\n\tstd::unique_ptr<NiMaterialProperty> newMaterial = nullptr;\n\n\tswitch (targetGame) {\n\t\tcase OB:\n\t\t\tnewMaterial = std::make_unique<NiMaterialProperty>();\n\t\t\tshape->propertyRefs.AddBlockRef(nif->GetHeader().AddBlock(std::move(newMaterial)));\n\t\t\tbreak;\n\n\t\tcase FO3:\n\t\tcase FONV:\n\t\t\tnewShader = std::make_unique<BSShaderPPLightingProperty>();\n\t\t\tshape->propertyRefs.AddBlockRef(nif->GetHeader().AddBlock(std::move(newShader)));\n\n\t\t\tnewMaterial = std::make_unique<NiMaterialProperty>();\n\t\t\tshape->propertyRefs.AddBlockRef(nif->GetHeader().AddBlock(std::move(newMaterial)));\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tnewShader = std::make_unique<BSLightingShaderProperty>(nif->GetHeader().GetVersion());\n\t\t\tauto shaderPropertyRef = shape->ShaderPropertyRef();\n\t\t\tif (shaderPropertyRef)\n\t\t\t\tshaderPropertyRef->index = nif->GetHeader().AddBlock(std::move(newShader));\n\t}\n\n\tshader = nif->GetShader(shape);\n\tif (shader) {\n\t\tauto nifTexSet = std::make_unique<BSShaderTextureSet>(nif->GetHeader().GetVersion());\n\t\tauto textureSetRef = shader->TextureSetRef();\n\t\tif (textureSetRef)\n\t\t\ttextureSetRef->index = nif->GetHeader().AddBlock(std::move(nifTexSet));\n\t}\n\n\tAssignDefaultTexture(shape);\n\tGetShader();\n\tos->SetPendingChanges();\n}\n\nvoid ShapeProperties::OnRemoveShader(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShowConfirmationDialog())\n\t\treturn;\n\n\tfor (auto& shape : shapes)\n\t\tRemoveShader(shape);\n\n\tGetShader();\n\tGetTransparency();\n}\n\nvoid ShapeProperties::RemoveShader(NiShape* shape) {\n\tNiShader* shader = nif->GetShader(shape);\n\tif (!shader)\n\t\treturn;\n\n\tnif->DeleteShader(shape);\n\tAssignDefaultTexture(shape);\n\tos->SetPendingChanges();\n}\n\nvoid ShapeProperties::OnSetTextures(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShowConfirmationDialog())\n\t\treturn;\n\n\tbool shaderFound = false;\n\tfor (auto& shape : shapes) {\n\t\tNiShader* shader = nif->GetShader(shape);\n\t\tif (shader) {\n\t\t\tshaderFound = true;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (!shaderFound)\n\t\treturn;\n\n\twxDialog dlg;\n\tif (wxXmlResource::Get()->LoadDialog(&dlg, this, \"dlgShapeTextures\")) {\n\t\twxGrid* stTexGrid = XRCCTRL(dlg, \"stTexGrid\", wxGrid);\n\t\tstTexGrid->CreateGrid(10, 1);\n\t\tstTexGrid->EnableEditing(true);\n\t\tstTexGrid->EnableGridLines(true);\n\t\tstTexGrid->EnableDragGridSize(false);\n\t\tstTexGrid->SetMargins(0, 0);\n\n\t\t// Columns\n\t\tstTexGrid->SetColSize(0, 700);\n\t\tstTexGrid->EnableDragColMove(false);\n\t\tstTexGrid->EnableDragColSize(false);\n\t\tstTexGrid->SetColLabelSize(30);\n\t\tstTexGrid->SetColLabelValue(0, \"Game Texture Paths\");\n\t\tstTexGrid->SetColLabelAlignment(wxALIGN_CENTRE, wxALIGN_CENTRE);\n\n\t\t// Rows\n\t\tstTexGrid->AutoSizeRows();\n\t\tstTexGrid->EnableDragRowSize(false);\n\t\tstTexGrid->SetRowLabelSize(80);\n\t\tstTexGrid->SetRowLabelValue(0, \"Diffuse\");\n\t\tstTexGrid->SetRowLabelValue(1, \"Normal\");\n\t\tstTexGrid->SetRowLabelValue(2, \"Glow/Skin\");\n\t\tstTexGrid->SetRowLabelValue(3, \"Parallax\");\n\t\tstTexGrid->SetRowLabelValue(4, \"Environment\");\n\t\tstTexGrid->SetRowLabelValue(5, \"Env Mask\");\n\t\tstTexGrid->SetRowLabelValue(6, \"6\");\n\t\tstTexGrid->SetRowLabelValue(7, \"Specular\");\n\t\tstTexGrid->SetRowLabelValue(8, \"8\");\n\t\tstTexGrid->SetRowLabelValue(9, \"9\");\n\t\tstTexGrid->SetRowLabelAlignment(wxALIGN_LEFT, wxALIGN_CENTRE);\n\n\t\t// Cell Defaults\n\t\tstTexGrid->SetDefaultCellAlignment(wxALIGN_LEFT, wxALIGN_TOP);\n\n\t\tNiShape* firstShape = shapes[0];\n\n\t\tint blockType = 0;\n\t\tfor (int i = 0; i < 10; i++) {\n\t\t\tstd::string texPath;\n\t\t\tblockType = nif->GetTextureSlot(firstShape, texPath, i);\n\t\t\tif (!blockType)\n\t\t\t\tcontinue;\n\n\t\t\tstTexGrid->SetCellValue(i, 0, ToOSSlashes(texPath));\n\t\t}\n\n\t\t// BSEffectShaderProperty\n\t\tif (blockType == 2) {\n\t\t\tstTexGrid->SetRowLabelValue(0, \"Source\");\n\t\t\tstTexGrid->SetRowLabelValue(1, \"Normal\");\n\t\t\tstTexGrid->HideRow(2);\n\t\t\tstTexGrid->SetRowLabelValue(3, \"Greyscale\");\n\t\t\tstTexGrid->SetRowLabelValue(4, \"Environment\");\n\t\t\tstTexGrid->SetRowLabelValue(5, \"Env Mask\");\n\t\t\tstTexGrid->HideRow(6);\n\t\t\tstTexGrid->HideRow(7);\n\t\t\tstTexGrid->HideRow(8);\n\t\t\tstTexGrid->HideRow(9);\n\t\t}\n\n\t\t// NiTexturingProperty/NiSourceTexture\n\t\tif (blockType == 3) {\n\t\t\tstTexGrid->SetRowLabelValue(0, \"Base\");\n\t\t\tstTexGrid->SetRowLabelValue(1, \"Dark\");\n\t\t\tstTexGrid->SetRowLabelValue(2, \"Detail\");\n\t\t\tstTexGrid->SetRowLabelValue(3, \"Gloss\");\n\t\t\tstTexGrid->SetRowLabelValue(4, \"Glow\");\n\t\t\tstTexGrid->SetRowLabelValue(5, \"Bump Map\");\n\t\t\tstTexGrid->SetRowLabelValue(6, \"Decal 0\");\n\t\t\tstTexGrid->SetRowLabelValue(7, \"Decal 1\");\n\t\t\tstTexGrid->SetRowLabelValue(8, \"Decal 2\");\n\t\t\tstTexGrid->SetRowLabelValue(9, \"Decal 3\");\n\t\t}\n\n\t\tif (dlg.ShowModal() == wxID_OK) {\n\t\t\tauto dataPath = Config[\"GameDataPath\"];\n\t\t\tstd::vector<std::string> texFiles(10);\n\t\t\tfor (int i = 0; i < 10; i++) {\n\t\t\t\tstd::string texPath = stTexGrid->GetCellValue(i, 0).ToStdString();\n\t\t\t\tstd::string texPath_bs = ToBackslashes(texPath);\n\n\t\t\t\tfor (auto& shape : shapes)\n\t\t\t\t\tnif->SetTextureSlot(shape, texPath_bs, i);\n\n\t\t\t\tif (!texPath.empty())\n\t\t\t\t\ttexFiles[i] = dataPath + texPath;\n\t\t\t}\n\n\t\t\tnif->TrimTexturePaths();\n\t\t\tos->SetPendingChanges();\n\n\t\t\tfor (auto& shape : shapes) {\n\t\t\t\tos->project->SetTextures(shape, texFiles);\n\t\t\t\tos->glView->SetMeshTextures(shape->name.get(), texFiles, false, MaterialFile(), true);\n\t\t\t}\n\n\t\t\tos->glView->Render();\n\t\t}\n\t}\n}\n\nvoid ShapeProperties::AssignDefaultTexture(NiShape* shape) {\n\tos->project->SetTextures(shape);\n\tos->SetPendingChanges();\n\tos->glView->Render();\n}\n\nvoid ShapeProperties::GetTransparency() {\n\tbool multipleShapes = shapes.size() > 1;\n\n\tbool anyWithTrans = false;\n\tbool anyWithoutTrans = false;\n\tfor (auto& shape : shapes) {\n\t\tNiAlphaProperty* alphaProp = nif->GetAlphaProperty(shape);\n\t\tif (alphaProp)\n\t\t\tanyWithTrans = true;\n\t\telse\n\t\t\tanyWithoutTrans = true;\n\t}\n\n\tNiShape* shape = shapes[0];\n\tNiAlphaProperty* alphaProp = nif->GetAlphaProperty(shape);\n\n\tif (multipleShapes) {\n\t\tbtnAddTransparency->Enable(anyWithoutTrans);\n\t\tbtnRemoveTransparency->Enable(anyWithTrans);\n\n\t\talphaThreshold->Disable();\n\t\tvertexAlpha->Disable();\n\t\talphaTest->Disable();\n\t\talphaBlend->Disable();\n\t\talphaSrcBlend->Disable();\n\t\talphaDestBlend->Disable();\n\t\talphaTestFunc->Disable();\n\t\talphaNoSorter->Disable();\n\t}\n\telse {\n\t\tif (alphaProp) {\n\t\t\talphaThreshold->Enable();\n\t\t\tbtnAddTransparency->Disable();\n\t\t\tbtnRemoveTransparency->Enable();\n\t\t\talphaTest->Enable();\n\t\t\talphaBlend->Enable();\n\t\t\talphaSrcBlend->Enable();\n\t\t\talphaDestBlend->Enable();\n\t\t\talphaTestFunc->Enable();\n\t\t\talphaNoSorter->Enable();\n\n\t\t\tNiShader* shader = nif->GetShader(shape);\n\t\t\tif (shader) {\n\t\t\t\t// FO3/NV: Vertex Alpha only works with BSShaderNoLightingProperty\n\t\t\t\tif (!isFO3NV || isFO3NVNoLighting)\n\t\t\t\t\tvertexAlpha->Enable();\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\talphaThreshold->Disable();\n\t\t\tvertexAlpha->Disable();\n\t\t\talphaTest->Disable();\n\t\t\talphaBlend->Disable();\n\t\t\talphaSrcBlend->Disable();\n\t\t\talphaDestBlend->Disable();\n\t\t\talphaTestFunc->Disable();\n\t\t\talphaNoSorter->Disable();\n\t\t\tbtnAddTransparency->Enable();\n\t\t\tbtnRemoveTransparency->Disable();\n\t\t}\n\t}\n\n\t// Set values of first shape's alpha property\n\tif (alphaProp) {\n\t\talphaThreshold->SetValue(wxString::Format(\"%d\", alphaProp->threshold));\n\t\talphaTest->SetValue(alphaProp->flags & (1 << 9));\n\t\talphaBlend->SetValue(alphaProp->flags & 1);\n\n\t\tint srcBlend = (alphaProp->flags >> 1) & 0xF;\n\t\tint destBlend = (alphaProp->flags >> 5) & 0xF;\n\t\tint testFunc = (alphaProp->flags >> 10) & 0x7;\n\t\tbool noSorter = (alphaProp->flags >> 13) & 1;\n\n\t\talphaSrcBlend->SetSelection(srcBlend < static_cast<int>(alphaSrcBlend->GetCount()) ? srcBlend : 0);\n\t\talphaDestBlend->SetSelection(destBlend < static_cast<int>(alphaDestBlend->GetCount()) ? destBlend : 0);\n\t\talphaTestFunc->SetSelection(testFunc < static_cast<int>(alphaTestFunc->GetCount()) ? testFunc : 0);\n\t\talphaNoSorter->SetValue(noSorter);\n\t}\n\n\t// Expand transparency pane if the mesh has an alpha property\n\tif (anyWithTrans)\n\t\ttransparencyPane->Collapse(false);\n}\n\nvoid ShapeProperties::OnAddTransparency(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShowConfirmationDialog())\n\t\treturn;\n\n\tfor (auto& shape : shapes)\n\t\tAddTransparency(shape);\n\n\tGetTransparency();\n}\n\nvoid ShapeProperties::AddTransparency(NiShape* shape) {\n\tNiAlphaProperty* alphaPropExists = nif->GetAlphaProperty(shape);\n\tif (alphaPropExists)\n\t\treturn;\n\n\tauto alphaProp = std::make_unique<NiAlphaProperty>();\n\tnif->AssignAlphaProperty(shape, std::move(alphaProp));\n\tos->SetPendingChanges();\n}\n\nvoid ShapeProperties::OnRemoveTransparency(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShowConfirmationDialog())\n\t\treturn;\n\n\tfor (auto& shape : shapes)\n\t\tRemoveTransparency(shape);\n\n\tGetTransparency();\n}\n\nvoid ShapeProperties::OnCopyShaderFromShape(wxCommandEvent& WXUNUSED(event)) {\n\tif (!ShowConfirmationDialog())\n\t\treturn;\n\n\tbool multipleShapes = shapes.size() > 1;\n\tNiShape* firstShape = shapes[0];\n\twxArrayString choices;\n\n\tauto nifShapes = nif->GetShapes();\n\tfor (auto& s : nifShapes) {\n\t\t// If there's only one selected shape, it can't be the source of the copy\n\t\tif (multipleShapes || s != firstShape) {\n\t\t\tchoices.Add(wxString::FromUTF8(s->name.get()));\n\t\t}\n\t}\n\n\tif (choices.GetCount() > 0) {\n\t\tstd::string shapeName{wxGetSingleChoice(_(\"Please choose a shape to copy from\"), _(\"Choose shape\"), choices, 0, this).ToUTF8()};\n\t\tif (shapeName.empty())\n\t\t\treturn;\n\n\t\tauto shapeChoice = nif->FindBlockByName<NiShape>(shapeName);\n\t\tif (shapeChoice) {\n\t\t\tauto shapeChoiceShader = nif->GetShader(shapeChoice);\n\t\t\tauto texturePaths = os->project->GetShapeTextures(shapeChoice);\n\n\t\t\tfor (auto& shape : shapes) {\n\t\t\t\tif (shape != shapeChoice) {\n\t\t\t\t\t// Delete old shader and children from destination shapes\n\t\t\t\t\tnif->DeleteShader(shape);\n\n\t\t\t\t\tif (shapeChoiceShader) {\n\t\t\t\t\t\t// Clone shader\n\t\t\t\t\t\tauto destShaderS = shapeChoiceShader->Clone();\n\t\t\t\t\t\tauto destShader = destShaderS.get();\n\n\t\t\t\t\t\tint destShaderId = nif->GetHeader().AddBlock(std::move(destShaderS));\n\n\t\t\t\t\t\t// Clone shader children\n\t\t\t\t\t\tnif->CloneChildren(destShader);\n\n\t\t\t\t\t\t// Assign cloned shader to shape\n\t\t\t\t\t\tshape->ShaderPropertyRef()->index = destShaderId;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shapeChoiceShader) {\n\t\t\t\t\t\t// Load same textures\n\t\t\t\t\t\tos->project->SetTextures(shape, texturePaths);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Update UI\n\t\t\tGetShader();\n\t\t\tGetTransparency();\n\n\t\t\tos->SetPendingChanges();\n\t\t\tos->glView->Render();\n\t\t}\n\t}\n}\n\nvoid ShapeProperties::RemoveTransparency(NiShape* shape) {\n\tNiAlphaProperty* alphaPropExists = nif->GetAlphaProperty(shape);\n\tif (!alphaPropExists)\n\t\treturn;\n\n\tnif->RemoveAlphaProperty(shape);\n\tos->SetPendingChanges();\n}\n\n\nvoid ShapeProperties::GetGeometry() {\n\t// Initially set checkbox states for first shape\n\tNiShape* firstShape = shapes[0];\n\tskinned->SetValue(firstShape->IsSkinned());\n\n\tbool hasSubIndex = firstShape->HasType<BSSubIndexTriShape>();\n\tsubIndex->SetValue(hasSubIndex);\n\n\tbool hasDynamic = firstShape->HasType<BSDynamicTriShape>();\n\tdynamic->SetValue(hasDynamic);\n\n\tBSTriShape* bsTriShapeFirst = dynamic_cast<BSTriShape*>(firstShape);\n\tif (bsTriShapeFirst) {\n\t\tfullPrecision->SetValue(bsTriShapeFirst->IsFullPrecision());\n\t\tfullPrecision->Enable(bsTriShapeFirst->CanChangePrecision());\n\t}\n\telse\n\t\tfullPrecision->SetValue(true);\n\n\tsubIndex->Disable();\n\tdynamic->Disable();\n\tfullPrecision->Disable();\n\n\tauto& version = nif->GetHeader().GetVersion();\n\n\tbool subIndexAvail = false;\n\tif (version.Stream() >= 130)\n\t\tsubIndexAvail = true;\n\n\tbool dynamicAvail = false;\n\tif (version.Stream() == 100)\n\t\tdynamicAvail = true;\n\n\tbool fullPrecisionAvail = true;\n\n\tfor (auto& shape : shapes) {\n\t\tBSTriShape* bsTriShape = dynamic_cast<BSTriShape*>(shape);\n\t\tif (!bsTriShape) {\n\t\t\t// Changing these only possible with BSTriShape and co.\n\t\t\tsubIndexAvail = false;\n\t\t\tdynamicAvail = false;\n\t\t\tfullPrecisionAvail = false;\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (fullPrecisionAvail) {\n\t\t\tif (nif->GetHeader().GetVersion().Stream() == 100) {\n\t\t\t\tfullPrecisionAvail = false; // Changing precision only possible in FO4\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\n\t\tif (fullPrecisionAvail) {\n\t\t\tif (!bsTriShape->CanChangePrecision()) {\n\t\t\t\tfullPrecisionAvail = false;  // Changing precision only if shape allows it\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (fullPrecisionAvail)\n\t\tfullPrecision->Enable();\n\tif (subIndexAvail)\n\t\tsubIndex->Enable();\n\tif (dynamicAvail)\n\t\tdynamic->Enable();\n\n\t// Check for undetermined (multiple) skinned states\n\tfor (auto& shape : shapes) {\n\t\tbool checked = skinned->Get3StateValue() == wxCheckBoxState::wxCHK_CHECKED;\n\t\tif (checked != shape->IsSkinned()) {\n\t\t\tskinned->Set3StateValue(wxCheckBoxState::wxCHK_UNDETERMINED);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t// Check for undetermined (multiple) subindex states\n\tfor (auto& shape : shapes) {\n\t\tif (subIndexAvail) {\n\t\t\tbool checked = subIndex->Get3StateValue() == wxCheckBoxState::wxCHK_CHECKED;\n\t\t\tif (checked != shape->HasType<BSSubIndexTriShape>()) {\n\t\t\t\tsubIndex->Set3StateValue(wxCheckBoxState::wxCHK_UNDETERMINED);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for undetermined (multiple) dynamic states\n\tfor (auto& shape : shapes) {\n\t\tif (dynamicAvail) {\n\t\t\tbool checked = dynamic->Get3StateValue() == wxCheckBoxState::wxCHK_CHECKED;\n\t\t\tif (checked != shape->HasType<BSDynamicTriShape>()) {\n\t\t\t\tdynamic->Set3StateValue(wxCheckBoxState::wxCHK_UNDETERMINED);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for undetermined (multiple) full precision states\n\tfor (auto& shape : shapes) {\n\t\tif (fullPrecisionAvail) {\n\t\t\tBSTriShape* bsTriShape = dynamic_cast<BSTriShape*>(shape);\n\t\t\tif (bsTriShape) {\n\t\t\t\tbool checked = fullPrecision->Get3StateValue() == wxCheckBoxState::wxCHK_CHECKED;\n\t\t\t\tif (checked != bsTriShape->IsFullPrecision()) {\n\t\t\t\t\tfullPrecision->Set3StateValue(wxCheckBoxState::wxCHK_UNDETERMINED);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\n\nvoid ShapeProperties::GetExtraData() {\n\tpgExtraData->Enable(shapes.size() == 1);\n\tNiShape* shape = shapes[0];\n\n\tfor (size_t i = 0; i < extraDataIndices.size(); i++) {\n\t\tfor (int base : {1000, 2000, 3000, 4000}) {\n\t\t\twxWindow* ctrl = FindWindowById(base + static_cast<int>(i), this);\n\t\t\tif (ctrl)\n\t\t\t\tctrl->Destroy();\n\t\t}\n\n\t\tpgExtraData->FitInside();\n\t\tpgExtraData->Layout();\n\t}\n\n\textraDataIndices.clear();\n\n\tfor (auto& extraDataRef : shape->extraDataRefs) {\n\t\tauto extraData = nif->GetHeader().GetBlock(extraDataRef);\n\t\tif (extraData) {\n\t\t\textraDataIndices.push_back(extraDataRef.index);\n\t\t\tAddExtraData(shape, extraData, true);\n\t\t}\n\t}\n}\n\nvoid ShapeProperties::OnAddExtraData(wxCommandEvent& WXUNUSED(event)) {\n\tNiShape* shape = shapes[0];\n\n\tNiStringExtraData extraDataTemp;\n\tAddExtraData(shape, &extraDataTemp);\n}\n\nvoid ShapeProperties::AddExtraData(NiShape* shape, NiExtraData* extraData, bool uiOnly) {\n\tif (!uiOnly) {\n\t\tauto newExtraData = extraData->Clone();\n\t\tint index = nif->AssignExtraData(shape, std::move(newExtraData));\n\t\textraDataIndices.push_back(index);\n\t\tos->SetPendingChanges();\n\t}\n\n\tif (extraDataIndices.empty())\n\t\treturn;\n\n\tint id = extraDataIndices.size() - 1;\n\n\twxButton* extraDataBtn = new wxButton(pgExtraData, 1000 + id, \"Remove\");\n\textraDataBtn->Bind(wxEVT_BUTTON, &ShapeProperties::OnRemoveExtraData, this);\n\n\twxArrayString types;\n\ttypes.Add(\"NiStringExtraData\");\n\ttypes.Add(\"NiIntegerExtraData\");\n\ttypes.Add(\"NiFloatExtraData\");\n\ttypes.Add(\"NiBooleanExtraData\");\n\ttypes.Add(\"NiVectorExtraData\");\n\ttypes.Add(\"NiColorExtraData\");\n\ttypes.Add(\"NiIntegersExtraData\");\n\ttypes.Add(\"NiStringsExtraData\");\n\ttypes.Add(\"NiFloatsExtraData\");\n\ttypes.Add(\"BSDistantObjectLargeRefExtraData\");\n\twxChoice* extraDataType = new wxChoice(pgExtraData, 2000 + id, wxDefaultPosition, wxDefaultSize, types);\n\textraDataType->SetSelection(0);\n\textraDataType->Bind(wxEVT_CHOICE, &ShapeProperties::OnChangeExtraDataType, this);\n\n\twxTextCtrl* extraDataName = new wxTextCtrl(pgExtraData, 3000 + id);\n\n\tint typeSelection = 0;\n\n\tif (uiOnly) {\n\t\tif (extraData->HasType<NiStringExtraData>()) {\n\t\t\tauto stringExtraData = static_cast<NiStringExtraData*>(extraData);\n\t\t\ttypeSelection = 0;\n\t\t\textraDataName->SetValue(stringExtraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiIntegerExtraData>()) {\n\t\t\tauto intExtraData = static_cast<NiIntegerExtraData*>(extraData);\n\t\t\ttypeSelection = 1;\n\t\t\textraDataName->SetValue(intExtraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiFloatExtraData>()) {\n\t\t\tauto floatExtraData = static_cast<NiFloatExtraData*>(extraData);\n\t\t\ttypeSelection = 2;\n\t\t\textraDataName->SetValue(floatExtraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiBooleanExtraData>()) {\n\t\t\ttypeSelection = 3;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiVectorExtraData>()) {\n\t\t\ttypeSelection = 4;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiColorExtraData>()) {\n\t\t\ttypeSelection = 5;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiIntegersExtraData>()) {\n\t\t\ttypeSelection = 6;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiStringsExtraData>()) {\n\t\t\ttypeSelection = 7;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<NiFloatsExtraData>()) {\n\t\t\ttypeSelection = 8;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse if (extraData->HasType<BSDistantObjectLargeRefExtraData>()) {\n\t\t\ttypeSelection = 9;\n\t\t\textraDataName->SetValue(extraData->name.get());\n\t\t}\n\t\telse {\n\t\t\textraDataBtn->Destroy();\n\t\t\textraDataType->Destroy();\n\t\t\textraDataName->Destroy();\n\t\t\treturn;\n\t\t}\n\t}\n\n\textraDataType->SetSelection(typeSelection);\n\n\twxWindow* valueCtrl = CreateValueControl(id, typeSelection);\n\n\tif (uiOnly) {\n\t\tif (extraData->HasType<NiStringExtraData>()) {\n\t\t\tauto stringExtraData = static_cast<NiStringExtraData*>(extraData);\n\t\t\tstatic_cast<wxTextCtrl*>(valueCtrl)->SetValue(stringExtraData->stringData.get());\n\t\t}\n\t\telse if (extraData->HasType<NiIntegerExtraData>()) {\n\t\t\tauto intExtraData = static_cast<NiIntegerExtraData*>(extraData);\n\t\t\tstatic_cast<wxTextCtrl*>(valueCtrl)->SetValue(wxString::Format(\"%d\", intExtraData->integerData));\n\t\t}\n\t\telse if (extraData->HasType<NiFloatExtraData>()) {\n\t\t\tauto floatExtraData = static_cast<NiFloatExtraData*>(extraData);\n\t\t\tstatic_cast<wxTextCtrl*>(valueCtrl)->SetValue(wxString::Format(\"%f\", floatExtraData->floatData));\n\t\t}\n\t\telse if (extraData->HasType<NiBooleanExtraData>()) {\n\t\t\tauto boolExtraData = static_cast<NiBooleanExtraData*>(extraData);\n\t\t\tstatic_cast<wxCheckBox*>(valueCtrl)->SetValue(boolExtraData->booleanData);\n\t\t}\n\t\telse if (extraData->HasType<BSDistantObjectLargeRefExtraData>()) {\n\t\t\tauto distExtraData = static_cast<BSDistantObjectLargeRefExtraData*>(extraData);\n\t\t\tstatic_cast<wxCheckBox*>(valueCtrl)->SetValue(distExtraData->largeRef);\n\t\t}\n\t\telse {\n\t\t\tUpdateEditButtonLabel(id);\n\t\t}\n\t}\n\n\textraDataGrid->Add(extraDataBtn, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);\n\textraDataGrid->Add(extraDataType, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);\n\textraDataGrid->Add(extraDataName, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);\n\textraDataGrid->Add(valueCtrl, 0, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxALL, 5);\n\n\tpgExtraData->FitInside();\n\tpgExtraData->Layout();\n}\n\nvoid ShapeProperties::OnChangeExtraDataType(wxCommandEvent& event) {\n\tNiShape* shape = shapes[0];\n\tChangeExtraDataType(shape, event.GetId() - 2000);\n}\n\nvoid ShapeProperties::ChangeExtraDataType(NiShape* shape, int id) {\n\twxChoice* extraDataType = dynamic_cast<wxChoice*>(FindWindowById(2000 + id, this));\n\tint selection = extraDataType->GetSelection();\n\n\tint index = extraDataIndices[id];\n\tnif->GetHeader().DeleteBlock(index);\n\n\tfor (size_t i = 0; i < extraDataIndices.size(); i++)\n\t\tif (extraDataIndices[i] > index)\n\t\t\textraDataIndices[i]--;\n\n\textraDataIndices[id] = 0xFFFFFFFF;\n\n\twxTextCtrl* extraDataName = dynamic_cast<wxTextCtrl*>(FindWindowById(3000 + id, this));\n\tstd::string nameStr = extraDataName->GetValue().ToStdString();\n\n\t// Destroy the old value control and create the appropriate new one\n\twxWindow* oldValueCtrl = FindWindowById(4000 + id, this);\n\tif (oldValueCtrl) {\n\t\textraDataGrid->Replace(oldValueCtrl, CreateValueControl(id, selection));\n\t\toldValueCtrl->Destroy();\n\t}\n\n\tstd::unique_ptr<NiExtraData> extraDataResult = nullptr;\n\tswitch (selection) {\n\t\tcase 0: {\n\t\t\tauto strExtraData = std::make_unique<NiStringExtraData>();\n\t\t\tstrExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(strExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 1: {\n\t\t\tauto intExtraData = std::make_unique<NiIntegerExtraData>();\n\t\t\tintExtraData->name.get() = nameStr;\n\t\t\tintExtraData->integerData = 0;\n\t\t\textraDataResult = std::move(intExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 2: {\n\t\t\tauto floatExtraData = std::make_unique<NiFloatExtraData>();\n\t\t\tfloatExtraData->name.get() = nameStr;\n\t\t\tfloatExtraData->floatData = 0.0f;\n\t\t\textraDataResult = std::move(floatExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 3: {\n\t\t\tauto boolExtraData = std::make_unique<NiBooleanExtraData>();\n\t\t\tboolExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(boolExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 4: {\n\t\t\tauto vecExtraData = std::make_unique<NiVectorExtraData>();\n\t\t\tvecExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(vecExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 5: {\n\t\t\tauto colorExtraData = std::make_unique<NiColorExtraData>();\n\t\t\tcolorExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(colorExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 6: {\n\t\t\tauto intsExtraData = std::make_unique<NiIntegersExtraData>();\n\t\t\tintsExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(intsExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 7: {\n\t\t\tauto strsExtraData = std::make_unique<NiStringsExtraData>();\n\t\t\tstrsExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(strsExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 8: {\n\t\t\tauto floatsExtraData = std::make_unique<NiFloatsExtraData>();\n\t\t\tfloatsExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(floatsExtraData);\n\t\t\tbreak;\n\t\t}\n\t\tcase 9: {\n\t\t\tauto distExtraData = std::make_unique<BSDistantObjectLargeRefExtraData>();\n\t\t\tdistExtraData->name.get() = nameStr;\n\t\t\textraDataResult = std::move(distExtraData);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (extraDataResult) {\n\t\textraDataIndices[id] = nif->AssignExtraData(shape, std::move(extraDataResult));\n\t\tos->SetPendingChanges();\n\t}\n\n\tpgExtraData->Layout();\n}\n\nvoid ShapeProperties::OnRemoveExtraData(wxCommandEvent& event) {\n\tRemoveExtraData(event.GetId() - 1000);\n}\n\nvoid ShapeProperties::RemoveExtraData(int id) {\n\tfor (int base : {1000, 2000, 3000, 4000}) {\n\t\twxWindow* ctrl = FindWindowById(base + id, this);\n\t\tif (ctrl)\n\t\t\tctrl->Destroy();\n\t}\n\n\tint index = extraDataIndices[id];\n\tnif->GetHeader().DeleteBlock(index);\n\n\tfor (size_t i = 0; i < extraDataIndices.size(); i++)\n\t\tif (extraDataIndices[i] > index)\n\t\t\textraDataIndices[i]--;\n\n\textraDataIndices[id] = 0xFFFFFFFF;\n\n\tpgExtraData->FitInside();\n\tpgExtraData->Layout();\n\tos->SetPendingChanges();\n}\n\nwxWindow* ShapeProperties::CreateValueControl(int id, int typeSelection) {\n\twxWindow* ctrl = nullptr;\n\n\tswitch (typeSelection) {\n\t\tcase 0: // NiStringExtraData\n\t\t\tctrl = new wxTextCtrl(pgExtraData, 4000 + id);\n\t\t\tbreak;\n\n\t\tcase 1: // NiIntegerExtraData\n\t\t\tctrl = new wxTextCtrl(pgExtraData, 4000 + id, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxIntegerValidator<unsigned long>());\n\t\t\tbreak;\n\n\t\tcase 2: // NiFloatExtraData\n\t\t\tctrl = new wxTextCtrl(pgExtraData, 4000 + id, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, wxFloatingPointValidator<float>());\n\t\t\tbreak;\n\n\t\tcase 3: // NiBooleanExtraData\n\t\tcase 9: // BSDistantObjectLargeRefExtraData\n\t\t\tctrl = new wxCheckBox(pgExtraData, 4000 + id, \"\");\n\t\t\tbreak;\n\n\t\tcase 4: // NiVectorExtraData\n\t\tcase 5: // NiColorExtraData\n\t\tcase 6: // NiIntegersExtraData\n\t\tcase 7: // NiStringsExtraData\n\t\tcase 8: // NiFloatsExtraData\n\t\t{\n\t\t\tauto* btn = new wxButton(pgExtraData, 4000 + id, _(\"Edit...\"));\n\t\t\tbtn->Bind(wxEVT_BUTTON, &ShapeProperties::OnEditExtraData, this);\n\t\t\tctrl = btn;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn ctrl;\n}\n\nvoid ShapeProperties::UpdateEditButtonLabel(int id) {\n\tauto* btn = dynamic_cast<wxButton*>(FindWindowById(4000 + id, this));\n\tif (!btn)\n\t\treturn;\n\n\tint blockIndex = extraDataIndices[id];\n\tauto extraData = nif->GetHeader().GetBlock<NiExtraData>(blockIndex);\n\tif (!extraData)\n\t\treturn;\n\n\tif (extraData->HasType<NiVectorExtraData>()) {\n\t\tauto vecED = static_cast<NiVectorExtraData*>(extraData);\n\t\tbtn->SetLabel(wxString::Format(_(\"Edit... (%.2f, %.2f, %.2f, %.2f)\"),\n\t\t\tvecED->vectorData.x, vecED->vectorData.y, vecED->vectorData.z, vecED->vectorData.w));\n\t}\n\telse if (extraData->HasType<NiColorExtraData>()) {\n\t\tauto colorED = static_cast<NiColorExtraData*>(extraData);\n\t\tbtn->SetLabel(wxString::Format(_(\"Edit... (%.2f, %.2f, %.2f, %.2f)\"),\n\t\t\tcolorED->colorData.r, colorED->colorData.g, colorED->colorData.b, colorED->colorData.a));\n\t}\n\telse if (extraData->HasType<NiIntegersExtraData>()) {\n\t\tauto intsED = static_cast<NiIntegersExtraData*>(extraData);\n\t\tbtn->SetLabel(wxString::Format(_(\"%s (%u items)\"), _(\"Edit...\"), static_cast<unsigned int>(intsED->integersData.size())));\n\t}\n\telse if (extraData->HasType<NiStringsExtraData>()) {\n\t\tauto strsED = static_cast<NiStringsExtraData*>(extraData);\n\t\tbtn->SetLabel(wxString::Format(_(\"%s (%u items)\"), _(\"Edit...\"), static_cast<unsigned int>(strsED->stringsData.size())));\n\t}\n\telse if (extraData->HasType<NiFloatsExtraData>()) {\n\t\tauto floatsED = static_cast<NiFloatsExtraData*>(extraData);\n\t\tbtn->SetLabel(wxString::Format(_(\"%s (%u items)\"), _(\"Edit...\"), static_cast<unsigned int>(floatsED->floatsData.size())));\n\t}\n}\n\nvoid ShapeProperties::OnEditExtraData(wxCommandEvent& event) {\n\tint id = event.GetId() - 4000;\n\tif (id < 0 || id >= static_cast<int>(extraDataIndices.size()))\n\t\treturn;\n\n\tint blockIndex = extraDataIndices[id];\n\tauto extraData = nif->GetHeader().GetBlock<NiExtraData>(blockIndex);\n\tif (!extraData)\n\t\treturn;\n\n\tif (extraData->HasType<NiVectorExtraData>())\n\t\tShowVectorEditDialog(blockIndex);\n\telse if (extraData->HasType<NiColorExtraData>())\n\t\tShowColorEditDialog(blockIndex);\n\telse if (extraData->HasType<NiIntegersExtraData>() || extraData->HasType<NiStringsExtraData>() || extraData->HasType<NiFloatsExtraData>())\n\t\tShowListEditDialog(blockIndex);\n\n\tUpdateEditButtonLabel(id);\n\tpgExtraData->Layout();\n}\n\nvoid ShapeProperties::ShowVectorEditDialog(int extraDataIndex) {\n\tauto vecED = nif->GetHeader().GetBlock<NiVectorExtraData>(extraDataIndex);\n\tif (!vecED)\n\t\treturn;\n\n\twxDialog dlg(this, wxID_ANY, _(\"Edit Vector Extra Data\"), wxDefaultPosition, wxSize(400, 280), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tauto* grid = new wxFlexGridSizer(2, 5, 5);\n\tgrid->AddGrowableCol(1, 1);\n\n\tauto addField = [&](const wxString& label, float value) -> wxTextCtrl* {\n\t\tgrid->Add(new wxStaticText(&dlg, wxID_ANY, label), 0, wxALIGN_CENTER_VERTICAL);\n\t\tauto* tc = new wxTextCtrl(&dlg, wxID_ANY, wxString::Format(\"%.6f\", value));\n\t\tgrid->Add(tc, 1, wxEXPAND);\n\t\treturn tc;\n\t};\n\n\tauto* xCtrl = addField(\"X:\", vecED->vectorData.x);\n\tauto* yCtrl = addField(\"Y:\", vecED->vectorData.y);\n\tauto* zCtrl = addField(\"Z:\", vecED->vectorData.z);\n\tauto* wCtrl = addField(\"W:\", vecED->vectorData.w);\n\n\tsizer->Add(grid, 1, wxEXPAND | wxALL, 10);\n\tsizer->Add(dlg.CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);\n\tdlg.SetSizer(sizer);\n\n\tif (dlg.ShowModal() == wxID_OK) {\n\t\tdouble val;\n\t\tif (xCtrl->GetValue().ToDouble(&val)) vecED->vectorData.x = static_cast<float>(val);\n\t\tif (yCtrl->GetValue().ToDouble(&val)) vecED->vectorData.y = static_cast<float>(val);\n\t\tif (zCtrl->GetValue().ToDouble(&val)) vecED->vectorData.z = static_cast<float>(val);\n\t\tif (wCtrl->GetValue().ToDouble(&val)) vecED->vectorData.w = static_cast<float>(val);\n\t\tos->SetPendingChanges();\n\t}\n}\n\nvoid ShapeProperties::ShowColorEditDialog(int extraDataIndex) {\n\tauto colorED = nif->GetHeader().GetBlock<NiColorExtraData>(extraDataIndex);\n\tif (!colorED)\n\t\treturn;\n\n\twxDialog dlg(this, wxID_ANY, _(\"Edit Color Extra Data\"), wxDefaultPosition, wxSize(420, 320), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\tauto* grid = new wxFlexGridSizer(2, 5, 5);\n\tgrid->AddGrowableCol(1, 1);\n\n\tauto addField = [&](const wxString& label, float value) -> wxTextCtrl* {\n\t\tgrid->Add(new wxStaticText(&dlg, wxID_ANY, label), 0, wxALIGN_CENTER_VERTICAL);\n\t\tauto* tc = new wxTextCtrl(&dlg, wxID_ANY, wxString::Format(\"%.6f\", value));\n\t\tgrid->Add(tc, 1, wxEXPAND);\n\t\treturn tc;\n\t};\n\n\tauto* rCtrl = addField(\"R:\", colorED->colorData.r);\n\tauto* gCtrl = addField(\"G:\", colorED->colorData.g);\n\tauto* bCtrl = addField(\"B:\", colorED->colorData.b);\n\tauto* aCtrl = addField(\"A:\", colorED->colorData.a);\n\n\t// Color picker row\n\tgrid->Add(new wxStaticText(&dlg, wxID_ANY, _(\"Preview:\")), 0, wxALIGN_CENTER_VERTICAL);\n\tauto clampByte = [](float f) -> unsigned char {\n\t\treturn static_cast<unsigned char>(std::clamp(f * 255.0f, 0.0f, 255.0f));\n\t};\n\twxColour initColor(clampByte(colorED->colorData.r), clampByte(colorED->colorData.g), clampByte(colorED->colorData.b));\n\tauto* picker = new wxColourPickerCtrl(&dlg, wxID_ANY, initColor);\n\tgrid->Add(picker, 1, wxEXPAND);\n\n\t// Sync: picker -> float fields\n\tpicker->Bind(wxEVT_COLOURPICKER_CHANGED, [rCtrl, gCtrl, bCtrl](wxColourPickerEvent& evt) {\n\t\twxColour c = evt.GetColour();\n\t\trCtrl->ChangeValue(wxString::Format(\"%.6f\", c.Red() / 255.0f));\n\t\tgCtrl->ChangeValue(wxString::Format(\"%.6f\", c.Green() / 255.0f));\n\t\tbCtrl->ChangeValue(wxString::Format(\"%.6f\", c.Blue() / 255.0f));\n\t});\n\n\t// Sync: float fields -> picker\n\tauto syncPickerFromFields = [rCtrl, gCtrl, bCtrl, picker, clampByte](wxCommandEvent&) {\n\t\tdouble r, g, b;\n\t\tif (!rCtrl->GetValue().ToDouble(&r)) return;\n\t\tif (!gCtrl->GetValue().ToDouble(&g)) return;\n\t\tif (!bCtrl->GetValue().ToDouble(&b)) return;\n\t\tpicker->SetColour(wxColour(clampByte(static_cast<float>(r)), clampByte(static_cast<float>(g)), clampByte(static_cast<float>(b))));\n\t};\n\trCtrl->Bind(wxEVT_TEXT, syncPickerFromFields);\n\tgCtrl->Bind(wxEVT_TEXT, syncPickerFromFields);\n\tbCtrl->Bind(wxEVT_TEXT, syncPickerFromFields);\n\n\tsizer->Add(grid, 1, wxEXPAND | wxALL, 10);\n\tsizer->Add(dlg.CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);\n\tdlg.SetSizer(sizer);\n\n\tif (dlg.ShowModal() == wxID_OK) {\n\t\tdouble val;\n\t\tif (rCtrl->GetValue().ToDouble(&val)) colorED->colorData.r = static_cast<float>(val);\n\t\tif (gCtrl->GetValue().ToDouble(&val)) colorED->colorData.g = static_cast<float>(val);\n\t\tif (bCtrl->GetValue().ToDouble(&val)) colorED->colorData.b = static_cast<float>(val);\n\t\tif (aCtrl->GetValue().ToDouble(&val)) colorED->colorData.a = static_cast<float>(val);\n\t\tos->SetPendingChanges();\n\t}\n}\n\nvoid ShapeProperties::ShowListEditDialog(int extraDataIndex) {\n\tauto extraData = nif->GetHeader().GetBlock<NiExtraData>(extraDataIndex);\n\tif (!extraData)\n\t\treturn;\n\n\tbool isIntegers = extraData->HasType<NiIntegersExtraData>();\n\tbool isStrings = extraData->HasType<NiStringsExtraData>();\n\tbool isFloats = extraData->HasType<NiFloatsExtraData>();\n\n\twxString title;\n\tif (isIntegers) title = _(\"Edit Integers Extra Data\");\n\telse if (isStrings) title = _(\"Edit Strings Extra Data\");\n\telse if (isFloats) title = _(\"Edit Floats Extra Data\");\n\telse return;\n\n\twxDialog dlg(this, wxID_ANY, title, wxDefaultPosition, wxSize(450, 400), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);\n\tauto* sizer = new wxBoxSizer(wxVERTICAL);\n\n\tauto* grid = new wxGrid(&dlg, wxID_ANY);\n\tgrid->CreateGrid(0, 1);\n\tgrid->EnableEditing(true);\n\tgrid->SetColLabelValue(0, _(\"Value\"));\n\tgrid->SetColSize(0, 350);\n\tgrid->SetColLabelSize(25);\n\tgrid->SetRowLabelSize(50);\n\tgrid->EnableDragRowSize(false);\n\tgrid->EnableDragColSize(true);\n\n\t// Populate\n\tif (isIntegers) {\n\t\tauto intsED = static_cast<NiIntegersExtraData*>(extraData);\n\t\tfor (size_t i = 0; i < intsED->integersData.size(); i++) {\n\t\t\tgrid->AppendRows(1);\n\t\t\tgrid->SetCellValue(static_cast<int>(i), 0, wxString::Format(\"%u\", intsED->integersData[i]));\n\t\t}\n\t}\n\telse if (isStrings) {\n\t\tauto strsED = static_cast<NiStringsExtraData*>(extraData);\n\t\tfor (size_t i = 0; i < strsED->stringsData.size(); i++) {\n\t\t\tgrid->AppendRows(1);\n\t\t\tgrid->SetCellValue(static_cast<int>(i), 0, strsED->stringsData[i].get());\n\t\t}\n\t}\n\telse if (isFloats) {\n\t\tauto floatsED = static_cast<NiFloatsExtraData*>(extraData);\n\t\tfor (size_t i = 0; i < floatsED->floatsData.size(); i++) {\n\t\t\tgrid->AppendRows(1);\n\t\t\tgrid->SetCellValue(static_cast<int>(i), 0, wxString::Format(\"%.6f\", floatsED->floatsData[i]));\n\t\t}\n\t}\n\n\tsizer->Add(grid, 1, wxEXPAND | wxALL, 10);\n\n\t// Button bar for adding/removing rows\n\tauto* btnSizer = new wxBoxSizer(wxHORIZONTAL);\n\tauto* addRowBtn = new wxButton(&dlg, wxID_ANY, _(\"Add Row\"));\n\tauto* removeRowBtn = new wxButton(&dlg, wxID_ANY, _(\"Remove Row\"));\n\tbtnSizer->Add(addRowBtn, 0, wxRIGHT, 5);\n\tbtnSizer->Add(removeRowBtn, 0);\n\tsizer->Add(btnSizer, 0, wxLEFT | wxRIGHT | wxBOTTOM, 10);\n\n\taddRowBtn->Bind(wxEVT_BUTTON, [grid](wxCommandEvent&) {\n\t\tgrid->AppendRows(1);\n\t});\n\n\tremoveRowBtn->Bind(wxEVT_BUTTON, [grid](wxCommandEvent&) {\n\t\twxArrayInt selectedRows = grid->GetSelectedRows();\n\t\tif (selectedRows.IsEmpty() && grid->GetNumberRows() > 0) {\n\t\t\tgrid->DeleteRows(grid->GetNumberRows() - 1, 1);\n\t\t}\n\t\telse {\n\t\t\tselectedRows.Sort([](int* a, int* b) { return *b - *a; });\n\t\t\tfor (int row : selectedRows)\n\t\t\t\tgrid->DeleteRows(row, 1);\n\t\t}\n\t});\n\n\tsizer->Add(dlg.CreateStdDialogButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);\n\tdlg.SetSizer(sizer);\n\n\t// Ensure in-place editor is closed before the dialog is dismissed\n\tdlg.Bind(wxEVT_CLOSE_WINDOW, [grid](wxCloseEvent& evt) {\n\t\tgrid->SaveEditControlValue();\n\t\tevt.Skip();\n\t});\n\n\tif (dlg.ShowModal() == wxID_OK) {\n\n\t\tif (isIntegers) {\n\t\t\tauto intsED = static_cast<NiIntegersExtraData*>(extraData);\n\t\t\tintsED->integersData.clear();\n\t\t\tfor (int i = 0; i < grid->GetNumberRows(); i++) {\n\t\t\t\tunsigned long val = 0;\n\t\t\t\tgrid->GetCellValue(i, 0).ToULong(&val);\n\t\t\t\tuint32_t uval = static_cast<uint32_t>(val);\n\t\t\t\tintsED->integersData.push_back(uval);\n\t\t\t}\n\t\t}\n\t\telse if (isStrings) {\n\t\t\tauto strsED = static_cast<NiStringsExtraData*>(extraData);\n\t\t\tstrsED->stringsData.clear();\n\t\t\tfor (int i = 0; i < grid->GetNumberRows(); i++) {\n\t\t\t\tNiString s;\n\t\t\t\ts.get() = grid->GetCellValue(i, 0).ToStdString();\n\t\t\t\tstrsED->stringsData.push_back(s);\n\t\t\t}\n\t\t}\n\t\telse if (isFloats) {\n\t\t\tauto floatsED = static_cast<NiFloatsExtraData*>(extraData);\n\t\t\tfloatsED->floatsData.clear();\n\t\t\tfor (int i = 0; i < grid->GetNumberRows(); i++) {\n\t\t\t\tdouble val = 0.0;\n\t\t\t\tgrid->GetCellValue(i, 0).ToDouble(&val);\n\t\t\t\tfloat fval = static_cast<float>(val);\n\t\t\t\tfloatsED->floatsData.push_back(fval);\n\t\t\t}\n\t\t}\n\n\t\tos->SetPendingChanges();\n\t}\n}\n\nvoid ShapeProperties::GetCoordTrans() {\n\tpgCoordinates->Enable(shapes.size() == 1);\n\n\tNiShape* shape = shapes[0];\n\tVector3 rotationVec;\n\n\toldTransform = os->project->GetWorkAnim()->GetTransformShapeToGlobal(shape);\n\tnewTransform = oldTransform;\n\trotationVec = RotMatToVec(newTransform.rotation);\n\n\ttextScale->ChangeValue(wxString::Format(\"%.10f\", newTransform.scale));\n\ttextX->ChangeValue(wxString::Format(\"%.10f\", newTransform.translation.x));\n\ttextY->ChangeValue(wxString::Format(\"%.10f\", newTransform.translation.y));\n\ttextZ->ChangeValue(wxString::Format(\"%.10f\", newTransform.translation.z));\n\ttextRX->ChangeValue(wxString::Format(\"%.10f\", rotationVec.x));\n\ttextRY->ChangeValue(wxString::Format(\"%.10f\", rotationVec.y));\n\ttextRZ->ChangeValue(wxString::Format(\"%.10f\", rotationVec.z));\n\n\tcbTransformGeo->Disable();\n}\n\nvoid ShapeProperties::OnTransChanged(wxCommandEvent&) {\n\tif (!textScale || !textX || !textY || !textZ || !textRX || !textRY || !textRZ)\n\t\treturn;\n\n\tdouble scale, x, y, z, rx, ry, rz;\n\tif (!textScale->GetValue().ToDouble(&scale))\n\t\treturn;\n\tif (scale <= 0)\n\t\treturn;\n\tif (!textX->GetValue().ToDouble(&x))\n\t\treturn;\n\tif (!textY->GetValue().ToDouble(&y))\n\t\treturn;\n\tif (!textZ->GetValue().ToDouble(&z))\n\t\treturn;\n\tif (!textRX->GetValue().ToDouble(&rx))\n\t\treturn;\n\tif (!textRY->GetValue().ToDouble(&ry))\n\t\treturn;\n\tif (!textRZ->GetValue().ToDouble(&rz))\n\t\treturn;\n\n\tnewTransform.scale = scale;\n\tnewTransform.translation.x = x;\n\tnewTransform.translation.y = y;\n\tnewTransform.translation.z = z;\n\tnewTransform.rotation = RotVecToMat(Vector3(rx, ry, rz));\n\tcbTransformGeo->Enable(!newTransform.IsNearlyEqualTo(oldTransform));\n}\n\nvoid ShapeProperties::RefreshMesh() {\n\tfor (auto& shape : shapes) {\n\t\tos->project->SetTextures(shape);\n\t\tos->MeshFromProj(shape, true);\n\t}\n\tos->UpdateActiveShape();\n}\n\nvoid ShapeProperties::OnApply(wxCommandEvent& WXUNUSED(event)) {\n\tApplyChanges();\n\tRefreshMesh();\n\tEndModal(wxID_OK);\n}\n\nvoid ShapeProperties::ApplyChanges() {\n\tbool multipleShapes = shapes.size() > 1;\n\tauto& version = nif->GetHeader().GetVersion();\n\n\twxColour color = specularColor->GetColour();\n\tVector3 specColor(color.Red(), color.Green(), color.Blue());\n\tspecColor /= 255.0f;\n\tfloat specStrength = atof(specularStrength->GetValue().c_str());\n\tfloat specPower = atof(specularPower->GetValue().c_str());\n\n\tcolor = emissiveColor->GetColour();\n\tColor4 emisColor(color.Red(), color.Green(), color.Blue(), color.Alpha());\n\temisColor /= 255.0f;\n\tfloat emisMultiple = atof(emissiveMultiple->GetValue().c_str());\n\tfloat alphaValue = atof(alpha->GetValue().c_str());\n\n\tif (!multipleShapes) {\n\t\tNiShape* shape = shapes[0];\n\t\tNiShader* shader = nif->GetShader(shape);\n\t\tif (shader) {\n\t\t\tstd::string name = shaderName->GetValue().ToStdString();\n\t\t\tuint32_t type = shaderType->GetSelection();\n\t\t\tuint32_t oldType = shader->GetShaderType();\n\n\t\t\tshader->name.get() = name;\n\n\t\t\tbool hadVertexColors = shader->HasVertexColors();\n\t\t\tshader->SetVertexColors(vertexColors->IsChecked());\n\n\t\t\tif (vertexColors->IsChecked() && !hadVertexColors)\n\t\t\t\tshape->SetVertexColors(true);\n\n\t\t\t// FO3/NV: Double sided is controlled by NiStencilProperty, not shader flags\n\t\t\tif (isFO3NV) {\n\t\t\t\tbool wantDoubleSided = doubleSided->IsChecked();\n\t\t\t\tNiStencilProperty* stencil = nif->GetStencilProperty(shape);\n\t\t\t\tif (wantDoubleSided) {\n\t\t\t\t\tif (!stencil) {\n\t\t\t\t\t\tauto stencilProp = std::make_unique<NiStencilProperty>();\n\t\t\t\t\t\tint stencilRef = nif->GetHeader().AddBlock(std::move(stencilProp));\n\t\t\t\t\t\tshape->propertyRefs.AddBlockRef(stencilRef);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tstencil->flags = (stencil->flags & ~DRAW_MASK) | (DRAW_BOTH << DRAW_POS);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (stencil) {\n\t\t\t\t\tstencil->flags = (stencil->flags & ~DRAW_MASK) | (DRAW_CCW << DRAW_POS);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tshader->SetDoubleSided(doubleSided->IsChecked());\n\t\t\t}\n\n\t\t\tif (shader->HasType<BSEffectShaderProperty>()) {\n\t\t\t\tshader->SetEmissiveColor(emisColor);\n\t\t\t\tshader->SetEmissiveMultiple(emisMultiple);\n\t\t\t}\n\t\t\telse if (shader->HasType<BSLightingShaderProperty>()) {\n\t\t\t\tauto bslsp = dynamic_cast<BSLightingShaderProperty*>(shader);\n\t\t\t\tif (bslsp) {\n\t\t\t\t\tbslsp->SetShaderType(type);\n\n\t\t\t\t\tif (oldType != BSLightingShaderPropertyShaderType::BSLSP_ENVMAP && type == BSLightingShaderPropertyShaderType::BSLSP_ENVMAP) {\n\t\t\t\t\t\t// Shader type was changed to environment mapping, enable flag as well\n\t\t\t\t\t\tbslsp->SetEnvironmentMapping(true);\n\t\t\t\t\t}\n\t\t\t\t\telse if (oldType == BSLightingShaderPropertyShaderType::BSLSP_ENVMAP && type != BSLightingShaderPropertyShaderType::BSLSP_ENVMAP) {\n\t\t\t\t\t\t// Shader type was changed away from environment mapping, disable flag as well\n\t\t\t\t\t\tbslsp->SetEnvironmentMapping(false);\n\t\t\t\t\t}\n\n\t\t\t\t\tbslsp->SetSpecularColor(specColor);\n\t\t\t\t\tbslsp->SetSpecularStrength(specStrength);\n\t\t\t\t\tbslsp->SetGlossiness(specPower);\n\n\t\t\t\t\tbslsp->SetEmissiveColor(emisColor);\n\t\t\t\t\tbslsp->SetEmissiveMultiple(emisMultiple);\n\n\t\t\t\t\tbslsp->SetAlpha(alphaValue);\n\n\t\t\t\t\t// Advanced properties\n\t\t\t\t\tauto* bssp = dynamic_cast<BSShaderProperty*>(shader);\n\t\t\t\t\tif (bssp) {\n\t\t\t\t\t\tbssp->uvOffset.u = atof(uvOffsetU->GetValue().c_str());\n\t\t\t\t\t\tbssp->uvOffset.v = atof(uvOffsetV->GetValue().c_str());\n\t\t\t\t\t\tbssp->uvScale.u = atof(uvScaleU->GetValue().c_str());\n\t\t\t\t\t\tbssp->uvScale.v = atof(uvScaleV->GetValue().c_str());\n\t\t\t\t\t\tbssp->environmentMapScale = atof(environmentMapScale->GetValue().c_str());\n\t\t\t\t\t}\n\n\t\t\t\t\tbslsp->textureClampMode = static_cast<TexClampMode>(textureClampMode->GetSelection());\n\t\t\t\t\tbslsp->refractionStrength = atof(refractionStrength->GetValue().c_str());\n\t\t\t\t\tbslsp->softlighting = atof(lightingEffect1->GetValue().c_str());\n\t\t\t\t\tbslsp->rimlightPower = atof(lightingEffect2->GetValue().c_str());\n\n\t\t\t\t\twxColour stc = skinTintColor->GetColour();\n\t\t\t\t\tbslsp->skinTintColor = Vector3(stc.Red() / 255.0f, stc.Green() / 255.0f, stc.Blue() / 255.0f);\n\n\t\t\t\t\twxColour htc = hairTintColor->GetColour();\n\t\t\t\t\tbslsp->hairTintColor = Vector3(htc.Red() / 255.0f, htc.Green() / 255.0f, htc.Blue() / 255.0f);\n\n\t\t\t\t\tbslsp->maxPasses = atof(parallaxMaxPasses->GetValue().c_str());\n\t\t\t\t\tbslsp->scale = atof(parallaxScale->GetValue().c_str());\n\t\t\t\t\tbslsp->parallaxInnerLayerThickness = atof(parallaxInnerLayerThickness->GetValue().c_str());\n\t\t\t\t\tbslsp->parallaxRefractionScale = atof(parallaxRefractionScale->GetValue().c_str());\n\t\t\t\t\tbslsp->parallaxInnerLayerTextureScale.u = atof(parallaxInnerLayerTexScaleU->GetValue().c_str());\n\t\t\t\t\tbslsp->parallaxInnerLayerTextureScale.v = atof(parallaxInnerLayerTexScaleV->GetValue().c_str());\n\t\t\t\t\tbslsp->parallaxEnvmapStrength = atof(parallaxEnvmapStrength->GetValue().c_str());\n\n\t\t\t\t\tbslsp->sparkleParameters.r = atof(sparkleParamsR->GetValue().c_str());\n\t\t\t\t\tbslsp->sparkleParameters.g = atof(sparkleParamsG->GetValue().c_str());\n\t\t\t\t\tbslsp->sparkleParameters.b = atof(sparkleParamsB->GetValue().c_str());\n\t\t\t\t\tbslsp->sparkleParameters.a = atof(sparkleParamsA->GetValue().c_str());\n\n\t\t\t\t\tbslsp->eyeCubemapScale = atof(eyeCubemapScale->GetValue().c_str());\n\t\t\t\t\tbslsp->eyeLeftReflectionCenter.x = atof(eyeLeftReflectX->GetValue().c_str());\n\t\t\t\t\tbslsp->eyeLeftReflectionCenter.y = atof(eyeLeftReflectY->GetValue().c_str());\n\t\t\t\t\tbslsp->eyeLeftReflectionCenter.z = atof(eyeLeftReflectZ->GetValue().c_str());\n\t\t\t\t\tbslsp->eyeRightReflectionCenter.x = atof(eyeRightReflectX->GetValue().c_str());\n\t\t\t\t\tbslsp->eyeRightReflectionCenter.y = atof(eyeRightReflectY->GetValue().c_str());\n\t\t\t\t\tbslsp->eyeRightReflectionCenter.z = atof(eyeRightReflectZ->GetValue().c_str());\n\n\t\t\t\t\tif (version.Stream() >= 130) {\n\t\t\t\t\t\tbslsp->SetWetMaterialName(wetMaterialPath->GetValue().ToStdString());\n\t\t\t\t\t\tbslsp->subsurfaceRolloff = atof(subsurfaceRolloff->GetValue().c_str());\n\t\t\t\t\t\tbslsp->backlightPower = atof(backlightPower->GetValue().c_str());\n\t\t\t\t\t\tbslsp->grayscaleToPaletteScale = atof(grayscaleToPaletteScale->GetValue().c_str());\n\t\t\t\t\t\tbslsp->fresnelPower = atof(fresnelPower->GetValue().c_str());\n\t\t\t\t\t\tbslsp->wetnessSpecScale = atof(wetnessSpecScale->GetValue().c_str());\n\t\t\t\t\t\tbslsp->wetnessSpecPower = atof(wetnessSpecPower->GetValue().c_str());\n\t\t\t\t\t\tbslsp->wetnessMinVar = atof(wetnessMinVar->GetValue().c_str());\n\t\t\t\t\t\tbslsp->wetnessEnvmapScale = atof(wetnessEnvMapScale->GetValue().c_str());\n\t\t\t\t\t\tbslsp->wetnessFresnelPower = atof(wetnessFresnelPower->GetValue().c_str());\n\t\t\t\t\t\tbslsp->wetnessMetalness = atof(wetnessMetalness->GetValue().c_str());\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse if (shader->HasType<BSShaderPPLightingProperty>()) {\n\t\t\t\tswitch (type) {\n\t\t\t\t\tcase 0: type = BSShaderType::SHADER_TALL_GRASS; break;\n\t\t\t\t\tcase 1: type = BSShaderType::SHADER_DEFAULT; break;\n\t\t\t\t\tcase 2: type = BSShaderType::SHADER_SKY; break;\n\t\t\t\t\tcase 3: type = BSShaderType::SHADER_SKIN; break;\n\t\t\t\t\tcase 4: type = BSShaderType::SHADER_WATER; break;\n\t\t\t\t\tcase 5: type = BSShaderType::SHADER_LIGHTING30; break;\n\t\t\t\t\tcase 6: type = BSShaderType::SHADER_TILE; break;\n\t\t\t\t\tcase 7: type = BSShaderType::SHADER_NOLIGHTING; break;\n\t\t\t\t}\n\n\t\t\t\tshader->SetShaderType(type);\n\n\t\t\t\tauto bspplp = dynamic_cast<BSShaderPPLightingProperty*>(shader);\n\t\t\t\tif (bspplp) {\n\t\t\t\t\tauto* bssp = dynamic_cast<BSShaderProperty*>(shader);\n\t\t\t\t\tif (bssp) {\n\t\t\t\t\t\tbssp->environmentMapScale = atof(environmentMapScale->GetValue().c_str());\n\t\t\t\t\t\tbssp->shadingFlags = shadingType->GetSelection() == 1 ? SHADING_SMOOTH : SHADING_HARD;\n\t\t\t\t\t}\n\n\t\t\t\t\tauto* bsslp = dynamic_cast<BSShaderLightingProperty*>(shader);\n\t\t\t\t\tif (bsslp)\n\t\t\t\t\t\tbsslp->textureClampMode = static_cast<TexClampMode>(textureClampMode->GetSelection());\n\n\t\t\t\t\tbspplp->refractionStrength = atof(refractionStrength->GetValue().c_str());\n\t\t\t\t\tbspplp->refractionFirePeriod = atoi(refractionFirePeriod->GetValue().c_str());\n\t\t\t\t\tbspplp->parallaxMaxPasses = atof(parallaxMaxPasses->GetValue().c_str());\n\t\t\t\t\tbspplp->parallaxScale = atof(parallaxScale->GetValue().c_str());\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Save shader flags\n\t\t\tauto* bssp = dynamic_cast<BSShaderProperty*>(shader);\n\t\t\tif (bssp) {\n\t\t\t\tuint32_t sf1 = 0;\n\t\t\t\tuint32_t sf2 = 0;\n\t\t\t\tfor (unsigned int i = 0; i < shaderFlags1List->GetCount(); i++) {\n\t\t\t\t\tif (shaderFlags1List->IsChecked(i))\n\t\t\t\t\t\tsf1 |= (static_cast<uint32_t>(1) << i);\n\t\t\t\t}\n\t\t\t\tfor (unsigned int i = 0; i < shaderFlags2List->GetCount(); i++) {\n\t\t\t\t\tif (shaderFlags2List->IsChecked(i))\n\t\t\t\t\t\tsf2 |= (static_cast<uint32_t>(1) << i);\n\t\t\t\t}\n\t\t\t\tbssp->shaderFlags1 = sf1;\n\t\t\t\tbssp->shaderFlags2 = sf2;\n\t\t\t}\n\t\t}\n\n\t\tNiMaterialProperty* material = nif->GetMaterialProperty(shape);\n\t\tif (material) {\n\t\t\tmaterial->SetSpecularColor(specColor);\n\t\t\tmaterial->SetGlossiness(specPower);\n\n\t\t\tmaterial->SetEmissiveColor(emisColor);\n\t\t\tmaterial->SetEmissiveMultiple(emisMultiple);\n\t\t\tmaterial->SetAlpha(alphaValue);\n\t\t}\n\n\t\tNiAlphaProperty* alphaProp = nif->GetAlphaProperty(shape);\n\t\tif (alphaProp) {\n\t\t\talphaProp->threshold = atoi(alphaThreshold->GetValue().c_str());\n\n\t\t\t// Rebuild flags from all controls\n\t\t\tuint16_t flags = 0;\n\n\t\t\tif (alphaBlend->IsChecked())\n\t\t\t\tflags |= 1;\n\n\t\t\tint srcBlend = alphaSrcBlend->GetSelection();\n\t\t\tif (srcBlend >= 0)\n\t\t\t\tflags |= (static_cast<uint16_t>(srcBlend) & 0xF) << 1;\n\n\t\t\tint destBlend = alphaDestBlend->GetSelection();\n\t\t\tif (destBlend >= 0)\n\t\t\t\tflags |= (static_cast<uint16_t>(destBlend) & 0xF) << 5;\n\n\t\t\tif (alphaTest->IsChecked())\n\t\t\t\tflags |= 1 << 9;\n\n\t\t\tint testFunc = alphaTestFunc->GetSelection();\n\t\t\tif (testFunc >= 0)\n\t\t\t\tflags |= (static_cast<uint16_t>(testFunc) & 0x7) << 10;\n\n\t\t\tif (alphaNoSorter->IsChecked())\n\t\t\t\tflags |= 1 << 13;\n\n\t\t\talphaProp->flags = flags;\n\n\t\t\tif (shader) {\n\t\t\t\t// FO3/NV: Vertex Alpha only works with BSShaderNoLightingProperty\n\t\t\t\tbool canSetVertexAlpha = !isFO3NV || isFO3NVNoLighting;\n\t\t\t\tif (canSetVertexAlpha) {\n\t\t\t\t\tbool hadVertexAlpha = shader->HasVertexAlpha();\n\t\t\t\t\tshader->SetVertexAlpha(vertexAlpha->IsChecked());\n\n\t\t\t\t\tif (vertexAlpha->IsChecked() && !hadVertexAlpha) {\n\t\t\t\t\t\tshader->SetVertexColors(true);\n\t\t\t\t\t\tshape->SetVertexColors(true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (size_t i = 0; i < extraDataIndices.size(); i++) {\n\t\t\twxTextCtrl* extraDataName = dynamic_cast<wxTextCtrl*>(FindWindowById(3000 + i, this));\n\t\t\tif (!extraDataName)\n\t\t\t\tcontinue;\n\n\t\t\tauto extraData = nif->GetHeader().GetBlock<NiExtraData>(extraDataIndices[i]);\n\t\t\tif (extraData) {\n\t\t\t\textraData->name.get() = extraDataName->GetValue().ToStdString();\n\n\t\t\t\tif (extraData->HasType<NiStringExtraData>()) {\n\t\t\t\t\tauto stringExtraData = static_cast<NiStringExtraData*>(extraData);\n\t\t\t\t\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindowById(4000 + i, this));\n\t\t\t\t\tif (valCtrl)\n\t\t\t\t\t\tstringExtraData->stringData.get() = valCtrl->GetValue().ToStdString();\n\t\t\t\t}\n\t\t\t\telse if (extraData->HasType<NiIntegerExtraData>()) {\n\t\t\t\t\tauto intExtraData = static_cast<NiIntegerExtraData*>(extraData);\n\t\t\t\t\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindowById(4000 + i, this));\n\t\t\t\t\tif (valCtrl) {\n\t\t\t\t\t\tunsigned long val = 0;\n\t\t\t\t\t\tif (valCtrl->GetValue().ToULong(&val))\n\t\t\t\t\t\t\tintExtraData->integerData = val;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (extraData->HasType<NiFloatExtraData>()) {\n\t\t\t\t\tauto floatExtraData = static_cast<NiFloatExtraData*>(extraData);\n\t\t\t\t\tauto* valCtrl = dynamic_cast<wxTextCtrl*>(FindWindowById(4000 + i, this));\n\t\t\t\t\tif (valCtrl) {\n\t\t\t\t\t\tdouble val = 0.0;\n\t\t\t\t\t\tif (valCtrl->GetValue().ToDouble(&val))\n\t\t\t\t\t\t\tfloatExtraData->floatData = (float)val;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse if (extraData->HasType<NiBooleanExtraData>()) {\n\t\t\t\t\tauto boolExtraData = static_cast<NiBooleanExtraData*>(extraData);\n\t\t\t\t\tauto* valCtrl = dynamic_cast<wxCheckBox*>(FindWindowById(4000 + i, this));\n\t\t\t\t\tif (valCtrl)\n\t\t\t\t\t\tboolExtraData->booleanData = valCtrl->GetValue();\n\t\t\t\t}\n\t\t\t\telse if (extraData->HasType<BSDistantObjectLargeRefExtraData>()) {\n\t\t\t\t\tauto distExtraData = static_cast<BSDistantObjectLargeRefExtraData*>(extraData);\n\t\t\t\t\tauto* valCtrl = dynamic_cast<wxCheckBox*>(FindWindowById(4000 + i, this));\n\t\t\t\t\tif (valCtrl)\n\t\t\t\t\t\tdistExtraData->largeRef = valCtrl->GetValue();\n\t\t\t\t}\n\t\t\t\t// NiVectorExtraData, NiColorExtraData, NiIntegersExtraData,\n\t\t\t\t// NiStringsExtraData, NiFloatsExtraData are saved directly\n\t\t\t\t// from their edit dialogs, so no action needed here.\n\t\t\t}\n\t\t}\n\t}\n\n\tfor (auto& shape : shapes) {\n\t\tauto bsTriShape = dynamic_cast<BSTriShape*>(shape);\n\t\tif (bsTriShape) {\n\t\t\twxCheckBoxState fullPrecisionState = fullPrecision->Get3StateValue();\n\t\t\tif (fullPrecision->IsEnabled() && fullPrecisionState != wxCheckBoxState::wxCHK_UNDETERMINED) {\n\t\t\t\tif (nif->GetHeader().GetVersion().Stream() != 100)\n\t\t\t\t\tbsTriShape->SetFullPrecision(fullPrecisionState == wxCheckBoxState::wxCHK_CHECKED);\n\t\t\t}\n\n\t\t\twxCheckBoxState subIndexState = subIndex->Get3StateValue();\n\t\t\tif (subIndex->IsEnabled() && subIndexState != wxCheckBoxState::wxCHK_UNDETERMINED) {\n\t\t\t\tbool hasSubIndex = shape->HasType<BSSubIndexTriShape>();\n\n\t\t\t\tif (version.Stream() >= 130) {\n\t\t\t\t\tif (subIndexState == wxCheckBoxState::wxCHK_CHECKED && !hasSubIndex) {\n\t\t\t\t\t\tauto bsSITS = std::make_unique<BSSubIndexTriShape>();\n\t\t\t\t\t\t*static_cast<BSTriShape*>(bsSITS.get()) = *bsTriShape;\n\t\t\t\t\t\tbsSITS->SetDefaultSegments();\n\t\t\t\t\t\tbsSITS->name.get() = bsTriShape->name.get();\n\n\t\t\t\t\t\tshape = bsSITS.get();\n\t\t\t\t\t\tos->UpdateShapeReference(bsTriShape, shape);\n\t\t\t\t\t\tnif->GetHeader().ReplaceBlock(nif->GetBlockID(bsTriShape), std::move(bsSITS));\n\t\t\t\t\t}\n\t\t\t\t\telse if (subIndexState == wxCheckBoxState::wxCHK_UNCHECKED && hasSubIndex) {\n\t\t\t\t\t\tauto bsTS = std::make_unique<BSTriShape>(*bsTriShape);\n\t\t\t\t\t\tbsTS->name.get() = bsTriShape->name.get();\n\n\t\t\t\t\t\tshape = bsTS.get();\n\t\t\t\t\t\tos->UpdateShapeReference(bsTriShape, shape);\n\t\t\t\t\t\tnif->GetHeader().ReplaceBlock(nif->GetBlockID(bsTriShape), std::move(bsTS));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\twxCheckBoxState dynamicState = dynamic->Get3StateValue();\n\t\t\tif (dynamic->IsEnabled() && dynamicState != wxCheckBoxState::wxCHK_UNDETERMINED) {\n\t\t\t\tbool hasDynamic = shape->HasType<BSDynamicTriShape>();\n\n\t\t\t\tif (version.Stream() == 100) {\n\t\t\t\t\tif (dynamicState == wxCheckBoxState::wxCHK_CHECKED && !hasDynamic) {\n\t\t\t\t\t\tauto bsDTS = std::make_unique<BSDynamicTriShape>();\n\t\t\t\t\t\t*static_cast<BSTriShape*>(bsDTS.get()) = *bsTriShape;\n\t\t\t\t\t\tbsDTS->name.get() = bsTriShape->name.get();\n\n\t\t\t\t\t\tbsDTS->vertexDesc.RemoveFlag(VF_VERTEX);\n\t\t\t\t\t\tbsDTS->vertexDesc.SetFlag(VF_FULLPREC);\n\n\t\t\t\t\t\tbsDTS->CalcDynamicData();\n\t\t\t\t\t\tbsDTS->CalcDataSizes(nif->GetHeader().GetVersion());\n\n\t\t\t\t\t\tshape = bsDTS.get();\n\t\t\t\t\t\tos->UpdateShapeReference(bsTriShape, shape);\n\t\t\t\t\t\tnif->GetHeader().ReplaceBlock(nif->GetBlockID(bsTriShape), std::move(bsDTS));\n\t\t\t\t\t}\n\t\t\t\t\telse if (dynamicState == wxCheckBoxState::wxCHK_UNCHECKED && hasDynamic) {\n\t\t\t\t\t\tauto bsTS = std::make_unique<BSTriShape>(*bsTriShape);\n\t\t\t\t\t\tbsTS->name.get() = bsTriShape->name.get();\n\n\t\t\t\t\t\tbsTS->vertexDesc.SetFlag(VF_VERTEX);\n\t\t\t\t\t\tbsTS->vertexDesc.RemoveFlag(VF_FULLPREC);\n\n\t\t\t\t\t\tbsTS->CalcDataSizes(nif->GetHeader().GetVersion());\n\n\t\t\t\t\t\tshape = bsTS.get();\n\t\t\t\t\t\tos->UpdateShapeReference(bsTriShape, shape);\n\t\t\t\t\t\tnif->GetHeader().ReplaceBlock(nif->GetBlockID(bsTriShape), std::move(bsTS));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\twxCheckBoxState skinnedState = skinned->Get3StateValue();\n\t\tif (skinned->IsEnabled() && skinnedState != wxCheckBoxState::wxCHK_UNDETERMINED) {\n\t\t\tif (skinnedState == wxCheckBoxState::wxCHK_CHECKED) {\n\t\t\t\tos->project->CreateSkinning(shape);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tos->project->RemoveSkinning(shape);\n\t\t\t\tos->UpdateAnimationGUI();\n\t\t\t}\n\t\t}\n\n\t\tif (!multipleShapes) {\n\t\t\tif (!newTransform.IsNearlyEqualTo(oldTransform)) {\n\t\t\t\tif (cbTransformGeo->IsChecked())\n\t\t\t\t\tos->project->ApplyTransformToShapeGeometry(shape, newTransform.InverseTransform().ComposeTransforms(oldTransform));\n\n\t\t\t\tos->project->GetWorkAnim()->SetTransformShapeToGlobal(shape, newTransform);\n\t\t\t}\n\t\t}\n\t}\n\n\tos->SetPendingChanges();\n}\n"
  },
  {
    "path": "src/program/ShapeProperties.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"OutfitStudio.h\"\n#include \"ShaderFlagDefs.h\"\n#include <wx/checklst.h>\n#include <wx/clrpicker.h>\n#include <wx/collpane.h>\n#include <wx/notebook.h>\n\nclass ShapeProperties : public wxDialog {\npublic:\n\tShapeProperties(wxWindow*, nifly::NifFile*, std::vector<nifly::NiShape*>);\n\t~ShapeProperties();\n\nprivate:\n\twxNotebook* nbProperties = nullptr;\n\n\twxPanel* pgShader = nullptr;\n\twxStaticText* lbShaderName = nullptr;\n\twxTextCtrl* shaderName = nullptr;\n\twxButton* btnMaterialChooser = nullptr;\n\twxChoice* shaderType = nullptr;\n\twxStaticText* lbShadingType = nullptr;\n\twxChoice* shadingType = nullptr;\n\twxColourPickerCtrl* specularColor = nullptr;\n\twxTextCtrl* specularStrength = nullptr;\n\twxTextCtrl* specularPower = nullptr;\n\twxColourPickerCtrl* emissiveColor = nullptr;\n\twxTextCtrl* emissiveMultiple = nullptr;\n\twxTextCtrl* alpha = nullptr;\n\twxCheckBox* vertexColors = nullptr;\n\twxCheckBox* doubleSided = nullptr;\n\twxButton* btnAddShader = nullptr;\n\twxButton* btnRemoveShader = nullptr;\n\twxButton* btnSetTextures = nullptr;\n\n\t// Shader flags\n\twxCollapsiblePane* shaderFlagsPane = nullptr;\n\twxCheckListBox* shaderFlags1List = nullptr;\n\twxCheckListBox* shaderFlags2List = nullptr;\n\n\t// Advanced shader properties\n\twxCollapsiblePane* advancedShaderPane = nullptr;\n\twxTextCtrl* uvOffsetU = nullptr;\n\twxTextCtrl* uvOffsetV = nullptr;\n\twxTextCtrl* uvScaleU = nullptr;\n\twxTextCtrl* uvScaleV = nullptr;\n\twxChoice* textureClampMode = nullptr;\n\twxTextCtrl* environmentMapScale = nullptr;\n\twxTextCtrl* refractionStrength = nullptr;\n\twxTextCtrl* refractionFirePeriod = nullptr;\n\twxTextCtrl* parallaxMaxPasses = nullptr;\n\twxTextCtrl* parallaxScale = nullptr;\n\twxTextCtrl* lightingEffect1 = nullptr;\n\twxTextCtrl* lightingEffect2 = nullptr;\n\twxColourPickerCtrl* skinTintColor = nullptr;\n\twxColourPickerCtrl* hairTintColor = nullptr;\n\twxTextCtrl* parallaxInnerLayerThickness = nullptr;\n\twxTextCtrl* parallaxRefractionScale = nullptr;\n\twxTextCtrl* parallaxInnerLayerTexScaleU = nullptr;\n\twxTextCtrl* parallaxInnerLayerTexScaleV = nullptr;\n\twxTextCtrl* parallaxEnvmapStrength = nullptr;\n\twxTextCtrl* sparkleParamsR = nullptr;\n\twxTextCtrl* sparkleParamsG = nullptr;\n\twxTextCtrl* sparkleParamsB = nullptr;\n\twxTextCtrl* sparkleParamsA = nullptr;\n\twxTextCtrl* eyeCubemapScale = nullptr;\n\twxTextCtrl* eyeLeftReflectX = nullptr;\n\twxTextCtrl* eyeLeftReflectY = nullptr;\n\twxTextCtrl* eyeLeftReflectZ = nullptr;\n\twxTextCtrl* eyeRightReflectX = nullptr;\n\twxTextCtrl* eyeRightReflectY = nullptr;\n\twxTextCtrl* eyeRightReflectZ = nullptr;\n\twxTextCtrl* wetMaterialPath = nullptr;\n\twxTextCtrl* subsurfaceRolloff = nullptr;\n\twxTextCtrl* rimlightPower = nullptr;\n\twxTextCtrl* backlightPower = nullptr;\n\twxTextCtrl* grayscaleToPaletteScale = nullptr;\n\twxTextCtrl* fresnelPower = nullptr;\n\twxTextCtrl* wetnessSpecScale = nullptr;\n\twxTextCtrl* wetnessSpecPower = nullptr;\n\twxTextCtrl* wetnessMinVar = nullptr;\n\twxTextCtrl* wetnessEnvMapScale = nullptr;\n\twxTextCtrl* wetnessFresnelPower = nullptr;\n\twxTextCtrl* wetnessMetalness = nullptr;\n\n\twxCollapsiblePane* transparencyPane = nullptr;\n\twxTextCtrl* alphaThreshold = nullptr;\n\twxCheckBox* vertexAlpha = nullptr;\n\twxCheckBox* alphaTest = nullptr;\n\twxCheckBox* alphaBlend = nullptr;\n\twxChoice* alphaSrcBlend = nullptr;\n\twxChoice* alphaDestBlend = nullptr;\n\twxChoice* alphaTestFunc = nullptr;\n\twxCheckBox* alphaNoSorter = nullptr;\n\twxButton* btnAddTransparency = nullptr;\n\twxButton* btnRemoveTransparency = nullptr;\n\n\twxButton* btnCopyShaderFromShape = nullptr;\n\n\twxPanel* pgGeometry = nullptr;\n\twxCheckBox* fullPrecision = nullptr;\n\twxCheckBox* subIndex = nullptr;\n\twxCheckBox* skinned = nullptr;\n\twxCheckBox* dynamic = nullptr;\n\n\tstd::vector<int> extraDataIndices;\n\twxPanel* pgExtraData = nullptr;\n\twxFlexGridSizer* extraDataGrid = nullptr;\n\n\twxPanel* pgCoordinates = nullptr;\n\twxTextCtrl* textScale = nullptr;\n\twxTextCtrl* textX = nullptr;\n\twxTextCtrl* textY = nullptr;\n\twxTextCtrl* textZ = nullptr;\n\twxTextCtrl* textRX = nullptr;\n\twxTextCtrl* textRY = nullptr;\n\twxTextCtrl* textRZ = nullptr;\n\twxCheckBox* cbTransformGeo = nullptr;\n\tnifly::MatTransform oldTransform;\n\tnifly::MatTransform newTransform;\n\n\tOutfitStudioFrame* os = nullptr;\n\tnifly::NifFile* nif = nullptr;\n\tstd::vector<nifly::NiShape*> shapes;\n\n\t// Shader type classification for the first shape (set in GetShader)\n\tbool isFO3NV = false;\n\tbool isFO3NVNoLighting = false;\n\n\tbool confirmationAccepted = false;\n\n\tbool ShowConfirmationDialog();\n\n\tvoid GetShader();\n\tvoid GetShaderType();\n\tvoid GetShaderFlags();\n\tvoid GetAdvancedShaderProperties();\n\tvoid UpdateShaderTypeFields(uint32_t shaderTypeVal);\n\tvoid AddShader(nifly::NiShape* shape);\n\tvoid RemoveShader(nifly::NiShape* shape);\n\n\tvoid GetTransparency();\n\tvoid AddTransparency(nifly::NiShape* shape);\n\tvoid RemoveTransparency(nifly::NiShape* shape);\n\n\tvoid GetGeometry();\n\n\tvoid GetExtraData();\n\tvoid AddExtraData(nifly::NiShape* shape, nifly::NiExtraData* extraData, bool uiOnly = false);\n\twxWindow* CreateValueControl(int id, int typeSelection);\n\tvoid UpdateEditButtonLabel(int id);\n\tvoid ChangeExtraDataType(nifly::NiShape* shape, int index);\n\tvoid RemoveExtraData(int index);\n\tvoid OnEditExtraData(wxCommandEvent& event);\n\tvoid ShowVectorEditDialog(int extraDataIndex);\n\tvoid ShowColorEditDialog(int extraDataIndex);\n\tvoid ShowListEditDialog(int extraDataIndex);\n\n\tvoid GetCoordTrans();\n\tvoid OnTransChanged(wxCommandEvent&);\n\n\tvoid AssignDefaultTexture(nifly::NiShape* shape);\n\tvoid RefreshMesh();\n\tvoid ApplyChanges();\n\n\tvoid OnChooseMaterial(wxCommandEvent& event);\n\tvoid OnAddShader(wxCommandEvent& event);\n\tvoid OnRemoveShader(wxCommandEvent& event);\n\tvoid OnSetTextures(wxCommandEvent& event);\n\tvoid OnAddTransparency(wxCommandEvent& event);\n\tvoid OnRemoveTransparency(wxCommandEvent& event);\n\tvoid OnCopyShaderFromShape(wxCommandEvent& event);\n\tvoid OnAddExtraData(wxCommandEvent& event);\n\tvoid OnChangeExtraDataType(wxCommandEvent& event);\n\tvoid OnRemoveExtraData(wxCommandEvent& event);\n\tvoid OnApply(wxCommandEvent& event);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/program/SliderDataImportDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"SliderDataImportDialog.h\"\n\n#include \"OutfitProject.h\"\n#include \"../utils/ConfigurationManager.h\"\n#include \"../utils/ConfigDialogUtil.h\"\n\nextern ConfigurationManager Config;\n\nwxBEGIN_EVENT_TABLE(SliderDataImportDialog, wxDialog)\n\tEVT_BUTTON(wxID_OK, SliderDataImportDialog::OnImport)\nwxEND_EVENT_TABLE()\n\nSliderDataImportDialog::SliderDataImportDialog(wxWindow* parent, OutfitProject* project, ConfigurationManager& outfitStudioConfig)\n\t: project(project), outfitStudioConfig(outfitStudioConfig) {\n\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/SliderDataImport.xrc\");\n\txrc->LoadDialog(this, parent, \"dlgSliderDataImport\");\n\tConfigDialogUtil::LoadDialogCheckBox(outfitStudioConfig, *this, \"SliderDataImport\", \"chkImportMergeSliders\");\n\n\tshapesCheckListBox = XRCCTRL(*this, \"sliderShapesImportList\", wxCheckListBox);\n\tshapesCheckListBox->Bind(wxEVT_CHECKLISTBOX, &SliderDataImportDialog::OnShapeSelectionChanged, this);\n\n\tslidersCheckListBox = XRCCTRL(*this, \"sliderImportList\", wxCheckListBox);\n\tslidersCheckListBox->Bind(wxEVT_RIGHT_UP, &SliderDataImportDialog::OnSliderListContext, this);\n\n\tSetDoubleBuffered(true);\n\tCenterOnParent();\n}\n\nSliderDataImportDialog::~SliderDataImportDialog() {\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/SliderDataImport.xrc\");\n}\n\nint SliderDataImportDialog::ShowModal(const std::unordered_map<std::string, std::unordered_map<std::string, std::string>>& sliderData) {\n\n\tstd::unordered_set<std::string> addedSliders;\n\tfor (auto& shapeSliders : sliderData) {\n\t\tauto shapeName = project->TargetToShape(shapeSliders.first);\n\t\tshapesCheckListBox->Append(shapeName, new ShapeSliderData(shapeName, shapeSliders.first, shapeSliders.second));\n\n\t\tfor (auto& sliderName : shapeSliders.second) {\n\t\t\tif (addedSliders.find(sliderName.first) != addedSliders.end())\n\t\t\t\tcontinue;\n\n\t\t\tslidersCheckListBox->Append(sliderName.first);\n\t\t\taddedSliders.emplace(sliderName.first);\n\t\t}\n\t}\n\n\tfor (uint32_t i = 0; i < shapesCheckListBox->GetCount(); i++)\n\t\tshapesCheckListBox->Check(i);\n\n\tfor (uint32_t i = 0; i < slidersCheckListBox->GetCount(); i++)\n\t\tslidersCheckListBox->Check(i);\n\n\treturn wxDialog::ShowModal();\n}\n\nvoid SliderDataImportDialog::OnShapeSelectionChanged(wxCommandEvent& WXUNUSED(event)) {\n\tslidersCheckListBox->Clear();\n\tstd::unordered_set<std::string> addedSliders;\n\n\twxArrayInt checked;\n\tshapesCheckListBox->GetCheckedItems(checked);\n\tfor (const auto& i : checked) {\n\t\tconst auto data = dynamic_cast<ShapeSliderData*>(shapesCheckListBox->GetClientObject(i));\n\t\tfor (auto& sliderName : data->sliderNames) {\n\t\t\tif (addedSliders.find(sliderName.first) != addedSliders.end())\n\t\t\t\tcontinue;\n\n\t\t\tslidersCheckListBox->Append(sliderName.first);\n\t\t\taddedSliders.emplace(sliderName.first);\n\t\t}\n\t}\n\n\tfor (uint32_t i = 0; i < slidersCheckListBox->GetCount(); i++)\n\t\tslidersCheckListBox->Check(i);\n}\n\nvoid SliderDataImportDialog::OnImport(wxCommandEvent& WXUNUSED(event)) {\n\n\toptions.mergeSliders = ConfigDialogUtil::SetBoolFromDialogCheckbox(outfitStudioConfig, *this, \"SliderDataImport\", \"chkImportMergeSliders\");\n\n\twxArrayInt checked;\n\tslidersCheckListBox->GetCheckedItems(checked);\n\tstd::unordered_set<std::string> selectedSliders;\n\tfor (const auto& i : checked) {\n\t\tconst auto sliderDisplayName = slidersCheckListBox->GetString(i);\n\t\tselectedSliders.emplace(sliderDisplayName);\n\t}\n\n\tshapesCheckListBox->GetCheckedItems(checked);\n\tfor (const auto& i : checked) {\n\t\tconst auto data = dynamic_cast<ShapeSliderData*>(shapesCheckListBox->GetClientObject(i));\n\t\tfor (auto sliderNames : data->sliderNames) {\n\t\t\tif (selectedSliders.find(sliderNames.first) == selectedSliders.end())\n\t\t\t\tcontinue;\n\n\t\t\toptions.selectedShapesToSliders[data->targetShape].emplace(sliderNames.second, sliderNames.first);\n\t\t}\n\t}\n\n\tEndModal(wxID_OK);\n}\n\nvoid SliderDataImportDialog::OnSliderListContext(wxMouseEvent& WXUNUSED(event)) {\n\twxMenu* menu = wxXmlResource::Get()->LoadMenu(\"sliderDataContext\");\n\tif (menu) {\n\t\tmenu->Bind(wxEVT_MENU, &SliderDataImportDialog::OnSliderListContextSelect, this);\n\t\tPopupMenu(menu);\n\t\tdelete menu;\n\t}\n}\n\nvoid SliderDataImportDialog::OnSliderListContextSelect(wxCommandEvent& event) {\n\tif (event.GetId() == XRCID(\"sliderDataContextNone\")) {\n\t\tfor (uint32_t i = 0; i < slidersCheckListBox->GetCount(); i++)\n\t\t\tslidersCheckListBox->Check(i, false);\n\t}\n\telse if (event.GetId() == XRCID(\"sliderDataContextAll\")) {\n\t\tfor (uint32_t i = 0; i < slidersCheckListBox->GetCount(); i++)\n\t\t\tslidersCheckListBox->Check(i);\n\t}\n\telse if (event.GetId() == XRCID(\"sliderDataContextInvert\")) {\n\t\tfor (uint32_t i = 0; i < slidersCheckListBox->GetCount(); i++)\n\t\t\tslidersCheckListBox->Check(i, !slidersCheckListBox->IsChecked(i));\n\t}\n}"
  },
  {
    "path": "src/program/SliderDataImportDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"ShapeProperties.h\"\n\n#include <wx/wx.h>\n#include <wx/xrc/xmlres.h>\n\nclass OutfitProject;\nclass ConfigurationManager;\n\nclass ShapeSliderData : public wxClientData {\npublic:\n\tShapeSliderData(const std::string& name, const std::string& originalName, const std::unordered_map<std::string, std::string>& sliderNames)\n\t:  shapeName(originalName), targetShape(name), sliderNames(sliderNames) {}\n\tstd::string shapeName;\n\tstd::string targetShape;\n\tstd::unordered_map<std::string, std::string> sliderNames;\n};\n\nclass SliderDataImportOptions {\npublic:\n\tSliderDataImportOptions()\n\t\t: mergeSliders(false) {}\n\n\tstd::unordered_map<std::string, std::unordered_map<std::string, std::string>> selectedShapesToSliders;\n\tbool mergeSliders;\n};\n\n\nclass SliderDataImportDialog : public wxDialog {\npublic:\n\tSliderDataImportDialog(wxWindow* parent, OutfitProject* project, ConfigurationManager& outfitStudioConfig);\n\t~SliderDataImportDialog();\n\n\tint ShowModal(const std::unordered_map<std::string, std::unordered_map<std::string, std::string>>& sliderData);\n\tvoid OnImport(wxCommandEvent& event);\n\n\tSliderDataImportOptions GetOptions() { return options; }\n\twxDECLARE_EVENT_TABLE();\n\nprivate:\n\tvoid OnShapeSelectionChanged(wxCommandEvent& WXUNUSED(event));\n\tvoid OnSliderListContext(wxMouseEvent& WXUNUSED(event));\n\tvoid OnSliderListContextSelect(wxCommandEvent& event);\n\n\twxCheckListBox* shapesCheckListBox;\n\twxCheckListBox* slidersCheckListBox;\n\tOutfitProject* project;\n\tConfigurationManager& outfitStudioConfig;\n\tSliderDataImportOptions options;\n};\n\n\n"
  },
  {
    "path": "src/render/GLCanvas.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLDialog.h\"\n\nwxBEGIN_EVENT_TABLE(GLCanvas, wxGLCanvas)\n\tEVT_PAINT(GLCanvas::OnPaint)\n\tEVT_MOTION(GLCanvas::OnMotion)\n\tEVT_MOUSEWHEEL(GLCanvas::OnMouseWheel)\n\tEVT_KEY_UP(GLCanvas::OnKeyUp)\n\tEVT_SIZE(GLCanvas::OnResized)\nwxEND_EVENT_TABLE()\n\nGLCanvas::GLCanvas(GLDialog* parent, const wxGLAttributes& attribs)\n\t: wxGLCanvas(parent, attribs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)\n\t, parent(parent) {}\n\nvoid GLCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {\n\t// Initialize OpenGL the first time the window is painted.\n\t// We unfortunately can't initialize it before the window is shown.\n\t// We could register for the EVT_SHOW event, but unfortunately it\n\t// appears to only be called after the first few EVT_PAINT events.\n\t// It also isn't supported on all platforms.\n\tif (firstPaint) {\n\t\tfirstPaint = false;\n\t\tparent->OnShown();\n\t}\n\tparent->Render();\n}\n\nvoid GLCanvas::OnMotion(wxMouseEvent& event) {\n\tif (parent->IsActive())\n\t\tSetFocus();\n\n\tauto delta = event.GetPosition() - lastMousePosition;\n\n\tif (event.LeftIsDown()) {\n\t\tparent->LeftDrag(delta.x, delta.y);\n\t}\n\telse if (event.MiddleIsDown()) {\n\t\tif (wxGetKeyState(WXK_SHIFT))\n\t\t\tparent->MouseWheel(delta.y);\n\t\telse\n\t\t\tparent->LeftDrag(delta.x, delta.y);\n\t}\n\telse if (event.RightIsDown()) {\n\t\tif (wxGetKeyState(WXK_SHIFT))\n\t\t\tparent->LeftDrag(delta.x, delta.y);\n\t\telse\n\t\t\tparent->RightDrag(delta.x, delta.y);\n\t}\n\telse\n\t\tparent->TrackMouse(event.GetX(), event.GetY());\n\n\tlastMousePosition = event.GetPosition();\n}\n\nvoid GLCanvas::OnMouseWheel(wxMouseEvent& event) {\n\tparent->MouseWheel(event.GetWheelRotation());\n}\n\nvoid GLCanvas::OnKeyUp(wxKeyEvent& event) {\n\tint key = event.GetKeyCode();\n\tswitch (key) {\n\t\tcase 'T': parent->ToggleTextures(); break;\n\t\tcase 'W': parent->ToggleWireframe(); break;\n\t\tcase 'L': parent->ToggleLighting(); break;\n\t\tcase 'G': parent->ToggleFloor(); break;\n\t}\n}\n\nvoid GLCanvas::OnResized(wxSizeEvent& event) {\n\tparent->Resized(event.GetSize().GetWidth(), event.GetSize().GetHeight());\n}\n"
  },
  {
    "path": "src/render/GLCanvas.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <wx/wx.h>\n#include <wx/glcanvas.h>\n\nclass GLDialog;\n\nclass GLCanvas : public wxGLCanvas {\n\tGLDialog* parent = nullptr;\n\tbool firstPaint = true;\n\twxPoint lastMousePosition;\n\npublic:\n\tGLCanvas(GLDialog* parent, const wxGLAttributes& attribs);\n\n\tvoid OnPaint(wxPaintEvent& event);\n\tvoid OnMotion(wxMouseEvent& event);\n\tvoid OnMouseWheel(wxMouseEvent& event);\n\tvoid OnKeyUp(wxKeyEvent& event);\n\tvoid OnResized(wxSizeEvent& event);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/render/GLDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLDialog.h\"\n#include \"../utils/ConfigurationManager.h\"\n\nusing namespace nifly;\n\nextern ConfigurationManager Config;\n\n\nwxBEGIN_EVENT_TABLE(GLDialog, wxDialog)\n\tEVT_CLOSE(GLDialog::OnClose)\nwxEND_EVENT_TABLE()\n\nGLDialog::GLDialog() {\n\tCenterOnParent();\n}\n\nGLCanvas* GLDialog::CreateCanvas() {\n\tcanvas = new GLCanvas(this, GLSurface::GetGLAttribs());\n\tcontext = std::make_unique<wxGLContext>(canvas, nullptr, &GLSurface::GetGLContextAttribs());\n\treturn canvas;\n}\n\nvoid GLDialog::OnShown() {\n\tif (!context->IsOK()) {\n\t\tDestroy();\n\t\tcanvas = nullptr;\n\t\twxLogError(\"Preview failed: OpenGL context is not OK.\");\n\t\twxMessageBox(_(\"Preview failed: OpenGL context is not OK.\"), _(\"OpenGL Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\tgls.Initialize(canvas, context.get());\n\n\tauto size = canvas->GetSize();\n\tgls.SetStartingView(Vector3(0.0f, -5.0f, -15.0f), Vector3(15.0f, 0.0f, 0.0f), size.GetWidth(), size.GetHeight(), 65.0);\n\n\tint ambient = Config.GetIntValue(\"Lights/Ambient\");\n\tint frontal = Config.GetIntValue(\"Lights/Frontal\");\n\n\tint directional0 = Config.GetIntValue(\"Lights/Directional0\");\n\tint directional0X = Config.GetIntValue(\"Lights/Directional0.x\");\n\tint directional0Y = Config.GetIntValue(\"Lights/Directional0.y\");\n\tint directional0Z = Config.GetIntValue(\"Lights/Directional0.z\");\n\n\tint directional1 = Config.GetIntValue(\"Lights/Directional1\");\n\tint directional1X = Config.GetIntValue(\"Lights/Directional1.x\");\n\tint directional1Y = Config.GetIntValue(\"Lights/Directional1.y\");\n\tint directional1Z = Config.GetIntValue(\"Lights/Directional1.z\");\n\n\tint directional2 = Config.GetIntValue(\"Lights/Directional2\");\n\tint directional2X = Config.GetIntValue(\"Lights/Directional2.x\");\n\tint directional2Y = Config.GetIntValue(\"Lights/Directional2.y\");\n\tint directional2Z = Config.GetIntValue(\"Lights/Directional2.z\");\n\n\tVector3 directional0Dir = Vector3(directional0X / 100.0f, directional0Y / 100.0f, directional0Z / 100.0f);\n\tVector3 directional1Dir = Vector3(directional1X / 100.0f, directional1Y / 100.0f, directional1Z / 100.0f);\n\tVector3 directional2Dir = Vector3(directional2X / 100.0f, directional2Y / 100.0f, directional2Z / 100.0f);\n\tgls.UpdateLights(ambient, frontal, directional0, directional1, directional2, directional0Dir, directional1Dir, directional2Dir);\n\n\tif (Config.Exists(\"Rendering/ColorBackground\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorBackground.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorBackground.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorBackground.b\");\n\t\tgls.SetBackgroundColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorWire\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorWire.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorWire.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorWire.b\");\n\t\tgls.SetWireColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorPoints\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPoints.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPoints.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPoints.b\");\n\t\tgls.SetPointColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorPointsMasked\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPointsMasked.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPointsMasked.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPointsMasked.b\");\n\t\tgls.SetMaskedPointColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\t// Turn texture rendering off initially\n\tgls.ToggleTextures();\n\n\tfloorMeshes = gls.AddFloor();\n}\n\nvoid GLDialog::OnClose(wxCloseEvent& WXUNUSED(event)) {\n\tCleanup();\n\tDestroy();\n}\n\nvoid GLDialog::LeftDrag(int dX, int dY) {\n\tgls.PanCamera(dX, dY);\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::RightDrag(int dX, int dY) {\n\tgls.TurnTableCamera(dX);\n\tgls.PitchCamera(dY);\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::MouseWheel(int dW) {\n\tgls.DollyCamera(dW);\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::TrackMouse(int X, int Y) {\n\tgls.UpdateCursor(X, Y);\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::ToggleTextures() {\n\tgls.ToggleTextures();\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::ToggleWireframe() {\n\tgls.ToggleWireframe();\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::ToggleLighting() {\n\tgls.ToggleLighting();\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::ToggleFloor() {\n\tfor (auto& m : floorMeshes)\n\t\tm->bVisible = !m->bVisible;\n\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::Render() {\n\tgls.RenderOneFrame();\n}\n\nvoid GLDialog::Resized(uint32_t w, uint32_t h) {\n\tgls.SetSize(w, h);\n}\n\nvoid GLDialog::Cleanup() {\n\t// Set current context for resource deletion\n\tif (canvas && context)\n\t\tcanvas->SetCurrent(*context);\n\n\tgls.Cleanup();\n\tshapeMaterials.clear();\n\tgls.RenderOneFrame();\n}\n"
  },
  {
    "path": "src/render/GLDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"GLSurface.h\"\n#include \"GLCanvas.h\"\n\n#include <wx/wx.h>\n\nclass GLDialog : public wxDialog {\npublic:\n\tGLDialog();\n\n\tGLCanvas* CreateCanvas();\n\tvirtual void OnShown();\n\tvoid OnClose(wxCloseEvent& event);\n\n\tGLCanvas* GetCanvas() { return canvas; }\n\twxGLContext* GetContext() { return context.get(); }\n\tGLSurface& GetSurface() { return gls; }\n\n\tvoid LeftDrag(int dX, int dY);\n\tvoid RightDrag(int dX, int dY);\n\tvoid MouseWheel(int dW);\n\tvoid TrackMouse(int X, int Y);\n\n\tvoid ToggleTextures();\n\tvoid ToggleWireframe();\n\tvoid ToggleLighting();\n\tvoid ToggleFloor();\n\n\tvoid Resized(uint32_t w, uint32_t h);\n\n\tvoid Render();\n\tvoid Cleanup();\n\n\twxDECLARE_EVENT_TABLE();\n\nprotected:\n\tGLCanvas* canvas = nullptr;\n\nprivate:\n\tstd::unique_ptr<wxGLContext> context;\n\tGLSurface gls;\n\n\tstd::unordered_map<std::string, GLMaterial*> shapeMaterials;\n\tstd::vector<Mesh*> floorMeshes;\n};\n"
  },
  {
    "path": "src/render/GLExtensions.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLExtensions.h\"\n#include <string>\n\nbool extInitialized = false;\nbool extSupported = true;\nbool extGLISupported = true;\n\n#ifndef __linux__\n// OpenGL 4.2\nPFNGLTEXSTORAGE1DPROC glTexStorage1D = nullptr;\nPFNGLTEXSTORAGE2DPROC glTexStorage2D = nullptr;\nPFNGLTEXSTORAGE3DPROC glTexStorage3D = nullptr;\n\n// OpenGL 3.0\nPFNGLGETSTRINGIPROC glGetStringi = nullptr;\nPFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;\nPFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;\nPFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr;\n\nPFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr;\nPFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr;\nPFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr;\nPFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr;\nPFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr;\nPFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr;\nPFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr;\nPFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr;\nPFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr;\nPFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = nullptr;\nPFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = nullptr;\n\n// OpenGL 2.0\nPFNGLCREATESHADERPROC glCreateShader = nullptr;\nPFNGLSHADERSOURCEPROC glShaderSource = nullptr;\nPFNGLCOMPILESHADERPROC glCompileShader = nullptr;\nPFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;\nPFNGLATTACHSHADERPROC glAttachShader = nullptr;\nPFNGLLINKPROGRAMPROC glLinkProgram = nullptr;\nPFNGLUSEPROGRAMPROC glUseProgram = nullptr;\n\nPFNGLGETATTRIBLOCATIONPROC glGetAttribLocation = nullptr;\nPFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;\nPFNGLUNIFORM1FPROC glUniform1f = nullptr;\nPFNGLUNIFORM1IPROC glUniform1i = nullptr;\nPFNGLUNIFORM2FPROC glUniform2f = nullptr;\nPFNGLUNIFORM3FPROC glUniform3f = nullptr;\nPFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv = nullptr;\nPFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = nullptr;\n\nPFNGLGETSHADERIVPROC glGetShaderiv = nullptr;\nPFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;\nPFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;\nPFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;\n\nPFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;\nPFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr;\nPFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;\n\n// OpenGL 1.5\nPFNGLGENBUFFERSPROC glGenBuffers = nullptr;\nPFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr;\nPFNGLBINDBUFFERPROC glBindBuffer = nullptr;\nPFNGLBUFFERDATAPROC glBufferData = nullptr;\nPFNGLBUFFERSUBDATAPROC glBufferSubData = nullptr;\n\n// OpenGL 1.3\nPFNGLACTIVETEXTUREPROC glActiveTexture = nullptr;\nPFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D = nullptr;\nPFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D = nullptr;\nPFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D = nullptr;\n\n// OpenGL 1.2\nPFNGLTEXSUBIMAGE3DPROC glTexSubImage3D = nullptr;\n\nvoid InitExtensions() {\n\tif (!extInitialized) {\n\t\tglTexStorage1D = (PFNGLTEXSTORAGE1DPROC)wglGetProcAddress(\"glTexStorage1D\");\n\t\tglTexStorage2D = (PFNGLTEXSTORAGE2DPROC)wglGetProcAddress(\"glTexStorage2D\");\n\t\tglTexStorage3D = (PFNGLTEXSTORAGE3DPROC)wglGetProcAddress(\"glTexStorage3D\");\n\t\tglCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)wglGetProcAddress(\"glCompressedTexSubImage1D\");\n\t\tglCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)wglGetProcAddress(\"glCompressedTexSubImage2D\");\n\t\tglCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)wglGetProcAddress(\"glCompressedTexSubImage3D\");\n\t\tglTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)wglGetProcAddress(\"glTexSubImage3D\");\n\n\t\tglGetStringi = (PFNGLGETSTRINGIPROC)wglGetProcAddress(\"glGetStringi\");\n\t\tglGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress(\"glGenVertexArrays\");\n\t\tglBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress(\"glBindVertexArray\");\n\t\tglDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)wglGetProcAddress(\"glDeleteVertexArrays\");\n\t\tglGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress(\"glGenFramebuffers\");\n\t\tglDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress(\"glDeleteFramebuffers\");\n\t\tglBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress(\"glBindFramebuffer\");\n\t\tglFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress(\"glFramebufferTexture2D\");\n\t\tglGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wglGetProcAddress(\"glGenRenderbuffers\");\n\t\tglBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wglGetProcAddress(\"glBindRenderbuffer\");\n\t\tglRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wglGetProcAddress(\"glRenderbufferStorage\");\n\t\tglFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wglGetProcAddress(\"glFramebufferRenderbuffer\");\n\t\tglDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)wglGetProcAddress(\"glDeleteRenderbuffers\");\n\t\tglRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)wglGetProcAddress(\"glRenderbufferStorageMultisample\");\n\t\tglBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC)wglGetProcAddress(\"glBlitFramebuffer\");\n\n\t\tglCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress(\"glCreateShader\");\n\t\tglShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress(\"glShaderSource\");\n\t\tglCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress(\"glCompileShader\");\n\n\t\tglCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress(\"glCreateProgram\");\n\t\tglAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress(\"glAttachShader\");\n\t\tglLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress(\"glLinkProgram\");\n\t\tglUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress(\"glUseProgram\");\n\n\t\tglGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress(\"glGetShaderiv\");\n\t\tglGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress(\"glGetShaderInfoLog\");\n\t\tglGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress(\"glGetProgramiv\");\n\t\tglGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress(\"glGetProgramInfoLog\");\n\n\t\tglDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress(\"glDisableVertexAttribArray\");\n\t\tglEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress(\"glEnableVertexAttribArray\");\n\t\tglVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress(\"glVertexAttribPointer\");\n\n\t\tglGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress(\"glGenBuffers\");\n\t\tglDeleteBuffers = (PFNGLDELETEBUFFERSPROC)wglGetProcAddress(\"glDeleteBuffers\");\n\t\tglBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress(\"glBindBuffer\");\n\t\tglBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress(\"glBufferData\");\n\t\tglBufferSubData = (PFNGLBUFFERSUBDATAPROC)wglGetProcAddress(\"glBufferSubData\");\n\n\t\tglGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)wglGetProcAddress(\"glGetAttribLocation\");\n\t\tglGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress(\"glGetUniformLocation\");\n\t\tglUniform1f = (PFNGLUNIFORM1FPROC)wglGetProcAddress(\"glUniform1f\");\n\t\tglUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress(\"glUniform1i\");\n\t\tglUniform2f = (PFNGLUNIFORM2FPROC)wglGetProcAddress(\"glUniform2f\");\n\t\tglUniform3f = (PFNGLUNIFORM3FPROC)wglGetProcAddress(\"glUniform3f\");\n\t\tglUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)wglGetProcAddress(\"glUniformMatrix3fv\");\n\t\tglUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress(\"glUniformMatrix4fv\");\n\n\t\tglActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress(\"glActiveTexture\");\n\n\t\tif (!glTexStorage1D || !glTexStorage2D || !glTexStorage3D || !glTexSubImage3D || !glCompressedTexSubImage1D || !glCompressedTexSubImage2D || !glCompressedTexSubImage3D) {\n\t\t\textGLISupported = false;\n\t\t}\n\n\t\tif (!glGetStringi || !glGenVertexArrays || !glBindVertexArray || !glDeleteVertexArrays || !glCreateShader || !glShaderSource || !glCompileShader || !glCreateProgram\n\t\t\t|| !glAttachShader || !glLinkProgram || !glUseProgram || !glGetShaderiv || !glGetShaderInfoLog || !glGetProgramiv || !glGetProgramInfoLog || !glDisableVertexAttribArray\n\t\t\t|| !glEnableVertexAttribArray || !glVertexAttribPointer || !glGenBuffers || !glDeleteBuffers || !glBindBuffer || !glBufferData || !glBufferSubData\n\t\t\t|| !glGetAttribLocation || !glGetUniformLocation || !glUniform1f || !glUniform1i || !glUniform2f || !glUniform3f || !glUniformMatrix4fv || !glActiveTexture) {\n\t\t\textSupported = false;\n\t\t}\n\n\t\textInitialized = true;\n\t}\n}\n\nbool IsExtensionSupported(const char* ext) {\n\t// Get number of extensions\n\tGLint numExtensions = 0;\n\tglGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);\n\n\tif (numExtensions <= 0)\n\t\treturn false;\n\n\t// Compare extension strings\n\tfor (int i = 0; i < numExtensions; i++) {\n\t\tstd::string extension((const char*)glGetStringi(GL_EXTENSIONS, i));\n\t\tif (extension.compare(ext) == 0)\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n#else // __linux__\n\nvoid InitExtensions() {\n\tif (extInitialized)\n\t\treturn;\n\tGLenum err = glewInit();\n\t// TODO: figure out why we're getting GLEW_ERROR_NO_GLX_DISPLAY (error\n\t// code 4) with gtk3 builds of wxWidgets and fix it.  Everything still\n\t// seems to work if we ignore the error, though.\n\tif (err != GLEW_OK && err != GLEW_ERROR_NO_GLX_DISPLAY) {\n\t\tfprintf(stderr, \"Error (%d): %s\\n\", (int)err, glewGetErrorString(err));\n\t\tabort();\n\t}\n\textGLISupported = glTexStorage1D && glTexStorage2D && glTexStorage3D && glTexSubImage3D && glCompressedTexSubImage1D && glCompressedTexSubImage2D && glCompressedTexSubImage3D;\n\textSupported = glGetStringi && glGenVertexArrays && glBindVertexArray && glDeleteVertexArrays && glCreateShader && glShaderSource && glCompileShader && glCreateProgram\n\t\t\t\t   && glAttachShader && glLinkProgram && glUseProgram && glGetShaderiv && glGetShaderInfoLog && glGetProgramiv && glGetProgramInfoLog && glDisableVertexAttribArray\n\t\t\t\t   && glEnableVertexAttribArray && glVertexAttribPointer && glGenBuffers && glDeleteBuffers && glBindBuffer && glBufferData && glBufferSubData\n\t\t\t\t   && glGetAttribLocation && glGetUniformLocation && glUniform1f && glUniform1i && glUniform2f && glUniform3f && glUniformMatrix4fv && glActiveTexture;\n\textInitialized = true;\n}\n\nbool IsExtensionSupported(const char* ext) {\n\treturn glewIsSupported(ext);\n}\n\n#endif\n"
  },
  {
    "path": "src/render/GLExtensions.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#if defined(_WIN32)\n#include <Windows.h>\n#include <GL/gl.h>\n#include <GL/glu.h>\n#include <GL/glext.h>\n#elif defined(__APPLE__)\n#include <OpenGL/gl.h>\n#include <OpenGL/glu.h>\n#include <OpenGL/glext.h>\n#elif defined(__linux__)\n#include <GL/glew.h>\n#else\n#error Platform OpenGL headers not defined yet!\n#endif\n\nextern bool extInitialized;\nextern bool extSupported;\nextern bool extGLISupported;\n\n#ifndef __linux__\n// OpenGL 4.2\nextern PFNGLTEXSTORAGE1DPROC glTexStorage1D;\nextern PFNGLTEXSTORAGE2DPROC glTexStorage2D;\nextern PFNGLTEXSTORAGE3DPROC glTexStorage3D;\n\n// OpenGL 3.0\nextern PFNGLGETSTRINGIPROC glGetStringi;\nextern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;\nextern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;\nextern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;\n\nextern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;\nextern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;\nextern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;\nextern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;\nextern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;\nextern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;\nextern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;\nextern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;\nextern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;\nextern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;\nextern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;\n\n// OpenGL 2.0\nextern PFNGLCREATESHADERPROC glCreateShader;\nextern PFNGLSHADERSOURCEPROC glShaderSource;\nextern PFNGLCOMPILESHADERPROC glCompileShader;\nextern PFNGLCREATEPROGRAMPROC glCreateProgram;\nextern PFNGLATTACHSHADERPROC glAttachShader;\nextern PFNGLLINKPROGRAMPROC glLinkProgram;\nextern PFNGLUSEPROGRAMPROC glUseProgram;\n\nextern PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;\nextern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;\nextern PFNGLUNIFORM1FPROC glUniform1f;\nextern PFNGLUNIFORM1IPROC glUniform1i;\nextern PFNGLUNIFORM2FPROC glUniform2f;\nextern PFNGLUNIFORM3FPROC glUniform3f;\nextern PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv;\nextern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;\n\nextern PFNGLGETSHADERIVPROC glGetShaderiv;\nextern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;\nextern PFNGLGETPROGRAMIVPROC glGetProgramiv;\nextern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;\n\nextern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;\nextern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;\nextern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;\n\n// OpenGL 1.5\nextern PFNGLGENBUFFERSPROC glGenBuffers;\nextern PFNGLDELETEBUFFERSPROC glDeleteBuffers;\nextern PFNGLBINDBUFFERPROC glBindBuffer;\nextern PFNGLBUFFERDATAPROC glBufferData;\nextern PFNGLBUFFERSUBDATAPROC glBufferSubData;\n\n// OpenGL 1.3\nextern PFNGLACTIVETEXTUREPROC glActiveTexture;\nextern PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D;\nextern PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D;\nextern PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D;\n\n// OpenGL 1.2\nextern PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D;\n#endif\n\nextern void InitExtensions();\nextern bool IsExtensionSupported(const char* ext);\n"
  },
  {
    "path": "src/render/GLMaterial.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLMaterial.h\"\n\nusing namespace nifly;\n\nGLMaterial::GLMaterial() {}\n\nGLMaterial::~GLMaterial() {}\n\n// Shader-only material, does not contain texture references, and thus does not use reference to res loader.\nGLMaterial::GLMaterial(const std::string& vertShaderProg, const std::string& fragShaderProg) {\n\tshader = GLShader(vertShaderProg, fragShaderProg);\n}\n\nGLMaterial::GLMaterial(ResourceLoader* resLoader, std::string texName, const std::string& vertShaderProg, const std::string& fragShaderProg) {\n\tresLoaderRef = resLoader;\n\ttexNames.push_back(texName);\n\tresLoader->CacheStamp(cacheTime);\n\ttexCache.push_back(resLoader->GetTexID(texName));\n\tshader = GLShader(vertShaderProg, fragShaderProg);\n}\n\nGLMaterial::GLMaterial(ResourceLoader* resLoader, std::vector<std::string> inTexNames, const std::string& vertShaderProg, const std::string& fragShaderProg)\n\t: texNames(inTexNames) {\n\tresLoaderRef = resLoader;\n\tresLoader->CacheStamp(cacheTime);\n\ttexCache.resize(inTexNames.size(), 0);\n\tfor (size_t i = 0; i < inTexNames.size(); i++)\n\t\ttexCache[i] = resLoader->GetTexID(inTexNames[i]);\n\n\tshader = GLShader(vertShaderProg, fragShaderProg);\n}\n\nGLShader& GLMaterial::GetShader() {\n\treturn shader;\n}\n\nGLuint GLMaterial::GetTexID(uint32_t index) {\n\tif (resLoaderRef && !resLoaderRef->CacheStamp(cacheTime)) {\n\t\t// outdated cache, rebuild it.\n\t\tfor (size_t i = 0; i < texCache.size(); i++) {\n\t\t\ttexCache[i] = resLoaderRef->GetTexID(texNames[i]);\n\t\t}\n\t}\n\treturn texCache[index];\n}\n\nstd::string GLMaterial::GetTexName(uint32_t index) {\n\tif (index < texNames.size())\n\t\treturn texNames[index];\n\n\treturn \"\";\n}\n\nvoid GLMaterial::BindTextures(GLfloat largestAF, const bool hasEnvMapping, const bool hasGlowmap, const bool hasBacklightMap, const bool hasLightmask) {\n\tif (resLoaderRef && !resLoaderRef->CacheStamp(cacheTime)) {\n\t\t// outdated cache, rebuild it.\n\t\tfor (size_t i = 0; i < texCache.size(); i++) {\n\t\t\ttexCache[i] = resLoaderRef->GetTexID(texNames[i]);\n\t\t}\n\t}\n\n\tshader.BindTexture(0, 0, \"texDiffuse\");\n\tshader.BindTexture(1, 0, \"texNormal\");\n\tshader.BindTexture(2, 0, \"texGlowmap\");\n\tshader.BindTexture(3, 0, \"texGreyscale\");\n\tshader.BindCubemap(4, 0, \"texCubemap\");\n\tshader.BindTexture(5, 0, \"texEnvMask\");\n\tshader.BindTexture(7, 0, \"texSpecular\");\n\tshader.BindTexture(7, 0, \"texBacklight\");\n\tshader.BindTexture(20, 0, \"texAlphaMask\");\n\n\tfor (GLint id = 0; id < static_cast<GLint>(texCache.size()); id++) {\n\t\tswitch (id) {\n\t\t\tcase 0:\n\t\t\t\tshader.BindTexture(id, texCache[id], \"texDiffuse\");\n\t\t\t\tif (largestAF)\n\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\tbreak;\n\n\t\t\tcase 1:\n\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texNormal\");\n\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\tshader.SetNormalMapEnabled(true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tshader.SetNormalMapEnabled(false);\n\t\t\t\tbreak;\n\n\t\t\tcase 2:\n\t\t\t\tif (hasGlowmap) {\n\t\t\t\t\tshader.SetRimlightEnabled(false);\n\t\t\t\t\tshader.SetSoftlightEnabled(false);\n\n\t\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texGlowmap\");\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tshader.SetGlowmapEnabled(false);\n\t\t\t\t}\n\t\t\t\telse if (hasLightmask) {\n\t\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texLightmask\");\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 3:\n\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texGreyscale\");\n\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 4:\n\t\t\t\tif (hasEnvMapping) {\n\t\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\t\tshader.BindCubemap(id, texCache[id], \"texCubemap\");\n\t\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tshader.SetCubemapEnabled(false);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 5:\n\t\t\t\tif (hasEnvMapping) {\n\t\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texEnvMask\");\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\t\tshader.SetEnvMaskEnabled(true);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tshader.SetEnvMaskEnabled(false);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 7:\n\t\t\t\tif (!hasBacklightMap) {\n\t\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texSpecular\");\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texBacklight\");\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tshader.SetBacklightEnabled(false);\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 20:\n\t\t\t\t// Internal use for compositing and postprocessing textures, not represented by game textures.\n\t\t\t\tif (texCache[id] != 0) {\n\t\t\t\t\tshader.BindTexture(id, texCache[id], \"texAlphaMask\");\n\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\t\t\tif (largestAF)\n\t\t\t\t\t\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, largestAF);\n\t\t\t\t\tshader.SetAlphaMaskEnabled(true);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tshader.SetAlphaMaskEnabled(false);\n\t\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/render/GLMaterial.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"../files/ResourceLoader.h\"\n#include \"GLShader.h\"\n\nclass GLMaterial {\nprivate:\n\t// texture names linked with this material.  Used to lookup OGL texture ids in Resource Loader.\n\tstd::vector<std::string> texNames;\n\t// Cache of texture IDs. These are direct OGL texture ids used to bind textures and avoid lookups to\n\t//  the resource loader's texture database each frame.\n\tstd::vector<GLuint> texCache;\n\t// A value indicating the last time the cache was updated from the resource loader. This isn't a time,\n\t//  but instead a numeric indicator of change state. This is checked prior to binding textures, and if\n\t//  a change has happened, texids are refreshed from ResourceLoader based on texNames.\n\tint64_t cacheTime = 0;\n\tGLShader shader;\n\tResourceLoader* resLoaderRef = nullptr;\n\npublic:\n\tGLMaterial();\n\t~GLMaterial();\n\n\t// Shader-only material, does not contain texture references, and thus does not use reference to res loader.\n\tGLMaterial(const std::string& vertShaderProg, const std::string& fragShaderProg);\n\tGLMaterial(ResourceLoader* resLoader, std::string texName, const std::string& vertShaderProg, const std::string& fragShaderProg);\n\tGLMaterial(ResourceLoader* resLoader, std::vector<std::string> inTexNames, const std::string& vertShaderProg, const std::string& fragShaderProg);\n\n\tGLShader& GetShader();\n\n\tGLuint GetTexID(uint32_t index);\n\tstd::string GetTexName(uint32_t index);\n\n\tvoid BindTextures(GLfloat largestAF, const bool hasEnvMapping, const bool hasGlowmap, const bool hasBacklight, const bool hasLightmask);\n};\n"
  },
  {
    "path": "src/render/GLOffscreenBuffer.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLOffscreenBuffer.h\"\n\n#include <convert.hpp>\n#include <make_texture.hpp>\n#include <save.hpp>\n#include <texture2d.hpp>\n\n#include <glm/gtx/gradient_paint.hpp>\n\nGLOffScreenBuffer::GLOffScreenBuffer(GLSurface* gls, int width, int height, int count, const std::vector<GLuint>& texIds, int samples) {\n\t// for naming textures in CreateTextures\n\tstatic int globcount = 0;\n\tglobcount++;\n\tGLOBCount = globcount;\n\n\tglsRef = gls;\n\tw = width;\n\th = height;\n\tmsaaSamples = (samples > 0 && glRenderbufferStorageMultisample && glBlitFramebuffer) ? samples : 0;\n\n\t// current active buffer index starts at -1 to detect if it's been set yet or not\n\tcurrent = -1;\n\tisBound = false;\n\tnumBuffers = count;\n\tpmtex = new GLuint[count];\n\tpmfbo = new GLuint[count];\n\n\t// Create Texture destination\n\tcreateTextures();\n\tglGenFramebuffers(count, pmfbo);\n\n\t// Create a renderbuffer for depth information, and attach it\n\tglGenRenderbuffers(1, &mrbo);\n\tglBindRenderbuffer(GL_RENDERBUFFER, mrbo);\n\tglRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w, h);\n\n\tfor (int i = 0; i < count; i++) {\n\t\tif (texIds.size() > (size_t)i && texIds[i] != 0) {\n\t\t\tpmtex[i] = texIds[i];\n\t\t}\n\t\telse {\n\t\t\tglBindTexture(GL_TEXTURE_2D, pmtex[i]);\n\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);\n\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);\n\t\t\tglTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);\n\t\t}\n\n\t\t// Create frame buffer for rendering destination, and attach texture to it\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, pmfbo[i]);\n\t\tglFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pmtex[i], 0);\n\t\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, mrbo);\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, 0);\n\t}\n\n\t// Create MSAA resources if requested\n\tif (msaaSamples > 0) {\n\t\tglGenFramebuffers(1, &msaaFBO);\n\t\tglGenRenderbuffers(1, &msaaColorRBO);\n\t\tglGenRenderbuffers(1, &msaaDepthRBO);\n\n\t\tglBindRenderbuffer(GL_RENDERBUFFER, msaaColorRBO);\n\t\tglRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_RGBA8, w, h);\n\t\tglBindRenderbuffer(GL_RENDERBUFFER, msaaDepthRBO);\n\t\tglRenderbufferStorageMultisample(GL_RENDERBUFFER, msaaSamples, GL_DEPTH_COMPONENT24, w, h);\n\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, msaaFBO);\n\t\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, msaaColorRBO);\n\t\tglFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaaDepthRBO);\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, 0);\n\t}\n}\n\nstd::string GLOffScreenBuffer::texName(int index) {\n\tif (index == -1)\n\t\tindex = current;\n\n\tstd::string texname = \"glob_\" + std::to_string(GLOBCount) + \"_\" + std::to_string(index);\n\treturn texname;\n}\n\nbool GLOffScreenBuffer::SetCurrentBuffer(int bufferIndex) {\n\tif (bufferIndex < 0 || bufferIndex >= numBuffers)\n\t\treturn false;\n\tcurrent = bufferIndex;\n\treturn true;\n}\n\nbool GLOffScreenBuffer::NextBuffer(bool cycle) {\n\tif (current < -1)\n\t\tcurrent = -1; // setting to -1 because we want the increment to put it at 0.\n\n\tcurrent++;\n\n\t// cycle buffers automatically.\n\tif (current >= numBuffers) {\n\t\tif (cycle) {\n\t\t\tcurrent = 0;\n\t\t}\n\t\telse {\n\t\t\tcurrent--;\n\t\t\treturn false;\n\t\t}\n\t}\n\n\treturn true;\n}\n\nvoid GLOffScreenBuffer::Start() {\n\tif (current < 0)\n\t\tNextBuffer();\n\n\tif (msaaSamples > 0) {\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, msaaFBO);\n\t\tglEnable(GL_MULTISAMPLE);\n\t}\n\telse {\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, pmfbo[current]);\n\t}\n\n\tisBound = true;\n\tglClearDepth(1.0f);\n\tglClear(GL_DEPTH_BUFFER_BIT);\n\n\tglViewport(0, 0, w, h);\n\tglMatrixMode(GL_PROJECTION);\n\tglLoadIdentity();\n\tglOrtho(0.0, w, 0.0, h, -1.0, 1.0);\n\tglMatrixMode(GL_MODELVIEW);\n\tglLoadIdentity();\n}\n\n// Retrieves the current texture ID.  Useful for externally selecting as a texture source before moving to another\n// buffer in a multi rendering chain.\nGLuint GLOffScreenBuffer::GetTexID() {\n\tif (current > -1)\n\t\treturn pmtex[current];\n\n\treturn 0;\n}\n\nvoid GLOffScreenBuffer::SaveTexture(const std::string& filename) {\n\tif (!isBound)\n\t\tStart(); //not bound, bind the current framebuffer to read it's pixels.\n\n\tGLubyte* pixels = new GLubyte[w * h * 4];\n\tglReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n\n\t//gli::texture TexA = gli::make_texture2d(gli::FORMAT_RGB8_UNORM_PACK8, gli::extent2d(4), 2);\n\n\t//gli::texture2d TexB(gli::FORMAT_RGBA_DXT5_UNORM_BLOCK16, gli::extent2d(32), 1);\n\t/* \n\tgli::texture2d TexB(gli::FORMAT_RGBA_DXT5_UNORM_BLOCK16, gli::texture2d::extent_type(256), 1);\n\tglm::u8vec4 * DstData = (glm::u8vec4*)TexB.data();\n\t\n\tgli::detail::dxt5_block{}\n\n\tfor (int y = 0; y < TexB.extent().y; ++y)\n\t\tfor (int x = 0; x < TexB.extent().x; ++x)\n\t\t{\n\t\t\tstd::size_t Index = x + y * TexB.extent().x;\n \t\t\t*(DstData + Index) = glm::u8vec4(255, 127, 0, 255);\n\t\t}\n\n\t\t\tfloat Value = glm::linearGradient(\n\t\t\t\t0.5f * glm::vec2(256),\n\t\t\t\t0.7f * glm::vec2(256),\n\t\t\t\tgli::vec2(x, y));\n\n\t\t\tstd::size_t Index = x + y * TexB.extent().x;\n\n\t\t\t*(DstData + Index) = glm::u8vec3(glm::u8(glm::clamp(Value * 255.f, 0.f, 255.f)));\n\t\t}\n\t*/\n\n\t//char cleary[16];\n\t//memset(cleary, 255, 16);\n\t//cleary.push_back(gli::u8vec4(255, 127, 0, 255));\n\t//cleary.push_back(gli::u8vec4(255, 127, 0, 255));\n\t//cleary.push_back(gli::u8vec4(255, 127, 0, 255));\n\t//cleary.push_back(gli::u8vec4(255, 127, 0, 255));\n\t//TexB.clear(cleary);\n\t//TexB.clear(gli::u8vec4(255, 127, 0, 255));\n\n\t//gli::load((const char*)pixels, w*h * 4));\n\t//gli::texture2d outTex = gli::convert(TexB, gli::FORMAT_RGBA_DXT5_UNORM_BLOCK16);\n\n\t//gli::save_dds(TexB, filename);\n\n\tSOIL_save_image(filename.c_str(), SOIL_SAVE_TYPE_DDS, w, h, 4, pixels);\n\n\tdelete[] pixels;\n}\n\nvoid GLOffScreenBuffer::Resolve() {\n\tif (msaaSamples > 0 && current >= 0) {\n\t\tglBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFBO);\n\t\tglBindFramebuffer(GL_DRAW_FRAMEBUFFER, pmfbo[current]);\n\t\tglBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, pmfbo[current]);\n\t}\n}\n\nvoid GLOffScreenBuffer::End() {\n\tif (msaaSamples > 0)\n\t\tglDisable(GL_MULTISAMPLE);\n\n\tglBindFramebuffer(GL_FRAMEBUFFER, 0);\n\tisBound = false;\n}\n\nGLOffScreenBuffer::~GLOffScreenBuffer() {\n\tif (isBound)\n\t\tEnd();\n\n\tif (msaaSamples > 0) {\n\t\tglDeleteRenderbuffers(1, &msaaColorRBO);\n\t\tglDeleteRenderbuffers(1, &msaaDepthRBO);\n\t\tglDeleteFramebuffers(1, &msaaFBO);\n\t}\n\n\tdeleteTextures();\n\tglDeleteRenderbuffers(1, &mrbo);\n\tglBindFramebuffer(GL_FRAMEBUFFER, 0);\n\tglDeleteFramebuffers(numBuffers, pmfbo);\n\n\tdelete[] pmfbo;\n\tdelete[] pmtex;\n}\n"
  },
  {
    "path": "src/render/GLOffscreenBuffer.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../render/GLSurface.h\"\n\n\n/*\nClass for managing offscreen rendering buffers.\nAllows more than one buffer to be created, and automatically cycled for a multipass rendering chain\nEnables exporting buffers to disk files\n*/\nclass GLOffScreenBuffer {\n\tGLSurface* glsRef = nullptr;\n\tGLuint* pmfbo = nullptr;\n\tGLuint* pmtex = nullptr;\n\tGLuint mrbo = 0;\n\tbool isBound = false;\n\tint current = -1;\n\tint numBuffers = 0;\n\tint w = 0, h = 0;\n\tint GLOBCount = 0;\n\tint msaaSamples = 0;\n\n\t// MSAA resources (only used when msaaSamples > 0)\n\tGLuint msaaFBO = 0;\n\tGLuint msaaColorRBO = 0;\n\tGLuint msaaDepthRBO = 0;\n\n\tvoid createTextures() {\n\t\tfor (int i = 0; i < numBuffers; i++) {\n\t\t\tpmtex[i] = glsRef->GetResourceLoader()->GenerateTextureID(texName(i));\n\t\t}\n\t}\n\n\t// Delete textures calls resource loader to remove textures with the appropriate name, and is only\n\t// called during destruction.\n\t//  note, you can save textures by renaming them while GLOB exists.\n\tvoid deleteTextures() {\n\t\tfor (int i = 0; i < numBuffers; i++) {\n\t\t\tglsRef->GetResourceLoader()->DeleteTexture(texName(i));\n\t\t}\n\t}\n\npublic:\n\tGLOffScreenBuffer(GLSurface* gls, int width, int height, int count = 1, const std::vector<GLuint>& texIds = std::vector<GLuint>(), int samples = 0);\n\n\tstd::string texName(int index = -1);\n\n\tbool SetCurrentBuffer(int bufferIndex = 0);\n\tbool NextBuffer(bool cycle = true);\n\tvoid Start();\n\n\t// Retrieves the current texture ID.  Useful for externally selecting as a texture source before moving to another\n\t// buffer in a multi rendering chain.\n\tGLuint GetTexID();\n\n\tvoid SaveTexture(const std::string& filename);\n\tvoid Resolve();\n\tvoid End();\n\n\t~GLOffScreenBuffer();\n};\n"
  },
  {
    "path": "src/render/GLShader.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLShader.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"Object3d.hpp\"\n\n#include <fstream>\n#include <sstream>\n\nusing namespace nifly;\n\nGLShader::GLShader(const std::string& vertexSource, const std::string& fragmentSource)\n\t: GLShader() {\n\tif (CheckExtensions() && LoadShaders(vertexSource, fragmentSource)) {\n\t\tShowLighting();\n\t\tShowTexture();\n\t\tShowMask();\n\t\tShowWeight(false);\n\t\tShowVertexColors(false);\n\t\tShowVertexAlpha(false);\n\n\t\tSetColor(Vector3(1.0f, 1.0f, 1.0f));\n\t\tSetModelSpace(false);\n\t\tSetEmissive(false);\n\t\tSetWireframeEnabled(false);\n\t\tSetLightingEnabled(true);\n\t}\n}\n\nbool GLShader::extChecked = false;\n\nbool GLShader::CheckExtensions() {\n\tif (!extChecked) {\n\t\tif (!extSupported) {\n\t\t\terrorState = 1;\n\t\t\terrorString = \"OpenGL: One or more extensions are not supported.\";\n\t\t}\n\n\t\textChecked = true;\n\t}\n\n\treturn extSupported;\n}\n\nbool GLShader::LoadShaderFile(const std::string& fileName, std::string& text) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios_base::in | std::ios_base::binary);\n\tif (!file)\n\t\treturn false;\n\n\tstd::stringstream buffer;\n\tbuffer << file.rdbuf();\n\n\ttext = buffer.str();\n\n\tif (text.empty())\n\t\treturn false;\n\n\treturn true;\n}\n\nbool GLShader::LoadShaders(const std::string& vertexSource, const std::string& fragmentSource) {\n\tif (!LoadShaderFile(vertexSource, vertSrc)) {\n\t\terrorState = 2;\n\t\terrorString = \"OpenGL: Failed to load vertex shader from file: \" + vertexSource;\n\t\treturn false;\n\t}\n\n\tif (!LoadShaderFile(fragmentSource, fragSrc)) {\n\t\terrorState = 3;\n\t\terrorString = \"OpenGL: Failed to load fragment shader from file: \" + fragmentSource;\n\t\treturn false;\n\t}\n\n\treturn BuildShaders();\n}\n\nvoid GLShader::SetColor(const Vector3& color) {\n\tGLint loc = glGetUniformLocation(progID, \"color\");\n\tif (loc >= 0)\n\t\tglUniform3f(loc, color.x, color.y, color.z);\n}\n\nvoid GLShader::SetSubColor(const Vector3& color) {\n\tGLint loc = glGetUniformLocation(progID, \"subColor\");\n\tif (loc >= 0)\n\t\tglUniform3f(loc, color.x, color.y, color.z);\n}\n\nvoid GLShader::SetModelSpace(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bModelSpace\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetEmissive(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bEmissive\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetWireframeEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bWireframe\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetLightingEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bLighting\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetMatrixProjection(const glm::mat4x4& mat) {\n\tGLint loc = glGetUniformLocation(progID, \"matProjection\");\n\tif (loc >= 0)\n\t\tglUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*)&mat);\n}\n\nvoid GLShader::SetMatrixModelView(const glm::mat4x4& matView, const glm::mat4x4& matModel) {\n\tGLint loc = glGetUniformLocation(progID, \"matView\");\n\tif (loc >= 0)\n\t\tglUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*)&matView);\n\n\tloc = glGetUniformLocation(progID, \"matModel\");\n\tif (loc >= 0)\n\t\tglUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*)&matModel);\n\n\tloc = glGetUniformLocation(progID, \"matModelView\");\n\tif (loc >= 0) {\n\t\tglm::mat4x4 matModelView = matView * matModel;\n\t\tglUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*)&matModelView);\n\t\tloc = glGetUniformLocation(progID, \"matModelViewInverse\");\n\t\tif (loc >= 0) {\n\t\t\tglm::mat4x4 matModelViewInverse = glm::inverse(matModelView);\n\t\t\tglUniformMatrix4fv(loc, 1, GL_FALSE, (GLfloat*)&matModelViewInverse);\n\t\t}\n\t\tloc = glGetUniformLocation(progID, \"mv_normalMatrix\");\n\t\tif (loc >= 0) {\n\t\t\tglm::mat3x3 mv_normalMatrix = glm::transpose(glm::inverse(glm::mat3(matModelView)));\n\t\t\tglUniformMatrix3fv(loc, 1, GL_FALSE, (GLfloat*)&mv_normalMatrix);\n\t\t}\n\t}\n}\n\nvoid GLShader::SetAlphaProperties(const uint16_t flags, const float threshold, const float value) {\n\tstatic const GLenum blendMap[16] = {GL_ONE,\n\t\t\t\t\t\t\t\t\t\tGL_ZERO,\n\t\t\t\t\t\t\t\t\t\tGL_SRC_COLOR,\n\t\t\t\t\t\t\t\t\t\tGL_ONE_MINUS_SRC_COLOR,\n\t\t\t\t\t\t\t\t\t\tGL_DST_COLOR,\n\t\t\t\t\t\t\t\t\t\tGL_ONE_MINUS_DST_COLOR,\n\t\t\t\t\t\t\t\t\t\tGL_SRC_ALPHA,\n\t\t\t\t\t\t\t\t\t\tGL_ONE_MINUS_SRC_ALPHA,\n\t\t\t\t\t\t\t\t\t\tGL_DST_ALPHA,\n\t\t\t\t\t\t\t\t\t\tGL_ONE_MINUS_DST_ALPHA,\n\t\t\t\t\t\t\t\t\t\tGL_SRC_ALPHA_SATURATE,\n\t\t\t\t\t\t\t\t\t\tGL_ONE,\n\t\t\t\t\t\t\t\t\t\tGL_ONE,\n\t\t\t\t\t\t\t\t\t\tGL_ONE,\n\t\t\t\t\t\t\t\t\t\tGL_ONE,\n\t\t\t\t\t\t\t\t\t\tGL_ONE};\n\n\t//static const GLenum testMap[8] = {\n\t//\tGL_ALWAYS, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_NEVER\n\t//};\n\n\tbool alphaBlend = flags & 1;\n\tbool alphaTest = (flags & (1 << 9)) != 0;\n\tGLenum alphaSrc = blendMap[(flags >> 1) & 0x0F];\n\tGLenum alphaDst = blendMap[(flags >> 5) & 0x0F];\n\n\t//Always GL_GREATER right now\n\t//GLenum alphaFunc = testMap[(flags >> 10) & 0x7];\n\n\tglDisable(GL_BLEND);\n\n\tif (alphaBlend) {\n\t\tglEnable(GL_BLEND);\n\t\tglBlendFunc(alphaSrc, alphaDst);\n\t}\n\n\tif (!alphaBlend && value < 1.0f) {\n\t\tglEnable(GL_BLEND);\n\t\tglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t}\n\n\tif (alphaTest)\n\t\tSetAlphaThreshold(threshold);\n\telse\n\t\tSetAlphaThreshold(-1.0f);\n}\n\nvoid GLShader::SetAlphaThreshold(const float threshold) {\n\tGLint loc = glGetUniformLocation(progID, \"alphaThreshold\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, threshold);\n}\n\nvoid GLShader::SetAdjustPointSize(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bAdjustPointSize\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetFrontalLight(const DirectionalLight& light) {\n\tGLint loc = glGetUniformLocation(progID, \"frontal.diffuse\");\n\tif (loc >= 0)\n\t\tglUniform3f(loc, light.diffuse.x, light.diffuse.y, light.diffuse.z);\n\n\tloc = glGetUniformLocation(progID, \"frontal.direction\");\n\tif (loc >= 0)\n\t\tglUniform3f(loc, 0.0f, 0.0f, 1.0f);\n}\n\nvoid GLShader::SetDirectionalLight(const DirectionalLight& light, const int index) {\n\tGLint locDiffuse = -1;\n\tGLint locDirection = -1;\n\n\tif (index == 0) {\n\t\tlocDiffuse = glGetUniformLocation(progID, \"directional0.diffuse\");\n\t\tlocDirection = glGetUniformLocation(progID, \"directional0.direction\");\n\t}\n\telse if (index == 1) {\n\t\tlocDiffuse = glGetUniformLocation(progID, \"directional1.diffuse\");\n\t\tlocDirection = glGetUniformLocation(progID, \"directional1.direction\");\n\t}\n\telse if (index == 2) {\n\t\tlocDiffuse = glGetUniformLocation(progID, \"directional2.diffuse\");\n\t\tlocDirection = glGetUniformLocation(progID, \"directional2.direction\");\n\t}\n\n\tif (locDiffuse >= 0)\n\t\tglUniform3f(locDiffuse, light.diffuse.x, light.diffuse.y, light.diffuse.z);\n\n\tif (locDirection >= 0)\n\t\tglUniform3f(locDirection, light.direction.x, light.direction.y, light.direction.z);\n}\n\nvoid GLShader::SetAmbientLight(const float light) {\n\tGLint loc = glGetUniformLocation(progID, \"ambient\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, light);\n}\n\nvoid GLShader::SetProperties(const Mesh::ShaderProperties& prop) {\n\tGLint loc = glGetUniformLocation(progID, \"prop.uvOffset\");\n\tif (loc >= 0)\n\t\tglUniform2f(loc, prop.uvOffset.u, prop.uvOffset.v);\n\n\tloc = glGetUniformLocation(progID, \"prop.uvScale\");\n\tif (loc >= 0)\n\t\tglUniform2f(loc, prop.uvScale.u, prop.uvScale.v);\n\n\tloc = glGetUniformLocation(progID, \"prop.specularColor\");\n\tif (loc >= 0)\n\t\tglUniform3f(loc, prop.specularColor.x, prop.specularColor.y, prop.specularColor.z);\n\n\tloc = glGetUniformLocation(progID, \"prop.specularStrength\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.specularStrength);\n\n\tloc = glGetUniformLocation(progID, \"prop.shininess\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.shininess);\n\n\tloc = glGetUniformLocation(progID, \"prop.envReflection\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.envReflection);\n\n\tloc = glGetUniformLocation(progID, \"prop.emissiveColor\");\n\tif (loc >= 0)\n\t\tglUniform3f(loc, prop.emissiveColor.x, prop.emissiveColor.y, prop.emissiveColor.z);\n\n\tloc = glGetUniformLocation(progID, \"prop.emissiveMultiple\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.emissiveMultiple);\n\n\tloc = glGetUniformLocation(progID, \"prop.alpha\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.alpha);\n\n\tloc = glGetUniformLocation(progID, \"prop.backlightPower\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.backlightPower);\n\n\tloc = glGetUniformLocation(progID, \"prop.rimlightPower\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.rimlightPower);\n\n\tloc = glGetUniformLocation(progID, \"prop.softlighting\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.softlighting);\n\n\tloc = glGetUniformLocation(progID, \"prop.subsurfaceRolloff\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.subsurfaceRolloff);\n\n\tloc = glGetUniformLocation(progID, \"prop.fresnelPower\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.fresnelPower);\n\n\tloc = glGetUniformLocation(progID, \"prop.paletteScale\");\n\tif (loc >= 0)\n\t\tglUniform1f(loc, prop.paletteScale);\n}\n\nvoid GLShader::ShowLighting(bool bShow) {\n\tGLint loc = glGetUniformLocation(progID, \"bLightEnabled\");\n\n\tif (loc >= 0) {\n\t\tglUseProgram(progID);\n\t\tglUniform1i(loc, bShow ? GL_TRUE : GL_FALSE);\n\t\tglUseProgram(0);\n\t}\n}\n\nvoid GLShader::ShowMask(bool bShow) {\n\tGLint loc = glGetUniformLocation(progID, \"bShowMask\");\n\n\tif (loc >= 0) {\n\t\tglUseProgram(progID);\n\t\tglUniform1i(loc, bShow ? GL_TRUE : GL_FALSE);\n\t\tglUseProgram(0);\n\t}\n}\n\nvoid GLShader::ShowWeight(bool bShow) {\n\tGLint loc = glGetUniformLocation(progID, \"bShowWeight\");\n\n\tif (loc >= 0) {\n\t\tglUseProgram(progID);\n\t\tglUniform1i(loc, bShow ? GL_TRUE : GL_FALSE);\n\t\tglUseProgram(0);\n\t}\n}\n\nvoid GLShader::ShowVertexColors(bool bShow) {\n\tGLint loc = glGetUniformLocation(progID, \"bShowVertexColor\");\n\n\tif (loc >= 0) {\n\t\tglUseProgram(progID);\n\t\tglUniform1i(loc, bShow ? GL_TRUE : GL_FALSE);\n\t\tglUseProgram(0);\n\t}\n}\n\nvoid GLShader::ShowVertexAlpha(bool bShow) {\n\tGLint loc = glGetUniformLocation(progID, \"bShowVertexAlpha\");\n\n\tif (loc >= 0) {\n\t\tglUseProgram(progID);\n\t\tglUniform1i(loc, bShow ? GL_TRUE : GL_FALSE);\n\t\tglUseProgram(0);\n\t}\n}\n\nvoid GLShader::ShowTexture(bool bShow) {\n\tGLint loc = glGetUniformLocation(progID, \"bShowTexture\");\n\tif (loc >= 0) {\n\t\tglUseProgram(progID);\n\t\tglUniform1i(loc, bShow ? GL_TRUE : GL_FALSE);\n\t\tglUseProgram(0);\n\t}\n}\n\nvoid GLShader::SetNormalMapEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bNormalMap\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetAlphaMaskEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bAlphaMask\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetGreyscaleColorEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bGreyscaleColor\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetCubemapEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bCubemap\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetEnvMaskEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bEnvMask\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetSpecularEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bSpecular\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetBacklightEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bBacklight\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetRimlightEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bRimlight\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetSoftlightEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bSoftlight\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::SetGlowmapEnabled(const bool enable) {\n\tGLint loc = glGetUniformLocation(progID, \"bGlowmap\");\n\tif (loc >= 0)\n\t\tglUniform1i(loc, enable ? GL_TRUE : GL_FALSE);\n}\n\nvoid GLShader::BindTexture(const GLint& index, const GLuint& texture, const char* samplerName) {\n\tGLint texLoc = glGetUniformLocation(progID, samplerName);\n\tif (texLoc >= 0) {\n\t\tglUniform1i(texLoc, index);\n\t\tglActiveTexture(GL_TEXTURE0 + index);\n\n\t\tglBindTexture(GL_TEXTURE_2D, texture);\n\t}\n}\n\nvoid GLShader::BindCubemap(const GLint& index, const GLuint& texture, const char* samplerName) {\n\tGLint texLoc = glGetUniformLocation(progID, samplerName);\n\tif (texLoc >= 0) {\n\t\tglUniform1i(texLoc, index);\n\t\tglActiveTexture(GL_TEXTURE0 + index);\n\n\t\tglBindTexture(GL_TEXTURE_CUBE_MAP, texture);\n\t}\n}\n\nbool GLShader::GetError(std::string* errorStr) {\n\tif (!errorState)\n\t\treturn false;\n\n\tif (errorStr)\n\t\t(*errorStr) = errorString;\n\n\treturn true;\n}\n\nbool GLShader::BuildShaders() {\n\tGLint compiled;\n\tGLint loglength;\n\n\tconst GLchar* src = vertSrc.c_str();\n\tvertShadID = glCreateShader(GL_VERTEX_SHADER);\n\tglShaderSource(vertShadID, 1, &src, nullptr);\n\n\tglCompileShader(vertShadID);\n\tglGetShaderiv(vertShadID, GL_COMPILE_STATUS, &compiled);\n\tif (!compiled) {\n\t\tglGetShaderiv(vertShadID, GL_INFO_LOG_LENGTH, &loglength);\n\t\tGLchar* logdata = new GLchar[loglength];\n\t\tglGetShaderInfoLog(vertShadID, loglength, nullptr, logdata);\n\t\terrorString = std::string(\"OpenGL: Vertex shader compile failed: \") + logdata;\n\t\tdelete[] logdata;\n\n\t\terrorState = 2;\n\t\treturn false;\n\t}\n\n\tsrc = fragSrc.c_str();\n\tfragShadID = glCreateShader(GL_FRAGMENT_SHADER);\n\tglShaderSource(fragShadID, 1, &src, nullptr);\n\n\tglCompileShader(fragShadID);\n\tglGetShaderiv(fragShadID, GL_COMPILE_STATUS, &compiled);\n\tif (!compiled) {\n\t\tglGetShaderiv(fragShadID, GL_INFO_LOG_LENGTH, &loglength);\n\t\tGLchar* logdata = new GLchar[loglength];\n\t\tglGetShaderInfoLog(fragShadID, loglength, nullptr, logdata);\n\t\terrorString = std::string(\"OpenGL: Fragment shader compile failed: \") + logdata;\n\t\tdelete[] logdata;\n\n\t\terrorState = 3;\n\t\treturn false;\n\t}\n\n\tprogID = glCreateProgram();\n\n\tglAttachShader(progID, vertShadID);\n\tglAttachShader(progID, fragShadID);\n\n\tglLinkProgram(progID);\n\tglGetProgramiv(progID, GL_LINK_STATUS, &compiled);\n\tif (!compiled) {\n\t\tglGetProgramiv(progID, GL_INFO_LOG_LENGTH, &loglength);\n\t\tGLchar* logdata = new GLchar[loglength];\n\t\tglGetProgramInfoLog(progID, loglength, nullptr, logdata);\n\t\terrorString = std::string(\"OpenGL: Shader program link failed: \") + logdata;\n\t\tdelete[] logdata;\n\n\t\terrorState = 4;\n\t\treturn false;\n\t}\n\n\terrorString = \"OpenGL: Shader program ready.\";\n\terrorState = 0;\n\treturn true;\n}\n\nint GLShader::Begin() {\n\tif (errorState == 0)\n\t\tglUseProgram(progID);\n\n\treturn !errorState;\n}\n\nvoid GLShader::End() {\n\tglUseProgram(0);\n}\n"
  },
  {
    "path": "src/render/GLShader.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../components/Mesh.h\"\n#include \"GLExtensions.h\"\n\nclass GLShader {\n\tstatic bool extChecked;\n\n\t// Source text for shaders\n\tstd::string vertSrc;\n\tstd::string fragSrc;\n\n\t// Compiled shader IDs after compile.\n\tGLuint vertShadID = 0;\n\tGLuint fragShadID = 0;\n\tGLint vertShadLength = 0;\n\tGLint fragShadLength = 0;\n\n\t// Linked Program ID after program creation.\n\tGLuint progID = 0;\n\n\t/* error state, set if compile/link fails.  check errorstring for compile log\n\t\t-1 = initial state -- not ready\n\t\t0 = no error, shader ready\n\t\t1 = shaders not supported,\n\t\t2 = vertex shader compile failed,\n\t\t3 = fragment shader compile failed,\n\t\t4 = program link failed.\n\t\t*/\n\tint errorState = -1;\n\tstd::string errorString;\n\n\tbool CheckExtensions();\n\tbool LoadShaderFile(const std::string& fileName, std::string& text);\n\n\t// Attempts to load the specified source files (in text format).\n\tbool LoadShaders(const std::string& vertexSource, const std::string& fragmentSource);\n\n\t// Compiles and links the loaded shaders, generating a program that can be activated.\n\tbool BuildShaders();\n\npublic:\n\tstruct DirectionalLight {\n\t\tnifly::Vector3 diffuse;\n\t\tnifly::Vector3 direction;\n\t};\n\n\tGLShader() {}\n\n\t// Creates the shader object and runs LoadShaders followed by BuildShaders.\n\tGLShader(const std::string& vertexSource, const std::string& fragmentSource);\n\n\tvoid SetColor(const nifly::Vector3& color);\n\tvoid SetSubColor(const nifly::Vector3& color);\n\tvoid SetModelSpace(const bool enable);\n\tvoid SetEmissive(const bool enable);\n\tvoid SetWireframeEnabled(const bool enable);\n\tvoid SetLightingEnabled(const bool enable);\n\tvoid SetMatrixProjection(const glm::mat4x4& mat);\n\tvoid SetMatrixModelView(const glm::mat4x4& matView, const glm::mat4x4& matModel);\n\tvoid SetAlphaProperties(const uint16_t flags, const float threshold, const float value);\n\tvoid SetAlphaThreshold(const float threshold);\n\tvoid SetAdjustPointSize(const bool enable);\n\n\tvoid SetFrontalLight(const DirectionalLight& light);\n\tvoid SetDirectionalLight(const DirectionalLight& light, const int index);\n\tvoid SetAmbientLight(const float light);\n\tvoid SetProperties(const Mesh::ShaderProperties& prop);\n\n\tvoid ShowLighting(bool bShow = true);\n\tvoid ShowMask(bool bShow = true);\n\tvoid ShowWeight(bool bShow = true);\n\tvoid ShowVertexColors(bool bShow = true);\n\tvoid ShowVertexAlpha(bool bShow = true);\n\tvoid ShowTexture(bool bShow = true);\n\n\tvoid SetNormalMapEnabled(const bool enable);\n\tvoid SetAlphaMaskEnabled(const bool enable);\n\tvoid SetGreyscaleColorEnabled(const bool enable);\n\tvoid SetCubemapEnabled(const bool enable);\n\tvoid SetEnvMaskEnabled(const bool enable);\n\tvoid SetSpecularEnabled(const bool enable);\n\tvoid SetBacklightEnabled(const bool enable);\n\tvoid SetRimlightEnabled(const bool enable);\n\tvoid SetSoftlightEnabled(const bool enable);\n\tvoid SetGlowmapEnabled(const bool enable);\n\tvoid BindTexture(const GLint& index, const GLuint& texture, const char* samplerName);\n\tvoid BindCubemap(const GLint& index, const GLuint& texture, const char* samplerName);\n\n\tbool GetError(std::string* errorStr = nullptr);\n\n\t// Activates the stored program for subsequent GL rendering calls.\n\tint Begin();\n\n\t// Turns off the stored program.\n\tvoid End();\n};\n"
  },
  {
    "path": "src/render/GLSurface.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"GLSurface.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <wx/log.h>\n#include <wx/msgdlg.h>\n\n#include <algorithm>\n#include <limits>\n#include <set>\n\nusing namespace nifly;\n\nextern ConfigurationManager Config;\n\nconst wxGLAttributes& GLSurface::GetGLAttribs() {\n\tstatic bool attribsInitialized{false};\n\tstatic wxGLAttributes attribs;\n\n\tif (!attribsInitialized) {\n\t\t// 16x AA\n\t\tattribs.PlatformDefaults().DoubleBuffer().RGBA().Depth(24).SampleBuffers(1).Samplers(16).EndList();\n\n\t\tbool displaySupported = wxGLCanvas::IsDisplaySupported(attribs);\n\t\tif (!displaySupported) {\n\t\t\twxLogWarning(\"OpenGL attributes with 16x AA not supported. Trying out different ones...\");\n\t\t\tattribs.Reset();\n\n\t\t\t// 8x AA\n\t\t\tattribs.PlatformDefaults().DoubleBuffer().RGBA().Depth(24).SampleBuffers(1).Samplers(8).EndList();\n\t\t\tdisplaySupported = wxGLCanvas::IsDisplaySupported(attribs);\n\t\t}\n\n\t\tif (!displaySupported) {\n\t\t\twxLogWarning(\"OpenGL attributes with 8x AA not supported. Trying out different ones...\");\n\t\t\tattribs.Reset();\n\n\t\t\t// 4x AA\n\t\t\tattribs.PlatformDefaults().DoubleBuffer().RGBA().Depth(24).SampleBuffers(1).Samplers(4).EndList();\n\t\t\tdisplaySupported = wxGLCanvas::IsDisplaySupported(attribs);\n\t\t}\n\n\t\tif (!displaySupported) {\n\t\t\twxLogWarning(\"OpenGL attributes with 4x AA not supported. Trying out different ones...\");\n\t\t\tattribs.Reset();\n\n\t\t\t// No AA\n\t\t\tattribs.PlatformDefaults().DoubleBuffer().RGBA().Depth(24).SampleBuffers(0).EndList();\n\t\t\tdisplaySupported = wxGLCanvas::IsDisplaySupported(attribs);\n\t\t}\n\n\t\tif (!displaySupported)\n\t\t\twxLogWarning(\"No supported OpenGL attributes could be found!\");\n\t\telse\n\t\t\twxLogMessage(\"OpenGL attributes are supported.\");\n\n\t\tattribsInitialized = true;\n\t}\n\n\treturn attribs;\n}\n\nconst wxGLContextAttrs& GLSurface::GetGLContextAttribs() {\n\tstatic bool ctxAttribsInitialized{false};\n\tstatic wxGLContextAttrs ctxAttribs;\n\n\tif (!ctxAttribsInitialized) {\n\t\tctxAttribs.PlatformDefaults().CoreProfile().OGLVersion(3, 3).EndList();\n\t\tctxAttribsInitialized = true;\n\t}\n\n\treturn ctxAttribs;\n}\n\nvoid GLSurface::InitLighting() {\n\tambientLight = 0.2f;\n\n\tfrontalLight.diffuse = Vector3(0.2f, 0.2f, 0.2f);\n\n\tdirectionalLight0.diffuse = Vector3(0.6f, 0.6f, 0.6f);\n\tdirectionalLight0.direction = Vector3(-0.90f, 0.1f, 1.0f);\n\tdirectionalLight0.direction.Normalize();\n\n\tdirectionalLight1.diffuse = Vector3(0.6f, 0.6f, 0.6f);\n\tdirectionalLight1.direction = Vector3(0.70f, 0.1f, 1.0f);\n\tdirectionalLight1.direction.Normalize();\n\n\tdirectionalLight2.diffuse = Vector3(0.85f, 0.85f, 0.85f);\n\tdirectionalLight2.direction = Vector3(0.3f, 0.2f, -1.0f);\n\tdirectionalLight2.direction.Normalize();\n}\n\nint GLSurface::Initialize(wxGLCanvas* can, wxGLContext* ctx) {\n\tcanvas = can;\n\tcontext = ctx;\n\n\tcanvas->SetCurrent(*context);\n\n\twxLogMessage(\"OpenGL Context Info:\");\n\twxLogMessage(wxString::Format(\"-> Vendor:   '%s'\", wxString(glGetString(GL_VENDOR))));\n\twxLogMessage(wxString::Format(\"-> Renderer: '%s'\", wxString(glGetString(GL_RENDERER))));\n\twxLogMessage(wxString::Format(\"-> Version:  '%s'\", wxString(glGetString(GL_VERSION))));\n\n\tInitGLExtensions();\n\treturn InitGLSettings();\n}\n\nvoid GLSurface::InitGLExtensions() {\n\tInitExtensions();\n\tif (IsExtensionSupported(\"GL_EXT_texture_filter_anisotropic\"))\n\t\tglGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largestAF);\n}\n\nint GLSurface::InitGLSettings() {\n\tglShadeModel(GL_SMOOTH);\n\n\tglClearDepth(1.0f);\n\tglEnable(GL_DEPTH_TEST);\n\tglDepthFunc(GL_LEQUAL);\n\tglEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);\n\n\t// Get supported line width range\n\tGLfloat lineRange[2];\n\tglGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, lineRange);\n\n\tif (lineRange[0] > 1.0f)\n\t\tdefLineWidth = lineRange[0];\n\telse if (lineRange[1] < 1.0f)\n\t\tdefLineWidth = lineRange[1];\n\telse\n\t\tdefLineWidth = 1.0f;\n\n\t// Get supported point size range\n\tGLfloat pointRange[2];\n\tglGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, pointRange);\n\n\tif (pointRange[0] > 5.0f)\n\t\tdefPointSize = pointRange[0];\n\telse if (pointRange[1] < 5.0f)\n\t\tdefPointSize = pointRange[1];\n\telse\n\t\tdefPointSize = 5.0f;\n\n\tglLineWidth(defLineWidth);\n\tglPointSize(defPointSize);\n\n\tInitLighting();\n\n\treturn 0;\n}\n\nvoid GLSurface::Cleanup() {\n\t// Set current context for resource deletion\n\tSetContext();\n\n\tfor (auto& m : meshes)\n\t\tdelete m;\n\n\tfor (auto& o : overlays)\n\t\tdelete o;\n\n\tmeshes.clear();\n\toverlays.clear();\n\tactiveMeshes.clear();\n\n\tselectedMesh = nullptr;\n\n\tif (pointsMat) {\n\t\tdelete pointsMat;\n\t\tpointsMat = nullptr;\n\t}\n\n\tif (primitiveMat) {\n\t\tdelete primitiveMat;\n\t\tprimitiveMat = nullptr;\n\t}\n\n\tresLoader.Cleanup();\n}\n\nvoid GLSurface::SetStartingView(const Vector3& pos, const Vector3& rot, const uint32_t& vpWidth, const uint32_t& vpHeight, const float& fov) {\n\tperspective = true;\n\tcamPos = pos;\n\tcamOffset.Zero();\n\tcamRot = rot;\n\tcamRotOffset.Zero();\n\tvpW = vpWidth;\n\tvpH = vpHeight;\n\tmFov = fov;\n\tSetSize(vpWidth, vpHeight);\n}\n\nvoid GLSurface::TurnTableCamera(int dScreenX) {\n\tfloat pct = (float)dScreenX / (float)vpW;\n\tcamRot.y += (pct * 500.0f);\n}\n\nvoid GLSurface::PitchCamera(int dScreenY) {\n\tfloat pct = (float)dScreenY / (float)vpH;\n\tcamRot.x += (pct * 500.0f);\n\tif (camRot.x > 80.0f)\n\t\tcamRot.x = 80.0f;\n\tif (camRot.x < -80.0f)\n\t\tcamRot.x = -80.0f;\n}\n\nvoid GLSurface::PanCamera(int dScreenX, int dScreenY) {\n\tfloat fabsZ = fabs(camPos.z);\n\tif (fabsZ < 0.5f)\n\t\tfabsZ = 0.5f;\n\n\tcamPos.y -= ((float)dScreenY / vpH) * fabsZ;\n\tcamPos.x += ((float)dScreenX / vpW) * fabsZ;\n}\n\nvoid GLSurface::DollyCamera(int dAmt) {\n\tcamPos.z += (float)dAmt / 200.0f;\n}\n\nvoid GLSurface::ClampCameraPosition(char axis, float lower, float upper) {\n\tswitch (axis) {\n\t\tcase 'X': camPos.x = std::max(lower, std::min(camPos.x, upper)); break;\n\t\tcase 'Y': camPos.y = std::max(lower, std::min(camPos.y, upper)); break;\n\t\tcase 'Z': camPos.z = std::max(lower, std::min(camPos.z, upper)); break;\n\t}\n}\n\nvoid GLSurface::UnprojectCamera(Vector3& result) {\n\tglm::vec4 vp(0.0f, 0.0f, (float)vpW, (float)vpH);\n\tglm::vec3 win(vp[2] / 2.0f, vp[3] / 2.0f, 0.0f);\n\tglm::vec3 res = glm::unProject(win, matView, matProjection, vp);\n\n\tresult.x = res.x;\n\tresult.y = res.y;\n\tresult.z = res.z;\n}\n\nvoid GLSurface::SetView(const char type) {\n\tcamRotOffset.Zero();\n\n\tif (type == 'F') {\n\t\tcamPos = Vector3(0.0f, -5.0f, -15.0f);\n\t\tcamRot.Zero();\n\t}\n\telse if (type == 'B') {\n\t\tcamPos = Vector3(0.0f, -5.0f, -15.0f);\n\t\tcamRot = Vector3(0.0f, 180.0f, 0.0f);\n\t}\n\telse if (type == 'L') {\n\t\tcamPos = Vector3(0.0f, -5.0f, -15.0f);\n\t\tcamRot = Vector3(0.0f, -90.0f, 0.0f);\n\t}\n\telse if (type == 'R') {\n\t\tcamPos = Vector3(0.0f, -5.0f, -15.0f);\n\t\tcamRot = Vector3(0.0f, 90.0f, 0.0f);\n\t}\n}\n\nvoid GLSurface::SetPerspective(const bool enabled) {\n\tperspective = enabled;\n}\n\nvoid GLSurface::SetFieldOfView(const int fieldOfView) {\n\tmFov = fieldOfView;\n}\n\nvoid GLSurface::SetDepthClip(const float pzNear, const float pzFar) {\n\tzNear = pzNear;\n\tzFar = pzFar;\n}\n\nvoid GLSurface::UpdateLights(const int ambient,\n\t\t\t\t\t\t\t const int frontal,\n\t\t\t\t\t\t\t const int directional0,\n\t\t\t\t\t\t\t const int directional1,\n\t\t\t\t\t\t\t const int directional2,\n\t\t\t\t\t\t\t const Vector3& directional0Dir,\n\t\t\t\t\t\t\t const Vector3& directional1Dir,\n\t\t\t\t\t\t\t const Vector3& directional2Dir) {\n\tambientLight = 0.01f * ambient;\n\tfrontalLight.diffuse = Vector3(0.01f * frontal, 0.01f * frontal, 0.01f * frontal);\n\tdirectionalLight0.diffuse = Vector3(0.01f * directional0, 0.01f * directional0, 0.01f * directional0);\n\tdirectionalLight1.diffuse = Vector3(0.01f * directional1, 0.01f * directional1, 0.01f * directional1);\n\tdirectionalLight2.diffuse = Vector3(0.01f * directional2, 0.01f * directional2, 0.01f * directional2);\n\n\tif (Vector3() != directional0Dir)\n\t\tdirectionalLight0.direction = directional0Dir;\n\tif (Vector3() != directional1Dir)\n\t\tdirectionalLight1.direction = directional1Dir;\n\tif (Vector3() != directional2Dir)\n\t\tdirectionalLight2.direction = directional2Dir;\n\n\tdirectionalLight0.direction.Normalize();\n\tdirectionalLight1.direction.Normalize();\n\tdirectionalLight2.direction.Normalize();\n}\n\nvoid GLSurface::ProjectPointToScreen(const Vector3& p, int& x, int& y) {\n\tglm::vec4 vp(0.0f, 0.0f, (float)vpW, (float)vpH);\n\tglm::vec3 sp(p.x, p.y, p.z);\n\tglm::vec3 res = glm::project(sp, matView, matProjection, vp);\n\tx = std::round(res.x);\n\ty = std::round(vpH - res.y);\n}\n\nvoid GLSurface::GetPickRay(int ScreenX, int ScreenY, Mesh* m, Vector3& dirVect, Vector3& outNearPos) {\n\tglm::vec4 vp(0.0f, 0.0f, (float)vpW, (float)vpH);\n\tglm::vec3 winS(ScreenX, vp[3] - ScreenY, 0.0f);\n\tglm::vec3 winD(ScreenX, vp[3] - ScreenY, 1.0f);\n\n\tauto resS = glm::vec3();\n\tauto resD = glm::vec3();\n\tif (m) {\n\t\tresS = glm::unProject(winS, matView * m->matModel, matProjection, vp);\n\t\tresD = glm::unProject(winD, matView * m->matModel, matProjection, vp);\n\t}\n\telse {\n\t\tresS = glm::unProject(winS, matView, matProjection, vp);\n\t\tresD = glm::unProject(winD, matView, matProjection, vp);\n\t}\n\n\tdirVect.x = resD.x - resS.x;\n\tdirVect.y = resD.y - resS.y;\n\tdirVect.z = resD.z - resS.z;\n\n\toutNearPos.x = resS.x;\n\toutNearPos.y = resS.y;\n\toutNearPos.z = resS.z;\n\n\tdirVect.Normalize();\n}\n\nMesh* GLSurface::PickMesh(int ScreenX, int ScreenY) {\n\tVector3 o;\n\tVector3 d;\n\tfloat curd = FLT_MAX;\n\tMesh* pickedMesh = nullptr;\n\n\tstd::vector<IntersectResult> results;\n\n\tfor (auto& m : meshes) {\n\t\tresults.clear();\n\t\tif (!m->bVisible || !m->bvh)\n\t\t\tcontinue;\n\n\t\tGetPickRay(ScreenX, ScreenY, m, d, o);\n\n\t\tif (m->bvh->IntersectRay(o, d, &results)) {\n\t\t\tif (results[0].HitDistance < curd) {\n\t\t\t\tpickedMesh = m;\n\t\t\t\tcurd = results[0].HitDistance;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn pickedMesh;\n}\n\nbool GLSurface::CollideMeshes(int ScreenX, int ScreenY, Vector3& outOrigin, Vector3& outNormal, bool mirrored, Mesh** hitMesh, bool allMeshes, int* outFacet) {\n\tif (activeMeshes.empty())\n\t\treturn false;\n\n\tbool collided = false;\n\tstd::unordered_map<Mesh*, float> allHitDistances;\n\tfor (auto& m : activeMeshes) {\n\t\tif (!m->bvh)\n\t\t\tcontinue;\n\n\t\tif (!allMeshes && m != selectedMesh)\n\t\t\tcontinue;\n\n\t\tVector3 d;\n\t\tVector3 o;\n\n\t\tGetPickRay(ScreenX, ScreenY, nullptr, d, o);\n\t\tif (mirrored) {\n\t\t\td.x *= -1.0f;\n\t\t\to.x *= -1.0f;\n\t\t}\n\t\to = m->TransformPosModelToMesh(o);\n\t\td = m->TransformDirModelToMesh(d);\n\n\t\tstd::vector<IntersectResult> results;\n\t\tif (m->bvh->IntersectRay(o, d, &results)) {\n\t\t\tif (results.size() > 0) {\n\t\t\t\tif (!m->bVisible)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcollided = true;\n\n\t\t\t\tsize_t min_i = 0;\n\t\t\t\tfloat minDist = results[0].HitDistance;\n\t\t\t\tfor (size_t i = 1; i < results.size(); i++) {\n\t\t\t\t\tif (results[i].HitDistance < minDist) {\n\t\t\t\t\t\tminDist = results[i].HitDistance;\n\t\t\t\t\t\tmin_i = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tVector3 origin = results[min_i].HitCoord;\n\n\t\t\t\tbool closest = true;\n\t\t\t\tfloat viewDistance = origin.DistanceTo(o);\n\n\t\t\t\tfor (auto& p : allHitDistances)\n\t\t\t\t\tif (viewDistance > p.second)\n\t\t\t\t\t\tclosest = false;\n\n\t\t\t\tallHitDistances[m] = viewDistance;\n\n\t\t\t\tif (closest) {\n\t\t\t\t\toutOrigin = origin;\n\n\t\t\t\t\tif (outFacet)\n\t\t\t\t\t\t(*outFacet) = results[min_i].HitFacet;\n\n\t\t\t\t\toutNormal = m->tris[results[min_i].HitFacet].trinormal(m->verts.get());\n\n\t\t\t\t\tif (hitMesh)\n\t\t\t\t\t\t(*hitMesh) = m;\n\n\t\t\t\t\tif (!allMeshes)\n\t\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collided;\n}\n\nbool GLSurface::CollideOverlay(int ScreenX, int ScreenY, Vector3& outOrigin, Vector3& outNormal, Mesh** hitMesh, int* outFacet) {\n\tbool collided = false;\n\tstd::unordered_map<Mesh*, float> allHitDistances;\n\tfor (auto& ov : overlays) {\n\t\tstd::vector<IntersectResult> results;\n\t\tif (!ov->bvh)\n\t\t\tcontinue;\n\n\t\tVector3 o;\n\t\tVector3 d;\n\t\tGetPickRay(ScreenX, ScreenY, ov, d, o);\n\n\t\tif (ov->bvh->IntersectRay(o, d, &results)) {\n\t\t\tif (results.size() > 0) {\n\t\t\t\tif (!ov->bVisible)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcollided = true;\n\n\t\t\t\tsize_t min_i = 0;\n\t\t\t\tfloat minDist = results[0].HitDistance;\n\t\t\t\tfor (size_t i = 1; i < results.size(); i++) {\n\t\t\t\t\tif (results[i].HitDistance < minDist) {\n\t\t\t\t\t\tminDist = results[i].HitDistance;\n\t\t\t\t\t\tmin_i = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tVector3 origin = results[min_i].HitCoord;\n\n\t\t\t\tbool closest = true;\n\t\t\t\tfloat viewDistance = origin.DistanceTo(o);\n\n\t\t\t\tfor (auto& p : allHitDistances)\n\t\t\t\t\tif (viewDistance > p.second)\n\t\t\t\t\t\tclosest = false;\n\n\t\t\t\tallHitDistances[ov] = viewDistance;\n\n\t\t\t\tif (closest) {\n\t\t\t\t\toutOrigin = origin;\n\n\t\t\t\t\tif (hitMesh)\n\t\t\t\t\t\t(*hitMesh) = ov;\n\n\t\t\t\t\tif (outFacet)\n\t\t\t\t\t\t(*outFacet) = results[min_i].HitFacet;\n\n\t\t\t\t\toutNormal = ov->tris[results[min_i].HitFacet].trinormal(ov->verts.get());\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collided;\n}\n\nbool GLSurface::CollidePlane(int ScreenX, int ScreenY, Vector3& outOrigin, const Vector3& inPlaneNormal, float inPlaneDist) {\n\tVector3 o;\n\tVector3 d;\n\tGetPickRay(ScreenX, ScreenY, nullptr, d, o);\n\n\tfloat den = inPlaneNormal.dot(d);\n\tif (fabs(den) < .00001)\n\t\treturn false;\n\n\tfloat t = -(inPlaneNormal.dot(o) - inPlaneDist) / den;\n\toutOrigin = o + d * t;\n\n\treturn true;\n}\n\nbool GLSurface::UpdateCursor(int ScreenX, int ScreenY, bool allMeshes, CursorHitResult* hitResult) {\n\tbool collided = false;\n\tif (activeMeshes.empty())\n\t\treturn collided;\n\n\tstd::unordered_map<Mesh*, Vector3> allHitDistances;\n\tfor (auto& m : activeMeshes) {\n\t\tif (!allMeshes && m != selectedMesh)\n\t\t\tcontinue;\n\n\t\tVector3 o;\n\t\tVector3 d;\n\t\tGetPickRay(ScreenX, ScreenY, m, d, o);\n\n\t\tstd::vector<IntersectResult> results;\n\t\tif (m->bvh && m->bvh->IntersectRay(o, d, &results)) {\n\t\t\tif (results.size() > 0) {\n\t\t\t\tif (!m->bVisible)\n\t\t\t\t\tcontinue;\n\n\t\t\t\tcollided = true;\n\n\t\t\t\tsize_t min_i = 0;\n\t\t\t\tfloat minDist = results[0].HitDistance;\n\t\t\t\tfor (size_t i = 1; i < results.size(); i++) {\n\t\t\t\t\tif (results[i].HitDistance < minDist) {\n\t\t\t\t\t\tminDist = results[i].HitDistance;\n\t\t\t\t\t\tmin_i = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tVector3 origin = results[min_i].HitCoord;\n\n\t\t\t\tTriangle t = m->tris[results[min_i].HitFacet];\n\n\t\t\t\tVector3 hilitepoint = m->verts[t.p1];\n\t\t\t\tfloat closestdist = fabs(m->verts[t.p1].DistanceTo(origin));\n\t\t\t\tfloat nextdist = fabs(m->verts[t.p2].DistanceTo(origin));\n\t\t\t\tint pointid = t.p1;\n\n\t\t\t\tif (nextdist < closestdist) {\n\t\t\t\t\tclosestdist = nextdist;\n\t\t\t\t\thilitepoint = m->verts[t.p2];\n\t\t\t\t\tpointid = t.p2;\n\t\t\t\t}\n\t\t\t\tnextdist = fabs(m->verts[t.p3].DistanceTo(origin));\n\t\t\t\tif (nextdist < closestdist) {\n\t\t\t\t\thilitepoint = m->verts[t.p3];\n\t\t\t\t\tpointid = t.p3;\n\t\t\t\t}\n\n\t\t\t\tbool closest = true;\n\t\t\t\tfloat viewDistance = hilitepoint.DistanceTo(o);\n\n\t\t\t\tfor (auto& p : allHitDistances) {\n\t\t\t\t\tif (viewDistance > p.second.DistanceTo(o))\n\t\t\t\t\t\tclosest = false;\n\t\t\t\t}\n\n\t\t\t\tif (closest) {\n\t\t\t\t\tconst int dec = 5;\n\t\t\t\t\tEdge closestEdge = t.ClosestEdge(m->verts.get(), origin);\n\n\t\t\t\t\tVector3 morigin = m->TransformPosMeshToModel(origin);\n\n\t\t\t\t\tVector3 norm = m->tris[results[min_i].HitFacet].trinormal(m->verts.get());\n\t\t\t\t\tnorm = m->TransformDirMeshToModel(norm);\n\n\t\t\t\t\tAddVisCircle(morigin, norm, cursorSize, \"cursormesh\");\n\n\t\t\t\t\tVector3 modelMirrorNorm = norm;\n\t\t\t\t\tmodelMirrorNorm.x = -modelMirrorNorm.x;\n\t\t\t\t\tVector3 modelMirrorOrigin = morigin;\n\t\t\t\t\tmodelMirrorOrigin.x = -modelMirrorOrigin.x;\n\n\t\t\t\t\tMesh* mirrorCircle = AddVisCircle(modelMirrorOrigin, modelMirrorNorm, cursorSize, \"mirrorcircle\");\n\t\t\t\t\tmirrorCircle->prop.alpha = 0.25f;\n\n\t\t\t\t\tVector3 mhilitepoint = m->TransformPosMeshToModel(hilitepoint);\n\t\t\t\t\tAddVisPoint(mhilitepoint, \"pointhilite\");\n\t\t\t\t\tAddVisPoint(morigin, \"cursorcenter\")->color = Vector3(1.0f, 0.0f, 0.0f);\n\n\t\t\t\t\tVector3 mep1 = m->TransformPosMeshToModel(m->verts[closestEdge.p1]);\n\t\t\t\t\tVector3 mep2 = m->TransformPosMeshToModel(m->verts[closestEdge.p2]);\n\t\t\t\t\tAddVisSeg(mep1, mep2, \"seghilite\");\n\n\t\t\t\t\tif (hitResult) {\n\t\t\t\t\t\thitResult->hoverPoint = pointid;\n\t\t\t\t\t\thitResult->hoverMeshCoord = hilitepoint;\n\t\t\t\t\t\thitResult->hoverRealCoord = mhilitepoint;\n\t\t\t\t\t\thitResult->hoverMask = std::floor(m->mask[pointid] * std::pow(10, dec) + 0.5f) / std::pow(10, dec);\n\t\t\t\t\t\thitResult->hoverWeight = std::floor(m->weight[pointid] * std::pow(10, dec) + 0.5f) / std::pow(10, dec);\n\t\t\t\t\t\thitResult->hoverColor.x = std::floor(m->vcolors[pointid].x * std::pow(10, dec) + 0.5f) / std::pow(10, dec);\n\t\t\t\t\t\thitResult->hoverColor.y = std::floor(m->vcolors[pointid].y * std::pow(10, dec) + 0.5f) / std::pow(10, dec);\n\t\t\t\t\t\thitResult->hoverColor.z = std::floor(m->vcolors[pointid].z * std::pow(10, dec) + 0.5f) / std::pow(10, dec);\n\t\t\t\t\t\thitResult->hoverAlpha = std::floor(m->valpha[pointid] * std::pow(10, dec) + 0.5f) / std::pow(10, dec);\n\t\t\t\t\t\thitResult->hitMesh = m;\n\t\t\t\t\t\thitResult->hitMeshName = m->shapeName;\n\t\t\t\t\t\thitResult->hoverEdge = closestEdge;\n\t\t\t\t\t\thitResult->hoverTri = results[min_i].HitFacet;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tallHitDistances[m] = hilitepoint;\n\t\t\t}\n\t\t}\n\t}\n\n\tShowCursor(collided);\n\treturn collided;\n}\n\nbool GLSurface::GetCursorVertex(int ScreenX, int ScreenY, int* outIndex, Mesh* hitMesh, Mesh** outHitMesh) {\n\tif (!hitMesh && activeMeshes.empty())\n\t\treturn false;\n\n\tif (outIndex)\n\t\t(*outIndex) = -1;\n\n\tif (outHitMesh)\n\t\t(*outHitMesh) = nullptr;\n\n\tstd::vector<Mesh*> hitMeshes;\n\tif (hitMesh)\n\t\thitMeshes.push_back(hitMesh);\n\telse\n\t\thitMeshes = activeMeshes;\n\n\tfor (auto& m : hitMeshes) {\n\t\tVector3 o;\n\t\tVector3 d;\n\t\tGetPickRay(ScreenX, ScreenY, m, d, o);\n\n\t\tstd::vector<IntersectResult> results;\n\t\tif (m->bvh && m->bvh->IntersectRay(o, d, &results)) {\n\t\t\tif (results.size() > 0) {\n\t\t\t\tsize_t min_i = 0;\n\t\t\t\tfloat minDist = results[0].HitDistance;\n\t\t\t\tfor (size_t i = 1; i < results.size(); i++) {\n\t\t\t\t\tif (results[i].HitDistance < minDist) {\n\t\t\t\t\t\tminDist = results[i].HitDistance;\n\t\t\t\t\t\tmin_i = i;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tVector3 origin = results[min_i].HitCoord;\n\n\t\t\t\tTriangle t = m->tris[results[min_i].HitFacet];\n\n\t\t\t\tfloat closestdist = fabs(m->verts[t.p1].DistanceTo(origin));\n\t\t\t\tfloat nextdist = fabs(m->verts[t.p2].DistanceTo(origin));\n\t\t\t\tint pointid = t.p1;\n\n\t\t\t\tif (nextdist < closestdist) {\n\t\t\t\t\tclosestdist = nextdist;\n\t\t\t\t\tpointid = t.p2;\n\t\t\t\t}\n\n\t\t\t\tnextdist = fabs(m->verts[t.p3].DistanceTo(origin));\n\n\t\t\t\tif (nextdist < closestdist)\n\t\t\t\t\tpointid = t.p3;\n\n\t\t\t\tif (outIndex)\n\t\t\t\t\t(*outIndex) = pointid;\n\t\t\t\tif (outHitMesh)\n\t\t\t\t\t(*outHitMesh) = m;\n\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn false;\n}\n\nvoid GLSurface::ShowCursor(bool show) {\n\tSetOverlayVisibility(\"cursormesh\", show && (cursorType & CircleCursor));\n\tSetOverlayVisibility(\"pointhilite\", show && (cursorType & PointCursor));\n\tSetOverlayVisibility(\"cursorcenter\", show && (cursorType & CenterCursor));\n\tSetOverlayVisibility(\"seghilite\", show && (cursorType & SegCursor));\n\tSetOverlayVisibility(\"mirrorpoint\", false);\n\tSetOverlayVisibility(\"mirrorcircle\", show && xmirrorCursor && (cursorType & CircleCursor));\n}\n\nvoid GLSurface::HidePointCursor() {\n\tSetOverlayVisibility(\"pointhilite\", false);\n}\n\nvoid GLSurface::HideSegCursor() {\n\tSetOverlayVisibility(\"seghilite\", false);\n}\n\nvoid GLSurface::SetPointCursor(const Vector3 &p, Mesh* m) {\n\tVector3 gp = m ? m->TransformPosMeshToModel(p) : p;\n\tAddVisPoint(gp, \"pointhilite\");\n}\n\nvoid GLSurface::SetCenterCursor(const Vector3 &p, Mesh* m) {\n\tVector3 gp = m ? m->TransformPosMeshToModel(p) : p;\n\tAddVisPoint(gp, \"cursorcenter\")->color = Vector3(1.0f, 0.0f, 0.0f);\n}\n\nvoid GLSurface::ShowMirrorPointCursor(const Vector3 &p, Mesh* m) {\n\tVector3 gp = m ? m->TransformPosMeshToModel(p) : p;\n\tAddVisPoint(gp, \"mirrorpoint\")->color = Vector3(0.3f, 0.7f, 0.7f);;\n\tSetOverlayVisibility(\"mirrorpoint\", true);\n}\n\nvoid GLSurface::SetSize(uint32_t w, uint32_t h) {\n\tif (!SetContext())\n\t\treturn;\n\n\tglViewport(0, 0, w*this->canvas->GetContentScaleFactor(), h*this->canvas->GetContentScaleFactor());\n\tvpW = w;\n\tvpH = h;\n}\n\nvoid GLSurface::GetSize(uint32_t& w, uint32_t& h) {\n\tw = vpW;\n\th = vpH;\n}\n\nvoid GLSurface::UpdateProjection() {\n\tfloat aspect = (float)vpW / (float)vpH;\n\tif (perspective)\n\t\tmatProjection = glm::perspective(glm::radians(mFov), aspect, zNear, zFar);\n\telse\n\t\tmatProjection = glm::ortho((camPos.z + camOffset.z) / 2.0f * aspect,\n\t\t\t\t\t\t\t\t   (-camPos.z + camOffset.z) / 2.0f * aspect,\n\t\t\t\t\t\t\t\t   (camPos.z + camOffset.z) / 2.0f,\n\t\t\t\t\t\t\t\t   (-camPos.z + camOffset.z) / 2.0f,\n\t\t\t\t\t\t\t\t   zNear,\n\t\t\t\t\t\t\t\t   zFar);\n\n\tauto mat = glm::identity<glm::mat4x4>();\n\tmatView = glm::translate(mat, glm::vec3(camPos.x, camPos.y, camPos.z));\n\tmatView = glm::translate(matView, glm::vec3(camRotOffset.x, camRotOffset.y, camRotOffset.z));\n\tmatView = glm::rotate(matView, glm::radians(camRot.x), glm::vec3(1.0f, 0.0f, 0.0f));\n\tmatView = glm::rotate(matView, glm::radians(camRot.y), glm::vec3(0.0f, 1.0f, 0.0f));\n\tmatView = glm::translate(matView, -glm::vec3(camRotOffset.x, camRotOffset.y, camRotOffset.z));\n\tmatView = glm::translate(matView, glm::vec3(camOffset.x, camOffset.y, camOffset.z));\n}\n\nvoid GLSurface::RenderFullScreenQuad(GLMaterial* renderShader, unsigned int w, unsigned int h) {\n\tif (!canvas)\n\t\treturn;\n\tcanvas->SetCurrent(*context);\n\n\t// Dummy vertexArrayObject, needs to be bound in order for OGL to activate the shader with Draw Arrays.\n\t// No array buffer is used, so this shouldn't be too slow to create here, but could be moved if necessary.\n\tGLuint m_vertexArrayObject = 0;\n\tglGenVertexArrays(1, &m_vertexArrayObject);\n\n\tglViewport(0, 0, w*this->canvas->GetContentScaleFactor(), h*this->canvas->GetContentScaleFactor());\n\tglClear(GL_DEPTH_BUFFER_BIT);\n\n\t// This relies on shader manipulation of vertex positions to render a single triangle clipped to the surface\n\t//\n\tGLShader shader = renderShader->GetShader();\n\tshader.Begin();\n\trenderShader->BindTextures(0, false, false, false, false);\n\t// bind the dummy array and send three fake positions to the shader.\n\tglBindVertexArray(m_vertexArrayObject);\n\tglDrawArrays(GL_TRIANGLES, 0, 3);\n\tglFlush();\n\n\tshader.End();\n\n\t// clear out the dummy array object.\n\tglDeleteVertexArrays(1, &m_vertexArrayObject);\n\n\tcanvas->SwapBuffers();\n}\n\nvoid GLSurface::RenderToTexture(GLMaterial* renderShader) {\n\tif (!canvas)\n\t\treturn;\n\n\tcanvas->SetCurrent(*context);\n\n\t//glClearColor(colorBackground.x, colorBackground.y, colorBackground.z, 0.0f);\n\t//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n\t// Set up orthographic projection and identity view\n\n\tmatProjection = glm::ortho(0.0f, 1.0f, 0.0f, 1.0f, -100.0f, 100.0f);\n\t//matProjection = glm::ortho((camPos.z + camOffset.z) / 2.0f * aspect, (-camPos.z + camOffset.z) / 2.0f * aspect, (camPos.z + camOffset.z) / 2.0f, (-camPos.z + camOffset.z) / 2.0f, 0.1f, 100.0f);\n\tmatView = glm::identity<glm::mat4x4>();\n\n\tMesh* m = nullptr;\n\tbool oldDS;\n\tGLMaterial* oldmat;\n\n\t// Render regular meshes only\n\tfor (size_t i = 0; i < meshes.size(); i++) {\n\t\tm = meshes[i];\n\t\tif (!m->bVisible || m->nTris == 0)\n\t\t\tcontinue;\n\n\t\toldDS = m->doublesided;\n\t\toldmat = m->material;\n\t\tm->material = renderShader;\n\t\tm->modelSpace = false;\n\t\tm->doublesided = true;\n\t\tRenderMesh(m);\n\t\tm->doublesided = oldDS;\n\t\tm->modelSpace = true;\n\t\tm->material = oldmat;\n\t}\n\n\t// note no buffer swap\n}\n\nbool GLSurface::SetContext() {\n\tif (canvas && context) {\n\t\tcanvas->SetCurrent(*context);\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nvoid GLSurface::RenderOneFrame() {\n\tif (!canvas)\n\t\treturn;\n\n\tcanvas->SetCurrent(*context);\n\n\tglClearColor(colorBackground.x, colorBackground.y, colorBackground.z, 1.0f);\n\tglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\n\tUpdateProjection();\n\n\t// Render regular meshes\n\tfor (auto& m : meshes) {\n\t\tif (!m->HasAlphaBlend() && m->bVisible && (m->nTris != 0 || m->nEdges != 0))\n\t\t\tRenderMesh(m);\n\t}\n\n\t// Render meshes with alpha blending only\n\tfor (auto& m : meshes) {\n\t\tif (m->HasAlphaBlend() && m->bVisible && (m->nTris != 0 || m->nEdges != 0)) {\n\t\t\tglEnable(GL_CULL_FACE);\n\t\t\tglCullFace(GL_FRONT);\n\n\t\t\tglDepthFunc(GL_LESS);\n\t\t\tglDepthMask(GL_FALSE);\n\n\t\t\tRenderMesh(m);\n\n\t\t\tglCullFace(GL_BACK);\n\t\t\tglDepthMask(GL_TRUE);\n\n\t\t\tRenderMesh(m);\n\t\t}\n\t}\n\n\t// Render overlays on top\n\tstd::vector<Mesh*> renderOverlays(overlays);\n\tstd::sort(renderOverlays.begin(), renderOverlays.end(), SortOverlaysLayer());\n\n\tuint32_t lastOverlayLayer = static_cast<uint32_t>(-1);\n\tfor (auto& o : renderOverlays) {\n\t\tif (o->bVisible) {\n\t\t\tif (o->overlayLayer != lastOverlayLayer)\n\t\t\t\tglClear(GL_DEPTH_BUFFER_BIT);\n\n\t\t\tlastOverlayLayer = o->overlayLayer;\n\t\t\tRenderMesh(o);\n\t\t}\n\t}\n\n\tcanvas->SwapBuffers();\n\treturn;\n}\n\nvoid GLSurface::RenderMesh(Mesh* m) {\n\tm->UpdateBuffers();\n\n\tif (!m->genBuffers || !m->material)\n\t\treturn;\n\n\tGLShader& shader = m->material->GetShader();\n\tif (!shader.Begin())\n\t\treturn;\n\n\tif (!m->HasAlphaBlend()) {\n\t\tglDepthFunc(GL_LEQUAL);\n\t\tglDepthMask(GL_TRUE);\n\n\t\tif (!m->doublesided)\n\t\t\tglEnable(GL_CULL_FACE);\n\t\telse\n\t\t\tglDisable(GL_CULL_FACE);\n\n\t\tglCullFace(m->cullMode);\n\t}\n\n\tshader.SetAlphaProperties(m->alphaFlags, m->alphaThreshold / 255.0f, m->prop.alpha);\n\tshader.SetMatrixProjection(matProjection);\n\tshader.SetMatrixModelView(matView, m->matModel);\n\tshader.SetColor(m->color);\n\tshader.SetSubColor(Vector3(1.0f, 1.0f, 1.0f));\n\tshader.SetModelSpace(m->modelSpace);\n\tshader.SetSpecularEnabled(m->specular);\n\tshader.SetEmissive(m->emissive);\n\tshader.SetBacklightEnabled(m->backlight);\n\tshader.SetRimlightEnabled(m->rimlight);\n\tshader.SetSoftlightEnabled(m->softlight);\n\tshader.SetGlowmapEnabled(m->glowmap);\n\tshader.SetGreyscaleColorEnabled(m->greyscaleColor);\n\tshader.SetLightingEnabled(bLighting);\n\tshader.SetWireframeEnabled(false);\n\tshader.SetNormalMapEnabled(false);\n\tshader.SetAlphaMaskEnabled(false);\n\tshader.SetCubemapEnabled(m->cubemap);\n\tshader.SetEnvMaskEnabled(false);\n\tshader.SetProperties(m->prop);\n\n\tglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\tglEnable(GL_DEPTH_TEST);\n\n\tglBindVertexArray(m->vao);\n\n\tif (m->rendermode == Mesh::RenderMode::Normal || m->rendermode == Mesh::RenderMode::LitWire || m->rendermode == Mesh::RenderMode::UnlitSolid) {\n\t\tshader.SetFrontalLight(frontalLight);\n\t\tshader.SetDirectionalLight(directionalLight0, 0);\n\t\tshader.SetDirectionalLight(directionalLight1, 1);\n\t\tshader.SetDirectionalLight(directionalLight2, 2);\n\t\tshader.SetAmbientLight(ambientLight);\n\n\t\tif (m->rendermode == Mesh::RenderMode::LitWire) {\n\t\t\tglDisable(GL_CULL_FACE);\n\t\t\tglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\t\t}\n\n\t\tif (m->rendermode == Mesh::RenderMode::UnlitSolid)\n\t\t\tshader.SetLightingEnabled(false);\n\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);\n\n\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[0]);\n\t\tglEnableVertexAttribArray(0);\n\t\tglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Positions\n\n\t\tif (m->norms) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[1]);\n\t\t\tglEnableVertexAttribArray(1);\n\t\t\tglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Normals\n\t\t}\n\n\t\tif (m->tangents) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[2]);\n\t\t\tglEnableVertexAttribArray(2);\n\t\t\tglVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Tangents\n\t\t}\n\n\t\tif (m->bitangents) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[3]);\n\t\t\tglEnableVertexAttribArray(3);\n\t\t\tglVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Bitangents\n\t\t}\n\n\t\tif (m->vcolors) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[4]);\n\t\t\tglEnableVertexAttribArray(4);\n\t\t\tglVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Colors\n\t\t}\n\n\t\tif (m->valpha) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[5]);\n\t\t\tglEnableVertexAttribArray(5);\n\t\t\tglVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Alpha\n\t\t}\n\n\t\tif (bTextured && m->textured && m->texcoord) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[6]);\n\t\t\tglEnableVertexAttribArray(6);\n\t\t\tglVertexAttribPointer(6, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Texture Coordinates\n\n\t\t\tm->material->BindTextures(largestAF, m->cubemap, m->glowmap, m->backlightMap, m->rimlight || m->softlight);\n\t\t}\n\n\t\tif (m->mask) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[7]);\n\t\t\tglEnableVertexAttribArray(7);\n\t\t\tglVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Mask\n\t\t}\n\n\t\tif (m->weight) {\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[8]);\n\t\t\tglEnableVertexAttribArray(8);\n\t\t\tglVertexAttribPointer(8, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Weight\n\t\t}\n\n\t\tGLuint subMeshesSize = 0;\n\t\tif (!m->subMeshes.empty()) {\n\t\t\tauto& lastSubMesh = m->subMeshes.back();\n\t\t\tsubMeshesSize = lastSubMesh.first + lastSubMesh.second;\n\t\t}\n\n\t\t// Render full mesh or remainder of it\n\t\tglDrawElements(GL_TRIANGLES, (m->nTris - subMeshesSize) * 3, GL_UNSIGNED_SHORT, (GLvoid*)(subMeshesSize * 3 * sizeof(GLushort)));\n\n\t\t// Render sub meshes\n\t\tfor (size_t s = 0; s < m->subMeshes.size(); ++s) {\n\t\t\tGLuint subIndex = m->subMeshes[s].first;\n\t\t\tGLuint subSize = m->subMeshes[s].second;\n\t\t\tVector3 subColor = m->color;\n\n\t\t\tif (!m->subMeshesColor.empty())\n\t\t\t\tsubColor = m->subMeshesColor[s];\n\n\t\t\tshader.SetSubColor(subColor);\n\t\t\tglDrawElements(GL_TRIANGLES, subSize * 3, GL_UNSIGNED_SHORT, (GLvoid*)(subIndex * 3 * sizeof(GLushort)));\n\t\t}\n\n\t\t// Render wireframe (full mesh or remainder of it)\n\t\tif (bWireframe && m->rendermode == Mesh::RenderMode::Normal) {\n\t\t\tshader.SetWireframeEnabled(true);\n\t\t\tshader.SetColor(colorWire);\n\t\t\tglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\t\t\tglDrawElements(GL_TRIANGLES, (m->nTris - subMeshesSize) * 3, GL_UNSIGNED_SHORT, (GLvoid*)(subMeshesSize * 3 * sizeof(GLushort)));\n\n\t\t\t// Render wireframes for sub meshes\n\t\t\tfor (size_t s = 0; s < m->subMeshes.size(); ++s) {\n\t\t\t\tGLuint subIndex = m->subMeshes[s].first;\n\t\t\t\tGLuint subSize = m->subMeshes[s].second;\n\t\t\t\tglDrawElements(GL_TRIANGLES, subSize * 3, GL_UNSIGNED_SHORT, (GLvoid*)(subIndex * 3 * sizeof(GLushort)));\n\t\t\t}\n\t\t}\n\n\t\tif (bTextured && m->textured && m->texcoord)\n\t\t\tglDisableVertexAttribArray(6);\n\n\t\tglDisableVertexAttribArray(5);\n\t\tglDisableVertexAttribArray(4);\n\t\tglDisableVertexAttribArray(3);\n\t\tglDisableVertexAttribArray(2);\n\t\tglDisableVertexAttribArray(1);\n\t\tglDisableVertexAttribArray(0);\n\t}\n\telse if (m->rendermode == Mesh::RenderMode::UnlitWire || m->rendermode == Mesh::RenderMode::UnlitWireDepth) {\n\t\tglDisable(GL_CULL_FACE);\n\n\t\tif (m->rendermode != Mesh::RenderMode::UnlitWireDepth)\n\t\t\tglDisable(GL_DEPTH_TEST);\n\n\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);\n\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[0]);\n\t\tglEnableVertexAttribArray(0);\n\t\tglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);\n\n\t\tglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);\n\t\tglDrawElements(GL_LINES, m->nEdges * 2, GL_UNSIGNED_SHORT, (GLvoid*)0);\n\n\t\tglDisableVertexAttribArray(0);\n\t}\n\n\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\tglBindVertexArray(0);\n\n\tshader.End();\n\n\tif (m->rendermode != Mesh::RenderMode::UnlitWire && m->rendermode != Mesh::RenderMode::UnlitWireDepth) {\n\t\t// Render mesh as points afterwards\n\t\tRenderMeshAsPoints(m);\n\t}\n}\n\nvoid GLSurface::RenderMeshAsPoints(Mesh* m) {\n\tm->UpdateBuffers();\n\n\tif (!m->genBuffers)\n\t\treturn;\n\n\tauto material = GetPointsMaterial();\n\tif (!material)\n\t\treturn;\n\n\tGLShader& shader = material->GetShader();\n\tif (!shader.Begin())\n\t\treturn;\n\n\tglDepthFunc(GL_LEQUAL);\n\tglDepthMask(GL_TRUE);\n\n\tglDisable(GL_CULL_FACE);\n\n\tshader.SetMatrixProjection(matProjection);\n\tshader.SetMatrixModelView(matView, m->matModel);\n\tshader.SetColor(m->color);\n\tshader.SetSubColor(Vector3(1.0f, 1.0f, 1.0f));\n\tshader.SetAdjustPointSize(false);\n\n\tglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);\n\tglEnable(GL_DEPTH_TEST);\n\n\tglBindVertexArray(m->vao);\n\n\tif (m->rendermode == Mesh::RenderMode::Normal || m->rendermode == Mesh::RenderMode::LitWire || m->rendermode == Mesh::RenderMode::UnlitSolid) {\n\t\tif (m->bShowPoints && m->mask) {\n\t\t\tglEnable(GL_PROGRAM_POINT_SIZE);\n\t\t\tshader.SetAdjustPointSize(true);\n\t\t\tshader.SetColor(colorPoints);\n\t\t\tshader.SetSubColor(colorPointsMasked);\n\n\t\t\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo);\n\n\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[0]);\n\t\t\tglEnableVertexAttribArray(0);\n\t\t\tglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Positions\n\n\t\t\tif (m->norms) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[1]);\n\t\t\t\tglEnableVertexAttribArray(1);\n\t\t\t\tglVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Normals\n\t\t\t}\n\n\t\t\tif (m->tangents) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[2]);\n\t\t\t\tglEnableVertexAttribArray(2);\n\t\t\t\tglVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Tangents\n\t\t\t}\n\n\t\t\tif (m->bitangents) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[3]);\n\t\t\t\tglEnableVertexAttribArray(3);\n\t\t\t\tglVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Bitangents\n\t\t\t}\n\n\t\t\tif (m->vcolors) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[4]);\n\t\t\t\tglEnableVertexAttribArray(4);\n\t\t\t\tglVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Colors\n\t\t\t}\n\n\t\t\tif (m->valpha) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[5]);\n\t\t\t\tglEnableVertexAttribArray(5);\n\t\t\t\tglVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Alpha\n\t\t\t}\n\n\t\t\tif (bTextured && m->textured && m->texcoord) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[6]);\n\t\t\t\tglEnableVertexAttribArray(6);\n\t\t\t\tglVertexAttribPointer(6, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Texture Coordinates\n\n\t\t\t\tmaterial->BindTextures(largestAF, m->cubemap, m->glowmap, m->backlightMap, m->rimlight || m->softlight);\n\t\t\t}\n\n\t\t\tif (m->mask) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[7]);\n\t\t\t\tglEnableVertexAttribArray(7);\n\t\t\t\tglVertexAttribPointer(7, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Mask\n\t\t\t}\n\n\t\t\tif (m->weight) {\n\t\t\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[8]);\n\t\t\t\tglEnableVertexAttribArray(8);\n\t\t\t\tglVertexAttribPointer(8, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0); // Weight\n\t\t\t}\n\n\t\t\tglEnable(GL_BLEND);\n\t\t\tglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n\t\t\tglDrawArrays(GL_POINTS, 0, m->nVerts);\n\n\t\t\tif (bTextured && m->textured && m->texcoord)\n\t\t\t\tglDisableVertexAttribArray(6);\n\n\t\t\tglDisableVertexAttribArray(5);\n\t\t\tglDisableVertexAttribArray(4);\n\t\t\tglDisableVertexAttribArray(3);\n\t\t\tglDisableVertexAttribArray(2);\n\t\t\tglDisableVertexAttribArray(1);\n\t\t\tglDisableVertexAttribArray(0);\n\n\t\t\tglDisable(GL_PROGRAM_POINT_SIZE);\n\t\t}\n\t}\n\telse if (m->rendermode == Mesh::RenderMode::UnlitPoints || m->rendermode == Mesh::RenderMode::UnlitPointsDepth) {\n\t\tglDisable(GL_CULL_FACE);\n\n\t\tif (m->rendermode != Mesh::RenderMode::UnlitPointsDepth)\n\t\t\tglDisable(GL_DEPTH_TEST);\n\n\t\tglBindBuffer(GL_ARRAY_BUFFER, m->vbo[0]);\n\t\tglEnableVertexAttribArray(0);\n\t\tglVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);\n\n\t\tglDrawArrays(GL_POINTS, 0, m->nVerts);\n\n\t\tglDisableVertexAttribArray(0);\n\t}\n\n\tglBindBuffer(GL_ARRAY_BUFFER, 0);\n\tglBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\tglBindVertexArray(0);\n\n\tshader.End();\n}\n\nvoid GLSurface::UpdateShaders(Mesh* m) {\n\tif (m->material) {\n\t\tGLShader& shader = m->material->GetShader();\n\t\tshader.ShowTexture(bTextured && m->textured);\n\t\tshader.ShowLighting(bLighting);\n\t\tshader.ShowMask(bMaskVisible && m->mask);\n\t\tshader.ShowWeight(bWeightColors && m->weight);\n\t\tshader.ShowVertexColors(bVertexColors && m->vcolors && m->vertexColors);\n\t\tshader.ShowVertexAlpha(bVertexColors && m->valpha && m->vertexColors && m->vertexAlpha);\n\t\tshader.SetProperties(m->prop);\n\t}\n}\n\nMesh* GLSurface::ReloadMeshFromNif(NifFile* nif, std::string shapeName) {\n\tDeleteMesh(shapeName);\n\treturn AddMeshFromNif(nif, shapeName);\n}\n\nMesh* GLSurface::AddMeshFromNif(NifFile* nif, const std::string& shapeName, Vector3* color) {\n\tauto shape = nif->FindBlockByName<NiShape>(shapeName);\n\tif (!shape)\n\t\treturn nullptr;\n\n\tstd::vector<Vector3> nifVerts;\n\tnif->GetVertsForShape(shape, nifVerts);\n\n\tstd::vector<Triangle> nifTris;\n\tshape->GetTriangles(nifTris);\n\n\tconst std::vector<Vector3>* nifNorms = nif->GetNormalsForShape(shape);\n\tconst std::vector<Vector2>* nifUvs = nif->GetUvsForShape(shape);\n\n\tMesh* m = new Mesh();\n\n\tif (!shape->IsSkinned()) {\n\t\t// Calculate transform from shape's CS to global CS\n\t\tMatTransform ttg = shape->GetTransformToParent();\n\t\tNiNode* parent = nif->GetParentNode(shape);\n\t\twhile (parent) {\n\t\t\tttg = parent->GetTransformToParent().ComposeTransforms(ttg);\n\t\t\tparent = nif->GetParentNode(parent);\n\t\t}\n\n\t\tm->SetXformMeshToModel(Mesh::xformNifToMesh.ComposeTransforms(ttg.ComposeTransforms(Mesh::xformMeshToNif)));\n\t}\n\telse {\n\t\t// Skinned meshes\n\t\tMatTransform xformGlobalToSkin;\n\t\tif (nif->CalcShapeTransformGlobalToSkin(shape, xformGlobalToSkin)) {\n\t\t\tm->SetXformModelToMesh(Mesh::xformNifToMesh.ComposeTransforms(xformGlobalToSkin.ComposeTransforms(Mesh::xformMeshToNif)));\n\t\t}\n\t}\n\n\tNiShader* shader = nif->GetShader(shape);\n\tif (shader) {\n\t\tm->doublesided = shader->IsDoubleSided();\n\t\tm->modelSpace = shader->IsModelSpace();\n\t\tm->emissive = shader->IsEmissive();\n\t\tm->specular = shader->HasSpecular();\n\t\tm->vertexColors = shader->HasVertexColors();\n\t\tm->vertexAlpha = shader->HasVertexAlpha();\n\t\tm->glowmap = shader->HasGlowmap();\n\t\tm->greyscaleColor = shader->HasGreyscaleColor();\n\t\tm->cubemap = shader->HasEnvironmentMapping();\n\n\t\tif (nif->GetHeader().GetVersion().Stream() < 130) {\n\t\t\tm->backlight = shader->HasBacklight();\n\t\t\tm->backlightMap = m->backlight; // Dedicated map pre-130\n\t\t\tm->rimlight = shader->HasRimlight();\n\t\t\tm->softlight = shader->HasSoftlight();\n\t\t\tm->prop.rimlightPower = shader->GetRimlightPower();\n\t\t\tm->prop.softlighting = shader->GetSoftlight();\n\t\t}\n\t\telse {\n\t\t\tm->backlight = (shader->GetBacklightPower() > 0.0);\n\t\t\tm->softlight = (shader->GetSubsurfaceRolloff() > 0.0);\n\t\t\tm->prop.subsurfaceRolloff = shader->GetSubsurfaceRolloff();\n\t\t}\n\n\t\tm->prop.uvOffset = shader->GetUVOffset();\n\t\tm->prop.uvScale = shader->GetUVScale();\n\t\tm->prop.specularColor = shader->GetSpecularColor();\n\t\tm->prop.specularStrength = shader->GetSpecularStrength();\n\t\tm->prop.shininess = shader->GetGlossiness();\n\t\tm->prop.envReflection = shader->GetEnvironmentMapScale();\n\t\tm->prop.backlightPower = shader->GetBacklightPower();\n\t\tm->prop.paletteScale = shader->GetGrayscaleToPaletteScale();\n\t\tm->prop.fresnelPower = shader->GetFresnelPower();\n\n\t\tColor4 emissiveColor = shader->GetEmissiveColor();\n\t\tm->prop.emissiveColor = Vector3(emissiveColor.r, emissiveColor.g, emissiveColor.b);\n\t\tm->prop.emissiveMultiple = shader->GetEmissiveMultiple();\n\n\t\tm->prop.alpha = shader->GetAlpha();\n\t}\n\n\tNiMaterialProperty* material = nif->GetMaterialProperty(shape);\n\tif (material) {\n\t\tm->emissive = material->IsEmissive();\n\n\t\tm->prop.specularColor = material->GetSpecularColor();\n\t\tm->prop.shininess = material->GetGlossiness();\n\n\t\tColor4 emissiveColor = material->GetEmissiveColor();\n\t\tm->prop.emissiveColor = Vector3(emissiveColor.r, emissiveColor.g, emissiveColor.b);\n\t\tm->prop.emissiveMultiple = material->GetEmissiveMultiple();\n\n\t\tm->prop.alpha = material->GetAlpha();\n\t}\n\n\tNiStencilProperty* stencil = nif->GetStencilProperty(shape);\n\tif (stencil) {\n\t\tint drawMode = (stencil->flags & DRAW_MASK) >> DRAW_POS;\n\n\t\tswitch (drawMode) {\n\t\t\tcase DRAW_CW:\n\t\t\t\tm->doublesided = false;\n\t\t\t\tm->cullMode = GL_FRONT;\n\t\t\t\tbreak;\n\t\t\tcase DRAW_BOTH:\n\t\t\t\tm->doublesided = true;\n\t\t\t\tm->cullMode = GL_BACK;\n\t\t\t\tbreak;\n\t\t\tcase DRAW_CCW:\n\t\t\tdefault:\n\t\t\t\tm->doublesided = false;\n\t\t\t\tm->cullMode = GL_BACK;\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tNiAlphaProperty* alphaProp = nif->GetAlphaProperty(shape);\n\tif (alphaProp) {\n\t\tm->alphaFlags = alphaProp->flags;\n\t\tm->alphaThreshold = alphaProp->threshold;\n\t}\n\n\tm->nVerts = nifVerts.size();\n\tm->nTris = nifTris.size();\n\n\tif (m->nVerts > 0) {\n\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->norms = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->tangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->bitangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->vcolors = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->valpha = std::make_unique<float[]>(m->nVerts);\n\t\tm->texcoord = std::make_unique<Vector2[]>(m->nVerts);\n\t\tm->mask = std::make_unique<float[]>(m->nVerts);\n\t\tm->weight = std::make_unique<float[]>(m->nVerts);\n\t}\n\n\tif (m->nTris > 0)\n\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\tm->shapeName = shapeName;\n\n\t// Load verts. NIF verts are scaled up by approx. 10 and rotated on the x axis (Z up, Y forward).\n\t// Scale down by 10 and rotate on x axis by flipping y and z components. To face the camera, this also mirrors\n\t// on X and Y (180 degree y axis rotation.)\n\tfor (int i = 0; i < m->nVerts; i++)\n\t\tm->verts[i] = Mesh::TransformPosNifToMesh(nifVerts[i]);\n\n\tif (nifUvs && !nifUvs->empty()) {\n\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\tm->texcoord[i].u = (*nifUvs)[i].u;\n\t\t\tm->texcoord[i].v = (*nifUvs)[i].v;\n\t\t}\n\t\tm->textured = true;\n\t}\n\n\t// Copy triangles\n\tfor (int t = 0; t < m->nTris; t++)\n\t\tm->tris[t] = nifTris[t];\n\n\tif (!nifNorms || nifNorms->empty()) {\n\t\t// Calc weldVerts and normals\n\t\tm->SmoothNormals();\n\t}\n\telse {\n\t\t// Already have normals, just copy the data over.\n\t\t// Copy normals. Note, normals are transformed the same way the vertices are.\n\t\tfor (int i = 0; i < m->nVerts; i++)\n\t\t\tm->norms[i] = Mesh::TransformDirNifToMesh((*nifNorms)[i]);\n\n\t\tfor (auto& extraDataRef : shape->extraDataRefs) {\n\t\t\tauto integersExtraData = nif->GetHeader().GetBlock<NiIntegersExtraData>(extraDataRef);\n\t\t\tif (integersExtraData && integersExtraData->name == \"LOCKEDNORM\")\n\t\t\t\tfor (auto& i : integersExtraData->integersData)\n\t\t\t\t\tm->lockedNormalIndices.insert(i);\n\t\t}\n\n\t\t// Virtually weld verts across UV seams\n\t\tm->CalcWeldVerts();\n\t}\n\n\tstd::vector<Color4> vColors;\n\tif (nif->GetColorsForShape(shape, vColors)) {\n\t\tfor (size_t v = 0; v < vColors.size(); v++) {\n\t\t\tm->vcolors[v].x = vColors.at(v).r;\n\t\t\tm->vcolors[v].y = vColors.at(v).g;\n\t\t\tm->vcolors[v].z = vColors.at(v).b;\n\t\t\tm->valpha[v] = vColors.at(v).a;\n\t\t}\n\t}\n\n\tm->CalcTangentSpace();\n\tm->CreateBVH();\n\n\tif (color)\n\t\tm->color = (*color);\n\n\tAddMesh(m);\n\n\tif (!color) {\n\t\tint i = 0;\n\t\tauto meshesFiltered = GetMeshesFiltered();\n\t\tfor (auto& nm : meshesFiltered) {\n\t\t\tfloat c = 0.25f + (0.25f / meshesFiltered.size() * i);\n\t\t\tnm->color = Vector3(c, c, c);\n\t\t\ti++;\n\t\t}\n\t}\n\n\treturn m;\n}\n\nMesh* GLSurface::AddVisPoint(const Vector3& p, const std::string& name, const Vector3* color) {\n\tMesh* m = GetOverlay(name);\n\tif (m) {\n\t\tm->verts[0] = p;\n\t\tif (color)\n\t\t\tm->color = (*color);\n\t\telse\n\t\t\tm->color = Vector3(0.0f, 1.0f, 1.0f);\n\n\t\tm->bVisible = true;\n\t\tm->QueueUpdate(Mesh::UpdateType::Position);\n\t\treturn m;\n\t}\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tm = new Mesh();\n\n\tm->nVerts = 1;\n\tm->verts = std::make_unique<Vector3[]>(1);\n\tm->verts[0] = p;\n\tm->nEdges = 0;\n\tm->nTris = 0;\n\n\tm->rendermode = Mesh::RenderMode::UnlitPoints;\n\tm->shapeName = name;\n\tm->color = Vector3(0.0f, 1.0f, 1.0f);\n\tm->material = GetPrimitiveMaterial();\n\tm->CreateBuffers();\n\n\tAddOverlay(m);\n\treturn m;\n}\n\nMesh* GLSurface::AddVisCircle(const Vector3& center, const Vector3& normal, float radius, const std::string& name) {\n\tMatrix4 rotMat;\n\trotMat.Align(Vector3(0.0f, 0.0f, 1.0f), normal);\n\trotMat.Translate(center);\n\n\tfloat rStep = DEG2RAD * 5.0f;\n\n\tMesh* m = GetOverlay(name);\n\tif (m) {\n\t\tfloat i = 0.0f;\n\t\tfor (int j = 0; j < m->nVerts; j++) {\n\t\t\tm->verts[j].x = sin(i) * radius;\n\t\t\tm->verts[j].y = cos(i) * radius;\n\t\t\tm->verts[j].z = 0;\n\t\t\ti += rStep;\n\t\t\tm->verts[j] = rotMat * m->verts[j];\n\t\t}\n\n\t\tm->QueueUpdate(Mesh::UpdateType::Position);\n\t\treturn m;\n\t}\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tm = new Mesh();\n\n\tm->nVerts = 360 / 5;\n\tm->nEdges = m->nVerts;\n\n\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\tm->edges = std::make_unique<Edge[]>(m->nEdges);\n\n\tm->shapeName = name;\n\tm->color = Vector3(1.0f, 0.0f, 0.0f);\n\tm->rendermode = Mesh::RenderMode::UnlitWire;\n\tm->material = GetPrimitiveMaterial();\n\n\tfloat i = 0.0f;\n\tfor (int j = 0; j < m->nVerts; j++) {\n\t\tm->verts[j].x = sin(i) * radius;\n\t\tm->verts[j].y = cos(i) * radius;\n\t\tm->verts[j].z = 0;\n\t\tm->edges[j].p1 = j;\n\t\tm->edges[j].p2 = j + 1;\n\t\ti += rStep;\n\t\tm->verts[j] = rotMat * m->verts[j];\n\t}\n\n\tm->edges[m->nEdges - 1].p2 = 0;\n\tm->CreateBuffers();\n\n\tAddOverlay(m);\n\treturn m;\n}\n\nMesh* GLSurface::AddVis3dSphere(const nifly::Vector3& center, float radius, const nifly::Vector3& color, const std::string& name, bool asMesh) {\n\tconst int nStacks = 18;\n\tconst int nSectors = 36;\n\n\tconst float sectorStep = 2 * PI / nSectors;\n\tconst float stackStep = PI / nStacks;\n\n\tMesh* m = nullptr;\n\n\tif (!name.empty()) {\n\t\tif (asMesh)\n\t\t\tm = GetMesh(name);\n\t\telse\n\t\t\tm = GetOverlay(name);\n\t}\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tif (!m) {\n\t\tm = new Mesh();\n\n\t\tm->nVerts = (nStacks + 1) * (nSectors + 1);\n\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->texcoord = std::make_unique<Vector2[]>(m->nVerts);\n\t\tm->norms = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->tangents = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->bitangents = std::make_unique<Vector3[]>(m->nVerts);\n\n\t\tstd::vector<Triangle> tris;\n\n\t\tfor (int i = 0; i < nStacks; ++i) {\n\t\t\tint k1 = i * (nSectors + 1); // beginning of current stack\n\t\t\tint k2 = k1 + nSectors + 1;\t // beginning of next stack\n\n\t\t\tfor (int j = 0; j < nSectors; ++j, ++k1, ++k2) {\n\t\t\t\t// 2 triangles per sector excluding first and last stacks\n\t\t\t\t// k1 => k2 => k1+1\n\t\t\t\tif (i != 0)\n\t\t\t\t\ttris.push_back(Triangle(k1, k2, k1 + 1));\n\n\t\t\t\t// k1+1 => k2 => k2+1\n\t\t\t\tif (i != (nStacks - 1))\n\t\t\t\t\ttris.push_back(Triangle(k1 + 1, k2, k2 + 1));\n\t\t\t}\n\t\t}\n\n\t\tm->nTris = tris.size();\n\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\t\tfor (int i = 0; i < m->nTris; i++)\n\t\t\tm->tris[i] = tris[i];\n\n\t\tm->shapeName = name;\n\t\tm->rendermode = Mesh::RenderMode::UnlitSolid;\n\t\tm->material = GetPrimitiveMaterial();\n\n\t\tif (asMesh)\n\t\t\tAddMesh(m);\n\t\telse\n\t\t\tAddOverlay(m);\n\t}\n\n\tm->color = color;\n\n\tMatrix4 mat;\n\tmat.Translate(center);\n\n\tint index = 0;\n\tfloat lengthInv = 1.0f / radius;\n\n\tfor (int i = 0; i <= nStacks; ++i) {\n\t\tfloat stackAngle = PI / 2 - i * stackStep;\n\t\tfloat xy = radius * std::cos(stackAngle);\n\t\tfloat z = radius * std::sin(stackAngle);\n\n\t\t// Add (nSectors+1) vertices per stack\n\t\t// The first and last vertices have same position and normal, but different tex coords\n\t\tfor (int j = 0; j <= nSectors; ++j) {\n\t\t\tfloat sectorAngle = j * sectorStep;\n\n\t\t\tfloat x = xy * std::cos(sectorAngle);\n\t\t\tfloat y = xy * std::sin(sectorAngle);\n\t\t\tm->verts[index] = mat * Vector3(x, y, z);\n\n\t\t\tfloat nx = x * lengthInv;\n\t\t\tfloat ny = y * lengthInv;\n\t\t\tfloat nz = z * lengthInv;\n\t\t\tm->norms[index] = Vector3(nx, ny, nz);\n\n\t\t\tfloat u = (float)j / nSectors;\n\t\t\tfloat v = (float)i / nStacks;\n\t\t\tm->texcoord[index] = Vector2(u, v);\n\n\t\t\tindex++;\n\t\t}\n\t}\n\n\tm->CalcTangentSpace();\n\tm->CreateBuffers();\n\treturn m;\n}\n\nMesh* GLSurface::AddVis3dRing(const Vector3& center, const Vector3& normal, float holeRadius, float ringRadius, const Vector3& color, const std::string& name) {\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tconst int nRingSegments = 36;\n\tconst int nRingSteps = 4;\n\n\tMesh* m = GetOverlay(name);\n\tif (!m) {\n\t\tm = new Mesh();\n\n\t\tm->nVerts = nRingSegments * nRingSteps;\n\t\tm->nTris = m->nVerts * 2;\n\t\tm->nEdges = 0;\n\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\t\tm->shapeName = name;\n\t\tm->rendermode = Mesh::RenderMode::UnlitSolid;\n\t\tm->material = GetPrimitiveMaterial();\n\n\t\tAddOverlay(m);\n\t}\n\n\tm->color = color;\n\n\tMatrix4 xf1;\n\txf1.Align(Vector3(0.0f, 0.0f, 1.0f), Vector3(1.0f, 0.0f, 0.0f));\n\txf1.Translate(Vector3(0.0f, holeRadius, 0.0f));\n\n\tMatrix4 xf3;\n\txf3.Align(Vector3(0.0f, 0.0f, 1.0f), normal);\n\txf3.Translate(center);\n\n\tfloat rStep = DEG2RAD * (360.0f / nRingSteps);\n\tfloat i = 0.0f;\n\tVector3 loftVerts[nRingSteps];\n\tfor (int r = 0; r < nRingSteps; r++) {\n\t\tloftVerts[r].x = sin(i) * ringRadius;\n\t\tloftVerts[r].y = cos(i) * ringRadius;\n\t\tloftVerts[r].z = 0.0f;\n\t\ti += rStep;\n\t\tloftVerts[r] = xf1 * loftVerts[r];\n\t}\n\n\trStep = DEG2RAD * (360.0f / nRingSegments);\n\tMatrix4 xf2;\n\tint seg = 0.0f;\n\tint ctri = 0;\n\tint p1, p2, p3, p4;\n\tfor (int vi = 0; vi < m->nVerts;) {\n\t\txf2.Identity();\n\t\txf2.Rotate(rStep * seg, 0.0f, 0.0f, 1.0f);\n\t\tfor (int r = 0; r < nRingSteps; r++) {\n\t\t\tm->verts[vi] = xf3 * xf2 * loftVerts[r];\n\t\t\tif (seg > 0) {\n\t\t\t\tp1 = vi;\n\t\t\t\tp3 = vi - nRingSteps;\n\t\t\t\tif (r == nRingSteps - 1) {\n\t\t\t\t\tp2 = vi - (nRingSteps - 1);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tp2 = vi + 1;\n\t\t\t\t}\n\t\t\t\tp4 = p2 - nRingSteps;\n\t\t\t\tm->tris[ctri++] = Triangle(p1, p2, p3);\n\t\t\t\tm->tris[ctri++] = Triangle(p3, p2, p4);\n\t\t\t}\n\t\t\tvi++;\n\t\t}\n\t\tseg++;\n\t}\n\n\t// last segment needs tris\n\tfor (int r = 0; r < nRingSteps; r++) {\n\t\tp1 = r;\n\t\tp3 = m->nVerts - (nRingSteps - r);\n\t\tif (r == (nRingSteps - 1)) {\n\t\t\tp2 = 0;\n\t\t\tp4 = m->nVerts - nRingSteps;\n\t\t}\n\t\telse {\n\t\t\tp2 = r + 1;\n\t\t\tp4 = p3 + 1;\n\t\t}\n\t\tm->tris[ctri++] = Triangle(p1, p2, p3);\n\t\tm->tris[ctri++] = Triangle(p3, p2, p4);\n\t}\n\n\tm->CreateBuffers();\n\treturn m;\n}\n\n\nMesh* GLSurface::AddVis3dArrow(const Vector3& origin, const Vector3& direction, float stemRadius, float pointRadius, float length, const Vector3& color, const std::string& name) {\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tconst int nRingVerts = 36;\n\tMatrix4 rotMat;\n\n\tMesh* m = GetOverlay(name);\n\tif (!m) {\n\t\tm = new Mesh();\n\t\tm->nVerts = nRingVerts * 3 + 1; // base ring, inner point ring, outer point ring, and the tip\n\t\tm->nTris = nRingVerts * 5;\n\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\t\tm->shapeName = name;\n\t\tm->rendermode = Mesh::RenderMode::UnlitSolid;\n\t\tm->material = GetPrimitiveMaterial();\n\n\t\tAddOverlay(m);\n\t}\n\n\tm->nEdges = 0;\n\tm->color = color;\n\n\trotMat.Align(Vector3(0.0f, 0.0f, 1.0f), direction);\n\trotMat.Translate(origin);\n\n\tfloat rStep = DEG2RAD * (360.0f / nRingVerts);\n\tfloat i = 0.0f;\n\tfloat stemlen = length * 4.0 / 5.0;\n\tfor (int j = 0; j < nRingVerts; j++) {\n\t\tfloat si = sin(i);\n\t\tfloat ci = cos(i);\n\t\tm->verts[j].x = si * stemRadius;\n\t\tm->verts[j + nRingVerts].x = m->verts[j].x;\n\t\tm->verts[j + (nRingVerts * 2)].x = si * pointRadius;\n\t\tm->verts[j].y = ci * stemRadius;\n\t\tm->verts[j + nRingVerts].y = m->verts[j].y;\n\t\tm->verts[j + (nRingVerts * 2)].y = ci * pointRadius;\n\t\tm->verts[j].z = 0;\n\t\tm->verts[j + nRingVerts].z = stemlen;\n\t\tm->verts[j + (nRingVerts * 2)].z = stemlen;\n\t\ti += rStep;\n\t\tm->verts[j] = rotMat * m->verts[j];\n\t\tm->verts[j + nRingVerts] = rotMat * m->verts[j + nRingVerts];\n\t\tm->verts[j + (nRingVerts * 2)] = rotMat * m->verts[j + (nRingVerts * 2)];\n\t}\n\n\tm->verts[m->nVerts - 1].x = 0;\n\tm->verts[m->nVerts - 1].y = 0;\n\tm->verts[m->nVerts - 1].z = length;\n\tm->verts[m->nVerts - 1] = rotMat * m->verts[m->nVerts - 1];\n\n\tint p1, p2, p3, p4, p5, p6, p7;\n\tp7 = m->nVerts - 1;\n\tint t = 0;\n\tfor (int j = 0; j < nRingVerts; j++) {\n\t\tp1 = j;\n\t\tp3 = j + nRingVerts;\n\t\tp5 = j + nRingVerts * 2;\n\t\tif (j < nRingVerts - 1) {\n\t\t\tp2 = j + 1;\n\t\t\tp4 = j + nRingVerts + 1;\n\t\t\tp6 = j + nRingVerts * 2 + 1;\n\t\t}\n\t\telse {\n\t\t\tp2 = 0;\n\t\t\tp4 = nRingVerts;\n\t\t\tp6 = nRingVerts * 2;\n\t\t}\n\t\tm->tris[t].p1 = p1;\n\t\tm->tris[t].p2 = p2;\n\t\tm->tris[t].p3 = p3;\n\t\tm->tris[t + 1].p1 = p3;\n\t\tm->tris[t + 1].p2 = p2;\n\t\tm->tris[t + 1].p3 = p4;\n\t\tm->tris[t + 2].p1 = p3;\n\t\tm->tris[t + 2].p2 = p4;\n\t\tm->tris[t + 2].p3 = p5;\n\t\tm->tris[t + 3].p1 = p5;\n\t\tm->tris[t + 3].p2 = p4;\n\t\tm->tris[t + 3].p3 = p6;\n\t\tm->tris[t + 4].p1 = p5;\n\t\tm->tris[t + 4].p2 = p6;\n\t\tm->tris[t + 4].p3 = p7;\n\t\tt += 5;\n\t}\n\n\tm->CreateBuffers();\n\treturn m;\n}\n\nMesh* GLSurface::AddVis3dCube(const Vector3& center, const Vector3& normal, float radius, const Vector3& color, const std::string& name) {\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tconst int nCubeVerts = 8;\n\tconst int nCubeTris = 12;\n\n\tMesh* m = GetOverlay(name);\n\tif (!m) {\n\t\tm = new Mesh();\n\n\t\tm->nVerts = nCubeVerts;\n\t\tm->nTris = nCubeTris;\n\t\tm->nEdges = 0;\n\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\t\tm->tris[0] = Triangle(0, 1, 2);\n\t\tm->tris[1] = Triangle(2, 3, 0);\n\t\tm->tris[2] = Triangle(1, 5, 6);\n\t\tm->tris[3] = Triangle(6, 2, 1);\n\t\tm->tris[4] = Triangle(7, 6, 5);\n\t\tm->tris[5] = Triangle(5, 4, 7);\n\t\tm->tris[6] = Triangle(4, 0, 3);\n\t\tm->tris[7] = Triangle(3, 7, 4);\n\t\tm->tris[8] = Triangle(4, 5, 1);\n\t\tm->tris[9] = Triangle(1, 0, 4);\n\t\tm->tris[10] = Triangle(3, 2, 6);\n\t\tm->tris[11] = Triangle(6, 7, 3);\n\n\t\tm->shapeName = name;\n\t\tm->rendermode = Mesh::RenderMode::UnlitSolid;\n\t\tm->material = GetPrimitiveMaterial();\n\n\t\tAddOverlay(m);\n\t}\n\n\tm->color = color;\n\n\tMatrix4 mat;\n\tmat.Align(Vector3(0.0f, 0.0f, 1.0f), normal);\n\tmat.Scale(radius, radius, radius);\n\tmat.Translate(center);\n\n\tm->verts[0] = mat * Vector3(-1.0f, -1.0f, 1.0f);\n\tm->verts[1] = mat * Vector3(1.0f, -1.0f, 1.0f);\n\tm->verts[2] = mat * Vector3(1.0f, 1.0f, 1.0f);\n\tm->verts[3] = mat * Vector3(-1.0f, 1.0f, 1.0f);\n\tm->verts[4] = mat * Vector3(-1.0f, -1.0f, -1.0f);\n\tm->verts[5] = mat * Vector3(1.0f, -1.0f, -1.0f);\n\tm->verts[6] = mat * Vector3(1.0f, 1.0f, -1.0f);\n\tm->verts[7] = mat * Vector3(-1.0f, 1.0f, -1.0f);\n\n\tm->CreateBuffers();\n\treturn m;\n}\n\nMesh* GLSurface::AddVisPlane(const Matrix4& mat, const Vector2& size, float uvScale, float uvOffset, const std::string& name, const Vector3* color, const bool asMesh) {\n\tMesh* m = nullptr;\n\n\tif (!name.empty()) {\n\t\tif (asMesh)\n\t\t\tm = GetMesh(name);\n\t\telse\n\t\t\tm = GetOverlay(name);\n\t}\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tif (!m) {\n\t\tm = new Mesh();\n\n\t\tm->nVerts = 4;\n\t\tm->nTris = 2;\n\t\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\t\tm->texcoord = std::make_unique<Vector2[]>(m->nVerts);\n\t\tm->tris = std::make_unique<Triangle[]>(m->nTris);\n\n\t\tm->tris[0] = Triangle(0, 1, 2);\n\t\tm->tris[1] = Triangle(2, 3, 0);\n\n\t\tm->shapeName = name;\n\t\tm->rendermode = Mesh::RenderMode::UnlitSolid;\n\t\tm->material = GetPrimitiveMaterial();\n\t\tm->doublesided = true;\n\n\t\tif (asMesh)\n\t\t\tAddMesh(m);\n\t\telse\n\t\t\tAddOverlay(m);\n\t}\n\n\tif (color)\n\t\tm->color = *color;\n\n\tm->verts[0] = mat * Vector3(-size.u / 2.0f, -size.v / 2.0f, 0.0f);\n\tm->verts[1] = mat * Vector3(-size.u / 2.0f, size.v / 2.0f, 0.0f);\n\tm->verts[2] = mat * Vector3(size.u / 2.0f, size.v / 2.0f, 0.0f);\n\tm->verts[3] = mat * Vector3(size.u / 2.0f, -size.v / 2.0f, 0.0f);\n\n\tm->texcoord[0] = Vector2(uvOffset, uvScale + uvOffset);\n\tm->texcoord[1] = Vector2(uvOffset, uvOffset);\n\tm->texcoord[2] = Vector2(uvScale + uvOffset, uvOffset);\n\tm->texcoord[3] = Vector2(uvScale + uvOffset, uvScale + uvOffset);\n\n\tm->textured = true;\n\n\tm->CreateBuffers();\n\treturn m;\n}\n\nMesh* GLSurface::AddVisEdges(const Mesh* refMesh, const std::vector<Edge>& edges, const std::string& name, const Vector3& color) {\n\tif (!refMesh || edges.empty())\n\t\treturn nullptr;\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tauto m = new Mesh();\n\tm->nVerts = refMesh->nVerts;\n\tm->nEdges = static_cast<int>(edges.size());\n\n\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\tm->edges = std::make_unique<Edge[]>(m->nEdges);\n\n\tfor (int v = 0; v < refMesh->nVerts; v++)\n\t\tm->verts[v] = refMesh->verts[v];\n\n\tfor (size_t e = 0; e < edges.size(); e++)\n\t\tm->edges[e] = edges[e];\n\n\tm->shapeName = name;\n\tm->color = color;\n\tm->material = GetPrimitiveMaterial();\n\tm->CreateBuffers();\n\n\tm->rendermode = Mesh::RenderMode::UnlitWire;\n\tAddOverlay(m);\n\n\treturn m;\n}\n\nMesh* GLSurface::AddVisSeg(const Vector3& p1, const Vector3& p2, const std::string& name, const bool asMesh) {\n\tMesh* m = nullptr;\n\n\tif (!name.empty()) {\n\t\tif (asMesh)\n\t\t\tm = GetMesh(name);\n\t\telse\n\t\t\tm = GetOverlay(name);\n\n\t\tif (m) {\n\t\t\tm->verts[0] = p1;\n\t\t\tm->verts[1] = p2;\n\t\t\tm->bVisible = true;\n\t\t\tm->QueueUpdate(Mesh::UpdateType::Position);\n\t\t\treturn m;\n\t\t}\n\t}\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tm = new Mesh();\n\n\tm->nVerts = 2;\n\tm->nEdges = 1;\n\tm->verts = std::make_unique<Vector3[]>(2);\n\tm->edges = std::make_unique<Edge[]>(1);\n\tm->verts[0] = p1;\n\tm->verts[1] = p2;\n\tm->edges[0].p1 = 0;\n\tm->edges[0].p2 = 1;\n\n\tm->shapeName = name;\n\tm->color = Vector3(0.0f, 1.0f, 1.0f);\n\tm->material = GetPrimitiveMaterial();\n\tm->CreateBuffers();\n\n\tif (asMesh) {\n\t\tm->rendermode = Mesh::RenderMode::UnlitWireDepth;\n\t\tAddMesh(m);\n\t}\n\telse {\n\t\tm->rendermode = Mesh::RenderMode::UnlitWire;\n\t\tAddOverlay(m);\n\t}\n\n\treturn m;\n}\n\nMesh* GLSurface::AddVisSeamEdges(const Mesh* refMesh, bool asMesh) {\n\tif (!refMesh)\n\t\treturn nullptr;\n\n\tstd::string name = refMesh->shapeName + \"_seamedges\";\n\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tif (!refMesh->bGotWeldVerts || refMesh->weldVerts.empty())\n\t\treturn nullptr;\n\n\tstd::vector<Vector3> verts(refMesh->nVerts);\n\tfor (int i = 0; i < refMesh->nVerts; i++)\n\t\tverts[i] = refMesh->verts[i];\n\n\tstd::vector<Edge> edges;\n\n\t// Find edges of welded vertices\n\tfor (int e = 0; e < refMesh->nEdges; e++) {\n\t\tauto& edge = refMesh->edges[e];\n\t\tauto p1It = refMesh->weldVerts.find(edge.p1);\n\t\tauto p2It = refMesh->weldVerts.find(edge.p2);\n\t\tif (p1It != refMesh->weldVerts.end() && p2It != refMesh->weldVerts.end()) {\n\t\t\t// Both points of the edge are welded\n\t\t\tedges.push_back(edge);\n\t\t}\n\t}\n\n\t// Erase edges that aren't outer seam edges\n\tfor (auto it = edges.begin(); it != edges.end();) {\n\t\tsize_t p1Count = 0;\n\t\tsize_t p2Count = 0;\n\t\tauto& edge = *it;\n\t\tfor (const auto& otherEdge : edges) {\n\t\t\tif (otherEdge.p1 == edge.p1 || otherEdge.p2 == edge.p1)\n\t\t\t\tp1Count++;\n\t\t\tif (otherEdge.p2 == edge.p2 || otherEdge.p1 == edge.p2)\n\t\t\t\tp2Count++;\n\t\t}\n\n\t\t// If both points occur three or more times, the edge is not an outer edge\n\t\tif (p1Count >= 3 && p2Count >= 3)\n\t\t\tit = edges.erase(it);\n\t\telse\n\t\t\tit++;\n\t}\n\n\tauto m = new Mesh();\n\tm->nVerts = static_cast<int>(verts.size());\n\tm->nEdges = static_cast<int>(edges.size());\n\n\tm->verts = std::make_unique<Vector3[]>(m->nVerts);\n\tm->edges = std::make_unique<Edge[]>(m->nEdges);\n\n\tfor (size_t v = 0; v < verts.size(); v++)\n\t\tm->verts[v] = verts[v];\n\n\tfor (size_t e = 0; e < edges.size(); e++)\n\t\tm->edges[e] = edges[e];\n\n\tm->shapeName = name;\n\tm->color = Vector3(1.0f, 1.0f, 0.0f);\n\tm->material = GetPrimitiveMaterial();\n\tm->CreateBuffers();\n\n\tif (asMesh) {\n\t\tm->rendermode = Mesh::RenderMode::UnlitWireDepth;\n\t\tAddMesh(m);\n\t}\n\telse {\n\t\tm->rendermode = Mesh::RenderMode::UnlitWire;\n\t\tAddOverlay(m);\n\t}\n\n\treturn m;\n}\n\nstd::vector<Mesh*> GLSurface::AddFloor(float width, float stepSmall, float stepBig) {\n\tstd::vector<Mesh*> floorMeshes;\n\n\tfloat widthHalf = width / 2.0f;\n\tint numLinesSmall = (int)(width / stepSmall) + 1;\n\tint numLinesBig = (int)(width / stepBig) + 1;\n\n\tMatrix4 floorMat;\n\tfloorMat.Rotate(90.0f * DEG2RAD, 1.0f, 0.0f, 0.0f);\n\n\tVector3 floorColor(0.0f, 0.0f, 1.0f);\n\tauto floorMesh = AddVisPlane(floorMat, Vector2(width, width), 1.0f, 0.0f, \"\", &floorColor, true);\n\tif (floorMesh) {\n\t\tfloorMesh->prop.alpha = 0.05f;\n\t\tfloorMeshes.push_back(floorMesh);\n\t}\n\n\tfloat nextLinePos = width - widthHalf;\n\n\t// Floor with width on X and Y axis (big grid)\n\tfor (int i = 0; i < numLinesBig; i++) {\n\t\tVector3 startPos(widthHalf, 0.0f, nextLinePos);\n\t\tVector3 endPos(-widthHalf, 0.0f, nextLinePos);\n\n\t\tauto lineMesh = AddVisSeg(startPos, endPos, \"\", true);\n\t\tif (lineMesh) {\n\t\t\tlineMesh->color.x = 0.0f;\n\t\t\tlineMesh->color.y = 1.0f;\n\t\t\tlineMesh->color.z = 0.0f;\n\t\t\tfloorMeshes.push_back(lineMesh);\n\t\t}\n\n\t\tstartPos = Vector3(nextLinePos, 0.0f, widthHalf);\n\t\tendPos = Vector3(nextLinePos, 0.0f, -widthHalf);\n\n\t\tlineMesh = AddVisSeg(startPos, endPos, \"\", true);\n\t\tif (lineMesh) {\n\t\t\tlineMesh->color.x = 0.0f;\n\t\t\tlineMesh->color.y = 1.0f;\n\t\t\tlineMesh->color.z = 0.0f;\n\t\t\tfloorMeshes.push_back(lineMesh);\n\t\t}\n\n\t\tnextLinePos -= stepBig;\n\t}\n\n\tnextLinePos = width - widthHalf;\n\n\t// Floor with width on X and Y axis (small grid)\n\tfor (int i = 0; i < numLinesSmall; i++) {\n\t\tVector3 startPos(widthHalf, 0.0f, nextLinePos);\n\t\tVector3 endPos(-widthHalf, 0.0f, nextLinePos);\n\n\t\tauto lineMesh = AddVisSeg(startPos, endPos, \"\", true);\n\t\tif (lineMesh) {\n\t\t\tlineMesh->color.x = 0.0f;\n\t\t\tlineMesh->color.y = 1.0f;\n\t\t\tlineMesh->color.z = 0.0f;\n\t\t\tlineMesh->prop.alpha = 0.7f;\n\t\t\tfloorMeshes.push_back(lineMesh);\n\t\t}\n\n\t\tstartPos = Vector3(nextLinePos, 0.0f, widthHalf);\n\t\tendPos = Vector3(nextLinePos, 0.0f, -widthHalf);\n\n\t\tlineMesh = AddVisSeg(startPos, endPos, \"\", true);\n\t\tif (lineMesh) {\n\t\t\tlineMesh->color.x = 0.0f;\n\t\t\tlineMesh->color.y = 1.0f;\n\t\t\tlineMesh->color.z = 0.0f;\n\t\t\tlineMesh->prop.alpha = 0.7f;\n\t\t\tfloorMeshes.push_back(lineMesh);\n\t\t}\n\n\t\tnextLinePos -= stepSmall;\n\t}\n\n\treturn floorMeshes;\n}\n\nvoid GLSurface::Update(const std::string& shapeName, std::vector<Vector3>* vertices, std::vector<Vector2>* uvs, std::unordered_set<int>* changed) {\n\tMesh* m = GetMesh(shapeName);\n\tif (!m)\n\t\treturn;\n\n\tUpdate(m, vertices, uvs, changed);\n}\n\nvoid GLSurface::Update(Mesh* m, std::vector<Vector3>* vertices, std::vector<Vector2>* uvs, std::unordered_set<int>* changed) {\n\tif (m->nVerts != static_cast<int>(vertices->size()))\n\t\treturn;\n\n\tint uvSize = 0;\n\tif (uvs)\n\t\tuvSize = uvs->size();\n\n\tVector3 old;\n\tfor (int i = 0; i < m->nVerts; i++) {\n\t\tif (changed)\n\t\t\told = m->verts[i];\n\n\t\tm->verts[i] = Mesh::TransformPosNifToMesh((*vertices)[i]);\n\n\t\tif (uvSize > i)\n\t\t\tm->texcoord[i] = (*uvs)[i];\n\n\t\tif (changed && old != m->verts[i])\n\t\t\t(*changed).insert(i);\n\t}\n\n\tm->QueueUpdate(Mesh::UpdateType::Position);\n\tif (uvs)\n\t\tm->QueueUpdate(Mesh::UpdateType::TextureCoordinates);\n}\n\nvoid GLSurface::RecalculateMeshBVH(const std::string& shapeName) {\n\tMesh* m = GetMesh(shapeName);\n\tif (!m)\n\t\treturn;\n\n\tm->CreateBVH();\n}\n\nbool GLSurface::SetMeshVisibility(const std::string& name, bool visible) {\n\tbool changed = false;\n\n\tMesh* m = GetMesh(name);\n\tif (!m)\n\t\treturn changed;\n\n\tif (m->bVisible != visible)\n\t\tchanged = true;\n\n\tm->bVisible = visible;\n\treturn changed;\n}\n\nvoid GLSurface::SetOverlayVisibility(const std::string& name, bool visible) {\n\tMesh* m = GetOverlay(name);\n\tif (m)\n\t\tm->bVisible = visible;\n}\n\nvoid GLSurface::SetActiveMeshes(const std::vector<std::string>& shapeNames) {\n\tactiveMeshes.clear();\n\n\tfor (auto& s : shapeNames) {\n\t\tMesh* m = GetMesh(s);\n\t\tif (m)\n\t\t\tactiveMeshes.push_back(m);\n\t}\n}\n\nvoid GLSurface::SetSelectedMesh(const std::string& shapeName) {\n\tselectedMesh = GetMesh(shapeName);\n}\n\nMesh::RenderMode GLSurface::SetMeshRenderMode(const std::string& name, Mesh::RenderMode mode) {\n\tMesh* m = GetMesh(name);\n\tif (!m)\n\t\treturn Mesh::RenderMode::Normal;\n\n\tMesh::RenderMode r = m->rendermode;\n\tm->rendermode = mode;\n\treturn r;\n}\n\nGLMaterial* GLSurface::AddMaterial(const std::vector<std::string>& textureFiles, const std::string& vShaderFile, const std::string& fShaderFile, const bool reloadTextures) {\n\tif (!SetContext())\n\t\treturn nullptr;\n\n\tGLMaterial* mat = resLoader.AddMaterial(textureFiles, vShaderFile, fShaderFile, reloadTextures);\n\tif (mat) {\n\t\tstd::string shaderError;\n\t\tif (mat->GetShader().GetError(&shaderError)) {\n\t\t\twxLogError(wxString(shaderError));\n\t\t\twxMessageBox(shaderError, _(\"OpenGL Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\n\treturn mat;\n}\n\nGLMaterial* GLSurface::GetPointsMaterial() {\n\tif (!pointsMat) {\n\t\tif (!SetContext())\n\t\t\treturn nullptr;\n\n\t\tpointsMat = new GLMaterial(Config[\"AppDir\"] + \"/res/shaders/points.vert\", Config[\"AppDir\"] + \"/res/shaders/points.frag\");\n\n\t\tstd::string shaderError;\n\t\tif (pointsMat->GetShader().GetError(&shaderError)) {\n\t\t\twxLogError(wxString(shaderError));\n\t\t\twxMessageBox(shaderError, _(\"OpenGL Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\n\treturn pointsMat;\n}\n\nGLMaterial* GLSurface::GetPrimitiveMaterial() {\n\tif (!primitiveMat) {\n\t\tif (!SetContext())\n\t\t\treturn nullptr;\n\n\t\tprimitiveMat = new GLMaterial(Config[\"AppDir\"] + \"/res/shaders/primitive.vert\", Config[\"AppDir\"] + \"/res/shaders/primitive.frag\");\n\n\t\tstd::string shaderError;\n\t\tif (primitiveMat->GetShader().GetError(&shaderError)) {\n\t\t\twxLogError(wxString(shaderError));\n\t\t\twxMessageBox(shaderError, _(\"OpenGL Error\"), wxICON_ERROR);\n\t\t}\n\t}\n\n\treturn primitiveMat;\n}\n"
  },
  {
    "path": "src/render/GLSurface.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"GLMaterial.h\"\n#include \"NifFile.hpp\"\n\n#include <wx/glcanvas.h>\n\nclass GLSurface {\npublic:\n\tenum CursorType {\n\t\tNone = 0,\n\t\tCenterCursor = 1,\n\t\tPointCursor = 2,\n\t\tCircleCursor = 4,\n\t\tSegCursor = 8,\n\t\tBrushCursor = CenterCursor | PointCursor | CircleCursor,\n\t\tVertexCursor = CenterCursor | PointCursor,\n\t\tEdgeCursor = CenterCursor | SegCursor\n\t};\n\nprivate:\n\twxGLCanvas* canvas = nullptr;\n\twxGLContext* context = nullptr;\n\n\tglm::mat4x4 matProjection = glm::identity<glm::mat4x4>();\n\tglm::mat4x4 matView = glm::identity<glm::mat4x4>();\n\tuint32_t vpW = 800;\n\tuint32_t vpH = 600;\n\n\tGLfloat largestAF = 0;\n\n\tbool bWireframe = false;\n\tbool bLighting = true;\n\tbool bTextured = true;\n\tbool bMaskVisible = true;\n\tbool bWeightColors = false;\n\tbool bVertexColors = false;\n\n\tfloat defLineWidth = 1.0f;\n\tfloat defPointSize = 5.0f;\n\tfloat cursorSize = 0.5f;\n\tCursorType cursorType = CursorType::None;\n\tbool xmirrorCursor = false;\n\n\tGLShader::DirectionalLight frontalLight;\n\tGLShader::DirectionalLight directionalLight0;\n\tGLShader::DirectionalLight directionalLight1;\n\tGLShader::DirectionalLight directionalLight2;\n\tfloat ambientLight = 0.2f;\n\n\tnifly::Vector3 colorBackground = nifly::Vector3(0.82f, 0.82f, 0.82f);\n\tnifly::Vector3 colorWire = nifly::Vector3(0.3137f, 0.3137f, 0.3137f);\n\tnifly::Vector3 colorPoints = nifly::Vector3(0.0f, 1.0f, 0.0f);\n\tnifly::Vector3 colorPointsMasked = nifly::Vector3(1.0f, 0.0f, 0.0f);\n\tnifly::Vector3 colorRed = nifly::Vector3(1.0f, 0.25f, 0.25f);\n\tnifly::Vector3 colorGreen = nifly::Vector3(0.25f, 1.0f, 0.25f);\n\n\tResourceLoader resLoader;\n\tGLMaterial* pointsMat = nullptr;\n\tGLMaterial* primitiveMat = nullptr;\n\n\tstd::vector<Mesh*> meshes;\n\tstd::vector<Mesh*> overlays;\n\n\tstd::vector<Mesh*> activeMeshes;\n\tMesh* selectedMesh = nullptr;\n\n\tvoid InitLighting();\n\tvoid InitGLExtensions();\n\tint InitGLSettings();\n\npublic:\n\t// Get the attributes to use for creating a wxGLCanvas\n\tstatic const wxGLAttributes& GetGLAttribs();\n\tstatic const wxGLContextAttrs& GetGLContextAttribs();\n\n\tbool perspective = true;\n\tfloat mFov = 90.0f;\n\tfloat zNear = 0.1f;\n\tfloat zFar = 1000.0f;\n\tnifly::Vector3 camPos;\n\tnifly::Vector3 camOffset;\n\tnifly::Vector3 camRot; // Turntable camera emulation.\n\tnifly::Vector3 camRotOffset;\n\n\tnifly::Vector3 GetBackgroundColor() const { return colorBackground; }\n\tvoid SetBackgroundColor(const nifly::Vector3& color) { colorBackground = color; }\n\n\tnifly::Vector3 GetWireColor() const { return colorWire; }\n\tvoid SetWireColor(const nifly::Vector3& color) { colorWire = color; }\n\n\tnifly::Vector3 GetPointColor() const { return colorPoints; }\n\tvoid SetPointColor(const nifly::Vector3& color) { colorPoints = color; }\n\n\tnifly::Vector3 GetMaskedPointColor() const { return colorPointsMasked; }\n\tvoid SetMaskedPointColor(const nifly::Vector3& color) { colorPointsMasked = color; }\n\n\tvoid ClearMeshes() {\n\t\tSetContext();\n\n\t\tfor (auto& m : meshes)\n\t\t\tdelete m;\n\n\t\tmeshes.clear();\n\t\tactiveMeshes.clear();\n\t}\n\n\tvoid DeleteMesh(Mesh* m) {\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tauto it = std::find(meshes.begin(), meshes.end(), m);\n\t\tif (it != meshes.end()) {\n\t\t\tactiveMeshes.erase(std::remove(activeMeshes.begin(), activeMeshes.end(), m), activeMeshes.end());\n\t\t\tmeshes.erase(it);\n\n\t\t\tSetContext();\n\t\t\tdelete m;\n\t\t}\n\t}\n\n\tvoid DeleteMesh(const std::string& shapeName) { DeleteMesh(GetMesh(shapeName)); }\n\n\tvoid ClearOverlays() {\n\t\tSetContext();\n\n\t\tfor (auto& m : overlays)\n\t\t\tdelete m;\n\n\t\toverlays.clear();\n\t}\n\n\tvoid DeleteOverlay(Mesh* m) {\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tauto it = std::find(overlays.begin(), overlays.end(), m);\n\t\tif (it != overlays.end()) {\n\t\t\toverlays.erase(it);\n\n\t\t\tSetContext();\n\t\t\tdelete m;\n\t\t}\n\t}\n\n\tvoid DeleteOverlay(const std::string& shapeName) { DeleteOverlay(GetOverlay(shapeName)); }\n\n\tvoid RenameMesh(const std::string& shapeName, const std::string& newShapeName) {\n\t\tMesh* m = GetMesh(shapeName);\n\t\tif (m)\n\t\t\tm->shapeName = newShapeName;\n\t}\n\n\tstd::vector<Mesh*> GetActiveMeshes() { return activeMeshes; }\n\n\tnifly::Vector3 GetActiveCenter(bool useMask = true) {\n\t\tif (activeMeshes.empty())\n\t\t\treturn nifly::Vector3();\n\n\t\tint count = 0;\n\t\tnifly::Vector3 total;\n\n\t\tfor (auto& m : activeMeshes) {\n\t\t\tfor (int i = 0; i < m->nVerts; i++) {\n\t\t\t\tif (!useMask || m->mask[i] == 0.0f) {\n\t\t\t\t\ttotal += m->TransformPosMeshToModel(m->verts[i]);\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (count <= 0)\n\t\t\treturn nifly::Vector3();\n\n\t\ttotal /= count;\n\t\treturn total;\n\t}\n\n\tvoid AddMesh(Mesh* m) {\n\t\tif (!m->shapeName.empty())\n\t\t\tDeleteMesh(m->shapeName);\n\n\t\tmeshes.push_back(m);\n\t}\n\n\tvoid AddOverlay(Mesh* m) {\n\t\tif (!m->shapeName.empty())\n\t\t\tDeleteOverlay(m->shapeName);\n\n\t\toverlays.push_back(m);\n\t}\n\n\tMesh* GetMesh(const std::string& shapeName) {\n\t\tauto it = std::find_if(meshes.begin(), meshes.end(), [&shapeName](Mesh* m) { return m->shapeName == shapeName; });\n\t\tif (it != meshes.end())\n\t\t\treturn (*it);\n\n\t\treturn nullptr;\n\t}\n\n\tconst std::vector<Mesh*>& GetMeshes() { return meshes; }\n\n\tconst std::vector<Mesh*> GetMeshesFiltered() {\n\t\tstd::vector<Mesh*> filteredMeshes;\n\n\t\tfor (auto& m : meshes)\n\t\t\tif (m->rendermode == Mesh::RenderMode::Normal)\n\t\t\t\tfilteredMeshes.push_back(m);\n\n\t\treturn filteredMeshes;\n\t}\n\n\tMesh* GetOverlay(const std::string& shapeName) {\n\t\tauto it = std::find_if(overlays.begin(), overlays.end(), [&shapeName](Mesh* m) { return m->shapeName == shapeName; });\n\t\tif (it != overlays.end())\n\t\t\treturn (*it);\n\n\t\treturn nullptr;\n\t}\n\n\tfloat GetCursorSize() { return cursorSize; }\n\n\tvoid SetCursorSize(float newsize) { cursorSize = newsize; }\n\n\tCursorType GetCursorType() const { return cursorType; }\n\tvoid SetCursorType(CursorType newType) { cursorType = newType; }\n\tvoid SetXMirrorCursor(bool newval) { xmirrorCursor = newval; }\n\n\tint Initialize(wxGLCanvas* canvas, wxGLContext* context);\n\tvoid Cleanup();\n\n\tvoid SetStartingView(const nifly::Vector3& camPos, const nifly::Vector3& camRot, const uint32_t& vpWidth, const uint32_t& vpHeight, const float& fov = 65.0f);\n\tvoid SetSize(uint32_t w, uint32_t h);\n\tvoid GetSize(uint32_t& w, uint32_t& h);\n\tvoid UpdateProjection();\n\n\tvoid RenderFullScreenQuad(GLMaterial* renderShader, unsigned int w, unsigned int h);\n\n\tvoid TurnTableCamera(int dScreenX);\n\tvoid PitchCamera(int dScreenY);\n\tvoid PanCamera(int dScreenX, int dScreenY);\n\tvoid DollyCamera(int dAmount);\n\tvoid ClampCameraPosition(char axis, float lower, float upper);\n\tvoid UnprojectCamera(nifly::Vector3& result);\n\n\tvoid SetView(const char type);\n\tvoid SetPerspective(const bool enabled);\n\tvoid SetFieldOfView(const int fieldOfView);\n\tvoid SetDepthClip(const float zNear, const float zFar);\n\tvoid UpdateLights(const int ambient,\n\t\t\t\t\t  const int frontal,\n\t\t\t\t\t  const int directional0,\n\t\t\t\t\t  const int directional1,\n\t\t\t\t\t  const int directional2,\n\t\t\t\t\t  const nifly::Vector3& directional0Dir,\n\t\t\t\t\t  const nifly::Vector3& directional1Dir,\n\t\t\t\t\t  const nifly::Vector3& directional2Dir);\n\n\tvoid ProjectPointToScreen(const nifly::Vector3& p, int& x, int& y);\n\n\tvoid GetPickRay(int ScreenX, int ScreenY, Mesh* m, nifly::Vector3& dirVect, nifly::Vector3& outNearPos);\n\tMesh* PickMesh(int ScreenX, int ScreenY);\n\n\tstruct CursorHitResult {\n\t\tMesh* hitMesh = nullptr;\n\t\tstd::string hitMeshName;\n\t\tint hoverPoint = -1;\n\t\tfloat hoverMask = 0.0f;\n\t\tfloat hoverWeight = 0.0f;\n\t\tnifly::Vector3 hoverColor = nifly::Vector3(1.0f, 1.0f, 1.0f);\n\t\tfloat hoverAlpha = 1.0f;\n\t\tnifly::Edge hoverEdge;\n\t\tnifly::Vector3 hoverMeshCoord;\n\t\tnifly::Vector3 hoverRealCoord;\n\t\tint hoverTri = -1;\n\t};\n\n\tbool UpdateCursor(int ScreenX, int ScreenY, bool allMeshes = true, CursorHitResult* hitResult = nullptr);\n\tbool GetCursorVertex(int ScreenX, int ScreenY, int* outIndex = nullptr, Mesh* hitMesh = nullptr, Mesh** outHitMesh = nullptr);\n\tvoid ShowCursor(bool show = true);\n\tvoid HidePointCursor();\n\tvoid HideSegCursor();\n\tvoid SetPointCursor(const nifly::Vector3 &p, Mesh*m = nullptr);\n\tvoid SetCenterCursor(const nifly::Vector3 &p, Mesh*m = nullptr);\n\tvoid ShowMirrorPointCursor(const nifly::Vector3 &p, Mesh*m = nullptr);\n\n\t// Ray/mesh collision detection. From a screen point, calculates a ray and finds the nearest collision point and surface normal on\n\t// the active mesh.  The outOrigin and outNormal results are in mesh coordinates.\n\tbool CollideMeshes(int ScreenX,\n\t\t\t\t\t   int ScreenY,\n\t\t\t\t\t   nifly::Vector3& outOrigin,\n\t\t\t\t\t   nifly::Vector3& outNormal,\n\t\t\t\t\t   bool mirrored = false,\n\t\t\t\t\t   Mesh** hitMesh = nullptr,\n\t\t\t\t\t   bool allMeshes = true,\n\t\t\t\t\t   int* outFacet = nullptr);\n\tbool CollidePlane(int ScreenX, int ScreenY, nifly::Vector3& outOrigin, const nifly::Vector3& inPlaneNormal, float inPlaneDist);\n\tbool CollideOverlay(int ScreenX, int ScreenY, nifly::Vector3& outOrigin, nifly::Vector3& outNormal, Mesh** hitMesh = nullptr, int* outFacet = nullptr);\n\n\tMesh* AddVisCircle(const nifly::Vector3& center, const nifly::Vector3& normal, float radius, const std::string& name = \"RingMesh\");\n\tMesh* AddVis3dSphere(const nifly::Vector3& center, float radius, const nifly::Vector3& color, const std::string& name, bool asMesh = false);\n\tMesh* AddVis3dRing(const nifly::Vector3& center, const nifly::Vector3& normal, float holeRadius, float ringRadius, const nifly::Vector3& color, const std::string& name);\n\tMesh* AddVis3dArrow(\n\t\tconst nifly::Vector3& origin, const nifly::Vector3& direction, float stemRadius, float pointRadius, float length, const nifly::Vector3& color, const std::string& name);\n\tMesh* AddVis3dCube(const nifly::Vector3& center, const nifly::Vector3& normal, float radius, const nifly::Vector3& color, const std::string& name);\n\tMesh* AddVisPoint(const nifly::Vector3& p, const std::string& name = \"PointMesh\", const nifly::Vector3* color = nullptr);\n\tMesh* AddVisPlane(const nifly::Matrix4& mat,\n\t\t\t\t\t  const nifly::Vector2& size,\n\t\t\t\t\t  float uvScale = 1.0f,\n\t\t\t\t\t  float uvOffset = 0.0f,\n\t\t\t\t\t  const std::string& name = \"PlaneMesh\",\n\t\t\t\t\t  const nifly::Vector3* color = nullptr,\n\t\t\t\t\t  const bool asMesh = false);\n\tMesh* AddVisSeg(const nifly::Vector3& p1, const nifly::Vector3& p2, const std::string& name = \"\", const bool asMesh = false);\n\tMesh* AddVisEdges(const Mesh* refMesh, const std::vector<nifly::Edge>& edges, const std::string& name, const nifly::Vector3& color = nifly::Vector3(1.0f, 0.0f, 0.0f));\n\tMesh* AddVisSeamEdges(const Mesh* refMesh, bool asMesh = false);\n\tstd::vector<Mesh*> AddFloor(float width = 100.0f, float stepSmall = 1.0f, float stepBig = 5.0f);\n\n\tMesh* AddMeshFromNif(nifly::NifFile* nif, const std::string& shapeName, nifly::Vector3* color = nullptr);\n\tvoid Update(const std::string& shapeName, std::vector<nifly::Vector3>* vertices, std::vector<nifly::Vector2>* uvs = nullptr, std::unordered_set<int>* changed = nullptr);\n\tvoid Update(Mesh* m, std::vector<nifly::Vector3>* vertices, std::vector<nifly::Vector2>* uvs = nullptr, std::unordered_set<int>* changed = nullptr);\n\tMesh* ReloadMeshFromNif(nifly::NifFile* nif, std::string shapeName);\n\tvoid RecalculateMeshBVH(const std::string& shapeName);\n\n\tbool SetMeshVisibility(const std::string& name, bool visible = true);\n\tvoid SetOverlayVisibility(const std::string& name, bool visible = true);\n\tvoid SetActiveMeshes(const std::vector<std::string>& shapeNames);\n\tvoid SetSelectedMesh(const std::string& shapeName);\n\n\tMesh::RenderMode SetMeshRenderMode(const std::string& name, Mesh::RenderMode mode);\n\n\tGLMaterial* AddMaterial(const std::vector<std::string>& textureFiles, const std::string& vShaderFile, const std::string& fShaderFile, const bool reloadTextures = false);\n\tGLMaterial* GetPointsMaterial();\n\tGLMaterial* GetPrimitiveMaterial();\n\tResourceLoader* GetResourceLoader() { return &resLoader; }\n\n\tbool SetContext();\n\n\t// Sort function for overlay layer\n\tstruct SortOverlaysLayer {\n\t\tbool operator()(const Mesh* lhs, const Mesh* rhs) { return rhs->overlayLayer > lhs->overlayLayer; }\n\t};\n\n\tvoid RenderOneFrame();\n\tvoid RenderToTexture(GLMaterial* renderShader);\n\tvoid RenderMesh(Mesh* m);\n\tvoid RenderMeshAsPoints(Mesh* m);\n\n\tvoid UpdateShaders(Mesh* m);\n\n\tvoid ToggleTextures() {\n\t\tif (bTextured)\n\t\t\tbTextured = false;\n\t\telse\n\t\t\tbTextured = true;\n\n\t\tfor (auto& m : meshes)\n\t\t\tUpdateShaders(m);\n\n\t\tfor (auto& o : overlays)\n\t\t\tUpdateShaders(o);\n\t}\n\n\tvoid ToggleWireframe() {\n\t\tif (bWireframe)\n\t\t\tbWireframe = false;\n\t\telse\n\t\t\tbWireframe = true;\n\t}\n\n\tvoid ToggleLighting() {\n\t\tif (bLighting)\n\t\t\tbLighting = false;\n\t\telse\n\t\t\tbLighting = true;\n\n\t\tfor (auto& m : meshes)\n\t\t\tUpdateShaders(m);\n\n\t\tfor (auto& o : overlays)\n\t\t\tUpdateShaders(o);\n\t}\n\n\tvoid SetMaskVisible(bool bVisible = true) {\n\t\tbMaskVisible = bVisible;\n\n\t\tfor (auto& m : meshes)\n\t\t\tUpdateShaders(m);\n\n\t\tfor (auto& o : overlays)\n\t\t\tUpdateShaders(o);\n\t}\n\n\tvoid SetWeightColors(bool bVisible = true) {\n\t\tbWeightColors = bVisible;\n\n\t\tfor (auto& m : meshes)\n\t\t\tUpdateShaders(m);\n\n\t\tfor (auto& o : overlays)\n\t\t\tUpdateShaders(o);\n\t}\n\n\tbool GetWeightColors() const { return bWeightColors; }\n\n\tvoid SetVertexColors(bool bVisible = true) {\n\t\tbVertexColors = bVisible;\n\n\t\tfor (auto& m : meshes)\n\t\t\tUpdateShaders(m);\n\n\t\tfor (auto& o : overlays)\n\t\t\tUpdateShaders(o);\n\t}\n};\n"
  },
  {
    "path": "src/ui/PreviewPanel.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PreviewPanel.h\"\n#include \"../program/BodySlideApp.h\"\n#include \"../utils/PlatformUtil.h\"\n\n#include <regex>\n#include <sstream>\n\nusing namespace nifly;\n\nextern ConfigurationManager Config;\nextern ConfigurationManager BodySlideConfig;\n\nwxDEFINE_EVENT(EVT_PREVIEW_POPOUT, wxCommandEvent);\n\nwxBEGIN_EVENT_TABLE(PreviewPanel, wxPanel)\n\tEVT_COMMAND_SCROLL(wxID_ANY, PreviewPanel::OnWeightSlider)\nwxEND_EVENT_TABLE()\n\nPreviewPanel::~PreviewPanel() {}\n\nPreviewPanel::PreviewPanel(wxWindow* parent, BodySlideApp* app)\n\t: wxPanel(parent, wxID_ANY)\n\t, app(app)\n\t, refNormalGenLayers(emptyLayers) {\n\n\twxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);\n\twxBoxSizer* sizerPanel = new wxBoxSizer(wxHORIZONTAL);\n\twxBoxSizer* sizerProjectSelect = new wxBoxSizer(wxHORIZONTAL);\n\n\twxPanel* projectSelectPanel = new wxPanel(this);\n\tprojectLabel = new wxStaticText(projectSelectPanel, wxID_ANY, _(\"Outfit/Body\"));\n\tprojectChoice = new wxChoice(projectSelectPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxArrayString(), 0, wxDefaultValidator, \"projectChoice\");\n\tprojectChoice->Hide();\n\tprojectLabel->Hide();\n\n\tpresetLabel = new wxStaticText(projectSelectPanel, wxID_ANY, _(\"Preset\"));\n\tpresetChoice = new wxChoice(projectSelectPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxArrayString(), 0, wxDefaultValidator, \"presetChoice\");\n\tpresetChoice->Hide();\n\tpresetLabel->Hide();\n\n\tsizerProjectSelect->Add(projectLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\tsizerProjectSelect->Add(projectChoice, 1, wxALL | wxEXPAND, 5);\n\tsizerProjectSelect->Add(presetLabel, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\tsizerProjectSelect->Add(presetChoice, 1, wxALL | wxEXPAND, 5);\n\tprojectSelectPanel->SetSizer(sizerProjectSelect);\n\tprojectSelectPanel->SetBackgroundColour(wxColour(210, 210, 210));\n\n\twxPanel* uiPanel = new wxPanel(this);\n\twxSlider* weightSlider = new wxSlider(uiPanel, wxID_ANY, 100, 0, 100, wxDefaultPosition, wxDefaultSize, wxSL_LABELS, wxDefaultValidator, \"weightSlider\");\n\n\toptButton = new wxButton(uiPanel, wxID_ANY, \"N\", wxDefaultPosition, FromDIP(wxSize(25, 25)));\n\toptButton->SetToolTip(_(\"Show the Normal Map Generator dialog.\"));\n\toptButton->Bind(wxEVT_BUTTON, &PreviewPanel::ShowNormalGenWindow, this);\n\toptButton->Hide();\n\n\tlockShapeButton = new wxButton(uiPanel, wxID_ANY, _(\"Lock Shape\"), wxDefaultPosition, wxDefaultSize);\n\tlockShapeButton->SetToolTip(_(\"Set the current preview shape to both low and high weight sliders.\"));\n\tlockShapeButton->Bind(wxEVT_BUTTON, &PreviewPanel::OnLockShape, this);\n\tlockShapeButton->Hide();\n\n\tshowReferenceCheckbox = new wxCheckBox(uiPanel, wxID_ANY, _(\"Show Reference\"), wxDefaultPosition, wxDefaultSize);\n\tshowReferenceCheckbox->SetToolTip(_(\"Show the reference shape from the source project for clipping preview.\"));\n\tshowReferenceCheckbox->Bind(wxEVT_CHECKBOX, &PreviewPanel::OnShowReference, this);\n\tshowReferenceCheckbox->Hide();\n\n\tuiPanel->SetBackgroundColour(wxColour(210, 210, 210));\n\n\t// Pop-out button (placed in uiPanel, below Lock Shape)\n\tpopoutButton = new wxBitmapButton(uiPanel, wxID_ANY, wxArtProvider::GetBitmap(wxART_NEW_DIR, wxART_BUTTON, FromDIP(wxSize(16, 16))));\n\tpopoutButton->SetToolTip(_(\"Pop out preview into a separate window\"));\n\tpopoutButton->Bind(wxEVT_BUTTON, &PreviewPanel::OnPopout, this);\n\n\tcanvas = new PreviewCanvas(this, GLSurface::GetGLAttribs());\n\tcontext = std::make_unique<wxGLContext>(canvas, nullptr, &GLSurface::GetGLContextAttribs());\n\n\tsizerPanel->Add(weightSlider, 1, wxTOP | wxLEFT | wxRIGHT, 10);\n\n\twxBoxSizer* sizerRight = new wxBoxSizer(wxVERTICAL);\n\tsizerRight->Add(showReferenceCheckbox, 0, wxALIGN_CENTER_HORIZONTAL);\n\n\twxBoxSizer* sizerButtons = new wxBoxSizer(wxHORIZONTAL);\n\tsizerButtons->Add(lockShapeButton, 0, wxALIGN_CENTER_VERTICAL);\n\tsizerButtons->Add(popoutButton, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4);\n\tsizerRight->Add(sizerButtons, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 2);\n\n\tsizerPanel->Add(sizerRight, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);\n\n\tsizerPanel->Add(optButton, 0, wxALL | wxALIGN_BOTTOM, 10);\n\tuiPanel->SetSizer(sizerPanel);\n\n\t// Loading overlay (hidden by default, positioned over canvas)\n\tloadingOverlay = new wxPanel(this, wxID_ANY);\n\tloadingOverlay->SetBackgroundColour(wxColour(64, 64, 64));\n\twxBoxSizer* loadingSizer = new wxBoxSizer(wxVERTICAL);\n\tloadingSizer->AddStretchSpacer();\n\tloadingIndicator = new wxActivityIndicator(loadingOverlay);\n\tloadingSizer->Add(loadingIndicator, 0, wxALIGN_CENTER_HORIZONTAL);\n\twxStaticText* loadingText = new wxStaticText(loadingOverlay, wxID_ANY, _(\"Loading preview...\"));\n\tloadingText->SetForegroundColour(*wxWHITE);\n\tloadingSizer->Add(loadingText, 0, wxALIGN_CENTER_HORIZONTAL | wxTOP, 10);\n\tloadingSizer->AddStretchSpacer();\n\tloadingOverlay->SetSizer(loadingSizer);\n\tloadingOverlay->Hide();\n\n\tsizer->Add(projectSelectPanel, 0, wxEXPAND);\n\tsizer->Add(uiPanel, 0, wxEXPAND);\n\tsizer->Add(canvas, 1, wxEXPAND);\n\n\tSetSizer(sizer);\n\n\t// Reposition floating overlay when canvas resizes\n\tcanvas->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {\n\t\tif (loadingOverlay && loadingOverlay->IsShown()) {\n\t\t\tloadingOverlay->SetSize(canvas->GetRect());\n\t\t}\n\t\tevt.Skip();\n\t});\n\n\tprojectChoice->Bind(wxEVT_CHOICE, &PreviewPanel::OnProjectChoice, this);\n\tpresetChoice->Bind(wxEVT_CHOICE, &PreviewPanel::OnPresetChoice, this);\n}\n\nvoid PreviewPanel::ShowLoadingIndicator(bool show) {\n\tif (show) {\n\t\t// Position overlay on top of the canvas (canvas stays shown for GL ops)\n\t\tloadingOverlay->SetSize(canvas->GetRect());\n\t\tloadingOverlay->Show();\n\t\tloadingOverlay->Raise();\n\t\tloadingIndicator->Start();\n\t}\n\telse {\n\t\tloadingIndicator->Stop();\n\t\tloadingOverlay->Hide();\n\t\tcanvas->Refresh();\n\t}\n}\n\nvoid PreviewPanel::OnShown() {\n\tif (glInitialized)\n\t\treturn;\n\n\tif (!context->IsOK()) {\n\t\tcanvas = nullptr;\n\t\tapp->PreviewClosed();\n\t\twxLogError(\"Preview failed: OpenGL context is not OK.\");\n\t\twxMessageBox(_(\"Preview failed: OpenGL context is not OK.\"), _(\"OpenGL Error\"), wxICON_ERROR);\n\t\treturn;\n\t}\n\n\twxLogMessage(\"Initializing preview panel...\");\n\tgls.Initialize(canvas, context.get());\n\tauto size = canvas->GetClientSize();\n\tint vpW = size.GetWidth() > 0 ? size.GetWidth() : 800;\n\tint vpH = size.GetHeight() > 0 ? size.GetHeight() : 600;\n\tgls.SetStartingView(Vector3(0.0f, -5.0f, -15.0f), Vector3(15.0f, 0.0f, 0.0f), vpW, vpH, 65.0);\n\tgls.SetVertexColors(true);\n\n\tint ambient = Config.GetIntValue(\"Lights/Ambient\");\n\tint frontal = Config.GetIntValue(\"Lights/Frontal\");\n\n\tint directional0 = Config.GetIntValue(\"Lights/Directional0\");\n\tint directional0X = Config.GetIntValue(\"Lights/Directional0.x\");\n\tint directional0Y = Config.GetIntValue(\"Lights/Directional0.y\");\n\tint directional0Z = Config.GetIntValue(\"Lights/Directional0.z\");\n\n\tint directional1 = Config.GetIntValue(\"Lights/Directional1\");\n\tint directional1X = Config.GetIntValue(\"Lights/Directional1.x\");\n\tint directional1Y = Config.GetIntValue(\"Lights/Directional1.y\");\n\tint directional1Z = Config.GetIntValue(\"Lights/Directional1.z\");\n\n\tint directional2 = Config.GetIntValue(\"Lights/Directional2\");\n\tint directional2X = Config.GetIntValue(\"Lights/Directional2.x\");\n\tint directional2Y = Config.GetIntValue(\"Lights/Directional2.y\");\n\tint directional2Z = Config.GetIntValue(\"Lights/Directional2.z\");\n\n\tVector3 directional0Dir = Vector3(directional0X / 100.0f, directional0Y / 100.0f, directional0Z / 100.0f);\n\tVector3 directional1Dir = Vector3(directional1X / 100.0f, directional1Y / 100.0f, directional1Z / 100.0f);\n\tVector3 directional2Dir = Vector3(directional2X / 100.0f, directional2Y / 100.0f, directional2Z / 100.0f);\n\tgls.UpdateLights(ambient, frontal, directional0, directional1, directional2, directional0Dir, directional1Dir, directional2Dir);\n\n\tif (Config.Exists(\"Rendering/ColorBackground\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorBackground.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorBackground.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorBackground.b\");\n\t\tgls.SetBackgroundColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorWire\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorWire.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorWire.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorWire.b\");\n\t\tgls.SetWireColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorPoints\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPoints.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPoints.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPoints.b\");\n\t\tgls.SetPointColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tif (Config.Exists(\"Rendering/ColorPointsMasked\")) {\n\t\tint colorR = Config.GetIntValue(\"Rendering/ColorPointsMasked.r\");\n\t\tint colorG = Config.GetIntValue(\"Rendering/ColorPointsMasked.g\");\n\t\tint colorB = Config.GetIntValue(\"Rendering/ColorPointsMasked.b\");\n\t\tgls.SetMaskedPointColor(Vector3(colorR / 255.0f, colorG / 255.0f, colorB / 255.0f));\n\t}\n\n\tgls.SetPerspective(BodySlideConfig.GetBoolValue(\"Rendering/PerspectiveView\", true));\n\n\tglInitialized = true;\n\n\t// Load deferred project entries\n\tif (!projectEntries.empty()) {\n\t\tif (loadAllProjects) {\n\t\t\tLoadProjects(projectEntries);\n\t\t\tloadAllProjects = false;\n\t\t}\n\t\telse {\n\t\t\tLoadProjects({projectEntries[0]});\n\t\t}\n\t\treturn;\n\t}\n\n\t// Load deferred nifs if in NIF-only preview mode\n\tif (!extraNifPaths.empty()) {\n\t\twxLogMessage(\"Loading %zu nif file(s) in preview mode...\", extraNifPaths.size());\n\t\tShowWeight(false);\n\t\tLoadNifFiles(extraNifPaths);\n\t\tgls.RenderOneFrame();\n\t\treturn;\n\t}\n\n\tapp->InitPreview();\n}\n\nvoid PreviewPanel::LoadNifFiles(const std::vector<std::string>& nifFilePaths) {\n\tfor (const auto& nifPath : nifFilePaths) {\n\t\tstd::fstream file;\n\t\tPlatformUtil::OpenFileStream(file, nifPath, std::ios::in | std::ios::binary);\n\n\t\tNifFile* nifFile = new NifFile();\n\t\tif (nifFile->Load(file)) {\n\t\t\twxLogWarning(\"Failed to load nif file: %s\", nifPath);\n\t\t\tdelete nifFile;\n\t\t\tcontinue;\n\t\t}\n\n\t\twxLogMessage(\"Loading nif: %s\", nifPath);\n\t\tAddMeshFromNif(nifFile);\n\n\t\tfor (auto& s : nifFile->GetShapeNames())\n\t\t\tAddNifShapeTextures(nifFile, s);\n\n\t\tdelete nifFile;\n\t}\n}\n\nvoid PreviewPanel::SetProjectData(const std::vector<PreviewProjectEntry>& entries, bool loadAll) {\n\tprojectEntries = entries;\n\tloadAllProjects = loadAll;\n\n\tif (!loadAll && projectChoice) {\n\t\tprojectChoice->Clear();\n\t\tfor (auto& entry : projectEntries)\n\t\t\tprojectChoice->Append(wxString::FromUTF8(entry.setName));\n\n\t\tif (!projectEntries.empty())\n\t\t\tprojectChoice->SetSelection(0);\n\n\t\tprojectChoice->Show(projectEntries.size() > 1);\n\t\tprojectLabel->Show(projectEntries.size() > 1);\n\n\t\tprojectChoice->GetParent()->Show();\n\t\tLayout();\n\t}\n}\n\nvoid PreviewPanel::LoadProjects(const std::vector<PreviewProjectEntry>& entries) {\n\twxLogMessage(\"Loading %zu project(s) in preview mode...\", entries.size());\n\n\tapp->CleanupPreview();\n\n\tfor (auto& entry : entries) {\n\t\tif (app->AddProjectSliders(entry.projectFile, entry.setName)) {\n\t\t\twxLogError(\"Failed to load slider set '%s' from file: %s\", entry.setName, entry.projectFile);\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tif (entries.empty())\n\t\treturn;\n\n\tapp->LoadPresets(entries[0].setName);\n\n\tif (presetChoice) {\n\t\twxString previousPreset = presetChoice->GetStringSelection();\n\t\tpresetChoice->Clear();\n\n\t\tstd::vector<std::string> presetNames;\n\t\tapp->GetPresetNames(presetNames);\n\n\t\tif (!presetNames.empty()) {\n\t\t\tfor (auto& name : presetNames)\n\t\t\t\tpresetChoice->Append(wxString::FromUTF8(name));\n\n\t\t\tint idx = presetChoice->FindString(previousPreset);\n\t\t\tif (idx == wxNOT_FOUND)\n\t\t\t\tidx = 0;\n\n\t\t\tpresetChoice->SetSelection(idx);\n\t\t\tpresetChoice->Show();\n\t\t\tpresetLabel->Show();\n\n\t\t\tapp->InitializeSliders(presetNames[idx]);\n\t\t}\n\t\telse {\n\t\t\tpresetChoice->Hide();\n\t\t\tpresetLabel->Hide();\n\n\t\t\tapp->InitializeSliders();\n\t\t}\n\n\t\tpresetChoice->GetParent()->Show();\n\t\tLayout();\n\t}\n\n\tmultiProjectMode = true;\n\n\tapp->InitPreview();\n}\n\nvoid PreviewPanel::OnProjectChoice(wxCommandEvent& WXUNUSED(event)) {\n\tif (!projectChoice)\n\t\treturn;\n\n\tint selection = projectChoice->GetSelection();\n\tif (selection < 0 || selection >= (int)projectEntries.size())\n\t\treturn;\n\n\tLoadProjects({projectEntries[selection]});\n}\n\nvoid PreviewPanel::OnPresetChoice(wxCommandEvent& WXUNUSED(event)) {\n\tif (!presetChoice)\n\t\treturn;\n\n\tint selection = presetChoice->GetSelection();\n\tif (selection < 0)\n\t\treturn;\n\n\tstd::string presetName = presetChoice->GetStringSelection().ToUTF8().data();\n\twxLogMessage(\"Applying preset '%s' to preview...\", presetName);\n\n\tapp->InitializeSliders(presetName);\n\tapp->RebuildPreviewMeshes();\n}\n\nvoid PreviewPanel::SetNormalsGenerationLayers(std::vector<NormalGenLayer>& normalLayers) {\n\trefNormalGenLayers = normalLayers;\n\tif (normalLayers.size() != 0)\n\t\toptButton->Show();\n\telse\n\t\toptButton->Hide();\n\n\tif (normalsGenDlg)\n\t\tnormalsGenDlg->Hide();\n\n\tLayout();\n}\n\nMesh* PreviewPanel::GetMesh(const std::string& shapeName) {\n\treturn gls.GetMesh(shapeName);\n}\n\nvoid PreviewPanel::AddMeshFromNif(NifFile* nif, char* shapeName) {\n\tstd::vector<std::string> shapeList = nif->GetShapeNames();\n\tfor (size_t i = 0; i < shapeList.size(); i++) {\n\t\tstd::string& shapeListName = shapeList[i];\n\t\tif (!shapeName || (shapeName && shapeListName == shapeName)) {\n\t\t\tMesh* m = gls.AddMeshFromNif(nif, shapeListName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tSetShapeVertexColors(nif, shapeListName, m);\n\t\t\tm->BuildVertexAdjacency();\n\t\t\tm->CreateBuffers();\n\t\t}\n\t}\n}\n\nvoid PreviewPanel::RefreshMeshFromNif(const std::vector<NifFile*>& nifs) {\n\tgls.ClearMeshes();\n\n\tfor (auto* nif : nifs) {\n\t\tfor (auto& shapeListName : nif->GetShapeNames()) {\n\t\t\tMesh* m = gls.AddMeshFromNif(nif, shapeListName);\n\t\t\tif (!m)\n\t\t\t\tcontinue;\n\n\t\t\tSetShapeVertexColors(nif, shapeListName, m);\n\t\t\tm->BuildVertexAdjacency();\n\t\t\tm->SmoothNormals();\n\t\t\tm->CreateBuffers();\n\n\t\t\tauto iter = shapeMaterials.find(shapeListName);\n\t\t\tif (iter != shapeMaterials.end())\n\t\t\t\tm->material = iter->second;\n\t\t\telse\n\t\t\t\tAddNifShapeTextures(nif, shapeListName);\n\t\t}\n\t}\n\n\tLoadNifFiles(extraNifPaths);\n\n\tgls.RenderOneFrame();\n}\n\nvoid PreviewPanel::AddNifShapeTextures(NifFile* fromNif, const std::string& shapeName) {\n\tbool hasMat = false;\n\tstd::string matFile;\n\n\tconst uint8_t MAX_TEXTURE_PATHS = 10;\n\tstd::vector<std::string> texFiles(MAX_TEXTURE_PATHS);\n\n\tNiShader* shader = nullptr;\n\tauto shape = fromNif->FindBlockByName<NiShape>(shapeName);\n\tif (shape) {\n\t\tshader = fromNif->GetShader(shape);\n\t\tif (shader) {\n\t\t\tif (fromNif->GetHeader().GetVersion().IsFO4() || fromNif->GetHeader().GetVersion().IsFO76()) {\n\t\t\t\tmatFile = shader->name.get();\n\t\t\t\tif (!matFile.empty())\n\t\t\t\t\thasMat = true;\n\t\t\t}\n\t\t}\n\t}\n\n\tMaterialFile mat(MaterialFile::BGSM);\n\tif (hasMat) {\n\t\tmatFile = std::regex_replace(matFile, std::regex(\"\\\\\\\\+\"), \"/\");\n\t\tmatFile = std::regex_replace(matFile, std::regex(\"^(.*?)/materials/\", std::regex_constants::icase), \"\");\n\t\tmatFile = std::regex_replace(matFile, std::regex(\"^/+\"), \"\");\n\t\tmatFile = std::regex_replace(matFile, std::regex(\"^(?!^materials/)\", std::regex_constants::icase), \"materials/\");\n\n\t\tmat = MaterialFile(baseDataPath + matFile);\n\n\t\tif (mat.Failed()) {\n\t\t\twxMemoryBuffer data;\n\t\t\tfor (FSArchiveFile* archive : FSManager::archiveList()) {\n\t\t\t\tif (archive) {\n\t\t\t\t\tif (archive->hasFile(matFile)) {\n\t\t\t\t\t\twxMemoryBuffer outData;\n\t\t\t\t\t\tarchive->fileContents(matFile, outData);\n\n\t\t\t\t\t\tif (!outData.IsEmpty()) {\n\t\t\t\t\t\t\tdata = std::move(outData);\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!data.IsEmpty()) {\n\t\t\t\tstd::string content((char*)data.GetData(), data.GetDataLen());\n\t\t\t\tstd::istringstream contentStream(content, std::istringstream::binary);\n\n\t\t\t\tmat = MaterialFile(contentStream);\n\t\t\t}\n\t\t}\n\n\t\tif (!mat.Failed()) {\n\t\t\tif (mat.signature == MaterialFile::BGSM) {\n\t\t\t\ttexFiles[0] = mat.diffuseTexture.c_str();\n\t\t\t\ttexFiles[1] = mat.normalTexture.c_str();\n\t\t\t\ttexFiles[2] = mat.glowTexture.c_str();\n\t\t\t\ttexFiles[3] = mat.greyscaleTexture.c_str();\n\t\t\t\ttexFiles[4] = mat.envmapTexture.c_str();\n\t\t\t\ttexFiles[7] = mat.smoothSpecTexture.c_str();\n\t\t\t}\n\t\t\telse if (mat.signature == MaterialFile::BGEM) {\n\t\t\t\ttexFiles[0] = mat.baseTexture.c_str();\n\t\t\t\ttexFiles[1] = mat.fxNormalTexture.c_str();\n\t\t\t\ttexFiles[3] = mat.grayscaleTexture.c_str();\n\t\t\t\ttexFiles[4] = mat.fxEnvmapTexture.c_str();\n\t\t\t\ttexFiles[5] = mat.envmapMaskTexture.c_str();\n\t\t\t}\n\t\t}\n\t\telse if (shader) {\n\t\t\thasMat = false;\n\n\t\t\tfor (int i = 0; i < MAX_TEXTURE_PATHS; i++)\n\t\t\t\tfromNif->GetTextureSlot(shape, texFiles[i], i);\n\t\t}\n\t}\n\telse if (shader) {\n\t\tfor (int i = 0; i < MAX_TEXTURE_PATHS; i++)\n\t\t\tfromNif->GetTextureSlot(shape, texFiles[i], i);\n\t}\n\n\tfor (int i = 0; i < MAX_TEXTURE_PATHS; i++) {\n\t\tif (!texFiles[i].empty()) {\n\t\t\ttexFiles[i] = std::regex_replace(texFiles[i], std::regex(\"\\\\\\\\+\"), \"/\");\n\t\t\ttexFiles[i] = std::regex_replace(texFiles[i],\n\t\t\t\t\t\t\t\t\t\t\t std::regex(\"^(.*?)/textures/\", std::regex_constants::icase),\n\t\t\t\t\t\t\t\t\t\t\t \"\");\n\t\t\ttexFiles[i] = std::regex_replace(texFiles[i], std::regex(\"^/+\"), \"\");\n\t\t\ttexFiles[i] = std::regex_replace(texFiles[i],\n\t\t\t\t\t\t\t\t\t\t\t std::regex(\"^(?!^textures/)\", std::regex_constants::icase),\n\t\t\t\t\t\t\t\t\t\t\t \"textures/\");\n\n\t\t\ttexFiles[i] = baseDataPath + texFiles[i];\n\t\t}\n\t}\n\n\tstd::string vShader = Config[\"AppDir\"] + \"/res/shaders/default.vert\";\n\tstd::string fShader = Config[\"AppDir\"] + \"/res/shaders/default.frag\";\n\n\tTargetGame targetGame = (TargetGame)Config.GetIntValue(\"TargetGame\");\n\tif (targetGame == FO4 || targetGame == FO4VR || targetGame == FO76) {\n\t\tvShader = Config[\"AppDir\"] + \"/res/shaders/fo4_default.vert\";\n\t\tfShader = Config[\"AppDir\"] + \"/res/shaders/fo4_default.frag\";\n\t}\n\telse if (targetGame == OB) {\n\t\tvShader = Config[\"AppDir\"] + \"/res/shaders/ob_default.vert\";\n\t\tfShader = Config[\"AppDir\"] + \"/res/shaders/ob_default.frag\";\n\t}\n\n\tSetShapeTextures(shapeName, texFiles, vShader, fShader, hasMat, mat);\n}\n\nvoid PreviewPanel::RenderNormalMap(const std::string& outfilename) {\n\twxBusyCursor busycursor;\n\n\tstd::string dest_tex = gls.GetMesh(\"CBBE\")->material->GetTexName(1);\n\tGLuint w, h;\n\tgls.GetSize(w, h);\n\tstd::vector<GLuint> texIds;\n\tstd::vector<std::string> normTextures;\n\tnormTextures.resize(20);\n\n\tGLMaterial* normMat = gls.AddMaterial(normTextures, Config[\"AppDir\"] + \"/res/shaders/normalshade.vert\", Config[\"AppDir\"] + \"/res/shaders/normalshade.frag\");\n\n\tstd::vector<std::string> ppTex;\n\tppTex.push_back(\"pproc\");\n\tGLMaterial* ppMat = gls.AddMaterial(ppTex, Config[\"AppDir\"] + \"/res/shaders/fullscreentri.vert\", Config[\"AppDir\"] + \"/res/shaders/fullscreentri.frag\");\n\n\tGLOffScreenBuffer offscreen(&gls, 4096, 4096, 2, texIds);\n\n\tgls.SetPerspective(false);\n\toffscreen.Start();\n\tgls.RenderToTexture(normMat);\n\tgls.GetResourceLoader()->RenameTexture(offscreen.texName(0), \"pproc\", true);\n\toffscreen.End();\n\toffscreen.NextBuffer();\n\n\toffscreen.Start();\n\tgls.RenderFullScreenQuad(ppMat, 4096, 4096);\n\tgls.GetResourceLoader()->RenameTexture(offscreen.texName(1), dest_tex, true);\n\tif (!outfilename.empty()) {\n\t\toffscreen.SaveTexture(outfilename);\n\t}\n\toffscreen.End();\n\n\tgls.SetPerspective(true);\n\tgls.SetSize(w, h);\n\tRender();\n}\n\nvoid PreviewPanel::RightDrag(int dX, int dY) {\n\tgls.TurnTableCamera(dX);\n\tgls.PitchCamera(dY);\n\tgls.RenderOneFrame();\n}\n\nvoid PreviewPanel::LeftDrag(int dX, int dY) {\n\tgls.PanCamera(dX, dY);\n\tgls.RenderOneFrame();\n}\n\nvoid PreviewPanel::TrackMouse(int X, int Y) {\n\tgls.UpdateCursor(X, Y);\n\tgls.RenderOneFrame();\n}\n\nvoid PreviewPanel::MouseWheel(int dW) {\n\tgls.DollyCamera(dW);\n\tgls.RenderOneFrame();\n}\n\nvoid PreviewPanel::OnWeightSlider(wxScrollEvent& event) {\n\tweight = event.GetPosition();\n\tapp->UpdatePreview();\n}\n\nvoid PreviewPanel::OnLockShape(wxCommandEvent& WXUNUSED(event)) {\n\tapp->CopyPreviewWeightToSliders();\n}\n\nvoid PreviewPanel::OnShowReference(wxCommandEvent& WXUNUSED(event)) {\n\tapp->UpdatePreview();\n}\n\nvoid PreviewPanel::OnPopout(wxCommandEvent& WXUNUSED(event)) {\n\twxCommandEvent evt(EVT_PREVIEW_POPOUT);\n\twxPostEvent(GetParent(), evt);\n}\n\nvoid PreviewPanel::ShowPopoutButton(bool show) {\n\tif (popoutButton)\n\t\tpopoutButton->Show(show);\n}\n\nvoid PreviewPanel::ShowNormalGenWindow(wxCommandEvent& WXUNUSED(event)) {\n\tif (!normalsGenDlg)\n\t\tnormalsGenDlg = new NormalsGenDialog(this, refNormalGenLayers);\n\telse\n\t\tnormalsGenDlg->SetLayersRef(refNormalGenLayers);\n\n\tnormalsGenDlg->Show();\n}\n\nvoid PreviewPanel::Cleanup() {\n\tif (canvas && context)\n\t\tcanvas->SetCurrent(*context);\n\n\tgls.Cleanup();\n\tshapeMaterials.clear();\n\tgls.RenderOneFrame();\n}\n\nwxBEGIN_EVENT_TABLE(PreviewCanvas, wxGLCanvas)\n\tEVT_KEY_UP(PreviewCanvas::OnKeyUp)\n\tEVT_MOTION(PreviewCanvas::OnMotion)\n\tEVT_MOUSEWHEEL(PreviewCanvas::OnMouseWheel)\n\tEVT_PAINT(PreviewCanvas::OnPaint)\n\tEVT_SIZE(PreviewCanvas::OnResized)\nwxEND_EVENT_TABLE()\n\nPreviewCanvas::PreviewCanvas(PreviewPanel* pp, const wxGLAttributes& attribs)\n\t: wxGLCanvas(pp, attribs, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)\n\t, previewPanel(pp) {}\n\nvoid PreviewCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) {\n\t// Initialize OpenGL the first time the window is painted.\n\tif (firstPaint) {\n\t\tfirstPaint = false;\n\t\tpreviewPanel->OnShown();\n\t}\n\tpreviewPanel->Render();\n}\n\nvoid PreviewCanvas::OnKeyUp(wxKeyEvent& event) {\n\tint key = event.GetKeyCode();\n\tswitch (key) {\n\t\tcase 'T': previewPanel->ToggleTextures(); break;\n\t\tcase 'W': previewPanel->ToggleWireframe(); break;\n\t\tcase 'L': previewPanel->ToggleLighting(); break;\n\t\tcase 'G':\n\t\t\tbreak;\n\t}\n}\n\nvoid PreviewCanvas::OnMotion(wxMouseEvent& event) {\n\tif (!HasFocus()) {\n\t\tauto topLevel = dynamic_cast<wxTopLevelWindow*>(wxGetTopLevelParent(previewPanel));\n\t\tif (topLevel && topLevel->IsActive())\n\t\t\tSetFocus();\n\t}\n\n\tauto delta = event.GetPosition() - lastMousePosition;\n\n\tif (event.LeftIsDown()) {\n\t\tpreviewPanel->LeftDrag(delta.x, delta.y);\n\t}\n\telse if (event.MiddleIsDown()) {\n\t\tif (wxGetKeyState(WXK_SHIFT))\n\t\t\tpreviewPanel->MouseWheel(delta.y);\n\t\telse\n\t\t\tpreviewPanel->LeftDrag(delta.x, delta.y);\n\t}\n\telse if (event.RightIsDown()) {\n\t\tif (wxGetKeyState(WXK_SHIFT))\n\t\t\tpreviewPanel->LeftDrag(delta.x, delta.y);\n\t\telse\n\t\t\tpreviewPanel->RightDrag(delta.x, delta.y);\n\t}\n\telse\n\t\tpreviewPanel->TrackMouse(event.GetX(), event.GetY());\n\n\tlastMousePosition = event.GetPosition();\n}\n\nvoid PreviewCanvas::OnMouseWheel(wxMouseEvent& event) {\n\tpreviewPanel->MouseWheel(event.GetWheelRotation());\n}\n\nvoid PreviewCanvas::OnResized(wxSizeEvent& event) {\n\tpreviewPanel->Resized(event.GetSize().GetWidth(), event.GetSize().GetHeight());\n}\n"
  },
  {
    "path": "src/ui/PreviewPanel.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../render/GLOffscreenBuffer.h\"\n#include \"../render/GLSurface.h\"\n#include \"../utils/ConfigurationManager.h\"\n#include \"../program/NormalsGenDialog.h\"\n#include <wx/wx.h>\n#include <wx/activityindicator.h>\n\nclass BodySlideApp;\nclass PreviewCanvas;\n\nextern ConfigurationManager Config;\n\nstruct PreviewProjectEntry {\n\tstd::string projectFile;\n\tstd::string setName;\n};\n\nwxDECLARE_EVENT(EVT_PREVIEW_POPOUT, wxCommandEvent);\n\nclass PreviewPanel : public wxPanel {\n\tBodySlideApp* app = nullptr;\n\tPreviewCanvas* canvas = nullptr;\n\tstd::unique_ptr<wxGLContext> context;\n\twxButton* optButton = nullptr;\n\twxButton* lockShapeButton = nullptr;\n\twxCheckBox* showReferenceCheckbox = nullptr;\n\twxStaticText* projectLabel = nullptr;\n\twxChoice* projectChoice = nullptr;\n\twxStaticText* presetLabel = nullptr;\n\twxChoice* presetChoice = nullptr;\n\twxBitmapButton* popoutButton = nullptr;\n\n\twxPanel* loadingOverlay = nullptr;\n\twxActivityIndicator* loadingIndicator = nullptr;\n\n\tNormalsGenDialog* normalsGenDlg = nullptr;\n\tstd::vector<NormalGenLayer> emptyLayers;\n\tstd::vector<NormalGenLayer>& refNormalGenLayers;\n\n\tGLSurface gls;\n\tstd::unordered_map<std::string, GLMaterial*> shapeMaterials;\n\tstd::string baseDataPath;\n\tstd::vector<std::string> extraNifPaths;\n\tstd::vector<PreviewProjectEntry> projectEntries;\n\tbool loadAllProjects = false;\n\tbool multiProjectMode = false;\n\tbool readOnlyMode = false;\n\tint weight = 100;\n\tbool glInitialized = false;\n\npublic:\n\tPreviewPanel(wxWindow* parent, BodySlideApp* app);\n\t~PreviewPanel();\n\n\tvoid OnShown();\n\tvoid OnWeightSlider(wxScrollEvent& event);\n\tvoid OnProjectChoice(wxCommandEvent& event);\n\tvoid OnPresetChoice(wxCommandEvent& event);\n\n\tvoid ShowNormalGenWindow(wxCommandEvent& event);\n\tvoid OnLockShape(wxCommandEvent& event);\n\tvoid OnShowReference(wxCommandEvent& event);\n\tvoid OnPopout(wxCommandEvent& event);\n\n\tvoid ShowPopoutButton(bool show);\n\n\tvoid SetReadOnlyMode(bool readOnly) {\n\t\treadOnlyMode = readOnly;\n\t\tif (readOnly) {\n\t\t\tShowLockShapeButton(false);\n\t\t\tShowPopoutButton(false);\n\t\t}\n\t}\n\n\tbool IsReadOnlyMode() const { return readOnlyMode; }\n\n\tvoid Cleanup();\n\n\tbool IsGLInitialized() const { return glInitialized; }\n\n\tint GetWeight() { return weight; }\n\n\tvoid ShowWeight(bool show = true) {\n\t\tweight = 100;\n\t\twxSlider* weightSlider = (wxSlider*)FindWindowByName(\"weightSlider\", this);\n\t\tif (weightSlider) {\n\t\t\tweightSlider->SetValue(weight);\n\t\t\tweightSlider->GetParent()->Show(show);\n\t\t\tLayout();\n\t\t}\n\t}\n\n\tvoid ShowLockShapeButton(bool show = true) {\n\t\tif (lockShapeButton)\n\t\t\tlockShapeButton->Show(show);\n\t}\n\n\tvoid ShowReferenceCheckbox(bool show = true) {\n\t\tif (showReferenceCheckbox) {\n\t\t\tshowReferenceCheckbox->Show(show);\n\t\t\tLayout();\n\t\t}\n\t}\n\n\tvoid SetReferenceCheckboxState(bool checked, bool enabled) {\n\t\tif (showReferenceCheckbox) {\n\t\t\tshowReferenceCheckbox->SetValue(checked);\n\t\t\tshowReferenceCheckbox->Enable(enabled);\n\t\t}\n\t}\n\n\tbool IsShowReferenceChecked() const {\n\t\treturn showReferenceCheckbox && showReferenceCheckbox->IsShown() && showReferenceCheckbox->GetValue();\n\t}\n\n\tvoid SetMeshVisibility(const std::string& shapeName, bool visible) {\n\t\tgls.SetMeshVisibility(shapeName, visible);\n\t}\n\n\tvoid SetBaseDataPath(const std::string& path) { baseDataPath = path; }\n\n\tvoid SetExtraNifPaths(const std::vector<std::string>& paths) { extraNifPaths = paths; }\n\tconst std::vector<std::string>& GetExtraNifPaths() const { return extraNifPaths; }\n\tvoid SetProjectData(const std::vector<PreviewProjectEntry>& entries, bool loadAll = false);\n\tvoid SetNormalsGenerationLayers(std::vector<NormalGenLayer>& normalLayers);\n\tvoid LoadNifFiles(const std::vector<std::string>& nifFilePaths);\n\tvoid LoadProjects(const std::vector<PreviewProjectEntry>& entries);\n\n\tMesh* GetMesh(const std::string& shapeName);\n\tvoid AddMeshFromNif(nifly::NifFile* nif, char* shapeName = nullptr);\n\tvoid RefreshMeshFromNif(const std::vector<nifly::NifFile*>& nifs);\n\tvoid AddNifShapeTextures(nifly::NifFile* fromNif, const std::string& shapeName);\n\n\tvoid UpdateMeshes(const std::string& shapeName, std::vector<nifly::Vector3>* verts, std::vector<nifly::Vector2>* uvs = nullptr) {\n\t\tstd::unordered_set<int> changed;\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tgls.Update(m, verts, uvs, &changed);\n\t\tm->SmoothNormals(changed);\n\t}\n\n\tvoid SetShapeTextures(const std::string& shapeName,\n\t\t\t\t\t\t  const std::vector<std::string>& textureFiles,\n\t\t\t\t\t\t  const std::string& vShader,\n\t\t\t\t\t\t  const std::string& fShader,\n\t\t\t\t\t\t  const bool hasMatFile = false,\n\t\t\t\t\t\t  const MaterialFile& matFile = MaterialFile()) {\n\t\tMesh* m = gls.GetMesh(shapeName);\n\t\tif (!m)\n\t\t\treturn;\n\n\t\tGLMaterial* mat = gls.AddMaterial(textureFiles, vShader, fShader);\n\t\tif (mat) {\n\t\t\tm->material = mat;\n\t\t\tshapeMaterials[shapeName] = mat;\n\n\t\t\tif (hasMatFile)\n\t\t\t\tm->UpdateFromMaterialFile(matFile);\n\n\t\t\tgls.UpdateShaders(m);\n\t\t}\n\t}\n\n\tvoid SetShapeVertexColors(nifly::NifFile* nif, const std::string& shapeName, Mesh* mesh) {\n\t\tconst std::vector<nifly::Color4>* vcolors = nif->GetColorsForShape(shapeName);\n\t\tif (vcolors) {\n\t\t\tfor (size_t v = 0; v < vcolors->size(); v++) {\n\t\t\t\tmesh->vcolors[v].x = vcolors->at(v).r;\n\t\t\t\tmesh->vcolors[v].y = vcolors->at(v).g;\n\t\t\t\tmesh->vcolors[v].z = vcolors->at(v).b;\n\t\t\t\tmesh->valpha[v] = vcolors->at(v).a;\n\t\t\t}\n\t\t}\n\t}\n\n\tvoid Render() { gls.RenderOneFrame(); }\n\n\tvoid Resized(uint32_t w, uint32_t h) { gls.SetSize(w, h); }\n\n\tvoid ToggleTextures() {\n\t\tgls.ToggleTextures();\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid ToggleWireframe() {\n\t\tgls.ToggleWireframe();\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid ToggleLighting() {\n\t\tgls.ToggleLighting();\n\t\tgls.RenderOneFrame();\n\t}\n\n\tvoid RenderNormalMap(const std::string& outfilename = \"\");\n\n\tvoid RightDrag(int dX, int dY);\n\tvoid LeftDrag(int dX, int dY);\n\tvoid MouseWheel(int dW);\n\tvoid TrackMouse(int X, int Y);\n\n\tvoid ShowLoadingIndicator(bool show = true);\n\n\twxDECLARE_EVENT_TABLE();\n};\n\nclass PreviewCanvas : public wxGLCanvas {\n\tPreviewPanel* previewPanel = nullptr;\n\tbool firstPaint = true;\n\twxPoint lastMousePosition;\n\npublic:\n\tPreviewCanvas(PreviewPanel* pp, const wxGLAttributes& attribs);\n\n\tvoid OnPaint(wxPaintEvent& event);\n\tvoid OnKeyUp(wxKeyEvent& event);\n\tvoid OnMotion(wxMouseEvent& event);\n\tvoid OnMouseWheel(wxMouseEvent& event);\n\tvoid OnResized(wxSizeEvent& event);\n\n\twxDECLARE_EVENT_TABLE();\n};\n"
  },
  {
    "path": "src/ui/WeightCopyDialog.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"WeightCopyDialog.h\"\n\n#include \"../program/OutfitProject.h\"\n#include \"../program/OutfitStudio.h\"\n\n#include <wx/xrc/xmlres.h>\n\nusing namespace nifly;\n\nWeightCopyDialog::WeightCopyDialog(wxWindow* parent,\n\t\t\t\t\t\t\t\t   OutfitProject* project,\n\t\t\t\t\t\t\t\t   wxGLPanel* glView,\n\t\t\t\t\t\t\t\t   PoseDataCollection& poseDataCollection,\n\t\t\t\t\t\t\t\t   const std::unordered_set<std::string>& normalizeBones,\n\t\t\t\t\t\t\t\t   const std::vector<NiShape*>& previewShapes,\n\t\t\t\t\t\t\t\t   WeightCopyOptions& options,\n\t\t\t\t\t\t\t\t   bool silent)\n\t: project(project)\n\t, glView(glView)\n\t, poseDataCollection(poseDataCollection)\n\t, normalizeBones(normalizeBones)\n\t, previewShapes(previewShapes)\n\t, options(options) {\n\tpreviewUndoState.undoType = UndoType::Weight;\n\n\tif (!wxXmlResource::Get()->LoadDialog(this, parent, \"dlgCopyWeights\"))\n\t\treturn;\n\n\tSetupControls();\n\tPopulateBoneList();\n\tPopulatePoseDropdown();\n\tSetupEventHandlers();\n\tShowSkinTransOptions();\n\tSavePoseState();\n\n\t// Enable bone display and weight colors on dialog open\n\tprevBonesMode = glView->IsBonesMode();\n\tprevWeightColors = glView->gls.GetWeightColors();\n\tglView->ShowBones(true);\n\tglView->gls.SetWeightColors(true);\n\tglView->Refresh();\n\n\tif (silent) {\n\t\taccepted = true;\n\t\tCollectOptions();\n\t}\n\telse {\n\t\tint result = ShowModal();\n\n\t\tUndoPreview();\n\t\tRestorePoseState();\n\n\t\tglView->ShowBones(prevBonesMode);\n\t\tglView->gls.SetWeightColors(prevWeightColors);\n\t\tstatic_cast<OutfitStudioFrame*>(parent)->RefreshGUIWeightColors();\n\n\t\tif (result == wxID_OK) {\n\t\t\taccepted = true;\n\t\t\tCollectOptions();\n\t\t}\n\t}\n}\n\nvoid WeightCopyDialog::SetupControls() {\n\tboneListBox = XRCCTRL(*this, \"boneList\", wxCheckListBox);\n\tposeChoice = XRCCTRL(*this, \"poseChoice\", wxChoice);\n\tpreviewProgress = XRCCTRL(*this, \"previewProgress\", wxGauge);\n\n\tXRCCTRL(*this, \"proximityRadiusSlider\", wxSlider)->Bind(wxEVT_SLIDER, [this](wxCommandEvent&) {\n\t\tfloat changed = XRCCTRL(*this, \"proximityRadiusSlider\", wxSlider)->GetValue() / 1000.0f;\n\t\tXRCCTRL(*this, \"proximityRadiusText\", wxTextCtrl)->ChangeValue(wxString::Format(\"%0.5f\", changed));\n\t});\n\n\tXRCCTRL(*this, \"proximityRadiusText\", wxTextCtrl)->Bind(wxEVT_TEXT, [this](wxCommandEvent&) {\n\t\tfloat changed = atof(XRCCTRL(*this, \"proximityRadiusText\", wxTextCtrl)->GetValue().c_str());\n\t\tXRCCTRL(*this, \"proximityRadiusSlider\", wxSlider)->SetValue(changed * 1000);\n\t});\n\n\tXRCCTRL(*this, \"maxResultsSlider\", wxSlider)->Bind(wxEVT_SLIDER, [this](wxCommandEvent&) {\n\t\tint changed = XRCCTRL(*this, \"maxResultsSlider\", wxSlider)->GetValue();\n\t\tXRCCTRL(*this, \"maxResultsText\", wxTextCtrl)->ChangeValue(wxString::Format(\"%d\", changed));\n\t});\n\n\tXRCCTRL(*this, \"maxResultsText\", wxTextCtrl)->Bind(wxEVT_TEXT, [this](wxCommandEvent&) {\n\t\tint changed = atol(XRCCTRL(*this, \"maxResultsText\", wxTextCtrl)->GetValue().c_str());\n\t\tXRCCTRL(*this, \"maxResultsSlider\", wxSlider)->SetValue(changed);\n\t});\n\n\tXRCCTRL(*this, \"noTargetLimit\", wxCheckBox)->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {\n\t\tbool noTargetLimit = XRCCTRL(*this, \"noTargetLimit\", wxCheckBox)->IsChecked();\n\t\tXRCCTRL(*this, \"maxResultsText\", wxTextCtrl)->Enable(!noTargetLimit);\n\t\tXRCCTRL(*this, \"maxResultsSlider\", wxSlider)->Enable(!noTargetLimit);\n\t});\n}\n\nvoid WeightCopyDialog::PopulateBoneList() {\n\tNiShape* baseShape = project->GetBaseShape();\n\tif (baseShape) {\n\t\tstd::vector<std::string> baseBones = project->GetWorkAnim()->shapeBones[baseShape->name.get()];\n\t\tstd::sort(baseBones.begin(), baseBones.end());\n\t\tfor (const auto& bone : baseBones) {\n\t\t\tint idx = boneListBox->Append(bone);\n\t\t\tboneListBox->Check(idx, true);\n\t\t}\n\t}\n}\n\nvoid WeightCopyDialog::PopulatePoseDropdown() {\n\tposeChoice->Append(\"<No Pose>\");\n\tfor (auto& pose : poseDataCollection.poseData)\n\t\tposeChoice->Append(wxString::FromUTF8(pose.name), &pose);\n\tposeChoice->SetSelection(0);\n}\n\nvoid WeightCopyDialog::SetupEventHandlers() {\n\tXRCCTRL(*this, \"btnCheckAll\", wxButton)->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {\n\t\tfor (unsigned int i = 0; i < boneListBox->GetCount(); i++)\n\t\t\tboneListBox->Check(i, true);\n\t});\n\n\tXRCCTRL(*this, \"btnUncheckAll\", wxButton)->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) {\n\t\tfor (unsigned int i = 0; i < boneListBox->GetCount(); i++)\n\t\t\tboneListBox->Check(i, false);\n\t});\n\n\tposeChoice->Bind(wxEVT_CHOICE, &WeightCopyDialog::OnPoseSelected, this);\n\tboneListBox->Bind(wxEVT_LISTBOX, &WeightCopyDialog::OnBoneSelected, this);\n\tXRCCTRL(*this, \"btnPreview\", wxButton)->Bind(wxEVT_BUTTON, &WeightCopyDialog::OnPreview, this);\n\n\tBind(wxEVT_CHAR_HOOK, [this](wxKeyEvent& event) {\n\t\tif (event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_NUMPAD_ENTER)\n\t\t\tEndModal(wxID_OK);\n\t\telse\n\t\t\tevent.Skip();\n\t});\n}\n\nvoid WeightCopyDialog::ShowSkinTransOptions() {\n\twxCheckBox* cbCopySkinTrans = XRCCTRL(*this, \"cbCopySkinTrans\", wxCheckBox);\n\twxCheckBox* cbTransformGeo = XRCCTRL(*this, \"cbTransformGeo\", wxCheckBox);\n\tif (options.showSkinTransOption) {\n\t\tcbCopySkinTrans->SetValue(options.doSkinTransCopy);\n\t\tcbTransformGeo->SetValue(options.doTransformGeo);\n\t\tcbCopySkinTrans->Show();\n\t\tcbTransformGeo->Show();\n\t\tXRCCTRL(*this, \"copyTransDescription\", wxStaticText)->Show();\n\t}\n}\n\nvoid WeightCopyDialog::SavePoseState() {\n\tprevBPose = project->bPose;\n\n\tstd::vector<std::string> allBones;\n\tAnimSkeleton::getInstance().GetBoneNames(allBones);\n\tfor (const auto& boneName : allBones) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (bone)\n\t\t\tsavedPose[boneName] = {bone->poseRotVec, bone->poseTranVec, bone->poseScale};\n\t}\n}\n\nvoid WeightCopyDialog::RestorePoseState() {\n\tstd::vector<std::string> allBones;\n\tAnimSkeleton::getInstance().GetBoneNames(allBones);\n\tfor (const auto& boneName : allBones) {\n\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\tif (!bone)\n\t\t\tcontinue;\n\t\tauto it = savedPose.find(boneName);\n\t\tif (it != savedPose.end()) {\n\t\t\tbone->poseRotVec = it->second.rotVec;\n\t\t\tbone->poseTranVec = it->second.tranVec;\n\t\t\tbone->poseScale = it->second.scale;\n\t\t}\n\t\telse {\n\t\t\tbone->poseRotVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseTranVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\tbone->poseScale = 1.0f;\n\t\t}\n\t\tbone->UpdatePoseTransform();\n\t}\n\tproject->bPose = prevBPose;\n\n\t// Apply pose to meshes\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tstd::vector<Vector3> verts;\n\t\tproject->GetLiveVerts(shape, verts);\n\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t}\n\tglView->UpdateBones();\n\tglView->Render();\n\n\tstatic_cast<OutfitStudioFrame*>(GetParent())->PoseToGUI();\n}\n\nvoid WeightCopyDialog::OnPoseSelected(wxCommandEvent&) {\n\tint sel = poseChoice->GetSelection();\n\tif (sel == 0) {\n\t\tstd::vector<std::string> bones;\n\t\tAnimSkeleton::getInstance().GetBoneNames(bones);\n\t\tfor (const auto& boneName : bones) {\n\t\t\tAnimBone* bone = AnimSkeleton::getInstance().GetBonePtr(boneName);\n\t\t\tif (bone) {\n\t\t\t\tbone->poseRotVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\t\tbone->poseTranVec = Vector3(0.0f, 0.0f, 0.0f);\n\t\t\t\tbone->poseScale = 1.0f;\n\t\t\t\tbone->UpdatePoseTransform();\n\t\t\t}\n\t\t}\n\t\tproject->bPose = false;\n\t}\n\telse {\n\t\tauto poseData = reinterpret_cast<PoseData*>(poseChoice->GetClientData(sel));\n\t\tposeData->ApplyToSkeleton();\n\t\tproject->bPose = true;\n\t}\n\n\t// Apply pose to meshes\n\tfor (auto& shape : project->GetWorkNif()->GetShapes()) {\n\t\tstd::vector<Vector3> verts;\n\t\tproject->GetLiveVerts(shape, verts);\n\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t}\n\tglView->UpdateBones();\n\tglView->Render();\n}\n\nvoid WeightCopyDialog::OnBoneSelected(wxCommandEvent&) {\n\tint sel = boneListBox->GetSelection();\n\tif (sel == wxNOT_FOUND)\n\t\treturn;\n\tShowBoneWeightColors(boneListBox->GetString(sel).ToStdString());\n}\n\nvoid WeightCopyDialog::ShowBoneWeightColors(const std::string& boneName) {\n\tfor (auto& s : project->GetWorkNif()->GetShapeNames()) {\n\t\tMesh* m = glView->GetMesh(s);\n\t\tif (m) {\n\t\t\tm->WeightFill(0.0f);\n\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(s, boneName);\n\t\t\tif (weights) {\n\t\t\t\tfor (auto& bw : *weights)\n\t\t\t\t\tm->weight[bw.first] = bw.second;\n\t\t\t}\n\t\t}\n\t}\n\tglView->Refresh();\n}\n\nvoid WeightCopyDialog::UndoPreview() {\n\tif (!previewActive)\n\t\treturn;\n\n\tfor (auto& uss : previewUndoState.usss) {\n\t\tMesh* m = glView->GetMesh(uss.shapeName);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tfor (auto& bw : uss.boneWeights) {\n\t\t\tif (bw.weights.empty())\n\t\t\t\tcontinue;\n\n\t\t\tproject->GetWorkAnim()->AddShapeBone(m->shapeName, bw.boneName);\n\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(m->shapeName, bw.boneName);\n\t\t\tif (!weights)\n\t\t\t\tcontinue;\n\n\t\t\tfor (auto& p : bw.weights) {\n\t\t\t\tif (p.second.startVal == 0.0f)\n\t\t\t\t\tweights->erase(p.first);\n\t\t\t\telse\n\t\t\t\t\t(*weights)[p.first] = p.second.startVal;\n\t\t\t}\n\t\t}\n\n\t\tif (project->bPose) {\n\t\t\tauto shape = project->GetWorkNif()->FindBlockByName<NiShape>(m->shapeName);\n\t\t\tif (shape) {\n\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t\t\t}\n\t\t}\n\t}\n\n\tpreviewUndoState.usss.clear();\n\tpreviewActive = false;\n\tproject->morpher.ClearProximityCache();\n}\n\nvoid WeightCopyDialog::ApplyPreviewWeights() {\n\tfor (auto& uss : previewUndoState.usss) {\n\t\tMesh* m = glView->GetMesh(uss.shapeName);\n\t\tif (!m)\n\t\t\tcontinue;\n\n\t\tfor (auto& bw : uss.boneWeights) {\n\t\t\tif (bw.weights.empty())\n\t\t\t\tcontinue;\n\n\t\t\tproject->GetWorkAnim()->AddShapeBone(m->shapeName, bw.boneName);\n\t\t\tauto weights = project->GetWorkAnim()->GetWeightsPtr(m->shapeName, bw.boneName);\n\t\t\tif (!weights)\n\t\t\t\tcontinue;\n\n\t\t\tfor (auto& p : bw.weights) {\n\t\t\t\tif (p.second.endVal == 0.0f)\n\t\t\t\t\tweights->erase(p.first);\n\t\t\t\telse\n\t\t\t\t\t(*weights)[p.first] = p.second.endVal;\n\t\t\t}\n\t\t}\n\n\t\tif (project->bPose) {\n\t\t\tauto shape = project->GetWorkNif()->FindBlockByName<NiShape>(m->shapeName);\n\t\t\tif (shape) {\n\t\t\t\tstd::vector<Vector3> verts;\n\t\t\t\tproject->GetLiveVerts(shape, verts);\n\t\t\t\tglView->UpdateMeshVertices(shape->name.get(), &verts, true, true, false);\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid WeightCopyDialog::GetNormalizeBones(std::vector<std::string>* normBones, std::vector<std::string>* notNormBones) {\n\tstd::vector<std::string> activeBones;\n\tproject->GetActiveBones(activeBones);\n\n\tfor (auto& boneName : activeBones) {\n\t\tif (normalizeBones.find(boneName) != normalizeBones.end()) {\n\t\t\tif (normBones)\n\t\t\t\tnormBones->push_back(boneName);\n\t\t}\n\t\telse {\n\t\t\tif (notNormBones)\n\t\t\t\tnotNormBones->push_back(boneName);\n\t\t}\n\t}\n}\n\nvoid WeightCopyDialog::OnPreview(wxCommandEvent&) {\n\tUndoPreview();\n\n\tfloat proximityRadius = atof(XRCCTRL(*this, \"proximityRadiusText\", wxTextCtrl)->GetValue().c_str());\n\tbool noTargetLimit = XRCCTRL(*this, \"noTargetLimit\", wxCheckBox)->IsChecked();\n\tint maxResults = noTargetLimit ? std::numeric_limits<int>::max() : atol(XRCCTRL(*this, \"maxResultsText\", wxTextCtrl)->GetValue().c_str());\n\n\tstd::vector<std::string> checkedBones;\n\tfor (unsigned int i = 0; i < boneListBox->GetCount(); i++) {\n\t\tif (boneListBox->IsChecked(i))\n\t\t\tcheckedBones.push_back(boneListBox->GetString(i).ToStdString());\n\t}\n\n\tif (checkedBones.empty() || previewShapes.empty())\n\t\treturn;\n\n\tstd::sort(checkedBones.begin(), checkedBones.end());\n\n\tint nCopyBones = static_cast<int>(checkedBones.size());\n\tstd::vector<std::string> lockedBones;\n\tbool bSpreadWeight = false;\n\n\tstd::unordered_set<std::string> selBones{checkedBones.begin(), checkedBones.end()};\n\tstd::vector<std::string> normBones, notNormBones;\n\tGetNormalizeBones(&normBones, &notNormBones);\n\n\tfor (auto& bone : normBones)\n\t\tif (!selBones.count(bone))\n\t\t\tcheckedBones.push_back(bone);\n\n\tbSpreadWeight = static_cast<int>(checkedBones.size()) > nCopyBones;\n\n\tif (bSpreadWeight) {\n\t\tfor (auto& bone : notNormBones)\n\t\t\tif (!selBones.count(bone))\n\t\t\t\tlockedBones.push_back(bone);\n\t}\n\telse {\n\t\tfor (auto& bone : notNormBones)\n\t\t\tif (!selBones.count(bone))\n\t\t\t\tcheckedBones.push_back(bone);\n\t}\n\n\t// Show progress gauge\n\tpreviewProgress->Show();\n\tpreviewProgress->SetValue(0);\n\tLayout();\n\twxYield();\n\n\tstd::unordered_map<uint16_t, float> mask;\n\tint numShapes = static_cast<int>(previewShapes.size());\n\n\tfor (int i = 0; i < numShapes; i++) {\n\t\tauto shape = previewShapes[i];\n\t\tpreviewUndoState.usss.resize(previewUndoState.usss.size() + 1);\n\t\tpreviewUndoState.usss.back().shapeName = shape->name.get();\n\n\t\tmask.clear();\n\t\tglView->GetShapeMask(mask, shape->name.get());\n\n\t\tproject->CopyBoneWeights(shape, proximityRadius, maxResults, mask, checkedBones, nCopyBones, lockedBones, previewUndoState.usss.back(), bSpreadWeight);\n\n\t\tpreviewProgress->SetValue((i + 1) * 100 / numShapes);\n\t\twxYield();\n\t}\n\n\tApplyPreviewWeights();\n\tpreviewActive = true;\n\n\tproject->morpher.ClearProximityCache();\n\n\tpreviewProgress->Hide();\n\tLayout();\n\twxYield();\n\n\tint sel = boneListBox->GetSelection();\n\tif (sel != wxNOT_FOUND)\n\t\tShowBoneWeightColors(boneListBox->GetString(sel).ToStdString());\n\telse\n\t\tglView->Refresh();\n}\n\nvoid WeightCopyDialog::CollectOptions() {\n\toptions.proximityRadius = atof(XRCCTRL(*this, \"proximityRadiusText\", wxTextCtrl)->GetValue().c_str());\n\n\tbool noTargetLimit = XRCCTRL(*this, \"noTargetLimit\", wxCheckBox)->IsChecked();\n\tif (!noTargetLimit)\n\t\toptions.maxResults = atol(XRCCTRL(*this, \"maxResultsText\", wxTextCtrl)->GetValue().c_str());\n\telse\n\t\toptions.maxResults = std::numeric_limits<int>::max();\n\n\tif (options.showSkinTransOption) {\n\t\toptions.doSkinTransCopy = XRCCTRL(*this, \"cbCopySkinTrans\", wxCheckBox)->IsChecked();\n\t\toptions.doTransformGeo = XRCCTRL(*this, \"cbTransformGeo\", wxCheckBox)->IsChecked();\n\t}\n\n\toptions.selectedBones.clear();\n\tfor (unsigned int i = 0; i < boneListBox->GetCount(); i++) {\n\t\tif (boneListBox->IsChecked(i))\n\t\t\toptions.selectedBones.push_back(boneListBox->GetString(i).ToStdString());\n\t}\n}\n"
  },
  {
    "path": "src/ui/WeightCopyDialog.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../components/Anim.h\"\n#include \"../components/PoseData.h\"\n#include \"../components/UndoState.h\"\n\n#include <wx/checklst.h>\n#include <wx/gauge.h>\n#include <wx/wx.h>\n\nclass OutfitProject;\nclass wxGLPanel;\n\nstruct WeightCopyOptions {\n\tfloat proximityRadius = 0.0f;\n\tint maxResults = 0;\n\tbool showSkinTransOption = false;\n\tbool doSkinTransCopy = false;\n\tbool doTransformGeo = false;\n\tstd::vector<std::string> selectedBones;\n};\n\nclass WeightCopyDialog : public wxDialog {\npublic:\n\tWeightCopyDialog(wxWindow* parent,\n\t\t\t\t\t OutfitProject* project,\n\t\t\t\t\t wxGLPanel* glView,\n\t\t\t\t\t PoseDataCollection& poseDataCollection,\n\t\t\t\t\t const std::unordered_set<std::string>& normalizeBones,\n\t\t\t\t\t const std::vector<nifly::NiShape*>& previewShapes,\n\t\t\t\t\t WeightCopyOptions& options,\n\t\t\t\t\t bool silent);\n\n\tbool GetResult() const { return accepted; }\n\nprivate:\n\tvoid SetupControls();\n\tvoid PopulateBoneList();\n\tvoid PopulatePoseDropdown();\n\tvoid SetupEventHandlers();\n\tvoid ShowSkinTransOptions();\n\tvoid SavePoseState();\n\tvoid RestorePoseState();\n\n\tvoid OnPreview(wxCommandEvent& event);\n\tvoid UndoPreview();\n\tvoid ApplyPreviewWeights();\n\tvoid ShowBoneWeightColors(const std::string& boneName);\n\n\tvoid OnPoseSelected(wxCommandEvent& event);\n\tvoid OnBoneSelected(wxCommandEvent& event);\n\n\tvoid CollectOptions();\n\n\tOutfitProject* project = nullptr;\n\twxGLPanel* glView = nullptr;\n\tPoseDataCollection& poseDataCollection;\n\tconst std::unordered_set<std::string>& normalizeBones;\n\tconst std::vector<nifly::NiShape*>& previewShapes;\n\tWeightCopyOptions& options;\n\n\twxCheckListBox* boneListBox = nullptr;\n\twxChoice* poseChoice = nullptr;\n\twxGauge* previewProgress = nullptr;\n\n\tbool accepted = false;\n\tbool previewActive = false;\n\tUndoStateProject previewUndoState;\n\n\t// Saved state for restoration on close\n\tbool prevBonesMode = false;\n\tbool prevWeightColors = false;\n\tbool prevBPose = false;\n\n\tstruct SavedBonePose {\n\t\tnifly::Vector3 rotVec;\n\t\tnifly::Vector3 tranVec;\n\t\tfloat scale;\n\t};\n\tstd::unordered_map<std::string, SavedBonePose> savedPose;\n\n\t// Normalization helpers (need access to frame)\n\tvoid GetNormalizeBones(std::vector<std::string>* normBones, std::vector<std::string>* notNormBones);\n};\n"
  },
  {
    "path": "src/ui/wxBrushSettingsPopup.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"wxBrushSettingsPopup.h\"\n\n#include <wx/valnum.h>\n\nwxBrushSettingsPopupBase::wxBrushSettingsPopupBase(OutfitStudioFrame* parent, wxWindow* popupWin) {\n\tos = parent;\n\tSetup(popupWin);\n}\n\nvoid wxBrushSettingsPopupBase::Setup(wxWindow* popupWin) {\n\tauto onSliderSize = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat slideSize = brushSize->GetValue() / 1000.0f;\n\n\t\twxString valSizeStr = wxString::Format(\"%0.4f\", slideSize);\n\t\tbrushSizeVal->ChangeValue(valSizeStr);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tos->glView->SetBrushSize(slideSize);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderStrength = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat slideStrength = brushStrength->GetValue() / 1000.0f;\n\n\t\twxString valStrengthStr = wxString::Format(\"%0.4f\", slideStrength);\n\t\tbrushStrengthVal->ChangeValue(valStrengthStr);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->setStrength(slideStrength);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderFocus = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat slideFocus = brushFocus->GetValue() / 1000.0f;\n\n\t\twxString valFocusStr = wxString::Format(\"%0.4f\", slideFocus);\n\t\tbrushFocusVal->ChangeValue(valFocusStr);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->setFocus(slideFocus);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderSpacing = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat slideSpacing = brushSpacing->GetValue() / 1000.0f;\n\n\t\twxString valSpacingStr = wxString::Format(\"%0.4f\", slideSpacing);\n\t\tbrushSpacingVal->ChangeValue(valSpacingStr);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->setSpacing(slideSpacing);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderTextChangedSize = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat textSize = atof(brushSizeVal->GetValue().c_str());\n\t\tbrushSize->SetValue(textSize * 1000);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tos->glView->SetBrushSize(textSize);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderTextChangedStrength = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat textStrength = atof(brushStrengthVal->GetValue().c_str());\n\t\tbrushStrength->SetValue(textStrength * 1000);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->setStrength(textStrength);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderTextChangedFocus = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat textFocus = atof(brushFocusVal->GetValue().c_str());\n\t\tbrushFocus->SetValue(textFocus * 1000);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->setFocus(textFocus);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onSliderTextChangedSpacing = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tfloat textSpacing = atof(brushSpacingVal->GetValue().c_str());\n\t\tbrushSpacing->SetValue(textSpacing * 1000);\n\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->setSpacing(textSpacing);\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tauto onButtonReset = [&](wxCommandEvent& WXUNUSED(event)) {\n\t\tTweakBrush* brush = os->glView->GetActiveBrush();\n\t\tif (brush) {\n\t\t\tbrush->resetSettings();\n\t\t\tos->glView->ResetBrushSize();\n\t\t\tos->UpdateBrushSettings();\n\t\t\tos->CheckBrushBounds();\n\t\t}\n\t};\n\n\tconst int sliderWidth = 250;\n\tconst int textCtrlWidth = 50;\n\n\twxFloatingPointValidator<float> floatValidator(4);\n\tfloatValidator.SetRange(0.0, 10.0);\n\n\tpanel = new wxPanel(popupWin);\n\ttopSizer = new wxBoxSizer(wxVERTICAL);\n\tflexGridSizer = new wxFlexGridSizer(3, 0, 0);\n\tflexGridSizer->AddGrowableCol(1);\n\n\tlbBrushSize = new wxStaticText(panel, wxID_ANY, _(\"Size\"));\n\tflexGridSizer->Add(lbBrushSize, 0, wxALL, 5);\n\n\tbrushSize = new wxSlider(panel, wxID_ANY, 0, 0, 1000, wxDefaultPosition, panel->FromDIP(wxSize(sliderWidth, -1)), wxSL_HORIZONTAL);\n\tbrushSize->SetToolTip(_(\"Shortcut: 'S' + mouse wheel\"));\n\tbrushSize->Bind(wxEVT_SLIDER, onSliderSize);\n\tflexGridSizer->Add(brushSize, 1, wxALL, 5);\n\n\tbrushSizeVal = new wxTextCtrl(panel, wxID_ANY, \"0.0000\", wxDefaultPosition, panel->FromDIP(wxSize(textCtrlWidth, -1)));\n\tbrushSizeVal->SetValidator(floatValidator);\n\tbrushSizeVal->Bind(wxEVT_TEXT, onSliderTextChangedSize);\n\tflexGridSizer->Add(brushSizeVal, 0, wxALL, 5);\n\n\tlbBrushStrength = new wxStaticText(panel, wxID_ANY, _(\"Strength\"));\n\tflexGridSizer->Add(lbBrushStrength, 0, wxALL, 5);\n\n\tbrushStrength = new wxSlider(panel, wxID_ANY, 0, 0, 1000, wxDefaultPosition, panel->FromDIP(wxSize(sliderWidth, -1)), wxSL_HORIZONTAL);\n\tbrushStrength->Bind(wxEVT_SLIDER, onSliderStrength);\n\tflexGridSizer->Add(brushStrength, 1, wxALL, 5);\n\n\tbrushStrengthVal = new wxTextCtrl(panel, wxID_ANY, \"0.0000\", wxDefaultPosition, panel->FromDIP(wxSize(textCtrlWidth, -1)));\n\tbrushStrengthVal->SetValidator(floatValidator);\n\tbrushStrengthVal->Bind(wxEVT_TEXT, onSliderTextChangedStrength);\n\tflexGridSizer->Add(brushStrengthVal, 0, wxALL, 5);\n\n\tlbBrushFocus = new wxStaticText(panel, wxID_ANY, _(\"Focus\"));\n\tflexGridSizer->Add(lbBrushFocus, 0, wxALL, 5);\n\n\tbrushFocus = new wxSlider(panel, wxID_ANY, 0, 0, 1000, wxDefaultPosition, panel->FromDIP(wxSize(sliderWidth, -1)), wxSL_HORIZONTAL);\n\tbrushFocus->Bind(wxEVT_SLIDER, onSliderFocus);\n\tflexGridSizer->Add(brushFocus, 1, wxALL, 5);\n\n\tbrushFocusVal = new wxTextCtrl(panel, wxID_ANY, \"0.0000\", wxDefaultPosition, panel->FromDIP(wxSize(textCtrlWidth, -1)));\n\tbrushFocusVal->SetValidator(floatValidator);\n\tbrushFocusVal->Bind(wxEVT_TEXT, onSliderTextChangedFocus);\n\tflexGridSizer->Add(brushFocusVal, 0, wxALL, 5);\n\n\tlbBrushSpacing = new wxStaticText(panel, wxID_ANY, _(\"Spacing\"));\n\tflexGridSizer->Add(lbBrushSpacing, 0, wxALL, 5);\n\n\tbrushSpacing = new wxSlider(panel, wxID_ANY, 0, 0, 1000, wxDefaultPosition, panel->FromDIP(wxSize(sliderWidth, -1)), wxSL_HORIZONTAL);\n\tbrushSpacing->Bind(wxEVT_SLIDER, onSliderSpacing);\n\tflexGridSizer->Add(brushSpacing, 1, wxALL, 5);\n\n\tbrushSpacingVal = new wxTextCtrl(panel, wxID_ANY, \"0.0000\", wxDefaultPosition, panel->FromDIP(wxSize(textCtrlWidth, -1)));\n\tbrushSpacingVal->SetValidator(floatValidator);\n\tbrushSpacingVal->Bind(wxEVT_TEXT, onSliderTextChangedSpacing);\n\tflexGridSizer->Add(brushSpacingVal, 0, wxALL, 5);\n\n\ttopSizer->Add(flexGridSizer, 0, wxALL, 0);\n\n\tbottomSizer = new wxBoxSizer(wxHORIZONTAL);\n\n\tbuttonReset = new wxButton(panel, wxID_ANY, _(\"Reset\"));\n\tbuttonReset->Bind(wxEVT_BUTTON, onButtonReset);\n\tbottomSizer->Add(buttonReset, 0, wxALL, 0);\n\n\tbrushNameLabel = new wxStaticText(panel, wxID_ANY, \"\");\n\tbottomSizer->Add(brushNameLabel, 0, wxLEFT | wxALIGN_CENTER, 10);\n\n\ttopSizer->Add(bottomSizer, 0, wxALL, 0);\n\n\tpanel->SetSizer(topSizer);\n\n\ttopSizer->Fit(panel);\n\tpopupWin->SetClientSize(panel->GetSize());\n}\n\nvoid wxBrushSettingsPopupBase::SetBrushName(const wxString& brushName) {\n\tbrushNameLabel->SetLabel(brushName);\n}\n\nvoid wxBrushSettingsPopupBase::SetBrushSize(float value) {\n\twxString valStr = wxString::Format(\"%0.4f\", value);\n\tbrushSize->SetValue(std::atof(valStr.c_str()) * 1000.0f);\n\tbrushSizeVal->ChangeValue(valStr);\n}\n\nvoid wxBrushSettingsPopupBase::SetBrushStrength(float value) {\n\twxString valStr = wxString::Format(\"%0.4f\", value);\n\tbrushStrength->SetValue(std::atof(valStr.c_str()) * 1000.0f);\n\tbrushStrengthVal->ChangeValue(valStr);\n}\n\nvoid wxBrushSettingsPopupBase::SetBrushFocus(float value) {\n\twxString valStr = wxString::Format(\"%0.4f\", value);\n\tbrushFocus->SetValue(std::atof(valStr.c_str()) * 1000.0f);\n\tbrushFocusVal->ChangeValue(valStr);\n}\n\nvoid wxBrushSettingsPopupBase::SetBrushSpacing(float value) {\n\twxString valStr = wxString::Format(\"%0.4f\", value);\n\tbrushSpacing->SetValue(std::atof(valStr.c_str()) * 1000.0f);\n\tbrushSpacingVal->ChangeValue(valStr);\n}\n\n\nwxBrushSettingsPopupTransient::wxBrushSettingsPopupTransient(OutfitStudioFrame* parent, bool stayOpen)\n\t: wxPopupTransientWindow(parent, wxBORDER_SIMPLE | wxPU_CONTAINS_CONTROLS)\n\t, wxBrushSettingsPopupBase(parent, this) {\n\tthis->stayOpen = stayOpen;\n}\n"
  },
  {
    "path": "src/ui/wxBrushSettingsPopup.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../program/OutfitStudio.h\"\n\n#include <wx/popupwin.h>\n\nclass wxBrushSettingsPopupBase {\nprotected:\n\tOutfitStudioFrame* os = nullptr;\n\n\twxPanel* panel = nullptr;\n\twxBoxSizer* topSizer = nullptr;\n\twxFlexGridSizer* flexGridSizer = nullptr;\n\n\twxStaticText* lbBrushSize = nullptr;\n\twxSlider* brushSize = nullptr;\n\twxTextCtrl* brushSizeVal = nullptr;\n\n\twxStaticText* lbBrushStrength = nullptr;\n\twxSlider* brushStrength = nullptr;\n\twxTextCtrl* brushStrengthVal = nullptr;\n\n\twxStaticText* lbBrushFocus = nullptr;\n\twxSlider* brushFocus = nullptr;\n\twxTextCtrl* brushFocusVal = nullptr;\n\n\twxStaticText* lbBrushSpacing = nullptr;\n\twxSlider* brushSpacing = nullptr;\n\twxTextCtrl* brushSpacingVal = nullptr;\n\n\twxBoxSizer* bottomSizer = nullptr;\n\twxButton* buttonReset = nullptr;\n\twxStaticText* brushNameLabel = nullptr;\n\n\tvoid Setup(wxWindow* popupWin);\n\npublic:\n\twxBrushSettingsPopupBase(OutfitStudioFrame* parent, wxWindow* popupWin);\n\n\tvoid SetBrushName(const wxString& brushName);\n\tvoid SetBrushSize(float value);\n\tvoid SetBrushStrength(float value);\n\tvoid SetBrushFocus(float value);\n\tvoid SetBrushSpacing(float value);\n};\n\nclass wxBrushSettingsPopupTransient : public wxPopupTransientWindow, public wxBrushSettingsPopupBase {\nprivate:\n\tbool stayOpen = false;\n\npublic:\n\twxBrushSettingsPopupTransient(OutfitStudioFrame* parent, bool stayOpen);\n\n#ifdef _WINDOWS\n\t// IsMouseInWindow is only available on Windows\n\tvoid Dismiss() override {\n\t\tif (!stayOpen || !GetParent()->IsMouseInWindow())\n\t\t\tHide();\n\t}\n\n\tvoid MSWDismissUnfocusedPopup() override {\n\t\tif (stayOpen)\n\t\t\tDismiss();\n\t}\n#endif\n};\n"
  },
  {
    "path": "src/ui/wxNormalsGenDlg.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"wxNormalsGenDlg.h\"\n#include \"../utils/ConfigurationManager.h\"\n\n#include <wx/xrc/xmlres.h>\n\nextern ConfigurationManager Config;\n\nwxBEGIN_EVENT_TABLE(wxNormalsGenDlg, wxDialog)\n\tEVT_RIGHT_DOWN(wxNormalsGenDlg::ShowPresetContextMenu)\n\tEVT_BUTTON(XRCID(\"bpPreset\"), wxNormalsGenDlg::doShowPresetContext)\n\tEVT_BUTTON(XRCID(\"btnAddLayer\"), wxNormalsGenDlg::doAddLayer)\n\tEVT_BUTTON(XRCID(\"btnMoveUp\"), wxNormalsGenDlg::doMoveUpLayer)\n\tEVT_BUTTON(XRCID(\"btnDeleteLayer\"), wxNormalsGenDlg::doDeleteLayer)\n\tEVT_CHECKBOX(XRCID(\"cbSaveToBGLayerFile\"), wxNormalsGenDlg::OnUseBackgroundLayerCheck)\n\tEVT_FILEPICKER_CHANGED(XRCID(\"fpOutputFile\"), wxNormalsGenDlg::doSetOutputFileName)\n\tEVT_BUTTON(XRCID(\"btnPreview\"), wxNormalsGenDlg::doPreviewNormalMap)\n\tEVT_BUTTON(XRCID(\"btnGenerate\"), wxNormalsGenDlg::doGenerateNormalMap)\nwxEND_EVENT_TABLE()\n\nwxNormalsGenDlg::wxNormalsGenDlg(wxWindow* parent) {\n\twxXmlResource* xrc = wxXmlResource::Get();\n\txrc->Load(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/NormalsGenDlg.xrc\");\n\txrc->LoadDialog(this, parent, \"wxNormalsGenDlg\");\n\n\tbpPreset = XRCCTRL(*this, \"bpPreset\", wxBitmapButton);\n\tbtnAddLayer = XRCCTRL(*this, \"btnAddLayer\", wxButton);\n\tbtnMoveUp = XRCCTRL(*this, \"btnMoveUp\", wxButton);\n\tbtnDeleteLayer = XRCCTRL(*this, \"btnDeleteLayer\", wxButton);\n\tcbBackup = XRCCTRL(*this, \"cbBackup\", wxCheckBox);\n\tcbCompress = XRCCTRL(*this, \"cbCompress\", wxCheckBox);\n\tcbSaveToBGLayerFile = XRCCTRL(*this, \"cbSaveToBGLayerFile\", wxCheckBox);\n\tfpOutputFile = XRCCTRL(*this, \"fpOutputFile\", wxFilePickerCtrl);\n\tbtnPreview = XRCCTRL(*this, \"btnPreview\", wxButton);\n\tbtnGenerate = XRCCTRL(*this, \"btnGenerate\", wxButton);\n\n\tpgLayers = new wxPropertyGrid(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPG_DEFAULT_STYLE | wxPG_SPLITTER_AUTO_CENTER);\n\tpgLayers->SetExtraStyle(wxPG_EX_ENABLE_TLP_TRACKING | wxPG_EX_HELP_AS_TOOLTIPS);\n\tpgLayers->Bind(wxEVT_PG_CHANGED, &wxNormalsGenDlg::doPropertyChanged, this);\n\txrc->AttachUnknownControl(\"pgLayers\", pgLayers, this);\n\n\tpresetContext = xrc->LoadMenu(\"presetContext\");\n\tpresetContext->Bind(wxEVT_MENU, &wxNormalsGenDlg::doLoadPreset, this, presetContext->FindItem(XRCID(\"ctxLoadPreset\"))->GetId());\n\tpresetContext->Bind(wxEVT_MENU, &wxNormalsGenDlg::doSavePreset, this, presetContext->FindItem(XRCID(\"ctxSavePreset\"))->GetId());\n\n\tFit();\n\tLayout();\n\tCenterOnParent();\n}\n\nwxNormalsGenDlg::~wxNormalsGenDlg() {\n\tdelete presetContext;\n\twxXmlResource::Get()->Unload(wxString::FromUTF8(Config[\"AppDir\"]) + \"/res/xrc/NormalsGenDlg.xrc\");\n}\n"
  },
  {
    "path": "src/ui/wxNormalsGenDlg.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <wx/filepicker.h>\n#include <wx/propgrid/advprops.h>\n#include <wx/propgrid/propgrid.h>\n#include <wx/wx.h>\n\nclass wxNormalsGenDlg : public wxDialog {\nprotected:\n\tvoid ShowPresetContextMenu(wxMouseEvent& event) { PopupMenu(presetContext, event.GetPosition()); }\n\n\twxBitmapButton* bpPreset = nullptr;\n\twxPropertyGrid* pgLayers = nullptr;\n\twxButton* btnAddLayer = nullptr;\n\twxButton* btnMoveUp = nullptr;\n\twxButton* btnDeleteLayer = nullptr;\n\twxCheckBox* cbBackup = nullptr;\n\twxCheckBox* cbCompress = nullptr;\n\twxCheckBox* cbSaveToBGLayerFile = nullptr;\n\twxFilePickerCtrl* fpOutputFile = nullptr;\n\twxButton* btnPreview = nullptr;\n\twxButton* btnGenerate = nullptr;\n\twxMenu* presetContext = nullptr;\n\n\t// Virtual event handlers, override them in your derived class\n\tvirtual void doShowPresetContext(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doPropertyChanged(wxPropertyGridEvent& event) { event.Skip(); }\n\tvirtual void doAddLayer(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doMoveUpLayer(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doDeleteLayer(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void OnUseBackgroundLayerCheck(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doSetOutputFileName(wxFileDirPickerEvent& event) { event.Skip(); }\n\tvirtual void doPreviewNormalMap(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doGenerateNormalMap(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doLoadPreset(wxCommandEvent& event) { event.Skip(); }\n\tvirtual void doSavePreset(wxCommandEvent& event) { event.Skip(); }\n\n\twxDECLARE_EVENT_TABLE();\n\npublic:\n\twxNormalsGenDlg(wxWindow* parent);\n\t~wxNormalsGenDlg();\n};\n"
  },
  {
    "path": "src/ui/wxSliderPanel.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"wxSliderPanel.h\"\n\nIMPLEMENT_DYNAMIC_CLASS(wxSliderPanel, wxWindow)\n\nBEGIN_EVENT_TABLE(wxSliderPanel, wxWindow)\nEND_EVENT_TABLE()\n\nwxSliderPanel::wxSliderPanel()\n\t: wxWindow() {}\n\nwxSliderPanel::wxSliderPanel(wxWindow* parent, const wxString& name, int sliderMin, int sliderMax, const wxBitmap& bmpEdit, const wxBitmap& bmpSettings)\n\t: wxWindow() {\n\tCreate(parent, name, sliderMin, sliderMax, bmpEdit, bmpSettings);\n}\n\nbool wxSliderPanel::Create(wxWindow* parent, const wxString& name, int sliderMin, int sliderMax, const wxBitmap& bmpEdit, const wxBitmap& bmpSettings) {\n\tif (isCreated) {\n\t\tbtnSliderEdit->SetName(name + \"|btn\");\n\t\tbtnSliderProp->SetName(name + \"|btnSliderProp\");\n\t\tbtnMinus->SetName(name + \"|btnMinus\");\n\t\tbtnPlus->SetName(name + \"|btnPlus\");\n\t\tsliderCheck->SetName(name + \"|check\");\n\t\tsliderName->SetName(name + \"|lbl\");\n\t\tslider->SetName(name + \"|slider\");\n\t\tsliderReadout->SetName(name + \"|readout\");\n\n\t\tsliderName->SetLabel(name);\n\n\t\tsliderCheck->Enable(true);\n\t\tslider->SetMin(sliderMin);\n\t\tslider->SetMax(sliderMax);\n\t\tslider->SetValue(0);\n\t\tsliderReadout->ChangeValue(\"0%\");\n\t\tsliderCheck->Set3StateValue(wxCheckBoxState::wxCHK_CHECKED);\n\n\t\tbtnSliderProp->Hide();\n\t\tbtnMinus->Hide();\n\t\tbtnPlus->Hide();\n\n\t\tediting = false;\n\t\tSetBackgroundColour(wxColour(64, 64, 64));\n\n\t\tShow();\n\t\treturn true;\n\t}\n\n\tif (!wxWindow::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER | wxTAB_TRAVERSAL))\n\t\treturn false;\n\n\tHide();\n\n\tSetBackgroundColour(wxColour(64, 64, 64));\n\tSetMinSize(FromDIP(wxSize(-1, 25)));\n\tSetMaxSize(FromDIP(wxSize(-1, 25)));\n\n\tsizer = new wxBoxSizer(wxHORIZONTAL);\n\n\tbtnSliderEdit = new wxBitmapButton();\n\tbtnSliderEdit->Create(this, wxID_ANY, bmpEdit, wxDefaultPosition, FromDIP(wxSize(22, 22)), wxBU_AUTODRAW, wxDefaultValidator, name + \"|btn\");\n\tbtnSliderEdit->SetToolTip(_(\"Turn on edit mode for this slider.\"));\n\tsizer->Add(btnSliderEdit, 0, wxALIGN_CENTER_VERTICAL | wxALL);\n\n\tbtnSliderProp = new wxBitmapButton();\n\tbtnSliderProp->Hide();\n\tbtnSliderProp->Create(this, wxID_ANY, bmpSettings, wxDefaultPosition, FromDIP(wxSize(22, 22)), wxBU_AUTODRAW, wxDefaultValidator, name + \"|btnSliderProp\");\n\tbtnSliderProp->SetToolTip(_(\"Display and edit the active slider's properties.\"));\n\tsizer->Add(btnSliderProp, 0, wxALIGN_CENTER_VERTICAL | wxALL);\n\n\tbtnMinus = new wxButton();\n\tbtnMinus->Hide();\n\tbtnMinus->Create(this, wxID_ANY, \"-\", wxDefaultPosition, FromDIP(wxSize(18, 18)), 0, wxDefaultValidator, name + \"|btnMinus\");\n\tbtnMinus->SetToolTip(_(\"Weaken slider data by 1%.\"));\n\tbtnMinus->SetForegroundColour(wxTransparentColour);\n\tsizer->Add(btnMinus, 0, wxALIGN_CENTER_VERTICAL | wxALL);\n\n\tbtnPlus = new wxButton();\n\tbtnPlus->Hide();\n\tbtnPlus->Create(this, wxID_ANY, \"+\", wxDefaultPosition, FromDIP(wxSize(18, 18)), 0, wxDefaultValidator, name + \"|btnPlus\");\n\tbtnPlus->SetToolTip(_(\"Strengthen slider data by 1%.\"));\n\tbtnPlus->SetForegroundColour(wxTransparentColour);\n\tsizer->Add(btnPlus, 0, wxALIGN_CENTER_VERTICAL | wxALL);\n\n\tsliderCheck = new wxCheckBox();\n\tsliderCheck->Create(this, wxID_ANY, \"\", wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, name + \"|check\");\n\tsliderCheck->SetForegroundColour(wxColour(255, 255, 255));\n\tsizer->Add(sliderCheck, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);\n\n\tsliderName = new wxStaticText();\n\tsliderName->Create(this, wxID_ANY, name, wxDefaultPosition, wxDefaultSize, 0, name + \"|lbl\");\n\tsliderName->SetForegroundColour(wxColour(255, 255, 255));\n\tsizer->Add(sliderName, 0, wxALIGN_CENTER_VERTICAL | wxALL);\n\n\tslider = new wxSlider();\n\tslider->Create(this, wxID_ANY, 0, sliderMin, sliderMax, wxDefaultPosition, wxSize(-1, -1), wxSL_HORIZONTAL, wxDefaultValidator, name + \"|slider\");\n\tslider->SetMinSize(FromDIP(wxSize(-1, 20)));\n\tslider->SetMaxSize(FromDIP(wxSize(-1, 20)));\n\n\tsizer->Add(slider, 1, wxLEFT | wxRIGHT | wxEXPAND, 5);\n\n\tsliderReadout = new wxTextCtrl();\n\tsliderReadout->Create(this, wxID_ANY, \"0%\", wxDefaultPosition, FromDIP(wxSize(40, -1)), wxTE_RIGHT | wxTE_PROCESS_ENTER | wxSIMPLE_BORDER, wxDefaultValidator, name + \"|readout\");\n\tsliderReadout->SetMaxLength(0);\n\tsliderReadout->SetForegroundColour(wxColour(255, 255, 255));\n\tsliderReadout->SetBackgroundColour(wxColour(48, 48, 48));\n\tsliderReadout->SetMinSize(FromDIP(wxSize(40, 20)));\n\tsliderReadout->SetMaxSize(FromDIP(wxSize(40, 20)));\n\n\tsizer->Add(sliderReadout, 0, wxALIGN_CENTER_VERTICAL | wxALL, 2);\n\n\tSetSizer(sizer);\n\tsizer->Fit(this);\n\n\tisCreated = true;\n\treturn true;\n}\n\n\nwxSliderPanel* wxSliderPanelPool::Push() {\n\tif (pool.size() < MaxPoolSize) {\n\t\tauto entry = new wxSliderPanel();\n\t\tpool.push_back(entry);\n\t\treturn entry;\n\t}\n\n\treturn nullptr;\n}\n\nvoid wxSliderPanelPool::CreatePool(size_t poolSize, wxWindow* parent, const wxBitmap& bmpEdit, const wxBitmap& bmpSettings) {\n\tif (poolSize > MaxPoolSize)\n\t\tpoolSize = MaxPoolSize;\n\n\tpool.resize(poolSize, nullptr);\n\n\tfor (auto& p : pool) {\n\t\tif (!p)\n\t\t\tp = new wxSliderPanel();\n\n\t\tif (!p->IsCreated())\n\t\t\tp->Create(parent, \"sliderPoolDummy\", 0, 100, bmpEdit, bmpSettings);\n\t}\n}\n\nwxSliderPanel* wxSliderPanelPool::Get(size_t index) {\n\tif (pool.size() > index)\n\t\treturn pool[index];\n\n\treturn nullptr;\n}\n\nsize_t wxSliderPanelPool::FindIndex(wxSliderPanel* sliderPanel) {\n\tauto poolIt = std::find(pool.begin(), pool.end(), sliderPanel);\n\tif (poolIt == pool.end())\n\t\treturn static_cast<size_t>(-1);\n\n\treturn std::distance(pool.begin(), poolIt);\n}\n\nwxSliderPanel* wxSliderPanelPool::GetNext() {\n\tfor (size_t i = 0; i < pool.size(); ++i) {\n\t\twxSliderPanel* sliderPanel = pool[i];\n\n\t\t// Index of a slider panel that is invisible can be reused\n\t\tif (sliderPanel && !sliderPanel->IsShown())\n\t\t\treturn sliderPanel;\n\t}\n\n\treturn Push();\n}\n\nvoid wxSliderPanelPool::Clear() {\n\tfor (auto& p : pool)\n\t\tp->Destroy();\n\n\tpool.clear();\n}\n"
  },
  {
    "path": "src/ui/wxSliderPanel.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <wx/wx.h>\n\nclass wxSliderPanel : public wxWindow {\n\tbool isCreated = false;\n\twxBoxSizer* sizer = nullptr;\n\npublic:\n\twxBitmapButton* btnSliderEdit = nullptr;\n\twxBitmapButton* btnSliderProp = nullptr;\n\twxButton* btnMinus = nullptr;\n\twxButton* btnPlus = nullptr;\n\twxCheckBox* sliderCheck = nullptr;\n\twxStaticText* sliderName = nullptr;\n\twxSlider* slider = nullptr;\n\twxTextCtrl* sliderReadout = nullptr;\n\n\tbool editing = false;\n\n\twxSliderPanel();\n\twxSliderPanel(wxWindow* parent, const wxString& name, int sliderMin, int sliderMax, const wxBitmap& bmpEdit, const wxBitmap& bmpSettings);\n\n\tbool Create(wxWindow* parent, const wxString& name, int sliderMin, int sliderMax, const wxBitmap& bmpEdit, const wxBitmap& bmpSettings);\n\tbool IsCreated() { return isCreated; }\n\n\tDECLARE_DYNAMIC_CLASS(wxSliderPanel)\n\tDECLARE_EVENT_TABLE()\n};\n\nclass wxSliderPanelPool {\n\tstd::vector<wxSliderPanel*> pool;\n\n\tconst size_t MaxPoolSize = 500;\n\npublic:\n\twxSliderPanel* Push();\n\tvoid CreatePool(size_t poolSize, wxWindow* parent, const wxBitmap& bmpEdit, const wxBitmap& bmpSettings);\n\twxSliderPanel* Get(size_t index);\n\tsize_t FindIndex(wxSliderPanel* sliderPanel);\n\twxSliderPanel* GetNext();\n\tvoid Clear();\n};\n"
  },
  {
    "path": "src/ui/wxStateButton.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"wxStateButton.h\"\n\nwxIMPLEMENT_DYNAMIC_CLASS(wxStateButton, wxButton);\n\nwxBEGIN_EVENT_TABLE(wxStateButton, wxButton)\n\tEVT_LEFT_DOWN(wxStateButton::mouseDown)\n\tEVT_LEFT_UP(wxStateButton::mouseReleased)\n\tEVT_PAINT(wxStateButton::paintEvent)\nwxEND_EVENT_TABLE()\n\nwxStateButton::wxStateButton()\n\t: wxButton() {}\n\nwxStateButton::wxStateButton(wxWindow* parent,\n\t\t\t\t\t\t\t wxWindowID id,\n\t\t\t\t\t\t\t const wxString& label,\n\t\t\t\t\t\t\t const wxPoint& pos,\n\t\t\t\t\t\t\t const wxSize& size,\n\t\t\t\t\t\t\t long style,\n\t\t\t\t\t\t\t const wxValidator& validator,\n\t\t\t\t\t\t\t const wxString& name,\n\t\t\t\t\t\t\t const bool noState)\n\t: wxButton(parent, id, label, pos, size, style, validator, name) {\n\tm_bNoState = noState;\n}\n\n/*\n * Called by the system of by wxWidgets when the panel needs\n * to be redrawn. You can also trigger this call by\n * calling Refresh()/Update().\n */\nvoid wxStateButton::paintEvent(wxPaintEvent& WXUNUSED(evt)) {\n\t// Depending on your system you may need to look at double-buffered dcs\n\twxPaintDC dc(this);\n\trender(dc);\n}\n\n/*\n * Alternatively, you can use a clientDC to paint on the panel\n * at any time. Using this generally does not free you from\n * catching paint events, since it is possible that e.g. the window\n * manager throws away your drawing when the window comes to the\n * background, and expects you will redraw it when the window comes\n * back (by sending a paint event).\n */\nvoid wxStateButton::paintNow() {\n\t// Depending on your system you may need to look at double-buffered dcs\n\twxClientDC dc(this);\n\trender(dc);\n}\n\n/*\n * Here we do the actual rendering. I put it in a separate\n * method so that it can work no matter what type of DC\n * (e.g. wxPaintDC or wxClientDC) is used.\n */\nvoid wxStateButton::render(wxDC& dc) {\n\tint w;\n\tint h;\n\tdc.GetSize(&w, &h);\n\tif (m_bChecked) {\n\t\tdc.SetBrush(*wxGREY_BRUSH);\n\t\tdc.SetTextForeground(wxColor(255, 255, 255));\n\t}\n\telse {\n\t\tdc.SetBrush(wxBrush(wxColor(64, 64, 64)));\n\t\tdc.SetTextForeground(*wxLIGHT_GREY);\n\t}\n\tdc.SetPen(*wxGREY_PEN);\n\n\twxRect r = GetClientRect();\n\tdc.DrawRectangle(0, 0, w, h);\n\tdc.SetFont(wxSystemSettings::GetFont(wxSystemFont::wxSYS_DEFAULT_GUI_FONT));\n\n\tif (m_bPendingChanges)\n\t\tdc.DrawLabel(\"* \" + GetLabel(), r, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL);\n\telse\n\t\tdc.DrawLabel(GetLabel(), r, wxALIGN_CENTER_VERTICAL | wxALIGN_CENTER_HORIZONTAL);\n}\n\nvoid wxStateButton::SetPendingChanges(bool newPending) {\n\tif (m_bPendingChanges != newPending) {\n\t\tm_bPendingChanges = newPending;\n\t\tRefresh();\n\t}\n}\n\nvoid wxStateButton::mouseDown(wxMouseEvent& WXUNUSED(event)) {\n\twxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, GetId());\n\tevt.SetEventObject(this);\n\tProcessEvent(evt);\n\n\tif (!evt.GetSkipped()) {\n\t\tm_bChecked = true;\n\t\tRefresh();\n\t}\n}\n\nvoid wxStateButton::mouseReleased(wxMouseEvent& event) {\n\tif (m_bNoState) {\n\t\tm_bChecked = false;\n\t\tRefresh();\n\t}\n\tevent.Skip();\n}\n"
  },
  {
    "path": "src/ui/wxStateButton.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <wx/wx.h>\n\nclass wxStateButton : public wxButton {\n\tbool m_bChecked = false;\n\tbool m_bPendingChanges = false;\n\tbool m_bNoState = false;\n\twxString text;\n\npublic:\n\twxStateButton();\n\twxStateButton(wxWindow* parent,\n\t\t\t\t  wxWindowID,\n\t\t\t\t  const wxString& label = wxEmptyString,\n\t\t\t\t  const wxPoint& pos = wxDefaultPosition,\n\t\t\t\t  const wxSize& size = wxDefaultSize,\n\t\t\t\t  long style = 0,\n\t\t\t\t  const wxValidator& validator = wxDefaultValidator,\n\t\t\t\t  const wxString& name = \"button\",\n\t\t\t\t  const bool noState = false);\n\n\tvoid paintEvent(wxPaintEvent& evt);\n\tvoid paintNow();\n\n\tvoid render(wxDC& dc);\n\n\tbool GetCheck() { return m_bChecked; }\n\tvoid SetCheck(bool newCheck = true) { m_bChecked = newCheck; }\n\n\tbool HasPendingChanges() { return m_bPendingChanges; }\n\tvoid SetPendingChanges(bool newPending = true);\n\n\tvoid mouseDown(wxMouseEvent& WXUNUSED(event));\n\tvoid mouseReleased(wxMouseEvent& event);\n\n\tDECLARE_DYNAMIC_CLASS(wxStateButton)\n\tDECLARE_EVENT_TABLE()\n};\n"
  },
  {
    "path": "src/utils/AABBTree.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"AABBTree.h\"\n\nusing namespace nifly;\n\nAABB::AABB(const Vector3& newMin, const Vector3& newMax) {\n\tmin = newMin;\n\tmax = newMax;\n}\n\nAABB::AABB(const Vector3* points, const uint16_t nPoints) {\n\tif (nPoints <= 0)\n\t\treturn;\n\n\tmin = points[0];\n\tmax = points[0];\n\tfor (uint16_t i = 1; i < nPoints; i++) {\n\t\tif (points[i].x < min.x)\n\t\t\tmin.x = points[i].x;\n\t\tif (points[i].y < min.y)\n\t\t\tmin.y = points[i].y;\n\t\tif (points[i].z < min.z)\n\t\t\tmin.z = points[i].z;\n\n\t\tif (points[i].x > max.x)\n\t\t\tmax.x = points[i].x;\n\t\tif (points[i].y > max.y)\n\t\t\tmax.y = points[i].y;\n\t\tif (points[i].z > max.z)\n\t\t\tmax.z = points[i].z;\n\t}\n}\n\nAABB::AABB(const Vector3* points, const uint16_t* indices, const uint16_t nPoints) {\n\tif (nPoints <= 0)\n\t\treturn;\n\n\tmin = points[indices[0]];\n\tmax = points[indices[0]];\n\tuint16_t idx;\n\tfor (uint16_t i = 1; i < nPoints; i++) {\n\t\tidx = indices[i];\n\t\tif (points[idx].x < min.x)\n\t\t\tmin.x = points[idx].x;\n\t\tif (points[idx].y < min.y)\n\t\t\tmin.y = points[idx].y;\n\t\tif (points[idx].z < min.z)\n\t\t\tmin.z = points[idx].z;\n\n\t\tif (points[idx].x > max.x)\n\t\t\tmax.x = points[idx].x;\n\t\tif (points[idx].y > max.y)\n\t\t\tmax.y = points[idx].y;\n\t\tif (points[idx].z > max.z)\n\t\t\tmax.z = points[idx].z;\n\t}\n}\n\nvoid AABB::AddBoxToMesh(std::vector<Vector3>& verts, std::vector<Edge>& edges) {\n\tVector3 v;\n\tEdge e;\n\tuint16_t s = static_cast<uint16_t>(verts.size());\n\n\tv.x = min.x;\n\tv.y = min.y;\n\tv.z = min.z;\n\tverts.push_back(v);\n\tv.z = max.z;\n\tverts.push_back(v);\n\tv.y = max.y;\n\tverts.push_back(v);\n\tv.z = min.z;\n\tverts.push_back(v);\n\n\tv.x = max.x;\n\tverts.push_back(v);\n\tv.y = min.y;\n\tverts.push_back(v);\n\tv.z = max.z;\n\tverts.push_back(v);\n\tv.y = max.y;\n\tverts.push_back(v);\n\n\te.p1 = s;\n\te.p2 = s + 1;\n\tedges.push_back(e);\n\te.p1 = s + 1;\n\te.p2 = s + 2;\n\tedges.push_back(e);\n\te.p1 = s + 2;\n\te.p2 = s + 3;\n\tedges.push_back(e);\n\te.p1 = s + 3;\n\te.p2 = s;\n\tedges.push_back(e);\n\te.p1 = s + 3;\n\te.p2 = s + 4;\n\tedges.push_back(e);\n\te.p1 = s + 4;\n\te.p2 = s + 5;\n\tedges.push_back(e);\n\te.p1 = s + 5;\n\te.p2 = s + 6;\n\tedges.push_back(e);\n\te.p1 = s + 6;\n\te.p2 = s + 7;\n\tedges.push_back(e);\n\te.p1 = s;\n\te.p2 = s + 5;\n\tedges.push_back(e);\n\te.p1 = s + 1;\n\te.p2 = s + 6;\n\tedges.push_back(e);\n\te.p1 = s + 2;\n\te.p2 = s + 7;\n\tedges.push_back(e);\n\te.p1 = s + 7;\n\te.p2 = s + 4;\n\tedges.push_back(e);\n}\n\nvoid AABB::Merge(const Vector3* points, const uint16_t* indices, const uint16_t nPoints) {\n\tif (nPoints <= 0)\n\t\treturn;\n\n\tuint16_t idx;\n\tfor (uint16_t i = 0; i < nPoints; i++) {\n\t\tidx = indices[i];\n\t\tif (points[idx].x < min.x)\n\t\t\tmin.x = points[idx].x;\n\t\tif (points[idx].y < min.y)\n\t\t\tmin.y = points[idx].y;\n\t\tif (points[idx].z < min.z)\n\t\t\tmin.z = points[idx].z;\n\n\t\tif (points[idx].x > max.x)\n\t\t\tmax.x = points[idx].x;\n\t\tif (points[idx].y > max.y)\n\t\t\tmax.y = points[idx].y;\n\t\tif (points[idx].z > max.z)\n\t\t\tmax.z = points[idx].z;\n\t}\n}\n\nvoid AABB::Merge(const AABB& other) {\n\tif (other.min.x < min.x)\n\t\tmin.x = other.min.x;\n\tif (other.min.y < min.y)\n\t\tmin.y = other.min.y;\n\tif (other.min.z < min.z)\n\t\tmin.z = other.min.z;\n\n\tif (other.max.x > max.x)\n\t\tmax.x = other.max.x;\n\tif (other.max.y > max.y)\n\t\tmax.y = other.max.y;\n\tif (other.max.z > max.z)\n\t\tmax.z = other.max.z;\n}\n\nbool AABB::IntersectAABB(const AABB& other) {\n\tif (min.x > other.max.x)\n\t\treturn false;\n\tif (min.y > other.max.y)\n\t\treturn false;\n\tif (min.z > other.max.z)\n\t\treturn false;\n\tif (max.x < other.min.x)\n\t\treturn false;\n\tif (max.y < other.min.y)\n\t\treturn false;\n\tif (max.z < other.min.z)\n\t\treturn false;\n\treturn true;\n}\n\nbool AABB::IntersectRay(const Vector3& Origin, const Vector3& Direction, Vector3* outCoord) {\n\t//char side[3];  // side of potential collision plane: 0=left 1=right 2 = middle\n\tVector3 maxT(-1, -1, -1);\n\tVector3 collisionCoord;\n\tbool inside = true;\n\tchar axis = 0;\n\tfloat planeval = -1;\n\n\t// X Axis candidacy\n\tif (Origin.x < min.x) {\n\t\tinside = false;\n\t\tif (Direction.x != 0.0f) {\n\t\t\tmaxT.x = (min.x - Origin.x) / Direction.x;\n\t\t}\n\t}\n\telse if (Origin.x > max.x) {\n\t\tinside = false;\n\t\tif (Direction.x != 0.0f) {\n\t\t\tmaxT.x = (max.x - Origin.x) / Direction.x;\n\t\t}\n\t}\n\tplaneval = maxT.x;\n\t// Y Axis candidacy\n\tif (Origin.y < min.y) {\n\t\tinside = false;\n\t\tif (Direction.y != 0.0f) {\n\t\t\tmaxT.y = (min.y - Origin.y) / Direction.y;\n\t\t}\n\t}\n\telse if (Origin.y > max.y) {\n\t\tinside = false;\n\t\tif (Direction.y != 0.0f) {\n\t\t\tmaxT.y = (max.y - Origin.y) / Direction.y;\n\t\t}\n\t}\n\tif (maxT.y > planeval) {\n\t\tplaneval = maxT.y;\n\t\taxis = 1;\n\t}\n\t// Z Axis candidacy\n\tif (Origin.z < min.z) {\n\t\tinside = false;\n\t\tif (Direction.z != 0.0f) {\n\t\t\tmaxT.z = (min.z - Origin.z) / Direction.z;\n\t\t}\n\t}\n\telse if (Origin.z > max.z) {\n\t\tinside = false;\n\t\tif (Direction.z != 0.0f) {\n\t\t\tmaxT.z = (max.z - Origin.z) / Direction.z;\n\t\t}\n\t}\n\tif (maxT.z > planeval) {\n\t\tplaneval = maxT.z;\n\t\taxis = 2;\n\t}\n\n\tif (inside) {\n\t\tif (outCoord)\n\t\t\t(*outCoord) = Origin;\n\t\treturn true;\n\t}\n\tif (planeval < 0)\n\t\treturn false;\n\n\tif (axis == 0) {\n\t\tcollisionCoord.x = planeval;\n\t}\n\telse {\n\t\tcollisionCoord.x = Origin.x + planeval * Direction.x;\n\t\tif (collisionCoord.x < min.x || collisionCoord.x > max.x)\n\t\t\treturn false;\n\t}\n\tif (axis == 1) {\n\t\tcollisionCoord.y = planeval;\n\t}\n\telse {\n\t\tcollisionCoord.y = Origin.y + planeval * Direction.y;\n\t\tif (collisionCoord.y < min.y || collisionCoord.y > max.y)\n\t\t\treturn false;\n\t}\n\tif (axis == 2) {\n\t\tcollisionCoord.z = planeval;\n\t}\n\telse {\n\t\tcollisionCoord.z = Origin.z + planeval * Direction.z;\n\t\tif (collisionCoord.z < min.z || collisionCoord.z > max.z)\n\t\t\treturn false;\n\t}\n\n\tif (outCoord)\n\t\t(*outCoord) = collisionCoord;\n\treturn true;\n}\n\nbool AABB::IntersectSphere(const Vector3& Origin, const float radius) {\n\tfloat s, d = 0;\n\n\tif (Origin.x < min.x) {\n\t\ts = Origin.x - min.x;\n\t\td += s * s;\n\t}\n\telse if (Origin.x > max.x) {\n\t\ts = Origin.x - max.x;\n\t\td += s * s;\n\t}\n\tif (Origin.y < min.y) {\n\t\ts = Origin.y - min.y;\n\t\td += s * s;\n\t}\n\telse if (Origin.y > max.y) {\n\t\ts = Origin.y - max.y;\n\t\td += s * s;\n\t}\n\tif (Origin.z < min.z) {\n\t\ts = Origin.z - min.z;\n\t\td += s * s;\n\t}\n\telse if (Origin.z > max.z) {\n\t\ts = Origin.z - max.z;\n\t\td += s * s;\n\t}\n\n\treturn d <= radius * radius;\n}\n\nAABBTree::AABBTreeNode::AABBTreeNode(\n\tstd::vector<uint32_t>& facetIndices, const uint32_t start, const uint32_t end, AABBTree* treeRef, AABBTreeNode* parentRef, const uint32_t depth) {\n\tint axis;\n\tVector3 axis_avg;\n\ttree = treeRef;\n\tparent = parentRef;\n\tuint32_t moreStart = 0;\n\n\tif (facetIndices.size() < treeRef->MinFacets())\n\t\treturn;\n\n\t// calculate this node's containing AABB and the geometric average\n\ttreeRef->CalcAABBandGeoAvg(facetIndices, start, end, mBB, axis_avg);\n\n\t// Force a leaf if the facet count gets below a certain threshold or the depth becomes too large.\n\tif ((end - start + 1) <= treeRef->MinFacets() || depth > treeRef->MaxDepth()) {\n\t\tnFacets = end - start + 1;\n\t\tmIFacets = std::make_unique<uint32_t[]>(nFacets);\n\t\tint p = 0;\n\t\tfor (uint32_t f = start; f <= end; f++)\n\t\t\tmIFacets[p++] = facetIndices[f];\n\n\t\treturn;\n\t}\n\n\t// determine split axis\n\tVector3 diag = mBB.max - mBB.min;\n\taxis = 0;\n\tfloat curmax = diag.x;\n\tif (diag.y > curmax) {\n\t\taxis = 1;\n\t\tcurmax = diag.y;\n\t}\n\n\tif (diag.z > curmax)\n\t\taxis = 2;\n\n\tuint32_t l = start;\n\tfloat lval;\n\n\tuint32_t r = end;\n\tfloat rval;\n\n\tswitch (axis) {\n\t\tcase 0:\n\t\t\tlval = treeRef->triRef[facetIndices[l]].AxisMidPointX(treeRef->vertexRef);\n\t\t\trval = treeRef->triRef[facetIndices[r]].AxisMidPointX(treeRef->vertexRef);\n\t\t\twhile (l < r) {\n\t\t\t\twhile (lval < axis_avg.x && l != r) {\n\t\t\t\t\tlval = treeRef->triRef[facetIndices[++l]].AxisMidPointX(treeRef->vertexRef);\n\t\t\t\t}\n\t\t\t\twhile (rval >= axis_avg.x && r != l) {\n\t\t\t\t\trval = treeRef->triRef[facetIndices[--r]].AxisMidPointX(treeRef->vertexRef);\n\t\t\t\t}\n\t\t\t\tmoreStart = r;\n\t\t\t\tif (r == l) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tstd::swap(facetIndices[l], facetIndices[r]);\n\t\t\t\tlval = treeRef->triRef[facetIndices[++l]].AxisMidPointX(treeRef->vertexRef);\n\t\t\t\trval = treeRef->triRef[facetIndices[--r]].AxisMidPointX(treeRef->vertexRef);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tlval = treeRef->triRef[facetIndices[l]].AxisMidPointY(treeRef->vertexRef);\n\t\t\trval = treeRef->triRef[facetIndices[r]].AxisMidPointY(treeRef->vertexRef);\n\t\t\twhile (l < r) {\n\t\t\t\twhile (lval < axis_avg.y && l != r) {\n\t\t\t\t\tlval = treeRef->triRef[facetIndices[++l]].AxisMidPointY(treeRef->vertexRef);\n\t\t\t\t}\n\t\t\t\twhile (rval >= axis_avg.y && r != l) {\n\t\t\t\t\trval = treeRef->triRef[facetIndices[--r]].AxisMidPointY(treeRef->vertexRef);\n\t\t\t\t}\n\t\t\t\tmoreStart = r;\n\t\t\t\tif (r == l) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tstd::swap(facetIndices[l], facetIndices[r]);\n\t\t\t\tlval = treeRef->triRef[facetIndices[++l]].AxisMidPointY(treeRef->vertexRef);\n\t\t\t\trval = treeRef->triRef[facetIndices[--r]].AxisMidPointY(treeRef->vertexRef);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tlval = treeRef->triRef[facetIndices[l]].AxisMidPointZ(treeRef->vertexRef);\n\t\t\trval = treeRef->triRef[facetIndices[r]].AxisMidPointZ(treeRef->vertexRef);\n\t\t\twhile (l < r) {\n\t\t\t\twhile (lval < axis_avg.z && l != r) {\n\t\t\t\t\tlval = treeRef->triRef[facetIndices[++l]].AxisMidPointZ(treeRef->vertexRef);\n\t\t\t\t}\n\t\t\t\twhile (rval >= axis_avg.z && r != l) {\n\t\t\t\t\trval = treeRef->triRef[facetIndices[--r]].AxisMidPointZ(treeRef->vertexRef);\n\t\t\t\t}\n\t\t\t\tmoreStart = r;\n\t\t\t\tif (r == l)\n\t\t\t\t\tbreak;\n\n\t\t\t\tstd::swap(facetIndices[l], facetIndices[r]);\n\t\t\t\tlval = treeRef->triRef[facetIndices[++l]].AxisMidPointZ(treeRef->vertexRef);\n\t\t\t\trval = treeRef->triRef[facetIndices[--r]].AxisMidPointZ(treeRef->vertexRef);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\tif (moreStart == start)\n\t\tmoreStart = (end + start) / 2;\n\n\tP = std::make_unique<AABBTreeNode>(facetIndices, moreStart, end, treeRef, this, depth + 1);\n\tN = std::make_unique<AABBTreeNode>(facetIndices, start, moreStart - 1, treeRef, this, depth + 1);\n}\n\nAABBTree::AABBTreeNode::AABBTreeNode(std::vector<uint32_t>& facetIndices, AABBTree* treeRef, AABBTreeNode* parentRef, const uint32_t depth) {\n\tVector3 axis_avg;\n\ttree = treeRef;\n\tparent = parentRef;\n\n\t// Force a leaf if the facet count gets below a certain threshold or the depth becomes too large.\n\tif (facetIndices.size() <= treeRef->MinFacets() || depth > treeRef->MaxDepth()) {\n\t\ttreeRef->CalcAABBandGeoAvg(facetIndices, mBB, axis_avg);\n\t\tnFacets = static_cast<uint32_t>(facetIndices.size());\n\t\tmIFacets = std::make_unique<uint32_t[]>(nFacets);\n\t\tfor (uint32_t f = 0; f < nFacets; f++)\n\t\t\tmIFacets[f] = facetIndices[f];\n\n\t\treturn;\n\t}\n\n\t// less and more indx lists\n\tstd::vector<uint32_t> less;\n\tstd::vector<uint32_t> more;\n\n\t// calculate this node's containing AABB and the geometric average\n\ttreeRef->CalcAABBandGeoAvg(facetIndices, mBB, axis_avg);\n\n\t// determine split axis\n\tVector3 diag = mBB.max - mBB.min;\n\tuint32_t axis = 0;\n\tfloat curmax = diag.x;\n\tif (diag.y > curmax) {\n\t\taxis = 1;\n\t\tcurmax = diag.y;\n\t}\n\n\tif (diag.z > curmax)\n\t\taxis = 2;\n\n\tint facetnum;\n\tswitch (axis) {\n\t\tcase 0:\n\t\t\tfor (uint32_t i = 0; i < static_cast<uint32_t>(facetIndices.size()); i++) {\n\t\t\t\tfacetnum = facetIndices[i];\n\t\t\t\tif (treeRef->triRef[facetnum].AxisMidPointX(treeRef->vertexRef) < axis_avg.x) {\n\t\t\t\t\tless.push_back(facetnum);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tmore.push_back(facetnum);\n\t\t\t}\n\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tfor (uint32_t i = 0; i < static_cast<uint32_t>(facetIndices.size()); i++) {\n\t\t\t\tfacetnum = facetIndices[i];\n\t\t\t\tif (treeRef->triRef[facetnum].AxisMidPointY(treeRef->vertexRef) < axis_avg.y) {\n\t\t\t\t\tless.push_back(facetnum);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tmore.push_back(facetnum);\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tfor (uint32_t i = 0; i < static_cast<uint32_t>(facetIndices.size()); i++) {\n\t\t\t\tfacetnum = facetIndices[i];\n\t\t\t\tif (treeRef->triRef[facetnum].AxisMidPointZ(treeRef->vertexRef) < axis_avg.z) {\n\t\t\t\t\tless.push_back(facetnum);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tmore.push_back(facetnum);\n\t\t\t}\n\t\t\tbreak;\n\t}\n\n\t//  Split lists when all midpoints fall on one side of axis or the other\n\tuint32_t sz = static_cast<uint32_t>(more.size());\n\tuint32_t numFacets = static_cast<uint32_t>(facetIndices.size());\n\tif (sz == 0 || sz == numFacets) {\n\t\tif (sz > less.size()) {\n\t\t\tsz = sz / 2;\n\t\t\tless.assign(more.begin(), more.begin() + sz);\n\t\t\tmore.erase(more.begin(), more.begin() + sz);\n\t\t}\n\t\telse {\n\t\t\tsz = static_cast<uint32_t>(less.size() / 2);\n\t\t\tmore.assign(less.begin(), less.begin() + sz);\n\t\t\tless.erase(less.begin(), less.begin() + sz);\n\t\t}\n\t}\n\n\tP = std::make_unique<AABBTreeNode>(more, treeRef, this, depth + 1);\n\tN = std::make_unique<AABBTreeNode>(less, treeRef, this, depth + 1);\n}\n\nVector3 AABBTree::AABBTreeNode::Center() {\n\treturn ((mBB.max + mBB.min) / 2);\n}\n\nvoid AABBTree::AABBTreeNode::AddDebugFrames(std::vector<Vector3>& verts, std::vector<Edge>& edges, const uint32_t maxdepth, const uint32_t curdepth) {\n\tif (curdepth <= maxdepth) {\n\t\tmBB.AddBoxToMesh(verts, edges);\n\t} // else return;\n\n\tif (P)\n\t\tP->AddDebugFrames(verts, edges, maxdepth, curdepth + 1);\n\tif (N)\n\t\tN->AddDebugFrames(verts, edges, maxdepth, curdepth + 1);\n}\n\nvoid AABBTree::AABBTreeNode::AddRayIntersectFrames(Vector3& origin, Vector3& direction, std::vector<Vector3>& verts, std::vector<Edge>& edges) {\n\tbool collision = mBB.IntersectRay(origin, direction, nullptr);\n\tif (collision)\n\t\tmBB.AddBoxToMesh(verts, edges);\n\telse\n\t\treturn;\n\n\tif (P)\n\t\tP->AddRayIntersectFrames(origin, direction, verts, edges);\n\tif (N)\n\t\tN->AddRayIntersectFrames(origin, direction, verts, edges);\n}\n\nbool AABBTree::AABBTreeNode::IntersectRay(Vector3& origin, Vector3& direction, std::vector<IntersectResult>* results) {\n\tIntersectResult r;\n\tbool collision = mBB.IntersectRay(origin, direction, nullptr);\n\tif (!collision)\n\t\treturn false;\n\n\tif (!P && !N) {\n\t\tfor (uint32_t i = 0; i < nFacets; i++) {\n\t\t\tuint32_t f = mIFacets[i];\n\t\t\tif (tree->triRef[f].IntersectRay(tree->vertexRef, origin, direction, &r.HitDistance, &r.HitCoord)) {\n\t\t\t\tif (results) {\n\t\t\t\t\tr.HitFacet = mIFacets[i];\n\t\t\t\t\tr.bvhNode = this;\n\t\t\t\t\tresults->push_back(r);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tbool Pcollide = false;\n\tbool Ncollide = false;\n\tif (P)\n\t\tPcollide = P->IntersectRay(origin, direction, results);\n\n\tif (N)\n\t\tNcollide = N->IntersectRay(origin, direction, results);\n\n\treturn Pcollide || Ncollide;\n}\n\nbool AABBTree::AABBTreeNode::IntersectSphere(Vector3& origin, const float radius, std::vector<IntersectResult>* results) {\n\tIntersectResult r;\n\tbool collision = mBB.IntersectSphere(origin, radius);\n\tif (!collision)\n\t\treturn false;\n\n\tif (!P && !N) {\n\t\tbool found = false;\n\t\tfor (uint32_t i = 0; i < nFacets; i++) {\n\t\t\tuint32_t f = mIFacets[i];\n\t\t\tfloat dist = tree->triRef[f].DistanceToPoint(tree->vertexRef, origin);\n\t\t\tif (dist <= radius) {\n\t\t\t\tif (results) {\n\t\t\t\t\tr.HitDistance = dist;\n\t\t\t\t\tr.HitFacet = mIFacets[i];\n\t\t\t\t\tr.bvhNode = this;\n\t\t\t\t\tresults->push_back(r);\n\t\t\t\t\tfound = true;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn found;\n\t}\n\n\tbool Pcollide = false;\n\tbool Ncollide = false;\n\tif (P)\n\t\tPcollide = P->IntersectSphere(origin, radius, results);\n\tif (N)\n\t\tNcollide = N->IntersectSphere(origin, radius, results);\n\n\treturn Pcollide || Ncollide;\n}\n\nvoid AABBTree::AABBTreeNode::UpdateAABB(const AABB* childBB) {\n\tif (!childBB) {\n\t\tif (nFacets > 0) {\n\t\t\tVector3 bogus;\n\t\t\ttree->CalcAABBandGeoAvg(mIFacets.get(), 0, nFacets - 1, mBB, bogus);\n\t\t}\n\t}\n\telse\n\t\tmBB.Merge((*childBB));\n\n\tif (parent)\n\t\tparent->UpdateAABB(&mBB);\n}\n\nAABBTree::AABBTree(Vector3* vertices, Triangle* facets, const uint32_t nFacets, const uint32_t maxDepth, const uint32_t minFacets) {\n\ttriRef = facets;\n\tvertexRef = vertices;\n\tmax_depth = maxDepth;\n\tmin_facets = minFacets;\n\n\tstd::vector<uint32_t> facetIndices(nFacets, 0);\n\tfor (uint32_t i = 0; i < nFacets; i++)\n\t\tfacetIndices[i] = i;\n\n\tuint32_t start = 0;\n\tuint32_t depth = 0;\n\troot = std::make_unique<AABBTreeNode>(facetIndices, start, nFacets - 1, this, nullptr, depth);\n}\n\nuint32_t AABBTree::MinFacets() {\n\treturn min_facets;\n}\nuint32_t AABBTree::MaxDepth() {\n\treturn max_depth;\n}\n\nVector3 AABBTree::Center() {\n\treturn root->Center();\n}\n\nvoid AABBTree::CalcAABBandGeoAvg(std::vector<uint32_t>& forFacets, AABB& outBB, Vector3& outAxisAvg) {\n\tif (forFacets.empty())\n\t\treturn;\n\n\toutAxisAvg = Vector3(0.0f, 0.0f, 0.0f);\n\n\tVector3 mid;\n\tAABB tmpBB(vertexRef, (uint16_t*)(&triRef[forFacets[0]]), 3);\n\n\tuint32_t forFacetsSize = static_cast<uint32_t>(forFacets.size());\n\tfor (uint32_t i = 0; i < forFacetsSize; i++) {\n\t\ttriRef[forFacets[i]].midpoint(vertexRef, mid);\n\t\toutAxisAvg += (mid / forFacetsSize);\n\t\ttmpBB.Merge(vertexRef, (uint16_t*)&triRef[forFacets[i]], 3);\n\t}\n\toutBB = tmpBB;\n}\n\nvoid AABBTree::CalcAABBandGeoAvg(std::vector<uint32_t>& forFacets, const uint32_t start, const uint32_t end, AABB& outBB, Vector3& outAxisAvg) {\n\tif (forFacets.empty())\n\t\treturn;\n\n\tVector3 mid;\n\t//float ytot = 0;\n\t//float yaxis = 0;\n\toutAxisAvg = Vector3(0.0f, 0.0f, 0.0f);\n\n\tAABB tmpBB(vertexRef, (uint16_t*)(&triRef[forFacets[start]]), 3);\n\tuint32_t fcount = end - start + 1;\n\tfor (uint32_t i = start; i <= end; i++) {\n\t\ttriRef[forFacets[i]].midpoint(vertexRef, mid);\n\t\toutAxisAvg.x += mid.x;\n\t\toutAxisAvg.y += mid.y;\n\t\toutAxisAvg.z += mid.z;\n\t\ttmpBB.Merge(vertexRef, (uint16_t*)&triRef[forFacets[i]], 3);\n\t}\n\n\toutAxisAvg /= fcount;\n\toutBB = tmpBB;\n}\n\nvoid AABBTree::CalcAABBandGeoAvg(const uint32_t forFacets[], const uint32_t start, const uint32_t end, AABB& outBB, Vector3& outAxisAvg) {\n\tVector3 mid;\n\t//float ytot = 0;\n\t//float yaxis = 0;\n\toutAxisAvg = Vector3(0.0f, 0.0f, 0.0f);\n\n\tAABB tmpBB(vertexRef, (uint16_t*)(&triRef[forFacets[start]]), 3);\n\tuint32_t fcount = end - start + 1;\n\tfor (uint32_t i = start; i <= end; i++) {\n\t\ttriRef[forFacets[i]].midpoint(vertexRef, mid);\n\t\toutAxisAvg.x += mid.x;\n\t\toutAxisAvg.y += mid.y;\n\t\toutAxisAvg.z += mid.z;\n\t\ttmpBB.Merge(vertexRef, (uint16_t*)&triRef[forFacets[i]], 3);\n\t}\n\toutAxisAvg /= fcount;\n\toutBB = tmpBB;\n}\n\nvoid AABBTree::BuildDebugFrames(Vector3** outVerts, uint16_t* outNumVerts, Edge** outEdges, uint32_t* outNumEdges) {\n\tstd::vector<Vector3> v;\n\tstd::vector<Edge> e;\n\n\troot->AddDebugFrames(v, e, 8);\n\n\t//\tm->rendermode = 1;\n\t//\tm->color = Vector3(0,.2,0);\n\t//\tm->nVerts =  v.size();\n\t//\tm->verts = new Vector3[m->nVerts];\n\n\t//\tm->nEdges = e.size();\n\t//\tm->edges = new Edge[m->nEdges];\n\n\tauto vc = static_cast<uint16_t>(v.size());\n\t(*outNumVerts) = vc;\n\t(*outVerts) = new Vector3[vc];\n\n\tauto ec = static_cast<uint32_t>(e.size());\n\t(*outNumEdges) = ec;\n\t(*outEdges) = new Edge[ec];\n\n\tfor (uint16_t i = 0; i < vc; i++) {\n\t\t//m->verts[i] = v[i];\n\t\t(*outVerts)[i] = v[i];\n\t}\n\n\tfor (uint32_t i = 0; i < ec; i++) {\n\t\t//m->edges[i].p1 = e[i].p1;\n\t\t//m->edges[i].p2 = e[i].p2;\n\t\t(*outEdges)[i].p1 = e[i].p1;\n\t\t(*outEdges)[i].p2 = e[i].p2;\n\t}\n}\n\nvoid AABBTree::BuildRayIntersectFrames(Vector3& origin, Vector3& direction, Vector3** outVerts, uint16_t* outNumVerts, Edge** outEdges, uint32_t* outNumEdges) {\n\tstd::vector<Vector3> v;\n\tstd::vector<Edge> e;\n\tbFlag = false;\n\troot->AddRayIntersectFrames(origin, direction, v, e);\n\n\t//m->rendermode = 1;\n\t//m->color = Vector3(.8,.8,0);\n\t//\n\t//m->nVerts =  v.size();\n\t//m->verts = new Vector3[m->nVerts];\n\n\t//m->nEdges = e.size();\n\t//m->edges = new Edge[m->nEdges];\n\n\t//for(int i =0 ;i< m->nVerts; i++ ){\n\t//\tm->verts[i] = v[i];\n\t//}\n\t//for(int i=0;i<m->nEdges; i++) {\n\t//\tm->edges[i].p1 = e[i].p1;\n\t//\tm->edges[i].p2 = e[i].p2;\n\t//}\n\n\tauto vc = static_cast<uint16_t>(v.size());\n\t(*outNumVerts) = vc;\n\t(*outVerts) = new Vector3[vc];\n\n\tauto ec = static_cast<uint32_t>(e.size());\n\t(*outNumEdges) = ec;\n\t(*outEdges) = new Edge[ec];\n\n\tfor (uint16_t i = 0; i < vc; i++)\n\t\t(*outVerts)[i] = v[i];\n\n\tfor (uint32_t i = 0; i < ec; i++) {\n\t\t(*outEdges)[i].p1 = e[i].p1;\n\t\t(*outEdges)[i].p2 = e[i].p2;\n\t}\n}\n\nbool AABBTree::IntersectRay(Vector3& origin, Vector3& direction, std::vector<IntersectResult>* results) {\n\treturn root->IntersectRay(origin, direction, results);\n}\n\nbool AABBTree::IntersectSphere(Vector3& origin, const float radius, std::vector<IntersectResult>* results) {\n\treturn root->IntersectSphere(origin, radius, results);\n}\n"
  },
  {
    "path": "src/utils/AABBTree.h",
    "content": "#pragma once\n\n#include \"Object3d.hpp\"\n\n#include <memory>\n\nstruct IntersectResult;\n\nstruct AABB {\n\tnifly::Vector3 min;\n\tnifly::Vector3 max;\n\n\tAABB() {}\n\tAABB(const nifly::Vector3& newMin, const nifly::Vector3& newMax);\n\n\tAABB(const nifly::Vector3* points, const uint16_t nPoints);\n\tAABB(const nifly::Vector3* points, const uint16_t* indices, const uint16_t nPoints);\n\n\tvoid AddBoxToMesh(std::vector<nifly::Vector3>& verts, std::vector<nifly::Edge>& edges);\n\n\tvoid Merge(const nifly::Vector3* points, const uint16_t* indices, const uint16_t nPoints);\n\tvoid Merge(const AABB& other);\n\n\tbool IntersectAABB(const AABB& other);\n\n\tbool IntersectRay(const nifly::Vector3& Origin, const nifly::Vector3& Direction, nifly::Vector3* outCoord);\n\n\tbool IntersectSphere(const nifly::Vector3& Origin, const float radius);\n};\n\nclass AABBTree {\n\tuint32_t max_depth = 100;\n\tuint32_t min_facets = 2;\n\tnifly::Vector3* vertexRef = nullptr;\n\tnifly::Triangle* triRef = nullptr;\n\npublic:\n\tbool bFlag = false;\n\tuint32_t depthCounter = 0;\n\tuint32_t sentinel = 0;\n\n\tclass AABBTreeNode {\n\t\tstd::unique_ptr<AABBTreeNode> N;\n\t\tstd::unique_ptr<AABBTreeNode> P;\n\t\tAABBTreeNode* parent = nullptr;\n\t\tAABB mBB;\n\t\tAABBTree* tree = nullptr;\n\t\tstd::unique_ptr<uint32_t[]> mIFacets;\n\t\tuint32_t nFacets = 0;\n\n\tpublic:\n\t\tAABBTreeNode() {}\n\n\t\t// Recursively generates AABB Tree nodes using the referenced data.\n\t\tAABBTreeNode(std::vector<uint32_t>& facetIndices, AABBTree* treeRef, AABBTreeNode* parentRef, const uint32_t depth);\n\n\t\t// As above, but facetIndices is modified with in-place sorting rather than using vector::push_back to generate sub lists.\n\t\t// Sorting swaps from front of list to end when pos midpoints are found at the beginning of the list.\n\t\tAABBTreeNode(std::vector<uint32_t>& facetIndices, const uint32_t start, const uint32_t end, AABBTree* treeRef, AABBTreeNode* parentRef, const uint32_t depth);\n\n\t\tnifly::Vector3 Center();\n\n\t\tvoid AddDebugFrames(std::vector<nifly::Vector3>& verts, std::vector<nifly::Edge>& edges, const uint32_t maxdepth = 0, const uint32_t curdepth = 0);\n\t\tvoid AddRayIntersectFrames(nifly::Vector3& origin, nifly::Vector3& direction, std::vector<nifly::Vector3>& verts, std::vector<nifly::Edge>& edges);\n\t\tbool IntersectRay(nifly::Vector3& origin, nifly::Vector3& direction, std::vector<IntersectResult>* results);\n\t\tbool IntersectSphere(nifly::Vector3& origin, const float radius, std::vector<IntersectResult>* results);\n\t\tvoid UpdateAABB(const AABB* childBB = nullptr);\n\t};\n\n\tstd::unique_ptr<AABBTreeNode> root;\n\npublic:\n\tAABBTree() {}\n\tAABBTree(nifly::Vector3* vertices, nifly::Triangle* facets, const uint32_t nFacets, const uint32_t maxDepth, const uint32_t minFacets);\n\n\tuint32_t MinFacets();\n\tuint32_t MaxDepth();\n\n\tnifly::Vector3 Center();\n\n\t// Calculate bounding box and geometric average.\n\tvoid CalcAABBandGeoAvg(std::vector<uint32_t>& forFacets, AABB& outBB, nifly::Vector3& outAxisAvg);\n\n\t// Calculate bounding box and geometric average for sub list.\n\tvoid CalcAABBandGeoAvg(std::vector<uint32_t>& forFacets, const uint32_t start, const uint32_t end, AABB& outBB, nifly::Vector3& outAxisAvg);\n\tvoid CalcAABBandGeoAvg(const uint32_t forFacets[], const uint32_t start, const uint32_t end, AABB& outBB, nifly::Vector3& outAxisAvg);\n\tvoid BuildDebugFrames(nifly::Vector3** outVerts, uint16_t* outNumVerts, nifly::Edge** outEdges, uint32_t* outNumEdges);\n\tvoid BuildRayIntersectFrames(nifly::Vector3& origin, nifly::Vector3& direction, nifly::Vector3** outVerts, uint16_t* outNumVerts, nifly::Edge** outEdges, uint32_t* outNumEdges);\n\tbool IntersectRay(nifly::Vector3& origin, nifly::Vector3& direction, std::vector<IntersectResult>* results = nullptr);\n\tbool IntersectSphere(nifly::Vector3& origin, const float radius, std::vector<IntersectResult>* results = nullptr);\n};\n\nstruct IntersectResult {\n\tuint32_t HitFacet = 0;\n\tfloat HitDistance = 0.0f;\n\tnifly::Vector3 HitCoord;\n\tAABBTree::AABBTreeNode* bvhNode = nullptr;\n};\n"
  },
  {
    "path": "src/utils/ConfigDialogUtil.h",
    "content": "#pragma once\n#include \"../components/RefTemplates.h\"\n#include \"ConfigDialogUtil.h\"\n#include <type_traits>\n#include <vector>\n\n#include \"ConfigurationManager.h\"\n#include <wx/checkbox.h>\n#include <wx/choice.h>\n#include <wx/dialog.h>\n#include <wx/textctrl.h>\n#include <wx/xrc/xmlres.h>\n\nnamespace ConfigDialogUtil {\ninline std::string GetConfigKey(const char* configPrefix, const char* dlgProperty) {\n\tstd::string configKey = configPrefix;\n\tconfigKey += \"_\";\n\tconfigKey += dlgProperty;\n\treturn configKey;\n}\n\ninline void LoadDialogChoice(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\twxChoice* choice = XRCCTRL(dlg, dlgProperty, wxChoice);\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconst std::string& lastValue = configManager[configKey];\n\tif (!choice->SetStringSelection(wxString::FromUTF8(lastValue))) {\n\t\tif (choice->GetSelection() < 0)\n\t\t\tchoice->Select(0);\n\t}\n}\n\ninline void LoadDialogChoiceIndex(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\twxChoice* choice = XRCCTRL(dlg, dlgProperty, wxChoice);\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tint lastSel = configManager.GetIntValue(configKey, choice->GetSelection());\n\tchoice->SetSelection(lastSel);\n}\n\ntemplate<typename T, std::enable_if_t<std::is_base_of_v<NamedValue, T>, bool> = true>\nvoid LoadDialogChoices(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty, const std::vector<T> possibleChoices) {\n\twxChoice* choice = XRCCTRL(dlg, dlgProperty, wxChoice);\n\tfor (auto& entry : possibleChoices)\n\t\tchoice->Append(entry.GetName());\n\n\tLoadDialogChoice(configManager, dlg, configPrefix, dlgProperty);\n}\n\ninline void LoadDialogText(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\twxTextCtrl* textCtrl = XRCCTRL(dlg, dlgProperty, wxTextCtrl);\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tif (configManager.Exists(configKey)) {\n\t\tstd::string lastValue = configManager[configKey];\n\t\ttextCtrl->SetValue(lastValue);\n\t}\n}\n\ninline void LoadDialogTextInteger(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\twxTextCtrl* textCtrl = XRCCTRL(dlg, dlgProperty, wxTextCtrl);\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tif (configManager.Exists(configKey)) {\n\t\tint lastValue = configManager.GetIntValue(configKey);\n\t\ttextCtrl->SetValue(wxString::Format(\"%d\", lastValue));\n\t}\n}\n\ninline void LoadDialogTextFloat(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\twxTextCtrl* textCtrl = XRCCTRL(dlg, dlgProperty, wxTextCtrl);\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tif (configManager.Exists(configKey)) {\n\t\tfloat lastValue = configManager.GetFloatValue(configKey);\n\t\ttextCtrl->SetValue(wxString::Format(\"%f\", lastValue));\n\t}\n}\n\ninline void LoadDialogCheckBox(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\twxCheckBox* check = XRCCTRL(dlg, dlgProperty, wxCheckBox);\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tbool lastValue = configManager.GetBoolValue(configKey, check->GetValue());\n\tcheck->SetValue(lastValue);\n}\n\ninline bool SetBoolFromDialogCheckbox(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\tconst bool value = (XRCCTRL(dlg, dlgProperty, wxCheckBox)->IsChecked());\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconfigManager.SetBoolValue(configKey, value);\n\treturn value;\n}\n\ninline int SetIntegerFromDialogChoice(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\tint sel = XRCCTRL(dlg, dlgProperty, wxChoice)->GetSelection();\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconfigManager.SetValue(configKey, sel);\n\treturn sel;\n}\n\ninline wxString SetStringFromDialogChoice(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\tconst wxString str = XRCCTRL(dlg, dlgProperty, wxChoice)->GetStringSelection();\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconfigManager.SetValue(configKey, str.ToStdString());\n\treturn str;\n}\n\ninline int SetIntegerFromDialogTextControl(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\tint val = std::atoi(XRCCTRL(dlg, dlgProperty, wxTextCtrl)->GetValue().c_str());\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconfigManager.SetValue(configKey, val);\n\treturn val;\n}\n\ninline float SetFloatFromDialogTextControl(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\tfloat val = std::atof(XRCCTRL(dlg, dlgProperty, wxTextCtrl)->GetValue().c_str());\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconfigManager.SetValue(configKey, val);\n\treturn val;\n}\n\ninline wxString SetStringFromDialogTextControl(ConfigurationManager& configManager, const wxDialog& dlg, const char* configPrefix, const char* dlgProperty) {\n\tconst wxString str = XRCCTRL(dlg, dlgProperty, wxTextCtrl)->GetValue();\n\n\tstd::string configKey = GetConfigKey(configPrefix, dlgProperty);\n\tconfigManager.SetValue(configKey, str.ToStdString());\n\treturn str;\n}\n}; // namespace ConfigDialogUtil\n"
  },
  {
    "path": "src/utils/ConfigurationManager.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"ConfigurationManager.h\"\n#include \"../utils/PlatformUtil.h\"\n#include \"../utils/StringStuff.h\"\n\nConfigurationItem::~ConfigurationItem() {\n\tfor (auto& it : properties)\n\t\tdelete it;\n\n\tfor (auto& it : children)\n\t\tdelete it;\n\n\tproperties.clear();\n\tchildren.clear();\n}\n\nint ConfigurationItem::SettingFromXML(XMLElement* xml) {\n\tname = xml->Value();\n\tif (parent) {\n\t\tpath = parent->path + \"/\";\n\t\tpath += name;\n\t}\n\telse {\n\t\tlevel = 0;\n\t\tpath = name;\n\t}\n\tif (xml->GetText() != nullptr)\n\t\tvalue = xml->GetText();\n\n\tconst XMLAttribute* attr = xml->FirstAttribute();\n\twhile (attr) {\n\t\tConfigurationItem* newCI = new ConfigurationItem();\n\t\tnewCI->parent = this;\n\t\tnewCI->level = level + 1;\n\t\tnewCI->isProp = true;\n\t\tnewCI->name = attr->Name();\n\t\tnewCI->value = attr->Value();\n\t\tnewCI->path = path + \".\";\n\t\tnewCI->path += newCI->name;\n\t\tproperties.push_back(newCI);\n\n\t\tattr = attr->Next();\n\t}\n\n\tXMLNode* child = xml->FirstChild();\n\twhile (child) {\n\t\tif (child->ToComment())\n\t\t\tchildren.push_back(new ConfigurationItem(child->ToComment()->Value(), this, level + 1));\n\t\telse if (child->ToElement())\n\t\t\tchildren.push_back(new ConfigurationItem(child->ToElement(), this, level + 1));\n\t\tchild = child->NextSibling();\n\t}\n\n\treturn 0;\n}\n\nvoid ConfigurationItem::ToXML(XMLElement* elem) {\n\tXMLElement* newElement = elem->GetDocument()->NewElement(name.c_str());\n\tXMLElement* element = elem->InsertEndChild(newElement)->ToElement();\n\n\tfor (auto& prop : properties) {\n\t\tif (prop->isDefault)\n\t\t\tcontinue;\n\t\telement->SetAttribute(prop->name.c_str(), prop->value.c_str());\n\t}\n\tfor (auto& child : children) {\n\t\tif (child->isDefault)\n\t\t\tcontinue;\n\t\tif (child->isComment) {\n\t\t\tXMLComment* newComment = elem->GetDocument()->NewComment(child->value.c_str());\n\t\t\telement->InsertEndChild(newComment);\n\t\t}\n\t\telse\n\t\t\tchild->ToXML(element);\n\t}\n\n\tif (children.empty() || !value.empty()) {\n\t\tXMLText* newText = elem->GetDocument()->NewText(value.c_str());\n\t\telement->InsertEndChild(newText);\n\t}\n}\n\nint ConfigurationItem::EnumerateProperties(std::vector<ConfigurationItem*>& outList) {\n\tint count = 0;\n\tfor (auto& prop : properties) {\n\t\tcount++;\n\t\toutList.push_back(prop);\n\t}\n\treturn count;\n}\n\nint ConfigurationItem::EnumerateProperties(std::string& outList) {\n\tint count = 0;\n\toutList.clear();\n\n\tfor (auto& prop : properties) {\n\t\tcount++;\n\t\toutList += prop->name + \"=\\\"\" + prop->value + \"\\\" \";\n\t}\n\n\treturn count;\n}\n\nint ConfigurationItem::EnumerateChildren(std::vector<ConfigurationItem*>& outList, bool withProperties, bool traverse) {\n\tint count = 0;\n\tfor (auto& child : children) {\n\t\tif (child->isComment)\n\t\t\tcontinue;\n\n\t\tcount++;\n\t\toutList.push_back(child);\n\t\tif (traverse) {\n\t\t\tif (withProperties)\n\t\t\t\tcount += child->EnumerateProperties(outList);\n\t\t\tcount += child->EnumerateChildren(outList, withProperties, traverse);\n\t\t}\n\t}\n\treturn count;\n}\n\nint ConfigurationItem::EnumerateChildren(const std::string& inName, std::vector<std::string>& outList) {\n\tfor (auto& child : children) {\n\t\tif (child->isComment)\n\t\t\tcontinue;\n\t\tif (child->Match(inName))\n\t\t\toutList.push_back(child->value);\n\t}\n\treturn outList.size();\n}\n\nint ConfigurationItem::EnumerateChildrenProperty(const std::string& inName, const std::string& propertyName, std::vector<std::string>& outList) {\n\tfor (auto& child : children) {\n\t\tif (child->isComment)\n\t\t\tcontinue;\n\n\t\tif (child->Match(inName)) {\n\t\t\tConfigurationItem* prop = child->FindProperty(propertyName);\n\t\t\tif (prop)\n\t\t\t\toutList.push_back(prop->value);\n\t\t}\n\t}\n\treturn outList.size();\n}\n\nConfigurationItem* ConfigurationItem::FindChild(const std::string& inName, bool recurse) {\n\tConfigurationItem* found = nullptr;\n\tsize_t pos = inName.find_first_of(\"/.\");\n\n\tif (pos != std::string::npos) {\n\t\tstd::string tmpName = inName.substr(0, pos);\n\t\tfor (auto& child : children) {\n\t\t\tif (child->isComment)\n\t\t\t\tcontinue;\n\t\t\tif (child->Match(tmpName))\n\t\t\t\tfound = child;\n\t\t}\n\n\t\tif (!found)\n\t\t\treturn nullptr;\n\t\telse if (!recurse)\n\t\t\treturn found;\n\n\t\tif (inName.at(pos) == '/')\n\t\t\tfound = found->FindChild(inName.substr(pos + 1));\n\t\telse if (inName.at(pos) == '.')\n\t\t\tfound = found->FindProperty(inName.substr(pos + 1));\n\n\t\tif (!found)\n\t\t\treturn nullptr;\n\t}\n\telse {\n\t\tfor (auto& child : children) {\n\t\t\tif (child->isComment)\n\t\t\t\tcontinue;\n\t\t\tif (child->Match(inName))\n\t\t\t\tfound = child;\n\t\t}\n\t}\n\n\t// return nullptr if nothing was found\n\treturn found;\n}\n\nConfigurationItem* ConfigurationItem::AddChild(const std::string& inName, const std::string& val, bool isElement, bool forceAdd) {\n\tConfigurationItem* found = nullptr;\n\tint pos = inName.find_first_of(\"/.\");\n\tstd::string tmpName = inName.substr(0, pos);\n\n\tif (!forceAdd) {\n\t\tfor (auto& child : children) {\n\t\t\tif (child->isComment)\n\t\t\t\tcontinue;\n\t\t\tif (child->Match(tmpName))\n\t\t\t\tfound = child;\n\t\t}\n\t}\n\n\tif (!found) {\n\t\tauto newCI = new ConfigurationItem();\n\t\tnewCI->name = inName.substr(0, pos);\n\t\tnewCI->parent = this;\n\n\t\tif (isElement)\n\t\t\tnewCI->path = path + \"/\" + newCI->name;\n\t\telse\n\t\t\tnewCI->path = path + \".\" + newCI->name;\n\n\t\tnewCI->level = level + 1;\n\t\tif (pos == -1) {\n\t\t\tnewCI->value = val;\n\t\t\tfound = newCI;\n\t\t}\n\t\telse if (inName.at(pos) == '/') {\n\t\t\tfound = newCI->AddChild(inName.substr(pos + 1), val, true, forceAdd);\n\t\t}\n\t\telse if (inName.at(pos) == '.')\n\t\t\tfound = newCI->AddChild(inName.substr(pos + 1), val, false);\n\n\t\tif (isElement)\n\t\t\tchildren.push_back(newCI);\n\t\telse\n\t\t\tproperties.push_back(newCI);\n\t}\n\telse {\n\t\tif (pos == -1)\n\t\t\treturn nullptr;\n\t\telse if (inName.at(pos) == '/')\n\t\t\tfound = found->AddChild(inName.substr(pos + 1), val, true, forceAdd);\n\t\telse if (inName.at(pos) == '.')\n\t\t\tfound = found->AddChild(inName.substr(pos + 1), val, false);\n\t}\n\n\treturn found;\n}\n\nvoid ConfigurationItem::DeleteChild(ConfigurationItem* child) {\n\tif (!child)\n\t\treturn;\n\n\tfor (auto& p : child->properties)\n\t\tDeleteChild(p);\n\n\tchild->properties.clear();\n\n\tfor (auto& c : child->children)\n\t\tDeleteChild(c);\n\n\tchild->children.clear();\n\tdelete child;\n}\n\nConfigurationItem* ConfigurationItem::FindProperty(const std::string& inName) {\n\tfor (auto& prop : properties)\n\t\tif (prop->Match(inName))\n\t\t\treturn prop;\n\n\treturn nullptr;\n}\n\nvoid ConfigurationItem::ClearArrayChildren(const std::string& arrayName) {\n\tauto removeIt = std::remove_if(children.begin(), children.end(), [&](ConfigurationItem* child) { return child->Match(arrayName); });\n\n\tfor (auto it = removeIt; it != children.end(); it++)\n\t\tDeleteChild((*it));\n\n\tchildren.erase(removeIt, children.end());\n}\n\nConfigurationManager::ConfigurationManager() {}\n\nConfigurationManager::~ConfigurationManager() {\n\tClear();\n}\n\nvoid ConfigurationManager::Clear() {\n\tfor (auto& ci : ciList)\n\t\tdelete ci;\n\n\tciList.clear();\n}\n\nint ConfigurationManager::LoadConfig(const std::string& pathToFile, const std::string& rootElement) {\n\tint error = 0;\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(pathToFile);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"rb\");\n\tif (error || !fp)\n\t\treturn 1;\n#else\n\tfp = fopen(pathToFile.c_str(), \"rb\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn 1;\n\t}\n#endif\n\n\tXMLDocument doc;\n\terror = doc.LoadFile(fp);\n\tfclose(fp);\n\n\tif (error)\n\t\treturn 2;\n\n\tClear();\n\n\tXMLElement* root = doc.FirstChildElement(rootElement.c_str());\n\tif (!root)\n\t\treturn 3;\n\n\tXMLNode* child = root->FirstChild();\n\twhile (child) {\n\t\tif (child->ToComment())\n\t\t\tciList.push_back(new ConfigurationItem(child->ToComment()->Value(), 0, 0));\n\t\telse if (child->ToElement())\n\t\t\tciList.push_back(new ConfigurationItem(child->ToElement()));\n\n\t\tchild = child->NextSibling();\n\t}\n\n\treturn 0;\n}\n\nint ConfigurationManager::EnumerateCIs(std::vector<ConfigurationItem*>& outList, bool withProperties, bool traverse) {\n\tif (ciList.size() == 0)\n\t\treturn 0;\n\n\tint count = 0;\n\tfor (auto& ci : ciList) {\n\t\toutList.push_back(ci);\n\t\tcount++;\n\t\tif (traverse) {\n\t\t\tif (withProperties)\n\t\t\t\tcount += ci->EnumerateProperties(outList);\n\t\t\tcount += ci->EnumerateChildren(outList, withProperties, traverse);\n\t\t}\n\t}\n\treturn count;\n}\n\nint ConfigurationManager::EnumerateChildCIs(std::vector<ConfigurationItem*>& outList, const std::string& parentCI, bool withProperties, bool traverse) {\n\tConfigurationItem* ci = FindCI(parentCI);\n\tif (!ci)\n\t\treturn 0;\n\n\treturn ci->EnumerateChildren(outList, withProperties, traverse);\n}\n\nbool ConfigurationManager::Exists(const std::string& name) {\n\tConfigurationItem* itemFound = FindCI(name);\n\tif (itemFound)\n\t\treturn true;\n\telse\n\t\treturn false;\n}\n\nConfigurationItem* ConfigurationManager::FindCI(const std::string& inName) {\n\tConfigurationItem* found = nullptr;\n\tint pos = inName.find_first_of(\"/.\");\n\n\tif (pos != -1) {\n\t\tstd::string tmpName = inName.substr(0, pos);\n\t\tfor (auto& ci : ciList)\n\t\t\tif (ci->Match(tmpName))\n\t\t\t\tfound = ci;\n\n\t\tif (!found)\n\t\t\treturn nullptr;\n\n\t\tif (inName.at(pos) == '/')\n\t\t\tfound = found->FindChild(inName.substr(pos + 1));\n\t\telse if (inName.at(pos) == '.')\n\t\t\tfound = found->FindProperty(inName.substr(pos + 1));\n\n\t\tif (!found)\n\t\t\treturn nullptr;\n\t}\n\telse\n\t\tfor (auto& ci : ciList)\n\t\t\tif (ci->Match(inName))\n\t\t\t\tfound = ci;\n\n\treturn found;\n}\n\nint ConfigurationManager::GetIntValue(const std::string& inName, int def) {\n\tint res = def;\n\n\tConfigurationItem* itemFound = FindCI(inName);\n\tif (itemFound)\n\t\tif (!itemFound->value.empty())\n\t\t\tres = atoi(itemFound->value.c_str());\n\n\treturn res;\n}\n\nfloat ConfigurationManager::GetFloatValue(const std::string& inName, float def) {\n\tfloat res = def;\n\n\tConfigurationItem* itemFound = FindCI(inName);\n\tif (itemFound)\n\t\tif (!itemFound->value.empty())\n\t\t\tres = (float)atof(itemFound->value.c_str());\n\n\treturn res;\n}\n\nbool ConfigurationManager::GetBoolValue(const std::string& inName, bool def) {\n\tbool res = def;\n\n\tConfigurationItem* itemFound = FindCI(inName);\n\tif (itemFound) {\n\t\tif (StringsEqualNInsens(itemFound->value.c_str(), \"true\", 4))\n\t\t\tres = true;\n\t\telse if (StringsEqualNInsens(itemFound->value.c_str(), \"false\", 5))\n\t\t\tres = false;\n\t}\n\n\treturn res;\n}\n\nstd::string ConfigurationManager::GetString(const std::string& inName) {\n\tConfigurationItem* itemFound = FindCI(inName);\n\tif (itemFound)\n\t\treturn itemFound->value;\n\n\treturn \"\";\n}\n\nvoid ConfigurationManager::SetDefaultValue(const std::string& inName, const std::string& newValue) {\n\tif (FindCI(inName))\n\t\treturn;\n\n\tSetValue(inName, newValue, true);\n}\n\nvoid ConfigurationManager::SetDefaultValue(const std::string& inName, int newValue) {\n\tif (FindCI(inName))\n\t\treturn;\n\n\tSetValue(inName, newValue, true);\n}\n\nvoid ConfigurationManager::SetDefaultValue(const std::string& inName, float newValue) {\n\tif (FindCI(inName))\n\t\treturn;\n\n\tSetValue(inName, newValue, true);\n}\n\nvoid ConfigurationManager::SetDefaultBoolValue(const std::string& inName, bool newValue) {\n\tif (FindCI(inName))\n\t\treturn;\n\n\tSetBoolValue(inName, newValue, true);\n}\n\nvoid ConfigurationManager::SetValue(const std::string& inName, const std::string& newValue, bool flagDefault) {\n\tstd::string search = inName;\n\n\tConfigurationItem* itemFound = FindCI(search);\n\tif (itemFound) {\n\t\titemFound->value = newValue;\n\t\titemFound->isDefault = flagDefault;\n\t}\n\telse {\n\t\tint pos = search.find_first_of(\"/.\");\n\t\tstd::string tmpName = search.substr(0, pos);\n\t\tfor (auto& ci : ciList) {\n\t\t\tif (ci->Match(tmpName))\n\t\t\t\titemFound = ci;\n\t\t}\n\n\t\tif (!itemFound) {\n\t\t\tConfigurationItem* newCI = new ConfigurationItem();\n\t\t\tnewCI->name = tmpName;\n\t\t\tnewCI->path = tmpName;\n\t\t\tciList.push_back(newCI);\n\t\t\titemFound = newCI;\n\t\t\tif (pos == -1) {\n\t\t\t\tnewCI->value = newValue;\n\t\t\t\tnewCI->isDefault = flagDefault;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif (search.at(pos) == '/')\n\t\t\titemFound->AddChild(search.substr(pos + 1), newValue)->isDefault = flagDefault;\n\t\telse\n\t\t\titemFound->AddChild(search.substr(pos + 1), newValue, false)->isDefault = flagDefault;\n\t}\n}\n\nvoid ConfigurationManager::SetValue(const std::string& inName, int newValue, bool flagDefault) {\n\tchar intStr[24];\n\tsnprintf(intStr, 24, \"%d\", newValue);\n\tSetValue(inName, std::string(intStr), flagDefault);\n}\n\nvoid ConfigurationManager::SetValue(const std::string& inName, float newValue, bool flagDefault) {\n\tchar intStr[24];\n\tsnprintf(intStr, 24, \"%0.5f\", newValue);\n\tSetValue(inName, std::string(intStr), flagDefault);\n}\n\nvoid ConfigurationManager::SetBoolValue(const std::string& inName, bool newValue, bool flagDefault) {\n\tconst std::string strTrue = \"true\";\n\tconst std::string strFalse = \"false\";\n\tSetValue(inName, newValue ? strTrue : strFalse, flagDefault);\n}\n\nbool ConfigurationManager::MatchValue(const std::string& inName, const std::string& val, bool useCase) {\n\tConfigurationItem* itemFound = FindCI(inName);\n\tif (itemFound) {\n\t\tif (!useCase) {\n\t\t\tif (StringsEqualInsens(itemFound->value.c_str(), val.c_str()))\n\t\t\t\treturn true;\n\t\t}\n\t\telse {\n\t\t\tif (!strcmp(itemFound->value.c_str(), val.c_str()))\n\t\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\nvoid ConfigurationManager::GetFullKey(ConfigurationItem* from, std::string& outStr) {\n\tstd::vector<std::string> stringStack;\n\toutStr.clear();\n\n\twhile (from) {\n\t\tstringStack.push_back(from->name);\n\t\tfrom = from->parent;\n\t}\n\n\tint begin = stringStack.size() - 1;\n\tfor (int i = begin; i >= 0; --i) {\n\t\tif (i != begin)\n\t\t\toutStr += \"/\";\n\t\toutStr += stringStack[i];\n\t}\n}\n\nvoid ConfigurationManager::ClearValueArray(const std::string& containerName, const std::string& arrayName) {\n\tConfigurationItem* container = FindCI(containerName);\n\tif (container)\n\t\tcontainer->ClearArrayChildren(arrayName);\n}\n\nint ConfigurationManager::GetValueArray(const std::string& containerName, const std::string& arrayName, std::vector<std::string>& outValues) {\n\tint count = 0;\n\n\tConfigurationItem* container = FindCI(containerName);\n\tif (container)\n\t\tcount = container->EnumerateChildren(arrayName, outValues);\n\n\treturn count;\n}\n\nint ConfigurationManager::GetValueAttributeArray(const std::string& containerName,\n\t\t\t\t\t\t\t\t\t\t\t\t const std::string& arrayName,\n\t\t\t\t\t\t\t\t\t\t\t\t const std::string& attributeName,\n\t\t\t\t\t\t\t\t\t\t\t\t std::vector<std::string>& outValues) {\n\tint count = 0;\n\n\tConfigurationItem* container = FindCI(containerName);\n\tif (container)\n\t\tcount = container->EnumerateChildrenProperty(arrayName, attributeName, outValues);\n\n\treturn count;\n}\n\nvoid ConfigurationManager::AppendValueArray(const std::string& containerName, const std::string& arrayName, const std::vector<std::map<std::string, std::string>> arrayEntries) {\n\tConfigurationItem* container = FindCI(containerName);\n\tif (!container) {\n\t\tcontainer = new ConfigurationItem();\n\t\tcontainer->name = containerName;\n\t\tcontainer->path = containerName;\n\t\tciList.push_back(container);\n\t}\n\n\tfor (auto& entry : arrayEntries) {\n\t\tConfigurationItem* arrayItem = container->AddChild(arrayName, \"\", true, true);\n\t\tfor (auto& kv : entry)\n\t\t\tarrayItem->AddChild(kv.first, kv.second, false);\n\t}\n}\n\nvoid ConfigurationManager::ReplaceVars(std::string& inoutStr) {\n\tsize_t first = inoutStr.find('%');\n\tsize_t second;\n\twhile (first != std::string::npos) {\n\t\tsecond = inoutStr.find('%', first + 1);\n\t\tsize_t len = second - first;\n\t\tif (len > 1) {\n\t\t\tstd::string varname = inoutStr.substr(first + 1, len - 1);\n\t\t\tinoutStr.replace(first, len + 1, GetString(varname));\n\t\t\tfirst = inoutStr.find('%', first);\n\t\t}\n\t\telse if (len == 1) {\n\t\t\tinoutStr.replace(first, len + 1, \"%\");\n\t\t\tfirst = inoutStr.find('%', first + 2);\n\t\t}\n\t\telse {\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\nint ConfigurationManager::SaveConfig(const std::string& pathToFile, const std::string& rootElement) {\n\tif (rootElement.empty())\n\t\treturn 1;\n\n\tXMLDocument doc;\n\tdoc.SetBOM(true);\n\n\tXMLElement* newElement = doc.NewElement(rootElement.c_str());\n\tXMLElement* root = doc.InsertEndChild(newElement)->ToElement();\n\n\tfor (auto& ci : ciList) {\n\t\tif (ci->isDefault)\n\t\t\tcontinue;\n\t\tif (ci->isComment) {\n\t\t\tXMLComment* newComment = doc.NewComment(ci->value.c_str());\n\t\t\troot->InsertEndChild(newComment);\n\t\t}\n\t\telse\n\t\t\tci->ToXML(root);\n\t}\n\n\tint error = 0;\n\tFILE* fp = nullptr;\n\n#ifdef _WINDOWS\n\tstd::wstring winFileName = PlatformUtil::MultiByteToWideUTF8(pathToFile);\n\terror = _wfopen_s(&fp, winFileName.c_str(), L\"w\");\n\tif (error || !fp)\n\t\treturn 2;\n#else\n\tfp = fopen(pathToFile.c_str(), \"w\");\n\tif (!fp) {\n\t\terror = errno;\n\t\treturn 2;\n\t}\n#endif\n\n\terror = doc.SaveFile(fp);\n\tfclose(fp);\n\tif (error)\n\t\treturn 3;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "src/utils/ConfigurationManager.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include \"../TinyXML-2/tinyxml2.h\"\n#include \"../utils/StringStuff.h\"\n\n#include <map>\n#include <unordered_map>\n#include <vector>\n#include <wx/string.h>\n\nusing namespace tinyxml2;\n\nclass ConfigurationItem {\n\tstd::vector<ConfigurationItem*> children;\n\tstd::vector<ConfigurationItem*> properties;\n\npublic:\n\tConfigurationItem()\n\t\t: parent(nullptr)\n\t\t, level(0)\n\t\t, isProp(false)\n\t\t, isComment(false)\n\t\t, isDefault(false) {}\n\tConfigurationItem(XMLElement* srcElement, ConfigurationItem* inParent = nullptr, int inLevel = 0) {\n\t\tparent = inParent;\n\t\tlevel = inLevel;\n\t\tisProp = false;\n\t\tisComment = false;\n\t\tisDefault = false;\n\t\tSettingFromXML(srcElement);\n\t}\n\tConfigurationItem(std::string text, ConfigurationItem* inParent = nullptr, int inLevel = 0)\n\t\t: value(std::move(text)) {\n\t\tparent = inParent;\n\t\tlevel = inLevel;\n\t\tisProp = false;\n\t\tisComment = true;\n\t\tisDefault = false;\n\t}\n\t~ConfigurationItem();\n\n\tConfigurationItem* parent;\n\tint level;\n\tbool isProp;\n\tbool isComment;\n\tbool isDefault; // Default values are not saved with config.\n\n\tstd::string name;  // Name associated with this node.\n\tstd::string value; // Value associated with this node.\n\tstd::string path;\n\n\tint SettingFromXML(XMLElement* xml);\n\n\tvoid ToXML(XMLElement* parent);\n\tint EnumerateProperties(std::vector<ConfigurationItem*>& outList);\n\tint EnumerateProperties(std::string& outList);\n\tint EnumerateChildren(std::vector<ConfigurationItem*>& outList, bool withProperties = true, bool traverse = true);\n\tint EnumerateChildren(const std::string& inName, std::vector<std::string>& outValueList);\n\tint EnumerateChildrenProperty(const std::string& inName, const std::string& propertyName, std::vector<std::string>& outValueList);\n\tConfigurationItem* FindChild(const std::string& inName, bool recurse = true);\n\tConfigurationItem* AddChild(const std::string& inName, const std::string& value, bool isElement = true, bool forceAdd = false);\n\tvoid DeleteChild(ConfigurationItem* child);\n\n\tConfigurationItem* FindProperty(const std::string& inName);\n\n\tvoid ClearArrayChildren(const std::string& arrayName);\n\n\tbool Match(const std::string& otherName) { return StringsEqualInsens(name.c_str(), otherName.c_str()); }\n};\n\nclass ConfigurationManager {\n\tstd::vector<ConfigurationItem*> ciList;\n\tstd::string file;\n\tConfigurationItem* FindCI(const std::string& inName);\n\npublic:\n\tConfigurationManager();\n\t~ConfigurationManager();\n\n\tvoid Clear();\n\tint LoadConfig(const std::string& pathToFile, const std::string& rootElement = \"Config\");\n\tint SaveConfig(const std::string& pathToFile, const std::string& rootElement = \"Config\");\n\n\tint EnumerateCIs(std::vector<ConfigurationItem*>& outList, bool withProperties = true, bool traverse = true);\n\n\tint EnumerateChildCIs(std::vector<ConfigurationItem*>& outList, const std::string& parentCI, bool withProperties = true, bool traverse = true);\n\n\tbool Exists(const std::string& inName);\n\n\tstd::string GetString(const std::string& inName);\n\n\tint GetIntValue(const std::string& inName, int def = 0);\n\tfloat GetFloatValue(const std::string& inName, float def = 0.0f);\n\tbool GetBoolValue(const std::string& inName, bool def = false);\n\n\tvoid SetValue(const std::string& inName, const std::string& newValue, bool flagDefault = false);\n\tvoid SetValue(const std::string& inName, int newValue, bool flagDefault = false);\n\tvoid SetValue(const std::string& inName, float newValue, bool flagDefault = false);\n\tvoid SetBoolValue(const std::string& inName, bool newValue, bool flagDefault = false);\n\n\tvoid SetDefaultValue(const std::string& inName, const std::string& newValue);\n\tvoid SetDefaultValue(const std::string& inName, int newValue);\n\tvoid SetDefaultValue(const std::string& inName, float newValue);\n\tvoid SetDefaultBoolValue(const std::string& inName, bool newValue);\n\n\tbool MatchValue(const std::string& inName, const std::string& val, bool useCase = false);\n\n\tvoid GetFullKey(ConfigurationItem* from, std::string& outstr);\n\n\tvoid ClearValueArray(const std::string& containerName, const std::string& arrayName);\n\n\tint GetValueArray(const std::string& containerName, const std::string& arrayName, std::vector<std::string>& outValues);\n\tint GetValueAttributeArray(const std::string& containerName, const std::string& arrayName, const std::string& attributeName, std::vector<std::string>& outValues);\n\n\tvoid AppendValueArray(const std::string& containerName, const std::string& arrayName, const std::vector<std::map<std::string, std::string>> arrayEntries);\n\n\tstd::string operator[](const char* inName) { return GetString(std::string(inName)); }\n\n\tstd::string operator[](const std::string& inName) { return GetString(inName); }\n\twxString operator[](const wxString& inName) { return GetString(inName.ToStdString()); }\n\n\t/* Utility function to replace variables within a string with matching configuration data.  Variables\n\t\tare surrounded by %.  EG  :  \"%GameDataPath%rest of path\"  might become \"D:\\\\Skyrim\\\\Data\\\\rest of path.\n\t\ta double percent \"%%\" will be replaced with a single %, while a single % without matching variable will destroy most of the string.\n\t\t*/\n\tvoid ReplaceVars(std::string& inoutStr);\n};\n"
  },
  {
    "path": "src/utils/Log.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"Log.h\"\n\n#include <filesystem>\n#include <wx/utils.h>\n\n/*\n<LogLevel>\n-1: Off\n0: wxLogFatalError\n1: wxLogError\n2: wxLogWarning\n3: wxLogMessage\n*/\n\nvoid Log::Initialize(int level, const wxString& fileName) {\n\twxLog::EnableLogging(false);\n\n\tif (level >= 0) {\n\t\t//Signature to find separate runs\n\t\tstd::string signature = \"[#Log\";\n\t\tstd::string textCopy;\n\t\tint sigCount = 0;\n\n\t\t//Open stream at end to find out file size\n\t\tstd::filesystem::path filePath(fileName.ToStdWstring());\n\t\tstd::ifstream truncStream(filePath, std::ios_base::ate);\n\t\tif (truncStream) {\n\t\t\t//Store size and seek back to beginning\n\t\t\tstd::streampos streamSize = truncStream.tellg();\n\t\t\ttruncStream.seekg(0, std::ios::beg);\n\n\t\t\t//Count all occurences of the signature\n\t\t\tsigCount = std::count(std::istream_iterator<std::string>(truncStream), std::istream_iterator<std::string>(), signature);\n\t\t\tif (sigCount >= 4) {\n\t\t\t\t//Maximum amount of runs per log file exceeded, seek back to beginning\n\t\t\t\tsigCount = 0;\n\t\t\t\ttruncStream.clear();\n\t\t\t\ttruncStream.seekg(0, std::ios::beg);\n\n\t\t\t\t//Count signatures until the 2nd, starting the beginning, is reached\n\t\t\t\tauto pos = std::istream_iterator<std::string>(truncStream);\n\t\t\t\tauto end = std::istream_iterator<std::string>();\n\t\t\t\tfor (; pos != end; ++pos) {\n\t\t\t\t\tif (*pos == signature)\n\t\t\t\t\t\tsigCount++;\n\n\t\t\t\t\tif (sigCount >= 2) {\n\t\t\t\t\t\t//Read text from 2nd signature to EOF\n\t\t\t\t\t\tstd::streampos posCopy = truncStream.tellg();\n\t\t\t\t\t\ttextCopy.resize(streamSize - posCopy);\n\t\t\t\t\t\ttruncStream.read((char*)&textCopy.front(), textCopy.size());\n\t\t\t\t\t\ttextCopy.insert(0, *pos);\n\t\t\t\t\t\tsize_t trim = textCopy.find_last_of('\\n');\n\t\t\t\t\t\tif (trim != std::string::npos)\n\t\t\t\t\t\t\ttextCopy.erase(trim);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttruncStream.close();\n\t\t}\n\n\t\t//Open ofstream, creating empty log file\n\t\tstream.open(filePath, std::ios_base::app);\n\t\tif (stream) {\n\t\t\twxLog* log = new wxLogStream(&stream);\n\t\t\tlog->SetLogLevel(level);\n\n\t\t\t//Copy partial contents of old to new log\n\t\t\tif (!textCopy.empty()) {\n\t\t\t\tstream.close();\n\t\t\t\tstream.clear();\n\t\t\t\tstream.open(filePath);\n\t\t\t\tlog->LogText(textCopy);\n\t\t\t}\n\n\t\t\t//Write new signature line with date\n\t\t\tlog->LogText(wxString::Format(\"%s %s]\", signature, wxNow()));\n\n\t\t\twxLog::SetActiveTarget(log);\n\t\t\twxLog::EnableLogging();\n\t\t\tSetFormatter();\n\t\t}\n\t}\n}\n\nvoid Log::SetFormatter(bool withFile) {\n\twxLogFormatter* oldFormatter = nullptr;\n\n\tif (withFile)\n\t\toldFormatter = wxLog::GetActiveTarget()->SetFormatter(new LogFormatter());\n\telse\n\t\toldFormatter = wxLog::GetActiveTarget()->SetFormatter(new LogFormatterNoFile());\n\n\tif (oldFormatter)\n\t\tdelete oldFormatter;\n}\n"
  },
  {
    "path": "src/utils/Log.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <fstream>\n#include <wx/datetime.h>\n#include <wx/log.h>\n\n//Example\n//[19:30:25][3] Log.h(10): Message here\nclass LogFormatter : public wxLogFormatter {\n\tvirtual wxString Format(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info) const {\n\t\twxDateTime logTime(wxLongLong(info.timestampMS));\n\t\twxString fileName = info.filename;\n\t\tfileName = fileName.AfterLast('/').AfterLast('\\\\');\n\t\tint ihour = logTime.GetHour();\n\t\tint iminute = logTime.GetMinute();\n\t\tint isecond = logTime.GetSecond();\n\t\tint ilevel = level;\n\t\treturn wxString::Format(\"[%02d:%02d:%02d][%d]\\t%s(%d): %s\", ihour, iminute, isecond, ilevel, fileName, info.line, msg);\n\t}\n};\n\n//Example\n//[19:30:25][3] Message here\nclass LogFormatterNoFile : public wxLogFormatter {\n\tvirtual wxString Format(wxLogLevel level, const wxString& msg, const wxLogRecordInfo& info) const {\n\t\twxDateTime logTime(wxLongLong(info.timestampMS));\n\t\tint ihour = logTime.GetHour();\n\t\tint iminute = logTime.GetMinute();\n\t\tint isecond = logTime.GetSecond();\n\t\tint ilevel = level;\n\t\treturn wxString::Format(\"[%02d:%02d:%02d][%d]\\t%s\", ihour, iminute, isecond, ilevel, msg);\n\t}\n};\n\nclass Log {\n\t//Stream doing the actual writing\n\tstd::ofstream stream;\n\npublic:\n\t//Opens and truncates log file to a maximum of runs\n\tvoid Initialize(int level = -1, const wxString& fileName = \"Log.txt\");\n\n\t//Swaps out log formatter\n\tvoid SetFormatter(bool withFile = true);\n};\n"
  },
  {
    "path": "src/utils/PlatformUtil.cpp",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#include \"PlatformUtil.h\"\n\nnamespace {\nstd::string backslash_to_slash(const std::string& s) {\n\tstd::string sc(s);\n\tsize_t len = sc.length();\n\tfor (size_t i = 0; i < len; ++i)\n\t\tif (sc[i] == '\\\\')\n\t\t\tsc[i] = '/';\n\treturn sc;\n}\n} // namespace\n\nnamespace PlatformUtil {\n#ifdef _WINDOWS\n// ACP wide to multibyte\nstd::string WideToMultiByteACP(const std::wstring& wstr) {\n\tif (wstr.empty())\n\t\treturn std::string();\n\n\tint size_needed = WideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), nullptr, 0, nullptr, nullptr);\n\tstd::string strTo(size_needed, 0);\n\tWideCharToMultiByte(CP_ACP, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, nullptr, nullptr);\n\treturn strTo;\n}\n\n// UTF-8 multibyte to wide\nstd::wstring MultiByteToWideUTF8(const std::string& str) {\n\tif (str.empty())\n\t\treturn std::wstring();\n\n\tint size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), nullptr, 0);\n\tstd::wstring wstrTo(size_needed, 0);\n\tMultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);\n\treturn wstrTo;\n}\n#endif\n\nvoid OpenFileStream(std::fstream& file, const std::string& fileName, std::ios_base::openmode mode) {\n#ifdef _WINDOWS\n\t// Convert to std::wstring on Windows only\n\tfile.open(MultiByteToWideUTF8(fileName).c_str(), mode);\n#else\n\tstd::string fn_nobs = backslash_to_slash(fileName);\n\tfile.open(fn_nobs.c_str(), mode);\n#endif\n}\n\nbool FileExists(const std::string& fileName) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);\n\n\tif (!file)\n\t\treturn false;\n\n\treturn true;\n}\n\n// Provide std::wstring function for Windows\n#ifdef _WINDOWS\nvoid OpenFileStream(std::fstream& file, const std::wstring& fileName, unsigned int mode) {\n\tfile.open(fileName.c_str(), mode);\n}\n\nbool FileExists(const std::wstring& fileName) {\n\tstd::fstream file;\n\tPlatformUtil::OpenFileStream(file, fileName, std::ios::in | std::ios::binary);\n\n\tif (!file)\n\t\treturn false;\n\n\treturn true;\n}\n#endif\n} // namespace PlatformUtil\n"
  },
  {
    "path": "src/utils/PlatformUtil.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#ifdef _WINDOWS\n#include <Windows.h>\n#endif\n\n#include <cstdint>\n#include <fstream>\n#include <string>\n\nnamespace PlatformUtil {\n#ifdef _WINDOWS\n// ACP wide to multibyte\nstd::string WideToMultiByteACP(const std::wstring& wstr);\n\n// UTF-8 multibyte to wide\nstd::wstring MultiByteToWideUTF8(const std::string& str);\n#endif\n\nvoid OpenFileStream(std::fstream& file, const std::string& fileName, std::ios_base::openmode mode);\nbool FileExists(const std::string& fileName);\n\n// Provide std::wstring function for Windows\n#ifdef _WINDOWS\nvoid OpenFileStream(std::fstream& file, const std::wstring& fileName, unsigned int mode);\nbool FileExists(const std::wstring& fileName);\n#endif\n} // namespace PlatformUtil\n\n// This user-defined literal allows you to specify an int with a\n// multi-character string: \"OSD\\0\"_mci\ninline constexpr uint32_t operator\"\" _mci(const char* p, size_t n) {\n\tuint32_t v = 0;\n\tfor (size_t i = 0; i < n; ++i) {\n\t\tv <<= 8;\n\t\tv += static_cast<unsigned char>(p[i]);\n\t}\n\treturn v;\n}\n"
  },
  {
    "path": "src/utils/StringStuff.cpp",
    "content": "#include \"StringStuff.h\"\n#include <cctype>\n#include <sstream>\n\nbool StringsEqualNInsens(const char* a, const char* b, int len) {\n\twhile (len > 0) {\n\t\tif (std::tolower(*a) != std::tolower(*b))\n\t\t\treturn false;\n\t\tif (*a == '\\0')\n\t\t\treturn true;\n\t\t++a, ++b, --len;\n\t}\n\treturn true;\n}\n\nbool StringsEqualInsens(const char* a, const char* b) {\n\twhile (true) {\n\t\tif (std::tolower(*a) != std::tolower(*b))\n\t\t\treturn false;\n\t\tif (*a == '\\0')\n\t\t\treturn true;\n\t\t++a, ++b;\n\t}\n}\n\nbool StringStartsWith(std::string_view s, std::string_view prefix) {\n\treturn s.size() >= prefix.size() && s.compare(0, prefix.size(), prefix) == 0;\n}\n\nbool StringEndsWith(std::string_view s, std::string_view suffix) {\n\treturn s.size() >= suffix.size() && s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;\n}\n\nstd::string ToOSSlashes(const std::string& s) {\n\tstd::string d(s);\n\tsize_t len = d.length();\n\tfor (size_t i = 0; i < len; ++i)\n#ifdef _WINDOWS\n\t\tif (d[i] == '/')\n\t\t\td[i] = '\\\\';\n#else\n\t\tif (d[i] == '\\\\')\n\t\t\td[i] = '/';\n#endif\n\treturn d;\n}\n\nstd::string ToBackslashes(const std::string& s) {\n\tstd::string d(s);\n\tsize_t len = d.length();\n\tfor (size_t i = 0; i < len; ++i)\n\t\tif (d[i] == '/')\n\t\t\td[i] = '\\\\';\n\treturn d;\n}\n\nstd::vector<std::string> SplitString(const std::string& s, const char delim) {\n\tstd::stringstream sstrm(s);\n\tstd::string segment;\n\tstd::vector<std::string> seglist;\n\n\twhile (std::getline(sstrm, segment, delim)) {\n\t\tseglist.push_back(segment);\n\t}\n\n\treturn seglist;\n}\n\nstd::string JoinStrings(const std::vector<std::string>& elements, const char* const separator) {\n\tswitch (elements.size()) {\n\t\tcase 0: return \"\";\n\t\tcase 1: return elements[0];\n\t\tdefault:\n\t\t\tstd::ostringstream os;\n\t\t\tstd::copy(elements.begin(), elements.end() - 1, std::ostream_iterator<std::string>(os, separator));\n\t\t\tos << *elements.rbegin();\n\t\t\treturn os.str();\n\t}\n}\n"
  },
  {
    "path": "src/utils/StringStuff.h",
    "content": "/*\nBodySlide and Outfit Studio\nSee the included LICENSE file\n*/\n\n#pragma once\n\n#include <iterator>\n#include <string>\n#include <vector>\n\n/* StringsEqualNInsens: returns true if the first len characters of a\nand b are the same insensitive to case. */\nbool StringsEqualNInsens(const char* a, const char* b, int len);\n\n/* StringsEqualInsens: returns true if the strings a and b are the same\ninsensitive to case. */\nbool StringsEqualInsens(const char* a, const char* b);\n\n/* StringStartsWith: returns true if the string s starts with prefix.*/\nbool StringStartsWith(std::string_view s, std::string_view prefix);\n\n/* StringEndsWith: returns true if the string s ends with suffix.*/\nbool StringEndsWith(std::string_view s, std::string_view suffix);\n\n/* ToOSSlash: converts all forward and back slashes in s to the path\nseparator character for the operating system and returns the result. */\nstd::string ToOSSlashes(const std::string& s);\n\n/* ToBackslashes: converts all forward slashes into backslashes in s\nand returns the result. */\nstd::string ToBackslashes(const std::string& s);\n\n/* SplitString: splits a string into a vector of strings using a delimiter */\nstd::vector<std::string> SplitString(const std::string& s, const char delim);\n\n/* JoinStrings: joins a vector of strings into one string with separators */\nstd::string JoinStrings(const std::vector<std::string>& elements, const char* const separator);\n\n/* case_insensitive_compare: can be used for maps and more */\nstruct case_insensitive_compare {\n\tstruct nocase_compare {\n\t\tbool operator()(const unsigned char& c1, const unsigned char& c2) const { return tolower(c1) < tolower(c2); }\n\t};\n\n\tbool operator()(const std::string& s1, const std::string& s2) const { return std::lexicographical_compare(s1.begin(), s1.end(), s2.begin(), s2.end(), nocase_compare()); }\n};\n\n#ifdef _WINDOWS\nconstexpr char PathSepChar = '\\\\';\nconstexpr const char* PathSepStr = \"\\\\\";\n#else\nconstexpr char PathSepChar = '/';\nconstexpr const char* PathSepStr = \"/\";\n#endif\n"
  }
]